diff --git build/make/build.xml build/make/build.xml old mode 100644 new mode 100755 index a394436..6bb5668 --- build/make/build.xml +++ build/make/build.xml @@ -300,7 +300,7 @@ Version: $Revision: 1.16.2.20 $ - + @@ -392,6 +392,11 @@ Version: $Revision: 1.16.2.20 $ + + + + + @@ -433,6 +438,7 @@ Version: $Revision: 1.16.2.20 $ deploy.readme, deploy.getting_started, deploy.copy_classlib, + deploy.antlr, deploy.tweakname"> @@ -498,6 +504,24 @@ Version: $Revision: 1.16.2.20 $ + + + + + + + + + + +# Dependency for generics parser +bootclasspath.99=antlr-2.7.5.jar + + + + + + diff --git build/make/components/extra/apr.xml build/make/components/extra/apr.xml index 16acc25..0bc38c6 100644 --- build/make/components/extra/apr.xml +++ build/make/components/extra/apr.xml @@ -88,7 +88,10 @@ Version: $Revision: 1.4.2.5 $ - + + diff --git build/make/components/extra/eclipse_script.xml build/make/components/extra/eclipse_script.xml index 79dc319..a5244a1 100644 --- build/make/components/extra/eclipse_script.xml +++ build/make/components/extra/eclipse_script.xml @@ -51,7 +51,7 @@ if exist "%ECLIPSE_HOME%/plugins/org.ecl - + diff --git build/make/components/extra/jre_libraries.xml build/make/components/extra/jre_libraries.xml index 72db44c..e02fb60 100644 --- build/make/components/extra/jre_libraries.xml +++ build/make/components/extra/jre_libraries.xml @@ -28,6 +28,7 @@ Version: $Revision: 1.1.2.7 $ - + + diff --git build/make/components/vm.xml build/make/components/vm.xml index bb699a4..529c3db 100644 --- build/make/components/vm.xml +++ build/make/components/vm.xml @@ -59,16 +59,15 @@ Version: $Revision: 1.4.2.4 $ vm.gc, vm.interpreter, vm.hythr, + vm.jitrino, vm.kernel_classes, vm.vmstart" /> - - - + diff --git build/make/components/vm/em.xml build/make/components/vm/em.xml index 9ae34f0..aabba60 100644 --- build/make/components/vm/em.xml +++ build/make/components/vm/em.xml @@ -75,8 +75,10 @@ Version: $Revision: 1.5.2.2 $ diff --git build/make/components/vm/hythr.xml build/make/components/vm/hythr.xml index a1df6e1..c1c193f 100644 --- build/make/components/vm/hythr.xml +++ build/make/components/vm/hythr.xml @@ -60,14 +60,22 @@ vm.port,extra.log4cxx, extra.aprutil" /> - - + + + - - + @@ -77,7 +85,7 @@ vm.port,extra.log4cxx, extra.aprutil" /> - + diff --git build/make/components/vm/jitrino.xml build/make/components/vm/jitrino.xml index dc9d740..5536e72 100644 --- build/make/components/vm/jitrino.xml +++ build/make/components/vm/jitrino.xml @@ -37,6 +37,8 @@ Version: $Revision: 1.6.2.8 $ + + @@ -275,18 +277,15 @@ Version: $Revision: 1.6.2.8 $ - - - + + @@ -335,5 +334,15 @@ Version: $Revision: 1.6.2.8 $ + + + + + + + + diff --git build/make/components/vm/jthread.xml build/make/components/vm/jthread.xml index b8594d3..08a6bc0 100644 --- build/make/components/vm/jthread.xml +++ build/make/components/vm/jthread.xml @@ -55,11 +55,19 @@ vm.hythr" /> + + + - + + + diff --git build/make/components/vm/kernel_classes.xml build/make/components/vm/kernel_classes.xml index 69de1c1..6e321ad 100644 --- build/make/components/vm/kernel_classes.xml +++ build/make/components/vm/kernel_classes.xml @@ -41,7 +41,7 @@ Version: $Revision: 1.4.2.5 $ - + diff --git build/make/components/vm/vmcore.xml build/make/components/vm/vmcore.xml old mode 100644 new mode 100755 index 3b7ec13..d13c370 --- build/make/components/vm/vmcore.xml +++ build/make/components/vm/vmcore.xml @@ -92,6 +92,7 @@ Version: $Revision: 1.5.2.3 $ + + @@ -280,13 +285,14 @@ Version: $Revision: 1.5.2.3 $ diff --git build/make/deploy.xml build/make/deploy.xml index c234b01..e36e825 100644 --- build/make/deploy.xml +++ build/make/deploy.xml @@ -45,21 +45,18 @@ Description of the product deploy folder bin:interpreter - + + bin:jitrino + bin:* + bin:gc - + + bin:vmi + lib/boot:kernel diff --git build/make/lnx.properties build/make/lnx.properties index a11f4a9..a661147 100644 --- build/make/lnx.properties +++ build/make/lnx.properties @@ -74,6 +74,13 @@ #remote.HYPLUGIN.archive.type=svn remote.HYPLUGIN.archive=-r 387505 https://svn.apache.org/repos/asf/incubator/harmony/enhanced/tools/trunk/eclipse/org.apache.harmony.eclipse.jdt.launching remote.HYPLUGIN.archive.type=svn +# ANother Tool for Language Recognition +# http://www.antlr.org/download/antlr-2.7.5.jar +# remote.ANTLR.archive=/nfs/site/proj/drl/share/sync/externals/antlr-2.7.5/antlr-2.7.5.jar +# remote.ANTLR.archive=/nfs/ins/proj/drl/coreapi/antlr-2.7.5/antlr-2.7.5.jar +remote.ANTLR.archive=http://www.antlr.org/download/antlr-2.7.5.jar +remote.ANTLR.archive.type=asis + # Xalan-Java version 2.7.0 XALAN_HOME=${external.dep.CLASSLIB}/depends/jars/xalan-j_2.7.0 diff --git build/make/setup.xml build/make/setup.xml index aeb38ef..642928b 100644 --- build/make/setup.xml +++ build/make/setup.xml @@ -90,7 +90,8 @@ Version: $Revision: 1.5.2.33 $ download.remote.files, unzip.resources, check.unzipped.externals, - copy.nessessary.jars"> + copy.nessessary.jars, + apply.patches"> @@ -106,6 +107,8 @@ Version: $Revision: 1.5.2.33 $ + + @@ -191,7 +194,7 @@ Version: $Revision: 1.5.2.33 $ - + @@ -337,12 +340,14 @@ Version: $Revision: 1.5.2.33 $ - + diff --git build/make/targets/build.native.xml build/make/targets/build.native.xml index aaa22ab..f859c74 100644 --- build/make/targets/build.native.xml +++ build/make/targets/build.native.xml @@ -110,6 +110,7 @@ Version: $Revision: 1.5.2.6 $ diff --git build/make/targets/common_vm.xml build/make/targets/common_vm.xml index 1e1761d..4932de2 100644 --- build/make/targets/common_vm.xml +++ build/make/targets/common_vm.xml @@ -108,6 +108,9 @@ Version: $Revision: 1.6.2.6 $ + @@ -203,12 +206,12 @@ Version: $Revision: 1.6.2.6 $ - - + - + diff --git build/make/targets/cunit.test.xml build/make/targets/cunit.test.xml index 95a4059..1de1459 100644 --- build/make/targets/cunit.test.xml +++ build/make/targets/cunit.test.xml @@ -169,8 +169,8 @@ Version: $Revision$ - + diff --git build/make/targets/kernel.test.xml build/make/targets/kernel.test.xml new file mode 100644 index 0000000..7a2e59c --- /dev/null +++ build/make/targets/kernel.test.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ============================================== + Please set the classpath of junit as follows: + build.bat -Djunit.jar=%JUNIT_HOME% test" + ============================================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ================================== + Run kernel tests using ${jit.or.interpreter} + ================================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git build/make/targets/smoke.test.xml build/make/targets/smoke.test.xml index 83b0511..5a292be 100644 --- build/make/targets/smoke.test.xml +++ build/make/targets/smoke.test.xml @@ -26,7 +26,9 @@ Version: $Revision: 1.4.2.11 $ - + diff --git build/make/targets/test.xml build/make/targets/test.xml index 542e7ed..10249b8 100644 --- build/make/targets/test.xml +++ build/make/targets/test.xml @@ -18,6 +18,6 @@ Author: Marina V. Goldburt Version: $Revision: 1.3.2.2 $ --> - + diff --git build/make/win.properties build/make/win.properties index 4eb355d..741660c 100644 --- build/make/win.properties +++ build/make/win.properties @@ -76,6 +76,13 @@ # IJ Eclipse plugin remote.HYPLUGIN.archive=-r 387505 https://svn.apache.org/repos/asf/incubator/harmony/enhanced/tools/trunk/eclipse/org.apache.harmony.eclipse.jdt.launching remote.HYPLUGIN.archive.type=svn +# ANother Tool for Language Recognition +# http://www.antlr.org/download/antlr-2.7.5.jar +# remote.ANTLR.archive=/nfs/site/proj/drl/share/sync/externals/antlr-2.7.5/antlr-2.7.5.jar +# remote.ANTLR.archive=/nfs/ins/proj/drl/coreapi/antlr-2.7.5/antlr-2.7.5.jar +remote.ANTLR.archive=http://www.antlr.org/download/antlr-2.7.5.jar +remote.ANTLR.archive.type=asis + # Xalan-Java version 2.7.0 XALAN_HOME=${external.dep.CLASSLIB}/depends/jars/xalan-j_2.7.0 diff --git build/patches/common/LOG4CXX/include/log4cxx/helpers/unicodehelper.h build/patches/common/LOG4CXX/include/log4cxx/helpers/unicodehelper.h deleted file mode 100644 index 630d230..0000000 --- build/patches/common/LOG4CXX/include/log4cxx/helpers/unicodehelper.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2003,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LOG4CXX_HELPERS_UNICODEHELPER_H -#define _LOG4CXX_HELPERS_UNICODEHELPER_H - -#include -#include - -namespace log4cxx { - namespace helpers { - /** - * UnicodeHelper provides static methods for encoding and decoding - * UTF-8, UTF-16 and wchar_t from UCS-4 values. - * - */ - class UnicodeHelper { - private: - /** - * Inaccessible constructor. - */ - UnicodeHelper() { - } - - public: - /** - * Decodes next character from a sequence of UTF-8 bytes. - * @param src start of character, will be modified to point at next character. - * @param srcEnd end of sequence. - * @return scalar value (UCS-4) or 0xFFFF if invalid sequence. - */ - static unsigned int decodeUTF8(const char*& src, - const char* srcEnd); - - - /** - * Encodes a character using UTF-8. - * @param ch UCS-4 value. - * @param dst buffer to receive UTF-8 encoding (must be at least 8 bytes) - * @return number of bytes needed to represent character - */ - static int encodeUTF8(unsigned int ch, char* dst); - - /** - * Encodes a character using UTF-16BE. - * @param ch UCS-4 value. - * @param dst buffer to receive UTF-16BE encoding (must be at least 4 bytes) - * @return number of bytes needed to represent character - */ - static int encodeUTF16BE(unsigned int ch, char* dst); - - /** - * Encodes a character using UTF-16LE. - * @param ch UCS-4 value. - * @param dst buffer to receive UTF-16BE encoding (must be at least 4 bytes) - * @return number of bytes needed to represent character - */ - static int encodeUTF16LE(unsigned int ch, char* dst); - - -#if LOG4CXX_HAS_WCHAR_T - /** - * Decodes next character from a sequence of wchar_t values. - * @param src start of character, will be modified to point at next character. - * @param srcEnd end of sequence. - * @return scalar value (UCS-4) or 0xFFFF if invalid sequence. - */ - static unsigned int decodeWide(const wchar_t*& src, const wchar_t* srcEnd); - - - /** - * Encodes a character to wchar_t. - * @param ch UCS-4 value. - * @param dst buffer to receive wchar_t (must be at least 2 wchar_t) - * @return number of wchar_t needed to represent character - */ - static int encodeWide(unsigned int ch, wchar_t* str); - - /** - * Determines the number of UTF-8 bytes required to express - * the wchar_t value. - * @param ch wchar_t value - * @return number of bytes required. - */ - static int lengthUTF8(wchar_t ch); - -#endif - - /** - * Decodes next character from a LogString. - * @param in string from which the character is extracted. - * @param iter iterator addressing start of character, will be - * advanced to next character if successful. - * @return scalar value (UCS-4) or 0xFFFF if invalid sequence. - */ - static unsigned int decode(const LogString& in, - LogString::const_iterator& iter); - - /** - * Encodes a UCS-4 value to logchar. - * @param ch UCS-4 value. - * @param dst buffer to receive logchar encoding (must be at least 8) - * @return number of logchar needed to represent character - */ - static int encode(unsigned int ch, logchar* dst); - - }; - } -} -#endif diff --git build/patches/common/LOG4CXX/include/log4cxx/xml/domconfigurator.h build/patches/common/LOG4CXX/include/log4cxx/xml/domconfigurator.h deleted file mode 100644 index f64fb22..0000000 --- build/patches/common/LOG4CXX/include/log4cxx/xml/domconfigurator.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2003-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LOG4CXX_XML_DOM_CONFIGURATOR_H -#define _LOG4CXX_XML_DOM_CONFIGURATOR_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace log4cxx -{ - class File; - - namespace spi - { - class LoggerRepository; - typedef helpers::ObjectPtrT LoggerRepositoryPtr; - - class Filter; - typedef helpers::ObjectPtrT FilterPtr; - - class AppenderAttachable; - typedef helpers::ObjectPtrT AppenderAttachablePtr; - - class OptionHandler; - typedef helpers::ObjectPtrT OptionHandlerPtr; - } - - namespace helpers - { - class XMLDOMDocument; - typedef helpers::ObjectPtrT XMLDOMDocumentPtr; - - class XMLDOMElement; - typedef helpers::ObjectPtrT XMLDOMElementPtr; - } - - namespace config - { - class PropertySetter; - } - - namespace rolling - { - class RollingPolicy; - typedef helpers::ObjectPtrT RollingPolicyPtr; - - class TriggeringPolicy; - typedef helpers::ObjectPtrT TriggeringPolicyPtr; - } - - - - namespace xml - { - class AppenderMap - { - public: - AppenderPtr get(const LogString& appenderName); - void put(const LogString& appenderName, AppenderPtr appender); - - protected: - std::map map; - }; - - /** - Use this class to initialize the log4cxx environment using a DOM tree. - -

Sometimes it is useful to see how log4cxx is reading configuration - files. You can enable log4cxx internal logging by setting the - debug attribute in the - log4cxx element. As in -

-                      <log4j:configuration debug="true" xmlns:log4j="http://jakarta.apache.org/log4j/">
-                      ...
-                      </log4j:configuration>
-              
- -

There are sample XML files included in the package. - */ - class LOG4CXX_EXPORT DOMConfigurator : - virtual public spi::Configurator, - virtual public helpers::ObjectImpl - { - protected: - /** - Used internally to parse appenders by IDREF name. - */ - AppenderPtr findAppenderByName(helpers::XMLDOMDocumentPtr doc, - const LogString& appenderName); - - /** - Used internally to parse appenders by IDREF element. - */ - AppenderPtr findAppenderByReference( - helpers::XMLDOMElementPtr appenderRef); - - /** - Used internally to parse an appender element. - */ - AppenderPtr parseAppender(helpers::XMLDOMElementPtr appenderElement); - - /** - Used internally to parse an {@link spi::ErrorHandler ErrorHandler } element. - */ - void parseErrorHandler(helpers::XMLDOMElementPtr element, AppenderPtr appender); - - /** - Used internally to parse a filter element. - */ - void parseFilters(helpers::XMLDOMElementPtr element, - std::vector& filters); - - /** - Used internally to parse a logger element. - */ - void parseLogger(helpers::XMLDOMElementPtr loggerElement); - - /** - Used internally to parse the logger factory element. - */ - void parseLoggerFactory(helpers::XMLDOMElementPtr factoryElement); - - /** - Used internally to parse the logger factory element. - */ - log4cxx::rolling::TriggeringPolicyPtr parseTriggeringPolicy(helpers::XMLDOMElementPtr factoryElement); - - /** - Used internally to parse the logger factory element. - */ - log4cxx::rolling::RollingPolicyPtr parseRollingPolicy(helpers::XMLDOMElementPtr factoryElement); - - /** - Used internally to parse the roor category element. - */ - void parseRoot(helpers::XMLDOMElementPtr rootElement); - - /** - Used internally to parse the children of a category element. - */ - void parseChildrenOfLoggerElement(helpers::XMLDOMElementPtr catElement, - LoggerPtr logger, bool isRoot); - - /** - Used internally to parse a layout element. - */ - LayoutPtr parseLayout(helpers::XMLDOMElementPtr layout_element); - - /** - Used internally to parse a level element. - */ - void parseLevel(helpers::XMLDOMElementPtr element, - LoggerPtr logger, bool isRoot); - - void setParameter(helpers::XMLDOMElementPtr elem, - config::PropertySetter& propSetter); - - /** - Used internally to configure the log4cxx framework by parsing a DOM - tree of XML elements based on log4j.dtd. - - */ - void parse(helpers::XMLDOMElementPtr element); - - public: - DOMConfigurator(); - - DECLARE_LOG4CXX_OBJECT(DOMConfigurator) - BEGIN_LOG4CXX_CAST_MAP() - LOG4CXX_CAST_ENTRY(spi::Configurator) - END_LOG4CXX_CAST_MAP() - - DOMConfigurator(log4cxx::helpers::Pool& p); - - /** - A static version of #doConfigure. - */ - static void configure(const std::string& filename); -#if LOG4CXX_HAS_WCHAR_T - static void configure(const std::wstring& filename); -#endif - /** - Like #configureAndWatch(const String& configFilename, long delay) - except that the default delay as defined by - helpers::FileWatchdog#DEFAULT_DELAY is used. - @param configFilename A log4j configuration file in XML format. - */ - static void configureAndWatch(const std::string& configFilename); -#if LOG4CXX_HAS_WCHAR_T - static void configureAndWatch(const std::wstring& configFilename); -#endif - /** - Read the configuration file configFilename if it - exists. Moreover, a thread will be created that will periodically - check if configFilename has been created or - modified. The period is determined by the delay - argument. If a change or file creation is detected, then - configFilename is read to configure log4cxx. - - @param configFilename A log4j configuration file in XML format. - @param delay The delay in milliseconds to wait between each check. - */ - static void configureAndWatch(const std::string& configFilename, - long delay); -#if LOG4CXX_HAS_WCHAR_T - static void configureAndWatch(const std::wstring& configFilename, - long delay); -#endif - - /** - Interpret the XML file pointed by filename and set up - log4cxx accordingly. -

The configuration is done relative to the hierarchy parameter. - @param filename The file to parse. - @param repository The hierarchy to operation upon. - */ - void doConfigure(const File& filename, - spi::LoggerRepositoryPtr& repository); - - protected: - LogString subst(const LogString& value); - - protected: - void * appenderBag; - - helpers::Properties props; - spi::LoggerRepositoryPtr repository; - spi::LoggerFactoryPtr loggerFactory; - - private: - // prevent assignment or copy statements - DOMConfigurator(const DOMConfigurator&); - DOMConfigurator& operator=(const DOMConfigurator&); - }; - } // namespace xml -} // namespace log4cxx - -#endif // _LOG4CXX_XML_DOM_CONFIGURATOR_H diff --git vm/em/src/DrlEMImpl.cpp vm/em/src/DrlEMImpl.cpp index d067e28..5fc6d1d 100644 --- vm/em/src/DrlEMImpl.cpp +++ vm/em/src/DrlEMImpl.cpp @@ -21,6 +21,7 @@ #include "DrlEMImpl.h" #include "EBProfileCollector.h" +#include "EdgeProfileCollector.h" #include "jit_import.h" #include "em_intf.h" @@ -34,10 +35,14 @@ #include #include -#define DEFAULT_JIT_DLL "jitrino" #define DEFAULT_INTERPRETER_DLL "interpreter" #define LOG_DOMAIN "em" +#define EDGE_PROFILER_STR "EDGE_PROFILER" +#define ENTRY_BACKEDGE_PROFILER_STR "EB_PROFILER" + +#define EM_CONFIG_EXT std::string(".emconf") + DrlEMImpl* DrlEMFactory::emInstance = NULL; DrlEMImpl* DrlEMFactory::createAndInitEMInstance() { @@ -67,8 +72,7 @@ void DrlEMFactory::deinitEMInstance() { static EM_PCTYPE get_pc_type(EM_Handle _this, PC_Handle pc) { assert(_this!=NULL); assert(pc!=NULL); - assert(((ProfileCollector*)pc)->type == EM_PCTYPE_ENTRY_BACKEDGE); - return EM_PCTYPE_ENTRY_BACKEDGE; + return ((ProfileCollector*)pc)->type; } static PC_Handle get_pc(EM_Handle _this, EM_PCTYPE profile_type, JIT_Handle jh, EM_JIT_PC_Role jit_role) { @@ -96,14 +100,13 @@ RStep::RStep(JIT_Handle _jit, const std: //todo!! replace inlined strings with defines!! -DrlEMImpl::DrlEMImpl() : jh(NULL), _execute_method(NULL), interpreterMode(false) { +DrlEMImpl::DrlEMImpl() : jh(NULL), _execute_method(NULL), + interpreterMode(false), jitTiMode(false) { nMethodsCompiled=0; nMethodsRecompiled=0; tick=0; hymutex_create(&recompilationLock, TM_MUTEX_NESTED); -#ifndef _EM64T_ initProfileAccess(); -#endif } DrlEMImpl::~DrlEMImpl() { @@ -124,9 +127,22 @@ void DrlEMImpl::initProfileAccess() { profileAccessInterface.eb_profiler_get_entry_threshold = eb_profiler_get_entry_threshold; profileAccessInterface.eb_profiler_sync_mode_callback = (void (*)(Method_Profile_Handle))vm_create_helper_for_function((void *(*)(void *))eb_profiler_sync_mode_callback); profileAccessInterface.eb_profiler_get_backedge_threshold = eb_profiler_get_backedge_threshold; + + + //EDGE profile + profileAccessInterface.edge_profiler_create_profile = edge_profiler_create_profile; + profileAccessInterface.edge_profiler_get_num_counters = edge_profiler_get_num_counters; + profileAccessInterface.edge_profiler_get_checksum = edge_profiler_get_checksum; + profileAccessInterface.edge_profiler_get_counter_addr = edge_profiler_get_counter_addr; + profileAccessInterface.edge_profiler_get_entry_counter_addr = edge_profiler_get_entry_counter_addr; + profileAccessInterface.edge_profiler_get_entry_threshold = edge_profiler_get_entry_threshold; + profileAccessInterface.edge_profiler_get_backedge_threshold = edge_profiler_get_backedge_threshold; + + return; } + void DrlEMImpl::deallocateResources() { tbsClients.clear(); @@ -151,15 +167,32 @@ void DrlEMImpl::deallocateResources() { //_____________________________________________________________________ // Reading and parsing configuration +static bool endsWith(const std::string& str, const std::string& suffix) { + if (str.length() < suffix.length()) { + return false; + } + return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); +} -std::string buildDefaultLibPath(const std::string& dll_name) { - std::string library_path = vm_get_property_value("vm.boot.library.path"); +std::string prepareLibPath(const std::string& origPath) { #ifdef PLATFORM_NT - std::string fullPath = library_path + "\\"+ dll_name+".dll"; -#else - std::string fullPath = library_path + "/lib" + dll_name + ".so"; + std::string separator("\\"), libPrefix(""), libSuffix(".dll"); +#else + std::string separator("/"), libPrefix("lib"), libSuffix(".so"); #endif - return fullPath; + + std::string path = origPath; + if (path.find('/') == path.npos && path.find('\\') == path.npos ) { + std::string dir = vm_get_property_value("vm.boot.library.path"); + if (libPrefix.length() > 0 && !startsWith(path, libPrefix)) { + path = libPrefix + path; + } + path = dir + separator + path; + } + if (!endsWith(path, libSuffix)) { + path+=libSuffix; + } + return path; } static std::string getParam(const std::string& config, const std::string& name) { @@ -213,95 +246,52 @@ static StringList getAllParamsAsList(con return res; } -static std::string single2Chain(const string& pathToDll, const std::string& jitName) { - return "chains=chain1\nchain1.jits="+jitName+"\n"+jitName+".file="+pathToDll+"\n"; -} - -static std::string dpgo2Chain(const string& pathToDll, bool async) { - std::string res = std::string("chains=chain1,chain2\n") - +"chain1.jits=JET_CLINIT\n" - +"chain2.jits=JET_DPGO,OPT\n" - - +"chain1.filter=+::\n" - +"chain1.filter=-\n" - - +"JET_CLINIT.file="+pathToDll+"\n" - +"JET_DPGO.file="+pathToDll+"\n" - +"OPT.file="+pathToDll+"\n" - - +"JET_DPGO.genProfile=JET_DPGO_PROFILE\n" - +"JET_DPGO_PROFILE.profilerType=ENTRY_BACKEDGE_PROFILER\n" - +"OPT.useProfile=JET_DPGO_PROFILE\n" - +"JET_DPGO_PROFILE.mode="+(async ? "ASYNC" : "SYNC")+"\n" - +"JET_DPGO_PROFILE.entryThreshold=10000\n" - +"JET_DPGO_PROFILE.backedgeThreshold=100000\n" - +"JET_DPGO_PROFILE.tbsTimeout=5\n" - +"JET_DPGO_PROFILE.tbsInitialTimeout=0\n"; - - return res; -} - -static std::string readEMConfiguration() { - std::string prop = vm_get_property_value("em.properties"); +static std::string readFile(const std::string& fileName) { std::string config; - bool isJet=false, isOpt = false; - if (prop.empty()) { -#ifdef _IPF_ - config = single2Chain(buildDefaultLibPath(std::string(DEFAULT_JIT_DLL)), std::string("JIT")); -#else - config = dpgo2Chain(buildDefaultLibPath(std::string(DEFAULT_JIT_DLL)), false); -// config = single2Chain(buildDefaultLibPath(std::string(DEFAULT_JIT_DLL)), std::string("JIT")); -#endif - } else if (startsWith(prop, "single:") - || (isOpt = startsWith(prop, "opt:") || prop == "opt") - || (isJet = startsWith(prop, "jet:") || prop == "jet")) { - - if (isJet) { - prop = std::string("single:")+ "JET:" + (prop.length() > 4 ? prop.substr(4) : std::string("")); - } else if (isOpt) { - prop = std::string("single:")+ "OPT:" + (prop.length() > 4 ? prop.substr(4) : std::string("")); - } - std::string jitName, fileName; - size_t jitNameStartIdx = strlen("single:"); - size_t jitNameEndIdx = prop.find(':', jitNameStartIdx); - if (jitNameEndIdx!=std::string::npos) { - jitName = prop.substr(jitNameStartIdx, jitNameEndIdx - jitNameStartIdx); - fileName = prop.substr(jitNameEndIdx+1); - } - if (fileName.empty()) { - fileName = buildDefaultLibPath(std::string(DEFAULT_JIT_DLL)); + std::ifstream configFile; + configFile.open(fileName.c_str(), std::ios::in); + bool rc = false; + if (configFile.is_open()) { + std::string line; + size_t idx = std::string::npos; + while (getline(configFile, line)) { + if (startsWith(line, "#")) { + continue; + } else if (startsWith(line, "-D") && (idx = line.find('=')) != std::string::npos) { + std::string name = line.substr(2, idx-2); + std::string value = line.substr(idx+1); + const char* old_value = vm_get_property_value(name.c_str()); + if (old_value == NULL || *old_value == 0) { + vm_properties_set_value(name.c_str(), value.c_str()); + } + continue; + } + config+=line + "\n"; } - config = single2Chain(fileName, jitName); - } else if (startsWith(prop, "dpgo:") || prop == "dpgo" - || startsWith(prop, "dpgo_sync:") || prop == "dpgo_sync" - || startsWith(prop, "dpgo_async:") || prop == "dpgo_async" ) - { - bool async = startsWith(prop, "dpgo_async"); - std::string jitPath; - size_t colonPos = prop.find(':'); - if (colonPos!= std::string::npos && prop.length() > colonPos) { - jitPath = prop.substr(colonPos+1); - } else { - jitPath = buildDefaultLibPath(DEFAULT_JIT_DLL); + rc = !config.empty(); + } + if (!rc) { + std::string errMsg = "EM: Can't read configuration from '" + fileName+ "'"; + ECHO(errMsg.c_str()); + } + return config; +} + +std::string DrlEMImpl::readConfiguration() { + std::string configFileName = vm_get_property_value("em.properties"); + if (configFileName.empty()) { + configFileName = jitTiMode ? "ti" : "client"; + } + if (!endsWith(configFileName, EM_CONFIG_EXT)) { + configFileName = configFileName+EM_CONFIG_EXT; } - config = dpgo2Chain(jitPath, async); - } else { - std::ifstream configFile; - configFile.open(prop.c_str(), std::ios::in); - bool rc = false; - if (configFile.is_open()) { - std::string line; - while (getline(configFile, line)) { - config+=line+"\n"; - } - rc = !config.empty(); - } - if (!rc) { - std::string errMsg = "EM: Can't read configuration from '" + prop + "'"; - ECHO(errMsg.c_str()); + + if (configFileName.find('/') == configFileName.npos && configFileName.find('\\') == configFileName.npos ) { + std::string defaultConfigDir = vm_get_property_value("vm.boot.library.path"); + configFileName = defaultConfigDir + "/" + configFileName; } - } + std::string config = readFile(configFileName); return config; } @@ -310,9 +300,10 @@ #endif bool DrlEMImpl::init() { interpreterMode = vm_get_boolean_property_value_with_default("vm.use_interpreter"); + jitTiMode = vm_get_property_value_boolean("vm.jvmti.enabled", false); if (interpreterMode) { apr_dso_handle_t* libHandle; - std::string interpreterLib = buildDefaultLibPath(DEFAULT_INTERPRETER_DLL); + std::string interpreterLib = prepareLibPath(DEFAULT_INTERPRETER_DLL); jh = vm_load_jit(interpreterLib.c_str(), &libHandle); if (jh == NULL) { @@ -331,7 +322,7 @@ bool DrlEMImpl::init() { } //normal mode with recompilation chains.. _execute_method = JIT_execute_method_default; - std::string config = readEMConfiguration(); + std::string config = readConfiguration(); if (!config.empty()) { buildChains(config); } @@ -368,6 +359,15 @@ bool DrlEMImpl::initJIT(const std::strin return true; } +std::string DrlEMImpl::getJITLibFromCmdLine(const std::string& jitName) const { + std::string propName = std::string("em.")+jitName+".jitPath"; + std::string jitLib = vm_get_property_value(propName.c_str()); + if (jitLib.empty()) { + jitLib = vm_get_property_value("em.jitPath"); + } + return jitLib; +} + void DrlEMImpl::buildChains(std::string& config) { bool loggingEnabled = is_info_enabled(LOG_DOMAIN); StringList chainNames = getParamAsList(config, "chains", ',', true); @@ -387,16 +387,20 @@ void DrlEMImpl::buildChains(std::string& StringList jitsInChain= getParamAsList(config, chainName + ".jits", ',', true); for (StringList::const_iterator jitIt = jitsInChain.begin(), jitEnd = jitsInChain.end(); jitIt!=jitEnd; ++jitIt) { std::string jitName= *jitIt; - std::string libName = getParam(config, jitName+".file"); - if (libName.empty()) { - ECHO(("EM: No JIT library specified for JIT :'" + jitName+ "'").c_str()); + std::string jitLib = getJITLibFromCmdLine(jitName); + if (jitLib.empty()) { + jitLib = getParam(config, jitName+".file"); + } + if (jitLib.empty()) { + ECHO(("EM: No JIT library specified for JIT :'" + jitLib + "'").c_str()); failed = true; break; } + std::string fullJitLibPath = prepareLibPath(jitLib); apr_dso_handle_t* libHandle; - JIT_Handle jh = vm_load_jit(libName.c_str(), &libHandle); //todo: do not load the same dll twice!!! + JIT_Handle jh = vm_load_jit(fullJitLibPath.c_str(), &libHandle); //todo: do not load the same dll twice!!! if (jh == NULL) { - ECHO(("EM: JIT library loading error:'" + libName + "'").c_str()); + ECHO(("EM: JIT library loading error:'" + fullJitLibPath + "'").c_str()); failed = true; break; } @@ -404,7 +408,7 @@ void DrlEMImpl::buildChains(std::string& step->loggingEnabled = loggingEnabled || is_info_enabled(step->catName.c_str()); chain->steps.push_back(step); - if (!initJIT(libName, libHandle, *step)) { + if (!initJIT(fullJitLibPath, libHandle, *step)) { failed = true; break; } @@ -515,12 +519,13 @@ ProfileCollector* DrlEMImpl::createProfi return NULL; } std::string profilerType = getParam(config, profilerName+".profilerType"); - if (profilerType!="ENTRY_BACKEDGE_PROFILER") { + if (profilerType!=ENTRY_BACKEDGE_PROFILER_STR && profilerType!=EDGE_PROFILER_STR) { ECHO("EM: Unsupported profiler type"); return NULL; } EBProfileCollector::EB_ProfilerMode ebMode = EBProfileCollector::EB_PCMODE_SYNC; - std::string mode = getParam(config, profilerName+".mode"); + std::string mode = profilerType==EDGE_PROFILER_STR ? "ASYNC" : getParam(config, profilerName+".mode"); + if (mode == "ASYNC") { ebMode = EBProfileCollector::EB_PCMODE_ASYNC; } else if (mode!="SYNC") { @@ -552,7 +557,11 @@ ProfileCollector* DrlEMImpl::createProfi return NULL; } } + if (profilerType == EDGE_PROFILER_STR) { + pc = new EdgeProfileCollector(this, profilerName, step->jit, tbsInitialTimeout, tbsTimeout, eThreshold, bThreshold); + } else { pc = new EBProfileCollector(this, profilerName, step->jit, ebMode, eThreshold, bThreshold, tbsInitialTimeout, tbsTimeout); + } return pc; } @@ -720,7 +729,7 @@ void DrlEMImpl::tbsTimeout() { int DrlEMImpl::getTbsTimeout() const { - return 100; -} + return 100; +} + - diff --git vm/em/src/DrlEMImpl.h vm/em/src/DrlEMImpl.h index a8f260e..94af23c 100644 --- vm/em/src/DrlEMImpl.h +++ vm/em/src/DrlEMImpl.h @@ -96,18 +96,20 @@ public: virtual bool needTbsThreadSupport() const; virtual void tbsTimeout(); - virtual int getTbsTimeout() const; + virtual int getTbsTimeout() const; //EM PC access interface ProfileCollector* getProfileCollector(EM_PCTYPE type, JIT_Handle jh, EM_JIT_PC_Role jitRole) const; private: void initProfileAccess(); + std::string readConfiguration(); void buildChains(std::string& config); bool initJIT(const std::string& libName, apr_dso_handle_t* libHandle, RStep& step); bool initProfileCollectors(RChain* chain, const std::string& config); ProfileCollector* createProfileCollector(const std::string& profilerName, const std::string& config, RStep* step); ProfileCollector* getProfileCollector(const std::string& name) const; + std::string getJITLibFromCmdLine(const std::string& jitName) const; void deallocateResources(); @@ -115,6 +117,7 @@ private: JIT_Handle jh; void (*_execute_method) (JIT_Handle jit, jmethodID method, jvalue *return_value, jvalue *args); bool interpreterMode; + bool jitTiMode; RChains chains; size_t nMethodsCompiled, nMethodsRecompiled; diff --git vm/em/src/EdgeProfileCollector.cpp vm/em/src/EdgeProfileCollector.cpp new file mode 100644 index 0000000..07e0e53 --- /dev/null +++ vm/em/src/EdgeProfileCollector.cpp @@ -0,0 +1,270 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Jack Liu, Mikhail Y. Fursov, Chen-Dong Yuan +* @version $Revision$ +*/ + +#include "EdgeProfileCollector.h" + +#include +#include +#include "cxxlog.h" +#include + +#define LOG_DOMAIN "em" + +Method_Profile_Handle edge_profiler_create_profile( PC_Handle ph, + Method_Handle mh, + uint32 numCounters, + uint32* counterKeys, + uint32 checkSum ) +{ + ProfileCollector* pc = (ProfileCollector*)ph; + assert(pc->type == EM_PCTYPE_EDGE); + + EdgeMethodProfile* profile = + ((EdgeProfileCollector*)pc)->createProfile(mh, numCounters, counterKeys, checkSum); + return (Method_Profile_Handle)profile; +} + +void* edge_profiler_get_entry_counter_addr(Method_Profile_Handle mph) { + MethodProfile* mp = (MethodProfile*)mph; + assert(mp->pc->type == EM_PCTYPE_EDGE); + EdgeMethodProfile* emp = (EdgeMethodProfile*)mp; + return &emp->entryCounter; +} + +void* edge_profiler_get_counter_addr(Method_Profile_Handle mph, uint32 key) +{ + MethodProfile* mp = (MethodProfile*)mph; + assert(mp->pc->type == EM_PCTYPE_EDGE); + return ((EdgeMethodProfile*)mp)->getCounter( key ); +} + + +uint32 edge_profiler_get_num_counters(Method_Profile_Handle mph) +{ + MethodProfile* mp = (MethodProfile*)mph; + assert(mp->pc->type == EM_PCTYPE_EDGE); + return ((EdgeMethodProfile*)mp)->counters.size(); +} + + +uint32 edge_profiler_get_checksum(Method_Profile_Handle mph) +{ + MethodProfile* mp = (MethodProfile*)mph; + assert(mp->pc->type == EM_PCTYPE_EDGE); + return ((EdgeMethodProfile*)mp)->checkSum; +} + +uint32 edge_profiler_get_entry_threshold(PC_Handle pch) { + assert(pch!=NULL); + ProfileCollector* pc = (ProfileCollector*)pch; + assert(pc->type == EM_PCTYPE_EDGE); + return ((EdgeProfileCollector*)pc)->getEntryThreshold(); +} + +uint32 edge_profiler_get_backedge_threshold(PC_Handle pch) { + assert(pch!=NULL); + ProfileCollector* pc = (ProfileCollector*)pch; + assert(pc->type == EM_PCTYPE_EDGE); + return ((EdgeProfileCollector*)pc)->getBackedgeThreshold(); +} + + + + +EdgeProfileCollector::EdgeProfileCollector(EM_PC_Interface* em, const std::string& name, JIT_Handle genJit, + uint32 _initialTimeout, uint32 _timeout, + uint32 _eThreshold, uint32 _bThreshold) + : ProfileCollector(em, name, EM_PCTYPE_EDGE, genJit), initialTimeout(_initialTimeout), + timeout(_timeout),eThreshold(_eThreshold), bThreshold(_bThreshold) +{ + hymutex_create(&profilesLock, TM_MUTEX_NESTED); + catName = std::string(LOG_DOMAIN) + ".profiler." + name; + loggingEnabled = is_info_enabled(LOG_DOMAIN) || is_info_enabled(catName.c_str()); + if (loggingEnabled) { + std::ostringstream msg; + msg<< "EM: edge profiler intialized: "<second; + delete profile; + } + hymutex_destroy(profilesLock); +} + + +MethodProfile* EdgeProfileCollector::getMethodProfile(Method_Handle mh) const +{ + EdgeProfilesMap::const_iterator it = profilesByMethod.find(mh); + if (it == profilesByMethod.end()) { + return NULL; + } + return it->second; +} + + + +uint32* EdgeMethodProfile::getCounter( uint32 key ) const +{ + //log2 search + EdgeMap::const_iterator it = lower_bound(cntMap.begin(), cntMap.end(), key); + assert(it!=cntMap.end()); + uint32 val = *it; + if (val!=key) { + return NULL; + } + uint32 idx = it - cntMap.begin(); + return (uint32*)&counters.front() + idx; +} + +void EdgeMethodProfile::dump( const char* banner ) +{ + const char* methodName = method_get_name(mh); + Class_Handle ch = method_get_class(mh); + const char* className = class_get_name(ch); + const char* signature = method_get_descriptor(mh); + uint32 backEdgeCounter = entryCounter; + uint32 instrCost = entryCounter; + + assert( banner != NULL ); + + fprintf( stderr, "%s: %s::%s%s\n", banner, className, methodName, signature ); + + for( uint32 i = 0; i < counters.size(); i++ ){ + instrCost += counters[i]; + if( counters[i] > backEdgeCounter ){ + backEdgeCounter = counters[i]; + } + } + + assert( instrCost >= backEdgeCounter ); + + fprintf( stderr, "\t%s entry: %d\tcounters: %d\tbackedge: %d\tcost: %u\n", + _isHot ? "hot" : "cold", + entryCounter, counters.size(), backEdgeCounter, instrCost ); + + return; +} + + +EdgeMethodProfile* EdgeProfileCollector::createProfile( Method_Handle mh, + uint32 numCounters, + uint32* counterKeys, + uint32 checkSum) +{ + hymutex_lock(profilesLock); + + EdgeMethodProfile* profile = new EdgeMethodProfile(this, mh); + + // Allocate space for edge counters. + assert( profile->cntMap.empty() ); + profile->counters.resize(numCounters); + profile->checkSum = checkSum; + profile->cntMap.insert(profile->cntMap.begin(), counterKeys, counterKeys + numCounters); + std::sort(profile->cntMap.begin(), profile->cntMap.end()); + + assert(std::adjacent_find(profile->cntMap.begin(), profile->cntMap.end())==profile->cntMap.end()); + assert(profilesByMethod.find(mh) == profilesByMethod.end()); + profilesByMethod[mh] = profile; + newProfiles.push_back(profile); + + hymutex_unlock(profilesLock); + + return profile; +} + + +bool EdgeProfileCollector::isMethodHot( EdgeMethodProfile* profile ) +{ + uint32 entryCounter = profile->entryCounter; + if( entryCounter >= eThreshold ){ + return true; + } + + const uint32 cutoff = bThreshold; + + for( uint32 i = 0; i < profile->counters.size(); i++ ){ + if( profile->counters[i] >= cutoff ){ + return true; + } + } + + return false; +} + + +static void logReadyProfile(const std::string& catName, const std::string& profilerName, EdgeMethodProfile* mp) { + const char* methodName = method_get_name(mp->mh); + Class_Handle ch = method_get_class(mp->mh); + const char* className = class_get_name(ch); + const char* signature = method_get_descriptor(mp->mh); + + uint32 backEgdeMaxValue = mp->counters.empty() ? 0 : *std::max_element( mp->counters.begin(), mp->counters.end()); + std::ostringstream msg; + msg <<"EM: profiler["<entryCounter<<" b:"<::iterator it = greenProfiles.begin(); + std::vector::iterator end = greenProfiles.end(); + + while( it != end ){ + EdgeMethodProfile* profile = *it; + + if( isMethodHot( profile ) ){ + profile->setHotMethod(); + tmpProfiles.push_back(profile); + *it = NULL; + } + it++; + } + + if (!tmpProfiles.empty()) { + std::remove(greenProfiles.begin(), greenProfiles.end(), (EdgeMethodProfile*)NULL); + greenProfiles.resize(greenProfiles.size() - tmpProfiles.size()); + for (std::vector::iterator it = tmpProfiles.begin(), end = tmpProfiles.end(); it!=end; ++it) { + EdgeMethodProfile* profile = *it; + if (loggingEnabled) { + logReadyProfile(catName, name, profile); + } + em->methodProfileIsReady(profile); + } + tmpProfiles.clear(); + } + + return; +} diff --git vm/em/src/EdgeProfileCollector.h vm/em/src/EdgeProfileCollector.h new file mode 100644 index 0000000..11a5a40 --- /dev/null +++ vm/em/src/EdgeProfileCollector.h @@ -0,0 +1,101 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Jack Liu, Mikhail Y. Fursov, Chen-Dong Yuan +* @version $Revision$ +*/ + +#ifndef _EDGE_PROFILE_COLLECTOR_H_ +#define _EDGE_PROFILE_COLLECTOR_H_ + +#include "DrlProfileCollectionFramework.h" +#include "open/vm_util.h" + +#include +#include + +class EdgeMethodProfile; + +class EdgeProfileCollector : public ProfileCollector, public TbsEMClient { +public: + EdgeProfileCollector(EM_PC_Interface* em, const std::string& name, JIT_Handle genJit, + uint32 _initialTimeout, uint32 _timeout, + uint32 _eThreshold, uint32 _bThreshold); + virtual ~EdgeProfileCollector(); + + virtual TbsEMClient* getTbsEmClient() const {return (TbsEMClient*)this;} + + virtual uint32 getInitialTimeout() const {return initialTimeout;} + virtual uint32 getTimeout() const {return timeout;} + virtual void onTimeout(); + + MethodProfile* getMethodProfile(Method_Handle mh) const ; + EdgeMethodProfile* createProfile(Method_Handle mh, uint32 numCounters, uint32* counterKeys, uint32 checkSum); + + uint32 getEntryThreshold() const {return eThreshold;} + uint32 getBackedgeThreshold() const {return bThreshold;} + + +private: + uint32 initialTimeout; + uint32 timeout; + uint32 eThreshold; + uint32 bThreshold; + bool loggingEnabled; + std::string catName; + + bool isMethodHot( EdgeMethodProfile* profile ); + typedef std::map EdgeProfilesMap; + EdgeProfilesMap profilesByMethod; + std::vector greenProfiles; + std::vector newProfiles; + std::vector tmpProfiles; + hymutex_t profilesLock; +}; + +class EdgeMethodProfile : public MethodProfile { +private: + typedef std::vector EdgeMap; +public: + EdgeMethodProfile(EdgeProfileCollector* pc, Method_Handle mh) + : MethodProfile(pc, mh), entryCounter(0), + checkSum(0), _isHot(false) {} + + void dump( const char* banner ); + void setHotMethod() { _isHot = true; } + bool isHot() const { return _isHot; } + uint32* getCounter( uint32 key ) const; + + uint32 entryCounter; // point to the method entry counter + std::vector counters; + EdgeMap cntMap; // map to a counter, given a key + + uint32 checkSum; // checksum provided by instrumentation + +private: + bool _isHot; +}; + + +Method_Profile_Handle edge_profiler_create_profile(PC_Handle ph, Method_Handle mh, uint32 numCounters, uint32* counterKeys, uint32 checkSum); +uint32 edge_profiler_get_num_counters(Method_Profile_Handle mph); +uint32 edge_profiler_get_checksum(Method_Profile_Handle mph); +void* edge_profiler_get_entry_counter_addr(Method_Profile_Handle mph); +void* edge_profiler_get_counter_addr(Method_Profile_Handle mph, uint32 key); +uint32 edge_profiler_get_entry_threshold(PC_Handle pch); +uint32 edge_profiler_get_backedge_threshold(PC_Handle pch); + +#endif diff --git vm/em/src/em_intf.cpp vm/em/src/em_intf.cpp index 479c832..d808cb3 100644 --- vm/em/src/em_intf.cpp +++ vm/em/src/em_intf.cpp @@ -51,7 +51,7 @@ CompileMethod(Method_Handle method_handl static void ProfilerThreadTimeout() { - DrlEMFactory::getEMInstance()->tbsTimeout(); + DrlEMFactory::getEMInstance()->tbsTimeout(); } static const char* @@ -66,7 +66,7 @@ GetEmVersion() { static const char* GetDescription() { - return "Execution manager supports Jitrino.JET, Jitrino.OPT and dynamic recompilation"; + return "Execution manager ..."; } static const char* diff --git vm/include/interpreter.h vm/include/interpreter.h index 80275ae..8606100 100644 --- vm/include/interpreter.h +++ vm/include/interpreter.h @@ -21,10 +21,9 @@ #ifndef _INTERPRETER_H_ #define _INTERPRETER_H_ #include "Class.h" -#include "exception.h" +#include "stack_trace.h" #include "interpreter_exports.h" - extern bool interpreter_enabled(); #define ASSERT_NO_INTERPRETER assert(!interpreter_enabled()); diff --git vm/include/interpreter_exports.h vm/include/interpreter_exports.h index 0e8ac5d..9df6fe1 100644 --- vm/include/interpreter_exports.h +++ vm/include/interpreter_exports.h @@ -23,10 +23,18 @@ #define _INTERPRETER_EXPORTS_H_ #include "open/types.h" #include "jvmti.h" +typedef struct FrameHandle FrameHandle; + typedef struct { bool (*interpreter_st_get_frame) (unsigned target_depth, struct StackTraceFrame* stf); - void (*interpreter_st_get_trace) (unsigned* res_depth, struct StackTraceFrame** stfs); + void (*interpreter_st_get_trace) (class VM_thread *thread, unsigned* res_depth, struct StackTraceFrame** stfs); void (*interpreter_enumerate_thread) (class VM_thread *thread); + + FrameHandle* (*interpreter_get_last_frame) (class VM_thread *thread); + FrameHandle* (*interpreter_get_prev_frame) (FrameHandle* frame); + // 'end' is not inclusive + bool (*is_frame_in_native_frame) (struct FrameHandle* frame, void* begin, void* end); + #ifdef _IPF_ uint64* (*interpreter_get_stacked_register_address) (uint64* bsp, unsigned reg); #endif @@ -42,8 +50,6 @@ #endif jvmtiError (*interpreter_ti_setLocal64) ( jvmtiEnv*, class VM_thread*, int, int, int64); jvmtiError (*interpreter_ti_setObject) ( jvmtiEnv*, class VM_thread*, int, int, struct _jobject *); unsigned int (*interpreter_st_get_interrupted_method_native_bit) (class VM_thread *); - void (*interpreter_st_get_interrupted_method) (struct Method**, int64 *); - void (*interpreter_st_get_catch_method) (struct Method**, int64 *, struct _jobject *); // Open interfaces part begins diff --git vm/include/interpreter_imports.h vm/include/interpreter_imports.h index 5fbde03..4cce319 100644 --- vm/include/interpreter_imports.h +++ vm/include/interpreter_imports.h @@ -27,9 +27,12 @@ struct ManagedObject; typedef struct ManagedObject ManagedObject; VMEXPORT void vm_monitor_enter_wrapper(ManagedObject *obj); VMEXPORT void vm_monitor_exit_wrapper(ManagedObject *obj); +VMEXPORT void class_throw_linking_error_for_interpreter(Class_Handle ch, + unsigned cp_index, unsigned opcode); + VMEXPORT struct JNIEnv_Internal* get_jni_native_intf(); -VMEXPORT void* jvmti_process_breakpoint_event(jmethodID method, jlocation loc); +VMEXPORT void* jvmti_process_interpreter_breakpoint_event(jmethodID method, jlocation loc); VMEXPORT void jvmti_process_single_step_event(jmethodID method, jlocation location); VMEXPORT void jvmti_process_frame_pop_event(jvmtiEnv *env, diff --git vm/include/jit_intf.h vm/include/jit_intf.h index e514efc..8857731 100644 --- vm/include/jit_intf.h +++ vm/include/jit_intf.h @@ -251,6 +251,9 @@ VMEXPORT Boolean class_get_array_ VMEXPORT ClassLoaderHandle class_get_class_loader(Class_Handle c); VMEXPORT void +class_throw_linking_error_for_jit(Class_Handle ch, unsigned cp_index, unsigned opcode); + +void class_throw_linking_error(Class_Handle ch, unsigned cp_index, unsigned opcode); VMEXPORT Class_Handle @@ -304,6 +307,8 @@ VMEXPORT const char *const_pool_get_int VMEXPORT unsigned thread_get_suspend_request_offset(); +VMEXPORT unsigned thread_get_thread_state_flag_offset(); //temporary: for EscapeAnalysis prototype + VMEXPORT Compile_Handle jit_get_comp_handle(JIT_Handle j); // Needed for DLL problems diff --git vm/include/jit_runtime_support.h vm/include/jit_runtime_support.h index 0727ac7..ddd2558 100644 --- vm/include/jit_runtime_support.h +++ vm/include/jit_runtime_support.h @@ -190,7 +190,7 @@ enum VM_RT_SUPPORT { // Acquire the monitor associated with the object. // Throw java/lang/NullPointerException if the argument is null. - VM_RT_MONITOR_ENTER_NO_EXC=304, + VM_RT_MONITOR_ENTER_NON_NULL=304, // Arguments: // - Object // Return value: none. @@ -357,6 +357,29 @@ enum VM_RT_SUPPORT { // This call-back should be used to notify about method exit event. // Do a call-back when such capability is requested only. + VM_RT_JVMTI_FIELD_ACCESS_CALLBACK = 702, + // Arguments: + // - handle of the field under access + // - handle of the method, which accesses field + // - location of code which accesses field + // - pointer to the reference of the object, which field is beeng + // accessed or NULL for static field + // Return value: none + // + // Notifies about field access. + + VM_RT_JVMTI_FIELD_MODIFICATION_CALLBACK = 703, + // Arguments: + // - handle of the field under modification + // - handle of the method, which modifies field + // - location of code which modifies field + // - pointer to the reference of the object, which field is beeng + // modified or NULL for static field + // - pointer to the new value for the field + // Return value: none + // + // Notifies about field modification. + ////////////////////////////////////////////////////////////////////////// // Runtime resolution routine ////////////////////////////////////////////////////////////////////////// diff --git vm/include/open/em_profile_access.h vm/include/open/em_profile_access.h index 5d5580d..4d0f91e 100644 --- vm/include/open/em_profile_access.h +++ vm/include/open/em_profile_access.h @@ -27,23 +27,59 @@ #ifdef __cplusplus extern "C" { #endif +/** + * Known profiler types. Each of the profilers + * is represented with separate interface to + * create and to access to profiles. + */ enum EM_PCTYPE { - EM_PCTYPE_ENTRY_BACKEDGE=1 + /** Entry-backedge profiler + * Collects number execution counts for + * methods entries and backedges if present. + */ + EM_PCTYPE_ENTRY_BACKEDGE=1, + /** Edge profiler. + * Collects profile for method entry and + * all edges in IR Control Flow Graph + */ + EM_PCTYPE_EDGE=2 }; +/** A EM interface used to access to profile collectos*/ typedef struct EM_ProfileAccessInterface { + /** Request profile collector typ for specified profile collector handle + * @param _this - EM instance profile collector belongs to + * @param pc - profile collector handle we interested in + * @return - the type of profile collector + */ EM_PCTYPE (*get_pc_type) ( EM_Handle _this, PC_Handle pc ); + /** Request method profile from profile collector + * @param _this - EM instance profile collector belongs to + * @param pc - profile collector used to collect profile + * @param mh - method we asking profile for + * @return - method profile handle, that can be used to access + * to custom method profile properties with + * specialized profile collector interface + */ Method_Profile_Handle (*get_method_profile)( EM_Handle _this, PC_Handle pc, Method_Handle mh ); + /** Request profile collector of specified type and role for a JIT + * @param _this - EM instance profile collector belongs to + * @param profile_type - the type of profile collector + * @param jh - handle to JIT, profile collector created for. + * @param jit_role - the role of JIT: the user or supplier of profile + * @return - the handle to profile collector instance + */ + PC_Handle (*get_pc)( EM_Handle _this, EM_PCTYPE profile_type, @@ -52,32 +88,95 @@ typedef struct EM_ProfileAccessInterface ); - //to be moved to separate ENTRY-BACKAGE profile interface-struct in OPEN - //EB (entry-backedge) profile collector interface - // method to create new EB profile. This method fill if called twice - // for the same pair of (profile collector, method handle) + // Here follows entry-backedge and edge profilers interfaces. + // All methods below could be moved into separate EB and Edge + // profiler collectors specific files. + + /** Create new entry-backedge profile for a method + * Only one profile per method can be created for a single + * profile collector instance + */ Method_Profile_Handle (*eb_profiler_create_profile) (PC_Handle ph, Method_Handle mh); - // the address of entry counter - // JIT must generate a code to increment this counter on every method call + /** Request the address of entry counter + * JIT configured to generate entry-backedge profile must + * emit the code to increment this counter every time a method called + */ void* (*eb_profiler_get_entry_counter_addr)(Method_Profile_Handle mph); - // the address of backedge counter - // JIT must generate a code to increment this counter on every backedge + /** Request the address of backedge counter + * JIT configured to generate entry-backedge profile must + * emit the code to increment this counter every time any backedge in + * a method is called + */ void* (*eb_profiler_get_backedge_counter_addr)(Method_Profile_Handle mph); - // EB profile collector supports both synchronous (in-user-threads) - // and asynchronous (em-helper-thread)method profile checks. - // JIT must use this method to check the profile collector mode + /** Check if entry-backedge profiler is configured to work in synchronous mode + * In synchronous mode JIT is responsible to emit checks that counter's limit + * is reached for both entry and backedge counters. If limit is reached + * eb_profiler_sync_mode_callback must be called directly from managed code + * In asynchronous mode counters checks are done by profile collector in a + * separate thread. + * @see eb_profiler_sync_mode_callback() + */ char (*eb_profiler_is_in_sync_mode)(PC_Handle pch); + /** If profile collector is in 'sync' mode (@see eb_profiler_is_in_sync_mode()) + * JIT must call this method every time the counter limit is reached + */ void (*eb_profiler_sync_mode_callback)(Method_Profile_Handle mph); + /** Return the counter's limit for entry threshold for a given + * profile collector + */ uint32 (*eb_profiler_get_entry_threshold)(PC_Handle pch); + /** Return the counter's limit for backedge threshold for a given + * profile collector + */ uint32 (*eb_profiler_get_backedge_threshold)(PC_Handle pch); + + + //EDGE profiler interface + + /** Create an edge profile for a method. + * Only one profile per method can be created for a single + * profile collector instance + * @param ph - edge profile collector handle + * @param mh - method handle to create profile for + * @param numEdgeCounters - number of edge counters in a method + * @param counterKeys - the keys, or numbers, will be associated with + * each counter. The key must be used to access to + * counter value + * @param checksum - profile checksum + * @return - a handle to access method profile data + */ + Method_Profile_Handle (*edge_profiler_create_profile) (PC_Handle ph, Method_Handle mh, uint32 numEdgeCounters, uint32* counterKeys, uint32 checkSum); + + + /** Return number of edge counters in profile */ + uint32 (*edge_profiler_get_num_counters)(Method_Profile_Handle mph); + + /** Return profile checksum*/ + uint32 (*edge_profiler_get_checksum)(Method_Profile_Handle mph); + + /** Return the address of counter assosiated with key*/ + void* (*edge_profiler_get_counter_addr)(Method_Profile_Handle mph, uint32 key); + + /** Return the address of entry counter*/ + void* (*edge_profiler_get_entry_counter_addr)(Method_Profile_Handle mph); + + /** Return the entry threshold for profile collector + */ + uint32 (*edge_profiler_get_entry_threshold)(PC_Handle pch); + + /** Return the edge threshold for profile collector + */ + uint32 (*edge_profiler_get_backedge_threshold)(PC_Handle pch); + + } EM_ProfileAccessInterface; diff --git vm/include/open/em_vm_intf.h vm/include/open/em_vm_intf.h deleted file mode 100644 index 7709522..0000000 --- vm/include/open/em_vm_intf.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Mikhail Y. Fursov - * @version $Revision: 1.1.2.1.4.4 $ - */ -#ifndef _EM_VM_H_ -#define _EM_VM_H_ - -#include "open/types.h" -#include "open/em.h" -#include "jni_types.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -EMEXPORT char EM_init (); - -EMEXPORT void EM_deinit(); - -EMEXPORT void EM_execute_method(jmethodID meth, jvalue *return_value, jvalue *args); - -EMEXPORT JIT_Result EM_compile_method(Method_Handle method_handle); - -EMEXPORT char EM_need_profiler_thread_support(); - -EMEXPORT void EM_profiler_thread_timeout(); - -EMEXPORT int EM_get_profiler_thread_timeout(); - -#ifdef __cplusplus -} -#endif - - -#endif - diff --git vm/include/open/gc.h vm/include/open/gc.h index 10b40e7..38d07d7 100644 --- vm/include/open/gc.h +++ vm/include/open/gc.h @@ -584,6 +584,7 @@ extern void (*gc_test_safepoint)(); extern void (*gc_pin_object)(Managed_Object_Handle* p_object); extern void (*gc_unpin_object)(Managed_Object_Handle* p_object); +extern int32 (*gc_get_hashcode0) (Managed_Object_Handle p_object); extern Managed_Object_Handle (*gc_get_next_live_object)(void *iterator); extern void (*gc_finalize_on_exit)(); @@ -740,6 +741,11 @@ GCExport void gc_pin_object (Managed_Obj GCExport void gc_unpin_object (Managed_Object_Handle* p_object); /** + * * Get object hashcode + * */ +GCExport int32 gc_get_hashcode (Managed_Object_Handle p_object); + +/** * Iterate all live objects in heap. * Should be use only in classloader for class unloading purposes. */ diff --git vm/include/open/hythread_ext.h vm/include/open/hythread_ext.h index f4543cc..4d00917 100644 --- vm/include/open/hythread_ext.h +++ vm/include/open/hythread_ext.h @@ -132,7 +132,7 @@ typedef struct HyThreadGroup *hythread_g typedef struct HyThread *hythread_iterator_t; typedef struct HyThreadLibrary *hythread_library_t; -typedef IDATA hythread_thin_monitor_t; +typedef I_32 hythread_thin_monitor_t; typedef void (*hythread_event_callback_proc)(void); @@ -147,9 +147,6 @@ typedef void (*hythread_event_callback_p IDATA VMCALL hythread_global_lock(); IDATA VMCALL hythread_global_unlock(); void VMCALL hythread_init (hythread_library_t lib); -IDATA VMCALL hythread_shutdown(); -IDATA VMCALL hythread_wait_for_all_nondaemon_threads(); -UDATA* VMCALL hythread_global (char* name); //@} /** @name Basic manipulation @@ -196,7 +193,7 @@ IDATA VMCALL hycond_destroy (hycond_t co void hythread_suspend_enable(); void hythread_suspend_disable(); void hythread_safe_point(); -void VMCALL hythread_suspend_other(hythread_t thread); + IDATA VMCALL hythread_suspend_other(hythread_t thread); IDATA VMCALL hythread_set_safepoint_callback(hythread_t thread, hythread_event_callback_proc callback); hythread_event_callback_proc VMCALL hythread_get_safepoint_callback(hythread_t t); @@ -235,13 +232,10 @@ IDATA VMCALL hythread_iterator_size(hyth //@{ IDATA hysem_create(hysem_t *sem, UDATA initial_count, UDATA max_count); -IDATA VMCALL hysem_wait(hysem_t sem); IDATA VMCALL hysem_wait_timed(hysem_t sem, I_64 ms, IDATA nano); IDATA VMCALL hysem_wait_interruptable(hysem_t sem, I_64 ms, IDATA nano); IDATA VMCALL hysem_getvalue(IDATA *count, hysem_t sem); IDATA hysem_set(hysem_t sem, IDATA count); -IDATA VMCALL hysem_post(hysem_t sem); -IDATA VMCALL hysem_destroy(hysem_t sem); //@} /** @name Mutex diff --git vm/include/open/vm.h vm/include/open/vm.h index 6fc9285..60e83f5 100644 --- vm/include/open/vm.h +++ vm/include/open/vm.h @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Intel, Alexei Fedotov * @version $Revision: 1.1.2.2.4.3 $ - */ + */ // @@ -63,6 +63,10 @@ typedef struct ChaMethodIterator { // java.lang.Object. VMEXPORT Class_Handle get_system_object_class(); +// Returns a handle for the class class. For Java applications, it's +// java.lang.Class. +VMEXPORT Class_Handle get_system_class_class(); + // Returns a handle for the string class. For Java applications, it's // java.lang.String. VMEXPORT Class_Handle get_system_string_class(); @@ -319,6 +323,32 @@ VMEXPORT Boolean field_is_volatile(Field // Returns TRUE if the field is private. VMEXPORT Boolean field_is_private(Field_Handle fh); +/** + * Returns the address and bit mask, for the flag which determine whether field + * access event should be sent. JIT may use the following expression to + * determine if specified field access should be tracked: + * ( **address & *mask != 0 ) + * @param field - handle of the field + * @param[out] address - pointer to the address of the byte which contains the flag + * @param[out] mask - pointer to the bit mask of the flag + */ +VMEXPORT void +field_get_track_access_flag(Field_Handle field, char** address, char* mask); + +/** + * Returns the address and bit mask, for the flag which determine whether field + * modification event should be sent. JIT may use the following expression to + * determine if specified field modification should be tracked: + * ( **address & *mask != 0 ) + * @param field - handle of the field + * @param[out] address - pointer to the address of the byte which contains the flag + * @param[out] mask - pointer to the bit mask of the flag + */ +VMEXPORT void +field_get_track_modification_flag(Field_Handle field, char** address, + char* mask); + + // end field-related functions. ///////////////////////////////////////////////////////////////// @@ -389,7 +419,7 @@ VMEXPORT Boolean method_is_require_secur // and query the type of the method result. VMEXPORT Method_Signature_Handle method_get_signature(Method_Handle mh); -// Class ch is a subclass of method_get_class(mh). The function returns a method handle +// Class ch is a subclass of method_get_class(mh). The function returns a method handle // for an accessible method overriding mh in ch or in its closest superclass that overrides mh. // Class ch must be a class not an interface. VMEXPORT Method_Handle method_find_overridden_method(Class_Handle ch, Method_Handle mh); @@ -507,7 +537,7 @@ VMEXPORT Boolean type_info_is_unboxed(Ty // type_info_is_unboxed-->type_info_get_class-->class_is_primitive). VMEXPORT Boolean type_info_is_primitive(Type_Info_Handle tih); -// If TRUE, then +// If TRUE, then // type_info_get_type_info returns the type info that the pointer // points to. VMEXPORT Boolean type_info_is_unmanaged_pointer(Type_Info_Handle tih); @@ -528,7 +558,7 @@ VMEXPORT Boolean type_info_is_vector(Typ VMEXPORT Boolean type_info_is_general_array(Type_Info_Handle tih); // Get the class if type_info_is_reference or type_info_is_unboxed -// returned TRUE. If the type info is a vector or a general array, return the +// returned TRUE. If the type info is a vector or a general array, return the // class handle for the array type (not the element type). VMEXPORT Class_Handle type_info_get_class(Type_Info_Handle tih); @@ -559,7 +589,7 @@ VMEXPORT VM_Data_Type type_info_get_type // begin vector layout functions. // Vectors are one-dimensional, zero-based arrays. All Java "arrays" are -// vectors. +// vectors. // Functions provided in this section do not work on multidimensional or // non-zero based arrays (i.e. arrays with a lower bound that is non-zero // for at least one of the dimensions. @@ -620,7 +650,7 @@ VMEXPORT unsigned vm_vector_size(Class_H // begin miscellaneous functions. -// Returns TRUE if references within objects and vector elements are +// Returns TRUE if references within objects and vector elements are // to be treated as offsets rather than raw pointers. VMEXPORT Boolean vm_references_are_compressed(); @@ -658,11 +688,32 @@ VMEXPORT void free_string_buffer(char *b // command line argument. VMEXPORT const char *vm_get_property_value(const char *property_name); +VMEXPORT void vm_properties_set_value(const char* name, const char* value); + +typedef void *PropertiesIteratorHandle; + +// Create iterator for system properties. +// All iterators created with this method call +// must be destroyed with vm_properties_iterator_destroy +VMEXPORT PropertiesIteratorHandle vm_properties_iterator_create(); + +// Destroy iterator created by vm_properties_iterator_create +VMEXPORT void vm_properties_iterator_destroy(PropertiesIteratorHandle props_iter); + +// Advance iterator to a next property. +// Return false if no more properties left to iterate +VMEXPORT Boolean vm_properties_iterator_advance(PropertiesIteratorHandle props_iter); + +// Return a name of the current property +VMEXPORT const char* vm_properties_get_name(PropertiesIteratorHandle props_iter); + +// Return a value of the current property +VMEXPORT const char* vm_properties_get_string_value(PropertiesIteratorHandle props_iter); + // Return the boolean value of the property VMEXPORT Boolean vm_get_property_value_boolean(const char* property, Boolean default_value); -VMEXPORT Boolean vm_get_boolean_property_value_with_default( - const char *property_name); +VMEXPORT Boolean vm_get_boolean_property_value_with_default(const char *property_name); // Exit and perform the necessary cleanup. VMEXPORT void vm_exit(int exit_code); diff --git vm/include/open/vm_util.h vm/include/open/vm_util.h index 837e4ca..235ae71 100644 --- vm/include/open/vm_util.h +++ vm/include/open/vm_util.h @@ -45,27 +45,6 @@ typedef struct String String; // #include "object_layout.h" #include "vm_threads.h" -// This class encapsulates a set of OS/HW specific registers associated with a thread. -class VmRegisterContext -{ -public: - VmRegisterContext(); - ~VmRegisterContext(); - enum ContextFlag { - CF_FloatingPoint, - CF_Integer, - CF_Control, - CF_Debug, - CF_Segment - }; - void setFlag(ContextFlag flag); - void getContext(VM_thread *thread); - void setContext(VM_thread *thread); - void getBspAndRnat(VM_thread* p_thr, uint64** bspstore, uint64* rnat); // for IPF only -private: - void *_pcontext; // this would be a pointer to CONTEXT on NT -}; - VMEXPORT void vm_exit(int exit_code); unsigned sizeof_java_lang_class(); diff --git vm/interpreter/src/interp_defs.h vm/interpreter/src/interp_defs.h index 4580c9a..1175797 100644 --- vm/interpreter/src/interp_defs.h +++ vm/interpreter/src/interp_defs.h @@ -223,7 +223,6 @@ struct StackFrame { StackFrame *prev; FramePopListener *framePopListener; ManagedObject *This; - ManagedObject *exception; struct MonitorList *locked_monitors; struct MonitorList *free_monitors; PopFrameState jvmti_pop_frame; @@ -234,6 +233,8 @@ #ifdef INTERPRETER_DEEP_DEBUG uint8 last_bytecodes[8]; int n_last_bytecode; #endif + ManagedObject *exc; + ManagedObject *exc_catch; }; /********* PROTOTYPES ********/ @@ -252,6 +253,10 @@ extern void interpreter_execute_method( void method_entry_callback(Method *method); void method_exit_callback(Method *method, bool was_popped_by_exception, jvalue ret_val); void method_exit_callback_with_frame(Method *method, StackFrame& frame); +void putfield_callback(Field *field, StackFrame& frame); +void getfield_callback(Field *field, StackFrame& frame); +void putstatic_callback(Field *field, StackFrame& frame); +void getstatic_callback(Field *field, StackFrame& frame); void frame_pop_callback(FramePopListener *l, Method *method, jboolean was_popped_by_exception); void single_step_callback(StackFrame &frame); bool findExceptionHandler(StackFrame& frame, ManagedObject **exception, Handler **h); @@ -418,7 +423,10 @@ enum interpreter_ti_events { INTERPRETER_TI_METHOD_ENTRY_EVENT = 1, INTERPRETER_TI_METHOD_EXIT_EVENT = 2, INTERPRETER_TI_SINGLE_STEP_EVENT = 4, - INTERPRETER_TI_POP_FRAME_EVENT = 8 + INTERPRETER_TI_POP_FRAME_EVENT = 8, + INTERPRETER_TI_FIELD_ACCESS = 16, + INTERPRETER_TI_FIELD_MODIFICATION = 32, + INTERPRETER_TI_OTHER = 64 /* EXCEPTION, EXCEPTION_CATCH */ }; /** diff --git vm/interpreter/src/interp_exports.cpp vm/interpreter/src/interp_exports.cpp index d6fe255..9d613ae 100644 --- vm/interpreter/src/interp_exports.cpp +++ vm/interpreter/src/interp_exports.cpp @@ -79,9 +79,7 @@ extern jvmtiError interpreter_ti_setObje extern unsigned int interpreter_st_get_interrupted_method_native_bit(class VM_thread *); extern void interpreter_enumerate_thread(class VM_thread *); -extern void interpreter_st_get_interrupted_method(struct Method * *,int64 *); -extern void interpreter_st_get_catch_method(struct Method * *,int64 *,struct _jobject *); -extern void interpreter_st_get_trace(unsigned int *,struct StackTraceFrame * *); +extern void interpreter_st_get_trace(VM_thread *thread, unsigned int *,struct StackTraceFrame * *); uint64* interpreter_get_stacked_register_address(uint64* bsp, unsigned reg); extern void interpreter_execute_method(Method *method, jvalue *return_value, jvalue *args); @@ -91,12 +89,20 @@ extern void interpreter_ti_clear_breakpo extern jvmtiError interpreter_ti_pop_frame(jvmtiEnv*, VM_thread *thread); extern void stack_dump(VM_thread *thread); +extern FrameHandle* interpreter_get_last_frame(class VM_thread *thread); +extern FrameHandle* interpreter_get_prev_frame(FrameHandle* frame); +extern bool is_frame_in_native_frame(FrameHandle* frame, void* begin, void* end); + void EXPORT JIT_init(JIT_Handle UNREF h, const char* UNREF name) { Interpreter *interpreter = interpreter_table(); interpreter->interpreter_st_get_frame = &interpreter_st_get_frame; interpreter->interpreter_st_get_trace = &interpreter_st_get_trace; interpreter->interpreter_enumerate_thread = &interpreter_enumerate_thread; + + interpreter->interpreter_get_last_frame = &interpreter_get_last_frame; + interpreter->interpreter_get_prev_frame = &interpreter_get_prev_frame; + interpreter->is_frame_in_native_frame = &is_frame_in_native_frame; #ifdef _IPF_ interpreter->interpreter_get_stacked_register_address = &interpreter_get_stacked_register_address; #endif @@ -110,8 +116,6 @@ #endif interpreter->interpreter_ti_setLocal64 = &interpreter_ti_setLocal64; interpreter->interpreter_ti_setObject = &interpreter_ti_setObject; interpreter->interpreter_st_get_interrupted_method_native_bit = &interpreter_st_get_interrupted_method_native_bit; - interpreter->interpreter_st_get_interrupted_method = &interpreter_st_get_interrupted_method; - interpreter->interpreter_st_get_catch_method = &interpreter_st_get_catch_method; interpreter->interpreter_ti_set_notification_mode = &interpreter_ti_set_notification_mode; interpreter->interpreter_ti_set_breakpoint = &interpreter_ti_set_breakpoint; interpreter->interpreter_ti_clear_breakpoint = &interpreter_ti_clear_breakpoint; diff --git vm/interpreter/src/interp_native_em64t.cpp vm/interpreter/src/interp_native_em64t.cpp index a435158..663db8f 100644 --- vm/interpreter/src/interp_native_em64t.cpp +++ vm/interpreter/src/interp_native_em64t.cpp @@ -22,10 +22,10 @@ #include "interpreter.h" #include "interpreter_exports.h" #include "interpreter_imports.h" -#include "find_natives.h" +//#include "find_natives.h" #include "exceptions.h" #include "mon_enter_exit.h" - +#include "open/jthread.h" #include "interp_native.h" #include "interp_defs.h" #include "ini.h" @@ -84,7 +84,7 @@ interpreter_execute_native_method( return; } M2N_ALLOC_MACRO; - tmn_suspend_enable(); + hythread_suspend_enable(); int sz = method->get_num_arg_bytes() >> 2; @@ -192,7 +192,7 @@ interpreter_execute_native_method( switch(ret_type) { case JAVA_TYPE_VOID: invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -201,7 +201,7 @@ interpreter_execute_native_method( case JAVA_TYPE_STRING: { jobject obj = (jobject) invokeJNI_Obj(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); ManagedObject *ref = obj->object; M2N_FREE_MACRO; ObjectHandle new_handle = oh_allocate_local_handle(); @@ -216,25 +216,25 @@ interpreter_execute_native_method( case JAVA_TYPE_SHORT: case JAVA_TYPE_INT: resultPtr->i = invokeJNI_Int(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_FLOAT: resultPtr->f = invokeJNI_Float(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_LONG: resultPtr->j = invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_DOUBLE: resultPtr->d = invokeJNI_Double(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -255,12 +255,12 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - tmn_suspend_disable(); + hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -409,22 +409,22 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { vm_monitor_enter_wrapper(frame.This); } - tmn_suspend_enable(); + hythread_suspend_enable(); switch(method->get_return_java_type()) { case JAVA_TYPE_VOID: { invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -434,7 +434,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject **ref = invokeJNI_Ref(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -461,7 +461,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -472,7 +472,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -483,7 +483,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -495,7 +495,7 @@ #endif { Value res; res.i = invokeJNI_Int(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -507,7 +507,7 @@ #endif { Value res; res.f = invokeJNI_Float(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -519,7 +519,7 @@ #endif { Value2 res; res.i64 = invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -531,7 +531,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -692,22 +692,22 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { vm_monitor_enter_wrapper(frame.This); } - tmn_suspend_enable(); + hythread_suspend_enable(); switch(method->get_return_java_type()) { case JAVA_TYPE_VOID: { invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -717,7 +717,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject ** ref = invokeJNI_Ref(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -745,7 +745,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -756,7 +756,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -767,7 +767,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -779,7 +779,7 @@ #endif { Value res; res.i = invokeJNI_Int(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -791,7 +791,7 @@ #endif { Value res; res.f = invokeJNI_Float(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -803,7 +803,7 @@ #endif { Value2 res; res.i64 = invokeJNI(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -815,7 +815,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(out_args, n_fps, n_stacks, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); diff --git vm/interpreter/src/interp_native_ia32.cpp vm/interpreter/src/interp_native_ia32.cpp index 42dddd9..6a78c01 100644 --- vm/interpreter/src/interp_native_ia32.cpp +++ vm/interpreter/src/interp_native_ia32.cpp @@ -94,7 +94,7 @@ interpreter_execute_native_method( } M2N_ALLOC_MACRO; - tmn_suspend_enable(); + hythread_suspend_enable(); int sz = method->get_num_arg_bytes() >> 2; uword *arg_words = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword)); @@ -171,7 +171,7 @@ interpreter_execute_native_method( switch(ret_type) { case JAVA_TYPE_VOID: invokeJNI(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -180,7 +180,7 @@ interpreter_execute_native_method( case JAVA_TYPE_STRING: { jobject obj = (jobject) invokeJNI_Obj(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); ManagedObject *ref = obj->object; M2N_FREE_MACRO; ObjectHandle new_handle = oh_allocate_local_handle(); @@ -195,25 +195,25 @@ interpreter_execute_native_method( case JAVA_TYPE_SHORT: case JAVA_TYPE_INT: resultPtr->i = invokeJNI_Int(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_FLOAT: resultPtr->f = invokeJNI_Float(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_LONG: resultPtr->j = invokeJNI(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_DOUBLE: resultPtr->d = invokeJNI_Double(arg_words, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -234,12 +234,12 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - tmn_suspend_disable(); + hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -339,22 +339,22 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { vm_monitor_enter_wrapper(frame.This); } - tmn_suspend_enable(); + hythread_suspend_enable(); switch(method->get_return_java_type()) { case JAVA_TYPE_VOID: { invokeJNI(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -364,7 +364,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject **ref = invokeJNI_Ref(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -391,7 +391,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -402,7 +402,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -413,7 +413,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -425,7 +425,7 @@ #endif { Value res; res.i = invokeJNI_Int(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -437,7 +437,7 @@ #endif { Value res; res.f = invokeJNI_Float(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -449,7 +449,7 @@ #endif { Value2 res; res.i64 = invokeJNI(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -461,7 +461,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -578,22 +578,22 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { vm_monitor_enter_wrapper(frame.This); } - tmn_suspend_enable(); + hythread_suspend_enable(); switch(method->get_return_java_type()) { case JAVA_TYPE_VOID: { invokeJNI(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -603,7 +603,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject ** ref = invokeJNI_Ref(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -631,7 +631,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -642,7 +642,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -653,7 +653,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -665,7 +665,7 @@ #endif { Value res; res.i = invokeJNI_Int(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -677,7 +677,7 @@ #endif { Value res; res.f = invokeJNI_Float(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -689,7 +689,7 @@ #endif { Value2 res; res.i64 = invokeJNI(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -701,7 +701,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(args, argId, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); diff --git vm/interpreter/src/interp_native_ipf.cpp vm/interpreter/src/interp_native_ipf.cpp index 99fa9c4..33dbe0b 100644 --- vm/interpreter/src/interp_native_ipf.cpp +++ vm/interpreter/src/interp_native_ipf.cpp @@ -85,7 +85,7 @@ interpreter_execute_native_method( } M2N_ALLOC_MACRO; - tmn_suspend_enable(); + hythread_suspend_enable(); int sz = method->get_num_arg_bytes() >> 2; uword *arg_words = (uword*) ALLOC_FRAME((sz + 2) * sizeof(uword)); @@ -184,7 +184,7 @@ interpreter_execute_native_method( switch(ret_type) { case JAVA_TYPE_VOID: invokeJNI(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -193,7 +193,7 @@ interpreter_execute_native_method( case JAVA_TYPE_STRING: { jobject obj = (jobject) invokeJNI_Obj(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); ManagedObject *ref = obj->object; M2N_FREE_MACRO; ObjectHandle new_handle = oh_allocate_local_handle(); @@ -208,25 +208,25 @@ interpreter_execute_native_method( case JAVA_TYPE_SHORT: case JAVA_TYPE_INT: resultPtr->i = invokeJNI_Int(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_FLOAT: resultPtr->f = invokeJNI_Float(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_LONG: resultPtr->j = invokeJNI(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; case JAVA_TYPE_DOUBLE: resultPtr->d = invokeJNI_Double(arg_words, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); M2N_FREE_MACRO; break; @@ -248,12 +248,12 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - tmn_suspend_disable(); + hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -375,9 +375,9 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { @@ -390,7 +390,7 @@ #endif } - tmn_suspend_enable(); + hythread_suspend_enable(); DEBUG("invokeJNI: 1\n"); @@ -398,7 +398,7 @@ #endif case JAVA_TYPE_VOID: { invokeJNI(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -408,7 +408,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject **ref = invokeJNI_Ref(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); CREF cr; @@ -441,7 +441,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -452,7 +452,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -463,7 +463,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -475,7 +475,7 @@ #endif { Value res; res.i = invokeJNI_Int(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -487,7 +487,7 @@ #endif { Value res; res.f = invokeJNI_Float(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -499,7 +499,7 @@ #endif { Value2 res; res.i64 = invokeJNI(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -511,7 +511,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -652,9 +652,9 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - tmn_suspend_enable(); + hythread_suspend_enable(); method_entry_callback(method); - tmn_suspend_disable(); + hythread_suspend_disable(); } if (method->is_synchronized()) { @@ -666,7 +666,7 @@ #endif frameSize = -((((argId - 8) + 1) & ~1) << 3); } - tmn_suspend_enable(); + hythread_suspend_enable(); DEBUG("invokeJNI: 2\n"); @@ -674,7 +674,7 @@ #endif case JAVA_TYPE_VOID: { invokeJNI(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); } break; @@ -684,7 +684,7 @@ #endif case JAVA_TYPE_STRING: { ManagedObject ** ref = invokeJNI_Ref(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); CREF cr; @@ -718,7 +718,7 @@ #endif case JAVA_TYPE_BYTE: { int8 res = invokeJNI_Byte(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -729,7 +729,7 @@ #endif case JAVA_TYPE_CHAR: { uint16 res = invokeJNI_Char(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -740,7 +740,7 @@ #endif case JAVA_TYPE_SHORT: { int16 res = invokeJNI_Short(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -752,7 +752,7 @@ #endif { Value res; res.i = invokeJNI_Int(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -764,7 +764,7 @@ #endif { Value res; res.f = invokeJNI_Float(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(); @@ -776,7 +776,7 @@ #endif { Value2 res; res.i64 = invokeJNI(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); @@ -788,7 +788,7 @@ #endif { Value2 res; res.d = invokeJNI_Double(args, fpargs, argId, frameSize, f); - tmn_suspend_disable(); + hythread_suspend_disable(); prevFrame.stack.popClearRef(sz); prevFrame.stack.push(2); diff --git vm/interpreter/src/interp_stack_trace.cpp vm/interpreter/src/interp_stack_trace.cpp index e094d6c..4868cb7 100644 --- vm/interpreter/src/interp_stack_trace.cpp +++ vm/interpreter/src/interp_stack_trace.cpp @@ -102,8 +102,8 @@ interpreter_st_get_frame(unsigned target } static inline unsigned -interp_st_get_depth() { - StackIterator_interp* si = interp_si_create_from_native(); +interp_st_get_depth(VM_thread *p_thread) { + StackIterator_interp* si = interp_si_create_from_native(p_thread); unsigned depth = 0; while (!interp_si_is_past_end(si)) { if (interp_si_get_method(si)) @@ -114,55 +114,6 @@ interp_st_get_depth() { return depth; } -void -interpreter_st_get_interrupted_method(Method ** method_ptr, jlocation *location_ptr) { - - StackFrame *frame = getLastStackFrame(); - - *method_ptr = NULL; - *location_ptr = 0; - - if (frame){ - *method_ptr = frame->method; - *location_ptr = frame->ip - (uint8*)(*method_ptr)->get_byte_code_addr(); - } - } - -void -interpreter_st_get_catch_method(Method ** method_ptr, - jlocation *location_ptr, jobject exn) { - StackFrame *frame = NULL; - StackIterator_interp* si = interp_si_create_from_native(); - *method_ptr = NULL; - *location_ptr = 0; - - while(!interp_si_is_past_end(si)){ - frame = (StackFrame*) si; - if( frame->method->is_native()) - { - interp_si_goto_previous(si); - continue; - } - Handler *h; - - if(findExceptionHandler(*frame, &exn->object, &h)) { - *method_ptr = frame->method; - *location_ptr = frame->ip - (uint8*)(*method_ptr)->get_byte_code_addr(); - break; - } - - if (frame->exception) { - // FIXME: needs investigation, very specific condition - *method_ptr = NULL; - *location_ptr = 0; - frame->exception = NULL; - break; - } - - interp_si_goto_previous(si); - } -} - unsigned interpreter_st_get_interrupted_method_native_bit(VM_thread *thread) { StackIterator_interp* si = interp_si_create_from_native(thread); @@ -173,14 +124,14 @@ interpreter_st_get_interrupted_method_na return method -> is_native(); } -/*extern*/ void -interpreter_st_get_trace(unsigned* res_depth, StackTraceFrame** stfs) { - unsigned depth = interp_st_get_depth(); +void +interpreter_st_get_trace(VM_thread *p_vmthread, unsigned* res_depth, StackTraceFrame** stfs) { + unsigned depth = interp_st_get_depth(p_vmthread); StackTraceFrame* stf = st_alloc_frames(depth); assert(stf); *res_depth = depth; *stfs = stf; - StackIterator_interp* si = interp_si_create_from_native(); + StackIterator_interp* si = interp_si_create_from_native(p_vmthread); depth = 0; while (!interp_si_is_past_end(si)) { Method_Handle method = interp_si_get_method(si); @@ -220,15 +171,13 @@ interp_enumerate_root_set_single_thread_ method = method; if (si->This) { - ASSERT_OBJECT(si->This); vm_enumerate_root_reference((void**)&si->This, FALSE); DEBUG_GC(" [THIS]: " << si->This->vt()->clss->name->bytes << endl); } - if (si->exception) { - ASSERT_OBJECT(si->exception); - vm_enumerate_root_reference((void**)&si->exception, FALSE); - DEBUG_GC(" [EXCEPTION]: " << si->exception->vt()->clss->name->bytes << endl); + if (si->exc) { + vm_enumerate_root_reference((void**)&si->exc, FALSE); + DEBUG_GC(" [THIS]: " << si->exc->vt()->clss->name->bytes << endl); } if (method->is_native()) { @@ -255,7 +204,6 @@ interp_enumerate_root_set_single_thread_ DEBUG_GC("NULL"); } else { DEBUG_GC(obj->vt()->clss->name->bytes << endl); - ASSERT_OBJECT(UNCOMPRESS_REF(*cref)); vm_enumerate(cref, FALSE); } } @@ -272,14 +220,12 @@ interp_enumerate_root_set_single_thread_ DEBUG_GC("NULL\n"); } else { DEBUG_GC(obj->vt()->clss->name->bytes << endl); - ASSERT_OBJECT(UNCOMPRESS_REF(*cref)); vm_enumerate(cref, FALSE); } } } MonitorList *ml = si->locked_monitors; while(ml) { - ASSERT_OBJECT(ml->monitor); vm_enumerate_root_reference((void**)&ml->monitor, FALSE); ml = ml->next; } diff --git vm/interpreter/src/interp_vm_helpers.cpp vm/interpreter/src/interp_vm_helpers.cpp index 8a73fb4..6891a35 100644 --- vm/interpreter/src/interp_vm_helpers.cpp +++ vm/interpreter/src/interp_vm_helpers.cpp @@ -25,32 +25,34 @@ #include "compile.h" #include "cxxlog.h" #include "interp_defs.h" -void interp_throw_exception(const char* exc) { +void interp_throw_exception(const char* exc_name) { M2N_ALLOC_MACRO; assert(!hythread_is_suspend_enabled()); - tmn_suspend_enable(); + hythread_suspend_enable(); assert(hythread_is_suspend_enabled()); - throw_java_exception(exc); - tmn_suspend_disable(); + jthrowable exc_object = exn_create(exc_name); + exn_raise_object(exc_object); + hythread_suspend_disable(); M2N_FREE_MACRO; } -void interp_throw_exception(const char* exc, const char *message) { +void interp_throw_exception(const char* exc_name, const char* exc_message) { M2N_ALLOC_MACRO; assert(!hythread_is_suspend_enabled()); - tmn_suspend_enable(); + hythread_suspend_enable(); assert(hythread_is_suspend_enabled()); - throw_java_exception(exc, message); - tmn_suspend_disable(); + jthrowable exc_object = exn_create(exc_name, exc_message); + exn_raise_object(exc_object); + hythread_suspend_disable(); M2N_FREE_MACRO; } GenericFunctionPointer interp_find_native(Method_Handle method) { - tmn_suspend_enable(); + hythread_suspend_enable(); GenericFunctionPointer f = classloader_find_native((Method_Handle) method); - tmn_suspend_disable(); + hythread_suspend_disable(); return f; } @@ -61,12 +63,12 @@ Class* interp_resolve_class(Class *clazz handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Class *objClass = resolve_class((Compile_Handle*)&handle, clazz, classId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!objClass) { if (!exn_raised()) - class_throw_linking_error(clazz, classId, 0); + class_throw_linking_error_for_interpreter(clazz, classId, 0); } return objClass; @@ -78,12 +80,12 @@ Class* interp_resolve_class_new(Class *c handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Class *objClass = resolve_class_new((Compile_Handle*)&handle, clazz, classId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!objClass) { if (!exn_raised()) - class_throw_linking_error(clazz, classId, OPCODE_NEW); + class_throw_linking_error_for_interpreter(clazz, classId, OPCODE_NEW); } return objClass; @@ -96,13 +98,13 @@ Field* interp_resolve_static_field(Class handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Field *field = resolve_static_field((Compile_Handle*)&handle, clazz, fieldId, putfield); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!field) { if (!exn_raised()) - class_throw_linking_error(clazz, fieldId, + class_throw_linking_error_for_interpreter(clazz, fieldId, putfield?OPCODE_PUTSTATIC:OPCODE_GETSTATIC); } return field; @@ -114,13 +116,13 @@ Field* interp_resolve_nonstatic_field(Cl handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Field *field = resolve_nonstatic_field( (Compile_Handle*)&handle, clazz, fieldId, putfield); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!field) { if (!exn_raised()) - class_throw_linking_error(clazz, fieldId, + class_throw_linking_error_for_interpreter(clazz, fieldId, putfield?OPCODE_PUTFIELD:OPCODE_GETFIELD); } return field; @@ -133,14 +135,14 @@ Method* interp_resolve_virtual_method(Cl handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); assert(hythread_is_suspend_enabled()); Method *method = resolve_virtual_method( (Compile_Handle*)&handle, clazz, methodId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!method) { if (!exn_raised()) - class_throw_linking_error(clazz, methodId, OPCODE_INVOKEVIRTUAL); + class_throw_linking_error_for_interpreter(clazz, methodId, OPCODE_INVOKEVIRTUAL); } return method; } @@ -151,14 +153,14 @@ Method* interp_resolve_interface_method( handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); assert(hythread_is_suspend_enabled()); Method *method = resolve_interface_method( (Compile_Handle*)&handle, clazz, methodId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!method) { if (!exn_raised()) - class_throw_linking_error(clazz, methodId, OPCODE_INVOKEINTERFACE); + class_throw_linking_error_for_interpreter(clazz, methodId, OPCODE_INVOKEINTERFACE); } return method; } @@ -169,13 +171,13 @@ Method *interp_resolve_static_method(Cla handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Method *method = resolve_static_method( (Compile_Handle*)&handle, clazz, methodId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!method) { if (!exn_raised()) - class_throw_linking_error(clazz, methodId, OPCODE_INVOKESTATIC); + class_throw_linking_error_for_interpreter(clazz, methodId, OPCODE_INVOKESTATIC); } return method; } @@ -186,20 +188,20 @@ Method *interp_resolve_special_method(Cl handle.env = VM_Global_State::loader_env; handle.jit = 0; - tmn_suspend_enable(); + hythread_suspend_enable(); Method *method = resolve_special_method( (Compile_Handle*)&handle, clazz, methodId); - tmn_suspend_disable(); + hythread_suspend_disable(); if (!method) { if (!exn_raised()) - class_throw_linking_error(clazz, methodId, OPCODE_INVOKESPECIAL); + class_throw_linking_error_for_interpreter(clazz, methodId, OPCODE_INVOKESPECIAL); } return method; } Class* interp_class_get_array_of_class(Class *objClass) { - tmn_suspend_enable(); + hythread_suspend_enable(); Class *clazz = class_get_array_of_class(objClass); - tmn_suspend_disable(); + hythread_suspend_disable(); return clazz; } diff --git vm/interpreter/src/interpreter.cpp vm/interpreter/src/interpreter.cpp index 9be8456..86b9abf 100644 --- vm/interpreter/src/interpreter.cpp +++ vm/interpreter/src/interpreter.cpp @@ -20,6 +20,7 @@ #include "interpreter_imports.h" #include #include "exceptions.h" +#include "exceptions_int.h" #include "vm_arrays.h" #include "vm_strings.h" #include "jit_runtime_support_common.h" @@ -31,6 +32,7 @@ #include "ini.h" #include "compile.h" #include "thread_manager.h" +#include // ppervov: HACK: allows using STL modifiers (dec/hex) and special constants (endl) using namespace std; @@ -136,14 +138,14 @@ static void throwNPE() { interp_throw_exception("java/lang/NullPointerException"); } -static void throwAME() { +static void throwAME(const char *msg) { DEBUG("****** AbstractMethodError ******\n"); - interp_throw_exception("java/lang/AbstractMethodError"); + interp_throw_exception("java/lang/AbstractMethodError", msg); } -static void throwIAE() { +static void throwIAE(const char *msg) { DEBUG("****** IllegalAccessError ******\n"); - interp_throw_exception("java/lang/IllegalAccessError"); + interp_throw_exception("java/lang/IllegalAccessError", msg); } static inline void @@ -711,21 +713,21 @@ Opcode_D2I(StackFrame& frame) { Value2 arg; Value res; arg = frame.stack.getLong(0); - if (arg.d < 2147483647.) { - if (arg.d > -2147483648.) { - res.i = (int32) arg.d; - } else { - res.i = (int32)2147483648u; - } + + int64 val = arg.i64; + int64 exponent = val & ((int64)0x7FF << 52); + int64 max_exp = ((int64)0x3FF + 31) << 52; + + if (exponent < max_exp) { + res.i = (int) arg.d; } else { - if (arg.d >= 2147483647.) { - // +inf + if (arg.d > 0) { res.i = (int32)2147483647; } else { - // nan - res.i = 0; + res.i = (int32)2147483648u; } } + frame.stack.pop(); frame.stack.pick() = res; frame.ip++; @@ -735,19 +737,17 @@ static inline void Opcode_F2I(StackFrame& frame) { Value& arg = frame.stack.pick(0); - if (arg.f < 2147483647.f) { - if (arg.f > -2147483648.f) { - arg.i = (int32) arg.f; - } else { - arg.i = (int32)2147483648u; - } + int val = arg.i; + int exponent = val & (0xFF << 23); + int max_exp = (0x7F + 31) << 23; + + if (exponent < max_exp) { + arg.i = (int32) arg.f; } else { - if (arg.f >= 2147483647.f) { - // +inf + if (arg.f > 0) { arg.i = (int32)2147483647; } else { - // nan - arg.i = 0; + arg.i = (int32)2147483648u; } } frame.ip++; @@ -758,21 +758,21 @@ Opcode_D2L(StackFrame& frame) { Value2 arg; Value2 res; arg = frame.stack.getLong(0); - if (arg.d <= 4611686018427387903.) { - if (arg.d >= -4611686018427387904.) { - res.i64 = (int64) arg.d; - } else { - res.i64 = ((int64)-1) << 63; // 80000...... - } + + int64 val = arg.i64; + int64 exponent = val & ((int64)0x7FF << 52); + int64 max_exp = ((int64)0x3FF + 63) << 52; + + if (exponent < max_exp) { + res.i64 = (int64) arg.d; } else { - if (arg.d > 4611686018427387903.) { - // +inf - res.i64 = -((((int64)-1) << 63) + 1); // 7FFFF..... + if (arg.d > 0) { + res.i64 = (int64)(((uint64)(int64)-1) >> 1); // 7FFFF...... } else { - // nan - res.i64 = 0; + res.i64 = ((int64)-1) << 63; // 80000...... } } + frame.stack.setLong(0, res); frame.ip++; } @@ -782,21 +782,21 @@ Opcode_F2L(StackFrame& frame) { Value arg; Value2 res; arg = frame.stack.pick(0); - if (arg.f <= 4611686018427387903.) { - if (arg.f >= -4611686018427387904.) { - res.i64 = (int64) arg.f; - } else { - res.i64 = ((int64)-1) << 63; // 80000...... - } + + int val = arg.i; + int exponent = val & (0xFF << 23); + int max_exp = (0x7F + 63) << 23; + + if (exponent < max_exp) { + res.i64 = (int64) arg.f; } else { - if (arg.f > 4611686018427387903.) { - // +inf - res.i64 = -((((int64)-1) << 63) + 1); // 7FFFF..... + if (arg.f > 0) { + res.i64 = (int64)(((uint64)(int64)-1) >> 1); // 7FFFF...... } else { - // nan - res.i64 = 0; + res.i64 = ((int64)-1) << 63; // 80000...... } } + frame.stack.push(); frame.stack.setLong(0, res); frame.ip++; @@ -979,7 +979,7 @@ #endif // FIXME: only compressed references frame.stack.pick().cr = COMPRESS_REF(vm_instantiate_cp_string_resolved(str)); frame.stack.ref() = FLAG_OBJECT; - return !exn_raised(); + return !check_current_thread_exception(); } else if (cp_is_class(cp, index)) { @@ -1071,7 +1071,7 @@ Opcode_NEWARRAY(StackFrame& frame) { } Vector_Handle array = vm_new_vector_primitive(clazz,length); - if (exn_raised()) { + if (check_current_thread_exception()) { // OutOfMemoryError occured return; } @@ -1102,7 +1102,7 @@ Opcode_ANEWARRAY(StackFrame& frame) { Vector_Handle array = vm_new_vector(arrayClass, length); - if (exn_raised()) { + if (check_current_thread_exception()) { // OutOfMemoryError occured return; } @@ -1154,7 +1154,7 @@ allocDimensions(StackFrame& frame, Class // init root element ManagedObject* array = (ManagedObject*) vm_new_vector(clss[0], length[0]); - if (exn_raised()) { + if (check_current_thread_exception()) { // OutOfMemoryError occured return false; } @@ -1166,7 +1166,7 @@ allocDimensions(StackFrame& frame, Class // allocation dimensions while(true) { ManagedObject *element = (ManagedObject*) vm_new_vector(clss[d], length[d]); - if (exn_raised()) { + if (check_current_thread_exception()) { // OutOfMemoryError occured return false; } @@ -1231,13 +1231,13 @@ Opcode_NEW(StackFrame& frame) { class_initialize(objClass); - if (exn_raised()) { + if (check_current_thread_exception()) { return; } ManagedObject *obj = class_alloc_new_object(objClass); - if (exn_raised()) { + if (check_current_thread_exception()) { // OutOfMemoryError occured return; } @@ -1589,19 +1589,27 @@ static inline void Opcode_PUTSTATIC(StackFrame& frame) { uint32 fieldId = read_uint16(frame.ip + 1); Class *clazz = frame.method->get_class(); - + Field *field = interp_resolve_static_field(clazz, fieldId, true); if (!field) return; // exception - + + // FIXME: is it possible to move the code into !cp_is_resolved condition above? class_initialize(field->get_class()); - if (exn_raised()) { + if (check_current_thread_exception()) { return; } + if (interpreter_ti_notification_mode + & INTERPRETER_TI_FIELD_MODIFICATION) { + Method *method = frame.method; + putstatic_callback(field, frame); + } + + if (field->is_final()) { if (frame.method->get_class()->state != ST_Initializing) { - throwIAE(); + throwIAE(field_get_name(field)); return; } } @@ -1680,12 +1688,19 @@ Opcode_GETSTATIC(StackFrame& frame) { Field *field = interp_resolve_static_field(clazz, fieldId, false); if (!field) return; // exception + // FIXME: is it possible to move the code into !cp_is_resolved condition above? class_initialize(field->get_class()); - if (exn_raised()) { + if (check_current_thread_exception()) { return; } + if (interpreter_ti_notification_mode + & INTERPRETER_TI_FIELD_ACCESS) { + Method *method = frame.method; + getstatic_callback(field, frame); + } + void *addr = field->get_address(); frame.stack.push(); @@ -1752,9 +1767,15 @@ Opcode_PUTFIELD(StackFrame& frame) { Field *field = interp_resolve_nonstatic_field(clazz, fieldId, true); if (!field) return; // exception + if (interpreter_ti_notification_mode + & INTERPRETER_TI_FIELD_MODIFICATION) { + Method *method = frame.method; + putfield_callback(field, frame); + } + if (field->is_final()) { if (!frame.method->is_init()) { - throwIAE(); + throwIAE(field_get_name(field)); return; } } @@ -1915,6 +1936,12 @@ Opcode_GETFIELD(StackFrame& frame) { Field *field = interp_resolve_nonstatic_field(clazz, fieldId, false); if (!field) return; // exception + if (interpreter_ti_notification_mode + & INTERPRETER_TI_FIELD_ACCESS) { + Method *method = frame.method; + getfield_callback(field, frame); + } + CREF cref = frame.stack.pick(0).cr; if (cref == 0) { throwNPE(); @@ -2036,9 +2063,10 @@ Opcode_INVOKESTATIC(StackFrame& frame) { << method->get_name()->bytes << "/" << method->get_descriptor()->bytes << endl); + // FIXME: is it possible to move the code into !cp_is_resolved condition above? class_initialize(method->get_class()); - if (exn_raised()) { + if (check_current_thread_exception()) { return; } @@ -2225,7 +2253,7 @@ Opcode_MONITOREXIT(StackFrame& frame) { vm_monitor_exit_wrapper(UNCOMPRESS_REF(cr)); M2N_FREE_MACRO; - if (get_current_thread_exception()) + if (check_current_thread_exception()) return; MonitorList *ml = frame.locked_monitors; @@ -2262,7 +2290,7 @@ Opcode_ATHROW(StackFrame& frame) { bool findExceptionHandler(StackFrame& frame, ManagedObject **exception, Handler **hh) { - assert(!exn_raised()); + assert(!check_current_thread_exception()); assert(!hythread_is_suspend_enabled()); Method *m = frame.method; @@ -2299,8 +2327,6 @@ findExceptionHandler(StackFrame& frame, if (!obj) { // possible if verifier is disabled - frame.exception = get_current_thread_exception(); - clear_current_thread_exception(); return false; } @@ -2325,6 +2351,28 @@ processExceptionHandler(StackFrame& fram return false; } +void +findCatchMethod(ManagedObject **exception, Method **catch_method, jlocation *catch_location) { + StackFrame *frame = getLastStackFrame(); + *catch_method = NULL; + *catch_location = 0; + + for(StackFrame *frame = getLastStackFrame(); frame; frame = frame->prev) { + Method *method = frame->method; + if (method->is_native()) continue; + + Handler *h; + + if(findExceptionHandler(*frame, exception, &h)) { + *catch_method = frame->method; + *catch_location = frame->ip - (uint8*)(*catch_method)->get_byte_code_addr(); + return; + } + clear_current_thread_exception(); + } +} + + static inline void stackDump(StackFrame& frame) { @@ -2404,15 +2452,13 @@ void method_exit_callback_with_frame(Method *method, StackFrame& frame) { NativeObjectHandles handles; - bool exc = exn_raised(); + bool exc = check_current_thread_exception(); jvalue val; val.j = 0; if (exc) { - hythread_suspend_enable(); method_exit_callback(method, true, val); - hythread_suspend_disable(); return; } @@ -2463,7 +2509,7 @@ interpreter(StackFrame &frame) { << frame.method->get_descriptor()->bytes << endl); M2N_ALLOC_MACRO; - assert(!exn_raised()); + assert(!check_current_thread_exception()); assert(!hythread_is_suspend_enabled()); uint8 *first = (uint8*) get_thread_ptr()->firstFrame; @@ -2481,16 +2527,15 @@ interpreter(StackFrame &frame) { } } + frame.ip = (uint8*) frame.method->get_byte_code_addr(); + if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { M2N_ALLOC_MACRO; - hythread_suspend_enable(); method_entry_callback(frame.method); - hythread_suspend_disable(); M2N_FREE_MACRO; } - frame.ip = (uint8*) frame.method->get_byte_code_addr(); if (frame.method->is_synchronized()) { MonitorList *ml = (MonitorList*) ALLOC_FRAME(sizeof(MonitorList)); frame.locked_monitors = ml; @@ -2505,7 +2550,6 @@ interpreter(StackFrame &frame) { } while (true) { - ManagedObject *exc; uint8 ip0 = *frame.ip; DEBUG_BYTECODE(endl << "(" << frame.stack.getIndex() @@ -2525,6 +2569,11 @@ restart: & INTERPRETER_TI_SINGLE_STEP_EVENT) { single_step_callback(frame); } + assert(!exn_raised()); + if (get_thread_ptr()->p_exception_object_ti) { + frame.exc = get_current_thread_exception(); + goto got_exception; + } } #ifdef INTERPRETER_DEEP_DEBUG @@ -2532,6 +2581,8 @@ #ifdef INTERPRETER_DEEP_DEBUG #endif assert(!hythread_is_suspend_enabled()); + assert(&frame == getLastStackFrame()); + assert(!exn_raised()); switch(ip0) { case OPCODE_NOP: Opcode_NOP(frame); break; @@ -2711,7 +2762,7 @@ #endif case OPCODE_ATHROW: Opcode_ATHROW(frame); - exc = get_current_thread_exception(); + frame.exc = get_current_thread_exception(); goto got_exception; case OPCODE_MONITORENTER: @@ -2726,8 +2777,8 @@ #endif new_ml->monitor = NULL; frame.locked_monitors = new_ml; Opcode_MONITORENTER(frame); - exc = get_current_thread_exception(); - if (exc != 0) { + frame.exc = get_current_thread_exception(); + if (frame.exc != 0) { frame.locked_monitors = new_ml->next; new_ml->next = frame.free_monitors; frame.free_monitors = new_ml; @@ -2781,29 +2832,29 @@ #endif goto check_exception; case OPCODE_INVOKESTATIC: Opcode_INVOKESTATIC(frame); - exc = get_current_thread_exception(); - if (exc != 0) goto got_exception; + frame.exc = get_current_thread_exception(); + if (frame.exc != 0) goto got_exception; frame.ip += 3; break; case OPCODE_INVOKESPECIAL: Opcode_INVOKESPECIAL(frame); - exc = get_current_thread_exception(); - if (exc != 0) goto got_exception; + frame.exc = get_current_thread_exception(); + if (frame.exc != 0) goto got_exception; frame.ip += 3; break; case OPCODE_INVOKEVIRTUAL: Opcode_INVOKEVIRTUAL(frame); - exc = get_current_thread_exception(); - if (exc != 0) goto got_exception; + frame.exc = get_current_thread_exception(); + if (frame.exc != 0) goto got_exception; frame.ip += 3; break; case OPCODE_INVOKEINTERFACE: Opcode_INVOKEINTERFACE(frame); - exc = get_current_thread_exception(); - if (exc != 0) goto got_exception; + frame.exc = get_current_thread_exception(); + if (frame.exc != 0) goto got_exception; frame.ip += 5; break; @@ -2886,43 +2937,67 @@ #endif stackDump(frame); ABORT("Unexpected bytecode"); } + assert(&frame == getLastStackFrame()); continue; check_exception: - exc = get_current_thread_exception(); - if (exc == 0) continue; + frame.exc = get_current_thread_exception(); + if (frame.exc == 0) continue; got_exception: - if (get_thread_ptr()->ti_exception_callback_pending) { + assert(&frame == getLastStackFrame()); + clear_current_thread_exception(); - assert(exn_raised()); - assert(!hythread_is_suspend_enabled()); - jvmti_interpreter_exception_event_callback_call(); - assert(!hythread_is_suspend_enabled()); + if (interpreter_ti_notification_mode) { + frame.exc_catch = (ManagedObject*) get_thread_ptr()->p_exception_object_ti; + p_TLS_vmthread->p_exception_object_ti = NULL; - exc = get_current_thread_exception(); + if (frame.exc != frame.exc_catch) { - // is exception cleared in JVMTI? - if (!exc) continue; - } + Method *method = frame.method; + jlocation loc = frame.ip - method->get_byte_code_addr(); - frame.exception = exc; - clear_current_thread_exception(); + if (frame.exc_catch != NULL) { + + // EXCEPTION_CATCH should be generated for frame.exc_catch + jvmti_interpreter_exception_catch_event_callback_call( + frame.exc_catch, method, loc); + + assert(!exn_raised()); - if (processExceptionHandler(frame, &frame.exception)) { + // event is sent + frame.exc_catch = NULL; + + // if no pending exception continue execution + if (frame.exc == NULL) continue; + } + + // EXCEPTION event to be generated + assert(frame.exc); + Method *catch_method; + jlocation catch_location; + findCatchMethod(&frame.exc, &catch_method, &catch_location); + jvmti_interpreter_exception_event_callback_call(frame.exc, method, loc, catch_method, catch_location); + assert(!exn_raised()); + p_TLS_vmthread->p_exception_object_ti = (volatile ManagedObject*) frame.exc; + } + } + + if (processExceptionHandler(frame, &frame.exc)) { frame.stack.clear(); frame.stack.push(); - frame.stack.pick().cr = COMPRESS_REF(frame.exception); + frame.stack.pick().cr = COMPRESS_REF(frame.exc); frame.stack.ref() = FLAG_OBJECT; - frame.exception = 0; + frame.exc = NULL; continue; } - set_current_thread_exception(frame.exception); - p_TLS_vmthread->ti_exception_callback_pending = false; + + set_current_thread_exception(frame.exc); if (frame.locked_monitors) { vm_monitor_exit_wrapper(frame.locked_monitors->monitor); assert(!frame.locked_monitors->next); } + DEBUG_TRACE(" "); if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) @@ -2930,6 +3005,7 @@ got_exception: if (frame.framePopListener) frame_pop_callback(frame.framePopListener, frame.method, true); + M2N_FREE_MACRO; assert(!hythread_is_suspend_enabled()); return; @@ -3063,7 +3139,7 @@ #endif resultPtr->l = 0; //clear it } - if (exn_raised()) { + if (check_current_thread_exception()) { setLastStackFrame(frame.prev); DEBUG_TRACE(" interpreter_invoke }}}\n"); return; @@ -3167,7 +3243,7 @@ interpreterInvokeStatic(StackFrame& prev prevFrame.stack.popClearRef(args); - if (exn_raised()) { + if (check_current_thread_exception()) { setLastStackFrame(frame.prev); DEBUG_TRACE(" invoke_static }}}\n"); return; @@ -3256,7 +3332,7 @@ #endif prevFrame.stack.popClearRef(args); - if (exn_raised()) { + if (check_current_thread_exception()) { setLastStackFrame(frame.prev); return; } @@ -3315,7 +3391,10 @@ interpreterInvokeVirtual(StackFrame& pre method = objClass->vtable_descriptors[method->get_index()]; if (method->is_abstract()) { - throwAME(); + ostringstream str; + str << class_get_name(method_get_class(method)) << "." << + method_get_name(method) << method_get_descriptor(method); + throwAME(str.str().c_str()); return; } @@ -3359,12 +3438,18 @@ interpreterInvokeInterface(StackFrame& p method = found_method; if (method->is_abstract()) { - throwAME(); + ostringstream str; + str << class_get_name(method_get_class(method)) << "." << + method_get_name(method) << method_get_descriptor(method); + throwAME(str.str().c_str()); return; } if (!method->is_public()) { - throwIAE(); + ostringstream str; + str << class_get_name(method_get_class(method)) << "." << + method_get_name(method) << method_get_descriptor(method); + throwIAE(str.str().c_str()); return; } @@ -3390,7 +3475,10 @@ interpreterInvokeSpecial(StackFrame& pre } if (method->is_abstract()) { - throwAME(); + ostringstream str; + str << class_get_name(method_get_class(method)) << "." << + method_get_name(method) << method_get_descriptor(method); + throwAME(str.str().c_str()); return; } @@ -3441,7 +3529,7 @@ interpreterInvokeSpecial(StackFrame& pre prevFrame.stack.popClearRef(args); - if (exn_raised()) { + if (check_current_thread_exception()) { setLastStackFrame(frame.prev); DEBUG_TRACE(" invoke_special }}}\n"); return; diff --git vm/interpreter/src/interpreter_ti.cpp vm/interpreter/src/interpreter_ti.cpp index 79c98f4..90f3df7 100644 --- vm/interpreter/src/interpreter_ti.cpp +++ vm/interpreter/src/interpreter_ti.cpp @@ -175,7 +175,7 @@ interpreter_ti_getObject( } assert(hythread_is_suspend_enabled()); - tmn_suspend_disable(); + hythread_suspend_disable(); ManagedObject *obj = UNCOMPRESS_REF(frame->locals(slot).cr); if (NULL == obj) { *value_ptr = NULL; @@ -184,7 +184,7 @@ interpreter_ti_getObject( handle->object = obj; *value_ptr = (jobject) handle; } - tmn_suspend_enable(); + hythread_suspend_enable(); return JVMTI_ERROR_NONE; } @@ -354,7 +354,7 @@ uint8 Opcode_BREAKPOINT(StackFrame& frame) { Method *m = frame.method; jlocation l = frame.ip - (uint8*)m->get_byte_code_addr(); - return (uint8) (POINTER_SIZE_INT) jvmti_process_breakpoint_event((jmethodID)m, l); + return (uint8) (POINTER_SIZE_INT) jvmti_process_interpreter_breakpoint_event((jmethodID)m, l); } void* interpreter_ti_set_breakpoint(jmethodID method, jlocation location) { @@ -380,6 +380,10 @@ void interpreter_ti_set_notification_mod case JVMTI_EVENT_METHOD_ENTRY: new_mask = INTERPRETER_TI_METHOD_ENTRY_EVENT; break; case JVMTI_EVENT_METHOD_EXIT: new_mask = INTERPRETER_TI_METHOD_EXIT_EVENT; break; case JVMTI_EVENT_SINGLE_STEP: new_mask = INTERPRETER_TI_SINGLE_STEP_EVENT; break; + case JVMTI_EVENT_FIELD_ACCESS: new_mask = INTERPRETER_TI_FIELD_ACCESS; break; + case JVMTI_EVENT_FIELD_MODIFICATION: new_mask = INTERPRETER_TI_FIELD_MODIFICATION; break; + case JVMTI_EVENT_EXCEPTION_CATCH: new_mask = INTERPRETER_TI_OTHER; break; + case JVMTI_EVENT_EXCEPTION: new_mask = INTERPRETER_TI_OTHER; break; default: break; } @@ -396,26 +400,27 @@ #if 0 method->get_descriptor()->bytes); #endif - - assert(hythread_is_suspend_enabled()); + assert(!hythread_is_suspend_enabled()); assert(interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT); jvmti_process_method_entry_event((jmethodID) method); - assert(hythread_is_suspend_enabled()); + assert(!hythread_is_suspend_enabled()); } void method_exit_callback(Method *method, bool was_popped_by_exception, jvalue ret_val) { - assert(hythread_is_suspend_enabled()); + assert(!hythread_is_suspend_enabled()); assert(interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT); jvmti_process_method_exit_event((jmethodID) method, was_popped_by_exception, ret_val); + + assert(!hythread_is_suspend_enabled()); } void frame_pop_callback(FramePopListener *l, Method *method, jboolean was_popped_by_exception) { assert(!hythread_is_suspend_enabled()); - tmn_suspend_enable(); + hythread_suspend_enable(); while (l) { jvmtiEnv *env = (jvmtiEnv*) l->listener; @@ -424,7 +429,7 @@ frame_pop_callback(FramePopListener *l, l = l->next; STD_FREE((void*)prev); } - tmn_suspend_disable(); + hythread_suspend_disable(); } jvmtiError @@ -485,11 +490,136 @@ interpreter_ti_notify_frame_pop(jvmtiEnv void single_step_callback(StackFrame &frame) { uint8 ip0 = *frame.ip; if (ip0 == OPCODE_BREAKPOINT) return; - tmn_suspend_enable(); + hythread_suspend_enable(); Method *method = frame.method; jvmti_process_single_step_event((jmethodID) method, frame.ip - (uint8*)method->get_byte_code_addr()); + hythread_suspend_disable(); +} + +//////////////////////////////////////// +// Interpreter frames iteration +FrameHandle* interpreter_get_last_frame(class VM_thread *thread) +{ + return (FrameHandle*)getLastStackFrame(thread); +} + +FrameHandle* interpreter_get_prev_frame(FrameHandle* frame) +{ + if (frame == NULL) + return NULL; + + return (FrameHandle*)(((StackFrame*)frame)->prev); +} + +bool is_frame_in_native_frame(FrameHandle* frame, void* begin, void* end) +{ + return (frame >= begin && frame < end); +} + +///////////////////////////////// +/// Field Watch functionality +// +static inline bool field_event_mask(Field *field, bool modify) { + char *flag, mask; + if (modify) { + field_get_track_modification_flag(field, &flag, &mask); + } else { + field_get_track_access_flag(field, &flag, &mask); + } + return ((*flag & mask) != 0); +} + + +static inline void field_access_callback(Field *field, StackFrame& frame, ManagedObject *obj) { + Method *method = frame.method; + jlocation pc = frame.ip - (uint8*)method->get_code_addr(); + + M2N_ALLOC_MACRO; + ObjectHandle handle = oh_allocate_local_handle(); + handle->object = obj; + + tmn_suspend_enable(); + jvmti_process_field_access_event(field, (jmethodID) method, pc, &handle); + tmn_suspend_disable(); + M2N_FREE_MACRO; +} + +static inline void field_modification_callback(Field *field, StackFrame& frame, jobject obj, jvalue val) { + Method *method = frame.method; + jlocation pc = frame.ip - (uint8*)method->get_code_addr(); + tmn_suspend_enable(); + jvmti_process_field_modification_event(field, (jmethodID) method, pc, &obj, val); tmn_suspend_disable(); } + +void getfield_callback(Field *field, StackFrame& frame) { + if (!field_event_mask(field, false)) return; + + CREF cref = frame.stack.pick(0).cr; + ManagedObject *obj = UNCOMPRESS_REF(cref); + field_access_callback(field, frame, obj); +} + +void getstatic_callback(Field *field, StackFrame& frame) { + if (!field_event_mask(field, false)) return; + + field_access_callback(field, frame, NULL); +} + +jvalue new_field_value(Field *field, StackFrame& frame) { + jvalue val; + val.l = 0; + switch (field->get_java_type()) { + case VM_DATA_TYPE_BOOLEAN: val.z = (uint8) frame.stack.pick().u; break; + case VM_DATA_TYPE_CHAR: val.c = (uint16) frame.stack.pick().u; break; + case VM_DATA_TYPE_INT8: val.b = (int8) frame.stack.pick().i; break; + case VM_DATA_TYPE_INT16: val.s = (int16) frame.stack.pick().i; break; + case VM_DATA_TYPE_INT32: val.i = frame.stack.pick().i; break; + case VM_DATA_TYPE_INT64: val.j = frame.stack.getLong(0).i64; break; + case VM_DATA_TYPE_F8: val.d = frame.stack.getLong(0).d; break; + case VM_DATA_TYPE_ARRAY: + case VM_DATA_TYPE_CLASS: + { + ObjectHandle h = oh_allocate_local_handle(); + h->object = UNCOMPRESS_REF(frame.stack.pick().cr); + val.l = h; + } + break; + default: + ABORT("Unexpected data type"); + } + return val; +} + +void putstatic_callback(Field *field, StackFrame& frame) { + if (!field_event_mask(field, true)) return; + + M2N_ALLOC_MACRO; + jvalue val = new_field_value(field, frame); + field_modification_callback(field, frame, NULL, val); + M2N_FREE_MACRO; +} + +void putfield_callback(Field *field, StackFrame& frame) { + if (!field_event_mask(field, true)) return; + + Java_Type type = field->get_java_type(); + CREF cref; + + if (type == VM_DATA_TYPE_INT64 || type == VM_DATA_TYPE_F8) { + cref = frame.stack.pick(2).cr; + } else { + cref = frame.stack.pick(1).cr; + } + + M2N_ALLOC_MACRO; + ObjectHandle handle = oh_allocate_local_handle(); + handle->object = UNCOMPRESS_REF(cref); + jvalue val = new_field_value(field, frame); + field_modification_callback(field, frame, handle, val); + M2N_FREE_MACRO; +} + diff --git vm/jitrino/config/em64t/client.emconf vm/jitrino/config/em64t/client.emconf new file mode 100644 index 0000000..e69ed04 --- /dev/null +++ vm/jitrino/config/em64t/client.emconf @@ -0,0 +1,56 @@ +#EM configuration file for 'client' mode of Jitrino + +chains=chain1,chain2 +chain1.jits=JET_CLINIT +chain2.jits=JET_DPGO,CD_OPT + + +# JET_CLINIT compiles only methods, all other methods compiled with JET_DPGO +# which does entry/backedge instrumentation + +chain1.filter=+:: +chain1.filter=- + +JET_CLINIT.file=jitrino +JET_DPGO.file=jitrino +CD_OPT.file=jitrino + +#Confuguration of profile collector and recompilation +JET_DPGO.genProfile=EB_PROF +EB_PROF.profilerType=EB_PROFILER +CD_OPT.useProfile=EB_PROF + + +EB_PROF.mode=SYNC +EB_PROF.entryThreshold=10000 +EB_PROF.backedgeThreshold=100000 + +# these options could be used only in async profiler mode +#EB_PROF.tbsTimeout=5 +#EB_PROF.tbsInitialTimeout=0 + + + +# Options to be passed to JIT + +-Djit.JET_CLINIT.path= +-Djit.JET_DPGO.path= + +-Djit.CD_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.CD_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,uce,dce,memopt,simplify,uce,dce,lower,dessa,statprof,markglobals +-Djit.CD_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.CD_OPT.path.dce1=cg_dce +-Djit.CD_OPT.path.dce2=cg_dce +-Djit.CD_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.CD_OPT.path.bp_regalloc1=bp_regalloc +-Djit.CD_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.CD_OPT.CD_OPT_inliner_pipeline.filter=- +-Djit.CD_OPT.CD_OPT_inliner_pipeline.path=ssa,devirt +-Djit.CD_OPT.arg.optimizer.inline.pipeline=CD_OPT_inliner_pipeline + +-Djit.CD_OPT.arg.codegen.dce1.early=yes +-Djit.CD_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.CD_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/em64t/jet.emconf vm/jitrino/config/em64t/jet.emconf new file mode 100644 index 0000000..2decb85 --- /dev/null +++ vm/jitrino/config/em64t/jet.emconf @@ -0,0 +1,8 @@ +# EM configuration file for JET-only mode of Jitrino + +chains=chain1 +chain1.jits=JET +JET.file=jitrino + +#JIT options +-Djit.JET.path= diff --git vm/jitrino/config/em64t/opt.emconf vm/jitrino/config/em64t/opt.emconf new file mode 100644 index 0000000..4bd590d --- /dev/null +++ vm/jitrino/config/em64t/opt.emconf @@ -0,0 +1,28 @@ +# EM configuration file for CS_OPT-only mode of Jitrino. This is 'client static' mode + +chains=chain1 +chain1.jits=CS_OPT +CS_OPT.file=jitrino + + +# Options to be passed to JIT + +-Djit.CS_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.CS_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,uce,dce,memopt,simplify,uce,dce,lower,dessa,statprof,markglobals +-Djit.CS_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.CS_OPT.path.dce1=cg_dce +-Djit.CS_OPT.path.dce2=cg_dce +-Djit.CS_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.CS_OPT.path.bp_regalloc1=bp_regalloc +-Djit.CS_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.CS_OPT.CS_OPT_inliner_pipeline.filter=- +-Djit.CS_OPT.CS_OPT_inliner_pipeline.path=ssa,devirt +-Djit.CS_OPT.arg.optimizer.inline.pipeline=CS_OPT_inliner_pipeline + + +-Djit.CS_OPT.arg.codegen.dce1.early=yes +-Djit.CS_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.CS_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/em64t/server.emconf vm/jitrino/config/em64t/server.emconf new file mode 100644 index 0000000..a108b5c --- /dev/null +++ vm/jitrino/config/em64t/server.emconf @@ -0,0 +1,63 @@ +#EM configuration for 'server' mode of Jitrino +chains=chain1,chain2 +chain1.jits=JET_CLINIT +chain2.jits=SD1_OPT,SD2_OPT + +chain1.filter=+:: +chain1.filter=- + +JET_CLINIT.file=jitrino +SD1_OPT.file=jitrino +SD2_OPT.file=jitrino + +# Edge profiler and recompilation parameters +EDGE_PROF.profilerType=EDGE_PROFILER +EDGE_PROF.entryThreshold=40000 +EDGE_PROF.backedgeThreshold=150000 +EDGE_PROF.tbsTimeout=10 +EDGE_PROF.tbsInitialTimeout=0 + +SD1_OPT.genProfile=EDGE_PROF +SD2_OPT.useProfile=EDGE_PROF + +#options for JIT + +-Djit.JET_CLINIT.path= + + +-Djit.SD1_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SD1_OPT.path.optimizer=ssa,simplify,uce,dce,edge_instrument,dessa,statprof,markglobals +-Djit.SD1_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SD1_OPT.path.dce1=cg_dce +-Djit.SD1_OPT.path.dce2=cg_dce +-Djit.SD1_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SD1_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SD1_OPT.path.bp_regalloc2=bp_regalloc + +-Djit.SD1_OPT.arg.codegen.dce1.early=yes +-Djit.SD1_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SD1_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM + + + +-Djit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SD2_OPT.path.optimizer=ssa,simplify,uce,dce,edge_annotate,devirt,inline,purge,simplify,uce,dce,hvn,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,uce,dce,lower,uce,dce,memopt,reassoc,uce,dce,hvn,uce,dce,abcd,uce,dce,gcm,dessa,statprof,markglobals +-Djit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SD2_OPT.path.dce1=dce +-Djit.SD2_OPT.path.dce2=dce +-Djit.SD2_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SD2_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SD2_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.SD2_OPT.SD2_OPT_inliner_pipeline.filter=- +-Djit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,uce,dce,edge_annotate,devirt +-Djit.SD2_OPT.arg.optimizer.inline.pipeline=SD2_OPT_inliner_pipeline +-Djit.SD2_OPT.arg.optimizer.inline.connect_early=false + + +-Djit.SD2_OPT.arg.codegen.dce1.early=yes +-Djit.SD2_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SD2_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/em64t/server_static.emconf vm/jitrino/config/em64t/server_static.emconf new file mode 100644 index 0000000..d431b8e --- /dev/null +++ vm/jitrino/config/em64t/server_static.emconf @@ -0,0 +1,27 @@ +# EM configuration file for OPT-only mode of Jitrino with server optimization path. This is 'server static' mode + +chains=chain1 +chain1.jits=SS_OPT +SS_OPT.file=jitrino + + +# Options to be passed to JIT + +-Djit.SS_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SS_OPT.path.optimizer=ssa,simplify,uce,dce,statprof,devirt,inline,purge,simplify,uce,dce,hvn,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,uce,dce,lower,uce,dce,memopt,reassoc,uce,dce,hvn,uce,dce,abcd,uce,dce,gcm,dessa,statprof,markglobals +-Djit.SS_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SS_OPT.path.dce1=cg_dce +-Djit.SS_OPT.path.dce2=cg_dce +-Djit.SS_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SS_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SS_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.SS_OPT.SS_OPT_inliner_pipeline.filter=- +-Djit.SS_OPT.SS_OPT_inliner_pipeline.path=ssa,simplify,uce,dce,statprof,devirt +-Djit.SS_OPT.arg.optimizer.inline.pipeline=SS_OPT_inliner_pipeline + +-Djit.SS_OPT.arg.codegen.dce1.early=yes +-Djit.SS_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SS_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/em64t/ti.emconf vm/jitrino/config/em64t/ti.emconf new file mode 100644 index 0000000..a689f43 --- /dev/null +++ vm/jitrino/config/em64t/ti.emconf @@ -0,0 +1,8 @@ +# EM configuration file for JET-only mode of Jitrino + +chains=chain1 +chain1.jits=JET_TI +JET_TI.file=jitrino + +#JIT options +-Djit.JET_TI.path= diff --git vm/jitrino/config/ia32/client.emconf vm/jitrino/config/ia32/client.emconf new file mode 100644 index 0000000..2243437 --- /dev/null +++ vm/jitrino/config/ia32/client.emconf @@ -0,0 +1,56 @@ +#EM configuration file for 'client' mode of Jitrino + +chains=chain1,chain2 +chain1.jits=JET_CLINIT +chain2.jits=JET_DPGO,CD_OPT + + +# JET_CLINIT compiles only methods, all other methods compiled with JET_DPGO +# which does entry/backedge instrumentation + +chain1.filter=+:: +chain1.filter=- + +JET_CLINIT.file=jitrino +JET_DPGO.file=jitrino +CD_OPT.file=jitrino + +#Confuguration of profile collector and recompilation +JET_DPGO.genProfile=EB_PROF +EB_PROF.profilerType=EB_PROFILER +CD_OPT.useProfile=EB_PROF + + +EB_PROF.mode=SYNC +EB_PROF.entryThreshold=10000 +EB_PROF.backedgeThreshold=100000 + +# these options are used only in ASYNC profiler mode +#EB_PROF.tbsTimeout=5 +#EB_PROF.tbsInitialTimeout=0 + + + +# Options to be passed to JIT + +-Djit.JET_CLINIT.path= +-Djit.JET_DPGO.path= + +-Djit.CD_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.CD_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,uce,dce,lazyexc,memopt,simplify,uce,dce,lower,dessa,statprof,markglobals +-Djit.CD_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,early_prop,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.CD_OPT.path.dce1=cg_dce +-Djit.CD_OPT.path.dce2=cg_dce +-Djit.CD_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.CD_OPT.path.bp_regalloc1=bp_regalloc +-Djit.CD_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.CD_OPT.CD_OPT_inliner_pipeline.filter=- +-Djit.CD_OPT.CD_OPT_inliner_pipeline.path=ssa,devirt +-Djit.CD_OPT.arg.optimizer.inline.pipeline=CD_OPT_inliner_pipeline + +-Djit.CD_OPT.arg.codegen.dce1.early=yes +-Djit.CD_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.CD_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/ia32/jet.emconf vm/jitrino/config/ia32/jet.emconf new file mode 100644 index 0000000..2d9cc5b --- /dev/null +++ vm/jitrino/config/ia32/jet.emconf @@ -0,0 +1,9 @@ +# EM configuration file for JET-only mode of Jitrino + +chains=chain1 +chain1.jits=JET +JET.file=jitrino + +# Options to be passed to JIT + +-Djit.JET.path= diff --git vm/jitrino/config/ia32/opt.emconf vm/jitrino/config/ia32/opt.emconf new file mode 100644 index 0000000..3271056 --- /dev/null +++ vm/jitrino/config/ia32/opt.emconf @@ -0,0 +1,31 @@ +# EM configuration file for CS_OPT-only mode of Jitrino. This is 'client static' mode + +chains=chain1 +chain1.jits=CS_OPT +CS_OPT.file=jitrino + + +# Options to be passed to JIT + +-Djit.CS_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.CS_OPT.path.optimizer=ssa,devirt,inline,purge,simplify,uce,dce,lazyexc,memopt,simplify,uce,dce,lower,dessa,statprof,markglobals +-Djit.CS_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,early_prop,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.CS_OPT.path.dce1=cg_dce +-Djit.CS_OPT.path.dce2=cg_dce +-Djit.CS_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.CS_OPT.path.bp_regalloc1=bp_regalloc +-Djit.CS_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.CS_OPT.CS_OPT_inliner_pipeline.filter=- +-Djit.CS_OPT.CS_OPT_inliner_pipeline.path=ssa,devirt +-Djit.CS_OPT.arg.optimizer.inline.pipeline=CS_OPT_inliner_pipeline + + +-Djit.CS_OPT.arg.codegen.dce1.early=yes +-Djit.CS_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.CS_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM + +#-Djit.CS_OPT.arg.log.irdump.file=log/%jit%/%log%/%seqnb%_%class%.%method%.log +#-Djit.CS_OPT.arg.log=ct,ir,irdump,all diff --git vm/jitrino/config/ia32/server.emconf vm/jitrino/config/ia32/server.emconf new file mode 100644 index 0000000..3a623ee --- /dev/null +++ vm/jitrino/config/ia32/server.emconf @@ -0,0 +1,61 @@ +#EM configuration for 'server' mode of Jitrino +chains=chain1,chain2 +chain1.jits=JET_CLINIT +chain2.jits=SD1_OPT,SD2_OPT + +chain1.filter=+:: +chain1.filter=- + +JET_CLINIT.file=jitrino +SD1_OPT.file=jitrino +SD2_OPT.file=jitrino + +# Edge profiler and recompilation parameters +EDGE_PROF.profilerType=EDGE_PROFILER +EDGE_PROF.entryThreshold=40000 +EDGE_PROF.backedgeThreshold=150000 +EDGE_PROF.tbsTimeout=10 +EDGE_PROF.tbsInitialTimeout=0 + +SD1_OPT.genProfile=EDGE_PROF +SD2_OPT.useProfile=EDGE_PROF + +#options for JIT + +-Djit.JET_CLINIT.path= + + +-Djit.SD1_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SD1_OPT.path.optimizer=ssa,simplify,uce,dce,edge_instrument,dessa,statprof,markglobals +-Djit.SD1_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,early_prop,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SD1_OPT.path.dce1=cg_dce +-Djit.SD1_OPT.path.dce2=cg_dce +-Djit.SD1_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SD1_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SD1_OPT.path.bp_regalloc2=bp_regalloc + +-Djit.SD1_OPT.arg.codegen.dce1.early=yes +-Djit.SD1_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SD1_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM + +-Djit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SD2_OPT.path.optimizer=ssa,simplify,uce,dce,edge_annotate,lazyexc,devirt,inline,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,uce,dce,lower,uce,dce,memopt,reassoc,uce,dce,hvn,uce,dce,abcd,uce,dce,gcm,dessa,statprof,markglobals +-Djit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,early_prop,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SD2_OPT.path.dce1=cg_dce +-Djit.SD2_OPT.path.dce2=cg_dce +-Djit.SD2_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SD2_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SD2_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.SD2_OPT.SD2_OPT_inliner_pipeline.filter=- +-Djit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,uce,dce,edge_annotate,devirt +-Djit.SD2_OPT.arg.optimizer.inline.pipeline=SD2_OPT_inliner_pipeline +-Djit.SD2_OPT.arg.optimizer.inline.connect_early=false + + +-Djit.SD2_OPT.arg.codegen.dce1.early=yes +-Djit.SD2_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SD2_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/ia32/server_static.emconf vm/jitrino/config/ia32/server_static.emconf new file mode 100644 index 0000000..d0e2910 --- /dev/null +++ vm/jitrino/config/ia32/server_static.emconf @@ -0,0 +1,27 @@ +# EM configuration file for OPT-only mode of Jitrino with server optimization path. This is 'server static' mode + +chains=chain1 +chain1.jits=SS_OPT +SS_OPT.file=jitrino + + +# Options to be passed to JIT + +-Djit.SS_OPT.path=opt_init,translator,optimizer,hir2lir,codegen + +-Djit.SS_OPT.path.optimizer=ssa,simplify,uce,dce,statprof,lazyexc,devirt,inline,purge,simplify,uce,dce,hvn,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,uce,dce,lower,uce,dce,memopt,reassoc,uce,dce,hvn,uce,dce,abcd,uce,dce,gcm,dessa,statprof,markglobals +-Djit.SS_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l,early_prop,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method +-Djit.SS_OPT.path.dce1=cg_dce +-Djit.SS_OPT.path.dce2=cg_dce +-Djit.SS_OPT.path.regalloc=bp_regalloc1,bp_regalloc2 +-Djit.SS_OPT.path.bp_regalloc1=bp_regalloc +-Djit.SS_OPT.path.bp_regalloc2=bp_regalloc + +#inliner configuration +-Djit.SS_OPT.SS_OPT_inliner_pipeline.filter=- +-Djit.SS_OPT.SS_OPT_inliner_pipeline.path=ssa,simplify,uce,dce,statprof,devirt +-Djit.SS_OPT.arg.optimizer.inline.pipeline=SS_OPT_inliner_pipeline + +-Djit.SS_OPT.arg.codegen.dce1.early=yes +-Djit.SS_OPT.arg.codegen.regalloc.bp_regalloc1.regs=ALL_GP +-Djit.SS_OPT.arg.codegen.regalloc.bp_regalloc2.regs=ALL_XMM diff --git vm/jitrino/config/ia32/ti.emconf vm/jitrino/config/ia32/ti.emconf new file mode 100644 index 0000000..a689f43 --- /dev/null +++ vm/jitrino/config/ia32/ti.emconf @@ -0,0 +1,8 @@ +# EM configuration file for JET-only mode of Jitrino + +chains=chain1 +chain1.jits=JET_TI +JET_TI.file=jitrino + +#JIT options +-Djit.JET_TI.path= diff --git vm/jitrino/src/codegenerator/CodeGenIntfc.cpp vm/jitrino/src/codegenerator/CodeGenIntfc.cpp index f463745..43d976e 100644 --- vm/jitrino/src/codegenerator/CodeGenIntfc.cpp +++ vm/jitrino/src/codegenerator/CodeGenIntfc.cpp @@ -22,30 +22,14 @@ #include "CodeGenIntfc.h" #if defined (_IPF_) - #include "ipf/IpfCodeGenerator.h" + #include "IpfCodeGenerator.h" #else - #include "ia32/Ia32CodeGenerator.h" + #include "ia32/Ia32CodeGenerator.h" #endif -namespace Jitrino { - -void CodeGenerator::readFlagsFromCommandLine(CompilationContext* cs, bool ia32Cg) -{ -#if defined(_IPF_) - IPF::IpfCodeGenerator::readFlagsFromCommandLine(cs); -#else - Ia32::CodeGenerator::readFlagsFromCommandLine(cs); -#endif -} -void CodeGenerator::showFlagsFromCommandLine(bool ia32Cg) -{ -#if defined (_IPF_) - IPF::IpfCodeGenerator::showFlagsFromCommandLine(); -#else - Ia32::CodeGenerator::showFlagsFromCommandLine(); -#endif -} +namespace Jitrino { + } diff --git vm/jitrino/src/codegenerator/CodeGenIntfc.h vm/jitrino/src/codegenerator/CodeGenIntfc.h index b7f8083..e435829 100644 --- vm/jitrino/src/codegenerator/CodeGenIntfc.h +++ vm/jitrino/src/codegenerator/CodeGenIntfc.h @@ -27,17 +27,18 @@ #include "open/types.h" #include "Type.h" #include "Jitrino.h" #include "VMInterface.h" -#include "PropertyTable.h" -#include "Inst.h" +#include "Stl.h" namespace Jitrino { - class CodeProfiler; - // struct ::JitFrameContext; - class CG_OpndHandle { -}; +class InlineInfo; + + // struct ::JitFrameContext; + class CG_OpndHandle { + }; + // "_Ovf" types are used to support CLI's overflow semantics. CLI supports // overflow arithmetic. If an overflow type is used below, generated code must @@ -162,7 +163,9 @@ class JitHelperCallOp { public: enum Id { InitializeArray, - PseudoCanThrow + PseudoCanThrow, + SaveThisState, + ReadThisState }; }; @@ -190,7 +193,7 @@ public: virtual CG_OpndHandle* sub(ArithmeticOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2) = 0; virtual CG_OpndHandle* subRef(RefArithmeticOp::Types,CG_OpndHandle* refSrc, CG_OpndHandle* intSrc) = 0; virtual CG_OpndHandle* diffRef(bool ovf, CG_OpndHandle* ref1,CG_OpndHandle* ref2) = 0; - virtual CG_OpndHandle* scaledDiffRef(CG_OpndHandle* ref1,CG_OpndHandle* ref2) = 0; + virtual CG_OpndHandle* scaledDiffRef(CG_OpndHandle*, CG_OpndHandle*, Type*, Type*) = 0; virtual CG_OpndHandle* mul(ArithmeticOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2) = 0; virtual CG_OpndHandle* tau_div(DivOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2, CG_OpndHandle *tauSrc1NonZero) = 0; @@ -254,8 +257,7 @@ public: CG_OpndHandle *tauBaseNonNull) = 0; virtual CG_OpndHandle* getVTableAddr(Type *dstType, ObjectType *base) = 0; virtual CG_OpndHandle* tau_ldIntfTableAddr(Type *dstType, CG_OpndHandle* base, - NamedType* vtableType, - CG_OpndHandle *tauBaseHasIntf) = 0; + NamedType* vtableType) = 0; virtual CG_OpndHandle* call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, InlineInfo* ii = NULL) = 0; virtual CG_OpndHandle* tau_call(uint32 numArgs, CG_OpndHandle** args, Type* retType, @@ -277,7 +279,7 @@ public: virtual CG_OpndHandle* callhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType, JitHelperCallOp::Id callId) = 0; virtual CG_OpndHandle* callvmhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType, - VMHelperCallOp::Id callId) = 0; + VMHelperCallOp::Id callId, InlineInfo* ii = NULL) = 0; virtual CG_OpndHandle* ldc_i4(uint32 val) = 0; virtual CG_OpndHandle* ldc_i8(uint64 val) = 0; virtual CG_OpndHandle* ldc_s(float val) = 0; @@ -335,7 +337,7 @@ public: virtual CG_OpndHandle* ldFieldAddr(Type* fieldRefType,CG_OpndHandle* base,FieldDesc *desc) = 0; virtual CG_OpndHandle* ldStaticAddr(Type* fieldRefType,FieldDesc *desc) = 0; virtual CG_OpndHandle* ldElemBaseAddr(CG_OpndHandle* array) = 0; - virtual CG_OpndHandle* addElemIndex(CG_OpndHandle *elemBase,CG_OpndHandle* index) = 0; + virtual CG_OpndHandle* addElemIndex(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index) = 0; virtual CG_OpndHandle* ldElemAddr(CG_OpndHandle* array,CG_OpndHandle* index) = 0; // COMPRESSED_PTR note: // if we are using compressed references, and ptr is Ptr, then @@ -373,9 +375,9 @@ public: // COMPRESSED_PTR note: If we are using compressed references, and // ptr is Ptr, then // (1) if autoCompressRef, then src should be Ref and CG will compress - // it on store; type is uncompressedRef type + // it on store; type is uncompressedRef type // (2) if !autoCompressRef, then src should be CompressedRef; type is - // compressedRef type + // compressedRef type virtual void tau_stInd(CG_OpndHandle* src, CG_OpndHandle* ptr, Type::Tag memType, bool autoCompressRef, CG_OpndHandle* tauBaseNonNull, @@ -402,7 +404,7 @@ public: virtual CG_OpndHandle* newObj(ObjectType* objType) = 0; virtual CG_OpndHandle* newArray(ArrayType* arrayType, CG_OpndHandle* numElems) = 0; virtual CG_OpndHandle* newMultiArray(ArrayType* arrayType, uint32 numDims, CG_OpndHandle** dims) = 0; - virtual CG_OpndHandle* ldString(MethodDesc* enclosingMethod,uint32 stringToken, bool autouncompress) = 0; + virtual CG_OpndHandle* ldRef(Type* type,MethodDesc* enclosingMethod,uint32 stringToken, bool autouncompress) = 0; virtual CG_OpndHandle* ldToken(Type *dstType,MethodDesc* enclosingMethod,uint32 token) = 0; virtual void incCounter(Type *counterType,uint32 counter) = 0; @@ -453,11 +455,16 @@ public: virtual CG_OpndHandle* catchException(Type * exceptionType) = 0; virtual void prefetch(CG_OpndHandle* refSrc, uint32 offset, int hints) = 0; + virtual void pseudoInst() = 0; + + virtual void methodEntry(MethodDesc* mDesc) = 0; + virtual void methodEnd(MethodDesc* mDesc, CG_OpndHandle* retVallue = NULL) = 0; + // Set the current persistent instruction id associated with any subsequently generated instructions. virtual void setCurrentPersistentId(PersistentInstructionId persistentId) = 0; // Clear the current persistent instruction id. - // Any subsequently generated instructions have no associated ID. + // Any subsequently generated instructions have no associated ID. virtual void clearCurrentPersistentId() = 0; // Set current HIR instruction in order to allow Code Generator propagate bc offset info virtual void setCurrentHIRInstrID(uint64 HIRInstrID) = 0; @@ -472,9 +479,9 @@ public: virtual ~VarCodeSelector() {} class Callback { public: - virtual ~Callback() {} - virtual uint32 defVar(Type* varType,bool isAddressTaken,bool isPinned) = 0; - virtual void setManagedPointerBase(uint32 managedPtrVarNum, uint32 baseVarNum) = 0; + virtual ~Callback() {} + virtual uint32 defVar(Type* varType,bool isAddressTaken,bool isPinned) = 0; + virtual void setManagedPointerBase(uint32 managedPtrVarNum, uint32 baseVarNum) = 0; }; virtual void genCode(Callback&) = 0; }; @@ -496,8 +503,8 @@ public: virtual ~CFGCodeSelector() {} class Callback { public: - virtual ~Callback() {} enum BlockKind {Prolog, InnerBlock, Epilog}; + virtual ~Callback() {} virtual uint32 genDispatchNode(uint32 numInEdges,uint32 numOutEdges,double cnt) = 0; virtual uint32 genBlock(uint32 numInEdges,uint32 numOutEdges, BlockKind blockKind, BlockCodeSelector&, double cnt) = 0; @@ -511,9 +518,7 @@ public: virtual void genExceptionEdge(uint32 tailNodeId, uint32 headNodeId, double prob) = 0; virtual void genCatchEdge(uint32 tailNodeId,uint32 headNodeId, uint32 priority,Type* exceptionType, double prob) = 0; - virtual void genExitEdge(uint32 tailNodeId, uint32 headNodeId, double prob) = 0; - - virtual void setLoopInfo(uint32 nodeId, bool isLoopHeader, bool hasContainingLoopHeader, uint32 headerId) = 0; + // Set the persistent block ID for a given block. virtual void setPersistentId(uint32 nodeId, uint32 persistentId) = 0; }; @@ -524,25 +529,21 @@ public: // class MethodCodeSelector { public: - virtual ~MethodCodeSelector() {} MethodCodeSelector() {} class Callback { public: - virtual ~Callback() {} virtual void genVars(uint32 numLocals,VarCodeSelector&) = 0; virtual void setMethodDesc(MethodDesc * desc) = 0; virtual void genCFG(uint32 numNodes,CFGCodeSelector&,bool useProfile) = 0; - virtual void setProfileInfo(CodeProfiler *profiler) = 0; }; virtual void selectCode(Callback&) = 0; }; +class SessionAction; class CodeGenerator { public: virtual ~CodeGenerator() {} - virtual bool genCode(MethodCodeSelector&) = 0; - static void readFlagsFromCommandLine(CompilationContext* cs, bool ia32Cg); - static void showFlagsFromCommandLine(bool ia32Cg); + virtual void genCode(SessionAction* sa, MethodCodeSelector&) = 0; }; class CodeGeneratorFactory { @@ -578,6 +579,8 @@ #endif virtual uint32 getInlineDepth(InlineInfoPtr ptr, uint32 offset) { return 0; } virtual Method_Handle getInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { return NULL; } + virtual uint16 getInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) = 0; + }; class InlineInfoMap { @@ -597,15 +600,18 @@ public: uint32 computeSize() const; void write(InlineInfoPtr output); static uint32 get_inline_depth(InlineInfoPtr ptr, uint32 offset); - static Method_Handle get_inlined_method(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth); + static Method_Handle get_inlined_method(InlineInfoPtr ptr, uint32 offset, + uint32 inline_depth); + static uint16 get_inlined_bc(InlineInfoPtr ptr, uint32 offset, + uint32 inline_depth); private: - static uint64 ptr_to_uint64(void *ptr); - static Method_Handle uint64_to_mh(uint64 value); + static POINTER_SIZE_INT ptr_to_uint64(void *ptr); + static Method_Handle uint64_to_mh(POINTER_SIZE_INT value); // // returns pointer to serialized data corresponding to offset: // depth mh[depth] // - static uint64* find_offset(InlineInfoPtr ptr, uint32 offset); + static POINTER_SIZE_INT* find_offset(InlineInfoPtr ptr, uint32 offset); InlineInfoList list; MemoryManager& memManager; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.cpp vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.cpp index 6fa5c33..8d28bea 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.cpp @@ -18,13 +18,225 @@ * @version $Revision: 1.1.12.3.4.3 $ */ -#include "Ia32BBPolling.h" +#include "Ia32IRManager.h" #include "DrlVMInterface.h" namespace Jitrino { namespace Ia32{ + +const uint32 BBPollingMaxVersion = 6; + +//======================================================================================== +// class BBPolling +//======================================================================================== +/** + class BBPolling implements utilities for back branch polling pass + +*/ +class BBPolling +{ +typedef ::std::pair targetIdDispatchIdPair; +typedef StlMap BBPControllersMap; +public: + + BBPolling(IRManager& ir,uint32 ver) : + irManager(ir), + version(ver), + hasThreadInterruptablePoint(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), false), + hasNativeInterruptablePoint(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), false), + isOnThreadInterruptablePath(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), false), + tlsBaseRegForLoopHeader(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), NULL), + bbpCFGControllerForNode(irManager.getMemoryManager()), + toppestLoopHeader(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), NULL), + otherStartNdx(irManager.getMemoryManager(), irManager.getFlowGraph()->getMaxNodeId(), 0), + loopHeaders(irManager.getMemoryManager()), + otherEdges(irManager.getMemoryManager()), + eligibleEdges(irManager.getMemoryManager()), +#ifdef _DEBUG + interruptablePoints(0), + pollingPoints(0), +#endif + loopHeaderOfEdge(irManager.getMemoryManager()) + { + calculateInitialInterruptability(version == 5 || version == 6); + + if (version == 2 || version == 3) + calculateInterruptablePathes(); + // no more calculations here, just collect the edges! + switch (version) { + case 1: collectEligibleEdges(); break; + case 2: collectEligibleEdges2(); break; + case 3: collectEligibleEdgesRecursive(); break; + case 4: collectEligibleEdges(); break; + case 5: collectEligibleEdges(); break; + case 6: collectEligibleEdges(); break; + default: assert(0); + } + if (Log::isEnabled()) { + dumpEligibleEdges(); + } +#ifdef _DEBUG + if (version == 2 || version == 3) + verify(); +#endif + } + + uint32 numberOfAffectedEdges() { return eligibleEdges.size(); } + Edge* getAffectedEdge(uint32 i) { assert(i < eligibleEdges.size()); return eligibleEdges[i]; } + + Opnd* getOrCreateTLSBaseReg(Edge* e); + + static bool isThreadInterruptablePoint(const Inst* inst); + + static bool hasNativeInterruptablePoints(const Node* node); + + bool hasAllThreadInterruptablePredecessors(const Node* node); + + Node* getBBPSubCFGController(uint32 targetId, uint32 dispatchId); + void setBBPSubCFGController(uint32 targetId, uint32 dispatchId, Node* node); + ControlFlowGraph* createBBPSubCFG(IRManager& ir, Opnd* tlsBaseReg); + +private: + + bool isInterruptable(const BasicBlock* b) { + return hasThreadInterruptablePoint[b->getId()]; + } + // select all loopHeaders + // identify all nodes which hasNativeInterruptablePoints + // mark all successors of such nodes as hasThreadInterruptablePoint + void calculateInitialInterruptability(bool doPassingDown); + // identify the nodes which are on the way from a loopHeader to a node which hasThreadInterruptablePoints + void calculateInterruptablePathes(); + bool isOnInterruptablePath(Node* node); + + // collect the edges for substition by subCFG that checks the flag and call the helper if the flag. + // These edges are those from a Node which isOnInterruptablePath to it's succ_node which is not. + void collectEligibleEdges(); // all backedges + void collectEligibleEdges2(); // all pairs [isOnThreadInterruptablePath]->[!isOnThreadInterruptablePath] + void collectEligibleEdgesRecursive(); // recursive selecting of 2 + void collectEdgesDeeper(Node* node); + + void dumpEligibleEdges(); + +#ifdef _DEBUG + bool isEligible(Edge* e); + void verify(); + void verifyDeeper(Node* node, Node* enwind, Node* exit); +#endif // _DEBUG + + IRManager& irManager; + + // version of BBPolling: + // 0 - must be discarded in runImpl() + // 1 - insert bbpCFG at all backedges + // 2 - path analysis based on searching of pairs [isOnThreadInterruptablePath]->[!isOnThreadInterruptablePath] + // 3 - recursive version of "2" + // 4 - "1" + suspension flag addr [TLS base + offset] is calculated before the loop header + // 5 - like "1" but some backedges are not patched (if all paths through it are interuuptable) + // 6 - "4" + "5" + // 7.. illegal + uint32 version; + // storage for ThreadInterruptablePoints information + // hasThreadInterruptablePoint[Node->getId()] == true means that the Node is a LoopHeader + // OR It has at least one instruction that isThreadInterruptablePoint(inst) + // OR all predecessors hasThreadInterruptablePoint or incoming edge is a loopExit + StlVector hasThreadInterruptablePoint; + StlVector hasNativeInterruptablePoint; // only those that hase at least one InterruptablePoint(inst) + // storage for InterruptablePathes information + // isOnThreadInterruptablePath[Node->getId()] == true means that there is a way from the Node + // to another a_node which hasThreadInterruptablePoint[a_node->getId()] + StlVector isOnThreadInterruptablePath; + // tlsBaseRegs pointers. One per each affected loopHeader + StlVector tlsBaseRegForLoopHeader; + // pointers to already prepared bbpCFG. bbpCFG is placed "before" a node to collect all eligible edges. + // pair.first - targetNode id + // pair.second - sourceNode dispatch edge target id + BBPControllersMap bbpCFGControllerForNode; + // to get the toppest loop header of the given without calling getLoopHeader + StlVector toppestLoopHeader; + // start index in otheredges collection for the toppest loop headers + StlVector otherStartNdx; + + // just a collection of loop headers of the method (Basic blocks only!) + StlVector loopHeaders; + // edgse which are not a back edge + StlVector otherEdges; + // edges for inserting BBPolling subCFG + StlVector eligibleEdges; + +#ifdef _DEBUG + uint32 interruptablePoints; + uint32 pollingPoints; +#endif + StlHashMap loopHeaderOfEdge; + +}; // BBPolling class + +//___________________________________________________________________________________________________ + +class BBPollingTransformer : public SessionAction { +public: + BBPollingTransformer() : hasSideEffects(false){} + + bool hasSideEffects; + + void runImpl(){ + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + if(!lt->hasLoops()) { + return; + } + + version = getIntArg("version", 6); + if(version == 0) { + return; + } + if(version > BBPollingMaxVersion) { + assert(0); + return; + } + if (Log::isEnabled()) { + Log::out() << "BBPolling transformer version="<< version <<" STARTED" << ::std::endl; + } + BBPolling bbp = BBPolling(*irManager, version); + uint32 numOfAffectedEdges = bbp.numberOfAffectedEdges(); + hasSideEffects = numOfAffectedEdges != 0; + ControlFlowGraph* fg = irManager->getFlowGraph(); + // Foreach eligible backedge create bbpCFG and inline it between the backedge's Tail and it's target + for (uint32 j = 0; j < numOfAffectedEdges; j++) { + Edge* edge = bbp.getAffectedEdge(j); + + // get or create and insert before the loopHeade a basic block for calculating TLS base + Opnd* tlsBaseReg = bbp.getOrCreateTLSBaseReg(edge); + + uint32 originalTargetId = edge->getTargetNode()->getId(); + Edge* srcDispatchEdge = edge->getSourceNode()->getExceptionEdge(); + uint32 sourceDispatchId = srcDispatchEdge ? srcDispatchEdge->getTargetNode()->getId() : 0; + // CFG for inlining + Node* bbpCFGController = bbp.getBBPSubCFGController(originalTargetId,sourceDispatchId); + if (bbpCFGController) { // just retarget the edge + fg->replaceEdgeTarget(edge, bbpCFGController); + } else { // we need a new bbpCFG + ControlFlowGraph* bbpCFG = bbp.createBBPSubCFG(*irManager, tlsBaseReg); + + // Inlining bbpCFG at edge + fg->spliceFlowGraphInline(edge, *bbpCFG); + bbp.setBBPSubCFGController(originalTargetId,sourceDispatchId,edge->getTargetNode()); + } + } + if (Log::isEnabled()) + Log::out() << "BBPolling transformer FINISHED" << ::std::endl; + } //runImpl() + uint32 getNeedInfo()const{ return NeedInfo_LoopInfo; } + uint32 getSideEffects()const{ return hasSideEffects ? SideEffect_InvalidatesLoopInfo|SideEffect_InvalidatesLivenessInfo : 0; } + bool isIRDumpEnabled(){ return true; } + uint32 version; +}; + +static ActionFactory _bbp("bbp"); + + const uint32 gcFlagOffsetOffset = flagTLSSuspendRequestOffset(); Opnd* @@ -40,6 +252,10 @@ BBPolling::getOrCreateTLSBaseReg(Edge* e if ( tlsBaseReg ) { // it is already created for this loop return tlsBaseReg; } else { + +#ifdef _EM64T_ + tlsBaseReg = irManager.newOpnd(irManager.getTypeManager().getUnmanagedPtrType(irManager.getTypeManager().getIntPtrType()), Constraint(OpndKind_GPReg)); +#else Type* typeInt32 = irManager.getTypeManager().getPrimitiveType(Type::Int32); tlsBaseReg = irManager.newOpnd(typeInt32, Constraint(RegName_EAX)| RegName_EBX | @@ -48,42 +264,43 @@ BBPolling::getOrCreateTLSBaseReg(Edge* e RegName_EBP | RegName_ESI | RegName_EDI); +#endif // Basic Block for flag address calculating. (To be inserted before the loopHeaders) - BasicBlock * bbpFlagAddrBlock = irManager.newBasicBlock(); -//#ifdef PLATFORM_POSIX + Node * bbpFlagAddrBlock = irManager.getFlowGraph()->createBlockNode(); +#ifdef PLATFORM_POSIX // TLS base can be obtained by calling get_thread_ptr() (from vm_threads.h) - Opnd * target=irManager.newImmOpnd( irManager.getTypeManager().getIntPtrType(), + Opnd * target=irManager.newImmOpnd( irManager.getTypeManager().getUnmanagedPtrType(irManager.getTypeManager().getIntPtrType()), Opnd::RuntimeInfo::Kind_HelperAddress, (void*)CompilationInterface::Helper_GetSuspReqFlag ); - bbpFlagAddrBlock->appendInsts(irManager.newCallInst(target, &CallingConvention_STDCALL, 0, NULL, tlsBaseReg)); -/* + bbpFlagAddrBlock->appendInst(irManager.newCallInst(target, &CallingConvention_STDCALL, 0, NULL, tlsBaseReg)); #else // PLATFORM_POSIX // TLS base can be obtained from [fs:0x14] Opnd* tlsBase = irManager.newMemOpnd(typeInt32, MemOpndKind_Any, NULL, 0x14, RegName_FS); if (version == 4 || version == 6) { Opnd * offset = irManager.newImmOpnd(typeInt32, gcFlagOffsetOffset); - bbpFlagAddrBlock->appendInsts(irManager.newInstEx(Mnemonic_ADD, 1, tlsBaseReg, tlsBase, offset)); + bbpFlagAddrBlock->appendInst(irManager.newInstEx(Mnemonic_ADD, 1, tlsBaseReg, tlsBase, offset)); } else { - bbpFlagAddrBlock->appendInsts(irManager.newInst(Mnemonic_MOV, tlsBaseReg, tlsBase)); + bbpFlagAddrBlock->appendInst(irManager.newInst(Mnemonic_MOV, tlsBaseReg, tlsBase)); } #endif // PLATFORM_POSIX -*/ + // inserting bbpFlagAddrBlock before the given loopHeader uint32 startIndex = otherStartNdx[id]; + ControlFlowGraph* fg = irManager.getFlowGraph(); for (uint32 otherIdx = startIndex; ; otherIdx++) { if (otherIdx == otherEdges.size()) break; Edge* other = otherEdges[otherIdx]; - if (other->getNode(Direction_Head) != loopHeader) + if (other->getTargetNode() != loopHeader) break; - irManager.retargetEdge(Direction_Head, other, bbpFlagAddrBlock); + fg->replaceEdgeTarget(other, bbpFlagAddrBlock); } - assert(loopHeader->hasKind(Node::Kind_BasicBlock)); - irManager.newFallThroughEdge(bbpFlagAddrBlock,(BasicBlock*)loopHeader,1); + assert(loopHeader->isBlockNode()); + fg->addEdge(bbpFlagAddrBlock, loopHeader, 1); tlsBaseRegForLoopHeader[id] = tlsBaseReg; return tlsBaseReg; @@ -124,21 +341,21 @@ static void controllerStarter() } #endif -CFG* +ControlFlowGraph* BBPolling::createBBPSubCFG(IRManager& irManager, Opnd* tlsBaseReg) { Type* typeInt32 = irManager.getTypeManager().getPrimitiveType(Type::Int32); // CFG for inlining - CFG* bbpCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock * bbpBBController=bbpCFG->getPrologNode(); - BasicBlock * bbpBBHelpCaller=bbpCFG->newBasicBlock(); - ExitNode * bbpExit=bbpCFG->getExitNode(); - + ControlFlowGraph* bbpCFG = irManager.createSubCFG(true, true); + Node* bbpBBController=bbpCFG->getEntryNode(); + Node* bbpBBHelpCaller=bbpCFG->createBlockNode(); + Node* bbpReturn =bbpCFG->getReturnNode(); + // Controller node // This is a debug hack. It does not work with gcc (warning when casting to int64) #if 0 - Opnd * target = irManager.newImmOpnd( irManager.getTypeManager().getIntPtrType(), + Opnd * target = irManager.newImmOpnd( irManager.getTypeManager().getUnmanagedPtrType(irManager.getTypeManager().getIntPtrType()), (int64)controllerStarter); Inst* dbgCall = irManager.newCallInst(target, &CallingConvention_STDCALL, 0, NULL, NULL, NULL); bbpBBController->appendInsts(dbgCall); @@ -155,28 +372,28 @@ #else } #endif Opnd* zero = irManager.newImmOpnd(typeInt32, 0); - bbpBBController->appendInsts(irManager.newInst(Mnemonic_CMP, gcFlag, zero)); - bbpBBController->appendInsts(irManager.newBranchInst(Mnemonic_JNZ)); + bbpBBController->appendInst(irManager.newInst(Mnemonic_CMP, gcFlag, zero)); + bbpBBController->appendInst(irManager.newBranchInst(Mnemonic_JNZ, bbpBBHelpCaller, bbpReturn)); - bbpCFG->newDirectBranchEdge(bbpBBController,bbpBBHelpCaller, 0.001); - bbpCFG->newEdge(bbpBBController, bbpExit, 0.999); // Helper Caller node // This is a debug hack. It does not work with gcc (warning when casting to int64) #if 0 - target = irManager.newImmOpnd( irManager.getTypeManager().getIntPtrType(), + target = irManager.newImmOpnd( irManager.getTypeManager().getUnmanagedPtrType(irManager.getTypeManager().getIntPtrType()), (int64)callerStarter); dbgCall = irManager.newCallInst(target, &CallingConvention_STDCALL, 0, NULL, NULL, NULL); bbpBBHelpCaller->appendInsts(dbgCall); #endif - bbpBBHelpCaller->appendInsts(irManager.newRuntimeHelperCallInst( + bbpBBHelpCaller->appendInst(irManager.newRuntimeHelperCallInst( CompilationInterface::Helper_EnableThreadSuspension, 0, NULL, NULL) ); - bbpCFG->newEdge(bbpBBHelpCaller, bbpExit, 0.999); - bbpCFG->newUnwindNode(); - bbpCFG->newEdge(bbpBBHelpCaller, bbpCFG->getUnwindNode(), 0.001); + + bbpCFG->addEdge(bbpBBController,bbpBBHelpCaller, 0); + bbpCFG->addEdge(bbpBBController, bbpReturn, 1); + bbpCFG->addEdge(bbpBBHelpCaller, bbpReturn, 1); + bbpCFG->addEdge(bbpBBHelpCaller, bbpCFG->getUnwindNode(), 0); return bbpCFG; } @@ -203,13 +420,13 @@ BBPolling::isThreadInterruptablePoint(co bool BBPolling::hasNativeInterruptablePoints(const Node* node) { - if (node->hasKind(Node::Kind_DispatchNode)) + if (node->isDispatchNode()) { return true; - if (node->hasKind(Node::Kind_BasicBlock)) { - const Insts& insts = ((BasicBlock*)node)->getInsts(); + } + if (node->isBlockNode()) { // If current BB has an inst that is ThreadInterruptablePoint itself // the hasThreadInterruptablePoint becomes true for it - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)) { + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { if (BBPolling::isThreadInterruptablePoint(inst)) { return true; } @@ -220,14 +437,16 @@ BBPolling::hasNativeInterruptablePoints( bool BBPolling::hasAllThreadInterruptablePredecessors(const Node* node) { - if (node->hasKind(Node::Kind_DispatchNode)) + if (node->isDispatchNode()) { return true; - const Edges& edges = node->getEdges(Direction_In); + } + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); + assert(lt->isValid()); + const Edges& edges = node->getInEdges(); // All the predecessors must be processed earlier! - for (Edge* e = edges.getFirst(); e!=NULL; e = edges.getNext(e)) { - if (!hasThreadInterruptablePoint[e->getNode(Direction_Tail)->getId()] && - !e->isLoopExit() ) - { + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + if (!hasThreadInterruptablePoint[e->getSourceNode()->getId()] && !lt->isLoopExit(e)) { return false; } } @@ -237,27 +456,32 @@ BBPolling::hasAllThreadInterruptablePred void BBPolling::calculateInitialInterruptability(bool doPassingDown) { - const CFG::OrderType order = doPassingDown ? CFG::OrderType_Topological : CFG::OrderType_Arbitrary; - - for (CFG::NodeIterator it(irManager, order); it!=NULL; ++it) { - Node* node = it; + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); + assert(lt->isValid()); + const Nodes& postOrder = irManager.getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrder.rbegin(), end = postOrder.rend(); it!=end; ++it) { + Node* node = *it; const uint32 id = node->getId(); - if (node->isLoopHeader() && node->hasKind(Node::Kind_BasicBlock)) { + if (lt->isLoopHeader(node) && node->isBlockNode()) { loopHeaders.push_back(node); // here we calculate loopHeaders with depth == 0, and otherEdges for them // to create only one TLS base loader per each nested loop Node* loopHeader = node; - while (loopHeader->getLoopDepth() > 0) { - loopHeader = loopHeader->getLoopHeader(); + LoopNode* loop = lt->getLoopNode(loopHeader, false); + assert(loopHeader == loop->getHeader()); + while (loop->getDepth() > 1) { + loop = loop->getParent(); } + loopHeader = loop->getHeader(); if ( !toppestLoopHeader[id] ) { toppestLoopHeader[id] = loopHeader; // here we need to remember all otheredges and their start index for particular loopHeader otherStartNdx[loopHeader->getId()] = otherEdges.size(); - const Edges& edges = loopHeader->getEdges(Direction_In); - for (Edge* e = edges.getFirst(); e!=NULL; e = edges.getNext(e)) { - if ( !e->isBackEdge() ) { + const Edges& edges = loopHeader->getInEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + if ( !lt->isBackEdge(e) ) { otherEdges.push_back(e); } } @@ -270,18 +494,18 @@ BBPolling::calculateInitialInterruptabil hasNativeInterruptablePoint[id] = BBPolling::hasNativeInterruptablePoints(node); if (hasNativeInterruptablePoint[id]) { hasThreadInterruptablePoint[id] = true; - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " hasNativeInterruptablePoint["<isLoopHeader() ) { + if (!hasThreadInterruptablePoint[id] && !lt->isLoopHeader(node) ) { if ( hasThreadInterruptablePoint[id] = hasAllThreadInterruptablePredecessors(node) && - Log::cat_cg()->isDebugEnabled() ) + Log::isEnabled() ) { - Log::cat_cg()->out() << " (inherited) hasThreadInterruptablePoint["<getLoopTree(); + uint32 maxLoopDepth = lt->getMaxLoopDepth(); // process the deepest firstly for (uint32 currDepth = maxLoopDepth; currDepth > 0; currDepth--) @@ -300,21 +525,22 @@ BBPolling::calculateInterruptablePathes( for (uint32 i=0; i < loopHeaders.size(); i++) { Node* loopHeader = loopHeaders[i]; + LoopNode* loop = lt->getLoopNode(loopHeader, false); + assert(loopHeader == loop->getHeader()); const uint32 loopHeaderId = loopHeader->getId(); - if (loopHeader->getLoopDepth() == currDepth - 1) - { - if (hasNativeInterruptablePoint[loopHeaderId]) - { + if (loop->getDepth() == currDepth - 1) { + if (hasNativeInterruptablePoint[loopHeaderId]) { // fortunately we can skip this loop, because it is already interruptable ( it has respective // instructions and it was calculated earlier in calculateInitialInterruptability() ) continue; } // Process all successors of the loopHeader - const Edges& edges = loopHeader->getEdges(Direction_Out); - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) { - Node* succ = e->getNode(Direction_Head); - if( loopHeader == succ->getLoopHeader() ) { + const Edges& edges = loopHeader->getOutEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + Node* succ = e->getTargetNode(); + if( loop->inLoop(succ) && succ == loopHeader) { isOnInterruptablePath(succ); } else { // this edge does not go into the loop. Skip it. @@ -326,10 +552,10 @@ BBPolling::calculateInterruptablePathes( // Also it gets isOnThreadInterruptablePath mark for further selection of eligibleEdges hasThreadInterruptablePoint[loopHeaderId] = true; isOnThreadInterruptablePath[loopHeaderId] = true; - if (Log::cat_cg()->isDebugEnabled()) { - Log::cat_cg()->out() << " loopHeader:" << ::std::endl; - Log::cat_cg()->out() << " hasThreadInterruptablePoint["<out() << " isOnThreadInterruptablePath["<getId(); // the order of these check is essential! (because in case of nested loops // if the node is a loopHeader of a nested loop we must return true) + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); if( hasThreadInterruptablePoint[id] ) { isOnThreadInterruptablePath[id] = true; - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " isOnThreadInterruptablePath["<isLoopHeader() ) { + } else if ( lt->isLoopHeader(node) ) { return false; // loopHeader also breaks the recursion } bool retValue = false; - const Edges& edges = node->getEdges(Direction_Out); - - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) { - Node* succ = e->getNode(Direction_Head); + const Edges& edges = node->getOutEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e= *ite; + Node* succ = e->getTargetNode(); - if( !e->isLoopExit() && isOnInterruptablePath(succ) ) - { - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " isOnThreadInterruptablePath["<isLoopExit(e) && isOnInterruptablePath(succ) ) { + if (Log::isEnabled()) + Log::out() << " isOnThreadInterruptablePath["<getLoopTree(); for (uint32 i=0; i < loopHeaders.size(); i++) { Node* node = loopHeaders[i]; - const Edges& edges = node->getEdges(Direction_In); - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) { - if ( e->isBackEdge() && !e->hasKind(Edge::Kind_CatchEdge) && - !hasThreadInterruptablePoint[e->getNode(Direction_Tail)->getId()] + const Edges& edges = node->getInEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + if ( lt->isBackEdge(e) && !e->isCatchEdge() && + !hasThreadInterruptablePoint[e->getSourceNode()->getId()] ) { eligibleEdges.push_back(e); @@ -396,21 +624,23 @@ BBPolling::collectEligibleEdges() void BBPolling::collectEligibleEdges2() { - for (CFG::NodeIterator it(irManager, CFG::OrderType_Arbitrary); it!=NULL; ++it) { - Node* node = it; + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); + const Nodes& nodes = irManager.getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; const uint32 id = node->getId(); if ( isOnThreadInterruptablePath[id] && ! hasNativeInterruptablePoint[id] ) { - const Edges& edges = node->getEdges(Direction_Out); - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) { - Node* succ = e->getNode(Direction_Head); + const Edges& edges = node->getOutEdges(); + LoopNode* nodeLoop = lt->getLoopNode(node, false); + assert(nodeLoop!=NULL); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + Node* succ = e->getTargetNode(); uint32 succId = succ->getId(); - Node* nodeLH = node->isLoopHeader() ? node : node->getLoopHeader(); - assert(nodeLH); - if ( succ == node || nodeLH == succ->getLoopHeader() || e->isBackEdge() ) { - if( !isOnThreadInterruptablePath[succId] ) - { + if (nodeLoop->inLoop(succ)) { + if( !isOnThreadInterruptablePath[succId] ) { eligibleEdges.push_back(e); - loopHeaderOfEdge[e] = nodeLH; + loopHeaderOfEdge[e] = nodeLoop->getHeader(); } } else { continue; // the edge leaves our loop @@ -441,37 +671,40 @@ BBPolling::collectEdgesDeeper(Node* node if (hasNativeInterruptablePoint[id]) { return; } + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); if ( isOnThreadInterruptablePath[id] ) { // if the node has an outgoing edge to the node which: // - is not OnThreadInterruptablePath // - OR this ougoing edge points to the node itself // add the edge to eligibleEdges if it is not a loopExit - const Edges& edges = node->getEdges(Direction_Out); - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) { - Node* succ = e->getNode(Direction_Head); + const Edges& edges = node->getOutEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + Node* succ = e->getTargetNode(); uint32 succId = succ->getId(); if ( succ == node ) { eligibleEdges.push_back(e); loopHeaderOfEdge[e] = node; } - Node* nodeLH = node->isLoopHeader() ? node : node->getLoopHeader(); - assert(nodeLH); - if ( nodeLH == succ->getLoopHeader() ) { + LoopNode* nodeLoop= lt->getLoopNode(node, false); + assert(nodeLoop); + if ( nodeLoop->inLoop(succ) && succ != nodeLoop->getHeader()) { if(!isOnThreadInterruptablePath[succId]) { eligibleEdges.push_back(e); - loopHeaderOfEdge[e] = nodeLH; + loopHeaderOfEdge[e] = nodeLoop->getHeader(); } else { - if (succ->isLoopHeader()) { + if (lt->isLoopHeader(succ)) { continue; // there are no eligible edges deeper (nested loop) } else { collectEdgesDeeper(succ); } } - } else if (e->isBackEdge()) { + } else if (lt->isBackEdge(e)) { // get a backedge and have not met any interruptable points earlier + assert(e->getTargetNode() == nodeLoop->getHeader()); eligibleEdges.push_back(e); - loopHeaderOfEdge[e] = nodeLH; + loopHeaderOfEdge[e] = nodeLoop->getHeader(); } else { continue; // the edge leaves our loop } @@ -484,15 +717,15 @@ BBPolling::collectEdgesDeeper(Node* node void BBPolling::dumpEligibleEdges() { - assert(Log::cat_cg()->isDebugEnabled()); - Log::cat_cg()->out() << " EligibleEdges:" << ::std::endl; + assert(Log::isEnabled()); + Log::out() << " EligibleEdges:" << ::std::endl; for (uint32 i = 0; eligibleEdges.size() > i; i++) { Edge* e = eligibleEdges[i]; - uint32 srcId = e->getNode(Direction_Tail)->getId(); - uint32 succId = e->getNode(Direction_Head)->getId(); - Log::cat_cg()->out() << " eligibleEdge ["<["<getSourceNode()->getId(); + uint32 succId = e->getTargetNode()->getId(); + Log::out() << " eligibleEdge ["<["<out() << " EligibleEdges END! " << ::std::endl; + Log::out() << " EligibleEdges END! " << ::std::endl; } #ifdef _DEBUG @@ -506,13 +739,13 @@ BBPolling::isEligible(Edge* e) void BBPolling::verify() { - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << "BBPolling verification started" << ::std::endl; + if (Log::isEnabled()) + Log::out() << "BBPolling verification started" << ::std::endl; interruptablePoints = 0; pollingPoints = 0; - Node* unwind = irManager.getUnwindNode(); - Node* exit = irManager.getExitNode(); + Node* unwind = irManager.getFlowGraph()->getUnwindNode(); + Node* exit = irManager.getFlowGraph()->getExitNode(); for (uint32 i=0; i < loopHeaders.size(); i++) { @@ -525,42 +758,45 @@ BBPolling::verify() if(nativelyInterruptable) interruptablePoints++; - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification for loopHeader id=" << loopHeader->getId() << "STARTED" << ::std::endl; + if (Log::isEnabled()) + Log::out() << " verification for loopHeader id=" << loopHeader->getId() << "STARTED" << ::std::endl; verifyDeeper(loopHeader,unwind,exit); - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification for loopHeader id=" << loopHeader->getId() << "FINISHED" << ::std::endl; + if (Log::isEnabled()) + Log::out() << " verification for loopHeader id=" << loopHeader->getId() << "FINISHED" << ::std::endl; if(nativelyInterruptable) interruptablePoints--; } assert(interruptablePoints == 0); assert(pollingPoints == 0); - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << "BBPolling verification successfully finished" << ::std::endl; + if (Log::isEnabled()) + Log::out() << "BBPolling verification successfully finished" << ::std::endl; } // verify void BBPolling::verifyDeeper(Node* node, Node* unwind, Node* exit) { - const Edges& edges = node->getEdges(Direction_Out); - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification: NODE id=" << node->getId() << ::std::endl; + const Edges& edges = node->getOutEdges(); + if (Log::isEnabled()) { + Log::out() << " verification: NODE id=" << node->getId() << ::std::endl; + } + + LoopTree* lt = irManager.getFlowGraph()->getLoopTree(); - for (Edge* e = edges.getFirst(); e != NULL; e = edges.getNext(e)) - { + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e= *ite; bool eligible = isEligible(e); - Node* succ = e->getNode(Direction_Head); + Node* succ = e->getTargetNode(); - if ( e->isLoopExit() || succ == unwind ) { + if ( lt->isLoopExit(e) || succ == unwind ) { continue; } - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification: succ id=" << succ->getId() << ::std::endl; - if ( e->isBackEdge() ) { - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification BackEdge ["<getId()<<"]-->["<getId()<<"]" << ::std::endl; + if (Log::isEnabled()) + Log::out() << " verification: succ id=" << succ->getId() << ::std::endl; + if ( lt->isBackEdge(e)) { + if (Log::isEnabled()) + Log::out() << " verification BackEdge ["<getId()<<"]-->["<getId()<<"]" << ::std::endl; if(pollingPoints == 0 && eligible) continue; if(pollingPoints == 1 && !eligible) @@ -569,11 +805,13 @@ BBPolling::verifyDeeper(Node* node, Node continue; assert(0); } - if (succ->isLoopHeader()) { // nested loop - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << " verification NestedLoop" << ::std::endl; - if(pollingPoints == 0 && !eligible) + if (lt->isLoopHeader(succ)) { // nested loop + if (Log::isEnabled()) { + Log::out() << " verification NestedLoop" << ::std::endl; + } + if(pollingPoints == 0 && !eligible) { continue; + } assert(0); } diff --git vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.h vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.h deleted file mode 100644 index c801b1a..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32BBPolling.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author George A. Timoshenko - * @version $Revision: 1.1.12.4.4.3 $ - */ - -#ifndef _IA32_BBPOLLING_H_ -#define _IA32_BBPOLLING_H_ - -#include "Ia32IRManager.h" - -namespace Jitrino -{ -namespace Ia32{ - -const uint32 BBPollingMaxVersion = 6; - -//======================================================================================== -// class BBPolling -//======================================================================================== -/** - class BBPolling implements utilities for back branch polling pass - -*/ -class BBPolling -{ -typedef ::std::pair targetIdDispatchIdPair; -typedef StlMap BBPControllersMap; -public: - - BBPolling(IRManager& ir,uint32 ver) : - irManager(ir), - version(ver), - hasThreadInterruptablePoint(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, false), - hasNativeInterruptablePoint(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, false), - isOnThreadInterruptablePath(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, false), - tlsBaseRegForLoopHeader(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, NULL), - bbpCFGControllerForNode(irManager.getMemoryManager()), - toppestLoopHeader(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, NULL), - otherStartNdx(irManager.getMemoryManager(), irManager.getMaxNodeId()+1, 0), - loopHeaders(irManager.getMemoryManager()), - otherEdges(irManager.getMemoryManager()), - eligibleEdges(irManager.getMemoryManager()), -#ifdef _DEBUG - interruptablePoints(0), - pollingPoints(0), -#endif - loopHeaderOfEdge(irManager.getMemoryManager()) - { - calculateInitialInterruptability(version == 5 || version == 6); - - if (version == 2 || version == 3) - calculateInterruptablePathes(); - // no more calculations here, just collect the edges! - switch (version) { - case 1: collectEligibleEdges(); break; - case 2: collectEligibleEdges2(); break; - case 3: collectEligibleEdgesRecursive(); break; - case 4: collectEligibleEdges(); break; - case 5: collectEligibleEdges(); break; - case 6: collectEligibleEdges(); break; - default: assert(0); - } - if (Log::cat_cg()->isDebugEnabled()) { - dumpEligibleEdges(); - } -#ifdef _DEBUG - if (version == 2 || version == 3) - verify(); -#endif - } - - uint32 numberOfAffectedEdges() { return eligibleEdges.size(); } - Edge* getAffectedEdge(uint32 i) { assert(i < eligibleEdges.size()); return eligibleEdges[i]; } - - Opnd* getOrCreateTLSBaseReg(Edge* e); - - static bool isThreadInterruptablePoint(const Inst* inst); - - static bool hasNativeInterruptablePoints(const Node* node); - - bool hasAllThreadInterruptablePredecessors(const Node* node); - - Node* getBBPSubCFGController(uint32 targetId, uint32 dispatchId); - void setBBPSubCFGController(uint32 targetId, uint32 dispatchId, Node* node); - CFG* createBBPSubCFG(IRManager& ir, Opnd* tlsBaseReg); - -private: - - bool isInterruptable(const BasicBlock* b) { - return hasThreadInterruptablePoint[b->getId()]; - } - // select all loopHeaders - // identify all nodes which hasNativeInterruptablePoints - // mark all successors of such nodes as hasThreadInterruptablePoint - void calculateInitialInterruptability(bool doPassingDown); - // identify the nodes which are on the way from a loopHeader to a node which hasThreadInterruptablePoints - void calculateInterruptablePathes(); - bool isOnInterruptablePath(Node* node); - - // collect the edges for substition by subCFG that checks the flag and call the helper if the flag. - // These edges are those from a Node which isOnInterruptablePath to it's succ_node which is not. - void collectEligibleEdges(); // all backedges - void collectEligibleEdges2(); // all pairs [isOnThreadInterruptablePath]->[!isOnThreadInterruptablePath] - void collectEligibleEdgesRecursive(); // recursive selecting of 2 - void collectEdgesDeeper(Node* node); - - void dumpEligibleEdges(); - -#ifdef _DEBUG - bool isEligible(Edge* e); - void verify(); - void verifyDeeper(Node* node, Node* enwind, Node* exit); -#endif // _DEBUG - - IRManager& irManager; - - // version of BBPolling: - // 0 - must be discarded in runImpl() - // 1 - insert bbpCFG at all backedges - // 2 - path analysis based on searching of pairs [isOnThreadInterruptablePath]->[!isOnThreadInterruptablePath] - // 3 - recursive version of "2" - // 4 - "1" + suspension flag addr [TLS base + offset] is calculated before the loop header - // 5 - like "1" but some backedges are not patched (if all paths through it are interuuptable) - // 6 - "4" + "5" - // 7.. illegal - uint32 version; - // storage for ThreadInterruptablePoints information - // hasThreadInterruptablePoint[Node->getId()] == true means that the Node is a LoopHeader - // OR It has at least one instruction that isThreadInterruptablePoint(inst) - // OR all predecessors hasThreadInterruptablePoint or incoming edge is a loopExit - StlVector hasThreadInterruptablePoint; - StlVector hasNativeInterruptablePoint; // only those that hase at least one InterruptablePoint(inst) - // storage for InterruptablePathes information - // isOnThreadInterruptablePath[Node->getId()] == true means that there is a way from the Node - // to another a_node which hasThreadInterruptablePoint[a_node->getId()] - StlVector isOnThreadInterruptablePath; - // tlsBaseRegs pointers. One per each affected loopHeader - StlVector tlsBaseRegForLoopHeader; - // pointers to already prepared bbpCFG. bbpCFG is placed "before" a node to collect all eligible edges. - // pair.first - targetNode id - // pair.second - sourceNode dispatch edge target id - BBPControllersMap bbpCFGControllerForNode; - // to get the toppest loop header of the given without calling getLoopHeader - StlVector toppestLoopHeader; - // start index in otheredges collection for the toppest loop headers - StlVector otherStartNdx; - - // just a collection of loop headers of the method (Basic blocks only!) - StlVector loopHeaders; - // edgse which are not a back edge - StlVector otherEdges; - // edges for inserting BBPolling subCFG - StlVector eligibleEdges; - -#ifdef _DEBUG - uint32 interruptablePoints; - uint32 pollingPoints; -#endif - StlHashMap loopHeaderOfEdge; - -}; // BBPolling class - -//___________________________________________________________________________________________________ -BEGIN_DECLARE_IRTRANSFORMER(BBPollingTransformer, "bbp", "Back-branch polling. (Insertion of thread suspend points)") - - BBPollingTransformer(IRManager& irm, const char * params=0): IRTransformer(irm, params),hasSideEffects(false){} - - bool hasSideEffects; - - void runImpl(){ - if(!irManager.hasLoops()) - return; - if (parameters) { - version = atoi(std::string(parameters).c_str()); - if(version == 0) - return; - if(version > BBPollingMaxVersion) { - assert(0); - return; - } - } else { - return; - } - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << "BBPolling transformer version="<< version <<" STARTED" << ::std::endl; - BBPolling bbp = BBPolling(irManager, version); - uint32 numOfAffectedEdges = bbp.numberOfAffectedEdges(); - hasSideEffects = numOfAffectedEdges != 0; - // Foreach eligible backedge create bbpCFG and inline it between the backedge's Tail and it's target - for (uint32 j = 0; j < numOfAffectedEdges; j++) { - Edge* edge = bbp.getAffectedEdge(j); - - // get or create and insert before the loopHeade a basic block for calculating TLS base - Opnd* tlsBaseReg = bbp.getOrCreateTLSBaseReg(edge); - - uint32 originalTargetId = edge->getNode(Direction_Head)->getId(); - Edge* srcDispatchEdge = edge->getNode(Direction_Tail)->getEdge(Direction_Out,Node::Kind_DispatchNode); - uint32 sourceDispatchId = srcDispatchEdge ? srcDispatchEdge->getNode(Direction_Head)->getId() : 0; - // CFG for inlining - Node* bbpCFGController = bbp.getBBPSubCFGController(originalTargetId,sourceDispatchId); - if (bbpCFGController) { // just retarget the edge - irManager.retargetEdge(Direction_Head, edge, bbpCFGController); - } else { // we need a new bbpCFG - CFG* bbpCFG = bbp.createBBPSubCFG(irManager, tlsBaseReg); - - // Inlining bbpCFG at edge - irManager.mergeGraphAtEdge(bbpCFG, edge, true /*take parent's dispatch*/); - bbp.setBBPSubCFGController(originalTargetId,sourceDispatchId,edge->getNode(Direction_Head)); - } - } - if (Log::cat_cg()->isDebugEnabled()) - Log::cat_cg()->out() << "BBPolling transformer FINISHED" << ::std::endl; - } //runImpl() - uint32 getNeedInfo()const{ return NeedInfo_LoopInfo; } - uint32 getSideEffects()const{ return hasSideEffects ? SideEffect_InvalidatesLoopInfo|SideEffect_InvalidatesLivenessInfo : 0; } - bool isIRDumpEnabled(){ return true; } - uint32 version; -END_DECLARE_IRTRANSFORMER(BBPollingTransformer) - - -}}; // namespace Ia32 - -#endif // _IA32_BBPOLLING_H_ - diff --git vm/jitrino/src/codegenerator/ia32/Ia32BCMap.h vm/jitrino/src/codegenerator/ia32/Ia32BCMap.h index ae08802..49456a8 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32BCMap.h +++ vm/jitrino/src/codegenerator/ia32/Ia32BCMap.h @@ -45,41 +45,41 @@ #ifdef _DEBUG #endif } - uint32 getByteSize() { - uint32 mapSize = theMap->size(); + POINTER_SIZE_INT getByteSize() { + POINTER_SIZE_INT mapSize = theMap->size(); return (mapSize * (byteCodeOffsetSize + wordSize) + wordSize); } void write(Byte* output) { - uint32* data = (uint32*)output; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; StlHashMap::const_iterator citer; - uint32 mapSize; - uint32 i = 0; + POINTER_SIZE_INT mapSize; + POINTER_SIZE_INT i = 0; mapSize = theMap->size(); data[0] = mapSize; //store map size data = data + 1; for (citer = theMap->begin(); citer != theMap->end(); citer++) { - data[i*2] = (uint32)citer->first; // write key i.e. native addr - data[i*2+1] = (uint32)citer->second; // write value i.e. bc offset + data[i*2] = (POINTER_SIZE_INT)citer->first; // write key i.e. native addr + data[i*2+1] = (POINTER_SIZE_INT)citer->second; // write value i.e. bc offset i++; } return; } - uint32 readByteSize(const Byte* input) const { - uint32* data = (uint32*)input; - uint32 sizeOfMap = data[0]; + POINTER_SIZE_INT readByteSize(const Byte* input) const { + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)input; + POINTER_SIZE_INT sizeOfMap = data[0]; return (sizeOfMap * (byteCodeOffsetSize + wordSize) + wordSize); } /** read is deprecated method since creating HashMap is too cost */ void read(const Byte* output) { - uint32* data = (uint32*)output; - uint32 mapSize; - uint32 i = 0; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; + POINTER_SIZE_INT mapSize; + POINTER_SIZE_INT i = 0; mapSize = data[0]; //read map size data = data + 1; @@ -94,7 +94,7 @@ #endif } void writeZerroSize(Byte* output) { - uint32* data = (uint32*)(output); + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)(output); data[0] = 0; return; @@ -115,11 +115,11 @@ #endif } static uint64 get_bc_location_for_native(uint64 ncAddress, Byte* output) { - uint32* data = (uint32*)output; - uint32 mapSize; - uint32 i = 0; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; + POINTER_SIZE_INT mapSize; + POINTER_SIZE_INT i = 0; - mapSize = data[0]; //read map size + mapSize = data[0]; //read map size data = data + 1; for (i = 0; i < mapSize; i++) { @@ -132,17 +132,17 @@ #endif } static uint64 get_native_location_for_bc(uint64 bcOff, Byte* output) { - uint32* data = (uint32*)output; - uint32 mapSize; - uint32 i = 0; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; + POINTER_SIZE_INT mapSize; + POINTER_SIZE_INT i = 0; - mapSize = data[0]; //read map size + mapSize = data[0]; //read map size data = data + 1; uint64 ncAddress = ILLEGAL_VALUE; for (i = 0; i < mapSize; i++) { - uint32 ncAddr, bcOffset; + POINTER_SIZE_INT ncAddr, bcOffset; ncAddr = data[i * 2]; bcOffset = data[i * 2 + 1]; if (bcOffset == bcOff) ncAddress = ncAddr; @@ -155,15 +155,15 @@ #endif uint64 get_native_location_for_bc_prev(uint64 bcOff, Byte* output) { uint64 ncAddress = ILLEGAL_VALUE; #ifdef _DEBUG - uint32* data = (uint32*)output; - uint32 mapSize; - uint32 i = 0; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; + POINTER_SIZE_INT mapSize; + POINTER_SIZE_INT i = 0; mapSize = data[0]; //read map size data = data + 1; for (i = 0; i < mapSize; i++) { - uint32 ncAddr, bcOffset; + POINTER_SIZE_INT ncAddr, bcOffset; ncAddr = data[i * 2]; bcOffset = data[i * 2 + 1]; setEntry(ncAddr, bcOffset); // read key i.e. native addr and read value i.e. bc offset @@ -185,12 +185,12 @@ #endif } protected: private: - uint32 sizeInBytes; - uint32 mapSize; + POINTER_SIZE_INT sizeInBytes; + POINTER_SIZE_INT mapSize; StlHashMap* theMap; StlHashMultiMap* revMultiMap; - const static int wordSize = 4; // 4 bytes for ia32 - const static int byteCodeOffsetSize = 4; // byteCodeAddrSize should be 2, 4 will allow easy mem alignment + const static int wordSize = sizeof(POINTER_SIZE_INT); // 4 bytes for ia32 + const static int byteCodeOffsetSize = sizeof(POINTER_SIZE_INT); // byteCodeAddrSize should be 2, 4 will allow easy mem alignment typedef ::std::pair IntPair; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32CFG.cpp vm/jitrino/src/codegenerator/ia32/Ia32CFG.cpp index 98d47b4..b08b37d 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CFG.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32CFG.cpp @@ -14,1096 +14,36 @@ * limitations under the License. */ /** - * @author Intel, Vyacheslav P. Shakin, Mikhail Y. Fursov - * @version $Revision: 1.17.12.2.4.4 $ + * @author Vyacheslav P. Shakin, Mikhail Y. Fursov + * @version $Revision$ */ #include "Log.h" #include "Ia32CFG.h" -#include "Ia32Inst.h" -namespace Jitrino -{ -namespace Ia32{ +#include "Ia32IRManager.h" - //========================================================================================================= - // CFG Edge - //========================================================================================================= +namespace Jitrino{ +namespace Ia32 { - //_________________________________________________________________________________________________________ - bool Edge::isBlockEdge()const - { - return nodes[Direction_Head]->hasKind(Node::Kind_BasicBlock) && - nodes[Direction_Tail]->hasKind(Node::Kind_BasicBlock); - } +void CGNode::verify() { +} - //_________________________________________________________________________________________________________ - bool Edge::isBackEdge()const - { - Node * head=nodes[Direction_Head]; - return head->isLoopHeader() && getNode(Direction_Tail)->isWithinLoop(head); - } - - //_________________________________________________________________________________________________________ - bool Edge::isFallThroughEdge()const - { - return isBlockEdge() && ((BasicBlock*)nodes[Direction_In])->getFallThroughEdge()==this; - } - - //_________________________________________________________________________________________________________ - bool Edge::isDirectBranchEdge()const - { - return isBlockEdge() && ((BasicBlock*)nodes[Direction_In])->getDirectBranchEdge()==this; - } - - - //_________________________________________________________________________________________________________ - /** Check if an edge is a loop exit edge */ - bool Edge::isLoopExit() const - { - Node * tail=nodes[Direction_Tail]; - Node * tailLoopHeader = tail->isLoopHeader() ? tail : tail->getLoopHeader(); - return tailLoopHeader && !getNode(Direction_Head)->isWithinLoop(tailLoopHeader); - } - - //_________________________________________________________________________________________________________ - BranchInst * Edge::getBranch()const - { - Node * node=getNode(Direction_Tail); - if (!node->hasKind(Node::Kind_BasicBlock)) - return NULL; - BasicBlock * bb=(BasicBlock*)node; - if (bb->getDirectBranchEdge()!=this) - return NULL; - Inst * inst=bb->getInsts().getLast(); - assert(inst && inst->hasKind(Inst::Kind_BranchInst) && ((BranchInst*)inst)->isDirect()); - return (BranchInst*)inst; - } - - //========================================================================================================= - // Edges - //========================================================================================================= - //_________________________________________________________________________________________________________ - bool Edges::has(const Edge * edge)const - { - Edge * e = NULL; - for (e=getFirst(); e!=NULL && e!=edge; e=getNext(e)); - return e==edge; - } - - //========================================================================================================= - // Node - //========================================================================================================= - - //_________________________________________________________________________________________________________ - /** Construct a node */ - - Node::Node(CFG * cfg, uint32 _id, ExecCntValue cnt) - : id(_id), cfg(cfg), - execCnt(cnt), persistentId(EmptyUint32) - , nodeIsHeader(false), loopHeader(NULL) - { - edges[Direction_Backward].direction=Direction_Backward; - edges[Direction_Forward].direction=Direction_Forward; - liveAtEntry = new (cfg->getMemoryManager()) LiveSet(cfg->getMemoryManager(), 0); - cfg->incModCount(); - } - - //_________________________________________________________________________________________________________ - Edge * Node::getEdge(Direction dir, Kind k)const - { - const Edges & es=edges[dir]; - Edge * e = NULL; - for (e=es.getFirst(); e!=NULL && !e->getNode(dir)->hasKind(k); e=es.getNext(e)); - return e; - } - - //_________________________________________________________________________________________________________ - Edge * Node::getEdge(Direction dir, Node * node)const - { - const Edges & es=edges[dir]; - Edge * e = NULL; - for ( e=es.getFirst(); e!=NULL && e->getNode(dir)!=node; e=es.getNext(e)); - return e; - } - - //_________________________________________________________________________________________________________ - void Node::addEdge(Direction dir, Edge * edge) - { - assert(edge->getNode(dir==Direction_Out?Direction_Tail:Direction_Head)==this); - assert(edge->hasKind(Edge::Kind_CatchEdge) || !isConnectedTo(dir, edge->getNode(dir))); // such edge already exists - cfg->incModCount(); - edges[dir].append(edge); - } - - //_________________________________________________________________________________________________________ - void Node::delEdge(Direction dir, Edge * edge) - { - assert(edge->getNode(dir==Direction_Out?Direction_Tail:Direction_Head)==this); - assert(edges[dir].has(edge)); - cfg->incModCount(); - edges[dir].del(edge); - } - - //_________________________________________________________________________________________________________ - bool Node::isLoopHeader() const { - assert(cfg->isLoopInfoValid()); - return nodeIsHeader; - } - - //_________________________________________________________________________________________________________ - Node* Node::getLoopHeader() const { - assert(cfg->isLoopInfoValid()); - return loopHeader; - } - //_________________________________________________________________________________________________________ - bool Node::hasLoopInfo() const { - return cfg->isLoopInfoValid(); - } - //_________________________________________________________________________________________________________ - /** Compute loop depth */ - uint32 Node::getLoopDepth() const - { - uint32 depth = 0; - for (const Node * h=getLoopHeader(); h != NULL; h = h->getLoopHeader()) depth++; - return depth; - } - - //_________________________________________________________________________________________________________ - /** Check if a node is contained (directly or nested) in a loop headed by loopHeader. */ - bool Node::isWithinLoop(const Node * loopHeader) const - { - const Node * h=this; - for (; h != NULL && h != loopHeader; h = h->getLoopHeader()); - return h == loopHeader; - } - - //_________________________________________________________________________________________________ - void Node::verify() - { - const Edges& inEdges=getEdges(Direction_In); - const Edges& outEdges=getEdges(Direction_Out); - for (Edge * edge=inEdges.getFirst(); edge!=NULL; edge=inEdges.getNext(edge)) - assert(edge->getNode(Direction_Tail)->isConnectedTo(Direction_Out, this)); - for (Edge * edge=outEdges.getFirst(); edge!=NULL; edge=outEdges.getNext(edge)) - assert(edge->getNode(Direction_Head)->isConnectedTo(Direction_In, this)); - } - - //========================================================================================================= - // Exception Dispath Node - //========================================================================================================= - - //_________________________________________________________________________________________________________ - /** Check if catch edges are sorted */ - - bool DispatchNode::catchEdgesAreSorted() const { - const Edges& oEdges = getEdges(Direction_Out); - uint32 idx = 0; - for (Edge *edge = oEdges.getFirst() ;edge!=NULL; edge = oEdges.getNext(edge), idx++) { - if (edge->hasKind(Edge::Kind_CatchEdge) && ((CatchEdge*)edge)->getPriority()!=idx) { - return false; - } - } - return true; - } - - - //_________________________________________________________________________________________________________ - /** Sort catch edges according to their priority */ - - void DispatchNode::sortCatchEdges() { - Edges& oEdges = edges[Direction_Out]; - uint32 numCatchEdges = 0; - for (Edge *edge = oEdges.getFirst(); edge!=NULL; edge = oEdges.getNext(edge)) { - if (edge->hasKind(Edge::Kind_CatchEdge)) { - numCatchEdges++; - } - } - if (numCatchEdges == 0) { - return; - } - uint32 count = oEdges.getCount(); - StlVector sortedEdges(getCFG()->getMemoryManager(), count); - uint32 nonCatchIdx = numCatchEdges; - for (Edge *edge = oEdges.getFirst(), *nextEdge = NULL; edge!=NULL; edge = nextEdge) { - nextEdge = oEdges.getNext(edge); - delEdge(Direction_Out, edge); - if (edge->hasKind(Edge::Kind_CatchEdge)) { - uint32 idx = ((CatchEdge*)edge)->getPriority(); - assert(idx < numCatchEdges && sortedEdges[idx] == NULL); - sortedEdges[idx] = edge; - } else { // non-catch edges moved to the end of the list - assert(sortedEdges[nonCatchIdx] == NULL); - sortedEdges[nonCatchIdx] = edge; - nonCatchIdx++; - } - } - for (uint32 i = 0; igetNode(Direction_Head)->hasKind(Node::Kind_BasicBlock)); - if (directBranchEdge==edge) - directBranchEdge=fallThroughEdge; - fallThroughEdge=edge; - assert(layoutSucc==NULL||layoutSucc==fallThroughEdge->getNode(Direction_Head)); - } - - //_________________________________________________________________________________________________________ - void BasicBlock::makeEdgeDirectBranch(Edge * edge) - { - assert(edges[Direction_Head].has(edge)); - assert(edge->getNode(Direction_Head)->hasKind(Node::Kind_BasicBlock)); - assert(!isEmpty()); - assert(getInsts().getLast()->hasKind(Inst::Kind_BranchInst) && ((BranchInst*)getInsts().getLast())->isDirect()); - if (fallThroughEdge==edge){ - fallThroughEdge=directBranchEdge; - assert(fallThroughEdge==NULL||layoutSucc==NULL||layoutSucc==fallThroughEdge->getNode(Direction_Head)); - } - directBranchEdge=edge; - } - - //_________________________________________________________________________________________________________ - void BasicBlock::recalculateFallThroughEdgeProbability() - { - Edge * fallEdge=getFallThroughEdge(); - const Edges& outEdges=getEdges(Direction_Out); - ProbValue p=1.0; - for (Edge * edge=outEdges.getFirst(); edge!=NULL; edge=outEdges.getNext(edge)){ - if (edge!=fallEdge) - p-=edge->getProbability(); - } - if (p<=0.0) p=0.00001; - fallEdge->setProbability(p); - } - - //_________________________________________________________________________________________________________ - void BasicBlock::delEdge(Direction dir, Edge * edge) - { - if (dir == Direction_Out){ - if (directBranchEdge==edge) - directBranchEdge=0; - if (fallThroughEdge==edge) - fallThroughEdge=0; - } - Node::delEdge(dir, edge); - } - - //_________________________________________________________________________________________________________ - BasicBlock * BasicBlock::cloneSkeleton(CFG * cfg, uint32 nIn, uint32 nOut) - { - return 0; - } - - //_________________________________________________________________________________________________ - void BasicBlock::appendInsts(Inst * instList, Inst * after) - { - if (instList==0) - return; - if (after==NULL) - after=insts.getLast(); - assert(after==NULL||after->getBasicBlock()==this); - Inst * inst=NULL, * nextInst=instList, * lastInst=instList->getPrev(); - do { - inst=nextInst; - nextInst=inst->getNext(); - assert(inst->basicBlock==NULL); - inst->unlink(); - inst->basicBlock=this; insts.append(inst, after); - after=inst; - } while (inst!=lastInst); - } - - //_________________________________________________________________________________________________ - void BasicBlock::prependInsts(Inst * instList, Inst * before) - { - if (instList==0) - return; - if (before==NULL) - before=insts.getFirst(); - assert(before==NULL||before->getBasicBlock()==this); - Inst * inst=NULL, * nextInst=instList, * lastInst=instList->getPrev(); - do{ - inst=nextInst; - nextInst=inst->getNext(); - assert(inst->basicBlock==NULL); - inst->unlink(); - inst->basicBlock=this; insts.prepend(inst, before); - } while (inst!=lastInst); - } - - //_________________________________________________________________________________________________ - void BasicBlock::removeInst(Inst * inst) - { - assert(inst->basicBlock==this); - inst->basicBlock=NULL; - insts.del(inst); - } - - //_________________________________________________________________________________________________ - BasicBlock * BasicBlock::getIndirectBranchPredecessor()const - { - const Edges & inEdges = getEdges(Direction_In); - for (Edge * edge=inEdges.getFirst(); edge!=NULL; edge=inEdges.getNext(edge)){ - Node * node = edge->getNode(Direction_Tail); - if (!node->hasKind(Kind_BasicBlock)) - continue; - BasicBlock * bb=(BasicBlock*)node; - Inst * inst = bb->getInsts().getLast(); - if ( inst != NULL && inst->hasKind(Inst::Kind_BranchInst) && inst->getOpndCount() != 0 && inst->getOpnd(0)->isPlacedIn(OpndKind_Mem) ) - return bb; - } - return NULL; - } - - //_________________________________________________________________________________________________ - void BasicBlock::setLayoutSucc(BasicBlock *bb) - { - assert(bb!=this); - layoutSucc=bb; - } - - //_________________________________________________________________________________________________ - void * BasicBlock::getCodeStartAddr()const - { - return (uint8*)cfg->getCodeStartAddr()+getCodeOffset(); - } - - //_________________________________________________________________________________________________ - void BasicBlock::fixBasicBlockEndInstructions() - { - const Insts& insts=getInsts(); - Inst * instMustBeLast=NULL; - for (Inst * inst=insts.getLast(); inst!=NULL; inst=insts.getPrev(inst)){ - if (inst->hasKind(Inst::Kind_BranchInst)){ - instMustBeLast=inst; - break; - } - } - if (instMustBeLast){ - removeInst(instMustBeLast); - appendInsts(instMustBeLast); - } - } - - //_________________________________________________________________________________________________ - void BasicBlock::verify() - { - #ifdef _DEBUG - const Edges& outEdges=getEdges(Direction_Out); - - assert(fallThroughEdge==NULL || outEdges.has(fallThroughEdge)); - assert(directBranchEdge==NULL || outEdges.has(directBranchEdge)); - assert(directBranchEdge==NULL || (getInsts().getCount()>0 && getInsts().getLast()->hasKind(Inst::Kind_BranchInst))); - assert(directBranchEdge == NULL || (getInsts().getLast()->getProperties()&Inst::Properties_Conditional)==0 || fallThroughEdge!=NULL); - #endif - Node::verify(); - } - - //========================================================================================================= - // CFG - //========================================================================================================= - - //_________________________________________________________________________________________________ - CFG::CFG(MemoryManager& memManager) - :memoryManager(memManager), nodes(memManager), postorderNodesCache(memManager), nodeId(0), - prologNode(0), exitNode(0), unwindNode(0), - graphModCount(1), lastLoopInfoVersion(0),lastPostorderVersion(0), _isLaidOut(false), - maxLoopDepth(0), codeStartAddr(NULL), - traversalInfo(memManager), edgeProfile(false) - { - prologNode=newBasicBlock(); - prologNode->setLoopInfo(false, NULL); - newExitNode(); - } - - //_________________________________________________________________________________________________ - BasicBlock * CFG::newBasicBlock(ExecCntValue cnt) - { - BasicBlock * node=new(memoryManager) BasicBlock(this, nodeId++, cnt); - addNode(node); - return node; - } - - //_________________________________________________________________________________________________ - UnwindNode * CFG::newUnwindNode(ExecCntValue cnt) - { - assert(unwindNode == NULL); - unwindNode=new(memoryManager) UnwindNode(this, nodeId++, cnt); - addNode(unwindNode); - newEdge(unwindNode, exitNode, 1.0); - return unwindNode; - } - - //_________________________________________________________________________________________________ - ExitNode * CFG::newExitNode(ExecCntValue cnt) - { - assert(exitNode == NULL); - exitNode=new(memoryManager) ExitNode(this, nodeId++, cnt); - addNode(exitNode); - return exitNode; - } - - //_________________________________________________________________________________________________ - DispatchNode * CFG::newDispatchNode(ExecCntValue cnt) - { - DispatchNode * node=new(memoryManager) DispatchNode(this, nodeId++, cnt); - addNode(node); - return node; - } - - //_________________________________________________________________________________________________ - Edge * CFG::newEdge(Node *from, Node *to, ProbValue prob) - { - Edge * edge; -#ifdef _DEBUG - edge = from->getEdge(Direction_Out, to); - assert(!edge); - assert(!hasEdgeProfile() || (prob>0.0 && prob<=1.0)); -#endif - edge=new(memoryManager) Edge(from, to, prob); - from->addEdge(Direction_Out, edge); - to->addEdge(Direction_In, edge); - return edge; - } - - //_________________________________________________________________________________________________ - CatchEdge * CFG::newCatchEdge(DispatchNode * from, BasicBlock * to, Type *ty, uint32 prior, ProbValue prob) - { - Edge * edge; -#ifdef _DEBUG - edge = from->getEdge(Direction_Out, to); - assert(!edge); - assert(!hasEdgeProfile() || (prob>0.0 && prob<=1.0)); -#endif - - edge=new(memoryManager) CatchEdge(from, to, ty, prior, prob); - from->addEdge(Direction_Out, edge); - to->addEdge(Direction_In, edge); - return (CatchEdge *)edge; - } - - - //_________________________________________________________________________________________________ - void CFG::retargetEdge(Direction dir, Edge *edge, Node *newTo) - { - Direction nodeDir=dir==Direction_Head?Direction_In:Direction_Out; - edge->getNode(dir)->delEdge(nodeDir, edge); - edge->nodes[dir]=newTo; - newTo->addEdge(nodeDir, edge); - if (dir==Direction_Head && !newTo->hasKind(Node::Kind_BasicBlock)){ - Node * node = edge->getNode(nodeDir); - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bbFrom=(BasicBlock*)node; - if (bbFrom->fallThroughEdge==edge) - bbFrom->fallThroughEdge=NULL; - assert(!edge->isDirectBranchEdge()); - } - } - } - - //_________________________________________________________________________________________________ - void CFG::removeNode(Node * node) - { - for (uint32 i=0; i<2; i++){ - const Edges& es=node->getEdges(Direction(i)); - for (Edge * e=es.getFirst(), * ne=NULL; e!=NULL; e=ne){ - ne=es.getNext(e); - removeEdge(e); - } - } - delNode(node); - } - - //_________________________________________________________________________________________________ - void CFG::mergeSequentialBlocks() { - assert(!isLaidOut()); - for (Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - Node* node = *it; - tryMergeSequentialBlocks(node); - } - } - - //_________________________________________________________________________________________________ - void CFG::tryMergeSequentialBlocks(Node * node) - { - if (!node->hasKind(Node::Kind_BasicBlock)) - return; - BasicBlock * bb=(BasicBlock*)node; - if (bb==prologNode) - return; - if (isEpilog(bb)) - return; - if (!bb->canBeRemoved()) - return; - - const Edges & outEdges=bb->getEdges(Direction_Out); - Edge* fallEdge = bb->getFallThroughEdge(); - if (fallEdge==NULL) { - return; - } - for (Edge * edge=outEdges.getFirst(); edge!=NULL; edge=outEdges.getNext(edge)){ - if (edge!=fallEdge && !edge->getNode(Direction_Head)->hasKind(Node::Kind_UnwindNode)) { - return; - } - } - - BasicBlock * bbNext=(BasicBlock*)fallEdge->getNode(Direction_Out); - assert(bbNext->hasKind(Node::Kind_BasicBlock)); - - if (bbNext->getEdges(Direction_In).getCount()!=1) - return; - assert(bbNext->getEdges(Direction_In).getFirst()->getNode(Direction_Tail)==bb); - - if (bbNext->getNode(Direction_Out, Node::Kind_DispatchNode)!=NULL) - return; - - while(!bbNext->isEmpty()){ - Inst * inst=bbNext->getInsts().getFirst(); - bbNext->removeInst(inst); - bb->appendInsts(inst); - } - - const Edges & bbNextOutEdges=bbNext->getEdges(Direction_Out); - for (Edge * edge=bbNextOutEdges.getFirst(), * nextEdge=NULL; edge!=NULL; edge=nextEdge){ - nextEdge=bbNextOutEdges.getNext(edge); - if (!edge->isFallThroughEdge() && !bb->isConnectedTo(Direction_Out, edge->getNode(Direction_Head))){ - bool isDirectBranch=edge->isDirectBranchEdge(); - retargetEdge(Direction_Tail, edge, bb); - if (isDirectBranch){ - bb->makeEdgeDirectBranch(edge); - bb->recalculateFallThroughEdgeProbability(); - } - } - } - - purgeEmptyBlock(bbNext); - tryMergeSequentialBlocks(node); - } - - //_________________________________________________________________________________________________ - void CFG::purgeEmptyBlocks() { - assert(!isLaidOut()); - const Nodes& nodes = getNodesPostorder(); - for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { - Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock) && ((BasicBlock*)node)->isEmpty()){ - purgeEmptyBlock((BasicBlock*)node); - } - } - } - - - //_________________________________________________________________________________________________ - void CFG::purgeEmptyBlock(BasicBlock * bb) { - assert(!isLaidOut()); - assert(bb->getInsts().isEmpty()); - - if (!bb->canBeRemoved()) { - return; - } - - const Edges& inEdges=bb->getEdges(Direction_In); - const Edges& outEdges=bb->getEdges(Direction_Out); - - Edge* outEdge = NULL; - if (inEdges.getCount() == 1 && inEdges.getFirst()->hasKind(Edge::Kind_CatchEdge)) { - //handle catch edges - can't remove them (catch edge contains type info +priority info) - Edge* inEdge = inEdges.getFirst(); - assert(outEdges.getCount() == 1); - outEdge = outEdges.getFirst(); - Node* commonCatchHandler = outEdge->getNode(Direction_Head); - assert(commonCatchHandler->hasKind(Node::Kind_BasicBlock)); - retargetEdge(Direction_Head, inEdge, commonCatchHandler); - removeEdge(outEdge); - } else { - if (outEdges.getFirst()!=outEdges.getLast()) { - for (Edge* tmp = outEdges.getFirst(); tmp; tmp= outEdges.getNext(tmp)) { - if (tmp->isBlockEdge()) { - assert(outEdge == NULL); - outEdge = tmp; - } else { - // We don't want to introduce a disconnected cfg here. - Node* outNode = tmp->getNode(Direction_Head); - if( (outNode->getEdges(Direction_In)).getCount() == 1 ){ - return; - } - } - } - assert(outEdge!=NULL); - } else { - outEdge = outEdges.getFirst(); - } - if (outEdge!=NULL){ - Node* outNode = outEdge->getNode(Direction_Head); - - // Do not delete an empty while-true loop. - if( outNode == bb ){ - return; - } - - for (Edge * inEdge=inEdges.getFirst(), * nextInEdge=NULL; inEdge!=NULL; inEdge=nextInEdge){ - nextInEdge=inEdges.getNext(inEdge); - Node * inNode=inEdge->getNode(Direction_Tail); -#ifdef _DEBUG - inNode->verify(); -#endif - - if (inNode->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * inBB=(BasicBlock *)inNode; - const Insts& inNodeInsts=inBB->getInsts(); - if (!inNodeInsts.isEmpty()){ - Inst * lastInst=inNodeInsts.getLast(); - if (lastInst->hasKind(Inst::Kind_SwitchInst)){ - assert(outNode->hasKind(Node::Kind_BasicBlock)); - BasicBlock* outBB = (BasicBlock*)outNode; - SwitchInst * switchInst = (SwitchInst*)lastInst; - - switchInst->replaceTarget(bb, outBB); - } - } - } - - Edge * in2OutDirectEdge = inNode->getEdge(Direction_Out, outNode); - if (in2OutDirectEdge!=NULL) { - in2OutDirectEdge->setProbability(in2OutDirectEdge->getProbability() + inEdge->getProbability()); - if (inNode->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * inBB=(BasicBlock *)inNode; - if (inEdge->isDirectBranchEdge()){ - BranchInst * branchInst=inEdge->getBranch(); - if (branchInst) - inBB->removeInst(branchInst); - } - if (in2OutDirectEdge->isDirectBranchEdge()){ - BranchInst * branchInst=in2OutDirectEdge->getBranch(); - if (branchInst) - inBB->removeInst(branchInst); - inBB->makeEdgeFallThrough(in2OutDirectEdge); - } - } - removeEdge(inEdge); -#ifdef _DEBUG - inNode->verify(); -#endif - } else { - retargetEdge(Direction_Head, inEdge, outNode); -#ifdef _DEBUG - inNode->verify(); -#endif - } -#ifdef _DEBUG - inNode->verify(); -#endif - } - } +void BasicBlock::verify() { #ifdef _DEBUG - bb->verify(); -#endif - } - removeNode(bb); - } - - //_________________________________________________________________________________________________ - void CFG::removeEdge(Edge * edge) - { - edge->getNode(Direction_Tail)->delEdge(Direction_Out, edge); - edge->getNode(Direction_Head)->delEdge(Direction_In, edge); - edge->nodes[Direction_Tail]=edge->nodes[Direction_Head]=0; - } - - //_________________________________________________________________________________________________________ - // retarget all edges of src node to dst node - void CFG::retargetAllEdges(Direction dir, Node* oldNode, Node* newNode) { - CFG* cfg = oldNode->getCFG(); //todo: make retargetEdge static.. - Direction edgeTearDir = dir == Direction_In ? Direction_Head: Direction_Tail; - while (!oldNode->getEdges(dir).isEmpty()) { - Edge* edge = oldNode->getEdges(dir).getFirst(); - bool edgeIsFallThru = edge->isFallThroughEdge(); - if (!edgeIsFallThru && dir == Direction_In && oldNode->hasKind(Node::Kind_ExitNode)) { - // special handling when exit node is replaced with BB - // try to make edge fall-through in this case - Node* tailNode = edge->getNode(Direction_Tail); - edgeIsFallThru = tailNode->hasKind(Node::Kind_BasicBlock) && newNode->hasKind(Node::Kind_BasicBlock); - } - bool egdeIsDirectTarget = !edgeIsFallThru && edge->isDirectBranchEdge(); - cfg->retargetEdge(edgeTearDir, edge, newNode); - if (edgeIsFallThru || egdeIsDirectTarget) { - Node* tailNode = edge->getNode(Direction_Tail); - assert(tailNode->hasKind(Node::Kind_BasicBlock)); - if (egdeIsDirectTarget) { - ((BasicBlock*)tailNode)->makeEdgeDirectBranch(edge); - } else { - ((BasicBlock*)tailNode)->makeEdgeFallThrough(edge); - } - } - } - } - - //_________________________________________________________________________________________________________ - void CFG::importNodes(const Nodes& nodesToAdd) { - for (Nodes::const_iterator it = nodesToAdd.begin(), end = nodesToAdd.end(); it!=end; ++it) { - Node* newNode = *it; - newNode->cfg = this; - newNode->id = nodeId++; - addNode(newNode); - } - } - - //_________________________________________________________________________________________________________ - void CFG::mergeGraphAtEdge(CFG* cfg, Edge* edge, bool takeParentDispatch) { - - assert(!edge->hasKind(Edge::Kind_CatchEdge)); - - BasicBlock* prolog = cfg->getPrologNode(); - ExitNode* exit = cfg->getExitNode(); - UnwindNode* unwind = cfg->getUnwindNode(); - - Node* sourceNode = edge->getNode(Direction_Tail); - Node* targetNode = edge->getNode(Direction_Head); - assert(sourceNode->getCFG() == this); - CFG * parentCFG = this; - assert(&parentCFG->getMemoryManager() == &cfg->getMemoryManager()); - - UnwindNode* parentUnwind = parentCFG->getUnwindNode(); - Edge* parentDispatchEdge = sourceNode->getEdge(Direction_Out, Node::Kind_DispatchNode); - Node* parentBlockDipatchNode = parentDispatchEdge == NULL ? NULL : parentDispatchEdge->getNode(Direction_Head); - - //bind exception nodes. - if (unwind!=NULL) { - Node* unwindReplacement = 0; - if (takeParentDispatch && parentBlockDipatchNode != NULL ) - unwindReplacement = parentBlockDipatchNode; - else - unwindReplacement = parentUnwind; - if (unwindReplacement == NULL) { - unwindReplacement = parentCFG->newUnwindNode(); - } - retargetAllEdges(Direction_In, unwind, unwindReplacement); - Edge* edgeToExit = unwind->getEdge(Direction_Head, exit); - assert(edgeToExit!=NULL); - cfg->removeEdge(edgeToExit); - cfg->delNode(unwind); - } - - // cut the edge - parentCFG->retargetEdge(Direction_Head, edge, prolog); - parentCFG->retargetAllEdges(Direction_In, exit, targetNode); - - cfg->delNode(exit); - - //set inlined nodes owner to parent - parentCFG->importNodes(cfg->getNodes()); + CGNode::verify(); + Inst* last = (Inst*)getLastInst(); + if (last) { + last->verify(); + } else { + assert(getOutDegree()<=2); + assert(getUnconditionalEdge()!=NULL || getExceptionEdge()!=NULL); } - - //_________________________________________________________________________________________________________ - // WARN: childCFG insts must be created with parentCFG IR Manager! - void CFG::mergeGraphs(CFG* parentCFG, CFG* childCFG, Inst* insertLocation, bool insertAfter) { - //todo: handle persistent ids.. - assert(&parentCFG->getMemoryManager() == &childCFG->getMemoryManager()); - - BasicBlock* childProlog = childCFG->getPrologNode(); - ExitNode* childExit = childCFG->getExitNode(); - BasicBlock* parentBlock = insertLocation->getBasicBlock(); - UnwindNode* childUnwind = childCFG->getUnwindNode(); - UnwindNode* parentUnwind = parentCFG->getUnwindNode(); - Edge* parentDispatchEdge = parentBlock->getEdge(Direction_Out, Node::Kind_DispatchNode); - Node* parentBlockDipatchNode = parentDispatchEdge == NULL ? NULL : parentDispatchEdge->getNode(Direction_Head); - - const Insts& insts = parentBlock->getInsts(); - - - bool appendToParentBlock = insts.getLast() == insertLocation && insertAfter; - // can't optimize prepend -> need to keep SwitchInst targets -> leave parent block at the old place, even if it is empty - if (appendToParentBlock) { - assert(parentBlock->getDirectBranchEdge() == NULL); //only fall-through edge - Edge* parentFallEdge = parentBlock->getFallThroughEdge(); - assert (parentFallEdge!=NULL); - Node* fallTarget = parentFallEdge->getNode(Direction_Head); - parentCFG->retargetEdge(Direction_Out, parentFallEdge, childProlog); - retargetAllEdges(Direction_In, childExit, fallTarget); - } else { //split parent block in 2, bottomBlock contains bottom insts from parentBlock - BasicBlock* bottomBlock = parentCFG->newBasicBlock(); - Inst* insertAfterInst = insertAfter ? insertLocation: insts.getPrev(insertLocation); - for (Inst* inst = insts.getLast(); inst!=insertAfterInst; ){ - Inst* instToMove = inst; - inst = insts.getPrev(inst); - parentBlock->removeInst(instToMove); - bottomBlock->prependInsts(instToMove); - } - //now make all out edges of parentBlock to be out edges of the bottomBlock - retargetAllEdges(Direction_Out, parentBlock, bottomBlock); - - parentCFG->newFallThroughEdge(parentBlock, childProlog, 1.0); - retargetAllEdges(Direction_In, childExit, bottomBlock); - - if (parentBlockDipatchNode!=NULL) { - //recreate this edge again, was moved with retargetAllEdges(out,..).. - parentCFG->newEdge(parentBlock, parentBlockDipatchNode, 0.01); - } - } - - //bind exception nodes. - if (childUnwind!=NULL) { - Node* childUnwindReplacement = parentBlockDipatchNode != NULL ? parentBlockDipatchNode : parentUnwind; - if (childUnwindReplacement == NULL) { - childUnwindReplacement = parentCFG->newUnwindNode(); - } - retargetAllEdges(Direction_In, childUnwind, childUnwindReplacement); - - //delete child's unwind & exit (optional op) - Edge* edgeToExit = childUnwind->getEdge(Direction_Head, childExit); - assert(edgeToExit!=NULL); - childCFG->removeEdge(edgeToExit); - childCFG->delNode(childUnwind); - } else if (parentBlockDipatchNode != NULL){ - //no unwind node in child CFG, propagate parentBlock dispatching for every child node - const Nodes& childNodes = childCFG->getNodes(); - for (Nodes::const_iterator it = childNodes.begin(), end = childNodes.end(); it!=end; ++it) { - Node* childNode = *it; - if (childNode->hasKind(Node::Kind_BasicBlock)) { - assert(childNode->getEdge(Direction_Out, Node::Kind_DispatchNode) == NULL); - parentCFG->newEdge(childNode, parentBlockDipatchNode, 0.01); - } - } - } - - childCFG->delNode(childExit); - - //set child nodes owner to parent - parentCFG->importNodes(childCFG->getNodes()); - } - - //_________________________________________________________________________________________________ - void CFG::updateLoopInfo(bool force) { - if (!isLoopInfoValid() && !force) { - if (Log::cat_cg()->isDebugEnabled()) { - Log::cat_cg()->out() << "Loop info recalculation."; - } - maxLoopDepth = 0; - MemoryManager& mm = getMemoryManager();//(sizeof(DFSLoopInfo) * getMaxNodeId() * 2, "Ia32::CFG:updateLoopInfo"); - DFSLoopInfo* dfsInfo = new (mm) DFSLoopInfo[getMaxNodeId()]; - NodeList outerLoopHeaders(mm); - memset(dfsInfo, 0, sizeof(DFSLoopInfo) * getMaxNodeId()); - dfsInfo[prologNode->getId()].dfn = 1; - bool _hasLoops = doLoopInfoDFS(prologNode, dfsInfo, outerLoopHeaders); - assert (outerLoopHeaders.empty()); - lastLoopInfoVersion = graphModCount; - if (_hasLoops) { - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - if (node->isLoopHeader()) { - uint32 depth = 1 + node->getLoopDepth(); - maxLoopDepth = std::max(depth, maxLoopDepth); - } - if (node->execCnt <= 0 && !hasEdgeProfile()){ - uint32 execCnt = 1; - for (uint32 i = 0, loopDepth = (node->getLoopDepth() + (node->isLoopHeader() ? 1 : 0)); i < loopDepth; ++i) - execCnt *= 10; - node->execCnt = execCnt; - } - } - } - } - } - - //_________________________________________________________________________________________________ - bool CFG::doLoopInfoDFS(Node* node, DFSLoopInfo* info, NodeList& outerLoopHeaders) const { - bool hasLoops=false; - assert(node!=NULL); - node->loopHeader = NULL; - - node->nodeIsHeader = FALSE; - DFSLoopInfo& myInfo= info[node->getId()]; - assert(myInfo.dfn != 0); - assert(myInfo.color == 0); //white - myInfo.color = 1; //gray - const Edges& edges=node->getEdges(Direction_Out); - int nLoopHeadersBefore = outerLoopHeaders.size(); - for (const Edge * e=edges.getFirst(); e!=NULL; e=edges.getNext(e)) { - Node* targetNode = e->getNode(Direction_Head); - DFSLoopInfo& targetInfo = info[targetNode->getId()]; - if (targetInfo.color == 2) { //direct edge or cross-edge -> this edge was accessed by another DFS recursion - //target node could not be a loop header for current node -> it's black - Node* loopHeader = targetNode->loopHeader; - if (loopHeader!=NULL) { //check if target node is in loop -> copy its loop info - outerLoopHeaders.push_front(loopHeader); - } - } else if (targetInfo.color == 1) { //ok we found loop; targetNode is a loop header - outerLoopHeaders.push_front(targetNode); - } else { - targetInfo.dfn = myInfo.dfn+1; - hasLoops = doLoopInfoDFS(targetNode, info, outerLoopHeaders) || hasLoops; - } - } - - // find loop header for current node - // remove loop header from list if it equals to the current node - bool isLoopHeader = FALSE; - Node* myLoopHead = NULL; - // optimization: keeping all loop-heads for the dfs-parent node in the single list - // drawback : need to distinct loop-heads found while current node DFS from others (other children of dfs-parent) - int loopsHeadsReached = outerLoopHeaders.size() - nLoopHeadersBefore; - if (loopsHeadsReached>0) { - for (NodeList::iterator it = outerLoopHeaders.begin(); --loopsHeadsReached>=0; ++it) { - Node* headerNode = *it; - if (headerNode==node) { - isLoopHeader = TRUE; - outerLoopHeaders.erase(it); - } else { - if (myLoopHead == NULL) { - myLoopHead = headerNode; - } else if (myLoopHead!=headerNode){ - // there were edges to different loops (loop-exit edges, backedges). - // Our loop is the most inner one == head with max dfn - int myHeadDFN = info[myLoopHead->getId()].dfn; - int newHeadDFN = info[headerNode->getId()].dfn; - assert(myHeadDFN!=newHeadDFN); - if (myHeadDFN < newHeadDFN) { - myLoopHead = headerNode; // inner loop - } - } else { // myLoopHead == headerNode - //this also is possible -> multiple paths save the one loopHead many times (= nPathes) - //do nothing - } - } - } - assert(myLoopHead == NULL || info[myLoopHead->getId()].dfn < myInfo.dfn); - } - node->setLoopInfo(isLoopHeader, myLoopHead); - myInfo.color = 2; //black, node and all it's child-nodes are checked - return hasLoops || isLoopHeader; - } - - //_________________________________________________________________________________________________ - bool CFG::ensureLoopInfoIsValid() { - if (!isLoopInfoValid()) { - return FALSE; - } - MemoryManager tmpMM((sizeof(Node*)*4 + 1)*getMaxNodeId(), "Ia32CFG::ensureLoopInfoIsValid"); - Node **nodeLoopHead = new (tmpMM) Node*[getMaxNodeId()]; - bool *nodeIsLoopHead = new (tmpMM) bool[getMaxNodeId()]; - for(Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - Node* node = *it; - nodeLoopHead[node->getId()] = node->getLoopHeader(); - nodeIsLoopHead[node->getId()] = node->isLoopHeader(); - } - updateLoopInfo(TRUE); - for(Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - Node* node = *it; - if (nodeLoopHead[node->getId()] != node->getLoopHeader()) { - return FALSE; - } - if (nodeIsLoopHead[node->getId()]!=node->isLoopHeader()) { - return FALSE; - } - } - return TRUE; - } - - //_________________________________________________________________________________________________ - const Nodes& CFG::getNodesPostorder() const { - if (lastPostorderVersion != graphModCount) { - traversalInfo.resize(getMaxNodeId() + 1); - std::fill(traversalInfo.begin(), traversalInfo.end(), 0); - Direction edgeDir = Direction_Out; - Node* startNode = prologNode; - Node* endNode = exitNode; - // convention: first and last nodes in container are always prolog & exit - // here we fix it manually, otherwise loops in CFG may cause that exit node - // will not be the first node in container for postorder sort - traversalInfo[endNode->getId()] = 2; - postorderNodesCache.clear(); - postorderNodesCache.push_back(endNode); - getNodesDFS(postorderNodesCache, startNode, edgeDir); -#ifdef _DEBUG //check that all nodes have the same traversal number - for (Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; ++it) { - Node* tmp = *it; - assert(traversalInfo[tmp->getId()] == 2); - tmp->verify(); - } #endif - assert(postorderNodesCache.size() == nodes.size()); - lastPostorderVersion = graphModCount; - } - return postorderNodesCache; - } - - - //_________________________________________________________________________________________________ - void CFG::getNodesDFS(Nodes& container, Node * node, Direction edgeDir) const { - assert(node!=NULL); - assert(traversalInfo[node->getId()]==0); //node is white here - uint32 nodeId = node->getId(); - traversalInfo[nodeId] = 1; //mark node gray - // for preorder: container.push_back(node); - const Edges& edges=node->getEdges(edgeDir); - for (const Edge * e=edges.getLast(); e!=NULL; e=edges.getPrev(e)){ - Node* targetNode = e->getNode(edgeDir); - if ( traversalInfo[targetNode->getId()] !=0) { - //back-edge(gray) if == 1 or cross-edge or direct-edge (black) if ==2 - continue; - } - getNodesDFS(container, targetNode, edgeDir); - - } - traversalInfo[nodeId] = 2;//mark node black - container.push_back(node); - } - - //_________________________________________________________________________________________________________ - CFG::NodeIterator::NodeIterator(const CFG& cfg, OrderType orderType) - { - switch(orderType) { - case OrderType_Arbitrary: - nodes = &cfg.getNodes(); - break; - case OrderType_Postorder: - nodes = &cfg.getNodesPostorder(); - break; - case OrderType_ReversePostorder: - nodes = &cfg.getNodesPostorder(); - break; - case OrderType_Layout: - { - Nodes* tmp = new (cfg.getMemoryManager()) Nodes(cfg.getMemoryManager()); - cfg.getNodes(*tmp, OrderType_Layout); - nodes = tmp; - } - break; - - default: assert(0); - } +} - if (orderType!= OrderType_ReversePostorder) { - currentIdx = 0; - borderIdx = nodes->size(); - increment = 1; - } else { - currentIdx = nodes->size()-1; - borderIdx = -1; - increment = -1; - } - } +void* BasicBlock::getCodeStartAddr() const { + return (uint8*)irm.getCodeStartAddr()+getCodeOffset(); +} - - //_________________________________________________________________________________________________________ - void CFG::NodeIterator::rewind() { - if (increment == 1) { - currentIdx = 0; - } else { - currentIdx = nodes->size()-1; - } - } -}}; // namespace Ia32 +}}; // namespace diff --git vm/jitrino/src/codegenerator/ia32/Ia32CFG.h vm/jitrino/src/codegenerator/ia32/Ia32CFG.h index fb5d48d..951113d 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CFG.h +++ vm/jitrino/src/codegenerator/ia32/Ia32CFG.h @@ -21,199 +21,32 @@ #ifndef _IA32_CFG_H_ #define _IA32_CFG_H_ -#include "open/types.h" +#include "ControlFlowGraph.h" #include "MemoryManager.h" -#include "VMInterface.h" -#include "Type.h" #include "Stl.h" -#include "Ia32Inst.h" #include "BitSet.h" +#include "open/types.h" + namespace Jitrino { namespace Ia32{ - //========================================================================================================= - // Forward declarations - //========================================================================================================= - class Node; - class DispatchNode; - class BasicBlock; - class Inst; - class CFG; + class IRManager; - typedef double ProbValue; - typedef double ExecCntValue; - typedef StlVector Nodes; - typedef StlList NodeList; - -//deprecated -#define UnknownProbValue (-1.0) -#define UnknownExecCnt (-1.0) - -#define EdgeProbValue_Unknown (-1.0) -#define ExecCountValue_Unknown (-1.0) -#define EdgeProbValue_Exception 0.01 - - - //======================================================================================== - // class LiveSet - //======================================================================================== - /** class LiveSet represents a bit-set describing operand liveness at particular point - - Generally LiveSet can be implemented as any data structure emulating the bit-set pattern, - not necessarily the literal bit-set - - Currently it extends the BitSet helper class and adds the isLive convenience method - - */ - class LiveSet: public BitSet { - public: - /** initializes the bit-set to contain numOperands bits */ - LiveSet(MemoryManager& mm, uint32 numOperands) - :BitSet(mm, numOperands){} - - LiveSet(MemoryManager& mm, const LiveSet& setToCopy) - :BitSet(mm, setToCopy){} - - LiveSet(MemoryManager& mm) - :BitSet(mm,0){} - - /** returns true if the opnd's id is set in the bit set (the operand is live) */ - bool isLive(const Opnd * opnd)const{ return getBit(opnd->getId()); } - }; - - //========================================================================================================= - // class Edge: CFG edge - //========================================================================================================= - /** class Edge represents an edge in a control flow graph */ - class Edge { - - public: - - /** enum Kind represents dynamic type info of Edge and descendants. - This enumeration is hierarchical and is used in getKind and hasKind Edge methods - */ - enum Kind{ - Kind_Edge=0xffffffff, - Kind_CatchEdge=0xf, - }; - - /** returns the kind of the edge representing its class */ - Kind getKind()const {return kind;} - /** returns true if the edge is of kind (class) k or its subclass */ - bool hasKind(Kind k)const {return (kind&k)==kind;} - /** returns the node the edge is connected to at the edge's point defined by dir */ - Node * getNode(Direction dir)const {return nodes[dir];} - - - /** Returns true if both head and tail of an edge are basic blocks */ - bool isBlockEdge()const; - /** Returns true if an edge is a back edge */ - bool isBackEdge()const; - /** Returns true if an edge is a loop exit edge */ - bool isLoopExit()const; - - /** Returns true if an edge is a fall-through edge */ - bool isFallThroughEdge()const; - - /** Returns true if an edge is a direct branch edge */ - bool isDirectBranchEdge()const; - - /** returns the probability value associated with the edge */ - ProbValue getProbability()const { return probability; } - /** Associates a probability value with the edge */ - void setProbability(ProbValue prob) { probability = prob; } - - /** returns the BranchInst this edge corresponds to. - The tail node of the edge must be BasicBlock and the edge must be set as the block's direct branch. - */ - BranchInst * getBranch()const; - - //--------------------------------------------------------------------------------------------- - protected: - Edge(Node *from, Node *to, ProbValue prob = UnknownProbValue) - : kind(Kind_Edge), probability(prob) - { assert(from!=NULL && to!=NULL); nodes[Direction_Backward]=from; nodes[Direction_Forward]=to; } - - void setKind(Kind k){ kind=k; } - - //--------------------------------------------------------------------------------------------- - protected: - Kind kind; - Node * nodes[2]; - Dlink links[2]; - ProbValue probability; // Probability this edge is taken once control reaches tail. - - //--------------------------------------------------------------------------------------------- - friend class Edges; - friend class CFG; - friend class Node; - }; - - - //========================================================================================================= - // class Edges: edge collection - //========================================================================================================= - /** class Edge is a collection of edges. - - Emulates NULL-terminated iteration. - - Each CFG node contain two Edges collection (In and Out) - */ - class Edges: private Dlink - { - public: - /** Constructs either Direction_In or Direction_Out collection of edges - - The Direction value is used for internal needs and represent the corresponding Dlink element in an edge - */ - Edges(Direction dir=Direction_Backward): direction(dir), count(0) {} - /** returns the first edge in the collection or NULL if the collection is empty */ - Edge * getFirst()const {return toEdge(Dlink::getNext());} - /** returns the last edge in the collection or NULL if the collection is empty */ - Edge * getLast()const {return toEdge(Dlink::getPrev());} - /** returns the edge next to the specified edge or NULL if there are no such edges in the collection */ - Edge * getNext(const Edge * edge)const {return toEdge(edge->links[direction].getNext());} - /** returns the edge previous to the specified edge or NULL if there are no such edges in the collection */ - Edge * getPrev(const Edge * edge)const {return toEdge(edge->links[direction].getPrev());} - /** returns true if the collection is empty */ - bool isEmpty()const{ bool empty = Dlink::getNext()==this; assert(!empty||count==0); return empty; } - /** returns the Direction value of the collection set in its constructor */ - uint32 getDirection()const {return direction;} - /** returns the number of edges in the collection */ - uint32 getCount()const {return count;} - /** returns true if the collection contains the edge */ - bool has(const Edge * edge)const; - private: - Edges(const Edges& r){ assert(0); } // one should write "const Edges& es=..." instead of "Edges es=..." - Edges& operator=(const Edges& r){ assert(0); return *this; } - - void append(Edge* edge){ edge->links[direction].insertBefore(this); count++; } - void prepend(Edge* edge){ edge->links[direction].insertAfter(this); count++; } - void del(Edge* edge){ edge->links[direction].unlink(); count--; } - Edge * toEdge(Dlink * link)const - { return link==this?0:(Edge*)((char*)link-offsetof(Edge, links[direction])); } - - Direction direction; - uint32 count; - - friend class Node; - }; - - + //========================================================================================================= // edge with the exception information //========================================================================================================= /** class CatchEdge is specialization of Edge representing an edge from a dispatch node to a handler block */ - class CatchEdge : public Edge - { - + class CatchEdge : public Edge { + friend class IRManager; public: /** Returns the caught exception type associated with the edge */ Type * getType()const {return type;} + void setType(Type* _type) {type = _type;} /** Returns the priority of the edges during exception handling If the same exception can be handled by several @@ -221,12 +54,12 @@ #define EdgeProbValue_Exception 0.01 The smaller the priority number the hight is the priority. */ uint32 getPriority()const {return priority;} + void setPriority(uint32 p) {priority = p;} //--------------------------------------------------------------------------------------------- protected: - CatchEdge(DispatchNode * from, BasicBlock * to, Type *ty, uint32 prior, - ProbValue prob = UnknownProbValue) - : Edge((Node*)from, (Node*)to, prob), type(ty), priority(prior) { setKind(Kind_CatchEdge); } + CatchEdge() + : type(NULL), priority(0) { } //--------------------------------------------------------------------------------------------- protected: @@ -240,8 +73,6 @@ #define EdgeProbValue_Exception 0.01 uint32 priority; //--------------------------------------------------------------------------------------------- - friend class CFG; - friend class Node; }; @@ -249,291 +80,58 @@ #define EdgeProbValue_Exception 0.01 // node //========================================================================================================= /** class Node is a base class for all nodes in the CFG.*/ - class Node { - - //--------------------------------------------------------------------------------------------- + class CGNode : public Node { public: - /** enum Kind represents dynamic type info of Node and descendants. - This enumeration is hierarchical and is used in getKind and hasKind Node methods - */ - - enum Kind - { - // Kind_Node=0xffffffff, must not exist - Kind_BasicBlock=0xffff, - Kind_DispatchNode=0xf0000, - Kind_UnwindNode=0x10000000, - Kind_ExitNode=0x20000000 + enum OrderType { + OrderType_Arbitrary=0, + OrderType_Layout, + OrderType_Postorder, + OrderType_Topological, + OrderType_ReversePostorder = OrderType_Topological }; - //--------------------------------------------------------------------------------------------- - virtual ~Node() {} - /** Returns the ID of the node */ - uint32 getId()const {return id;} - /** Returns the kind of the node representing its class */ - Kind getKind()const{ return kind; } - /** Returns true if the node is of kind (class) k or its subclass */ - bool hasKind(Kind k)const{ return (kind&k)==kind; } - - /** returns the CFG this node is in */ - CFG * getCFG()const{ return cfg; } - - - /** Returns the ExecCntValue DPGO value */ - ExecCntValue getExecCnt()const { return execCnt; } - /** Sets the ExecCntValue DPGO value */ - void setExecCnt(ExecCntValue ec) { execCnt = ec; } - - /** Returns either Direction_In or Direction_Out collection of edges */ - const Edges& getEdges(Direction dir)const - { return edges[dir]; } - - /** Returns true if this node is connected to a node of the specified kind. */ - bool isConnectedTo(Direction dir, Kind k)const - { return getEdge(dir, k)!=NULL; } - /** Returns true if this node is connected to the specified node. */ - bool isConnectedTo(Direction dir, Node * node)const - { return getEdge(dir, node)!=NULL; } - - /** Returns the edge leading to the first node of the specified kind */ - Edge * getEdge(Direction dir, Kind k)const; - /** Returns the edge leading to the specified node */ - Edge * getEdge(Direction dir, Node * node)const; - - /** Returns the first node of the specified kind connected with this node */ - Node * getNode(Direction dir, Kind k)const - { Edge * e=getEdge(dir, k); return e!=NULL?e->getNode(dir):NULL; } - - /** Returns true if the node is a loop header. - Loop info must be set before calling this method (using setLoopInfo). - */ - bool isLoopHeader() const; - /** Returns true the loop header node for the node (if the node is withing a loop). - Loop info must be set before calling this method (using setLoopInfo). - */ - Node * getLoopHeader() const; - /** Returns the depth of the loop this node is in. */ - uint32 getLoopDepth()const; - /** Returns true if the node is within a loop. */ - bool isWithinLoop(const Node * loopHeader)const; - /** Sets loop info for the node. - The loop info is set during CFG lowering (CfgCodeSelector) - */ - - void setLoopInfo(bool _isLoopHeader, Node * header) - { nodeIsHeader = _isLoopHeader; loopHeader = header; } - /** Returns true if loop info has been set for the node */ - bool hasLoopInfo() const; /** Returns the persistent id of the node (HIR CFG node id resulting to this node) */ uint32 getPersistentId()const {return persistentId; } /** Sets the persistent id of the node (HIR CFG node id resulting to this node) */ void setPersistentId(uint32 persId) { persistentId = persId; } + IRManager & getIRManager() { return irm; } + virtual void verify(); - //--------------------------------------------------------------------------------------------- - protected: - - Node(CFG * cfg, uint32 id, ExecCntValue cnt = UnknownExecCnt); - - //--------------------------------------------------------------------------------------------- - void addEdge(Direction dir, Edge * edge); - virtual void delEdge(Direction dir, Edge * edge); - - LiveSet * getLiveAtEntry()const {return liveAtEntry;} - - void setKind(Kind k){ kind=k; } - - //--------------------------------------------------------------------------------------------- - protected: - Kind kind; - uint32 id; - Edges edges[2]; - - CFG * cfg; - - ExecCntValue execCnt; // Estimate for # times this node is entered - uint32 persistentId; // persistent id - - // Loop information - bool nodeIsHeader; // is this node a loop header - Node * loopHeader; // header of the containing loop, NULL if none. - LiveSet * liveAtEntry; // operands live at node entry - - //--------------------------------------------------------------------------------------------- - friend class CFG; - friend class IRManager; - friend class Edge; - }; - - //========================================================================================================= - // Exception dispatch node - //========================================================================================================= - /** class DispatchNode is a node collecting control flow for handled exceptions */ - class DispatchNode : public Node - { - public: - virtual ~DispatchNode() {} - - /** Auxiliary method, returns true if the catch edges are sorted */ - bool catchEdgesAreSorted()const; - void sortCatchEdges(); - //--------------------------------------------------------------------------------------------- protected: - DispatchNode(CFG * cfg, uint32 id, ExecCntValue cnt = UnknownExecCnt) - :Node(cfg, id, cnt) { setKind(Kind_DispatchNode); } - private: + CGNode(MemoryManager& mm, IRManager& _irm, Node::Kind kind) + : Node(mm, kind), irm(_irm), liveAtEntry(new (mm) BitSet(mm, 0)), persistentId(0) {} - //--------------------------------------------------------------------------------------------- - friend class CFG; - friend class Edge; - friend class Node; - }; - - //========================================================================================================= - // Unwind node - //========================================================================================================= - /** class DispatchNode is the only node in a CFG collecting control flow for unhandled exceptions */ - class UnwindNode : public Node - { - protected: - UnwindNode(CFG * cfg, uint32 id, ExecCntValue cnt = UnknownExecCnt) :Node(cfg, id, cnt) - {setKind(Kind_UnwindNode); } - virtual ~UnwindNode() {} - //--------------------------------------------------------------------------------------------- - friend class CFG; - }; + BitSet* getLiveAtEntry() const {return liveAtEntry;} - //========================================================================================================= - // Exit node - //========================================================================================================= - /** class DispatchNode is the exit node of a CFG */ - class ExitNode : public Node - { - protected: - ExitNode(CFG * cfg, uint32 id, ExecCntValue cnt = UnknownExecCnt) :Node(cfg, id, cnt) - {setKind(Kind_ExitNode); } - virtual ~ExitNode() {} - //--------------------------------------------------------------------------------------------- - friend class CFG; + IRManager& irm; + BitSet* liveAtEntry; + uint32 persistentId; + + friend class IRManager; + }; //========================================================================================================= - // class Insts: inst double linked list - //========================================================================================================= - /** Collection of instructions. Emulates NULL-terminated iteration. - Is used in basic blocks. - */ - class Insts: private Dlink - { - public: - /** constructs an empty Inst collection */ - Insts():count(0) {} - - - /** returns the first instruction in the collection or NULL if the collection is empty */ - Inst * getFirst()const {return toInst(Dlink::getNext());} - /** returns the last instruction in the collection or NULL if the collection is empty */ - Inst * getLast()const {return toInst(Dlink::getPrev());} - /** returns the instruction next to the specified instruction or - NULL if there are no such instruction in the collection */ - Inst * getNext(const Inst * inst)const {return toInst(((Dlink*)inst)->getNext());} - /** returns the instruction previous to the specified instruction or - NULL if there are no such edges in the collection */ - Inst * getPrev(const Inst * inst)const {return toInst(((Dlink*)inst)->getPrev());} - - /** returns the first inst if dir is Direction_Forward or the - last inst if dir is Direction_Backward*/ - Inst * getFirst(Direction dir)const - { return dir==Direction_Forward?getFirst():getLast(); } - - /** returns the next inst if dir is Direction_Forward or the - last inst if dir is Direction_Backward*/ - Inst * getNext(Direction dir, const Inst * inst)const - { return dir==Direction_Forward?getNext(inst):getPrev(inst); } - - /** returns true if the collection is empty */ - bool isEmpty()const{ bool empty = Dlink::getNext()==this; assert(!empty||count==0); return empty; } - /** returns the number of instructions in the collection */ - uint32 getCount()const {return count;} - - static void connectInstLists(Inst * inst1, Inst * inst2) - { inst1->_next = inst2; inst2->_prev = inst1; } - private: - Insts(const Insts& r){ assert(0); } // one should write "const Insts& is=..." instead of "Insts is=..." - Insts& operator=(const Insts& r){ assert(0); return *this; } - - void append(Inst* inst, Inst * after=0 ) - { if (after==0) after=(Inst*)Dlink::getPrev(); inst->insertAfter(after); count++; } - void prepend(Inst* inst, Inst * before=0 ) - { if (before==0) before=(Inst*)Dlink::getNext(); inst->insertBefore(before); count++; } - void del(Inst* inst){ inst->unlink(); count--; } - - Inst * toInst(Dlink * link)const - { return link==this?0:(Inst*)link; } - - uint32 count; - - friend class BasicBlock; - }; - - //========================================================================================================= // Basic block //========================================================================================================= /** class BasicBlock represents basic blocks of a CFG: nodes which can contain intructions */ - class BasicBlock : public Node { - + class BasicBlock : public CGNode { + friend class IRManager; public: - /** Returns the Insts collection with instructions of this basic block */ - const Insts& getInsts()const {return insts;} - /** Returns true if the basic block contains no instruction */ - bool isEmpty()const { return insts.isEmpty(); } - - /** Appends instList to the basic after instruction after - if after is provided it must be bound to this basic block - */ - void appendInsts(Inst * instList, Inst * after=0); - - /** Prepends instList to the basic block bb bevore instruction before - if before is provided it must be bound to this basic block - */ - void prependInsts(Inst * instList, Inst * before=0); - - /** Removes the inst from the basic block */ - void removeInst(Inst * inst); - - /** Returns the fall-through outgoing edge of this basic block */ - Edge * getFallThroughEdge()const{ return fallThroughEdge; } - /** Returns the outgoing edge of this basic block associated with a direct branch - The direct branch must be the last instruction in the block - */ - Edge * getDirectBranchEdge()const{ return directBranchEdge; } - - /** Marks the specified edge as a fall-through edge */ - void makeEdgeFallThrough(Edge * edge); - /** Marks the specified edge as a direct branch edge */ - void makeEdgeDirectBranch(Edge * edge); - - /** recalculates the probability of the fall-through edge - as 1 - (sum for other edges) */ - void recalculateFallThroughEdgeProbability(); - - BasicBlock * getIndirectBranchPredecessor()const; - - bool canBeRemoved()const - { return getIndirectBranchPredecessor() == NULL; } - + /** Returns the basic block which is the layout successor of this one The returned value must be set using setLayoutSucc by a code layout algorithm */ - BasicBlock * getLayoutSucc()const {return layoutSucc;} + BasicBlock * getLayoutSucc()const {return layoutSucc;} /** Sets the basic block which is the layout successor of this one */ - void setLayoutSucc(BasicBlock *bb); + void setLayoutSucc(BasicBlock *bb) {assert(bb!=this); layoutSucc = bb;} /** sets the offset of native code for this basic block */ void setCodeOffset(uint32 offset) {codeOffset = offset;} @@ -543,335 +141,24 @@ #define EdgeProbValue_Exception 0.01 void setCodeSize(uint32 size) {codeSize = size;} /** returns the size of native code for this basic block */ uint32 getCodeSize()const { return codeSize; } - + /** returns the pointer to the native code for this basic block */ - void * getCodeStartAddr()const; - - void fixBasicBlockEndInstructions(); + void* getCodeStartAddr() const; void verify(); //--------------------------------------------------------------------------------------------- protected: - BasicBlock(CFG * cfg, uint32 id, ExecCntValue cnt) - : Node(cfg, id, cnt), layoutSucc(NULL), codeOffset(0), codeSize(0), fallThroughEdge(0), directBranchEdge(0) - {setKind(Kind_BasicBlock); } - - // Clone block's skeleton, i.e. create new basic block of the same type for the same cfg - virtual BasicBlock * cloneSkeleton(CFG * cfg, uint32 nIn, uint32 nOut); - - virtual void delEdge(Direction dir, Edge * edge); + BasicBlock(MemoryManager& mm, IRManager& irm) + : CGNode(mm, irm, Node::Kind_Block), layoutSucc(NULL), codeOffset(0), codeSize(0), codeAddr(0){} + protected: - Insts insts; - BasicBlock * layoutSucc; - uint32 codeOffset; uint32 codeSize; - - Edge * fallThroughEdge; - Edge * directBranchEdge; - - - - //--------------------------------------------------------------------------------------------- - friend class Edge; - friend class CFG; - }; - - - //========================================================================================================= - // class CFG - //========================================================================================================= - /** class CFG represents a control flow graph */ - class CFG - { - public: - /** enum OrderType specifies order used in CFG traversing by visitors and iterators */ - enum OrderType { - OrderType_Arbitrary=0, - OrderType_Layout, - OrderType_Postorder, - OrderType_Topological, - OrderType_ReversePostorder = OrderType_Topological - }; - - //------------------------------------------------------------------------------------- - /** Creates a CFG instance which uses memManager to create its elements */ - CFG(MemoryManager& memManager); - - //------------------------------------------------------------------------------------- - /** Returns the memory manager used for LIR */ - MemoryManager & getMemoryManager()const{ return memoryManager; } - - /** Returns the prolog node of the CFG */ - BasicBlock * getPrologNode()const{ return prologNode; } - /** Returns the exit node of the CFG */ - ExitNode * getExitNode()const { return exitNode; } - /** Returns the Unwind node of the CFG */ - UnwindNode * getUnwindNode()const { return unwindNode; } - - /** returns the number of nodes in the CFG */ - uint32 getNodeCount()const{ return nodes.size(); } - - /** returns the maximum node id assigned to a node in this CFG */ - uint32 getMaxNodeId()const{ return nodeId; } - - /** returns true if the CFG has been laid out - (layout successor attributes of nodes are valid) */ - bool isLaidOut()const{ return _isLaidOut; } - void setIsLaidOut(){ _isLaidOut=true; } - - /** returns true if the specified node is an epilog basic block - A node is considered epilog if it is a basic block and is connected to the exit node of the CFG - */ - bool isEpilog(const Node * node)const - { return node->hasKind(Node::Kind_BasicBlock) && node->isConnectedTo(Direction_Out, exitNode); } - - //------------------------------------------------------------------------------------- - /** Creates a new unwind node and adds it to the control flow graph - We create unwind nodes in the same CFG - */ - UnwindNode * newUnwindNode(ExecCntValue cnt = UnknownExecCnt); - /** Creates a new basic lock and adds it to the control flow graph */ - BasicBlock * newBasicBlock(ExecCntValue cnt = UnknownExecCnt); - /** Creates a new dispatch node and adds it to the control flow graph */ - DispatchNode * newDispatchNode(ExecCntValue cnt = UnknownExecCnt); - - /** Creates a new CFG edge and addsit to the control flow graph */ - Edge * newEdge(Node *from, Node *to, ProbValue prob); - - /** Creates a new CFG edge which correspond to the taken direct branch control flow - and adds it to the control flow graph */ - Edge * newDirectBranchEdge(BasicBlock *from, BasicBlock * to, ProbValue prob) - { Edge * edge = newEdge(from, to, prob); from->makeEdgeDirectBranch(edge); return edge; } - - /** Creates a new CFG edge which correspond to the taken direct branch control flow - and adds it to the control flow graph */ - Edge * newFallThroughEdge(BasicBlock *from, BasicBlock * to, ProbValue prob) - { Edge * edge = newEdge(from, to, prob); from->makeEdgeFallThrough(edge); return edge; } - - /** Creates a new catch edge (thus adding it to the control flow graph) */ - CatchEdge * newCatchEdge(DispatchNode *from, BasicBlock *to, Type *ty, uint32 prior, ProbValue prob); - - //------------------------------------------------------------------------------------- - class NodeIterator; - - - - const Nodes& getNodesPostorder() const; - const Nodes& getNodes() const {return nodes;} - - //_________________________________________________________________________________________________ - template - void getNodes(Container& container, OrderType orderType) const { - switch(orderType){ - case OrderType_Arbitrary: - for (Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - Node* node = *it; - container.push_back(node); - } - break; - case OrderType_Layout: - assert(isLaidOut()); - for (BasicBlock * bb=getPrologNode(); bb!=NULL; bb=bb->getLayoutSucc()) { - container.push_back(bb); - } - break; - case OrderType_Postorder: - case OrderType_ReversePostorder: //same as topological -> get postorder and reverse.. - { - const Nodes& postOrder = getNodesPostorder(); - if (orderType == OrderType_ReversePostorder) { - container.insert(container.end(), postOrder.rbegin(), postOrder.rend()); - } else { - container.insert(container.end(), postOrder.begin(), postOrder.end()); - } - } - break; - } - } - - - //------------------------------------------------------------------------------------- - /** Retargets an existed CFG edge to the new target node */ - void retargetEdge(Direction dir, Edge *edge, Node *newTo); - - //----------------------------------------------------------------------------------------------- - /** splits the basic block after inst, adds the new basic block to CFG, - links it with other blocks appropriately, and returns bb */ - BasicBlock * splitBlockAfter(BasicBlock * bb, Inst * inst); - - /** merges sequential blocks according to some rules (TBD) */ - void mergeSequentialBlocks(); - - /** remove empty basic blocks */ - void purgeEmptyBlocks(); - - /** remove empty basic block bb */ - void purgeEmptyBlock(BasicBlock * bb); - - //----------------------------------------------------------------------------------------------- - /** removes node and all connected edges from the CFG */ - void removeNode(Node * node); - - /** removes edge from the CFG */ - void removeEdge(Edge * edge); - - /** manual control for loop info validity, can be removed later*/ - void invalidateLoopInfo() { lastLoopInfoVersion = 0; } - - bool isLoopInfoValid() const {return graphModCount == lastLoopInfoVersion;} - - /** could be used as optimization if algorithms modifies graph and maintains valid loop info by itself. */ - void forceLoopInfoIsValid() {lastLoopInfoVersion = graphModCount; assert(ensureLoopInfoIsValid());} - - /** tmp solution(to discuss) : the problem is that non-friend to CFG class Node - needs in API to incModCount on edges modification */ - void incModCount() {graphModCount++;} - - /** recalculates loop info if necessary - loop info is valid after method call*/ - void updateLoopInfo(bool force = FALSE); - - bool hasLoops() const { - return getMaxLoopDepth()!= 0; - } - - uint32 getMaxLoopDepth() const { - assert(isLoopInfoValid()); - return maxLoopDepth; - } - - /** recalculates exec counts, using edge probs, tries to fix edge probs if illegal*/ - void updateExecCounts(); - - //------------------------------------------------------------------------------------- - void * getCodeStartAddr(uint32 sectionId=0)const - { return codeStartAddr; } - - void setCodeStartAddr(void * addr, uint32 sectionId=0) - { codeStartAddr=addr; } - - //------------------------------------------------------------------------------------- - /** adds nodes to CFG, changes node owner and ids. */ - void importNodes(const Nodes& nodesToAdd); - - /** Inserts childCFG into parent CFG right after or before (insertAfter param) of insertLocation - Note: Be sure that childCFG's insts are created with the same IRManager as parentCFG's insts. - Note: childCFG is unusable after this call, its nodes imported to parentCFG - */ - void mergeGraphs(CFG* parentCFG, CFG* childCFG, Inst* insertLocation, bool insertAfter); - - /** Inlines CFG into edge's (parent) CFG between edge's tail and head - Note: Be sure that childCFG's insts are created with the same IRManager as parentCFG's insts. - Note: inlined CFG is unusable after this call, its nodes imported to edge's (parent) CFG - */ - void mergeGraphAtEdge(CFG* cfg, Edge* edge, bool takeParentDispatch=true); - - void setHasEdgeProfile(bool val) { edgeProfile = val;} - bool hasEdgeProfile() const { return edgeProfile;} - - protected: - /** retargets all dir-edges of src to be in-edges of dst. No fallthru or direct edge info is lost - * dispatch edges are retargeted too. - * While using this function be careful with catch edges, dispatch nodes and switch targets. - */ - static void retargetAllEdges(Direction dir, Node* oldNode, Node* newNode); - - /** methods do not tracks graph mod-count -> for internal CFG use only!*/ - void addNode(Node* node){ nodes.push_back(node); incModCount(); } - void delNode(Node* node){ nodes.erase(std::find(nodes.begin(), nodes.end(), node)); incModCount(); } - - ExitNode * newExitNode(ExecCntValue cnt=UnknownProbValue); - - void tryMergeSequentialBlocks(Node * node); - - void getNodesDFS(Nodes& c, Node* node, Direction edgeDir) const; - - struct DFSLoopInfo { - int color : 8; - int dfn : 24; - }; - /** Updates loopHeader info for all nodes accessible from node. - Heavily depends on valid 'info' and 'outerLoopHeaders' contents -> should be used only - to recalculate loop info for a whole CFG, starting from prologue node. - */ - bool doLoopInfoDFS(Node* node, DFSLoopInfo* info, NodeList& outerLoopHeaders) const; - - /** debug check for loop info, should be used inside asserts - recalculates loop-info and returns TRUE if OK*/ - bool ensureLoopInfoIsValid(); - - - - //------------------------------------------------------------------------------------- - MemoryManager & memoryManager; - - Nodes nodes; - mutable Nodes postorderNodesCache; - uint32 nodeId; - BasicBlock * prologNode; - ExitNode * exitNode; - UnwindNode * unwindNode; - - - /** number of graph modification: nodes (add/remove) and edges(add/remove/retarget) */ - uint32 graphModCount; - /** graph mod count value when loop info was calculated */ - uint32 lastLoopInfoVersion; - mutable uint32 lastPostorderVersion; - bool _isLaidOut; - - uint32 maxLoopDepth; - - void * codeStartAddr; - mutable StlVector traversalInfo; - - bool edgeProfile; - }; - - //========================================================================================================= - // class CFG::NodeIterator - //========================================================================================================= - /** - class CFG::NodeIterator is an alternative CFG traversal interface - which is more convenient than visitor - - The NodeIterator is a forward-only iterator - - One creates an iterator using its constructor and calls its ++ operator to gen access to the next node - - Usage pattern: - for(CFG::NodeIterator it(irManager, CFG::OrderType_Postorder); it!=NULL; it++) { - Node * node=it.getNode(); - } - */ - class CFG::NodeIterator { - const Nodes* nodes; - int currentIdx, borderIdx, increment; - public: - /** gets the current node */ - Node * getNode()const { return currentIdx != borderIdx ? (*nodes)[currentIdx]: NULL;} - /** increments the iterator */ - NodeIterator& operator++(){ if (currentIdx!=borderIdx) currentIdx+=increment; return *this;} - operator Node*()const{ return getNode(); } - void rewind(); - - /** creates an iterator traversing CFG in the orderType order */ - NodeIterator(const CFG& fg, OrderType orderType=OrderType_Arbitrary); - ~NodeIterator(){}; - private: - NodeIterator(const NodeIterator& r) { assert(0); } // should not copy NodeIterator - NodeIterator& operator=(const NodeIterator& r){ assert(0); return *this; } - //---------------------------------------------------------------------------------- - - friend class CFG; + void* codeAddr; }; - - //========================================================================================================= - }; //namespace Ia32 } #endif // _IA32_FLOWGRAPH_H diff --git vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.cpp vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.cpp index 938f383..4c699d1 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.cpp @@ -25,99 +25,199 @@ namespace Jitrino{ namespace Ia32{ const CallingConvention * CallingConvention::str2cc(const char * cc_name) { - if( NULL == cc_name ) { // default - return &CallingConvention_STDCALL; - } - - if( !strcmpi(cc_name, "stdcall") ) { - return &CallingConvention_STDCALL; - } - - if( !strcmpi(cc_name, "drl") ) { - return &CallingConvention_DRL; - } - - if( !strcmpi(cc_name, "cdecl") ) { - return &CallingConvention_CDECL; - } - assert( false ); - return NULL; + if( NULL == cc_name ) { // default + return &CallingConvention_STDCALL; + } + + if( !strcmpi(cc_name, "stdcall") ) { + return &CallingConvention_STDCALL; + } + + if( !strcmpi(cc_name, "drl") ) { + return &CallingConvention_DRL; + } + + if( !strcmpi(cc_name, "cdecl") ) { + return &CallingConvention_CDECL; + } + assert( false ); + return NULL; } //======================================================================================== -STDCALLCallingConvention CallingConvention_STDCALL; -DRLCallingConvention CallingConvention_DRL; -CDECLCallingConvention CallingConvention_CDECL; +STDCALLCallingConvention CallingConvention_STDCALL; +DRLCallingConvention CallingConvention_DRL; +CDECLCallingConvention CallingConvention_CDECL; //======================================================================================== // class STDCALLCallingConvention //======================================================================================== +#ifdef _EM64T_ +const RegName fastCallGPRegs[6] = {RegName_RDI, RegName_RSI, RegName_RDX, RegName_RCX, RegName_R8, RegName_R9} ; +const RegName fastCallFPRegs[8] = {RegName_XMM0,RegName_XMM1,RegName_XMM2,RegName_XMM3,RegName_XMM4,RegName_XMM5,RegName_XMM6,RegName_XMM7}; +#endif + //______________________________________________________________________________________ -void STDCALLCallingConvention::getOpndInfo(ArgKind kind, uint32 count, OpndInfo * infos)const +void STDCALLCallingConvention::getOpndInfo(ArgKind kind, uint32 count, OpndInfo * infos)const { - if (kind==ArgKind_InArg){ - for (uint32 i=0; i0){ - infos[i].slotCount=0; - }else{ - switch(typeTag){ - case Type::Void: - infos[i].slotCount=0; - break; - case Type::Float: - case Type::Double: - case Type::Single: - infos[i].slotCount=1; - infos[i].slots[0]=RegName_FP0; - break; - default: - { - OpndSize size=IRManager::getTypeSize(typeTag); - assert(size!=OpndSize_Null && size<=OpndSize_64); - - infos[i].slotCount=1; - infos[i].slots[0]=RegName_EAX; - - if (size==OpndSize_64){ - infos[i].slotCount=2; - infos[i].slots[1]=RegName_EDX; - } - } - } - } - } - } + if (kind==ArgKind_InArg){ +#ifdef _EM64T_ + uint32 gpreg = 0; + uint32 fpreg = 0; +#endif + for (uint32 i=0; iType::Float ||typeTag=Type::Single) && fpreg < lengthof(fastCallFPRegs))) { + infos[i].slotCount=1; + infos[i].slots[0]=fastCallFPRegs[fpreg]; + infos[i].isReg=true; + fpreg++; + } else { + infos[i].slotCount=1; + infos[i].slots[0]=RegName_Null; + infos[i].isReg=false; + } + + +#else + OpndSize size=IRManager::getTypeSize(typeTag); + assert(size!=OpndSize_Null && size<=OpndSize_64); + + infos[i].slotCount=1; + infos[i].slots[0]=RegName_Null; + infos[i].isReg=false; + + if (size==OpndSize_64){ + infos[i].slotCount=2; + infos[i].slots[1]=RegName_Null; + } +#endif + + } + }else{ + for (uint32 i=0; i0){ + infos[i].slotCount=0; + }else{ + switch(typeTag){ + case Type::Void: + infos[i].slotCount=0; + break; + case Type::Float: + case Type::Double: + case Type::Single: +#ifdef _EM64T_ + infos[i].slotCount=1; + infos[i].slots[0]=RegName_XMM0; +#else + infos[i].slotCount=1; + infos[i].slots[0]=RegName_FP0; +#endif + break; + default: + { + OpndSize size=IRManager::getTypeSize(typeTag); +#ifdef _EM64T_ + infos[i].slotCount=1; + infos[i].slots[0]=RegName_RAX; + + if (size==OpndSize_128){ + infos[i].slotCount=2; + infos[i].slots[1]=RegName_RDX; + } +#else + assert(size!=OpndSize_Null && size<=OpndSize_64); + + infos[i].slotCount=1; + infos[i].slots[0]=RegName_EAX; + + if (size==OpndSize_64){ + infos[i].slotCount=2; + infos[i].slots[1]=RegName_EDX; + } +#endif + } + } + } + } + } } //______________________________________________________________________________________ -uint32 STDCALLCallingConvention::getCalleeSavedRegs(OpndKind regKind)const +Constraint STDCALLCallingConvention::getCalleeSavedRegs(OpndKind regKind)const { - switch (regKind){ - case OpndKind_GPReg: - return (Constraint(RegName_EBX)|RegName_EBP|RegName_ESI|RegName_EDI).getMask(); - default: - return 0; - } + switch (regKind){ + case OpndKind_GPReg: +#ifdef _EM64T_ + return (Constraint(RegName_RBX)|RegName_RBP|RegName_R12|RegName_R13|RegName_R14|RegName_R15); +#else + return (Constraint(RegName_EBX)|RegName_EBP|RegName_ESI|RegName_EDI); +#endif + default: + return Constraint(); + } } +#ifdef _EM64T_ +//______________________________________________________________________________________ +void CDECLCallingConvention::getOpndInfo(ArgKind kind, uint32 count, OpndInfo * infos)const +{ + if (kind==ArgKind_InArg){ + for (uint32 i=0; i0){ + infos[i].isReg=false; + infos[i].slotCount=0; + }else{ + switch(typeTag){ + case Type::Void: + infos[i].isReg=false; + infos[i].slotCount=0; + break; + case Type::Float: + case Type::Double: + case Type::Single: + infos[i].isReg=true; + infos[i].slotCount=1; + infos[i].slots[0]=RegName_XMM0; + break; + default: + { + OpndSize size=IRManager::getTypeSize(typeTag); + infos[i].slotCount=1; + infos[i].slots[0]=RegName_RAX; + infos[i].isReg=true; + + if (size==OpndSize_128){ + infos[i].slotCount=2; + infos[i].slots[1]=RegName_RDX; + } + } + } + } + } + } +} + +#endif //______________________________________________________________________________________ diff --git vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h index e951aef..3f5716c 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h +++ vm/jitrino/src/codegenerator/ia32/Ia32CallingConvention.h @@ -24,6 +24,7 @@ #define _IA32_CALLING_CONVENTION_H_ #include "open/types.h" #include "Type.h" #include "Ia32IRConstants.h" +#include "Ia32Constraint.h" namespace Jitrino @@ -46,49 +47,50 @@ Implementers of this interface are used */ class CallingConvention -{ -public: - virtual ~CallingConvention() {} - //-------------------------------------------------------------- - - struct OpndInfo - { - uint32 typeTag; - uint32 slotCount; - RegName slots[4]; - }; - - //-------------------------------------------------------------- - enum ArgKind - { - ArgKind_InArg, - ArgKind_RetArg - }; - - - /** Fills the infos array with information how incoming arguments or return values are passed - according to this calling convention - */ - virtual void getOpndInfo(ArgKind kind, uint32 argCount, OpndInfo * infos) const =0; - - /** Returns a mask describing registers of regKind which are to be preserved by a callee - */ - virtual uint32 getCalleeSavedRegs(OpndKind regKind) const =0; - - /** Returns true if restoring arg stack is callee's responsibility - */ - virtual bool calleeRestoresStack() const =0; - - /** True arguments are pushed from the last to the first, false in the other case - */ - virtual bool pushLastToFirst()const =0; - /** - * Maps a string representation of CallingConvention to the - * appropriate CallingConvention_* item. - * If cc_name is NULL, then default for this platform convention - * is returned. - */ - static const CallingConvention * str2cc(const char * cc_name); +{ +public: + //-------------------------------------------------------------- + + struct OpndInfo + { + uint32 typeTag; + uint32 slotCount; + bool isReg; + uint32 slots[4]; + }; + + //-------------------------------------------------------------- + enum ArgKind + { + ArgKind_InArg, + ArgKind_RetArg + }; + + virtual ~CallingConvention() {} + + /** Fills the infos array with information how incoming arguments or return values are passed + according to this calling convention + */ + virtual void getOpndInfo(ArgKind kind, uint32 argCount, OpndInfo * infos) const =0; + + /** Returns a mask describing registers of regKind which are to be preserved by a callee + */ + virtual Constraint getCalleeSavedRegs(OpndKind regKind) const =0; + + /** Returns true if restoring arg stack is callee's responsibility + */ + virtual bool calleeRestoresStack() const =0; + + /** True arguments are pushed from the last to the first, false in the other case + */ + virtual bool pushLastToFirst()const =0; + /** + * Maps a string representation of CallingConvention to the + * appropriate CallingConvention_* item. + * If cc_name is NULL, then default for this platform convention + * is returned. + */ + static const CallingConvention * str2cc(const char * cc_name); }; @@ -102,13 +104,18 @@ typedef StlVector& container, + Node * node, bool isForward); + void CodeEmitter::reportCompiledInlinees(); + + //------------------------------------------------------------------------------------ + class ConstantAreaLayout + { + public: + ConstantAreaLayout(MemoryManager& mm) + :memoryManager(mm), items(memoryManager){}; + + void collectItems(); + void calculateItemOffsets(); + void doLayout(IRManager*); + void finalizeSwitchTables(); + + protected: + IRManager* irManager; + MemoryManager& memoryManager; + StlVector items; + + POINTER_SIZE_INT dataSize; + + const static POINTER_SIZE_INT blockAlignment=16; + private: + + }; + + + //------------------------------------------------------------------------------------ + struct ExceptionHandlerInfo + { + void * regionStart; + void * regionEnd; + void * handlerAddr; + ObjectType * exceptionType; + bool exceptionObjectIsDead; + + ExceptionHandlerInfo( + void * _regionStart, + void * _regionEnd, + void * _handlerAddr, + ObjectType * _exceptionType, + bool _exceptionObjectIsDead=false + ): + regionStart(_regionStart), + regionEnd(_regionEnd), + handlerAddr(_handlerAddr), + exceptionType(_exceptionType), + exceptionObjectIsDead(_exceptionObjectIsDead){} + + }; + + // bc to native map stuff + VectorHandler* bc2LIRMapHandler; + + MemoryManager memoryManager; + StlVector exceptionHandlerInfos; + ConstantAreaLayout constantAreaLayout; + StlVector traversalInfo; + StlMap methodLocationMap; + StlMap entryExitMap; +}; +class CompiledMethodInfo { +public: + CompiledMethodInfo(MemoryManager& mm): locationList(mm) {} + uint32 getCodeSize() { return codeSize; } + void* getCodeAddr() { return codeAddr; } + +protected: + friend class CodeEmitter; + StlList* > locationList; + uint32 codeSize; + void* codeAddr; + void setCodeSize(uint32 size) { codeSize = size; } + void setCodeAddr(void* addr) { codeAddr = addr; } + void addLocation(std::pair* entry) { + locationList.push_back(entry); + } +private: + +}; + + +static ActionFactory _emitter("emitter"); //======================================================================================== // class CodeEmitter::ConstantAreaLayout @@ -38,13 +160,20 @@ namespace Ia32 //________________________________________________________________________________________ void CodeEmitter::ConstantAreaLayout::collectItems() { - for (uint32 i=0, n=irManager.getOpndCount(); igetOpndCount(); igetOpnd(i); Opnd::RuntimeInfo * ri=NULL; if (opnd->isPlacedIn(OpndKind_Mem)&&opnd->getMemOpndKind()==MemOpndKind_ConstantArea){ Opnd * addrOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); +#ifndef _EM64T_ ri=addrOpnd->getRuntimeInfo(); assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); +#else + if(addrOpnd) { + ri=addrOpnd->getRuntimeInfo(); + assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); + } +#endif }else if (opnd->isPlacedIn(OpndKind_Imm)){ ri=opnd->getRuntimeInfo(); if (ri && ri->getKind()!=Opnd::RuntimeInfo::Kind_ConstantAreaItem) @@ -63,11 +192,11 @@ void CodeEmitter::ConstantAreaLayout::co //________________________________________________________________________________________ void CodeEmitter::ConstantAreaLayout::calculateItemOffsets() { - uint32 offset=0; + POINTER_SIZE_INT offset=0; for (uint32 i=0, n=items.size(); igetSize(); - uint32 alignment=size; + POINTER_SIZE_INT size=item->getSize(); + POINTER_SIZE_INT alignment=size; if (size<=4) alignment=4; else if (size<=8) @@ -82,19 +211,20 @@ void CodeEmitter::ConstantAreaLayout::ca } //________________________________________________________________________________________ -void CodeEmitter::ConstantAreaLayout::doLayout() +void CodeEmitter::ConstantAreaLayout::doLayout(IRManager* irm) { + irManager = irm; collectItems(); calculateItemOffsets(); - uint32 dataBlock = (uint32)irManager.getCompilationInterface() + POINTER_SIZE_INT dataBlock = (POINTER_SIZE_INT)irManager->getCompilationInterface() .allocateDataBlock(dataSize + blockAlignment*2, blockAlignment); dataBlock=(dataBlock+blockAlignment-1)&~(blockAlignment-1); assert(dataBlock % blockAlignment == 0); for (uint32 i=0, n=items.size(); igetAddress(); + POINTER_SIZE_INT offset=(POINTER_SIZE_INT)item->getAddress(); item->setAddress((void*)(dataBlock+offset)); if (!item->hasKind(ConstantAreaItem::Kind_SwitchTableConstantAreaItem)) memcpy(item->getAddress(), item->getValue(), item->getSize()); @@ -104,17 +234,19 @@ void CodeEmitter::ConstantAreaLayout::do //________________________________________________________________________________________ void CodeEmitter::ConstantAreaLayout::finalizeSwitchTables() { +#ifdef _DEBUG + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); +#endif for (uint32 i=0, n=items.size(); ihasKind(ConstantAreaItem::Kind_SwitchTableConstantAreaItem)){ void ** table = (void **)item->getAddress(); - BasicBlock ** bbs=(BasicBlock **)item->getValue(); - uint32 nbb=(uint32)item->getSize()/sizeof(BasicBlock*); + Node** bbs=(Node **)item->getValue(); + uint32 nbb=(uint32)item->getSize()/sizeof(Node*); for (uint32 ibb=0; ibbgetCodeStartAddr()!=NULL); + assert(std::find(nodes.begin(), nodes.end(), bb)!=nodes.end()); table[ibb]=bb->getCodeStartAddr(); } } @@ -129,35 +261,43 @@ void CodeEmitter::ConstantAreaLayout::fi //________________________________________________________________________________________ void CodeEmitter::runImpl() { - irManager.setInfo("inlineInfo", new(irManager.getMemoryManager()) InlineInfoMap(irManager.getMemoryManager())); - constantAreaLayout.doLayout(); - irManager.resolveRuntimeInfo(); + if (irManager->getCompilationInterface().isBCMapInfoRequired()) { + MethodDesc* meth = irManager->getCompilationInterface().getMethodToCompile(); + bc2LIRMapHandler = new(memoryManager) VectorHandler(bcOffset2LIRHandlerName, meth); + } + + irManager->setInfo("inlineInfo", new(irManager->getMemoryManager()) InlineInfoMap(irManager->getMemoryManager())); + constantAreaLayout.doLayout(irManager); + irManager->resolveRuntimeInfo(); emitCode(); + packCode(); postPass(); constantAreaLayout.finalizeSwitchTables(); registerExceptionHandlers(); registerInlineInfoOffsets(); - + if (irManager->getCompilationInterface().isCompileLoadEventRequired()) { + reportCompiledInlinees(); + } } - +//________________________________________________________________________________________ void CodeEmitter::registerInlineInfoOffsets() { - InlineInfoMap * inlineMap = (InlineInfoMap *)irManager.getInfo("inlineInfo"); - for (CFG::NodeIterator it(irManager); it!=NULL; ++it){ - if (((Node*)it)->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock * )(Node*)it; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ + InlineInfoMap * inlineMap = (InlineInfoMap *)irManager->getInfo("inlineInfo"); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ if(inst->getMnemonic() == Mnemonic_CALL) { CallInst* callinst = (CallInst*)inst; if ( callinst->getInlineInfo() ) { - Log::cat_opt_inline()->ir << "callinstr, at offset=" << (uint32)inst->getCodeStartAddr()+inst->getCodeSize() << ::std::endl; - Log::cat_opt_inline()->ir << "has inline info:" << ::std::endl; - callinst->getInlineInfo()->printLevels(Log::cat_opt_inline()->ir); + Log::out() << "callinstr, at offset=" << (POINTER_SIZE_INT)inst->getCodeStartAddr()+inst->getCodeSize() << std::endl; + Log::out() << "has inline info:" << std::endl; + callinst->getInlineInfo()->printLevels(Log::out()); // report offset 1 bundle forward - inlineMap->registerOffset((uint32)inst->getCodeStartAddr() - (uint32)irManager.getCodeStartAddr()+inst->getCodeSize(), callinst->getInlineInfo()); + inlineMap->registerOffset((POINTER_SIZE_INT)inst->getCodeStartAddr()+inst->getCodeSize() - (POINTER_SIZE_INT)irManager->getCodeStartAddr(), callinst->getInlineInfo()); } - Log::cat_opt_inline()->ir << ::std::endl; + Log::out() << std::endl; } } } @@ -168,11 +308,11 @@ void CodeEmitter::registerInlineInfoOffs bool CodeEmitter::verify (bool force) { bool failed=false; - if (force || irManager.getVerificationLevel() >= 1) + if (force || getVerificationLevel() >= 1) { - irManager.updateLivenessInfo(); - for (uint32 i=0, n=irManager.getOpndCount(); iupdateLivenessInfo(); + for (uint32 i=0, n=irManager->getOpndCount(); igetOpnd(i); if (!opnd->hasAssignedPhysicalLocation()){ VERIFY_OUT("Unassigned operand: " << opnd << ::std::endl); failed=true; @@ -185,10 +325,10 @@ bool CodeEmitter::verify (bool force) //________________________________________________________________________________________ void CodeEmitter::emitCode( void ) { - // irManager.getMaxInstId() - is max possible number of instructions - // irManager.getMaxNodeId() - to handle number of basic blocks, when jmp targets alignment used + // irManager->getMaxInstId() - is max possible number of instructions + // irManager->getMaxNodeId() - to handle number of basic blocks, when jmp targets alignment used // as the current scheme only process basic blocks as jmp targets - const unsigned maxMethodSize = (irManager.getMaxInstId() + irManager.getMaxNodeId())*MAX_NATIVE_INST_SIZE; + const unsigned maxMethodSize = (irManager->getMaxInstId() + irManager->getFlowGraph()->getMaxNodeId())*MAX_NATIVE_INST_SIZE; // uint8 * codeStreamStart = (uint8*)malloc( maxMethodSize ); @@ -202,27 +342,45 @@ #endif uint8 * ip = codeStreamStart; - for( BasicBlock * bb = irManager.getPrologNode(); bb != NULL; bb=bb->getLayoutSucc()) { + for( BasicBlock * bb = (BasicBlock*)irManager->getFlowGraph()->getEntryNode(); bb != NULL; bb=bb->getLayoutSucc()) { uint8 * blockStartIp = ip; bb->setCodeOffset( blockStartIp-codeStreamStart ); - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ + for (Inst* inst = (Inst*)bb->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { if( inst->hasKind(Inst::Kind_PseudoInst)) continue; + +#ifdef _EM64T_ + if (inst->hasKind(Inst::Kind_ControlTransferInst) && + ((ControlTransferInst*)inst)->isDirect() && + inst->getMnemonic() == Mnemonic_CALL) + { + if ((POINTER_SIZE_INT)ip & 0xF) + { + uint64 align = 0x10 - ((POINTER_SIZE_INT)ip & 0xF); + ip = (uint8*)EncoderBase::nops((char*)ip, align); + } + uint8 * instStartIp = ip; + inst->setCodeOffset( instStartIp-blockStartIp ); + ip = inst->emit(ip); + ip = (uint8*)EncoderBase::nops((char*)ip, 0x10 - inst->getCodeSize()); + } else { +#endif uint8 * instStartIp = ip; inst->setCodeOffset( instStartIp-blockStartIp ); ip = inst->emit(ip); - inst->setCodeSize( ip-instStartIp ); +#ifdef _EM64T_ + } +#endif } bb->setCodeSize( ip-blockStartIp ); } unsigned codeSize = (unsigned)(ip-codeStreamStart); assert( codeSize < maxMethodSize ); - uint8 * codeBlock = (uint8*)irManager.getCompilationInterface().allocateCodeBlock( + uint8 * codeBlock = (uint8*)irManager->getCompilationInterface().allocateCodeBlock( codeSize , JMP_TARGET_ALIGMENT, getCodeSectionHeat(0), 0, false ); memcpy(codeBlock, codeStreamStart, codeSize); - irManager.setCodeStartAddr(codeBlock); + irManager->setCodeStartAddr(codeBlock); //^ //| @@ -232,16 +390,64 @@ #endif } //________________________________________________________________________________________ +void CodeEmitter::packCode() { + bool newOpndsCreated = false; + for( BasicBlock * bb = (BasicBlock*)irManager->getFlowGraph()->getEntryNode(), * succ; bb != NULL; bb = succ) { + succ = (BasicBlock*)bb->getLayoutSucc(); + Inst* inst = (Inst*)bb->getLastInst(); + if (inst != NULL){ + if (inst->hasKind(Inst::Kind_ControlTransferInst) && ((ControlTransferInst*)inst)->isDirect()){ + BasicBlock * bbTarget = NULL; + if (inst->hasKind(Inst::Kind_BranchInst)) + bbTarget=(BasicBlock*)((BranchInst*)inst)->getTrueTarget(); + else if (inst->hasKind(Inst::Kind_JmpInst)) + bbTarget = (BasicBlock*)bb->getUnconditionalEdgeTarget(); + if (bbTarget != NULL){ + uint8 * instCodeStartAddr = (uint8*)inst->getCodeStartAddr(); + uint8 * instCodeEndAddr = (uint8*)instCodeStartAddr+inst->getCodeSize(); + uint8 * targetCodeStartAddr = (uint8*)bbTarget->getCodeStartAddr(); + uint32 targetOpndIndex = ((ControlTransferInst*)inst)->getTargetOpndIndex(); + int64 offset=targetCodeStartAddr-instCodeEndAddr; + if (offset >= -128 && offset < 127 && inst->getOpnd(targetOpndIndex)->getSize() != OpndSize_8) { + inst->setOpnd(targetOpndIndex, irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int8), offset)); + uint8 * newInstCodeEndAddr = inst->emit(instCodeStartAddr); + bb->setCodeSize(bb->getCodeSize() + (newInstCodeEndAddr - instCodeEndAddr)); + newOpndsCreated = true; + } + } + } + + if (newOpndsCreated && succ != NULL){ + int bbCodeOffset = bb->getCodeOffset(); + int succCodeOffset = succ->getCodeOffset(); + int bbCodeSize = bb->getCodeSize(); + int succCodeSize = succ->getCodeSize(); + int bbDisplacement = succCodeOffset - bbCodeOffset - bbCodeSize; + if (bbDisplacement != 0){ + uint8 * ps = (uint8*)irManager->getCodeStartAddr() + succCodeOffset; + uint8 * pd = ps - bbDisplacement; + uint8 * pn = ps + succCodeSize; + while (ps < pn) + *pd++ = *ps++; + succ->setCodeOffset(succCodeOffset - bbDisplacement); + } + } + } + } + if (newOpndsCreated) + irManager->fixLivenessInfo(); +} + +//________________________________________________________________________________________ void CodeEmitter::postPass() { - MemoryManager& irmm = irManager.getMemoryManager(); - bool isBcRequired = irManager.getCompilationInterface().isBCMapInfoRequired(); + MemoryManager& irmm = irManager->getMemoryManager(); + bool isBcRequired = irManager->getCompilationInterface().isBCMapInfoRequired(); BcMap* bcMap = new(irmm) BcMap(irmm); - irManager.setInfo("bcMap", bcMap); - for( BasicBlock * bb = irManager.getPrologNode(); bb != NULL; bb=bb->getLayoutSucc()) { + irManager->setInfo("bcMap", bcMap); + for( BasicBlock * bb = (BasicBlock*)irManager->getFlowGraph()->getEntryNode(); bb != NULL; bb=bb->getLayoutSucc()) { uint64 bcOffset; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)) { + for (Inst* inst = (Inst*)bb->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { if (inst->hasKind(Inst::Kind_ControlTransferInst) && ((ControlTransferInst*)inst)->isDirect() ){ @@ -250,21 +456,42 @@ void CodeEmitter::postPass() uint8 * targetCodeStartAddr=0; uint32 targetOpndIndex = ((ControlTransferInst*)inst)->getTargetOpndIndex(); if (inst->hasKind(Inst::Kind_BranchInst)){ - BasicBlock * bbTarget=((BranchInst*)inst)->getDirectBranchTarget(); + BasicBlock * bbTarget=(BasicBlock*)((BranchInst*)inst)->getTrueTarget(); targetCodeStartAddr=(uint8*)bbTarget->getCodeStartAddr(); - }else if (inst->hasKind(Inst::Kind_CallInst)){ + } else if (inst->hasKind(Inst::Kind_JmpInst)){ + BasicBlock* bbTarget = (BasicBlock*)bb->getUnconditionalEdgeTarget(); + targetCodeStartAddr=(uint8*)bbTarget->getCodeStartAddr(); + } else if (inst->hasKind(Inst::Kind_CallInst)){ targetCodeStartAddr=(uint8*)(POINTER_SIZE_INT)inst->getOpnd(targetOpndIndex)->getImmValue(); }else continue; - uint32 offset=targetCodeStartAddr-instCodeEndAddr; - inst->getOpnd(targetOpndIndex)->assignImmValue((int)offset); + int64 offset=targetCodeStartAddr-instCodeEndAddr; + +#ifdef _EM64T_ + if (llabs(offset) > 0xFFFFFFFF) { + const RegName TMP_BASE = RegName_R14; + EncoderBase::Operands args; + args.clear(); + args.add(TMP_BASE); + args.add(EncoderBase::Operand(OpndSize_64, offset)); + char * ip = EncoderBase::encode((char*)instCodeStartAddr, Mnemonic_MOV, args); + args.clear(); + args.add(TMP_BASE); + EncoderBase::encode(ip, Mnemonic_CALL, args); + } else { +#endif + inst->getOpnd(targetOpndIndex)->assignImmValue((int64)offset); // re-emit the instruction: inst->emit(instCodeStartAddr); if (inst->hasKind(Inst::Kind_CallInst)){ registerDirectCall(inst); } - } +#ifdef _EM64T_ + } +#endif + } + // todo64 if (isBcRequired) { uint64 instID = inst->getId(); bcOffset = bc2LIRMapHandler->getVectorEntry(instID); @@ -290,8 +517,8 @@ void CodeEmitter::registerDirectCall(Ins if( !ri || ri->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) { return; }; MethodDesc * md = (MethodDesc*)ri->getValue(0); - irManager.getCompilationInterface().setNotifyWhenMethodIsRecompiled(md,inst->getCodeStartAddr()); - if (Log::cat_cg()->isDebugEnabled()) { + irManager->getCompilationInterface().setNotifyWhenMethodIsRecompiled(md,inst->getCodeStartAddr()); + if (Log::isEnabled()) { Log::out() << "Registered call to " << md->getParentType()->getName() << "." << md->getName() << " at "; Log::out() << inst->getCodeStartAddr() << " for recompiled method event" << ::std::endl; } @@ -307,9 +534,10 @@ bool RuntimeInterface::recompiledMethodE Byte * callAddr = (Byte*)data; uint32 offset = targetAddr - callAddr-5; - if (Log::cat_rt()->isDebugEnabled()) { - Log::cat_rt()->out() << "patching call to "<getName()<<" at "<<(void*)callAddr<<"; new target address is "<<(void*)targetAddr<< ::std::endl; - } + //FIXME + //if (Log::cat_rt()->isDebugEnabled()) { + // Log::cat_rt()->out() << "patching call to "<getName()<<" at "<<(void*)callAddr<<"; new target address is "<<(void*)targetAddr<< ::std::endl; + //} *(uint32*)(callAddr+1)=offset; @@ -320,44 +548,44 @@ bool RuntimeInterface::recompiledMethodE CompilationInterface::CodeBlockHeat CodeEmitter::getCodeSectionHeat(uint32 sectionID)const { CompilationInterface::CodeBlockHeat heat; - CompilationInterface& ci=irManager.getCompilationInterface(); - uint32 level = ci.getOptimizationLevel(); - if (level == 0) - heat = CompilationInterface::CodeBlockHeatMin; - else if (level == 1 && ci.isDynamicProfiling()) + if (irManager->getCompilationContext()->hasDynamicProfileToUse()) heat = CompilationInterface::CodeBlockHeatDefault; else if (sectionID==0) heat = CompilationInterface::CodeBlockHeatMax; else heat = CompilationInterface::CodeBlockHeatMin; + return heat; } //________________________________________________________________________________________ void CodeEmitter::registerExceptionHandlers() { - uint32 regionStart=0, regionEnd=0; DispatchNode * regionDispatchNode=NULL; - for( BasicBlock * bb = irManager.getPrologNode(); bb != NULL; bb=bb->getLayoutSucc()) { - DispatchNode * dispatchNode=(DispatchNode *)bb->getNode(Direction_Out, Node::Kind_DispatchNode); - if (regionDispatchNode!=dispatchNode){ - if (regionDispatchNode!=NULL && regionStartgetCodeStartAddr(); + ControlFlowGraph* fg = irManager->getFlowGraph(); + Node* unwind = fg->getUnwindNode(); + POINTER_SIZE_INT regionStart=0, regionEnd=0; Node * regionDispatchNode=NULL; + for( BasicBlock * bb = (BasicBlock*)fg->getEntryNode(); bb != NULL; bb=bb->getLayoutSucc()) { + Node * dispatchNode= bb->getExceptionEdgeTarget(); + if (regionDispatchNode!=dispatchNode) { + if (regionDispatchNode!=NULL && regionDispatchNode!=unwind && regionStartgetCodeSize(); + regionDispatchNode=dispatchNode; + regionStart=regionEnd=(POINTER_SIZE_INT)bb->getCodeStartAddr(); + } + if (dispatchNode!=NULL){ + regionEnd+=bb->getCodeSize(); } } - if (regionDispatchNode!=NULL && regionStartgetCompilationInterface().setNumExceptionHandler(handlerInfoCount); for (uint32 i=0; iisDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Exception Handler Info [ " << i << "]: " << ::std::endl; Log::out() << " " << (void*)(info.regionStart) << " - "<<(void*)(info.regionEnd) << " => " << (void*)info.handlerAddr << ::std::endl << " "; @@ -365,7 +593,7 @@ void CodeEmitter::registerExceptionHandl Log::out() << ::std::endl; } - irManager.getCompilationInterface(). + irManager->getCompilationInterface(). setExceptionHandlerInfo(i, (Byte*)info.regionStart, (Byte*)info.regionEnd, (Byte*)info.handlerAddr, @@ -375,40 +603,173 @@ void CodeEmitter::registerExceptionHandl } + +static bool edge_prior_comparator(const Edge* e1, const Edge* e2) { + assert(e1->isCatchEdge() && e2->isCatchEdge()); + uint32 p1 = ((CatchEdge*)e1)->getPriority(); + uint32 p2 = ((CatchEdge*)e2)->getPriority(); + assert(p1!=p2 || e1==e2); + return p1 < p2 ? true : p1 > p2 ? false : e1 > e2; +}; + //________________________________________________________________________________________ -void CodeEmitter::registerExceptionRegion(void * regionStart, void * regionEnd, DispatchNode * regionDispatchNode) +void CodeEmitter::registerExceptionRegion(void * regionStart, void * regionEnd, Node* regionDispatchNode) { + assert(regionDispatchNode->isDispatchNode()); assert(regionStart!=NULL && regionStartsortCatchEdges(); - const Edges& edges=regionDispatchNode->getEdges(Direction_Out); - for (Edge * edge=edges.getFirst(); edge!=NULL; edge=edges.getNext(edge)){ - Node * head=edge->getNode(Direction_Head); - if (edge->hasKind(Edge::Kind_CatchEdge)){ - BasicBlock * handler=(BasicBlock*)head; - - const Insts& insts = handler->getInsts(); - Inst * catchInst =insts.getFirst(); - for(; catchInst != NULL && catchInst->getKind() != Inst::Kind_CatchPseudoInst;catchInst = insts.getNext(catchInst)); - assert(catchInst); - MemoryManager mm(0x400, "CatchOpnds"); - LiveSet * ls=new(mm) LiveSet(mm, irManager.getOpndCount()); - irManager.getLiveAtExit(handler, *ls); - for (Inst * inst=insts.getLast(); inst!=catchInst; inst=insts.getPrev(inst)){ - irManager.updateLiveness(inst, *ls); + assert(regionDispatchNode!=irManager->getFlowGraph()->getUnwindNode()); + + const Edges& edges=regionDispatchNode->getOutEdges(); + Edges catchEdges(irManager->getMemoryManager()); + Node* dispatchHead = NULL; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (edge->isCatchEdge()) { + catchEdges.push_back(edge); + } else { + assert(dispatchHead == NULL); + dispatchHead = edge->getTargetNode(); + assert(dispatchHead->isDispatchNode()); + } + } + std::sort(catchEdges.begin(), catchEdges.end(), edge_prior_comparator); + + for (Edges::const_iterator ite = catchEdges.begin(), ende = catchEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + BasicBlock* handler = (BasicBlock*)edge->getTargetNode(); + Inst * catchInst = (Inst*)handler->getFirstInst(); + assert(catchInst && catchInst->getKind() == Inst::Kind_CatchPseudoInst); + MemoryManager mm(0x400, "CatchOpnds"); + BitSet * ls=new(mm) BitSet(mm, irManager->getOpndCount()); + irManager->getLiveAtExit(handler, *ls); + for (Inst* inst = (Inst*)handler->getLastInst(); inst!=catchInst; inst = inst->getPrevInst()) { + irManager->updateLiveness(inst, *ls); + } + bool isExceptObjDead = !ls->getBit(catchInst->getOpnd(0)->getId()); + + void * handlerAddr=handler->getCodeStartAddr(); + ObjectType * exceptionType = (ObjectType*)((CatchEdge*)edge)->getType(); + exceptionHandlerInfos.push_back( + ExceptionHandlerInfo(regionStart, regionEnd, handlerAddr, exceptionType, isExceptObjDead) + ); + } + if (dispatchHead!=NULL && dispatchHead!=irManager->getFlowGraph()->getUnwindNode()) { + registerExceptionRegion(regionStart, regionEnd, dispatchHead); + } +} +//___________________________________________________________________ +// Yet another CFG ordering to compute inliniees +//___________________________________________________________________ +void CodeEmitter::orderNodesAndMarkInlinees(StlList& inlineStack, + Node* node, bool isForward) { + assert(node!=NULL); + assert(traversalInfo[node->getId()]==0); //node is white here + uint32 nodeId = node->getId(); + traversalInfo[nodeId] = 1; //mark node gray + // preprocess the node + if (node->getKind() == Node::Kind_Block) { + MethodMarkerPseudoInst* methMarkerInst = NULL; + CompiledMethodInfo* methInfo = NULL; + + if (!inlineStack.empty()) { + methMarkerInst = inlineStack.back(); + methInfo = methodLocationMap[methMarkerInst]; + } + + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { + if (inst->getKind() == Inst::Kind_MethodEntryPseudoInst) { + methMarkerInst = (MethodMarkerPseudoInst*)inst; + inlineStack.push_back(methMarkerInst); + methInfo = new(memoryManager) CompiledMethodInfo(memoryManager); + methInfo->setCodeAddr(methMarkerInst->getCodeStartAddr()); + methodLocationMap[methMarkerInst] = methInfo; + } else if (inst->getKind() == Inst::Kind_MethodEndPseudoInst) { + methMarkerInst = (MethodMarkerPseudoInst*)inst; + assert(((MethodMarkerPseudoInst*)inlineStack.back())->getMethodDesc() == methMarkerInst->getMethodDesc()); + entryExitMap[methMarkerInst] = inlineStack.back(); + if (methInfo != NULL) { + Inst* entryInst = inlineStack.back(); + POINTER_SIZE_INT codeSize = (POINTER_SIZE_INT)entryInst->getCodeStartAddr() + - (POINTER_SIZE_INT)methMarkerInst->getCodeStartAddr(); + methInfo->setCodeSize((uint32)codeSize); + } + inlineStack.pop_back(); + methMarkerInst = NULL; + } else { //handle usual instructions + if (methMarkerInst != NULL) { // inlined locations for methMarkerInst + assert(methInfo == methodLocationMap[methMarkerInst]); + uint64 instID = inst->getId(); + uint64 bcOffset = bc2LIRMapHandler->getVectorEntry(instID); + + if (bcOffset != ILLEGAL_VALUE) { + POINTER_SIZE_INT instStartAddr = (POINTER_SIZE_INT) inst->getCodeStartAddr(); + methInfo->addLocation(new(memoryManager) std::pair(instStartAddr, (uint16)bcOffset)); + } + } } - bool isExceptObjDead = !ls->isLive(catchInst->getOpnd(0)); - - void * handlerAddr=handler->getCodeStartAddr(); - ObjectType * exceptionType = (ObjectType*)((CatchEdge*)edge)->getType(); - exceptionHandlerInfos.push_back( - ExceptionHandlerInfo(regionStart, regionEnd, handlerAddr, exceptionType, isExceptObjDead) - ); - }else{ - if (head->hasKind(Node::Kind_DispatchNode)) - registerExceptionRegion(regionStart, regionEnd, (DispatchNode*)head); } } + + const Edges& edges=node->getEdges(isForward); + Edges::const_reverse_iterator edge_riter; + + for(edge_riter = edges.rbegin(); edge_riter != edges.rend(); ++edge_riter) { + Edge* e = *edge_riter; + Node* targetNode = e->getNode(isForward); + if ( traversalInfo[targetNode->getId()] !=0) { + //back-edge(gray) if == 1 or cross-edge or direct-edge (black) if ==2 + continue; + } + orderNodesAndMarkInlinees(inlineStack, targetNode, isForward); + } + traversalInfo[nodeId] = 2;//mark node black + + // postprocess the node with reverse instruction order + if (node->getKind() == Node::Kind_Block) { + BasicBlock* bb = (BasicBlock*)node; + + for (Inst* inst = (Inst*)bb->getLastInst(); inst != NULL; inst = inst->getPrevInst()) { + if (inst->getKind() == Inst::Kind_MethodEndPseudoInst) { + MethodMarkerPseudoInst* methMarkerInst = (MethodMarkerPseudoInst*)inst; + inlineStack.push_back(entryExitMap[methMarkerInst]); + } else if (inst->getKind() == Inst::Kind_MethodEntryPseudoInst) { + //MethodMarkerPseudoInst* methMarkerInst = (MethodMarkerPseudoInst*)inst; + assert(((MethodMarkerPseudoInst*)inlineStack.back())->getMethodDesc() == ((MethodMarkerPseudoInst*)inst)->getMethodDesc()); + inlineStack.pop_back(); + } + } + } + +} + +void CodeEmitter::reportCompiledInlinees() { + StlList inlineList(memoryManager); + traversalInfo.resize(irManager->getFlowGraph()->getMaxNodeId() + 1, 0); + bool isForward = true; + orderNodesAndMarkInlinees(inlineList, irManager->getFlowGraph()->getEntryNode(), isForward); + + StlMap::const_iterator i, + itEnd = methodLocationMap.end(); + //std::cout << " * Method: " << irManager.getMethodDesc().getName() << std::endl; + for (i = methodLocationMap.begin(); i != itEnd; i++) { + MethodMarkerPseudoInst* metEntryInst = (MethodMarkerPseudoInst*)i->first; + CompiledMethodInfo* methInfo = (CompiledMethodInfo*)i->second; + AddrLocation* addrLocationMap = new(memoryManager) AddrLocation[methInfo->locationList.size()]; + + StlList* >::const_iterator lit, + litEnd = methInfo->locationList.end(); + int j = 0; + for (lit = methInfo->locationList.begin(); lit != litEnd; lit++) { + addrLocationMap[j].start_addr = (void*)(*lit)->first; + addrLocationMap[j].location = (*lit)->second; + } + irManager->getCompilationInterface().sendCompiledMethodLoadEvent(metEntryInst->getMethodDesc(), + methInfo->codeSize, methInfo->codeAddr, (uint32)methInfo->locationList.size(), + addrLocationMap, NULL); + } } }}; // ~Jitrino::Ia32 + + diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.h vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.h deleted file mode 100644 index abc8ffb..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeEmitter.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Vyacheslav P. Shakin - * @version $Revision: 1.8.22.3 $ - */ - -#ifndef _IA32_CODEEMITTER_H_ -#define _IA32_CODEEMITTER_H_ - -#include "Ia32IRManager.h" -#include "CGSupport.h" -namespace Jitrino -{ -namespace Ia32{ - -//======================================================================================== -// class CodeEmitter -//======================================================================================== -/** - class CodeEmitter - -*/ -BEGIN_DECLARE_IRTRANSFORMER(CodeEmitter, "emitter", "Code emitter") - - CodeEmitter(IRManager & irm, const char * params=0) - :IRTransformer(irm), memoryManager(0x1000, "CodeEmitter"), - exceptionHandlerInfos(memoryManager), constantAreaLayout(irManager, memoryManager) - { - if (irManager.getCompilationInterface().isBCMapInfoRequired()) { - MethodDesc* meth = irManager.getCompilationInterface().getMethodToCompile(); - bc2LIRMapHandler = new(memoryManager) VectorHandler(bcOffset2LIRHandlerName, meth); - } - } - - - CompilationInterface::CodeBlockHeat getCodeSectionHeat(uint32 sectionID)const; - -protected: - uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo; } - uint32 getSideEffects()const{ return 0; } - - void runImpl(); - bool verify(bool force=false); - - //------------------------------------------------------------------------------------ - void emitCode(); - void registerExceptionHandlers(); - void registerExceptionRegion(void * regionStart, void * regionEnd, DispatchNode * regionDispatchNode); - void postPass(); - void registerDirectCall(Inst * inst); - void registerInlineInfoOffsets( void ); - - - //------------------------------------------------------------------------------------ - class ConstantAreaLayout - { - public: - ConstantAreaLayout(IRManager& irm, MemoryManager& mm) - :irManager(irm), memoryManager(mm), items(memoryManager){}; - - void collectItems(); - void calculateItemOffsets(); - void doLayout(); - void finalizeSwitchTables(); - - protected: - IRManager& irManager; - MemoryManager& memoryManager; - StlVector items; - - uint32 dataSize; - - const static uint32 blockAlignment=16; - private: - - }; - - - //------------------------------------------------------------------------------------ - struct ExceptionHandlerInfo - { - void * regionStart; - void * regionEnd; - void * handlerAddr; - ObjectType * exceptionType; - bool exceptionObjectIsDead; - - ExceptionHandlerInfo( - void * _regionStart, - void * _regionEnd, - void * _handlerAddr, - ObjectType * _exceptionType, - bool _exceptionObjectIsDead=false - ): - regionStart(_regionStart), - regionEnd(_regionEnd), - handlerAddr(_handlerAddr), - exceptionType(_exceptionType), - exceptionObjectIsDead(_exceptionObjectIsDead){} - - }; - - // bc to native map stuff - VectorHandler* bc2LIRMapHandler; - - MemoryManager memoryManager; - StlVector exceptionHandlerInfos; - ConstantAreaLayout constantAreaLayout; - -END_DECLARE_IRTRANSFORMER(CodeEmitter) - -}; // namespace Ia32 -} -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.cpp vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.cpp index 279d299..6d3cd09 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.cpp @@ -28,526 +28,97 @@ #include "Log.h" #include "Ia32IRManager.h" #include "Ia32Printer.h" -#include "Ia32DCE.h" -#include "Ia32RCE.h" -#include "Ia32ComplexAddrFormLoader.h" -#include "Ia32CodeLayout.h" -#include "Ia32ConstraintsResolver.h" -#include "Ia32RegAlloc2.h" -#include "Ia32SpillGen.h" -#include "Ia32CopyExpansion.h" -#include "Ia32CodeEmitter.h" -#include "Ia32StackLayout.h" -#include "Ia32GCMap.h" -#include "Ia32I8Lowerer.h" -#include "Ia32InternalTrace.h" -#include "Ia32GCSafePoints.h" -#include "Ia32RCE.h" -#include "CGSupport.h" -#include "Ia32InternalProfiler.h" -#include "Ia32BBPolling.h" +#ifdef PLATFORM_POSIX + #include + #include + #include +#endif //PLATFORM_POSIX + namespace Jitrino { -namespace Ia32{ +namespace Ia32 +{ //___________________________________________________________________________________________________ void _cdecl die(uint32 retCode, const char * message, ...) { - ::std::cerr<<"---------- die called (ret code = "<selectCode(codeSelector); - printIRDumpEnd("hir2lir.log"); - } - uint32 getNeedInfo()const{ return 0; } -END_DECLARE_IRTRANSFORMER(CodeSelector) - -//___________________________________________________________________________________________________ -BEGIN_DECLARE_IRTRANSFORMER(InstructionFormTranslator, "native", "Translation to native form") - IRTRANSFORMER_CONSTRUCTOR(InstructionFormTranslator) - void runImpl(){ irManager.translateToNativeForm(); } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } -END_DECLARE_IRTRANSFORMER(InstructionFormTranslator) - -//___________________________________________________________________________________________________ -BEGIN_DECLARE_IRTRANSFORMER(UserRequestedDie, "die", "User requested run time termination") - IRTRANSFORMER_CONSTRUCTOR(UserRequestedDie) - void runImpl(){ die(10, parameters); } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - bool isIRDumpEnabled(){ return false; } -END_DECLARE_IRTRANSFORMER(UserRequestedDie) - -//___________________________________________________________________________________________________ -BEGIN_DECLARE_IRTRANSFORMER(UserRequestedReturnFalse, "false", "User requested rejection of code generation (return false)") - IRTRANSFORMER_CONSTRUCTOR(UserRequestedReturnFalse) - void runImpl(){ } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - bool isIRDumpEnabled(){ return false; } -END_DECLARE_IRTRANSFORMER(UserRequestedReturnFalse) - -//___________________________________________________________________________________________________ -BEGIN_DECLARE_IRTRANSFORMER(UserRequestedBreakPoint, "break", "User requested break point at beginning of each method") - IRTRANSFORMER_CONSTRUCTOR(UserRequestedBreakPoint) - void runImpl(){ - irManager.getPrologNode()->prependInsts(irManager.newInst(Mnemonic_INT3)); - } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - bool isIRDumpEnabled(){ return false; } -END_DECLARE_IRTRANSFORMER(UserRequestedBreakPoint) //___________________________________________________________________________________________________ - -BEGIN_DECLARE_IRTRANSFORMER(EarlyPropagation, "early_prop", "Early Propagation") - IRTRANSFORMER_CONSTRUCTOR(EarlyPropagation) - - struct OpndInfo - { - uint32 defCount; - Inst * sourceInst; - uint32 sourceOpndId; - uint32 sourceOpndDefCountAtCopy; - OpndInfo() - :defCount(0), sourceInst(NULL), sourceOpndId(EmptyUint32), sourceOpndDefCountAtCopy(0){} - }; - - void runImpl() - { - irManager.updateLoopInfo(); - uint32 opndCount=irManager.getOpndCount(); - - MemoryManager mm(0x100 + sizeof(OpndInfo) * opndCount + sizeof(Opnd*) * opndCount, "early_prop"); - OpndInfo * opndInfos = new(mm) OpndInfo[opndCount]; - Node * currentLoopHeader = NULL; - - bool anyInstHandled=false; - - for (CFG::NodeIterator it(irManager, CFG::OrderType_Topological); it!=NULL; ++it){ - Node * node=it; - if (!node->hasKind(Node::Kind_BasicBlock)) - continue; - const Insts& insts = ((BasicBlock*)node)->getInsts(); - Node * loopHeader = node->isLoopHeader() ? node : node->getLoopHeader(); - if (currentLoopHeader != loopHeader){ - currentLoopHeader = loopHeader; - for (uint32 i = 0; i < opndCount; ++i) - if (opndInfos[i].sourceOpndId != EmptyUint32) - opndInfos[i].defCount++; - } - - for (Inst * inst = insts.getFirst(); inst != NULL; inst=insts.getNext(inst)){ - bool assignedOpndPropagated = false; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * opnd=inst->getOpnd(it); - uint32 roles=inst->getOpndRoles(it); - uint32 opndId = opnd->getId(); - OpndInfo& opndInfo = opndInfos[opndId]; - - if (roles & Inst::OpndRole_Def){ - ++opndInfo.defCount; - }else if (roles & Inst::OpndRole_Use){ - if (opndInfo.sourceOpndId != EmptyUint32){ - if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount) - opndInfo.sourceOpndId = EmptyUint32; - else{ - Opnd * srcOpnd = irManager.getOpnd(opndInfo.sourceOpndId); - Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location); - if (co.getKind() == OpndKind_Mem){ - if ((roles & Inst::OpndRole_Explicit) == 0 || - inst->hasKind(Inst::Kind_PseudoInst) || irManager.isGCSafePoint(inst) || - opndInfo.sourceInst != insts.getPrev(inst) || assignedOpndPropagated || - (inst->getConstraint(Inst::ConstraintKind_Weak, it, co.getSize())&co).isNull() - ) - opndInfo.sourceOpndId = EmptyUint32; - assignedOpndPropagated = true; - } - } - } - } - if (opndInfo.defCount > 1){ - opndInfo.sourceOpndId = EmptyUint32; - } - } - bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||( - (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && - inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0 - && inst->getOpnd(3)->getRuntimeInfo()==NULL - ); - - if (isCopy){ // CopyPseudoInst or mov - Opnd * defOpnd = inst->getOpnd(0); - Opnd * srcOpnd = inst->getOpnd(1); - uint32 defOpndId = defOpnd->getId(); - OpndInfo * opndInfo = opndInfos + defOpndId; - bool instHandled=false; - if (opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){ - if (!defOpnd->hasAssignedPhysicalLocation()){ - opndInfo->sourceInst = inst; - opndInfo->sourceOpndId = srcOpnd->getId(); - instHandled=true; - } - } - if (instHandled){ - if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32) - opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId; - opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount; - anyInstHandled=true; - } - } - } - } - - if (anyInstHandled){ - Opnd ** replacements = new(mm) Opnd* [opndCount]; - memset(replacements, 0, sizeof(Opnd*) * opndCount); - bool hasReplacements = false; - for (uint32 i = 0; i < opndCount; ++i){ - if (opndInfos[i].sourceOpndId != EmptyUint32){ - Inst * inst = opndInfos[i].sourceInst; - if (inst !=NULL){ - BasicBlock * bb = inst->getBasicBlock(); - if (bb != NULL) - bb->removeInst(inst); - } - if (opndInfos[i].sourceOpndId != i){ - replacements[i] = irManager.getOpnd(opndInfos[i].sourceOpndId); - hasReplacements = true; - } - } - } - - if (hasReplacements){ - for (CFG::NodeIterator it(irManager, CFG::OrderType_Topological); it!=NULL; ++it){ - Node * node=it; - if (!node->hasKind(Node::Kind_BasicBlock)) - continue; - const Insts& insts = ((BasicBlock*)node)->getInsts(); - for (Inst * inst = insts.getFirst(); inst != NULL; inst=insts.getNext(inst)){ - inst->replaceOpnds(replacements); - } - } - } - } - } - +class InstructionFormTranslator : public SessionAction { + void runImpl(){ irManager->translateToNativeForm(); } uint32 getNeedInfo()const{ return 0; } + uint32 getSideEffects()const{ return 0; } +}; -END_DECLARE_IRTRANSFORMER(EarlyPropagation) - - - -//================================================================================ -// class IRTransformerPath +static ActionFactory _native("native"); //___________________________________________________________________________________________________ -bool CodeGenerator::IRTransformerPath::parse(const char * str) -{ - steps.resize(0); - error=0; - while(*str){ - while (*str && *str<=' ') str++; - const char * p=parseTag(str); - if (error!=0) - return false; - if (p){ - str=p; - - while (*str && *str<=' ') str++; - p=parseSwitch(str, steps.back()); - if (error!=0) - return false; - if (p) - str=p; - - while (*str && *str<=' ') str++; - p=parseParams(str, steps.back()); - if (error!=0) - return false; - if (p) - str=p; - - }else - str++; - } - - IRManager::ConstCharStringToVoidPtrMap tagCounters(memoryManager); - - for (uint32 i=0; isecond; - steps[i].extentionIndex=counter; - tagCounters[tag]=(void*)(counter+1); - - } - - return true; -} - -//___________________________________________________________________________________________________ -bool CodeGenerator::IRTransformerPath::parseOption(const char * str, Step& result) -{ - error=0; - while (*str && *str<=' ') str++; - const char * p=parseSwitch(str, result, false); - if (error!=0) - return false; - if (p) - str=p; - - while (*str && *str<=' ') str++; - p=parseParams(str, result); - if (error!=0) - return false; - return true; -} - -//___________________________________________________________________________________________________ -const char * CodeGenerator::IRTransformerPath::parseTag(const char * str) -{ - char tag[IRTransformer::MaxTagLength+1]; - uint32 i=0; - for (; i _die("die"); //___________________________________________________________________________________________________ -const char * CodeGenerator::IRTransformerPath::parseSwitch(const char * str, Step& step, bool startsWithColon) -{ - if (*str==0) - return NULL; - if (startsWithColon){ - if (*str!=':') - return NULL; - str++; - } - char sw[IRTransformer::MaxTagLength+1]; - uint32 i=0; - for (; igetFlowGraph()->getEntryNode()->prependInst(irManager->newInst(Mnemonic_INT3)); + } + uint32 getNeedInfo()const{ return 0; } + uint32 getSideEffects()const{ return 0; } + bool isIRDumpEnabled(){ return false; } +}; -//___________________________________________________________________________________________________ -const char * CodeGenerator::IRTransformerPath::parseParams(const char * str, Step& step) -{ - if (*str==0 || *str!='{') - return NULL; - str++; - const char * start=str; - while (*str && *str!='}') str++; - if (*str!='}') - return NULL; - step.parameters=newString(memoryManager, start, str-start); - return ++str; -} +static ActionFactory _break("break"); -//___________________________________________________________________________________________________ -void CodeGenerator::IRTransformerPath::readFlagsFromCommandLine(const JitrinoParameterTable *params) -{ - IRManager::ConstCharStringToVoidPtrMap tagCounters(memoryManager); - for (uint32 i=0; ilookup(pname); - if (value==NULL){ - strcat(pname, "-"); - sprintf(pname+strlen(pname), "%d", (int)steps[i].extentionIndex); - value=params->lookup(pname); - } - if (value!=NULL){ - Step step(tag); - if (!parseOption(value, step)) - die(1, "Cannot parse option %s=%s", pname, value); - if (steps[i].tagSwitch!=Step::Switch_AlwaysOn && step.tagSwitch!=Step::Switch_AlwaysOn) - steps[i].tagSwitch=step.tagSwitch; - if (step.parameters) - steps[i].parameters=step.parameters; - } - } -} //================================================================================ // class CodeGenerator //================================================================================ //___________________________________________________________________________________________________ -CodeGenerator::CodeGenerator(MemoryManager &mm, CompilationInterface& compInterface) - : methodMemManager(mm), compilationInterface(compInterface), - typeManager(compInterface.getTypeManager()), - irTransformerPath(mm), - irManager(mm,typeManager,*compInterface.getMethodToCompile(),compInterface), - instrMap(NULL) -{ -} - - -//___________________________________________________________________________________________________ -// Command line flag processing - -Timer * CodeGenerator::paramsTimer=NULL; - -const char * CodeGenerator::defaultPathString="selector,bbp:on{6},gcpoints,cafl:on{4},dce:on{1},i8l,early_prop:on,itrace:off," -"native,opco:off{1},constraints,dce:on," - "bp_regalloc:on{EAX|ECX|EDX|EBX|ESI|EDI|EBP}," - "bp_regalloc:on{XMM0|XMM1|XMM2|XMM3|XMM4|XMM5|XMM6|XMM7}," - "spillgen," - "layout,copy,rce:on,stack,break:off,iprof:off,emitter,si_insts,gcmap,info"; - -//___________________________________________________________________________________________________ -void CodeGenerator::readFlagsFromCommandLine(const CompilationContext* context) -{ - // just clear this way - CGFlags& flags = *context->getIa32CGFlags(); - JitrinoParameterTable* params = context->getThisParameterTable(); - flags.dumpdot = params->lookupBool("ia32::dumpdot", false); - flags.useOptLevel = params->lookupBool("ia32::useOptLevel",true); +void CodeGenerator::genCode(::Jitrino::SessionAction* sa, ::Jitrino::MethodCodeSelector& inputProvider) { + CompilationContext* cc = sa->getCompilationContext(); + CompilationInterface* ci = cc->getVMCompilationInterface(); + MemoryManager& mm = cc->getCompilationLevelMemoryManager(); + IRManager* irManager = new (mm) IRManager(mm,ci->getTypeManager(),*ci->getMethodToCompile(), *ci); #ifdef _DEBUG - flags.verificationLevel = params->lookupUint("ia32::verify",1); + irManager->setVerificationLevel(1); #else - flags.verificationLevel = params->lookupUint("ia32::verify",0); -#endif - -} - -//___________________________________________________________________________________________________ -// Help for command line flags - -void CodeGenerator::showFlagsFromCommandLine() { - - Log::out() << " ia32::dumpdot[={on|OFF}]" << ::std::endl; -} - -//___________________________________________________________________________________________________ -bool CodeGenerator::runIRTransformer(const char * tag, const char * params) -{ - assert(tag!=NULL); - if (stricmp(tag, "false")==0) - return false; - IRTransformer * tr=IRTransformer::newIRTransformer(tag, irManager, params); - assert(tr); - tr->run(); - tr->destroy(); - return true; -} - -//___________________________________________________________________________________________________ -const char * CodeGenerator::getDefaultIRTransformerPathName() -{ -/* VSH: current fast path is not fast, it increases compilation time for Eclipse startup ! -*/ - return "default"; -} - -//___________________________________________________________________________________________________ -bool CodeGenerator::createIRTransformerPath() -{ - PhaseTimer tm(paramsTimer, "ia32::params"); - const JitrinoParameterTable * methodParams=irManager.getCompilationContext()->getThisParameterTable(); - const char * pathString=methodParams->lookup("ia32::path"); - - if (pathString==NULL) - pathString=getDefaultIRTransformerPathName(); - - if (stricmp(pathString, "default")==0) - pathString=defaultPathString; - if (!irTransformerPath.parse(pathString)) - return false; - irTransformerPath.readFlagsFromCommandLine(methodParams); - return true; -} - -//___________________________________________________________________________________________________ -bool CodeGenerator::runIRTransformerPath() -{ - const StlVector steps=irTransformerPath.getSteps(); - bool seenEmitter=false; - for (uint32 i=0; iverificationLevel); - irManager.setInfo("methodCodeSelector", &inputProvider); - if (!createIRTransformerPath()) - die(1, "Cannot parse IRTransformer path"); - // add bc <-> HIR code map handler - MemoryManager& ir_mmgr = irManager.getMemoryManager(); - StlVector *lirMap; - MethodDesc* meth = irManager.getCompilationInterface().getMethodToCompile(); - - if (compilationInterface.isBCMapInfoRequired()) { - lirMap = new(ir_mmgr) StlVector (ir_mmgr, meth->getByteCodeSize() - * (ESTIMATED_HIR_SIZE_PER_BYTECODE - 1) * ESTIMATED_LIR_SIZE_PER_HIR + 5 ); + irManager->setVerificationLevel(0); +#endif + cc->setLIRManager(irManager); + + MethodDesc* meth = ci->getMethodToCompile(); + if (ci->isBCMapInfoRequired()) { + StlVector* lirMap = new(mm) StlVector (mm, + (size_t) getVectorSize(bcOffset2HIRHandlerName, meth) * + ESTIMATED_LIR_SIZE_PER_HIR + 5, ILLEGAL_VALUE); addContainerHandler(lirMap, bcOffset2LIRHandlerName, meth); } - result = runIRTransformerPath(); + bool slowLdString = sa->getBoolArg("SlowLdString", false); + MemoryManager codeSelectorMemManager(1024, "CodeGenerator::selectCode.codeSelectorMemManager"); + MethodCodeSelector codeSelector(*ci, mm, codeSelectorMemManager, *irManager, slowLdString); - if (compilationInterface.isBCMapInfoRequired()) { - removeContainerHandler(bcOffset2LIRHandlerName, meth); - } - - return result; + inputProvider.selectCode(codeSelector); } - }}; // namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.h vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.h index 3661180..39437f9 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.h +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeGenerator.h @@ -22,10 +22,9 @@ #ifndef _IA32_CODE_GENERATOR_ #define _IA32_CODE_GENERATOR_ #include "CodeGenIntfc.h" -#include "PropertyTable.h" -#include "Ia32CFG.h" #include "Ia32IRManager.h" -#include "Timer.h" +#include "Ia32CodeGeneratorFlags.h" + namespace Jitrino { namespace Ia32{ @@ -33,39 +32,8 @@ namespace Ia32{ //======================================================================================================== class MethodSplitter; -// -// Optimization levels -// -enum OptLevel { - OptLevel_Low, - OptLevel_High -}; - - - //----------------------------------------------------------------------------------- - /** struct Flags is a bit set defining various options controling - the Ia32 code generator - - These flags can be set directly in the code of from the VM command line - if VM supports this - */ -struct CGFlags { - CGFlags () { - dumpdot = false; - useOptLevel = true; - earlyDCEOn = false; - verificationLevel = 1; - } - - bool dumpdot : 1; - bool useOptLevel : 1;// Use fast compilation for first compile - bool earlyDCEOn : 1; - uint32 verificationLevel : 2; - - }; - //======================================================================================================== // class CodeGenerator -- main class for IA32 back end //======================================================================================================== @@ -78,97 +46,11 @@ class CodeGenerator : public ::Jitrino:: public: //----------------------------------------------------------------------------------- - CodeGenerator(MemoryManager &mm, CompilationInterface& compInterface); - + CodeGenerator(){}; + virtual ~CodeGenerator() {} - - bool genCode(MethodCodeSelector& inputProvider); - - bool runIRTransformer(const char * tag, const char * params=0); - - static void readFlagsFromCommandLine(const CompilationContext* context); - static void showFlagsFromCommandLine(); - - OptLevel getOptLevel() { return optLevel; } - void setOptLevel(OptLevel o) { optLevel = o; } - - - //-------------------------------------------------------------- - class IRTransformerPath - { - public: - struct Step - { - enum Switch - { - Switch_Off=0, - Switch_On=1, - Switch_AlwaysOn=11 - }; - - - const char * tag; - const char * parameters; - Switch tagSwitch; - uint32 extentionIndex; - - Step() - :tag(NULL), parameters(NULL), tagSwitch(Switch_AlwaysOn), extentionIndex(0){} - - Step(const char * _tag) - :tag(_tag), parameters(NULL), tagSwitch(Switch_AlwaysOn), extentionIndex(0) - { assert(tag!=NULL&&tag[0]!=0); } - - }; - - IRTransformerPath(MemoryManager& mm) - :memoryManager(mm), steps(mm), error(0) - {} - - bool parse(const char * str); - - bool parseOption(const char * str, Step& result); - - void readFlagsFromCommandLine(const JitrinoParameterTable *params); - - const StlVector& getSteps()const - { return steps; } - - protected: - const char * parseTag(const char * str); - const char * parseSwitch(const char * str, Step& step, bool startsWithColon=true); - const char * parseParams(const char * str, Step& step); - - MemoryManager& memoryManager; - StlVector steps; - - uint32 error; - - }; - - //-------------------------------------------------------------- -protected: - bool runIRTransformerPath(); - bool createIRTransformerPath(); - const char * getDefaultIRTransformerPathName(); - - //-------------------------------------------------------------- -private: - MemoryManager& methodMemManager; - CompilationInterface& compilationInterface; - TypeManager& typeManager; - - IRTransformerPath irTransformerPath; - - IRManager irManager; - - void * instrMap; - OptLevel optLevel; - - static const char * defaultPathString; - static const char * fastPathString; - static Timer * paramsTimer; + virtual void genCode(::Jitrino::SessionAction* sa, ::Jitrino::MethodCodeSelector&); }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeGeneratorFlags.h vm/jitrino/src/codegenerator/ia32/Ia32CodeGeneratorFlags.h new file mode 100644 index 0000000..9c02dc7 --- /dev/null +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeGeneratorFlags.h @@ -0,0 +1,42 @@ +/* +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Vyacheslav P. Shakin +* @version $Revision$ +*/ + +#ifndef _IA32_CODE_GENERATORFLAGS_ +#define _IA32_CODE_GENERATORFLAGS_ + +namespace Jitrino +{ + namespace Ia32{ + +//----------------------------------------------------------------------------------- +/** struct Flags is a bit set defining various options controling +the Ia32 code generator + +These flags can be set directly in the code of from the VM command line +if VM supports this +*/ +struct CGFlags { + CGFlags () { + earlyDCEOn = false; + } + bool earlyDCEOn; +}; +}} //namespace +#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeLayout.cpp vm/jitrino/src/codegenerator/ia32/Ia32CodeLayout.cpp index d5fa68e..fdba86f 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeLayout.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeLayout.cpp @@ -28,65 +28,86 @@ namespace Jitrino { namespace Ia32 { -#define ACCEPTABLE_DOUBLE_PRECISION_LOSS 0.000000000001 +static ActionFactory _layout("layout"); + +#define ACCEPTABLE_DOUBLE_PRECISION_LOSS 0.000000001 Linearizer::Linearizer(IRManager* irMgr) : irManager(irMgr) { } -/** Fix branches to work with the code layout */ -void Linearizer::fixBranches() { - const Nodes& nodes = irManager->getNodes(); - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { - fixBranches((BasicBlock*)node); +static Edge* findEdgeToAddJump(BasicBlock* block) { + Inst* lastInst = (Inst*)block->getLastInst(); + BasicBlock* layoutSuccessor = block->getLayoutSucc(); + if (lastInst && lastInst->hasKind(Inst::Kind_BranchInst)) { + BranchInst* br = (BranchInst*)lastInst; + if (br->isDirect() && br->getFalseTarget() != layoutSuccessor) { + return block->getFalseEdge(); } + return NULL; + } + if (lastInst && lastInst->hasKind(Inst::Kind_ControlTransferInst) && !lastInst->hasKind(Inst::Kind_CallInst)) { + //unconditional jumps (jump inst, ret, switch) + return NULL; + } + + if (block->getOutDegree() == 1 && block->getExceptionEdge()!=NULL) { + return NULL; //throw } + + Edge* uncondEdge = block->getUnconditionalEdge(); + assert(uncondEdge); + return uncondEdge->getTargetNode() == layoutSuccessor ? NULL : uncondEdge; } -void Linearizer::fixBranches(BasicBlock* block) { - BasicBlock* succBlock = block->getLayoutSucc(); - // If block ends with branch to its layout successor reverse - // the branch to fallthrough to the layout successor - if (!block->isEmpty()) { - Inst * lastInst = block->getInsts().getLast(); - if (lastInst->hasKind(Inst::Kind_BranchInst)) { - BranchInst* bInst = ((BranchInst *)lastInst); - if (bInst->isDirect()) { - BasicBlock* target =bInst->getDirectBranchTarget(); - if (target == succBlock) { - reverseBranchIfPossible(block); + +/** Fix branches to work with the code layout */ +void Linearizer::fixBranches() { + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + BasicBlock* block = (BasicBlock*)node; + BasicBlock* layoutSuccessor = block->getLayoutSucc(); + + // If block ends with true branch to its layout successor reverse + // the branch to fallthrough to the layout successor + Inst * lastInst = (Inst*)block->getLastInst(); + if (lastInst!=NULL && lastInst->hasKind(Inst::Kind_BranchInst)) { + BranchInst* bInst = (BranchInst *)lastInst; + if (bInst->isDirect()) { + Node * target = bInst->getTrueTarget(); + if (target == layoutSuccessor) { + reverseBranchIfPossible(block); + } } } + + //check for every out edge that additional jump block is needed + Edge* edge = findEdgeToAddJump(block); + if (edge!=NULL) { + BasicBlock * jmpBlk = addJumpBlock(edge); + // Put jump block after the block in code layout + jmpBlk->setLayoutSucc(layoutSuccessor); + block->setLayoutSucc(jmpBlk); + } } } - - // If block's fallthrough successor is not its layout successor - // add new block with a jump - Edge * fallEdge = block->getFallThroughEdge(); - if (fallEdge != NULL && fallEdge->getNode(Direction_Head) != succBlock) { - BasicBlock * jmpBlk = addJumpBlock(fallEdge); - // Put jump block after the block in code layout - jmpBlk->setLayoutSucc(succBlock); - block->setLayoutSucc(jmpBlk); - } } - /** Reverse branch predicate. We assume that branch is the last instruction in the node. */ -bool Linearizer::reverseBranchIfPossible(BasicBlock * bb) { +bool Linearizer::reverseBranchIfPossible(Node * bb) { // Last instruction of the basic block should be predicated branch: // (p1) br N // Find p2 in (p1,p2) or (p2,p1) produced by the compare. - assert(!bb->isEmpty() && bb->getInsts().getLast()->hasKind(Inst::Kind_BranchInst)); - BranchInst * branch = (BranchInst *)bb->getInsts().getLast(); + assert(bb->isBlockNode() && !bb->isEmpty() && ((Inst*)bb->getLastInst())->hasKind(Inst::Kind_BranchInst)); + BranchInst * branch = (BranchInst *)bb->getLastInst(); assert(branch->isDirect()); - Edge* edge = bb->getDirectBranchEdge(); + Edge* edge = bb->getTrueEdge(); if (canEdgeBeMadeToFallThrough(edge)) { branch->reverse(irManager); } @@ -97,52 +118,11 @@ bool Linearizer::reverseBranchIfPossible /** Add block containing jump instruction to the fallthrough successor * after this block */ -BasicBlock * Linearizer::addJumpBlock(Edge * fallEdge) { - // Create basic block for jump inst and add this block to the CFG - Node* block = fallEdge->getNode(Direction_Tail); - Node* targetNode= fallEdge->getNode(Direction_Head); - assert(targetNode->hasKind(Node::Kind_BasicBlock)); - bool loopInfoIsValidOnStart = irManager->isLoopInfoValid(); - Node* loopHeader = loopInfoIsValidOnStart ? (targetNode->isLoopHeader()? targetNode : targetNode->getLoopHeader()):NULL;//cache in advance - bool livenessInfoIsValidOnStart = irManager->hasLivenessInfo(); - BasicBlock* targetBlock = (BasicBlock*)targetNode; - BasicBlock* jumpBlock = irManager->newBasicBlock(fallEdge->getProbability() * block->getExecCnt()); - jumpBlock->setPersistentId(targetBlock->getPersistentId()); - - // Add jump instruction to the created block - BranchInst * jumpInst = irManager->newBranchInst(Mnemonic_JMP); - jumpBlock->appendInsts(jumpInst); - irManager->newDirectBranchEdge(jumpBlock, targetBlock, 1.0); - - // Retarget head of fallthrough edge to the jumpBlock - irManager->retargetEdge(Direction_Head, fallEdge, jumpBlock); - - // now fix liveness and loop infos - if (livenessInfoIsValidOnStart) { //fixing liveness info - assert(jumpInst->getOpndCount() == 1); - uint32 nOpnds = irManager->getOpndCount(); -#ifdef _DEBUG - Opnd* opnd = jumpInst->getOpnd(0); - assert(opnd->getId() == nOpnds - 1); -#endif - const Nodes& nodes = irManager->getNodes(); - for (Nodes::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - Node* node = *it; - LiveSet* liveSet = irManager->getLiveAtEntry(node); - assert(node == jumpBlock || liveSet->getSetSize() == nOpnds - 1); - liveSet->resize(nOpnds); //fills new opnd info with 0 - } - LiveSet* jumpBlockLiveness = irManager->getLiveAtEntry(jumpBlock); - irManager->getLiveAtExit(jumpBlock, *jumpBlockLiveness); // get liveness from child nodes - irManager->updateLiveness(jumpInst, *irManager->getLiveAtEntry(jumpBlock)); // and add local info to it - assert(irManager->ensureLivenessInfoIsValid()); - } - - if (loopInfoIsValidOnStart) { //fixing loop info if needed - jumpBlock->setLoopInfo(false, loopHeader); - irManager->forceLoopInfoIsValid(); - } - return jumpBlock; +BasicBlock* Linearizer::addJumpBlock(Edge * fallEdge) { + irManager->invalidateLivenessInfo(); + Inst* jumpInst = irManager->newJumpInst(); + Node* jumpBlock = irManager->getFlowGraph()->spliceBlockOnEdge(fallEdge, jumpInst); + return (BasicBlock*)jumpBlock; } @@ -150,27 +130,27 @@ #endif // Returns true if edge can be converted to a fall-through edge (i.e. an edge // not requiring a branch) assuming the edge's head block is laid out after the tail block. bool Linearizer::canEdgeBeMadeToFallThrough(Edge *edge) { - BranchInst *br = edge->getBranch(); - if (br == NULL) { - return TRUE; - } - return br->canReverse(); + assert(edge->isTrueEdge()); + Inst *br = (Inst*)edge->getSourceNode()->getLastInst(); + assert(br!=NULL); + assert(br->hasKind(Inst::Kind_BranchInst)); + return ((BranchInst*)br)->canReverse(); } bool Linearizer::isBlockLayoutDone() { - bool lastBlockFound = FALSE; - const Nodes& nodes = irManager->getNodes(); + bool lastBlockFound = false; + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (!node->hasKind(Node::Kind_BasicBlock)) { + if (!node->isBlockNode()) { continue; } BasicBlock* block = (BasicBlock*)node; if (block->getLayoutSucc()==NULL) { if (lastBlockFound) { - return FALSE; //two blocks without layout successor found + return false; //two blocks without layout successor found } - lastBlockFound = TRUE; + lastBlockFound = true; } } return lastBlockFound; @@ -183,12 +163,13 @@ #ifdef _DEBUG #endif linearizeCfgImpl(); + + fixBranches(); assert(isBlockLayoutDone()); - irManager->setIsLaidOut(); + irManager->setLaidOut(true); #ifdef _DEBUG - assert(hasValidLayout(irManager)); - assert(hasValidFallthroughEdges(irManager)); + checkLayout(irManager); if (livenessIsOkOnStart) { assert(irManager->ensureLivenessInfoIsValid()); } @@ -210,160 +191,118 @@ void Linearizer::doLayout(LinearizerType } } -bool Linearizer::hasValidLayout(IRManager* irm) { - uint32 maxNodes = irm->getMaxNodeId(); - StlVector numVisits(irm->getMemoryManager(), maxNodes); - StlVector isBB(irm->getMemoryManager(), maxNodes); - uint32 i; - - for (i = 0; i < maxNodes; i++) { - numVisits[i] = 0; - isBB[i] = FALSE; - } - // Find basic blocks - bool foundExit = FALSE; - const Nodes& nodes = irm->getNodes(); +void Linearizer::checkLayout(IRManager* irm) { +#ifdef _DEBUG + uint32 maxNodes = irm->getFlowGraph()->getMaxNodeId(); + StlVector numVisits(irm->getMemoryManager(), maxNodes, 0); + StlVector isBB(irm->getMemoryManager(), maxNodes, false); + + // Find basic blocks + bool wasLast = false; + const Nodes& nodes = irm->getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node *node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { - isBB[node->getId()] = TRUE; + if (node->isBlockNode()) { + isBB[node->getId()] = true; BasicBlock* layoutSucc =((BasicBlock*)node)->getLayoutSucc(); if (layoutSucc==NULL ) { - if (foundExit) { - if (Log::cat_cg()->isWarnEnabled()) { - Log::out() << "two blocks without layout successor\n"; - } - return FALSE; - } else { - foundExit = TRUE; - } + assert(!wasLast); + wasLast = true; } else { uint32 id = layoutSucc->getId(); numVisits[id]++; - if (numVisits[id] > 1) { - return FALSE; - } + assert(numVisits[id] == 1); } } } - // Check that every basic block has been visited once - bool foundEntry = FALSE; - for (i = 0; i < maxNodes; i++) { + // Check that every basic block has been visited once + bool wasFirst = false; + for (uint32 i = 0; i < maxNodes; i++) { uint32 correctNumVisits = isBB[i] ? 1 : 0; if (numVisits[i] != correctNumVisits) { - if (isBB[i] && numVisits[i] == 0 && !foundEntry) { - foundEntry = TRUE; + if (isBB[i] && numVisits[i] == 0 && !wasFirst) { + wasFirst = true; } else { - if (Log::cat_cg()->isWarnEnabled()) { - Log::out() << "numVisits[" << (int) i << "] = "; - Log::out() << (int) numVisits[i]; - Log::out() << " expected " << (int) correctNumVisits << ::std::endl; - } - return FALSE; + assert(0); } } } - return TRUE; -} -bool Linearizer::hasValidFallthroughEdges(IRManager* irm) { - const Nodes& nodes = irm->getNodes(); + //check fallthru successors for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node *node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { + if (node->isBlockNode()) { BasicBlock* block = (BasicBlock*)node; - Edge * fallEdge = block->getFallThroughEdge(); - if (fallEdge != NULL && fallEdge->getNode(Direction_Head) != block->getLayoutSucc()) { - return FALSE; + BasicBlock* layoutSucc = block->getLayoutSucc(); + Edge* fallEdge = layoutSucc==NULL ? NULL : block->findEdgeTo(true, layoutSucc); + if (fallEdge == NULL) { + Inst *inst = (Inst*)block->getLastInst(); + assert(!inst->hasKind(Inst::Kind_BranchInst)); //false edge must be fallthru + bool ok = inst->hasKind(Inst::Kind_ControlTransferInst) && !inst->hasKind(Inst::Kind_CallInst); + ok = ok || (block->getOutDegree() == 1 && block->getExceptionEdge() != NULL); + assert(ok); + } else { + assert(fallEdge->isUnconditionalEdge() || fallEdge->isFalseEdge()); } - } + } } - return TRUE; + +#endif } -void Linearizer::ensureProfileIsValid() const { - const Nodes& nodes = irManager->getNodes(); - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - const Edges& inEdges = node->getEdges(Direction_In); -#ifdef _DEBUG - double myFreq = node->getExecCnt(); - assert(myFreq>0); -#endif - - - if (node!=irManager->getPrologNode()) { // checking in-edges, sum freq=myFreq - double inFreq = 0; - for (Edge *e = inEdges.getFirst(); e; e = inEdges.getNext(e)) { - Node* fromNode = e->getNode(Direction_Tail); - double edgeProb = e->getProbability(); - double dfreq = edgeProb * fromNode->getExecCnt(); - inFreq+=dfreq; - } - assert ((double(abs(int(myFreq - inFreq))) / myFreq) < ACCEPTABLE_DOUBLE_PRECISION_LOSS); - } - - if (node!=irManager->getExitNode()) { //checking out edges -> sum prob == 100% - const Edges& outEdges = node->getEdges(Direction_Out); - double prob = 0.0; - for (Edge *e = outEdges.getFirst(); e; e = outEdges.getNext(e)) { - double dprob = e->getProbability(); - prob+=dprob; - } - assert ((double(abs(int(1 - prob)))) < ACCEPTABLE_DOUBLE_PRECISION_LOSS); - } - } -} ///////////////////////////////////////////////////////////////////// /////////////////// TOPOLOGICAL LAYOUT ////////////////////////////// void TopologicalLayout::linearizeCfgImpl() { BasicBlock* prev = NULL; - CFG::NodeIterator it(*irManager, CFG::OrderType_Topological); - for (; it.getNode()!=NULL; ++it) { - Node* node = it.getNode(); - if (!node->hasKind(Node::Kind_BasicBlock)) { + const Nodes& postOrderedNodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrderedNodes.rbegin(), end = postOrderedNodes.rend(); it!=end; ++it) { + Node* node = *it; + if (!node->isBlockNode()) { continue; } BasicBlock* block = (BasicBlock*)node; if (prev!= NULL) { prev->setLayoutSucc(block); } else { - assert(block == irManager->getPrologNode()); + assert(block == irManager->getFlowGraph()->getEntryNode()); } prev=block; } - fixBranches(); } ////////////////////////////////////////////////////////////////////////// ///////////////////IRTransformer impl //////////////////////////////////// void Layouter::runImpl() { - const char* params = getParameters(); - Linearizer::LinearizerType type = irManager.hasEdgeProfile() ? Linearizer::BOTTOM_UP : Linearizer::TOPOLOGICAL; + const char* params = getArg("type"); + ControlFlowGraph* fg = irManager->getFlowGraph(); + bool hasEdgeProfile = fg->hasEdgeProfile(); + bool isClinit = irManager->getMethodDesc().isClassInitializer(); + Linearizer::LinearizerType type = hasEdgeProfile && !isClinit ? Linearizer::BOTTOM_UP : Linearizer::TOPOLOGICAL; if (params != NULL) { if (!strcmp(params, "bottomup")) { type = Linearizer::BOTTOM_UP; } else if (!strcmp(params, "topdown")) { type = Linearizer::TOPDOWN; } else if (!strcmp(params, "mixed")) { - type = irManager.hasLoops() ? Linearizer::BOTTOM_UP : Linearizer::TOPDOWN; + LoopTree* lt = fg->getLoopTree(); + type = lt->hasLoops() ? Linearizer::BOTTOM_UP : Linearizer::TOPDOWN; } else if (!strcmp(params, "topological")) { type = Linearizer::TOPOLOGICAL; } else { - if (Log::cat_cg()->isWarnEnabled()) { + if (Log::isEnabled()) { Log::out() << "Layout: unsupported layout type: '"<isWarnEnabled()) { + if (Log::isEnabled()) { Log::out() << "Layout: not edge profile found: '"<getMaxNodeId(), "Ia32::bottomUpLayout"), -firstInChain(mm,irManager->getMaxNodeId(), false), -lastInChain(mm,irManager->getMaxNodeId(), false), -prevInLayoutBySuccessorId(mm, irManager->getMaxNodeId(), NULL) +mm(40*irm->getFlowGraph()->getNodeCount(), "Ia32::bottomUpLayout"), +firstInChain(mm, irm->getFlowGraph()->getNodeCount(), false), +lastInChain(mm, irm->getFlowGraph()->getNodeCount(), false), +prevInLayoutBySuccessorId(mm, irm->getFlowGraph()->getNodeCount(), NULL) { } struct edge_comparator { bool operator() (const Edge* e1, const Edge* e2) const { //true -> e1 is first - ExecCntValue v1 = getEdgeExecCount(e1); - ExecCntValue v2 = getEdgeExecCount(e2); + double v1 = getEdgeExecCount(e1); + double v2 = getEdgeExecCount(e2); return v1 > v2 ? true : (v1 < v2 ? false: e1 < e2); } - static ExecCntValue getEdgeExecCount(const Edge* e) { - return e->getNode(Direction_Tail)->getExecCnt() * e->getProbability(); + static double getEdgeExecCount(const Edge* e) { + return e->getSourceNode()->getExecCount() * e->getEdgeProb(); } }; void BottomUpLayout::linearizeCfgImpl() { - irManager->updateExecCounts(); -#ifdef _DEBUG - ensureProfileIsValid(); -#endif + assert(irManager->getFlowGraph()->isEdgeProfileConsistent()); StlVector sortedEdges(mm); - const Nodes& nodes = irManager->getNodes(); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); sortedEdges.reserve(nodes.size() * 3); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - const Edges& edges = node->getEdges(Direction_Out); - for (Edge *e = edges.getFirst(); e; e = edges.getNext(e)) { - sortedEdges.push_back(e); - } + const Edges& edges = node->getOutEdges(); + sortedEdges.insert(sortedEdges.end(), edges.begin(), edges.end()); } std::sort(sortedEdges.begin(), sortedEdges.end(), edge_comparator()); for(StlVector::const_iterator it = sortedEdges.begin(), itEnd = sortedEdges.end(); it!=itEnd; it++) { @@ -76,25 +71,24 @@ #endif //these blocks are dispatch successors or are blocks connected by in/out edges to already laid out chains for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { + if (node->isBlockNode()) { BasicBlock* block = (BasicBlock*)node; - if (block->getLayoutSucc() == NULL && !lastInChain[block->getId()]) { - firstInChain[block->getId()] = true; - lastInChain[block->getId()] = true; + if (block->getLayoutSucc() == NULL && !lastInChain[block->getDfNum()]) { + firstInChain[block->getDfNum()] = true; + lastInChain[block->getDfNum()] = true; } } } combineChains(); - fixBranches(); } void BottomUpLayout::layoutEdge(Edge *edge) { - Node* tailNode = edge->getNode(Direction_Tail); - Node* headNode = edge->getNode(Direction_Head); - if (!headNode->hasKind(Node::Kind_BasicBlock) || !tailNode->hasKind(Node::Kind_BasicBlock)) { + Node* tailNode = edge->getSourceNode(); + Node* headNode = edge->getTargetNode(); + if (!headNode->isBlockNode() || !tailNode->isBlockNode()) { return; } - if (headNode == irManager->getPrologNode()) { //prolog node should be first in layout + if (headNode == irManager->getFlowGraph()->getEntryNode()) { //prolog node should be first in layout return; } if (tailNode == headNode) { @@ -105,10 +99,10 @@ void BottomUpLayout::layoutEdge(Edge *e return; //tailBlock is layout predecessor for another successor } BasicBlock* headBlock = (BasicBlock*)headNode; - if (prevInLayoutBySuccessorId[headBlock->getId()]!=NULL) { + if (prevInLayoutBySuccessorId[headBlock->getDfNum()]!=NULL) { return; // head was already laid out (in other chain) } - if (lastInChain[tailBlock->getId()] && firstInChain[headBlock->getId()]) { + if (lastInChain[tailBlock->getDfNum()] && firstInChain[headBlock->getDfNum()]) { BasicBlock* tailOfHeadChain = headBlock; while (tailOfHeadChain->getLayoutSucc()!=NULL) { tailOfHeadChain = tailOfHeadChain->getLayoutSucc(); @@ -119,22 +113,22 @@ void BottomUpLayout::layoutEdge(Edge *e } tailBlock->setLayoutSucc(headBlock); - prevInLayoutBySuccessorId[headBlock->getId()] = tailBlock; + prevInLayoutBySuccessorId[headBlock->getDfNum()] = tailBlock; - BasicBlock* tailPred = prevInLayoutBySuccessorId[tailBlock->getId()]; + BasicBlock* tailPred = prevInLayoutBySuccessorId[tailBlock->getDfNum()]; if (tailPred) { - assert(lastInChain[tailBlock->getId()]); - lastInChain[tailBlock->getId()] = false; + assert(lastInChain[tailBlock->getDfNum()]); + lastInChain[tailBlock->getDfNum()] = false; } else { - firstInChain[tailBlock->getId()] = true; + firstInChain[tailBlock->getDfNum()] = true; }// here we have valid first - firstInChain[headBlock->getId()] = false; + firstInChain[headBlock->getDfNum()] = false; BasicBlock* newLast = headBlock; while (newLast->getLayoutSucc()!=NULL) { newLast = newLast->getLayoutSucc(); } - lastInChain[newLast->getId()] = true; + lastInChain[newLast->getDfNum()] = true; } @@ -153,8 +147,8 @@ struct chains_comparator{ if (c2 == prolog) { return false; } - ExecCntValue fromC1ToC2 = calcEdgesWeight(c1, c2); - ExecCntValue fromC2ToC1 = calcEdgesWeight(c2, c1); + double fromC1ToC2 = calcEdgesWeight(c1, c2); + double fromC2ToC1 = calcEdgesWeight(c2, c1); if (fromC1ToC2 > fromC2ToC1) { return true; //c1 is first in topological order } else if (fromC1ToC2 < fromC2ToC1) { @@ -163,19 +157,20 @@ struct chains_comparator{ return c1 > c2; //any stable order.. } - ExecCntValue calcEdgesWeight(const BasicBlock* c1, const BasicBlock* c2) const { - ExecCntValue d = 0.0; + double calcEdgesWeight(const BasicBlock* c1, const BasicBlock* c2) const { + double d = 0.0; //distance is sum of exec count of c1 blocks out edges c1 to c2; for (const BasicBlock* b = c1; b!=NULL; b = b->getLayoutSucc()) { - const Edges& outEdges = b->getEdges(Direction_Out); - for (Edge* e = outEdges.getFirst(); e!=NULL; e = outEdges.getNext(e)) { - Node* node = e->getNode(Direction_Head); - if (node != b->getLayoutSucc() && node->hasKind(Node::Kind_BasicBlock)) { + const Edges& outEdges = b->getOutEdges(); + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* e= *ite; + Node* node = e->getTargetNode(); + if (node != b->getLayoutSucc() && node->isBlockNode()) { const BasicBlock* targetBlock = (BasicBlock*)node; //look if node is in c2 chain const BasicBlock* targetChain = findChain(targetBlock); if (targetChain == c2) { - ExecCntValue dd = b->getExecCnt() * e->getProbability(); + double dd = b->getExecCount() * e->getEdgeProb(); d+=dd; } } @@ -186,7 +181,7 @@ struct chains_comparator{ const BasicBlock* findChain(const BasicBlock* bb) const { const BasicBlock* prev = bb; - while ((prev = prevInLayoutBySuccessorId[bb->getId()])!=NULL) { + while ((prev = prevInLayoutBySuccessorId[bb->getDfNum()])!=NULL) { bb = prev; } return bb; @@ -197,18 +192,19 @@ struct chains_comparator{ void BottomUpLayout::combineChains() { StlVector chains(mm); - const Nodes& nodes = irManager->getNodes(); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (firstInChain[node->getId()]) { - assert(node->hasKind(Node::Kind_BasicBlock)); + if (firstInChain[node->getDfNum()]) { + assert(node->isBlockNode()); chains.push_back((BasicBlock*)node); } } - std::sort(chains.begin(), chains.end(), chains_comparator(prevInLayoutBySuccessorId, irManager->getPrologNode())); - assert(*chains.begin() ==irManager->getPrologNode()); + std::sort(chains.begin(), chains.end(), + chains_comparator(prevInLayoutBySuccessorId, (BasicBlock*)irManager->getFlowGraph()->getEntryNode())); + assert(*chains.begin() ==irManager->getFlowGraph()->getEntryNode()); - assert(*chains.begin() == irManager->getPrologNode()); + assert(*chains.begin() == irManager->getFlowGraph()->getEntryNode()); for (uint32 i = 0, n = chains.size()-1; igetMaxNodeId(), "ia32::topdown_layout"), +memManager(40*irm->getFlowGraph()->getMaxNodeId(), "ia32::topdown_layout"), lastBlk(NULL), neighboursBlocks(memManager), -blockInfos(memManager, irm->getMaxNodeId()+1, NULL) +blockInfos(memManager, irm->getFlowGraph()->getMaxNodeId(), NULL) { - const Nodes& nodes = irManager->getNodes(); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node * node=*it; - if (node->hasKind(Node::Kind_BasicBlock)){ + if (node->isBlockNode()){ TopDownLayoutBlockInfo* info = new (memManager) TopDownLayoutBlockInfo(); info->block = (BasicBlock*)node; blockInfos[node->getId()]= info; @@ -51,52 +51,40 @@ blockInfos(memManager, irm->getMaxNodeId // Do complete top down code layout void TopDownLayout::linearizeCfgImpl() { - irManager->updateExecCounts(); -#ifdef _DEBUG - ensureProfileIsValid(); -#endif + assert(irManager->getFlowGraph()->isEdgeProfileConsistent()); BasicBlock * blk; - startBlockLayout(); - while ((blk = pickLayoutCandidate()) != NULL) { - layoutBlock(blk); - } - endBlockLayout(); -} - -// Start top down block layout -void TopDownLayout::startBlockLayout() { lastBlk = NULL; // Check that nodes have no layout successors set #ifdef _DEBUG - for (CFG::NodeIterator it(*irManager, CFG::OrderType_Postorder); it.getNode()!=NULL; ++it){ - Node * node=it.getNode(); - if (node->hasKind(Node::Kind_BasicBlock)){ + const Nodes& postOrderNodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = postOrderNodes.begin(), end = postOrderNodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ assert(((BasicBlock *)node)->getLayoutSucc()==NULL); } } #endif -} -// Called at the end of top down layout -void TopDownLayout::endBlockLayout() { - - if (lastBlk) { - fixBranches(lastBlk); + while ((blk = pickLayoutCandidate()) != NULL) { + layoutBlock(blk); } } + + + // Layout "blk" after "lastBlk". Do all bookkeeping and branch updates as needed void TopDownLayout::layoutBlock(BasicBlock *blk) { TopDownLayoutBlockInfo* bInfo = blockInfos[blk->getId()]; assert(!bInfo->isLayouted()); - if (Log::cat_cg()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "layoutBlock("; IRPrinter::printNodeName(Log::out(), blk); - Log::out() << ")" << ::std::endl; + Log::out() << ")" << std::endl; } // Remove the block from the localityMap if it is there if (bInfo->isLayoutNeighbour()) { @@ -106,11 +94,9 @@ void TopDownLayout::layoutBlock(BasicBlo if (lastBlk) { lastBlk->setLayoutSucc(blk); - // Add/fix any branches due to this layout decision. - fixBranches(lastBlk); } else { // Check our assumption that the first block laid-out is the entry block. - assert(blk== irManager->getPrologNode()); + assert(blk== irManager->getFlowGraph()->getEntryNode()); } lastBlk = blk; } @@ -123,7 +109,7 @@ #define PROB_SIMILAR_FACTOR 0.9 BasicBlock * TopDownLayout::pickLayoutCandidate() { if (lastBlk == NULL) { // Layout the entry block - return irManager->getPrologNode(); + return (BasicBlock*)irManager->getFlowGraph()->getEntryNode(); } // Return most likely successor of lastBlk if it has not already been placed // and if branch inversion is either not needed or is possible @@ -131,28 +117,28 @@ BasicBlock * TopDownLayout::pickLayoutCa // successors, pick the one that is not a Join block. This will help // reduce taken branches. Edge *bestEdge = NULL; - const Edges& outEdges=lastBlk->getEdges(Direction_Out); - for(Edge* edge = outEdges.getFirst(); edge!=NULL; edge = outEdges.getNext(edge)) { - Node *succ = edge->getNode(Direction_Head); - if (!succ->hasKind(Node::Kind_BasicBlock)) { + const Edges& outEdges=lastBlk->getOutEdges(); + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node *succ = edge->getTargetNode(); + if (!succ->isBlockNode()) { continue; } TopDownLayoutBlockInfo* info = blockInfos[succ->getId()]; if (info->isLayouted() ) { continue; } - if (!edge->isFallThroughEdge() && !canEdgeBeMadeToFallThrough(edge)) { + if (!edge->isFalseEdge() && !canEdgeBeMadeToFallThrough(edge)) { continue; } if (bestEdge == NULL) { bestEdge = edge; } - double bestEdgeWeight = bestEdge->getProbability(); - double edgeWeight = edge->getProbability(); + double bestEdgeWeight = bestEdge->getEdgeProb(); + double edgeWeight = edge->getEdgeProb(); if ( edgeWeight > bestEdgeWeight || (edgeWeight >= bestEdgeWeight * PROB_SIMILAR_FACTOR - && edge->getNode(Direction_Head)->getEdges(Direction_In).getCount() == 1 - && bestEdge->getNode(Direction_Head)->getEdges(Direction_In).getCount() > 1)) + && edge->getTargetNode()->getInDegree() == 1 && bestEdge->getTargetNode()->getInDegree() > 1)) { bestEdge = edge; } @@ -161,7 +147,7 @@ BasicBlock * TopDownLayout::pickLayoutCa // Before returning or choosing a block from the connectivity map, update // the layoutValue information to successors not chosen or already laid out. if (bestEdge) { - BasicBlock* headBlock = (BasicBlock*)bestEdge->getNode(Direction_Head); + BasicBlock* headBlock = (BasicBlock*)bestEdge->getTargetNode(); processSuccLayoutValue(lastBlk, headBlock); return headBlock; } @@ -178,7 +164,7 @@ #if _DEBUG prevInfo = bInfo; } #endif - if (Log::cat_cg()->isDebugEnabled()) { + if (Log::isEnabled()) { printConnectedBlkMap(Log::out()); } @@ -188,7 +174,7 @@ #endif TopDownLayoutBlockInfo* info = *neighboursBlocks.begin(); BasicBlock * locBlk = info->block; - if (Log::cat_cg()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Picking "; IRPrinter::printNodeName(Log::out(), locBlk); Log::out() << " " << info->layoutValue<< ::std::endl; @@ -202,30 +188,29 @@ #endif // If a successor is a dispatch node, recursively process its successors, since // dispatch nodes are not being laid out. void TopDownLayout::processSuccLayoutValue(Node *node, BasicBlock * layoutSucc) { - const Edges& outEdges = node->getEdges(Direction_Out); - for (Edge *edge = outEdges.getFirst();edge; edge = outEdges.getNext(edge)) { - Node *succ = edge->getNode(Direction_Head); - if (succ->hasKind(Node::Kind_DispatchNode)) { + const Edges& outEdges = node->getOutEdges(); + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node *succ = edge->getTargetNode(); + if (succ->isDispatchNode()) { processSuccLayoutValue(succ, layoutSucc); - } else if (succ->hasKind(Node::Kind_BasicBlock)) { + } else if (succ->isBlockNode()) { TopDownLayoutBlockInfo* succInfo = blockInfos[succ->getId()]; if (succ != layoutSucc && !succInfo->isLayouted()) { if (succInfo->isLayoutNeighbour()) { //remove from sorted map and insert latter to sort again. neighboursBlocks.erase(succInfo); } - succInfo->layoutValue+=node->getExecCnt() * edge->getProbability(); + succInfo->layoutValue+=node->getExecCount() * edge->getEdgeProb(); succInfo->state = TopDownLayoutBlockInfo::LAYOUT_NEIGHBOUR; neighboursBlocks.insert(succInfo); - if (Log::cat_cg()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Block "; IRPrinter::printNodeName(Log::out(), succInfo->block); - Log::out() << " is in neighbors set." << ::std::endl; + Log::out() << " is in neighbors set." << std::endl; } } - } else { - assert(succ->hasKind(Node::Kind_UnwindNode) || succ->hasKind(Node::Kind_ExitNode)); - } + } } } diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeLayoutTopDown.h vm/jitrino/src/codegenerator/ia32/Ia32CodeLayoutTopDown.h index b208eae..e2cb56a 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeLayoutTopDown.h +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeLayoutTopDown.h @@ -91,8 +91,6 @@ protected: void linearizeCfgImpl(); private: - void startBlockLayout(); - void endBlockLayout(); BasicBlock * pickLayoutCandidate(); void layoutBlock(BasicBlock *blk); diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.cpp vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.cpp index 6372d02..b53e549 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.cpp @@ -24,17 +24,16 @@ #include "Ia32CodeGenerator.h" #include "Ia32CodeSelector.h" #include "Ia32CFG.h" #include "Ia32InstCodeSelector.h" +#include "EMInterface.h" +#include "XTimer.h" + namespace Jitrino { namespace Ia32{ -Timer * MethodCodeSelector::selectionTimer=NULL; -Timer * MethodCodeSelector::blockMergingTimer=NULL; -Timer * MethodCodeSelector::fixNodeInfoTimer=NULL; -Timer * MethodCodeSelector::varTimer=NULL; - -Timer * CfgCodeSelector::instTimer=NULL; -Timer * CfgCodeSelector::blockTimer=NULL; +CountTime selectionTimer("ia32::selector::selection"); +CountTime blockMergingTimer("ia32::selector::blockMerging"); +CountTime fixNodeInfoTimer("ia32::selector::fixNodeInfo"); //_______________________________________________________________________________________________________________ @@ -46,12 +45,12 @@ Timer * CfgCodeSelector::blockTimer=NUL //_______________________________________________________________________________________________ /** Construct CFG builder */ -CfgCodeSelector::CfgCodeSelector(CompilationInterface& compIntfc, - MethodCodeSelector& methodCodeSel, - MemoryManager& codeSelectorMM, - uint32 nNodes, - IRManager& irM - ) +CfgCodeSelector::CfgCodeSelector(CompilationInterface& compIntfc, + MethodCodeSelector& methodCodeSel, + MemoryManager& codeSelectorMM, + uint32 nNodes, + IRManager& irM + ) : numNodes(nNodes), nextNodeId(0), compilationInterface(compIntfc), methodCodeSelector(methodCodeSel), irMemManager(irM.getMemoryManager()), codeSelectorMemManager(codeSelectorMM), irManager(irM), @@ -78,7 +77,9 @@ uint32 CfgCodeSelector::genDispatchNode( { assert(nextNodeId < numNodes); uint32 nodeId = nextNodeId++; - nodes[nodeId] = irManager.newDispatchNode(cnt); + Node* node = irManager.getFlowGraph()->createDispatchNode(); + node->setExecCount(cnt); + nodes[nodeId] = node; hasDispatchNodes = true; return nodeId; } @@ -94,30 +95,29 @@ uint32 CfgCodeSelector::genBlock(uint32 { assert(nextNodeId < numNodes); uint32 nodeId = nextNodeId++; - BasicBlock *bb = irManager.newBasicBlock(cnt); + Node* bb = irManager.getFlowGraph()->createBlockNode(); + bb->setExecCount(cnt); nodes[nodeId] = bb; InstCodeSelector instCodeSelector(compilationInterface, *this, irManager, bb); currBlock = bb; - { -// PhaseTimer tm(instTimer, "ia32::selector::blocks::insts"); - codeSelector.genCode(instCodeSelector); - } + { + codeSelector.genCode(instCodeSelector); + } - currBlock = NULL; + currBlock = NULL; // Set prolog or epilog node switch (blockKind) { case Prolog: { // Copy execution count into IA32 CFG prolog node and // create an edge from IA32 CFG prolog node to optimizer's prolog node - BasicBlock * prolog = irManager.getPrologNode(); - prolog->setExecCnt(cnt); - irManager.newFallThroughEdge(prolog,bb,1.0); + Node* prolog = irManager.getFlowGraph()->getEntryNode(); + prolog->setExecCount(cnt); + irManager.getFlowGraph()->addEdge(prolog, bb, 1.0); break; } case Epilog: { - //irManager.newEdge(bb, irManager.getExitNode(), 1.0); assert(bb->isEmpty()); break; } @@ -137,9 +137,9 @@ uint32 CfgCodeSelector::genBlock(uint32 //_______________________________________________________________________________________________ /** - Create unwind node. - This is a temporary node that exists only during code selection. - We create it using code selector memory manager and insert it into its own CFG. + Create unwind node. + This is a temporary node that exists only during code selection. + We create it using code selector memory manager and insert it into its own CFG. */ uint32 CfgCodeSelector::genUnwindNode(uint32 numInEdges, @@ -148,7 +148,11 @@ uint32 CfgCodeSelector::genUnwindNode(u { assert(nextNodeId < numNodes); uint32 nodeId = nextNodeId++; - nodes[nodeId] = irManager.newUnwindNode(cnt); + ControlFlowGraph* fg = irManager.getFlowGraph(); + Node* unwindNode = fg->createDispatchNode(); + fg->setUnwindNode(unwindNode); + unwindNode->setExecCount(cnt); + nodes[nodeId] = unwindNode; return nodeId; } @@ -159,24 +163,29 @@ uint32 CfgCodeSelector::genExitNode(uint { assert(nextNodeId < numNodes); uint32 nodeId = nextNodeId++; - nodes[nodeId] = irManager.getExitNode(); + ControlFlowGraph* fg = irManager.getFlowGraph(); + Node* exitNode = fg->createExitNode(); + exitNode->setExecCount(cnt); + fg->setExitNode(exitNode); + nodes[nodeId] = exitNode; return nodeId; } //_______________________________________________________________________________________________ /** Create a block for a switch statement */ -void CfgCodeSelector::genSwitchBlock(BasicBlock *originalBlock, +void CfgCodeSelector::genSwitchBlock(Node *originalBlock, uint32 numTargets, Opnd * switchSrc) { - BasicBlock *bb = irManager.newBasicBlock(originalBlock->getExecCnt()); + Node *bb = irManager.getFlowGraph()->createBlockNode(); + bb->setExecCount(originalBlock->getExecCount()); InstCodeSelector instSelector(compilationInterface, *this, irManager, bb); - { - instSelector.genSwitchDispatch(numTargets,switchSrc); - } + { + instSelector.genSwitchDispatch(numTargets,switchSrc); + } // Create an edge from the original block to bb - irManager.newFallThroughEdge(originalBlock,bb,1.0); + genFalseEdge(originalBlock, bb, 1.0); } //_______________________________________________________________________________________________ @@ -184,11 +193,20 @@ void CfgCodeSelector::genSwitchBlock(Bas void CfgCodeSelector::genTrueEdge(uint32 tailNodeId,uint32 headNodeId, double prob) { - assert(nodes[tailNodeId]->hasKind(Node::Kind_BasicBlock)); - assert(nodes[headNodeId]->hasKind(Node::Kind_BasicBlock)); - BasicBlock * tailBlock = (BasicBlock *)nodes[tailNodeId]; - BasicBlock * headBlock = (BasicBlock *)nodes[headNodeId]; - irManager.newDirectBranchEdge(tailBlock, headBlock, prob); + Node* tailNode= nodes[tailNodeId]; + Node * headNode = nodes[headNodeId]; + genTrueEdge(tailNode, headNode, prob); +} + +void CfgCodeSelector::genTrueEdge(Node* tailNode, Node* headNode, double prob) { + assert(tailNode->isBlockNode() && headNode->isBlockNode()); + + Inst* inst = (Inst*)tailNode->getLastInst(); + assert(inst!=NULL && inst->hasKind(Inst::Kind_BranchInst)); + BranchInst* br = (BranchInst*)inst; + br->setTrueTarget(headNode); + + irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); } //_______________________________________________________________________________________________ @@ -196,9 +214,20 @@ void CfgCodeSelector::genTrueEdge(uint32 void CfgCodeSelector::genFalseEdge(uint32 tailNodeId,uint32 headNodeId, double prob) { - assert(nodes[tailNodeId]->hasKind(Node::Kind_BasicBlock)); - assert(nodes[headNodeId]->hasKind(Node::Kind_BasicBlock)); - irManager.newFallThroughEdge((BasicBlock*)nodes[tailNodeId], (BasicBlock*)nodes[headNodeId], prob); + Node* tailNode = nodes[tailNodeId]; + Node* headNode = nodes[headNodeId]; + genFalseEdge(tailNode, headNode, prob); +} + +void CfgCodeSelector::genFalseEdge(Node* tailNode,Node* headNode, double prob) { + assert(tailNode->isBlockNode() && headNode->isBlockNode()); + + Inst* inst = (Inst*)tailNode->getLastInst(); + assert(inst!=NULL && inst->hasKind(Inst::Kind_BranchInst)); + BranchInst* br = (BranchInst*)inst; + br->setFalseTarget(headNode); + + irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); } //_______________________________________________________________________________________________ @@ -208,13 +237,16 @@ void CfgCodeSelector::genUnconditionalEd { Node * tailNode = nodes[tailNodeId]; Node * headNode = nodes[headNodeId]; - assert(tailNode->hasKind(Node::Kind_BasicBlock)); - assert(headNode->hasKind(Node::Kind_BasicBlock) || headNode == irManager.getExitNode()); - if (headNode == irManager.getExitNode()){ - irManager.newEdge(tailNode, headNode, 1.0); - }else{ - irManager.newFallThroughEdge((BasicBlock*)tailNode,(BasicBlock*)headNode, prob); - } + assert(tailNode->isBlockNode()); + assert(headNode->isBlockNode() || headNode == irManager.getFlowGraph()->getExitNode()); + Inst* lastInst = (Inst*)tailNode->getLastInst(); + if (lastInst!=NULL && lastInst->hasKind(Inst::Kind_BranchInst)) { + BranchInst* br = (BranchInst*)lastInst; + assert(br->getTrueTarget() != NULL); + assert(br->getFalseTarget() == NULL); + br->setFalseTarget(headNode); + } + irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); } //_______________________________________________________________________________________________ @@ -224,8 +256,8 @@ void CfgCodeSelector::genSwitchEdges(uin uint32 *targets, double *probs, uint32 defaultTarget) { - // - // Switch structure: + // + // Switch structure: // // origBlock switchBlock // =========== Fallthrough ============= @@ -234,15 +266,14 @@ void CfgCodeSelector::genSwitchEdges(uin // jmp defaultTarget // Node * origBlock = nodes[tailNodeId]; - const Edges& outEdges=origBlock->getEdges(Direction_Out); - assert(outEdges.getCount() == 1); - Node * switchNode = outEdges.getFirst()->getNode(Direction_Head); - assert(switchNode->hasKind(Node::Kind_BasicBlock)); - BasicBlock * switchBlock = (BasicBlock *)switchNode; - assert(switchBlock->getInsts().getLast()->hasKind(Inst::Kind_SwitchInst)); - SwitchInst * swInst = (SwitchInst *)switchBlock->getInsts().getLast(); - - double defaultEdgeProb = 1.0; + const Edges& outEdges=origBlock->getOutEdges(); + assert(outEdges.size() == 1); + Node * switchBlock= outEdges.front()->getTargetNode(); + assert(switchBlock->isBlockNode()); + assert(((Inst*)switchBlock->getLastInst())->hasKind(Inst::Kind_SwitchInst)); + SwitchInst * swInst = (SwitchInst *)switchBlock->getLastInst(); + + double defaultEdgeProb = 1.0; defaultEdgeProb = 1.0; for (uint32 i = 0; i < numTargets; i++) { uint32 targetId = targets[i]; @@ -253,27 +284,28 @@ void CfgCodeSelector::genSwitchEdges(uin if (std::find(targets, targets+i, targetId)!=targets+i) { continue; //repeated target } - if (probs[i] == EdgeProbValue_Unknown) { - defaultEdgeProb = EdgeProbValue_Unknown; + if (probs[i] < 0) { + defaultEdgeProb = 0; break; } defaultEdgeProb -= 1.0/(numTargets+1); } - genTrueEdge(tailNodeId, defaultTarget, defaultEdgeProb); + genTrueEdge(tailNodeId, defaultTarget, defaultEdgeProb); + // Fix probability of fallthrough edge - if (defaultEdgeProb!=EdgeProbValue_Unknown) { - origBlock->getEdges(Direction_Out).getFirst()->setProbability(1.0 - defaultEdgeProb); + if (defaultEdgeProb!=0) { + origBlock->getOutEdges().front()->setEdgeProb(1.0 - defaultEdgeProb); } // Generate edges from switchBlock to switch targets for (uint32 i = 0; i < numTargets; i++) { Node * targetNode = nodes[targets[i]]; // Avoid generating duplicate edges. Jump table however needs all entries - if (! switchBlock->isConnectedTo(Direction_Out, targetNode)) - irManager.newEdge(switchBlock, targetNode, probs[i]); - assert(targetNode->hasKind(Node::Kind_BasicBlock)); - swInst->setTarget(i, (BasicBlock *)targetNode); - } + if (! switchBlock->isConnectedTo(true, targetNode)) { + irManager.getFlowGraph()->addEdge(switchBlock, targetNode, probs[i]); + } + swInst->setTarget(i, targetNode); + } } //_______________________________________________________________________________________________ @@ -283,8 +315,8 @@ void CfgCodeSelector::genExceptionEdge(u { Node * headNode = nodes[headNodeId]; Node * tailNode = nodes[tailNodeId]; - assert(headNode->hasKind(Node::Kind_DispatchNode) || headNode->hasKind(Node::Kind_UnwindNode) ); - irManager.newEdge(tailNode, headNode, prob); + assert(headNode->isDispatchNode() || headNode->isExitNode()); + irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); } //_______________________________________________________________________________________________ @@ -298,38 +330,13 @@ void CfgCodeSelector::genCatchEdge(uint3 { Node * headNode = nodes[headNodeId]; Node * tailNode = nodes[tailNodeId]; - assert(tailNode->hasKind(Node::Kind_DispatchNode)); - assert(headNode->hasKind(Node::Kind_BasicBlock)); - irManager.newCatchEdge((DispatchNode*)tailNode, (BasicBlock*)headNode, exceptionType, priority, prob); + assert(tailNode->isDispatchNode()); + assert(headNode->isBlockNode()); + CatchEdge* edge = (CatchEdge*)irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); + edge->setType(exceptionType); + edge->setPriority(priority); } -//_______________________________________________________________________________________________ -/** Create an edge to the exit node */ - -void CfgCodeSelector::genExitEdge(uint32 tailNodeId, - uint32 headNodeId, - double prob) -{ - Node * headNode = nodes[headNodeId]; - Node * tailNode = nodes[tailNodeId]; - assert(headNode == irManager.getExitNode()); - if (tailNode!=irManager.getUnwindNode()) { // unwind->exit edge is auto-generated - irManager.newEdge(tailNode, headNode, prob); - } -} - -//_______________________________________________________________________________________________ -/** Set node loop info */ - -void CfgCodeSelector::setLoopInfo(uint32 nodeId, - bool isLoopHeader, - bool hasContainingLoopHeader, - uint32 headerId) -{ - Node * node = nodes[nodeId]; - Node * header = hasContainingLoopHeader ? nodes[headerId] : NULL; - node->setLoopInfo(isLoopHeader,header); -} //_______________________________________________________________________________________________ /** Cfg code selector is notified that method contains calls */ @@ -350,8 +357,8 @@ void CfgCodeSelector::methodHasCalls(boo //_______________________________________________________________________________________________ uint32 VarGenerator::defVar(Type* varType, bool isAddressTaken, bool isPinned) { - Opnd * opnd=irManager.newOpnd(varType); - return opnd->getId(); + Opnd * opnd=irManager.newOpnd(varType); + return opnd->getId(); } //_______________________________________________________________________________________________ @@ -384,51 +391,57 @@ void MethodCodeSelector::updateRegUsage( } //_______________________________________________________________________________________________ -/** Set loop info, persistent ids, and others for nodes that exist only in the code generator CFG */ +/** Set persistent ids, and others for nodes that exist only in the code generator CFG */ void CfgCodeSelector::fixNodeInfo() { -// connect throw nodes added during inst code selection to corresponding dispatch or unwind nodes - for (CFG::NodeIterator it(irManager); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock*)node; - - const Insts & insts = bb->getInsts(); - Inst * lastInst = insts.getLast(); - if (lastInst) { - Inst * prevInst = insts.getPrev(lastInst); - if(prevInst && prevInst->getKind() == Inst::Kind_BranchInst) { - Edge * ftEdge = bb->getFallThroughEdge(); - Edge * dbEdge = bb->getDirectBranchEdge(); - if (ftEdge && dbEdge) { - BasicBlock * newBB = irManager.newBasicBlock(0); - BasicBlock * nextFT = (BasicBlock *)ftEdge->getNode(Direction_Head); - irManager.removeEdge(ftEdge); - irManager.newFallThroughEdge(newBB, nextFT, 0.001); - newBB->appendInsts(irManager.newBranchInst(lastInst->getMnemonic())); - bb->removeInst(lastInst); - BasicBlock * nextDB = (BasicBlock *)dbEdge->getNode(Direction_Head); - irManager.removeEdge(dbEdge); - irManager.newDirectBranchEdge(bb, nextDB, 0.001); - irManager.newDirectBranchEdge(newBB, nextDB, 0.001); - irManager.newFallThroughEdge(bb, newBB, 0.001); - } else { - assert(0); - } - } - } - if (bb->getEdges(Direction_Out).getCount()==0){ // throw node - assert(bb->getEdges(Direction_In).getCount()==1); - BasicBlock * bbIn=(BasicBlock*)bb->getNode(Direction_In, Node::Kind_BasicBlock); - assert(bbIn!=NULL); - Node * target=bbIn->getNode(Direction_Out, (Node::Kind)(Node::Kind_DispatchNode|Node::Kind_UnwindNode)); - assert(target!=NULL); - irManager.newEdge(bb, target, 1.0); - } - } - } - irManager.updateLoopInfo(); + ControlFlowGraph* fg = irManager.getFlowGraph(); + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + // connect throw nodes added during inst code selection to corresponding dispatch or unwind nodes + if (node->isBlockNode()){ + Inst * lastInst = (Inst*)node->getLastInst(); + if (lastInst) { + Inst * prevInst = lastInst->getPrevInst(); + if(prevInst && prevInst->getKind() == Inst::Kind_BranchInst) { + Edge * ftEdge = node->getFalseEdge(); + Edge * dbEdge = node->getTrueEdge(); + assert(ftEdge && dbEdge); + + Node* newBB = fg->createBlockNode(); + Node* nextFT = ftEdge->getTargetNode(); + Node* nextDB = dbEdge->getTargetNode(); + + fg->removeEdge(ftEdge); + fg->removeEdge(dbEdge); + + newBB->appendInst(irManager.newBranchInst(lastInst->getMnemonic(), nextDB, nextFT)); + lastInst->unlink(); + + //now fix prev branch successors + BranchInst* prevBranch = (BranchInst*)prevInst; + assert(prevBranch->getTrueTarget() == NULL && prevBranch->getFalseTarget() == NULL); + prevBranch->setTrueTarget(nextDB); + prevBranch->setFalseTarget(newBB); + + + fg->addEdge(node, nextDB, 0); + fg->addEdge(node, newBB, 0); + fg->addEdge(newBB, nextDB, 0); + fg->addEdge(newBB, nextFT, 0); + } + } + if (node->getOutDegree() == 0){ // throw node + assert(node->getInDegree()==1); + Node* bbIn = node->getInEdges().front()->getSourceNode(); + assert(bbIn!=NULL); + Node * target=bbIn->getExceptionEdgeTarget(); + assert(target!=NULL); + fg->addEdge(node, target, 1.0); + } + } + } } //_______________________________________________________________________________________________ @@ -441,31 +454,53 @@ void MethodCodeSelector::genHeapBase() //_______________________________________________________________________________________________ /** Generate control flow graph */ +MethodCodeSelector::MethodCodeSelector(CompilationInterface& compIntfc, + MemoryManager& irMM, + MemoryManager& codeSelectorMM, + IRManager& irM, + bool slowLoadString) +: compilationInterface(compIntfc), +irMemManager(irMM), codeSelectorMemManager(codeSelectorMM), +irManager(irM), +methodDesc(NULL), +edgeProfile(NULL), +slowLdString(slowLoadString) +{ + ProfilingInterface* pi = irManager.getProfilingInterface(); + if (pi!=NULL && pi->isProfilingEnabled(ProfileType_Edge, JITProfilingRole_GEN)) { + edgeProfile = pi->getEdgeMethodProfile(irMM, irM.getMethodDesc(), JITProfilingRole_GEN); + } + +} + + void MethodCodeSelector::genCFG(uint32 numNodes, CFGCodeSelector& codeSelector, bool useEdgeProfile) { - irManager.setHasEdgeProfile(useEdgeProfile); + ControlFlowGraph* fg = irManager.getFlowGraph(); + fg->setEdgeProfile(useEdgeProfile); CfgCodeSelector cfgCodeSelector(compilationInterface, *this, - codeSelectorMemManager,numNodes, - irManager); - { - PhaseTimer tm(selectionTimer, "ia32::selector::selection"); - if( NULL == irManager.getEntryPointInst() ) { - irManager.newEntryPointPseudoInst( irManager.getDefaultManagedCallingConvention() ); - } - codeSelector.genCode(cfgCodeSelector); - } - { - PhaseTimer tm(fixNodeInfoTimer, "ia32::selector::fixNodeInfo"); - irManager.expandSystemExceptions(0); - cfgCodeSelector.fixNodeInfo(); - } - { - PhaseTimer tm(blockMergingTimer, "ia32::selector::blockMerging"); - irManager.mergeSequentialBlocks(); - irManager.purgeEmptyBlocks(); - } + codeSelectorMemManager,numNodes, + irManager); + { + AutoTimer tm(selectionTimer); + if( NULL == irManager.getEntryPointInst() ) { + irManager.newEntryPointPseudoInst( irManager.getDefaultManagedCallingConvention() ); + } + codeSelector.genCode(cfgCodeSelector); + } + { + AutoTimer tm(fixNodeInfoTimer); + irManager.expandSystemExceptions(0); + cfgCodeSelector.fixNodeInfo(); + } + { + AutoTimer tm(blockMergingTimer); + fg->purgeEmptyNodes(false, true); + fg->mergeAdjacentNodes(true, false); + fg->purgeUnreachableNodes(); + } } //_______________________________________________________________________________________________ diff --git vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.h vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.h index 605ff41..9bc17f4 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.h +++ vm/jitrino/src/codegenerator/ia32/Ia32CodeSelector.h @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Intel, Vyacheslav P. Shakin - * @version $Revision: 1.6.22.4 $ + * @author Vyacheslav P. Shakin + * @version $Revision$ */ #ifndef _IA32_CODE_SELECTOR_H_ @@ -25,11 +25,12 @@ #include "Stl.h" #include "CodeGenIntfc.h" #include "Ia32IRManager.h" #include "Ia32CFG.h" -#include "Timer.h" + namespace Jitrino { -class CodeProfiler; class CompilationInterface; +class EdgeMethodProfile; + namespace Ia32{ @@ -37,10 +38,6 @@ namespace Ia32{ // Forward delcarations //======================================================================================================== -class CFG; -class Node; -class BasicBlock; -class DispatchNode; class Inst; @@ -67,11 +64,11 @@ public: // CFGCodeSelector::Callback methods // CfgCodeSelector(CompilationInterface& compIntfc, - MethodCodeSelector& methodCodeSel, + MethodCodeSelector& methodCodeSel, MemoryManager& codeSelectorMM, uint32 nNodes, IRManager& irM); - uint32 genDispatchNode(uint32 numInEdges, uint32 numOutEdges, double cnt); + uint32 genDispatchNode(uint32 numInEdges, uint32 numOutEdges, double cnt); uint32 genBlock(uint32 numInEdges, uint32 numOutEdges, BlockKind blockKind, BlockCodeSelector& codeSelector, double cnt); @@ -79,64 +76,61 @@ public: uint32 genExitNode(uint32 numInEdges, double cnt); void genUnconditionalEdge(uint32 tailNodeId,uint32 headNodeId, double prob); void genTrueEdge(uint32 tailNodeId,uint32 headNodeId, double prob); + void genTrueEdge(Node* tailNode, Node* headNode, double prob); void genFalseEdge(uint32 tailNodeId,uint32 headNodeId, double prob); + void genFalseEdge(Node* tailNode, Node* headNode, double prob); void genSwitchEdges(uint32 tailNodeId, uint32 numTargets, uint32 *targets, double *probs, uint32 defaultTarget); void genExceptionEdge(uint32 tailNodeId, uint32 headNodeId, double prob); void genCatchEdge(uint32 headNodeId,uint32 tailNodeId, uint32 priority,Type* exceptionType, double prob); - void genExitEdge(uint32 tailNodeId, uint32 headNodeId, double prob); - - void setLoopInfo(uint32 nodeId, bool isLoopHeader, bool hasContainingLoopHeader, uint32 headerId); + void setPersistentId(uint32 nodeId, uint32 persistentId) { - nodes[nodeId]->setPersistentId(persistentId); + ((CGNode*)nodes[nodeId])->setPersistentId(persistentId); } - Opnd * getMethodReturnOpnd(){ - return returnOperand; - } + Opnd * getMethodReturnOpnd(){ + return returnOperand; + } - void setMethodReturnOpnd(Opnd * retOp){ - returnOperand=retOp; - } - - void fixNodeInfo(); + void setMethodReturnOpnd(Opnd * retOp){ + returnOperand=retOp; + } + + void fixNodeInfo(); - // + // // Used to differenciate between instrumented and uninstrumented cfgs // void markAsInstrumented() { } - // Callbacks for the instruction code selector + // Callbacks for the instruction code selector void methodHasCalls(bool nonExceptionCall); private: // // Methods // - void genSwitchBlock(BasicBlock *originalBlock, uint32 numTargets, + void genSwitchBlock(Node *originalBlock, uint32 numTargets, Opnd *switchSrc); void genEpilogNode(); - Inst * findExceptionInst(BasicBlock * block); - BasicBlock * getCurrentBlock() {return currBlock;} + Inst * findExceptionInst(Node* block); + Node* getCurrentBlock() {return currBlock;} // // Fields // - Node** nodes; - uint32 numNodes; - uint32 nextNodeId; - CompilationInterface& compilationInterface; - MethodCodeSelector& methodCodeSelector; - MemoryManager& irMemManager; // for data live after code selection - MemoryManager& codeSelectorMemManager; // for data dead after code selection - IRManager& irManager; - bool hasDispatchNodes; - BasicBlock * currBlock; - - Opnd * returnOperand; - - static Timer * instTimer; - static Timer * blockTimer; + Node** nodes; + uint32 numNodes; + uint32 nextNodeId; + CompilationInterface& compilationInterface; + MethodCodeSelector& methodCodeSelector; + MemoryManager& irMemManager; // for data live after code selection + MemoryManager& codeSelectorMemManager; // for data dead after code selection + IRManager& irManager; + bool hasDispatchNodes; + Node* currBlock; + + Opnd * returnOperand; // // bc map info @@ -144,7 +138,7 @@ private: VectorHandler* bc2HIRmapHandler; VectorHandler* bc2LIRmapHandler; - friend class InstCodeSelector; + friend class InstCodeSelector; }; //======================================================================================================== @@ -160,22 +154,17 @@ drives IR lowering for a whole method class MethodCodeSelector : public ::Jitrino::MethodCodeSelector::Callback { public: - MethodCodeSelector(CompilationInterface& compIntfc, - MemoryManager& irMM, - MemoryManager& codeSelectorMM, - IRManager& irM) - : compilationInterface(compIntfc), - irMemManager(irMM), codeSelectorMemManager(codeSelectorMM), - irManager(irM), - codeProfiler(NULL), - methodDesc(NULL){ } - - void genVars(uint32 numVars, ::Jitrino::VarCodeSelector& varCodeSelector); + MethodCodeSelector(CompilationInterface& compIntfc, + MemoryManager& irMM, + MemoryManager& codeSelectorMM, + IRManager& irM, + bool slowLoadString = false); + + + void genVars(uint32 numVars, ::Jitrino::VarCodeSelector& varCodeSelector); void setMethodDesc(MethodDesc * desc) {methodDesc = desc;} - void genCFG(uint32 numNodes, ::Jitrino::CFGCodeSelector& codeSelector, bool useDynamicProfile); + void genCFG(uint32 numNodes, ::Jitrino::CFGCodeSelector& codeSelector, bool useDynamicProfile); - void setProfileInfo(CodeProfiler *profiler) {codeProfiler = profiler;} - CodeProfiler * getProfileInfo() {return codeProfiler;} MethodDesc * getMethodDesc() {return methodDesc;} private: // @@ -190,18 +179,17 @@ private: CompilationInterface& compilationInterface; MemoryManager& irMemManager; // for data live after code selection MemoryManager& codeSelectorMemManager; // for data dead after code selection - IRManager& irManager; - CodeProfiler * codeProfiler; + IRManager& irManager; + MethodDesc * methodDesc; - static Timer * selectionTimer; - static Timer * blockMergingTimer; - static Timer * fixNodeInfoTimer; - static Timer * varTimer; + EdgeMethodProfile* edgeProfile; + + bool slowLdString; // 'false' by default - friend class CFGCodeSelector; - friend class VarGenerator; - friend class InstCodeSelector; + friend class CFGCodeSelector; + friend class VarGenerator; + friend class InstCodeSelector; }; //======================================================================================================== @@ -222,11 +210,11 @@ public: : nextVarId(0), irManager(irM), methodCodeSelector(methodCodeSel) { } uint32 defVar(Type* varType, bool isAddressTaken, bool isPinned); - void setManagedPointerBase(uint32 managedPtrVarNum, uint32 baseVarNum); + void setManagedPointerBase(uint32 managedPtrVarNum, uint32 baseVarNum); private: uint32 nextVarId; - IRManager& irManager; - MethodCodeSelector& methodCodeSelector; + IRManager& irManager; + MethodCodeSelector& methodCodeSelector; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.cpp vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.cpp index bfb303c..1a03039 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.cpp @@ -19,167 +19,218 @@ */ -#include "Ia32ComplexAddrFormLoader.h" +#include "Ia32CodeGenerator.h" +#include "Ia32CFG.h" +#include "Ia32IRManager.h" +#include "Ia32Inst.h" +#include "open/types.h" +#include "Stl.h" +#include "MemoryManager.h" +#include "Type.h" + namespace Jitrino { namespace Ia32 { +struct SubOpndsTable { + Opnd * baseOp; + Opnd * indexOp; + Opnd * scaleOp; + Opnd * dispOp; + Opnd * baseCand1; + Opnd * baseCand2; + Opnd * suspOp; + + SubOpndsTable(Opnd * s, Opnd * disp) : baseOp(NULL), indexOp(NULL), scaleOp(NULL), dispOp(disp), baseCand1(NULL), baseCand2(NULL), suspOp(s) {} +}; + +class ComplexAddrFormLoader : public SessionAction { + void runImpl(); +protected: + //fill complex address form + bool findAddressComputation(Opnd * memOp); + bool checkIsScale(Inst * inst); + void walkThroughOpnds(SubOpndsTable& table); +private: + uint32 refCountThreshold; +}; + +static ActionFactory _cafl("cafl"); + void ComplexAddrFormLoader::runImpl() { - if (parameters) { - refCountThreshold = atoi(std::string(parameters).c_str()); - if(refCountThreshold < 2) { - refCountThreshold = 2; - assert(0); - } - } else { - refCountThreshold = 2; - } - StlMap memOpnds(irManager.getMemoryManager()); - uint32 opndCount = irManager.getOpndCount(); - irManager.calculateOpndStatistics(); - for (uint32 i = 0; i < opndCount; i++) { - Opnd * opnd = irManager.getOpnd(i); - if(opnd->isPlacedIn(OpndKind_Mem)) { - Opnd * baseOp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); - Opnd * indexOp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); - if (baseOp && (!indexOp)) { - StlMap::iterator it = memOpnds.find(baseOp); - if(it == memOpnds.end() || it->second) { - memOpnds[baseOp]=findAddressComputation(opnd); - } - } - } - } + refCountThreshold = getIntArg("threshold", 4); + if(refCountThreshold < 2) { + refCountThreshold = 2; + assert(0); + } + + StlMap memOpnds(irManager->getMemoryManager()); + uint32 opndCount = irManager->getOpndCount(); + irManager->calculateOpndStatistics(); + for (uint32 i = 0; i < opndCount; i++) { + Opnd * opnd = irManager->getOpnd(i); + if(opnd->isPlacedIn(OpndKind_Mem)) { + Opnd * baseOp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + Opnd * indexOp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); + if (baseOp && (!indexOp)) { + StlMap::iterator it = memOpnds.find(baseOp); + if(it == memOpnds.end() || it->second) { + memOpnds[baseOp]=findAddressComputation(opnd); + } + } + } + } } bool ComplexAddrFormLoader::findAddressComputation(Opnd * memOp) { - - Opnd * disp = memOp->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - Opnd * base = memOp->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); - - Inst * inst = base->getDefiningInst(); - if (!inst) - return true; - - BasicBlock * bb = inst->getBasicBlock(); - - SubOpndsTable table(base, disp); - walkThroughOpnds(table); - if(!table.baseOp) - table.baseOp = table.suspOp; - - if(base->getRefCount() > refCountThreshold) { - if (table.indexOp) { - bb->appendInsts(irManager.newInst(Mnemonic_LEA, base, irManager.newMemOpnd(irManager.getTypeManager().getIntPtrType(), table.baseOp, table.indexOp, table.scaleOp, table.dispOp)), inst); - return false; - } - } else { - if (table.baseOp) { - memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Base, table.baseOp); - } - if (table.indexOp) { - memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Index, table.indexOp); - if (table.scaleOp) { - memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Scale, table.scaleOp); - } else { - assert(0); - } - } - if (table.dispOp) { - memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, table.dispOp); - - } - } - return true; + + Opnd * disp = memOp->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + Opnd * base = memOp->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + + Inst * inst = base->getDefiningInst(); + if (!inst) + return true; + + SubOpndsTable table(base, disp); + walkThroughOpnds(table); + if(!table.baseOp) + table.baseOp = table.suspOp; + + if(base->getRefCount() > refCountThreshold) { + if (table.indexOp) { + Inst* newIns = irManager->newInst(Mnemonic_LEA, base, irManager->newMemOpnd(irManager->getTypeManager().getUnmanagedPtrType(memOp->getType()), table.baseOp, table.indexOp, table.scaleOp, table.dispOp)); + newIns->insertAfter(inst); + return false; + } + } else { + if (table.baseOp) { + memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Base, table.baseOp); + } + if (table.indexOp) { + memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Index, table.indexOp); + if (table.scaleOp) { + memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Scale, table.scaleOp); + } else { + assert(0); + } + } + if (table.dispOp) { + memOp->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, table.dispOp); + + } + } + return true; }//end ComplexAddrFormLoader::findAddressComputation bool ComplexAddrFormLoader::checkIsScale(Inst * inst) { - Opnd * opnd = inst->getOpnd(3); - if(opnd->isPlacedIn(OpndKind_Imm)) { - switch(opnd->getImmValue()) { - case 1: - case 2: - case 4: - case 8: - return true; - default: - return false; - } - } - return false; + Opnd * opnd = inst->getOpnd(3); + if(opnd->isPlacedIn(OpndKind_Imm)) { + switch(opnd->getImmValue()) { + case 1: + case 2: + case 4: + case 8: + return true; + default: + return false; + } + } + return false; } void ComplexAddrFormLoader::walkThroughOpnds(SubOpndsTable& table) { - - Opnd * opnd; - if (table.baseCand1) - opnd = table.baseCand1; - else if(table.baseCand2) - opnd = table.baseCand2; - else - opnd = table.suspOp; - - Inst * instUp = opnd->getDefiningInst(); - - for(;instUp!=NULL && instUp->getMnemonic() == Mnemonic_MOV;instUp = instUp->getOpnd(1)->getDefiningInst()); - if(!instUp) { - if(!table.baseOp) - table.baseOp = opnd; - if (table.baseCand1) { - table.baseCand1 = NULL; - walkThroughOpnds(table); - } - return; - } - - uint32 defCount = instUp->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); - if(instUp->getMnemonic()==Mnemonic_ADD) { - if(instUp->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm)) { - if(table.dispOp) { - if (table.dispOp->getType()->isInteger() && instUp->getOpnd(defCount+1)->getType()->isInteger()) { - table.suspOp = instUp->getOpnd(defCount); - table.dispOp = irManager.newImmOpnd(table.dispOp->getType(), table.dispOp->getImmValue() + instUp->getOpnd(defCount+1)->getImmValue()); - } - return; - } else { - table.suspOp = instUp->getOpnd(defCount); - table.dispOp=instUp->getOpnd(defCount+1); - } - if (table.baseCand1) - table.baseCand1 = NULL; - walkThroughOpnds(table); - }else if(table.baseCand1) { - assert(!table.baseOp); - table.baseOp = table.baseCand1; - table.baseCand1 = NULL; - walkThroughOpnds(table); - }else if(table.baseCand2) { - assert(table.baseOp); - table.baseOp = table.suspOp; - }else if(!table.baseOp) { - table.baseCand1 = instUp->getOpnd(defCount); - table.baseCand2 = instUp->getOpnd(defCount+1); - walkThroughOpnds(table); - } else { - table.baseOp = table.suspOp; - } - } else if(instUp->getMnemonic()==Mnemonic_IMUL && checkIsScale(instUp)) { - table.indexOp = instUp->getOpnd(defCount); - table.scaleOp = instUp->getOpnd(defCount+1); - if(table.baseCand1) { - table.baseCand1 = NULL; - table.suspOp = table.baseCand2; - table.baseCand2 = NULL; - walkThroughOpnds(table); - } - } else { - table.baseOp = opnd; - } + Opnd * opnd; + if (table.baseCand1) + opnd = table.baseCand1; + else if(table.baseCand2) + opnd = table.baseCand2; + else + opnd = table.suspOp; + + Inst * instUp = opnd->getDefiningInst(); + + for(;instUp!=NULL && instUp->getMnemonic() == Mnemonic_MOV;instUp = instUp->getOpnd(1)->getDefiningInst()); + if(!instUp) { + if(!table.baseOp && !opnd->isPlacedIn(OpndKind_Mem)) { + table.baseOp = opnd; + if (table.baseCand1) { + table.baseCand1 = NULL; + walkThroughOpnds(table); + } + } + return; + } + + uint32 defCount = instUp->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); + if(instUp->getMnemonic()==Mnemonic_ADD) { + Opnd * src1 = instUp->getOpnd(defCount); + Opnd * src2 = instUp->getOpnd(defCount+1); + if(src1->isPlacedIn(OpndKind_Mem) || (src2->isPlacedIn(OpndKind_Mem))) { + table.baseOp = table.suspOp; + return; + } else if(src2->isPlacedIn(OpndKind_Imm)) { + irManager->resolveRuntimeInfo(src2); +#ifdef _EM64T_ + if((src2->getImmValue() > (int64)0x7FFFFFFF) || (src2->getImmValue() < -((int64)0x10000000))) { + table.baseOp = table.suspOp; + return; + } +#endif + + if (table.baseCand1) { + table.baseCand1 = NULL; + table.baseOp = src1; + } else if (table.baseCand2) { + if(!table.baseOp) + table.baseOp = src1; + else { + table.baseOp = table.suspOp; + return; + } + } else { + table.suspOp = src1; + } + + if(table.dispOp) { + irManager->resolveRuntimeInfo(table.dispOp); + table.dispOp = irManager->newImmOpnd(table.dispOp->getType(), table.dispOp->getImmValue() + src2->getImmValue()); + return; + } else { + table.dispOp = src2; + } + walkThroughOpnds(table); + }else if(table.baseCand1) { + assert(!table.baseOp); + table.baseOp = table.baseCand1; + table.baseCand1 = NULL; + walkThroughOpnds(table); + }else if(table.baseCand2) { + assert(table.baseOp); + table.baseOp = table.suspOp; + }else if(!table.baseOp) { + table.baseCand1 = src1; + table.baseCand2 = src2; + walkThroughOpnds(table); + } else { + table.baseOp = table.suspOp; + } + } else if(instUp->getMnemonic()==Mnemonic_IMUL && checkIsScale(instUp)) { + table.indexOp = instUp->getOpnd(defCount); + table.scaleOp = instUp->getOpnd(defCount+1); + if(table.baseCand1) { + table.baseCand1 = NULL; + table.suspOp = table.baseCand2; + table.baseCand2 = NULL; + walkThroughOpnds(table); + } + } else { + table.baseOp = table.suspOp; + } } } //end namespace Ia32 } diff --git vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.h vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.h deleted file mode 100644 index a123e60..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32ComplexAddrFormLoader.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Nikolay A. Sidelnikov - * @version $Revision: 1.10.14.1.4.3 $ - */ - -#ifndef _IA32_COMPLEXADDRFORMLOADER_H_ -#define _IA32_COMPLEXADDRFORMLOADER_H_ - -#include "Ia32CodeGenerator.h" -#include "Ia32CFG.h" -#include "Ia32IRManager.h" -#include "Ia32Inst.h" -#include "open/types.h" -#include "Stl.h" -#include "MemoryManager.h" -#include "Type.h" -namespace Jitrino -{ -namespace Ia32{ - -struct SubOpndsTable { - Opnd * baseOp; - Opnd * indexOp; - Opnd * scaleOp; - Opnd * dispOp; - Opnd * baseCand1; - Opnd * baseCand2; - Opnd * suspOp; - - SubOpndsTable(Opnd * s, Opnd * disp) : baseOp(NULL), indexOp(NULL), scaleOp(NULL), dispOp(disp), baseCand1(NULL), baseCand2(NULL), suspOp(s) {} -}; - -BEGIN_DECLARE_IRTRANSFORMER(ComplexAddrFormLoader, "cafl", "Complex Address Form Loader") - IRTRANSFORMER_CONSTRUCTOR(ComplexAddrFormLoader) - void runImpl(); -protected: - //fill complex address form - bool findAddressComputation(Opnd * memOp); - bool checkIsScale(Inst * inst); - void walkThroughOpnds(SubOpndsTable& table); -private: - uint32 refCountThreshold; -END_DECLARE_IRTRANSFORMER(ComplexAddrFormLoader) - -} //end namespace Ia32 -} -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp index db10e28..6fad7b6 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32Constraint.cpp @@ -33,134 +33,147 @@ const Constraint Constraint::nullConstra //================================================================================================= const char * Constraint::parse(const char * str) { - Constraint szc, kc; - for (uint32 i=0, j=0; i<0x100 && *str;){ - const char * tokenEnd=str; char token[0x100]; - for (j=0; j<0x100 && *tokenEnd && (isalpha(*tokenEnd)||isdigit(*tokenEnd)); tokenEnd++, j++) - token[j]=*tokenEnd; - token[j]=0; - - if (tokenEnd>str){ - - RegName r=getRegName(token); - if (r!=RegName_Null){ - if (!kc.canBeMergedWith(r)) - return NULL; - kc.unionWith(r); - }else{ - OpndKind k=getOpndKind(token); - if (k!=OpndKind_Null){ - if (!kc.canBeMergedWith(k)) - return NULL; - kc.unionWith(k); - }else{ - OpndSize sz=getOpndSize(token); - if (sz!=OpndSize_Null){ - Constraint c(OpndKind_Any, sz); - if (!szc.canBeMergedWith(c)) - return NULL; - szc=c; - }else - return NULL; - } - } - str=tokenEnd; - }else - str++; - } - if (szc.isNull()) - szc=Constraint(OpndKind_Any, OpndSize_Any); - if (kc.isNull()) - kc=Constraint(OpndKind_Any); - *this=szc&kc; - return str; + Constraint szc, kc; + for (uint32 i=0, j=0; i<0x100 && *str;){ + const char * tokenEnd=str; char token[0x100]; + for (j=0; j<0x100 && *tokenEnd && (isalpha(*tokenEnd)||isdigit(*tokenEnd)); tokenEnd++, j++) + token[j]=*tokenEnd; + token[j]=0; + + if (tokenEnd>str){ + + RegName r=getRegName(token); + if (r!=RegName_Null){ + if (!kc.canBeMergedWith(r)) + return NULL; + kc.unionWith(r); + }else{ + OpndKind k=getOpndKind(token); + if (k!=OpndKind_Null){ + if (!kc.canBeMergedWith(k)) + return NULL; + kc.unionWith(k); + }else{ + OpndSize sz=getOpndSize(token); + if (sz!=OpndSize_Null){ + Constraint c(OpndKind_Any, sz); + if (!szc.canBeMergedWith(c)) + return NULL; + szc=c; + }else + return NULL; + } + } + str=tokenEnd; + }else + str++; + } + if (szc.isNull()) + szc=Constraint(OpndKind_Any, OpndSize_Any); + if (kc.isNull()) + kc=Constraint(OpndKind_Any); + *this=szc&kc; + return str; } //_________________________________________________________________________________________________ OpndSize Constraint::getDefaultSize(uint32 k) { - OpndKind regKind=(OpndKind)(k & OpndKind_Reg); - if (regKind){ - switch(regKind){ - case OpndKind_SReg: return OpndSize_16; - case OpndKind_FPReg: return OpndSize_80; - case OpndKind_XMMReg: return OpndSize_128; - case OpndKind_GPReg: return OpndSize_32; - case OpndKind_StatusReg: return OpndSize_32; - default: return OpndSize_Any; - } - } - return OpndSize_Any; + OpndKind regKind=(OpndKind)(k & OpndKind_Reg); + if (regKind){ + switch(regKind){ + case OpndKind_SReg: return OpndSize_16; + case OpndKind_FPReg: return OpndSize_80; + case OpndKind_XMMReg: return OpndSize_128; +#ifdef _EM64T_ + case OpndKind_GPReg: return OpndSize_64; +#else + case OpndKind_GPReg: return OpndSize_32; +#endif + case OpndKind_StatusReg: return OpndSize_32; + default: return OpndSize_Any; + } + } + return OpndSize_Any; } //_________________________________________________________________________________________________ Constraint Constraint::getAliasConstraint(OpndSize s, uint32 offset)const { - OpndSize sz=(OpndSize)size; - if (s==OpndSize_Default){ - s=getDefaultSize(kind); - if (s==OpndSize_Any) - s=sz; - } - if (sz==s || s==OpndSize_Null || sz==OpndSize_Null) - return *this; - if (sz>s) - return Constraint(); - - uint32 newKind=kind, newMask=0; - uint32 newRegKind=newKind & OpndKind_Reg; - if (newRegKind==OpndKind_GPReg){ - if (sz==OpndSize_8 && (s==OpndSize_16 || s==OpndSize_32)) - newMask=((mask>>4)|mask)&0xf; - else if (sz==OpndSize_16) - newMask=mask; - }else if (newRegKind==OpndKind_FPReg || newRegKind==OpndKind_XMMReg){ - newMask=mask; - } - if (newMask==0) newKind&=~OpndKind_Reg; - return newKind==OpndKind_Null?Constraint():Constraint( (OpndKind)newKind, s, newMask); + OpndSize sz=(OpndSize)size; + if (s==OpndSize_Default){ + s=getDefaultSize(kind); + if (s==OpndSize_Any) + s=sz; + } + if (sz==s || s==OpndSize_Null || sz==OpndSize_Null) + return *this; + if (sz>s) + return Constraint(); + + uint32 newKind=kind, newMask=0; + uint32 newRegKind=newKind & OpndKind_Reg; + if (newRegKind==OpndKind_GPReg){ +#ifndef _EM64T_ + if (sz==OpndSize_8 && (s==OpndSize_16 || s==OpndSize_32)) + newMask=((mask>>4)|mask)&0xf; + else if (sz==OpndSize_16) + newMask=mask; +#else + newMask=mask; +#endif + }else if (newRegKind==OpndKind_FPReg || newRegKind==OpndKind_XMMReg){ + newMask=mask; + } + if (newMask==0) newKind&=~OpndKind_Reg; + return newKind==OpndKind_Null?Constraint():Constraint( (OpndKind)newKind, s, newMask); } //_________________________________________________________________________________________________ RegName Constraint::getAliasRegName(RegName regName, OpndSize sz, uint32 offset) { - if (regName==RegName_Null) - return RegName_Null; - OpndSize s=getRegSize(regName); - if (sz==OpndSize_Any){ - sz=getDefaultSize(getRegKind(regName)); - if (sz==OpndSize_Any) - sz=s; - } - if (sz==s) - return regName; - if (sz>s) - return RegName_Null; - - OpndKind regKind=getRegKind(regName); - - if (regKind==OpndKind_GPReg){ - if (sz==OpndSize_8 && (s==OpndSize_16 || s==OpndSize_32)){ - uint32 idx=getRegIndex(regName); - if (idx>4) - return RegName_Null; - return getRegName(regKind, sz, idx); - }else if (sz==OpndSize_16) - return getRegName(regKind, sz, getRegIndex(regName)); - }else if (regKind==OpndKind_FPReg){ - return getRegName(regKind, sz, getRegIndex(regName)); - }else if (regKind==OpndKind_XMMReg){ - return getRegName(regKind, sz, getRegIndex(regName)); - } - - return RegName_Null; + if (regName==RegName_Null) + return RegName_Null; + OpndSize s=getRegSize(regName); + if (sz==OpndSize_Any){ + sz=getDefaultSize(getRegKind(regName)); + if (sz==OpndSize_Any) + sz=s; + } + if (sz==s) + return regName; + if (sz>s) + return RegName_Null; + + OpndKind regKind=getRegKind(regName); + + if (regKind==OpndKind_GPReg){ +#ifndef _EM64T_ + if (sz==OpndSize_8 && (s==OpndSize_16 || s==OpndSize_32)){ + uint32 idx=getRegIndex(regName); + if (idx>4) + return RegName_Null; + return getRegName(regKind, sz, idx); + }else if (sz==OpndSize_16) { + return getRegName(regKind, sz, getRegIndex(regName)); + } +#else + return getRegName(regKind, sz, getRegIndex(regName)); +#endif + }else if (regKind==OpndKind_FPReg){ + return getRegName(regKind, sz, getRegIndex(regName)); + }else if (regKind==OpndKind_XMMReg){ + return getRegName(regKind, sz, getRegIndex(regName)); + } + + return RegName_Null; } //_________________________________________________________________________________________________ RegName Constraint::getAliasRegName(RegName regName, uint32 offset)const { - RegName rn=getAliasRegName(regName, (OpndSize)size, offset); - return contains(rn)?rn:RegName_Null; + RegName rn=getAliasRegName(regName, (OpndSize)size, offset); + return contains(rn)?rn:RegName_Null; } diff --git vm/jitrino/src/codegenerator/ia32/Ia32Constraint.h vm/jitrino/src/codegenerator/ia32/Ia32Constraint.h index 40c5faa..16ccdea 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Constraint.h +++ vm/jitrino/src/codegenerator/ia32/Ia32Constraint.h @@ -35,7 +35,7 @@ The constraint framework is similar to a with partial order set by the contains method The constraint contains 4 fields: - OpndKind kind, OpndSize size, and register mask + OpndKind kind, OpndSize size, and register mask Each constraint instance is exactly 4-bytes long making it possible to pass it directly by value. @@ -45,186 +45,186 @@ it directly by value. class Constraint { public: - //---------------------------------------------------------------------- - /** enum CompareResult represent results of Constraint::compare - - The values are self-documenting - */ - enum CompareResult - { - CompareResult_Equal=0, - CompareResult_LeftContainsRight=1, - CompareResult_RightContainsLeft=-1, - CompareResult_NotEqual=2 - }; - - //---------------------------------------------------------------------- - /** Creates a Null constraint */ - Constraint() - { fullValue = 0;} - - /** Creates a constraint of the specified OpndKind - This allows for passing of OpndKind values wherever Constraint is expected + //---------------------------------------------------------------------- + /** enum CompareResult represent results of Constraint::compare + + The values are self-documenting + */ + enum CompareResult + { + CompareResult_Equal=0, + CompareResult_LeftContainsRight=1, + CompareResult_RightContainsLeft=-1, + CompareResult_NotEqual=2 + }; + + //---------------------------------------------------------------------- + /** Creates a Null constraint */ + Constraint() + { fullValue = 0;} + + /** Creates a constraint of the specified OpndKind + This allows for passing of OpndKind values wherever Constraint is expected The size of the constraint is set to OpndSize_Any - For OpndKind_Reg and sub-kinds initializes the mask field to 0xffff - */ - Constraint(OpndKind k) - :mask(OpndKind_Reg&k?0xffff:0), size(OpndSize_Any), kind(k) - { assert(k!=OpndKind_Null); } + For OpndKind_Reg and sub-kinds initializes the mask field to 0xffff + */ + Constraint(OpndKind k) + :mask(OpndKind_Reg&k?0xffff:0), size(OpndSize_Any), kind(k) + { assert(k!=OpndKind_Null); } - /** Creates a constraint of the specified OpndKind k and OpndSize s + /** Creates a constraint of the specified OpndKind k and OpndSize s - Both k and s cannot be _Null. + Both k and s cannot be _Null. - If k contains OpndKind_Reg the constructor initializes the mask field to 0xffff - */ - Constraint(OpndKind k, OpndSize s) - :mask(OpndKind_Reg&k?0xffff:0), size(s), kind(k) - { assert(k!=OpndKind_Null && size!=OpndSize_Null); } + If k contains OpndKind_Reg the constructor initializes the mask field to 0xffff + */ + Constraint(OpndKind k, OpndSize s) + :mask(OpndKind_Reg&k?0xffff:0), size(s), kind(k) + { assert(k!=OpndKind_Null && size!=OpndSize_Null); } - /** Creates a constraint of the specified OpndKind, OpndSize, and register mask m + /** Creates a constraint of the specified OpndKind, OpndSize, and register mask m - Both k and s cannot be _Null, and k must contain be OpndKind_Reg if mask is not null + Both k and s cannot be _Null, and k must contain be OpndKind_Reg if mask is not null - For OpndKind_Reg and sub-kinds initializes the mask field to 0xffff - */ - Constraint(OpndKind k, OpndSize s, uint32 m) - :mask(m), size(s), kind(k) - { assert(k!=OpndKind_Null && size!=OpndSize_Null); assert(mask==0||(OpndKind_Reg&k)!=0); } + For OpndKind_Reg and sub-kinds initializes the mask field to 0xffff + */ + Constraint(OpndKind k, OpndSize s, uint32 m) + :mask(m), size(s), kind(k) + { assert(k!=OpndKind_Null && size!=OpndSize_Null); assert(mask==0||(OpndKind_Reg&k)!=0); } - /** Creates a constraint corresponding to the specified physical register RegName - This allows for passing of RegName values wherever Constraint is expected + /** Creates a constraint corresponding to the specified physical register RegName + This allows for passing of RegName values wherever Constraint is expected The size of the constraint is initialized to the size for the specified RegName - returned by getRegSize(OpndKind) - - The mask field of the constraint is initialized to the mask corresponding to the specified register - */ - Constraint(RegName reg) - :mask(getRegMask(reg)), size(getRegSize(reg)), kind(getRegKind(reg)) {} - - - Constraint(const char * str){ fullValue = 0; str=parse(str); assert(str!=NULL); } - - const char * parse(const char * str); - - //---------------------------------------------------------------------- - /** returns the kind field of the constraint */ - uint32 getKind()const{ return kind; } - /** returns the size field of the constraint */ - OpndSize getSize()const{ return (OpndSize)size; } - /** returns the mask field of the constraint */ - uint32 getMask()const{ return mask; } - - /** sets the mask field of the constraint */ - void setMask(uint32 m){ mask=m; } - - /** resets the constraint to the Null value */ - void makeNull(){ fullValue = 0; } - - /** resets the constraint to the Any value */ - void makeAny() - { fullValue = OpndKind_Any|OpndSize_Any|0xffff; } - - /** Convenience operator | - - Creates a copy of 'this' constraint, unions it with c, and returns the result - */ - Constraint operator|(Constraint c)const - { Constraint l=*this; l.unionWith(c); return l; } - - /** Convenience operator & - - Creates a copy of 'this' constraint, intersects it with c, and returns the result - */ - Constraint operator&(Constraint c)const - { Constraint l=*this; l.intersectWith(c); return l; } - - /** Returns true if the constraint is Null (its kind is Null) */ - bool isNull()const{ return kind==OpndKind_Null; } - - /** Returns the default size for the OpndKind combination k */ - static OpndSize getDefaultSize(uint32 k); - - /** Returns true if 'this' can be merged (via unionWith) with c - - Sizes must be equal, and kinds cannot designate different reg kinds (like GPReg vs XMMReg) - - Note: Null constraints are mergeable with any constraints - */ - bool canBeMergedWith(Constraint c) - { - uint32 filter = (uint32)OpndKind_Reg << 24; - uint32 thisTmp = fullValue & filter, cTmp = c.fullValue & filter, rTmp = thisTmp & cTmp; - if (rTmp!=thisTmp && rTmp!=cTmp) - return false; - filter = (uint32)OpndSize_Any << 16; - thisTmp = fullValue & filter, cTmp = c.fullValue & filter, rTmp = thisTmp & cTmp; - return rTmp==thisTmp || rTmp==cTmp; - } - - /** Unions 'this' with c (|-like) - - this must be mergeable with c (canBeMergedWith(c) must return true) - - */ - Constraint& unionWith(Constraint c) - { assert(canBeMergedWith(c)); fullValue |= c.fullValue; return *this; } - - /** Intersects 'this' constraint with c (&-like) */ - Constraint& intersectWith(Constraint c) - { - fullValue &= c.fullValue; - if (size==0 || kind==0) fullValue=0; else if (mask==0) kind&=~OpndKind_Reg; - return *this; - } - - /** returns true if 'this' constrains contains c */ - bool contains(Constraint c)const{ return (*this&c)==c; } - - /** returns true if 'this' constraint exactly equals to c */ - bool operator==(Constraint c)const - { return fullValue == c.fullValue; } - bool operator!=(Constraint c)const - { return fullValue != c.fullValue; } - - /** Determines the relationship of between 'this' constraint and c - - The semantics of the operation and possible result values are defined by the CompareResult enumeration - */ - CompareResult compare(Constraint c)const - { return *this==c?CompareResult_Equal:contains(c)?CompareResult_LeftContainsRight:c.contains(*this)?CompareResult_RightContainsLeft:CompareResult_NotEqual; } - - /** Returns the constraint for an outer aliased operand - s must be greater than or equal to the constraint's size - */ - Constraint getAliasConstraint(OpndSize s, uint32 offset=0)const; - - - /** Returns the regname for an aliased regname - In some sense this operations is reverse to getAliasConstraint. - e.g. for eax it can return eax, ax, ah, al, depending on the constraint - The constraint's size must be less than or equal to regName's size - */ - static RegName getAliasRegName(RegName regName, OpndSize s, uint32 offset=0); - RegName getAliasRegName(RegName regName, uint32 offset=0)const; - - //---------------------------------------------------------------------- + returned by getRegSize(OpndKind) + + The mask field of the constraint is initialized to the mask corresponding to the specified register + */ + Constraint(RegName reg) + :mask(getRegMask(reg)), size(getRegSize(reg)), kind(getRegKind(reg)) {} + + + Constraint(const char * str){ fullValue = 0; str=parse(str); assert(str!=NULL); } + + const char * parse(const char * str); + + //---------------------------------------------------------------------- + /** returns the kind field of the constraint */ + uint32 getKind()const{ return kind; } + /** returns the size field of the constraint */ + OpndSize getSize()const{ return (OpndSize)size; } + /** returns the mask field of the constraint */ + uint32 getMask()const{ return mask; } + + /** sets the mask field of the constraint */ + void setMask(uint32 m){ mask=m; } + + /** resets the constraint to the Null value */ + void makeNull(){ fullValue = 0; } + + /** resets the constraint to the Any value */ + void makeAny() + { fullValue = OpndKind_Any|OpndSize_Any|0xffff; } + + /** Convenience operator | + + Creates a copy of 'this' constraint, unions it with c, and returns the result + */ + Constraint operator|(Constraint c)const + { Constraint l=*this; l.unionWith(c); return l; } + + /** Convenience operator & + + Creates a copy of 'this' constraint, intersects it with c, and returns the result + */ + Constraint operator&(Constraint c)const + { Constraint l=*this; l.intersectWith(c); return l; } + + /** Returns true if the constraint is Null (its kind is Null) */ + bool isNull()const{ return kind==OpndKind_Null; } + + /** Returns the default size for the OpndKind combination k */ + static OpndSize getDefaultSize(uint32 k); + + /** Returns true if 'this' can be merged (via unionWith) with c + + Sizes must be equal, and kinds cannot designate different reg kinds (like GPReg vs XMMReg) + + Note: Null constraints are mergeable with any constraints + */ + bool canBeMergedWith(Constraint c) + { + uint32 filter = (uint32)OpndKind_Reg << 24; + uint32 thisTmp = fullValue & filter, cTmp = c.fullValue & filter, rTmp = thisTmp & cTmp; + if (rTmp!=thisTmp && rTmp!=cTmp) + return false; + filter = (uint32)OpndSize_Any << 16; + thisTmp = fullValue & filter, cTmp = c.fullValue & filter, rTmp = thisTmp & cTmp; + return rTmp==thisTmp || rTmp==cTmp; + } + + /** Unions 'this' with c (|-like) + + this must be mergeable with c (canBeMergedWith(c) must return true) + + */ + Constraint& unionWith(Constraint c) + { assert(canBeMergedWith(c)); fullValue |= c.fullValue; return *this; } + + /** Intersects 'this' constraint with c (&-like) */ + Constraint& intersectWith(Constraint c) + { + fullValue &= c.fullValue; + if (size==0 || kind==0) fullValue=0; else if (mask==0) kind&=~OpndKind_Reg; + return *this; + } + + /** returns true if 'this' constrains contains c */ + bool contains(Constraint c)const{ return (*this&c)==c; } + + /** returns true if 'this' constraint exactly equals to c */ + bool operator==(Constraint c)const + { return fullValue == c.fullValue; } + bool operator!=(Constraint c)const + { return fullValue != c.fullValue; } + + /** Determines the relationship of between 'this' constraint and c + + The semantics of the operation and possible result values are defined by the CompareResult enumeration + */ + CompareResult compare(Constraint c)const + { return *this==c?CompareResult_Equal:contains(c)?CompareResult_LeftContainsRight:c.contains(*this)?CompareResult_RightContainsLeft:CompareResult_NotEqual; } + + /** Returns the constraint for an outer aliased operand + s must be greater than or equal to the constraint's size + */ + Constraint getAliasConstraint(OpndSize s, uint32 offset=0)const; + + + /** Returns the regname for an aliased regname + In some sense this operations is reverse to getAliasConstraint. + e.g. for eax it can return eax, ax, ah, al, depending on the constraint + The constraint's size must be less than or equal to regName's size + */ + static RegName getAliasRegName(RegName regName, OpndSize s, uint32 offset=0); + RegName getAliasRegName(RegName regName, uint32 offset=0)const; + + //---------------------------------------------------------------------- private: - union{ - struct { - uint32 mask:16; - uint32 size:8; - uint32 kind:8; - }; - uint32 fullValue; - }; - - friend struct DefaultConstraintInitializer; - - const static Constraint nullConstraint; + union{ + struct { + uint32 mask:16; + uint32 size:8; + uint32 kind:8; + }; + uint32 fullValue; + }; + + friend struct DefaultConstraintInitializer; + + const static Constraint nullConstraint; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp index 49c12e2..ccfde23 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32ConstraintsResolver.cpp @@ -18,212 +18,296 @@ * @version $Revision: 1.11.14.2.4.3 $ */ -#include "Ia32ConstraintsResolver.h" +#include "Ia32IRManager.h" +#include "Ia32Printer.h" namespace Jitrino { namespace Ia32{ //======================================================================================== +// class Ia32ConstraintsResolver +//======================================================================================== +/** + * class Ia32ConstraintsResolver performs resolution of operand constraints + * and assigns calculated constraints (Opnd::ConstraintKind_Calculated) to operands. + * The resulting calculated constraints of operands determine allowable physical location + * for the operand. + * + * This transformer allows to insert operands into instructions before it + * regardless instruction constraints except that Initial constraints of explicit + * instruction operands must have non-null intersections with corresponding constraints + * of at least one opcode group of the instruction. + * + * ConstraintResolver analyzes instruction constraints and splits operands when necessary. + * + * This transformer ensures that + * 1) All instruction constraints for EntryPoints, CALLs and RETs + * are set appropriately (IRManager::applyCallingConventions()) + * 2) All operands has non-null calculated constraints + * 3) All operands fits into instructions they are used in (in terms of instruction constraints) + * For example: + * Original code piece: + * I38: (AD:s65:double) =CopyPseudoInst (AU:t1:double) + * I32: MULSD .s65.:double,.t2:double + * I33: RET t66(0):int16 (AU:s65:double) + * + * RET imposes constraint on s65 requiring to place it into FP0 register + * (its FP0D alias in this particular case) + * MULSD imposes constraint on s65 requiring to place it into XMM register + * + * After the pass: + * I38: (AD:s65:double) =CopyPseudoInst (AU:t1:double) + * I32: MULSD .s65.:double,.t2:double + * I46: (AD:t75:double) =CopyPseudoInst (AU:s65:double) + * I33: RET t66(20):int16 (AU:t75:double) + * + * Thus, ConstraintResolver inserted I46 splitting s65 to s65 and t75 + * s65 is assigned with Mem|XMM calculated constraint and t75 + * is assigned with FP0D calculated calculated constraint + * + * 4) If the live range of an operand crosses a call site and the operand is not redefined + * in the call site, the calculated constraint of the operand is narrowed the callee-save regs + * or memory (stack) + * + * 5) If the operand (referred as original operand here) is live at entry of a catch handler + * then necessary operand splitting is performed as close as possible to the instruction + * which caused the splitting and original operand is used before and after the instruction. + * + * The main principle of the algorithm is anding of instruction constraints into + * operand calculated constraints and splitting operands to ensure that the calculated constraint + * is not null + * + * This transformer must be inserted before register allocator which relies on + * calculated operand constraints. + * + * The implementation of this transformer is located in the ConstraintResolverImpl class. + * + */ + +class ConstraintsResolver : public SessionAction { + /** runImpl is required override, calls ConstraintsResolverImpl.runImpl */ + void runImpl(); + /** This transformer requires up-to-date liveness info */ + uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo; } + uint32 getSideEffects()const{ return 0; } +}; + +static ActionFactory _constraints("constraints"); + +//======================================================================================== // class ConstraintsResolverImpl //======================================================================================== /** - * class Ia32ConstraintsResolverImpl is implementation of simple constraint resolution algorithm - * The algorithm takes one-pass over CFG. + * class Ia32ConstraintsResolverImpl is an implementation of simple constraint resolution algorithm + * The algorithm takes one-pass over CFG. + * + * The algorithm works as follows: + * + * 1) Creates an array of basic blocks and orders by bb->getExecCount() + * in createBasicBlockArray(). + * Thus, the algorithm handles hottest basic blocks first and constraints are assigned to operands first + * from the most frequently used instructions * - * The algorithm works as follows: - * - * 1) Creates an array of basic blocks and orders by bb->getExecCnt() - * in createBasicBlockArray(). - * Thus, the algorithm handles hottest basic blocks first and constraints are assigned to operands first - * from the most frequently used instructions + * 2) Collects a bit vector of all operands live at entries of all dispatch node entries + * in calculateLiveAtDispatchBlockEntries() * - * 2) Collects a bit vector of all operands live at entries of all dispatch node entries - * in calculateLiveAtDispatchBlockEntries() + * 3) For all operands: + * - If an operand has already been assigned to some location + * (its location constraint is not null) the calculated constraint is set to + * the location constraint + * + * - If an operand is live at entry of a dispatch node + * the calculated constraint is set to the constraint + * preserving operand values during exception throwing + * This constraint is returned by getDispatchEntryConstraint + * In fact this is the constriant for the DRL calling convention * - * 3) For all operands: - * c0) has already been assigned to some location (its location constraint is not null) - * c1) or has some Initial constraint with kind!=OpndKind_Any - * c2) or is live at entry of a dispatch node - * the calculated constraint is pre-set to these constraints - * This is done in calculateStartupOpndConstraints() + * This is done in calculateStartupOpndConstraints() + * Originally all calculateed constraints are equial to Initial constraints * - * 4) Walks through all basic blocks collected and arranged at step 1 - * in resolveConstraints() + * 4) Walks through all basic blocks collected and arranged at step 1 + * in resolveConstraints() * - * The opndReplaceWorkset array of operand replacements is maintained - * (indexed by from-operand id). + * The opndReplaceWorkset array of operand replacements is maintained + * (indexed by from-operand id). * - * This is the array of current replacement for operands - * and is reset for each basic block (local within basic blocks) + * This is the array of current replacement for operands + * and is reset for each basic block (local within basic blocks) * - * This array is filled as a result of operand splitting and indicates - * which operand must be used instead of original ones for all the instructions - * above the one caused splitting - * - * 4.1) Walks throw all instruction of a basic block in backward order - * in resolveConstraints(BasicBlock * bb) - * 4.1.1) resolves constraints for each instruction - * in resolveConstraints(Inst * inst); - * - * To do this already collected calculated constraint of - * either original operand or its current replacement is anded - * with instruction constraint for this operand occurence and - * if the result is null, new operand is created and substituted instead - * - * 4.1.1.1) All def operands of the isntruction are traversed - * and operand splitting is performed after the instruction (when necessary) - * def&use cases are also handled during this step - * 4.1.1.2) If the instruction is CALL, all hovering operands of - * the isntruction are traversed. + * This array is filled as a result of operand splitting and indicates + * which operand must be used instead of original ones for all the instructions + * above the one caused splitting + * + * 4.1) Walks throw all instruction of a basic block in backward order + * in resolveConstraints(BasicBlock * bb) + * 4.1.1) resolves constraints for each instruction + * in resolveConstraints(Inst * inst); + * + * To do this already collected calculated constraint of + * either original operand or its current replacement is anded + * with instruction constraint for this operand occurence and + * if the result is null, new operand is created and substituted instead + * + * 4.1.1.1) All def operands of the isntruction are traversed + * and operand splitting is performed after the instruction (when necessary) + * def&use cases are also handled during this step + * 4.1.1.2) If the instruction is CALL, all hovering operands of + * the isntruction are traversed. * - * Hovering operands are operands which are live across a call site and are not - * redefined in the call site - * This step ensures operands are saved in callee-save regs or memory - * and takes into account whether an operand is live at dispatch node entries + * Hovering operands are operands which are live across a call site and are not + * redefined in the call site + * This step ensures operands are saved in callee-save regs or memory + * and takes into account whether an operand is live at dispatch node entries * - * Operand splitting is performed before the instruction (when necessary) - * 4.1.1.3) All use operands of the instruction are traversed - * and operand splitting is performed before the instruction (when necessary) - * - * For more details please refer to ConstraintsResolverImpl source code + * Operand splitting is performed before the instruction (when necessary) + * 4.1.1.3) All use operands of the instruction are traversed + * and operand splitting is performed before the instruction (when necessary) + * + * The current implementation doesn't deal properly with conditional memory constraints. + * I.e. it doesn't resolve properly things like ADD m, m when both operands are already + * assigned. + * + * For more details please refer to ConstraintsResolverImpl source code */ class ConstraintsResolverImpl { public: - ConstraintsResolverImpl(IRManager &irm) - :irManager(irm), - memoryManager(irManager.getOpndCount()*16, "ConstraintsResolverImpl"), + ConstraintsResolverImpl(IRManager &irm) + :irManager(irm), + memoryManager(irManager.getOpndCount()*16, "ConstraintsResolverImpl"), basicBlocks(memoryManager, 0), originalOpndCount(0), - liveOpnds(memoryManager,0), - liveAtDispatchBlockEntry(memoryManager,0), - needsOriginalOpnd(memoryManager,0), - hoveringOpnds(memoryManager,0), - opndReplaceWorkset(memoryManager,0) - { - } - - void run(); + liveOpnds(memoryManager,0), + liveAtDispatchBlockEntry(memoryManager,0), + needsOriginalOpnd(memoryManager,0), + hoveringOpnds(memoryManager,0), + opndReplaceWorkset(memoryManager,0) + { + } + + void run(); private: /** Get the priority of a the node for sorting in createBasicBlockArray */ - ExecCntValue getBasicBlockPriority(Node * node); + double getBasicBlockPriority(Node * node); /** Fills the basicBlocks array and orders it according to block exec count (hottest first) */ - void createBasicBlockArray(); - /** Fills the liveAtDispatchBlockEntry bit set with operands live at dispatch node entries */ - void calculateLiveAtDispatchBlockEntries(); - /** Pre-sets calculated constraints for each operand if conditions c0-c2 are met */ - void calculateStartupOpndConstraints(); - /** Scans basicBlocks array and calls resolveConstraints(BasicBlock * bb) for each entry */ - void resolveConstraints(); - /** Traverses instructions of bb and calls resolveConstraints(Inst *) - * for each inst - */ - void resolveConstraints(BasicBlock * bb); - /** - Main logic of constraint resolution for each instrution - */ - void resolveConstraints(Inst * inst); - - /** returns constraint describing call-safe locations for opnd in CallInst inst */ - Constraint getCalleeSaveConstraint(Inst * inst, Opnd * opnd); - /** returns constraint describing safe locations for operands live at dispatch node entries */ - Constraint getDispatchEntryConstraint(Opnd * opnd); - - - /** Reference to IRManager */ - IRManager& irManager; - - /** Private memory manager for this algorithm */ - MemoryManager memoryManager; - - /** Array of basic blocks to be handled */ - StlVector basicBlocks; - - /** result of irManager.getOpndCount before the pass */ - uint32 originalOpndCount; - - /** Current live set, updated as usual for each instruction in resolveConstraints(Inst*) */ - LiveSet liveOpnds; - - /** Bit set of operands live at dispatch node entries */ - BitSet liveAtDispatchBlockEntry; - - /** Bit set of operands met conditions c0-c2 described above */ - BitSet needsOriginalOpnd; - - /** Temporary bit set of hovering operands (live across call sites) - * Is initialized and used only during resolveConstraints(Inst*) - */ - BitSet hoveringOpnds; - - /** An array of current substitutions for operands - * Is filled as a result of operand splitting. - * Reset for each basic blocks (all replacements are local within basic blocks) - */ - StlVector opndReplaceWorkset; + void createBasicBlockArray(); + /** Fills the liveAtDispatchBlockEntry bit set with operands live at dispatch node entries */ + void calculateLiveAtDispatchBlockEntries(); + /** Pre-sets calculated constraints for each operand */ + void calculateStartupOpndConstraints(); + /** Scans basicBlocks array and calls resolveConstraints(BasicBlock * bb) for each entry */ + void resolveConstraints(); + /** Traverses instructions of bb and calls resolveConstraints(Inst *) + * for each inst + */ + void resolveConstraints(Node* bb); + /** + Main logic of constraint resolution for each instrution + */ + void resolveConstraintsWithOG(Inst * inst); + + /** returns constraint describing call-safe locations for opnd in CallInst inst */ + Constraint getCalleeSaveConstraint(Inst * inst, Opnd * opnd); + /** returns constraint describing safe locations for operands live at dispatch node entries */ + Constraint getDispatchEntryConstraint(Opnd * opnd); + + + /** Reference to IRManager */ + IRManager& irManager; + + /** Private memory manager for this algorithm */ + MemoryManager memoryManager; + + /** Array of basic blocks to be handled */ + Nodes basicBlocks; + + /** result of irManager.getOpndCount before the pass */ + uint32 originalOpndCount; + + /** Current live set, updated as usual for each instruction in resolveConstraints(Inst*) */ + BitSet liveOpnds; + + /** Bit set of operands live at dispatch node entries */ + BitSet liveAtDispatchBlockEntry; + + /** Bit set of operands for which original operand should be used wherever possible. + * Currently this is only for operands which are live at dispatch block entries. + */ + BitSet needsOriginalOpnd; + + /** Temporary bit set of hovering operands (live across call sites) + * Is initialized and used only during resolveConstraints(Inst*) + */ + BitSet hoveringOpnds; + + /** An array of current substitutions for operands + * Is filled as a result of operand splitting. + * Reset for each basic blocks (all replacements are local within basic blocks) + */ + StlVector opndReplaceWorkset; }; + //_________________________________________________________________________________________________ Constraint ConstraintsResolverImpl::getCalleeSaveConstraint(Inst * inst, Opnd * opnd) { // This implementation don't take into account operand types // and provides only GP call-safe regs (thus only memory for non-integer and non-pointer types) - Constraint c=(Constraint(OpndKind_Memory)|RegName_EDI|RegName_ESI|RegName_EBX|RegName_EBP|RegName_ESP) & - opnd->getConstraint(Opnd::ConstraintKind_Initial); - return c.isNull()?Constraint(OpndKind_Memory, opnd->getSize()):c; + assert(inst->getKind()==Inst::Kind_CallInst); + Constraint c=(Constraint(OpndKind_Memory)|STACK_REG|((CallInst*)inst)->getCalleeSaveRegs()) & opnd->getConstraint(Opnd::ConstraintKind_Initial); + return c.isNull()?Constraint(OpndKind_Memory, opnd->getSize()):c; } //_________________________________________________________________________________________________ Constraint ConstraintsResolverImpl::getDispatchEntryConstraint(Opnd * opnd) { // Currently the same result as from getCalleeSaveConstraint - Constraint c=(Constraint(OpndKind_Memory)|RegName_EDI|RegName_ESI|RegName_EBX|RegName_EBP|RegName_ESP) & - opnd->getConstraint(Opnd::ConstraintKind_Initial); - return c.isNull()?Constraint(OpndKind_Memory, opnd->getSize()):c; + Constraint c=(Constraint(OpndKind_Memory)|STACK_REG|Constraint(irManager.getEntryPointInst()->getCallingConventionClient().getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg))) & opnd->getConstraint(Opnd::ConstraintKind_Initial); + return c.isNull()?Constraint(OpndKind_Memory, opnd->getSize()):c; } //_________________________________________________________________________________________________ void ConstraintsResolverImpl::run() { // Set all instruction constraints for EntryPoints, CALLs and RETs - irManager.applyCallingConventions(); + irManager.applyCallingConventions(); // Initialization - originalOpndCount=irManager.getOpndCount(); - liveOpnds.resizeClear(originalOpndCount); - needsOriginalOpnd.resizeClear(originalOpndCount); - liveAtDispatchBlockEntry.resizeClear(originalOpndCount); + originalOpndCount=irManager.getOpndCount(); + liveOpnds.resizeClear(originalOpndCount); + needsOriginalOpnd.resizeClear(originalOpndCount); + liveAtDispatchBlockEntry.resizeClear(originalOpndCount); - opndReplaceWorkset.resize(originalOpndCount); - for (uint32 i=0; igetExecCnt(); + irManager.getFlowGraph()->getEntryNode() == node ? (double)0 : + irManager.isEpilog(node) ? (double)1 : + 10 + node->getExecCount(); } @@ -231,278 +315,276 @@ ExecCntValue ConstraintsResolverImpl::ge void ConstraintsResolverImpl::createBasicBlockArray() { // Filling of basicBlock, simple insertion-based ordering of basic blocks - for (CFG::NodeIterator it(irManager); it!=NULL; ++it){ - if (((Node*)it)->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb = (BasicBlock*)(Node*)it; - ExecCntValue bbecv = getBasicBlockPriority(bb); + const Nodes& nodes = irManager.getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + double bbecv = getBasicBlockPriority(node); uint32 ibb=0; for (uint32 nbb=basicBlocks.size(); ibb getBasicBlockPriority(basicBlocks[ibb])) break; } - basicBlocks.insert(basicBlocks.begin()+ibb, bb); + basicBlocks.insert(basicBlocks.begin()+ibb, node); } } } //_________________________________________________________________________________________________ void ConstraintsResolverImpl::calculateLiveAtDispatchBlockEntries() -{ - for (CFG::NodeIterator it(irManager); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_DispatchNode)) - liveAtDispatchBlockEntry.unionWith(*irManager.getLiveAtEntry(node)); - } -} - +{ + const Nodes& nodes = irManager.getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node *node = *it; + if (node->isDispatchNode()) { + liveAtDispatchBlockEntry.unionWith(*irManager.getLiveAtEntry(node)); + } + } +} + //_________________________________________________________________________________________________ void ConstraintsResolverImpl::calculateStartupOpndConstraints() -{ +{ // Reset calculated constraints to null constraints - irManager.resetOpndConstraints(); + irManager.resetOpndConstraints(); // For all operands in the CFG - for (uint32 i=0; igetConstraint(Opnd::ConstraintKind_Initial); - Constraint cl=opnd->getConstraint(Opnd::ConstraintKind_Location); - - if (!cl.isNull()) // Condition c0 satisfied - c=cl; - - if (liveAtDispatchBlockEntry.getBit(i)){ // Condition c2 satisfied - if (cl.isNull()){ // if location is set it is not changed over call sites potentially leading to dispatch/catch nodes - c=c & getDispatchEntryConstraint(opnd); - } - needsOriginalOpnd.setBit(i); - } - // result must not be null as well as opnd initial constrains - assert(!c.isNull() && !opnd->getConstraint(Opnd::ConstraintKind_Initial).isNull()); - // set the results - opnd->setCalculatedConstraint(c); - } -} - + for (uint32 i=0; igetConstraint(Opnd::ConstraintKind_Initial); + Constraint cl=opnd->getConstraint(Opnd::ConstraintKind_Location); + + if (!cl.isNull()) // Set Calculated to Location + c=cl; + + if (liveAtDispatchBlockEntry.getBit(i)){ // Set calculated to the constraint for dispatch entries + if (cl.isNull()){ // if location is set it must satisfy dispatch entry constraints. + c=c & getDispatchEntryConstraint(opnd); + } + needsOriginalOpnd.setBit(i); + } + // result must not be null as well as opnd initial constrains + assert(!c.isNull() && !opnd->getConstraint(Opnd::ConstraintKind_Initial).isNull()); + // set the results + opnd->setCalculatedConstraint(c); + } +} + //_________________________________________________________________________________________________ -void ConstraintsResolverImpl::resolveConstraints(Inst * inst) -{ - // Initialize hoveringOpnds with operands live after the call if the inst is CALL - if (inst->getMnemonic()==Mnemonic_CALL) - hoveringOpnds.copyFrom(liveOpnds); - - // first handle all defs - {Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * originalOpnd=inst->getOpnd(it); - - // We haven't changed def-operands yet for this instruction - assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); - // currentOpnd is either the current replacement or the original operand - Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) - currentOpnd=originalOpnd; - // get what is already collected - Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); - assert(!cc.isNull()); - // get the weak instruction constraint for this occurrence - Constraint ci=inst->getConstraint(Inst::ConstraintKind_Weak, it, originalOpnd->getSize()); - assert(!ci.isNull()); - // & the result - Constraint cr=cc & ci; - Opnd * opndToSet=currentOpnd; - if (!cr.isNull()){ - // can substitute currentReplacementOpnd into this position - currentOpnd->setCalculatedConstraint(cr); - }else{ - // cannot substitute currentReplacementOpnd into this position, needs splitting - opndToSet=irManager.newOpnd( originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize()) ); - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, opndToSet); - // split after the defining instruction - inst->getBasicBlock()->appendInsts(copySequence, inst); - if (inst->getOpndRoles(it)&Inst::OpndRole_Use){ - // This is def&use case (like add t0, t1 for t0) - if (!needsOriginalOpnd.getBit(originalOpnd->getId())){ - // c0-c2 are not satisfied, use the new operand for all the instructions above - opndReplaceWorkset[originalOpnd->getId()]=opndToSet; - }else{ - // c0-c2 are satisfied, use the original operand for all the instructions above - assert(currentOpnd==originalOpnd); - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); - // split above the instruction - inst->getBasicBlock()->prependInsts(copySequence, inst); - } - } - } - // Update liveness - if (inst->isLiveRangeEnd(it)){ // if pure def, not def&use, terminate live range - liveOpnds.setBit(originalOpnd->getId(), false); - // also terminate replacement chain - opndReplaceWorkset[originalOpnd->getId()] = NULL; - } - // need to set the new operand into this place of the instruction - if (opndToSet!=originalOpnd) - inst->setOpnd(it, opndToSet); - - }} - - // now handle operands hovering over call insts - if (inst->getMnemonic()==Mnemonic_CALL){ - // for all operands - LiveSet::IterB ib(hoveringOpnds); - for (int i = ib.getNext(); i != -1; i = ib.getNext()){ - Opnd * originalOpnd=irManager.getOpnd(i); - // The same checks that we check c0-c2 properly - assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); - // currentOpnd is either the current replacement or the original operand - Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) - currentOpnd=originalOpnd; - Opnd * opndToSet=NULL; - // was live and is not redefined by this inst - if (liveOpnds.isLive(originalOpnd)){ - // Instruction-level constraints are constraints describing locations safe across CALLs - Constraint ci=getCalleeSaveConstraint(inst, currentOpnd); - // we have at least memory - assert(!ci.isNull()); - Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); - assert(!cc.isNull()); - // & the result - Constraint cr=cc & ci; - opndToSet=currentOpnd; - if (cr.getMask()!=0 || cc.getMask()==0){ - // can substitute currentReplacementOpnd into this position - opndToSet->setCalculatedConstraint(cr); - }else{ - // cannot substitute currentReplacementOpnd into this position, needs splitting - // Try to use originalOpnd over this instruction and for the instructions above - Constraint co=originalOpnd->getConstraint(Opnd::ConstraintKind_Calculated); - Constraint cr=co & ci; - if (cr.getMask()!=0 || co.getMask()==0){ - opndToSet=originalOpnd; - opndToSet->setCalculatedConstraint(cr); - }else{ - // cannot use original, create a new one - opndToSet=irManager.newOpnd(originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize())); - } - } - } - - if (opndToSet!=NULL){ - if (opndToSet!=currentOpnd){ - // an operand different to the current replacement - // is required to be over this call site, append splitting below the call site - // this is like restoring from a call-safe location under a call - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, opndToSet); - inst->getBasicBlock()->appendInsts(copySequence, inst); - } - // no c0-c2, can use the replacement operand above - if (!needsOriginalOpnd.getBit(originalOpnd->getId())) - opndReplaceWorkset[originalOpnd->getId()]=opndToSet; - else if (opndToSet!=originalOpnd){ - // add splitting above - // this is like saving into a call-safe location above a call - assert(currentOpnd==originalOpnd); - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); - inst->getBasicBlock()->prependInsts(copySequence, inst); - } - } - } - } - - // now handle all uses - {Inst::Opnds opnds(inst, Inst::OpndRole_AllUses); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * originalOpnd=inst->getOpnd(it); - - if ((inst->getOpndRoles(it)&Inst::OpndRole_Def)==0){ // the use&def case was handled above - // The same checks that we check c0-c2 properly - assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); - // currentOpnd is either the current replacement or the original operand - Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; - if (currentOpnd==NULL) - currentOpnd=originalOpnd; - // get what is already collected - Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); - assert(!cc.isNull()); - // get the weak instruction constraint for this occurrence - Constraint ci=inst->getConstraint(Inst::ConstraintKind_Weak, it, originalOpnd->getSize()); - assert(!ci.isNull()); - Constraint cr=cc & ci; - - Opnd * opndToSet=currentOpnd; - - if (!cr.isNull()){ - // can substitute currentReplacementOpnd into this position - currentOpnd->setCalculatedConstraint(cr); - }else{ - // cannot substitute currentReplacementOpnd into this position, needs splitting - // split above the inst, force to insert the new operand into the inst, and use - // currentOpnd above - opndToSet=irManager.newOpnd(originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize())); - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, currentOpnd); - inst->getBasicBlock()->prependInsts(copySequence, inst); - } - // update liveness (for def/use case - if (inst->isLiveRangeStart(it)) - liveOpnds.setBit(originalOpnd->getId(), true); - // need to set the new operand into this place of the instruction - if (opndToSet!=originalOpnd) - inst->setOpnd(it, opndToSet); - } - }} -} - +void ConstraintsResolverImpl::resolveConstraintsWithOG(Inst * inst) +{ + // Initialize hoveringOpnds with operands live after the call if the inst is CALL + if (inst->getMnemonic()==Mnemonic_CALL) + hoveringOpnds.copyFrom(liveOpnds); + + // first handle all defs + {Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + Opnd * originalOpnd=inst->getOpnd(it); + + // We haven't changed def-operands yet for this instruction + assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); + + // currentOpnd is either the current replacement or the original operand + Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; + if (currentOpnd==NULL) + currentOpnd=originalOpnd; + // get what is already collected + Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); + assert(!cc.isNull()); + // get the weak instruction constraint for this occurrence + Constraint ci=inst->getConstraint(it, (1 << it) , originalOpnd->getSize()); + assert(!ci.isNull()); + // & the result + Constraint cr=cc & ci; + Opnd * opndToSet=currentOpnd; + if (!cr.isNull()){ + // can substitute currentReplacementOpnd into this position + currentOpnd->setCalculatedConstraint(cr); + }else{ + // cannot substitute currentReplacementOpnd into this position, needs splitting + opndToSet=irManager.newOpnd( originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize()) ); + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, opndToSet); + // split after the defining instruction + copySequence->insertAfter(inst); + if (inst->getOpndRoles(it)&Inst::OpndRole_Use){ + // This is def&use case (like add t0, t1 for t0) + if (!needsOriginalOpnd.getBit(originalOpnd->getId())){ + // use the new operand for all the instructions above + opndReplaceWorkset[originalOpnd->getId()]=opndToSet; + }else{ + // use the original operand for all the instructions above + assert(currentOpnd==originalOpnd); + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); + // split above the instruction + copySequence->insertBefore(inst); + } + } + } + // Update liveness + if (inst->isLiveRangeEnd(it)){ // if pure def, not def&use, terminate live range + liveOpnds.setBit(originalOpnd->getId(), false); + // also terminate replacement chain + opndReplaceWorkset[originalOpnd->getId()] = NULL; + } + // need to set the new operand into this place of the instruction + if (opndToSet!=originalOpnd) + inst->setOpnd(it, opndToSet); + + }} + + // now handle operands hovering over call insts + if (inst->getMnemonic()==Mnemonic_CALL){ + // for all operands + BitSet::IterB ib(hoveringOpnds); + for (int i = ib.getNext(); i != -1; i = ib.getNext()){ + Opnd * originalOpnd=irManager.getOpnd(i); + assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); + // currentOpnd is either the current replacement or the original operand + Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; + if (currentOpnd==NULL) + currentOpnd=originalOpnd; + Opnd * opndToSet=NULL; + // was live and is not redefined by this inst + if (liveOpnds.getBit(originalOpnd->getId())){ + // Instruction-level constraints are constraints describing locations safe across CALLs + Constraint ci=getCalleeSaveConstraint(inst, currentOpnd); + // we have at least memory + assert(!ci.isNull()); + Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); + assert(!cc.isNull()); + // & the result + Constraint cr=cc & ci; + opndToSet=currentOpnd; + if ((cr.getMask()!=0 || cc.getMask()==0) && !cr.isNull()){ + // can substitute currentReplacementOpnd into this position + opndToSet->setCalculatedConstraint(cr); + }else{ + // cannot substitute currentReplacementOpnd into this position, needs splitting + // Try to use originalOpnd over this instruction and for the instructions above + Constraint co=originalOpnd->getConstraint(Opnd::ConstraintKind_Calculated); + Constraint cr=co & ci; + if ((cr.getMask()!=0 || co.getMask()==0)&& !cr.isNull()){ + opndToSet=originalOpnd; + opndToSet->setCalculatedConstraint(cr); + }else{ + // cannot use original, create a new one + opndToSet=irManager.newOpnd(originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize())); + } + } + } + + if (opndToSet!=NULL){ + if (opndToSet!=currentOpnd){ + // an operand different to the current replacement + // is required to be over this call site, append splitting below the call site + // this is like restoring from a call-safe location under a call + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, opndToSet); + copySequence->insertAfter(inst); + } + if (!needsOriginalOpnd.getBit(originalOpnd->getId())) + opndReplaceWorkset[originalOpnd->getId()]=opndToSet; // can use the replacement operand above + else if (opndToSet!=originalOpnd){ + // add splitting above + // this is like saving into a call-safe location above a call + assert(currentOpnd==originalOpnd); + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, originalOpnd); + copySequence->insertBefore(inst); + } + } + } + } + + // now handle all uses + {Inst::Opnds opnds(inst, Inst::OpndRole_AllUses); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + Opnd * originalOpnd=inst->getOpnd(it); + + if ((inst->getOpndRoles(it)&Inst::OpndRole_Def)==0){ // the use&def case was handled above + assert(originalOpnd->getId()getId())||opndReplaceWorkset[originalOpnd->getId()]==NULL); + // currentOpnd is either the current replacement or the original operand + Opnd * currentOpnd=opndReplaceWorkset[originalOpnd->getId()]; + if (currentOpnd==NULL) + currentOpnd=originalOpnd; + // get what is already collected + Constraint cc=currentOpnd->getConstraint(Opnd::ConstraintKind_Calculated); + assert(!cc.isNull()); + + Constraint ci=inst->getConstraint(it, (1 << it), originalOpnd->getSize()); + assert(!ci.isNull()); + Constraint cr=cc & ci; + + Opnd * opndToSet=currentOpnd; + + if (!cr.isNull()){ + // can substitute currentReplacementOpnd into this position + currentOpnd->setCalculatedConstraint(cr); + }else{ + // cannot substitute currentReplacementOpnd into this position, needs splitting + // split above the inst, force to insert the new operand into the inst, and use + // currentOpnd above + opndToSet=irManager.newOpnd(originalOpnd->getType(), ci | Constraint(OpndKind_Mem, ci.getSize())); + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, opndToSet, currentOpnd); + copySequence->insertBefore(inst); + } + // update liveness (for def/use case + if (inst->isLiveRangeStart(it)) + liveOpnds.setBit(originalOpnd->getId(), true); + // need to set the new operand into this place of the instruction + if (opndToSet!=originalOpnd) + inst->setOpnd(it, opndToSet); + } + }} +} + //_________________________________________________________________________________________________ -void ConstraintsResolverImpl::resolveConstraints(BasicBlock * bb) +void ConstraintsResolverImpl::resolveConstraints(Node * bb) { - // scan all insts of bb in reverse order - const Insts& insts=bb->getInsts(); - irManager.getLiveAtExit(bb, liveOpnds); - for (Inst * inst=insts.getLast(), * prevInst=NULL; inst!=NULL; inst=prevInst){ - prevInst=insts.getPrev(inst); - resolveConstraints(inst); - } - - // if we come to bb entry with some replacement for an operand and the operand is live at the entry - // insert copying from the original operand to the replacement operand - LiveSet * ls = irManager.getLiveAtEntry(bb); - LiveSet::IterB ib(*ls); - for (int i = ib.getNext(); i != -1; i = ib.getNext()){ - Opnd * originalOpnd = irManager.getOpnd(i); - assert(originalOpnd->getId()getId()]; - if (currentOpnd!=NULL){ - if (currentOpnd!=originalOpnd){ -// assert(irManager.getLiveAtEntry(bb)->isLive(originalOpnd)); - Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, originalOpnd); - bb->prependInsts(copySequence); - } - opndReplaceWorkset[originalOpnd->getId()]=NULL; - } - } + assert(bb->isBlockNode()); + // scan all insts of bb in reverse order + irManager.getLiveAtExit(bb, liveOpnds); + for (Inst * inst=(Inst*)bb->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst){ + prevInst=inst->getPrevInst(); + resolveConstraintsWithOG(inst); + } + + // if we come to bb entry with some replacement for an operand and the operand is live at the entry + // insert copying from the original operand to the replacement operand + BitSet * ls = irManager.getLiveAtEntry(bb); + BitSet::IterB ib(*ls); + for (int i = ib.getNext(); i != -1; i = ib.getNext()){ + Opnd * originalOpnd = irManager.getOpnd(i); + assert(originalOpnd->getId()getId()]; + if (currentOpnd!=NULL){ + if (currentOpnd!=originalOpnd){ +// assert(irManager.getLiveAtEntry(bb)->isLive(originalOpnd)); + Inst * copySequence=irManager.newCopyPseudoInst(Mnemonic_MOV, currentOpnd, originalOpnd); + bb->prependInst(copySequence); + } + opndReplaceWorkset[originalOpnd->getId()]=NULL; + } + } } //_________________________________________________________________________________________________ void ConstraintsResolverImpl::resolveConstraints() -{ - // for all basic blocks in the array - for (uint32 ibb=0, nbb=basicBlocks.size(); ibb Intervals; + + struct CandidateInst + { + Inst * inst; + uint32 execCount; + CandidateInst(Inst * i = NULL, uint32 ec = 0) + :inst(i), execCount(ec){} + + static bool less (const CandidateInst& x, const CandidateInst& y) + { + return x.execCount > y.execCount; // order by execCount descending + } + }; + + typedef StlVector CandidateInsts; + + uint32 initIntervals(); + bool isCandidate(const Inst * inst) const; + void collectCandidates(); + void collectIntervals(); + void addReplacement(Opnd * dst, Opnd * src); + void removeInsts(); + void replaceOpnds(); + void printCandidates(::std::ostream& os, uint32 detailLevel = 0)const; + + IRManager & irManager; + MemoryManager memoryManager; + CandidateInsts candidateInsts; + Intervals intervals; + OpndVector opndReplacements; + uint32 replacementsAdded; + bool emptyBlocks; +}; + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::run() +{ + // initialize intervals vector and check if we have at least 2 stack operands + if (initIntervals() > 1){ + // scan through all instructions and find suitable CopyPseudoInsts + collectCandidates(); + // Are there CopyPseudoInsts to coalesce? + if (candidateInsts.size() > 0){ + // collect live-ranges of stack operands + collectIntervals(); + // collect remove redundant CopyPseudoInsts and collect vector of operand replacements + removeInsts(); + // Is anything removed? + if (replacementsAdded > 0){ + replaceOpnds(); + irManager.invalidateLivenessInfo(); + } + } + } +} + +//_________________________________________________________________________________________________ +uint32 SimpleStackOpndCoalescer::initIntervals() +{ + uint32 candidateOpndCount = 0; + uint32 opndCount = irManager.getOpndCount(); + intervals.resize(opndCount); + for (uint32 i = 0; i < opndCount; i++){ + Opnd * opnd = irManager.getOpnd(i); + if (opnd->isPlacedIn(OpndKind_Mem) && opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout){ + intervals[i] = new (memoryManager) Interval(memoryManager); + candidateOpndCount++; + }else + intervals[i] = NULL; + } + return candidateOpndCount; +} + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::collectCandidates() +{ + candidateInsts.resize(0); + + const Nodes& nodes = irManager.getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + if (isCandidate(inst)){ + uint32 execCount = (uint32)node->getExecCount(); + if (execCount < 1) + execCount = 1; + candidateInsts.push_back(CandidateInst(inst, execCount)); + } + } + } + } + if (candidateInsts.size() > 1) + ::std::sort(candidateInsts.begin(), candidateInsts.end(), CandidateInst::less); +} + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::printCandidates(::std::ostream& os, uint32 detailLevel)const +{ + os << irManager.getMethodDesc().getParentType()->getName() << "." << irManager.getMethodDesc().getName() + << ": " << candidateInsts.size() << ::std::endl; + if (detailLevel > 0){ + for (uint32 i = 0; i < candidateInsts.size(); i++){ + if (detailLevel > 1) + IRPrinter::printInst(os, candidateInsts[i].inst); + Inst * inst = candidateInsts[i].inst; + Opnd * dstOpnd = inst->getOpnd(0), * srcOpnd = inst->getOpnd(1); + int adj; + bool removable = !intervals[dstOpnd->getId()]->conflict(intervals[srcOpnd->getId()], adj); + os << inst->getId() << " - " << (removable?"removable":"not removable") << " - " << candidateInsts[i].execCount << ::std::endl; + if (detailLevel > 1){ + os << *intervals[dstOpnd->getId()] << ::std::endl; + os << *intervals[srcOpnd->getId()] << ::std::endl; + } + } + os << ::std::endl; + } +} + +//_________________________________________________________________________________________________ +bool SimpleStackOpndCoalescer::isCandidate(const Inst * inst)const +{ + if (inst->hasKind(Inst::Kind_CopyPseudoInst) && inst->getMnemonic() == Mnemonic_MOV){ + Opnd * dstOpnd = inst->getOpnd(0), * srcOpnd = inst->getOpnd(1); + if (dstOpnd != srcOpnd && + intervals[srcOpnd->getId()] != NULL && intervals[dstOpnd->getId()] != NULL + && dstOpnd->getSize() == srcOpnd->getSize()) + return true; + } + return false; +} + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::collectIntervals() +{ + irManager.indexInsts(); + uint32 opndCount = irManager.getOpndCount(); + + Interval * interval; + + const Nodes& nodes = irManager.getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + + Inst* inst = (Inst*)node->getLastInst(); + if (inst == 0) + continue; + + uint32 instIndex=inst->getIndex(); + + BitSet lives(memoryManager, opndCount); + + irManager.getLiveAtExit(node, lives); + BitSet::IterB ib(lives); + for (int x = ib.getNext(); x != -1; x = ib.getNext()){ + if ( (interval = intervals[x]) != NULL ) + interval->startOrExtend(instIndex + 1); + } + + for (; inst!=NULL; inst=inst->getPrevInst()){ + instIndex = inst->getIndex(); + Inst::Opnds defs(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = defs.begin(); it != defs.end(); it = defs.next(it)){ + Opnd * opnd = inst->getOpnd(it); + uint32 opndId = opnd->getId(); + if ( (interval = intervals[opndId]) != NULL ){ + if (inst->isLiveRangeEnd(it)) + intervals[opndId]->stop(instIndex + 1); + else + intervals[opndId]->startOrExtend(instIndex); + } + } + } + + BitSet* tmp = irManager.getLiveAtEntry(node); + + ib.init(*tmp); + for (int x = ib.getNext(); x != -1; x = ib.getNext()){ + if ( (interval = intervals[x]) != NULL ) + interval->stop(instIndex); + } + } + } + + for (uint32 i = 0; i < opndCount; i++){ + if ( (interval = intervals[i]) != NULL ) + interval->finish(); + } +} +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::replaceOpnds() +{ + const Nodes& nodes = irManager.getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()) + inst->replaceOpnds(&opndReplacements.front()); + } + } +} + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::addReplacement(Opnd * dstOpnd, Opnd * srcOpnd) +{ + if (dstOpnd != srcOpnd){ + intervals[srcOpnd->getId()]->unionWith(intervals[dstOpnd->getId()]); + for (uint32 i = 0, n = irManager.getOpndCount(); i < n; i++){ + if (opndReplacements[i] == dstOpnd){ + if (srcOpnd->getId() != i) + opndReplacements[i] = srcOpnd; + else + opndReplacements[i] = NULL; + } + } + opndReplacements[dstOpnd->getId()] = srcOpnd; + replacementsAdded++; + } +} + +//_________________________________________________________________________________________________ +void SimpleStackOpndCoalescer::removeInsts() +{ + uint32 opndCount = irManager.getOpndCount(); + replacementsAdded = 0; + opndReplacements.resize(opndCount); + for (uint32 i = 0; i < opndCount; i++) + opndReplacements[i] = NULL; + for (uint32 i = 0; i < candidateInsts.size(); i++){ + int adj; + Inst * inst = candidateInsts[i].inst; + Opnd * dstOpnd = inst->getOpnd(0), * srcOpnd = inst->getOpnd(1); + if (opndReplacements[dstOpnd->getId()] != NULL){ + dstOpnd = opndReplacements[dstOpnd->getId()]; + assert(opndReplacements[dstOpnd->getId()] == NULL); + } + if (opndReplacements[srcOpnd->getId()] != NULL){ + srcOpnd = opndReplacements[srcOpnd->getId()]; + assert(opndReplacements[srcOpnd->getId()] == NULL); + } + if (!intervals[dstOpnd->getId()]->conflict(intervals[srcOpnd->getId()], adj)) + addReplacement(dstOpnd, srcOpnd); + } +} + + //======================================================================================== +/** + class CopyExpansion translated CopyPseudoInsts to corresponding copying sequences +*/ +class CopyExpansion : public SessionAction { + void runImpl(); + void restoreRegUsage(Node * bb, Inst * toInst, uint32& gpRegUsageMask, uint32& appRegUsageMask); + uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo; } + uint32 getSideEffects()const{ return 0; } +}; + + +static ActionFactory _copy("copy"); + //_________________________________________________________________________________________________ void CopyExpansion::runImpl() { - IRManager & irm=getIRManager(); - CompilationInterface& compIntfc = irm.getCompilationInterface(); + CompilationInterface& compIntfc = irManager->getCompilationInterface(); VectorHandler* bc2LIRmapHandler = NULL; - MemoryManager& mm = irm.getMemoryManager(); + MemoryManager& mm = irManager->getMemoryManager(); if (compIntfc.isBCMapInfoRequired()) { bc2LIRmapHandler = new(mm) VectorHandler(bcOffset2LIRHandlerName, compIntfc.getMethodToCompile()); } - irm.finalizeCallSites(); + // call SimpleStackOpndCoalescer before all other things including finalizeCallSites + // as they add new local operands and fixLivenessInfo would be necessary + + bool coalesceStack = true; + getArg("coalesceStack", coalesceStack); + if (coalesceStack) { + SimpleStackOpndCoalescer(*irManager).run(); + irManager->updateLivenessInfo(); + } + + irManager->finalizeCallSites(); - const Nodes& nodes = irm.getNodesPostorder(); + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock *)node; - const Insts& insts=bb->getInsts(); - uint32 regUsageMask = 0; - bool calculatingRegUsage = false; - for (Inst * inst=insts.getLast(), * nextInst=NULL; inst!=NULL; inst=nextInst){ - nextInst=insts.getPrev(inst); - if (inst->hasKind(Inst::Kind_CopyPseudoInst)){ - Mnemonic mn=inst->getMnemonic(); + if (node->isBlockNode()){ + uint32 flagsRegUsageMask = 0; + uint32 gpRegUsageMask = 0; + bool calculatingRegUsage = false; + for (Inst * inst=(Inst*)node->getLastInst(), * nextInst=NULL; inst!=NULL; inst=nextInst){ + nextInst=inst->getPrevInst(); + if (inst->hasKind(Inst::Kind_CopyPseudoInst)){ + Mnemonic mn=inst->getMnemonic(); Inst *copySequence = NULL; - if (mn==Mnemonic_MOV){ - Opnd * toOpnd=inst->getOpnd(0); - Opnd * fromOpnd=inst->getOpnd(1); - - if (toOpnd->isPlacedIn(OpndKind_Reg) && fromOpnd->isPlacedIn(OpndKind_Reg)){ - if (toOpnd->getRegName()==fromOpnd->getRegName()) - continue; - }else{ - if (!calculatingRegUsage && toOpnd->isPlacedIn(OpndKind_Mem) && fromOpnd->isPlacedIn(OpndKind_Mem)){ - restoreRegUsage(bb, inst, regUsageMask); - calculatingRegUsage=true; - } + if (mn==Mnemonic_MOV){ + Opnd * toOpnd=inst->getOpnd(0); + Opnd * fromOpnd=inst->getOpnd(1); + + if (toOpnd == fromOpnd){ + continue; + } else if (toOpnd->isPlacedIn(OpndKind_Reg) && fromOpnd->isPlacedIn(OpndKind_Reg)){ + if (toOpnd->getRegName()==fromOpnd->getRegName()) + continue; + }else{ +#ifdef _EM64T_ + if (!calculatingRegUsage && ((toOpnd->isPlacedIn(OpndKind_Mem) && fromOpnd->isPlacedIn(OpndKind_Mem))||fromOpnd->isPlacedIn(OpndKind_Imm))){ +#else + if (!calculatingRegUsage && ((toOpnd->isPlacedIn(OpndKind_Mem) && fromOpnd->isPlacedIn(OpndKind_Mem))||(toOpnd->isPlacedIn(OpndKind_Reg) && fromOpnd->isPlacedIn(OpndKind_Imm)))){ +#endif + restoreRegUsage(node, inst, gpRegUsageMask, flagsRegUsageMask); + calculatingRegUsage=true; + } } - copySequence = irManager.newCopySequence(Mnemonic_MOV, toOpnd, fromOpnd, regUsageMask); - }else if (mn==Mnemonic_PUSH||mn==Mnemonic_POP){ - if (!calculatingRegUsage && inst->getOpnd(0)->isPlacedIn(OpndKind_Mem)){ - restoreRegUsage(bb, inst, regUsageMask); - calculatingRegUsage=true; + copySequence = irManager->newCopySequence(Mnemonic_MOV, toOpnd, fromOpnd, gpRegUsageMask, flagsRegUsageMask); + }else if (mn==Mnemonic_PUSH||mn==Mnemonic_POP){ +#ifdef _EM64T_ + if (!calculatingRegUsage && (inst->getOpnd(0)->isPlacedIn(OpndKind_Mem)||inst->getOpnd(0)->isPlacedIn(OpndKind_Imm))){ +#else + if (!calculatingRegUsage && inst->getOpnd(0)->isPlacedIn(OpndKind_Mem)){ +#endif + restoreRegUsage(node, inst, gpRegUsageMask, flagsRegUsageMask); + calculatingRegUsage=true; } - copySequence = irManager.newCopySequence(mn, inst->getOpnd(0), NULL, regUsageMask); - } + copySequence = irManager->newCopySequence(mn, inst->getOpnd(0), NULL, gpRegUsageMask, flagsRegUsageMask); + } // CopyPseudoInst map entries should be changed by new copy sequence instrutions in byte code map if (compIntfc.isBCMapInfoRequired() && copySequence != NULL) { uint64 instID = inst->getId(); @@ -92,28 +410,32 @@ void CopyExpansion::runImpl() } // End of code map change - bb->appendInsts(copySequence, inst); - bb->removeInst(inst); - }; - if (calculatingRegUsage) - irManager.updateRegUsage(inst, OpndKind_GPReg, regUsageMask); - } - } - } - irManager.fixLivenessInfo(); + copySequence->insertAfter(inst); + inst->unlink(); + }; + if (calculatingRegUsage) { + irManager->updateRegUsage(inst, OpndKind_GPReg, gpRegUsageMask); + irManager->updateRegUsage(inst, OpndKind_StatusReg, flagsRegUsageMask); + } + } + } + } + irManager->fixLivenessInfo(); } //_________________________________________________________________________________________________ -void CopyExpansion::restoreRegUsage(BasicBlock * bb, Inst * toInst, uint32& regUsageMask) +void CopyExpansion::restoreRegUsage(Node* bb, Inst * toInst, uint32& gpRegUsageMask, uint32& appRegUsageMask) { - const Insts& insts = bb->getInsts(); - Inst * inst = insts.getLast(); - if (inst == NULL) - return; - irManager.getRegUsageAtExit(bb, OpndKind_GPReg, regUsageMask); - for (; inst != toInst; inst = insts.getPrev(inst)){ - irManager.updateRegUsage(inst, OpndKind_GPReg, regUsageMask); - } + assert(bb->isBlockNode()); + if (bb->isEmpty()) { + return; + } + irManager->getRegUsageAtExit(bb, OpndKind_GPReg, gpRegUsageMask); + irManager->getRegUsageAtExit(bb, OpndKind_StatusReg, appRegUsageMask); + for (Inst* inst = (Inst*)bb->getLastInst(); inst != toInst; inst = inst->getPrevInst()){ + irManager->updateRegUsage(inst, OpndKind_GPReg, gpRegUsageMask); + irManager->updateRegUsage(inst, OpndKind_StatusReg, appRegUsageMask); + } } }}; //namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32CopyExpansion.h vm/jitrino/src/codegenerator/ia32/Ia32CopyExpansion.h deleted file mode 100644 index 8d4ad18..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32CopyExpansion.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Vyacheslav P. Shakin - * @version $Revision: 1.6.22.3 $ - */ - -#ifndef _IA32_COPYEXPANSION_H_ -#define _IA32_COPYEXPANSION_H_ - -#include "Ia32IRManager.h" -namespace Jitrino -{ -namespace Ia32{ - - - -//======================================================================================== -// class CopyExpansion -//======================================================================================== -/** - class CopyExpansion translated CopyPseudoInsts to corresponding copying sequences -*/ -BEGIN_DECLARE_IRTRANSFORMER(CopyExpansion, "copy", "Copy pseudo inst expansion") - IRTRANSFORMER_CONSTRUCTOR(CopyExpansion) - void runImpl(); - void restoreRegUsage(BasicBlock * bb, Inst * toInst, uint32& regUsageMask); - uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo; } - uint32 getSideEffects()const{ return 0; } -END_DECLARE_IRTRANSFORMER(CopyExpansion) - -}}; // namespace Ia32 - -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp index f7d8aa6..6a4dbc9 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32DCE.cpp @@ -18,13 +18,24 @@ * @version $Revision: 1.16.8.2.4.3 $ */ -#include "Ia32DCE.h" +#include "Ia32IRManager.h" #include "Ia32CodeGenerator.h" namespace Jitrino { namespace Ia32{ +/** + class DCE performs Dead code elimination +*/ +class DCE : public SessionAction { +public: + void runImpl(); + uint32 getSideEffects() const {return 0;} + uint32 getNeedInfo()const {return 0;} +}; + +static ActionFactory _dce("cg_dce"); //======================================================================================== @@ -33,25 +44,24 @@ namespace Ia32{ //_________________________________________________________________________________________________ void DCE::runImpl() -{ - if (parameters && !irManager.getCGFlags()->earlyDCEOn) { - return; - } +{ + bool early = false; + getArg("early", early); + if (early && !irManager->getCGFlags()->earlyDCEOn) { + return; + } - IRManager & irm=getIRManager(); - irm.updateLivenessInfo(); - irm.calculateOpndStatistics(); - LiveSet ls(irm.getMemoryManager(), irm.getOpndCount()); - const Nodes& nodes = irm.getNodesPostorder(); + irManager->updateLivenessInfo(); + irManager->calculateOpndStatistics(); + BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)){ - irm.getLiveAtExit(node, ls); - BasicBlock * bb=(BasicBlock *)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getLast(), * prevInst=NULL; inst!=NULL; inst=prevInst){ - prevInst=insts.getPrev(inst); - bool deadInst=!inst->hasSideEffect(); + if (node->isBlockNode()){ + irManager->getLiveAtExit(node, ls); + for (Inst * inst=(Inst*)node->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst){ + prevInst=inst->getPrevInst(); + bool deadInst=!inst->hasSideEffect(); if (deadInst){ if (inst->hasKind(Inst::Kind_CopyPseudoInst)){ Opnd * opnd=inst->getOpnd(1); @@ -60,11 +70,11 @@ void DCE::runImpl() } } if (deadInst){ - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * opnd = inst->getOpnd(it); - if ((ls.isLive(opnd) && (inst->getOpndRoles(it) & Inst::OpndRole_Def)) || - (((opnd->getMemOpndKind()&(MemOpndKind_Heap|MemOpndKind_StackManualLayout))!=0) && (inst->getMnemonic() != Mnemonic_LEA))) { + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator ito = opnds.begin(); ito != opnds.end(); ito = opnds.next(ito)){ + Opnd * opnd = inst->getOpnd(ito); + if ((ls.getBit(opnd->getId()) && (inst->getOpndRoles(ito) & Inst::OpndRole_Def)) || + (((opnd->getMemOpndKind()&(MemOpndKind_Heap|MemOpndKind_StackManualLayout))!=0) && (inst->getMnemonic() != Mnemonic_LEA))) { deadInst=false; break; } @@ -72,17 +82,23 @@ void DCE::runImpl() } } if (deadInst) { - bb->removeInst(inst); + inst->unlink(); } else { - irm.updateLiveness(inst, ls); + irManager->updateLiveness(inst, ls); } - } - irm.getLiveAtEntry(node)->copyFrom(ls); - } - } - irm.eliminateSameOpndMoves(); - irManager.packOpnds(); - irm.invalidateLivenessInfo(); + } + irManager->getLiveAtEntry(node)->copyFrom(ls); + } + } + + irManager->eliminateSameOpndMoves(); + + irManager->getFlowGraph()->purgeEmptyNodes(); + irManager->getFlowGraph()->mergeAdjacentNodes(true, false); + irManager->getFlowGraph()->purgeUnreachableNodes(); + + irManager->packOpnds(); + irManager->invalidateLivenessInfo(); } }}; //namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32DCE.h vm/jitrino/src/codegenerator/ia32/Ia32DCE.h deleted file mode 100644 index c0a70f2..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32DCE.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Vyacheslav P. Shakin - * @version $Revision: 1.7.20.3 $ - */ - -#ifndef _IA32_DCE_H_ -#define _IA32_DCE_H_ - -#include "Ia32IRManager.h" -namespace Jitrino -{ -namespace Ia32{ - -//======================================================================================== -// class DCE -//======================================================================================== -/** - class DCE performs Dead code elimination -*/ -BEGIN_DECLARE_IRTRANSFORMER(DCE, "dce", "Dead code elimination") - DCE(IRManager& irm, const char * params=0): IRTransformer(irm, params){} - void runImpl(); - uint32 getSideEffects() const {return 0;} - uint32 getNeedInfo()const {return 0;} -END_DECLARE_IRTRANSFORMER(DCE) - - -}}; // namespace Ia32 - -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp new file mode 100644 index 0000000..649498b --- /dev/null +++ vm/jitrino/src/codegenerator/ia32/Ia32EarlyPropagation.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Vyacheslav P. Shakin + * @version $Revision$ + */ + +#include +#include "Stl.h" +#include "Log.h" +#include "Ia32IRManager.h" +#include "Ia32Printer.h" + +namespace Jitrino +{ +namespace Ia32 +{ + +//======================================================================================== +// class EarlyPropagation +//======================================================================================== +/** + * class EarlyPropagation implements a simple algorithm of constant and copy propagation. + * It works only with operands which have single defintions. + * In addition to constants it also propagates heap reads. + * + * The main goal of the pass is to reduce register pressure. + * + */ +class EarlyPropagation : public SessionAction { + + struct OpndInfo + { + uint32 defCount; + Inst * sourceInst; + uint32 sourceOpndId; + uint32 sourceOpndDefCountAtCopy; + OpndInfo() + :defCount(0), sourceInst(NULL), sourceOpndId(EmptyUint32), sourceOpndDefCountAtCopy(0){} + }; + + void runImpl(); + uint32 getNeedInfo()const{ return 0; } +}; + +static ActionFactory _early_prop("early_prop"); + +//___________________________________________________________________________________________________ +void EarlyPropagation::runImpl() +{ + irManager->updateLoopInfo(); + uint32 opndCount=irManager->getOpndCount(); + + MemoryManager mm(0x100 + sizeof(OpndInfo) * opndCount + sizeof(Opnd*) * opndCount, "early_prop"); + OpndInfo * opndInfos = new(mm) OpndInfo[opndCount]; + Node * currentLoopHeader = NULL; + + bool anyInstHandled=false; + + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { + Node * node=*it; + if (!node->isBlockNode()) { + continue; + } + Node * loopHeader = lt->getLoopHeader(node, false); + if (currentLoopHeader != loopHeader){ + currentLoopHeader = loopHeader; + for (uint32 i = 0; i < opndCount; ++i) + if (opndInfos[i].sourceOpndId != EmptyUint32) + opndInfos[i].defCount++; + } + + for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ + bool assignedOpndPropagated = false; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + Opnd * opnd=inst->getOpnd(it); + uint32 roles=inst->getOpndRoles(it); + uint32 opndId = opnd->getId(); + OpndInfo& opndInfo = opndInfos[opndId]; + + uint32 mask = 0; + + if (roles & Inst::OpndRole_Def){ + ++opndInfo.defCount; + }else if (roles & Inst::OpndRole_Use){ + if (opndInfo.sourceOpndId != EmptyUint32){ + if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount) + opndInfo.sourceOpndId = EmptyUint32; + else{ + Opnd * srcOpnd = irManager->getOpnd(opndInfo.sourceOpndId); + Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location); + if (co.getKind() == OpndKind_Mem){ + mask = (1<hasKind(Inst::Kind_PseudoInst) || irManager->isGCSafePoint(inst) || + opndInfo.sourceInst != inst->getPrevInst() || assignedOpndPropagated || + (inst->getConstraint(it, mask, co.getSize())&co).isNull() + ) + opndInfo.sourceOpndId = EmptyUint32; + assignedOpndPropagated = true; + } + } + } + } + if (opndInfo.defCount > 1){ + opndInfo.sourceOpndId = EmptyUint32; + } + } + bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||( + (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && + inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0 + && inst->getOpnd(3)->getRuntimeInfo()==NULL + ); + + if (isCopy){ // CopyPseudoInst or mov + Opnd * defOpnd = inst->getOpnd(0); + Opnd * srcOpnd = inst->getOpnd(1); + uint32 defOpndId = defOpnd->getId(); + OpndInfo * opndInfo = opndInfos + defOpndId; + bool instHandled=false; + if (opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){ + if (!defOpnd->hasAssignedPhysicalLocation()){ + opndInfo->sourceInst = inst; + opndInfo->sourceOpndId = srcOpnd->getId(); + instHandled=true; + } + } + if (instHandled){ + if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32) + opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId; + opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount; + anyInstHandled=true; + } + } + } + } + + if (anyInstHandled){ + Opnd ** replacements = new(mm) Opnd* [opndCount]; + memset(replacements, 0, sizeof(Opnd*) * opndCount); + bool hasReplacements = false; + for (uint32 i = 0; i < opndCount; ++i){ + if (opndInfos[i].sourceOpndId != EmptyUint32){ + Inst * inst = opndInfos[i].sourceInst; + if (inst !=NULL){ + inst->unlink(); + } + if (opndInfos[i].sourceOpndId != i){ + replacements[i] = irManager->getOpnd(opndInfos[i].sourceOpndId); + hasReplacements = true; + } + } + } + + if (hasReplacements){ + const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { + Node * node=*it; + if (!node->isBlockNode()) { + continue; + } + for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ + inst->replaceOpnds(replacements); + } + } + } + } +} + + +}} + diff --git vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp index c36739c..97bfe22 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32Encoder.cpp @@ -20,18 +20,50 @@ #include "Ia32Encoder.h" #include "Ia32Inst.h" +#include +#include "mkernel.h" +#include "enc_prvt.h" namespace Jitrino { namespace Ia32 { -const Encoder::OpcodeGroupDescription Encoder::dummyOpcodeGroupDescription; +//fixme64: for adapter needs +bool is_ptr_type(const Type* typ) { + switch(typ->tag) { + case Type::TypedReference: + case Type::SystemObject: + case Type::SystemString: + case Type::NullObject: + case Type::Array: + case Type::Object: + case Type::BoxedValue: + case Type::UnmanagedPtr: + case Type::ManagedPtr: + case Type::MethodPtr: + case Type::VTablePtr: + case Type::VTablePtrObj: + case Type::ITablePtrObj: + return true; + default: + break; + } + return false; +} + + +const Encoder::OpcodeGroup Encoder::dummyOpcodeGroup; const Encoder::MemOpndConstraints Encoder::memOpndConstraints[16]= { - {{ + { +#ifdef _EM64T_ + Constraint(OpndKind_GPReg, OpndSize_64), + Constraint(OpndKind_GPReg, OpndSize_64), +#else Constraint(OpndKind_GPReg, OpndSize_32), Constraint(OpndKind_GPReg, OpndSize_32), +#endif Constraint(OpndKind_Imm, OpndSize_32), - Constraint(OpndKind_Imm, OpndSize_32) }}, + Constraint(OpndKind_Imm, OpndSize_32) }, // others contain null constraints, to be fixed later }; @@ -58,10 +90,15 @@ Constraint Encoder::getAllRegs(OpndKind uint32 Encoder::getMnemonicProperties(Mnemonic mn) { - const MnemonicDesc * mdesc = getMnemonicDesc(mn); - return (mdesc->conditional ? - Inst::Properties_Conditional:0) | - (mdesc->symmetric ? Inst::Properties_Symmetric : 0); + return getMnemonicProperties(*getMnemonicDesc(mn)); +}; + +uint32 Encoder::getMnemonicProperties(const MnemonicDesc& mdesc) +{ + return (mdesc.flags & MF_CONDITIONAL ? Inst::Properties_Conditional:0) | + (mdesc.flags & MF_SYMMETRIC ? Inst::Properties_Symmetric : 0) | + (mdesc.flags & MF_SAME_ARG_NO_USE? Inst::Properties_PureDef: 0); +; }; //_________________________________________________________________________________________________ @@ -69,141 +106,105 @@ bool Encoder::matches(Constraint co, Con bool allowAliases) { return co.isNull() || !(ci&co).isNull() || - (allowAliases && !(opndRoles&Inst::OpndRole_Def) && - !(ci.getAliasConstraint(co.getSize())&co).isNull()); + (allowAliases && !(ci.getAliasConstraint(co.getSize())&co).isNull()); } //_________________________________________________________________________________________________ -const Encoder::OpcodeGroupDescription * -Encoder::findOpcodeGroupDescription(const FindInfo& fi) +const Encoder::OpcodeGroup * +Encoder::findOpcodeGroup(const FindInfo& fi) { Mnemonic m = fi.mnemonic; assert(m != Mnemonic_Null && m < Mnemonic_Count); const OpcodeGroupsHolder& mi = getOpcodeGroups()[m]; // first, find better matching for already assigned operands for (uint32 i=0; iopndRoles.defCount || - fi.opndCount != ogd->opndRoles.defCount+ogd->opndRoles.useCount) { + if (fi.defOpndCount != og->opndRoles.defCount || + fi.opndCount != og->opndRoles.defCount+og->opndRoles.useCount) { return false; } } else { - if (fi.opndCount != ogd->opndRoles.count) { + if (fi.opndCount != og->opndRoles.count) { return false; } } for (uint32 i = 0, n = fi.opndCount; i < n; i++) { - uint32 idx = fi.isExtended ? ogd->extendedToNativeMap[i] : i; - assert(idxweakOpndConstraints[idx]; + uint32 idx = fi.isExtended ? og->extendedToNativeMap[i] : i; Constraint co=fi.opndConstraints[idx]; if (any) { co = Constraint(OpndKind_Any, co.getSize()); } - if (!matches(co, ci, Encoder::getOpndRoles(ogd->opndRoles,idx), any)) { + if (!isOpndAllowed(og, i, co, fi.isExtended, any)) return false; - } } return true; } //_________________________________________________________________________________________________ -bool Encoder::matches(const OpcodeDescription * od, const FindInfo& fi) +bool +Encoder::isOpndAllowed(const Encoder::OpcodeGroup * og, uint32 i, Constraint co, bool isExtended, bool any) { - const uint32 * extendedToNativeMap = fi.isExtended ? - fi.opcodeGroupDescription->extendedToNativeMap : NULL; - for (uint32 i = 0, n = fi.opndCount; i < n; i++) { - uint32 idx = extendedToNativeMap != NULL ? extendedToNativeMap[i] : i; + uint32 idx = isExtended ? og->extendedToNativeMap[i] : i; assert(idxopndConstraints[idx]; - Constraint co = fi.opndConstraints[i]; - if (!matches(co, ci, Encoder::getOpndRoles(od->opndRoles,idx), true)) { - return false; - } - } - return true; -} -//_________________________________________________________________________________________________ -uint32 Encoder::findOpcodeDescription(const FindInfo& fi) -{ - const OpcodeGroupDescription * ogd = fi.opcodeGroupDescription; - assert(ogd!=NULL); - for (uint32 i=0, n=ogd->opcodeDescriptionCount; iopcodeDescriptions + i, fi)) { - return i; - } - } - return EmptyUint32; -} + Constraint ci=og->opndConstraints[idx]; -//_________________________________________________________________________________________________ -uint8 * Encoder::emit(uint8* stream, const Inst * inst) -{ - FindInfo fi; - inst->initFindInfo(fi, Opnd::ConstraintKind_Current); - uint32 opcodeIdx=Encoder::findOpcodeDescription(fi); - assert(opcodeIdx!=EmptyUint32); - return Encoder::emit(stream, inst, - inst->opcodeGroupDescription->opcodeDescriptions+opcodeIdx); + if (!matches(co, ci, Encoder::getOpndRoles(og->opndRoles,idx), any && (!(Encoder::getOpndRoles(og->opndRoles,idx)&Inst::OpndRole_Def) || getBaseConditionMnemonic(og->mnemonic) == Mnemonic_SETcc))) { + return false; + } + return true; } //_________________________________________________________________________________________________ -uint8* Encoder::emit(uint8* stream, const Inst * inst, - const OpcodeDescription * desc) +uint8* Encoder::emit(uint8* stream, const Inst * inst) { Mnemonic mnemonic=inst->getMnemonic(); + #define OPND EncoderBase::Operand + #define OPNDS EncoderBase::Operands EncoderBase::Operands args; + Opnd * const * opnds = inst->getOpnds(); const uint32 * roles = inst->getOpndRoles(); for( int idx=0, n=inst->getOpndCount(); idxgetConstraint(Opnd::ConstraintKind_Location); - // A workaround: there are many cases when the size specified in - // the inst's operands does not match the real operands' sizes. - // I.e. there are number of 'MOVZX reg32, reg32' instructions as well - // as 'SETcc r/m32'. - // This causes a huge problem in opcode selection: - // first, such a mess blocks the fast opcode selection and makes it - // fall to slow path. For the particular 'MOVZX reg32, reg32' even - // the slow path unable to find the proper opcode without a huge - // complication of selection algorithm. - // Thus, trying to fix the inconsistency right here: use the size - // specified in the opcodeGroupDescriptions, of instruction and not - // the size specified in the operand. - - OpndSize sz = inst->opcodeGroupDescription->opcodeDescriptions[0]. - opndConstraints[args.count()].getSize(); - // ^^ args.count() serves as a sequental number of current operand. + OpndSize sz = inst->opcodeGroup->opndConstraints[args.count()].getSize(); + switch( c.getKind() ) { case OpndKind_Imm: args.add(EncoderBase::Operand(sz, p->getImmValue())); break; case OpndKind_Mem: { + RegName segReg = p->getSegReg(); + if (segReg == RegName_FS) { + stream = (uint8*)EncoderBase::prefix((char*)stream, + InstPrefix_FS); + } + const Opnd * pbase = p->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); const Opnd * pindex = @@ -214,40 +215,45 @@ uint8* Encoder::emit(uint8* stream, cons p->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); int disp = pdisp ? (int)pdisp->getImmValue() : 0 ; - RegName baseReg = p->getBaseReg(); - if (baseReg == RegName_Null && NULL != pbase) { - baseReg = pbase->getRegName(); - } - // Special processing of FS:[14] - in CFG, they exist as - // operands with base=RegName_FS and a displacement. - // Here, at this stage, we remove RegName_FS from the base - // in inserts appropriate prefix into the code stream. - if (baseReg == RegName_FS) { - stream = (uint8*)EncoderBase::prefix((char*)stream, - InstPrefix_FS); - baseReg = RegName_Null; - } - else { - // Just a check that no other segment register is used - // the same way. If something changes, then this - // new usage scheme must be processed in a special way. - assert(baseReg == RegName_Null || - getRegKind(baseReg) != OpndKind_SReg); - } + if (p->getMemOpndKind() == MemOpndKind_StackAutoLayout) { disp += inst->getStackDepth(); if (Mnemonic_POP == mnemonic) { - disp -= 4; + disp -= STACK_SLOT_SIZE; } } - + RegName baseReg = pbase == NULL ? RegName_Null : pbase->getRegName(); + RegName indexReg = pindex == NULL ? RegName_Null : pindex->getRegName(); +#ifdef _EM64T_ + // adapter: all PTR types go as 64 bits + const RegName TMP_BASE = RegName_R13; + bool is_ptr = is_ptr_type(p->getType()); + if (pindex== NULL && pbase == NULL) { + // have only displacement - load displacement to register + RegName reg = (RegName)(TMP_BASE + args.count()); + OPNDS tmp(reg, OPND(OpndSize_64, pdisp->getImmValue())); + stream = (uint8*)EncoderBase::encode((char*)stream, Mnemonic_MOV, tmp); + OPND mem(sz, reg, 0); + args.add(mem); + } + else { + EncoderBase::Operand o(is_ptr ? OpndSize_64 : sz, + baseReg, indexReg, + NULL == pscale ? 0 : (unsigned char)pscale->getImmValue(), + disp + ); + args.add(o); + } +#else EncoderBase::Operand o(sz, baseReg, - NULL == pindex ? RegName_Null : pindex->getRegName(), + indexReg, NULL == pscale ? 0 : (unsigned char)pscale->getImmValue(), disp ); args.add( o ); + +#endif } break; default: @@ -256,38 +262,33 @@ uint8* Encoder::emit(uint8* stream, cons RegName opndReg = p->getRegName(); // find an aliased register, with the same index and kind, but // with different size - RegName reg = getRegName(getRegKind(opndReg), sz, - getRegIndex(opndReg)); + RegName reg = Constraint::getAliasRegName(opndReg, sz); + assert(reg != RegName_Null); args.add(EncoderBase::Operand(reg)); } break; } } + if (inst->getId() == 12) { + // raise(SIGTRAP); + } return (uint8*)EncoderBase::encode((char*)stream, mnemonic, args); } +static Mutex opcodeGroupsLock; const Encoder::OpcodeGroupsHolder * Encoder::getOpcodeGroups(void) { - // NOTE: not multi-thread friendly ! - // Having static vars here is not safe for multi-threaded env. - // However, when Jitrino is working without Jitrino.JET, then there is - // *really* little chance that we'll get several threads here at the - // very beginning - when we just compiling java/lang/Thread::. - // When we're working with Jitrino.JET on leading edge, then we're - // getting recompilation requests from a single thread anyway. - // - // However, to be really safe (and, may be, to be ready for several - // recompilation threads) these statics need to be removed. Currently, - // we can not use auto-starting init, as we'll race with EncoderBase's - // auto-starting init of its tables. Need to change EncoderBase - // to avoid direct access to EncoderBase::mnemonic, etc. - TODO, later. static OpcodeGroupsHolder opcodeGroups[Mnemonic_Count]; - static bool groupsDone = false; - if (!groupsDone) { - memset(opcodeGroups, 0, sizeof opcodeGroups); - initOpcodeGroups(opcodeGroups); - groupsDone = true; + static volatile bool initialized = false; + if (!initialized) { + opcodeGroupsLock.lock(); + if (!initialized) { + memset(opcodeGroups, 0, sizeof opcodeGroups); + initOpcodeGroups(opcodeGroups); + initialized = true; + } + opcodeGroupsLock.unlock(); } return opcodeGroups; } @@ -295,11 +296,38 @@ const Encoder::OpcodeGroupsHolder * Enco void Encoder::initOpcodeGroups(OpcodeGroupsHolder * table) { for (unsigned mn = Mnemonic_Null; mn < Mnemonic_Count; mn++) { - buildHolder(table + mn, mnemonics[mn], opcodes[mn]); + buildOGHolder(table+ mn, mnemonics[mn], opcodes[mn]); + } +} + + +bool canBeIncluded(const Encoder::OpcodeGroup& og, Encoder::OpcodeDescription& od) +{ + unsigned notEq= 0; + unsigned oths= 0; + + for (unsigned j=0; j1 || (notEq==1 && oths > 0)) + return false; } + return true; } -void Encoder::buildHolder(OpcodeGroupsHolder * mitem, +void Encoder::buildOGHolder(OpcodeGroupsHolder * mitem, const MnemonicDesc& mdesc, const OpcodeDesc * opcodes) { @@ -328,82 +356,38 @@ void Encoder::buildHolder(OpcodeGroupsHo // unsigned j=0; for ( ; jcount; j++) { - const OpcodeGroupDescription& ogd = mitem->groups[j]; + OpcodeGroup& og = mitem->opgroups[j]; // check (1) from above - if( ogd.opndRoles.roles != od.opndRoles.roles ) continue; + if( og.opndRoles.roles != od.opndRoles.roles ) continue; // check (2) from above - OpcodeDescription& od0 = mitem->groups[j].opcodeDescriptions[0]; // - unsigned k = 0; - for (; kcount) { - // a group found. - OpcodeGroupDescription& ogd = mitem->groups[j]; - assert(ogd.opcodeDescriptionCount < - COUNTOF(ogd.opcodeDescriptions)); - ogd.opcodeDescriptions[ogd.opcodeDescriptionCount] = od; - ++ogd.opcodeDescriptionCount; continue; + } else { + // no appropriate group found, creating a new one. + assert(mitem->count < COUNTOF(mitem->opgroups)); + OpcodeGroup& og = mitem->opgroups[mitem->count]; + initOG(og, mdesc); + og.opndRoles = od.opndRoles; + for (uint32 j=0; jcount; } - // no appropriate group found, creating a new one. - assert(mitem->count < COUNTOF(mitem->groups)); - OpcodeGroupDescription& ogd = mitem->groups[mitem->count]; - initOGD(ogd, mdesc); - ogd.opndRoles = od.opndRoles; - ogd.opcodeDescriptions[0] = od; - ogd.opcodeDescriptionCount = 1; - ++mitem->count; } + for (unsigned i=0; icount; i++) { - finalizeOGD(mitem->groups[i]); + finalizeOG(mitem->opgroups[i]); } - if (getBaseConditionMnemonic(mdesc.mn) == Mnemonic_SETcc) { - // A workaround here: - // begins in the master encoding table in the record for SETcc - // instructions - see also (see enc_tabl.cpp) - there is a fake - // record fr 'SETcc rm32' instruction. - // However, we can not simply leave the instruction as is, as it will - // try to use the lower parts of EBP/ESI/EDI, which will be mapped - // to 'AH/CH/DH/DH' which is definitely not a behavior we need. - // Thus a second special case, which is implicit and resides in - // getAliasConstraint(): when we reques - // getAliasConstraint(OpndSize_32) for 'r_m8' it returns a constraint - // with mask which allows only lower 4 registers to be used (EAX, - // ECX, EDX, EBX) so only 'AL, CL, DL and BL' will be used in real. - // This magic feature of constraint prevents a tries to use - // EBP/ESI/EDI as arguments for that fake 'SETcc' instruction. - // - Constraint cRM8 = Constraint(OpndKind_GPReg, OpndSize_8)| - Constraint(OpndKind_Mem, OpndSize_8); - - for (unsigned i=0; icount; i++) { - assert(mitem->groups[i].opcodeDescriptionCount == 1); - OpcodeDescription& od = mitem->groups[i].opcodeDescriptions[0]; - assert( od.opndRoles.count == 1 ); - if (od.opndConstraints[0].getSize() == OpndSize_8) { - continue; - } - // Substitute the 'r/m32' constraint with the aliased 'r/m8' - od.opndConstraints[0] = cRM8.getAliasConstraint( - od.opndConstraints[0].getSize()); - // Clean initialized weak and strong constraints, so they'll be - // recomputed properly - mitem->groups[i].weakOpndConstraints[0] = Constraint(); - mitem->groups[i].strongOpndConstraints[0] = Constraint(); - // Recompute weak and strong constraints - finalizeOGD(mitem->groups[i]); - } - } } void Encoder::initOD(OpcodeDescription& od, const OpcodeDesc * opcode) @@ -423,139 +407,62 @@ void Encoder::initOD(OpcodeDescription& } } -void Encoder::initOGD(OpcodeGroupDescription& ogd, const MnemonicDesc& mdesc) +void Encoder::initOG(OpcodeGroup& og, const MnemonicDesc& mdesc) { - ogd.properties = - (mdesc.symmetric ? Inst::Properties_Symmetric : 0) | - (mdesc.conditional ? Inst::Properties_Conditional : 0); - - ogd.opcodeDescriptionCount = 0; + og.mnemonic = mdesc.mn; + og.properties = getMnemonicProperties(mdesc); const OpndRolesDescription NOOPNDS = {0, 0, 0, 0 }; - ogd.opndRoles = NOOPNDS; - //ogd.weakOpndConstraints[IRMaxNativeOpnds]; - //ogd.strongOpndConstraints[IRMaxNativeOpnds]; + og.opndRoles = NOOPNDS; - ogd.implicitOpndRegNames[0] = RegName_Null; - ogd.implicitOpndRegNames[1] = RegName_Null; - ogd.implicitOpndRegNames[2] = RegName_Null; + og.implicitOpndRegNames[0] = RegName_Null; + og.implicitOpndRegNames[1] = RegName_Null; + og.implicitOpndRegNames[2] = RegName_Null; - if( mdesc.affectsFlags && mdesc.usesFlags ) { - static const OpndRolesDescription DU = {1, 1, 1, + if ((mdesc.flags & MF_AFFECTS_FLAGS) && (mdesc.flags & MF_USES_FLAGS)) { + static const OpndRolesDescription _DU = {1, 1, 1, OpndRole_Def|OpndRole_Use}; - ogd.implicitOpndRoles = DU; - ogd.implicitOpndRegNames[0] = RegName_EFLAGS; + og.implicitOpndRoles = _DU; + og.implicitOpndRegNames[0] = RegName_EFLAGS; } - else if( mdesc.affectsFlags ) { - static const OpndRolesDescription D = {1, 1, 0, OpndRole_Def}; - ogd.implicitOpndRoles = D; - ogd.implicitOpndRegNames[0] = RegName_EFLAGS; + else if (mdesc.flags & MF_AFFECTS_FLAGS) { + static const OpndRolesDescription _D = {1, 1, 0, OpndRole_Def}; + og.implicitOpndRoles = _D; + og.implicitOpndRegNames[0] = RegName_EFLAGS; } - else if( mdesc.usesFlags ) { - static const OpndRolesDescription U = {1, 0, 1, OpndRole_Use}; - ogd.implicitOpndRoles = U; - ogd.implicitOpndRegNames[0] = RegName_EFLAGS; + else if (mdesc.flags & MF_USES_FLAGS) { + static const OpndRolesDescription _U = {1, 0, 1, OpndRole_Use}; + og.implicitOpndRoles = _U; + og.implicitOpndRegNames[0] = RegName_EFLAGS; } - // will be filled in finilizeOGD() - //for(int i=0; i 1) + og.properties |= Inst::Properties_MemoryOpndConditional; } }}; //namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32Encoder.h vm/jitrino/src/codegenerator/ia32/Ia32Encoder.h index df448f9..66f781a 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Encoder.h +++ vm/jitrino/src/codegenerator/ia32/Ia32Encoder.h @@ -35,136 +35,138 @@ class Inst; class Encoder : public EncoderBase { public: - // legacy code - for compatibility - typedef OpndRolesDesc OpndRolesDescription; - - /** - * struct OpcodeDescription contains the description of an opcode - */ - struct OpcodeDescription { - OpndRolesDescription opndRoles; - Constraint opndConstraints[IRMaxNativeOpnds]; - }; - - /** struct OpcodeGroupDescription contains the description of an opcode group */ - struct OpcodeGroupDescription { - uint32 properties; - uint32 opcodeDescriptionCount; - OpndRolesDescription opndRoles; - Constraint weakOpndConstraints[IRMaxNativeOpnds]; - Constraint strongOpndConstraints[IRMaxNativeOpnds]; - OpndRolesDesc implicitOpndRoles; - RegName implicitOpndRegNames[3]; - uint32 extendedToNativeMap[IRMaxExtendedOpnds]; - OpcodeDescription opcodeDescriptions[8]; - const char * printMnemonic; - }; - - - struct FindInfo { - Mnemonic mnemonic; - unsigned opndCount; - unsigned defOpndCount; - Constraint opndConstraints[IRMaxExtendedOpnds]; - bool isExtended; - const OpcodeGroupDescription * opcodeGroupDescription; - }; - - static bool matches(Constraint co, Constraint ci, uint32 opndRoles, bool allowAliases); - static const OpcodeGroupDescription * findOpcodeGroupDescription(const FindInfo& fi); - static uint32 findOpcodeDescription(const FindInfo& fi); - static bool matches(const OpcodeGroupDescription * ogd, const FindInfo& fi, bool any); - static bool matches(const OpcodeDescription * od, const FindInfo& fi); - static uint8 * emit(uint8* stream, const Inst * inst, const OpcodeDescription * desc); - /** - * Retunrs an empty opcode group. - */ - static const OpcodeGroupDescription * getDummyOpcodeGroupDescription(){ return &dummyOpcodeGroupDescription; } - /** - * Inserts the executable bytes into the byte stream. - */ - static uint8 * emit(uint8* stream, const Inst * inst); - /** - * struct MemOpndConstraints represents an element of an array of - * special memory operands. This array is referenced by the Constraint.getMemoryConstraintIndex() - * The 0 element of the constraint contains a default constraint set for the common addressing method: - * base+index*scale+displacement - */ - struct MemOpndConstraints { - Constraint constraints[MemOpndSubOpndKind_Count]; - }; - - static const MemOpndConstraints * getMemOpndConstraints(uint32 idx) - { assert(idxconstraints[subOpndIndex]; - } - - /** - * Returns a Constraint which describes all available registers of a given kind. - * Currently, it only returns 0xFF for GP and XMM regs, and '1' (a single register) - * for FP and Status registers. - * For other kinds it returns empty Constraint. - */ - static Constraint getAllRegs(OpndKind regKind); - /** - * Returns properties (see Inst::Properties) for a given mnemonic). - */ - static uint32 getMnemonicProperties(Mnemonic mn); + // legacy code - for compatibility + typedef OpndRolesDesc OpndRolesDescription; + + /** + * struct OpcodeDescription contains the description of an opcode + */ + struct OpcodeDescription { + OpndRolesDescription opndRoles; + Constraint opndConstraints[IRMaxNativeOpnds]; + }; + + /** struct OpcodeGroupDescription contains the description of an opcode group */ + struct OpcodeGroup { + Mnemonic mnemonic; + uint32 properties; + OpndRolesDescription opndRoles; + Constraint opndConstraints[IRMaxNativeOpnds]; + OpndRolesDesc implicitOpndRoles; + RegName implicitOpndRegNames[3]; + uint32 extendedToNativeMap[IRMaxExtendedOpnds]; + const char * printMnemonic; + }; + + struct FindInfo { + Mnemonic mnemonic; + unsigned opndCount; + unsigned defOpndCount; + Constraint opndConstraints[IRMaxExtendedOpnds]; + bool isExtended; + const OpcodeGroup * opcodeGroup; + }; + + static bool matches(Constraint co, Constraint ci, uint32 opndRoles, bool allowAliases); + static const OpcodeGroup* findOpcodeGroup(const FindInfo& fi); + static bool matches(const OpcodeGroup* og, const FindInfo& fi, bool any); + static bool Encoder::isOpndAllowed(const Encoder::OpcodeGroup * og, uint32 i, Constraint co, bool isExtended, bool any); + + /** + * Retunrs an empty opcode group. + */ + static const OpcodeGroup* getDummyOpcodeGroup(){ return &dummyOpcodeGroup; } + /** + * Inserts the executable bytes into the byte stream. + */ + static uint8 * emit(uint8* stream, const Inst * inst); + /** + * struct MemOpndConstraints represents an element of an array of + * special memory operands. This array is referenced by the Constraint.getMemoryConstraintIndex() + * The 0 element of the constraint contains a default constraint set for the common addressing method: + * base+index*scale+displacement + */ + struct MemOpndConstraints { + Constraint constraints[MemOpndSubOpndKind_Count]; + }; + + static const MemOpndConstraints * getMemOpndConstraints(uint32 idx) + { assert(idxconstraints[subOpndIndex]; + } + + /** + * Returns a Constraint which describes all available registers of a given kind. + * Currently, it only returns 0xFF for GP and XMM regs, and '1' (a single register) + * for FP and Status registers. + * For other kinds it returns empty Constraint. + */ + static Constraint getAllRegs(OpndKind regKind); + /** + * Returns properties (see Inst::Properties) for a given mnemonic. + */ + static uint32 getMnemonicProperties(Mnemonic mn); + + /** + * Returns properties (see Inst::Properties) for a given MnemonicDesc. + */ + static uint32 getMnemonicProperties(const MnemonicDesc& mdesc); private: - /** - * Empty opcode group. - */ - static const OpcodeGroupDescription dummyOpcodeGroupDescription; - static const MemOpndConstraints memOpndConstraints[16]; - - /** - * Maximum number of groups per mnemonic. No arithmetics behind the - * number, just measured. - */ - static const unsigned MAX_OPCODE_GROUPS = 8; - /** - * Struct OpcodeGroupsHolder represents an item in - * the array which maps mnemonics to a set of opcode group - * descriptions for the mnemonic. - */ - struct OpcodeGroupsHolder { - unsigned count; - OpcodeGroupDescription groups[MAX_OPCODE_GROUPS]; - }; + /** + * Empty opcode group. + */ + static const OpcodeGroup dummyOpcodeGroup; + static const MemOpndConstraints memOpndConstraints[16]; - /** - * Returns a table representing a mapping of a Mnemonic into - * its OpcodeGroups. - */ - static const OpcodeGroupsHolder * getOpcodeGroups(void); - /** - * Initializes the mapping table. - * Called once from the getOpcodeGroups() to initialize its - * static map. - */ - static void initOpcodeGroups(OpcodeGroupsHolder * table); - /** - * A helper function for initOpcodeGroups(), used to initialize - * a single item of OpcodeGroupsHolder. - */ - static void buildHolder(OpcodeGroupsHolder * mitem, - const MnemonicDesc& mdesc, const OpcodeDesc *); - /** - * A helper function for buildHolder(). - */ - static void initOD(OpcodeDescription& od, const OpcodeDesc * opcode); - /** - * A helper function for buildHolder(). - */ - static void initOGD(OpcodeGroupDescription& ogd, - const MnemonicDesc& mdesc); - /** - * A helper function for buildHolder(). - * Counts weak and strong constraints for the given group. - */ - static void finalizeOGD(OpcodeGroupDescription& ogd); + /** + * Maximum number of groups per mnemonic. No arithmetics behind the + * number, just measured. + */ + static const unsigned MAX_OPCODE_GROUPS = 20; + /** + * Struct OpcodeGroupsHolder represents an item in + * the array which maps mnemonics to a set of opcode group + * descriptions for the mnemonic. + */ + struct OpcodeGroupsHolder { + unsigned count; + OpcodeGroup opgroups[MAX_OPCODE_GROUPS]; + }; + + /** + * Returns a table representing a mapping of a Mnemonic into + * its OpcodeGroups. + */ + static const OpcodeGroupsHolder * getOpcodeGroups(void); + /** + * Initializes the mapping table. + * Called once from the getOpcodeGroups() to initialize its + * static map. + */ + static void initOpcodeGroups(OpcodeGroupsHolder * table); + /** + * A helper function for initOpcodeGroups(), used to initialize + * a single item of OpcodeGroupsHolder. + */ + static void buildOGHolder(OpcodeGroupsHolder * mitem, + const MnemonicDesc& mdesc, const OpcodeDesc * opcodes); + + /** + * A helper function for buildHolder(). + */ + static void initOD(OpcodeDescription& od, const OpcodeDesc * opcode); + /** + * A helper function for buildHolder(). + */ + static void initOG(OpcodeGroup& og, + const MnemonicDesc& mdesc); + /** + * A helper function for buildHolder(). + * Counts weak and strong constraints for the given group. + */ + static void finalizeOG(OpcodeGroup& og); }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32GCMap.cpp vm/jitrino/src/codegenerator/ia32/Ia32GCMap.cpp index df43b5b..2426897 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32GCMap.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32GCMap.cpp @@ -23,19 +23,17 @@ #include "Ia32Inst.h" #include "Ia32RuntimeInterface.h" #include "Ia32StackInfo.h" #include "Ia32GCSafePoints.h" - +#include "XTimer.h" #include "Ia32Printer.h" -#ifdef _DEBUG -//#define ENABLE_GC_RT_CHECKS -#endif //default mode, but could be enabled for release too - //#define ENABLE_GC_RT_CHECKS namespace Jitrino { namespace Ia32 { +static ActionFactory _gcmap("gcmap"); +static ActionFactory _info("info"); //_______________________________________________________________________ // GCMap @@ -48,25 +46,25 @@ void GCMap::registerInsts(IRManager& irm assert(offsetsInfo == NULL); assert(gcSafePoints.empty()); offsetsInfo = new (mm) GCSafePointsInfo(mm, irm, GCSafePointsInfo::MODE_2_CALC_OFFSETS); - const Nodes& nodes = irm.getNodes(); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { - processBasicBlock(irm, (BasicBlock*)node); + if (node->isBlockNode()) { + processBasicBlock(irm, node); } } } -void GCMap::processBasicBlock(IRManager& irm, const BasicBlock* block) { - uint32 safePointsInBlock = GCSafePointsInfo::getNumSafePointsInBlock(block); +void GCMap::processBasicBlock(IRManager& irm, const Node* block) { + assert(block->isBlockNode()); + POINTER_SIZE_INT safePointsInBlock = GCSafePointsInfo::getNumSafePointsInBlock(block); if (safePointsInBlock == 0) { return; } gcSafePoints.reserve(gcSafePoints.size() + safePointsInBlock); - LiveSet ls(mm, irm.getOpndCount()); + BitSet ls(mm, irm.getOpndCount()); irm.getLiveAtExit(block, ls); - const Insts& insts = block->getInsts(); - for (Inst* inst = insts.getLast(); inst!=NULL; inst = insts.getPrev(inst)) { + for (Inst* inst = (Inst*)block->getLastInst(); inst!=NULL; inst = inst->getPrevInst()) { if (IRManager::isGCSafePoint(inst)) { registerGCSafePoint(irm, ls, inst); #ifndef _DEBUG //for debug mode we collect all hardware exception points too @@ -82,15 +80,15 @@ #endif } } -void GCMap::registerGCSafePoint(IRManager& irm, const LiveSet& ls, Inst* inst) { - uint32 eip = (uint32)inst->getCodeStartAddr()+inst->getCodeSize(); +void GCMap::registerGCSafePoint(IRManager& irm, const BitSet& ls, Inst* inst) { + POINTER_SIZE_INT eip = (POINTER_SIZE_INT)inst->getCodeStartAddr()+inst->getCodeSize(); GCSafePoint* gcSafePoint = new (mm) GCSafePoint(mm, eip); GCSafePointPairs& pairs = offsetsInfo->getGCSafePointPairs(inst); const StlSet& staticFieldsMptrs = offsetsInfo->getStaticFieldMptrs(); #ifdef GC_MAP_DUMP_ENABLED StlVector* offsets = NULL; StlVector* basesAndMptrs = NULL; - bool loggingGCInst = Log::cat_cg()->isIREnabled(); + bool loggingGCInst = Log::isEnabled(); if (loggingGCInst) { offsets = new (mm) StlVector(mm); basesAndMptrs = new (mm) StlVector(mm); @@ -99,9 +97,9 @@ #endif #ifdef _DEBUG gcSafePoint->instId = inst->getId(); #endif - LiveSet::IterB liveOpnds(ls); - assert(inst->hasKind(Inst::Kind_CallInst)); - Opnd * callRes = inst->getOpndCount(Inst::OpndRole_AllDefs)>0 ? inst->getOpnd(0) : NULL; + BitSet::IterB liveOpnds(ls); + assert(inst->hasKind(Inst::Kind_CallInst)); + Opnd * callRes = inst->getOpndCount(Inst::OpndRole_AllDefs)>0 ? inst->getOpnd(0) : NULL; for (int i = liveOpnds.getNext(); i != -1; i = liveOpnds.getNext()) { Opnd* opnd = irm.getOpnd(i); if (callRes == opnd) { @@ -120,16 +118,23 @@ #endif MPtrPair* pair = GCSafePointsInfo::findPairByMPtrOpnd(pairs, opnd); int32 offset = pair == NULL ? 0 : pair->getOffset(); bool isObject = offset == 0; +#ifdef _EM64T_ + bool isCompressed = (opnd->getType()->tag <= Type::CompressedVTablePtr && opnd->getType()->tag >= Type::CompressedSystemObject); +#endif GCSafePointOpnd* gcOpnd; RegName reg = opnd->getRegName(); if (reg != RegName_Null) { +#ifdef _EM64T_ + gcOpnd = new (mm) GCSafePointOpnd(isObject, TRUE, uint32(reg), offset, isCompressed); +#else gcOpnd = new (mm) GCSafePointOpnd(isObject, TRUE, uint32(reg), offset); +#endif } else if (opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { const Opnd* displOpnd = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); assert(displOpnd!=NULL); int offset_from_esp0 = (int)displOpnd->getImmValue(); //opnd saving offset from the esp on method call int inst_offset_from_esp0 = (int)inst->getStackDepth(); - uint32 ptrToAddrOffset = inst_offset_from_esp0 + offset_from_esp0; //opnd saving offset from the esp on inst + POINTER_SIZE_INT ptrToAddrOffset = inst_offset_from_esp0 + offset_from_esp0; //opnd saving offset from the esp on inst gcOpnd = new (mm) GCSafePointOpnd(isObject, false, ptrToAddrOffset, offset); } else { assert(opnd->getMemOpndKind() == MemOpndKind_Heap); @@ -153,7 +158,7 @@ #ifdef GC_MAP_DUMP_ENABLED gcInst->desc = "gcmap"; gcInst->offsets.resize(offsets->size()); std::copy(offsets->begin(), offsets->end(), gcInst->offsets.begin()); - inst->getBasicBlock()->appendInsts(gcInst, inst); + gcInst->insertAfter(inst); } #endif } @@ -169,7 +174,7 @@ bool GCMap::isHardwareExceptionPoint(con } void GCMap::registerHardwareExceptionPoint(Inst* inst) { - uint32 eip = (uint32)inst->getCodeStartAddr(); + POINTER_SIZE_INT eip = (POINTER_SIZE_INT)inst->getCodeStartAddr(); GCSafePoint* gcSafePoint = new (mm) GCSafePoint(mm, eip); #ifdef _DEBUG gcSafePoint->instId = inst->getId(); @@ -179,19 +184,20 @@ #endif } -uint32 GCMap::getByteSize() const { - uint32 size = 4/*byte number */ + 4/*number of safepoints*/ - + 4*gcSafePoints.size()/*space to save safepoints sizes*/; +POINTER_SIZE_INT GCMap::getByteSize() const { + POINTER_SIZE_INT slotSize = sizeof(POINTER_SIZE_INT); + POINTER_SIZE_INT size = slotSize/*byte number */ + slotSize/*number of safepoints*/ + + slotSize*gcSafePoints.size()/*space to save safepoints sizes*/; for (int i=0, n = gcSafePoints.size(); igetUint32Size(); + size+= slotSize*gcSite->getUint32Size(); } return size; } -uint32 GCMap::readByteSize(const Byte* input) { - uint32* data = (uint32*)input; - uint32 gcMapSizeInBytes; +POINTER_SIZE_INT GCMap::readByteSize(const Byte* input) { + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)input; + POINTER_SIZE_INT gcMapSizeInBytes; gcMapSizeInBytes = data[0]; return gcMapSizeInBytes; @@ -210,10 +216,10 @@ struct hwecompare { #endif void GCMap::write(Byte* output) { - uint32* data = (uint32*)output; + POINTER_SIZE_INT* data = (POINTER_SIZE_INT*)output; data[0] = getByteSize(); data[1] = gcSafePoints.size(); - uint32 offs = 2; + POINTER_SIZE_INT offs = 2; #ifdef _DEBUG // make sure that hwe-points are after normal gcpoints @@ -224,24 +230,24 @@ #endif for (int i=0, n = gcSafePoints.size(); igetUint32Size(); + POINTER_SIZE_INT siteUint32Size = gcSite->getUint32Size(); data[offs++] = siteUint32Size; gcSite->write(data+offs); offs+=siteUint32Size; } - assert(4*offs == getByteSize()); + assert(sizeof(POINTER_SIZE_INT)*offs == getByteSize()); } -const uint32* GCMap::findGCSafePointStart(const uint32* data, uint32 ip) { - uint32 nGCSafePoints = data[1]; - uint32 offs = 2; - for (uint32 i = 0; i < nGCSafePoints; i++) { - uint32 siteIP = GCSafePoint::getIP(data + offs + 1); +const POINTER_SIZE_INT* GCMap::findGCSafePointStart(const POINTER_SIZE_INT* data, POINTER_SIZE_INT ip) { + POINTER_SIZE_INT nGCSafePoints = data[1]; + POINTER_SIZE_INT offs = 2; + for (POINTER_SIZE_INT i = 0; i < nGCSafePoints; i++) { + POINTER_SIZE_INT siteIP = GCSafePoint::getIP(data + offs + 1); if (siteIP == ip) { return data+offs+1; } - uint32 siteSize = data[offs]; + POINTER_SIZE_INT siteSize = data[offs]; offs+=1+siteSize; } return NULL; @@ -252,10 +258,10 @@ const uint32* GCMap::findGCSafePointStar // GCSafePoint //_______________________________________________________________________ -GCSafePoint::GCSafePoint(MemoryManager& mm, const uint32* image) : gcOpnds(mm) , ip(image[0]) { - uint32 nOpnds = image[1]; +GCSafePoint::GCSafePoint(MemoryManager& mm, const POINTER_SIZE_INT* image) : gcOpnds(mm) , ip(image[0]) { + POINTER_SIZE_INT nOpnds = image[1]; gcOpnds.reserve(nOpnds); - uint32 offs = 2; + POINTER_SIZE_INT offs = 2; for (uint32 i = 0; i< nOpnds; i++, offs+=3) { GCSafePointOpnd* gcOpnd= new (mm) GCSafePointOpnd(image[offs], int(image[offs+1]), int32(image[offs+2])); #ifdef _DEBUG @@ -270,8 +276,8 @@ #ifdef _DEBUG #endif } -uint32 GCSafePoint::getUint32Size() const { - uint32 size = 1/*ip*/+1/*nOpnds*/+GCSafePointOpnd::IMAGE_SIZE_UINT32 * gcOpnds.size()/*opnds images*/; +POINTER_SIZE_INT GCSafePoint::getUint32Size() const { + POINTER_SIZE_INT size = 1/*ip*/+1/*nOpnds*/+GCSafePointOpnd::IMAGE_SIZE_UINT32 * gcOpnds.size()/*opnds images*/; #ifdef _DEBUG size++; //instId size++; //hardwareExceptionPoint @@ -279,8 +285,8 @@ #endif return size; } -void GCSafePoint::write(uint32* data) const { - uint32 offs=0; +void GCSafePoint::write(POINTER_SIZE_INT* data) const { + POINTER_SIZE_INT offs=0; data[offs++] = ip; data[offs++] = gcOpnds.size(); for (uint32 i = 0, n = gcOpnds.size(); iisObject()) { #ifdef ENABLE_GC_RT_CHECKS GCMap::checkObject(tm, *(void**)valPtrAddr); #endif - gcInterface->enumerateRootReference((void**)valPtrAddr); +#ifdef _EM64T_ + if(gcOpnd->isCompressed()) + gcInterface->enumerateCompressedRootReference((uint32*)valPtrAddr); + else +#endif + gcInterface->enumerateRootReference((void**)valPtrAddr); } else { assert(gcOpnd->isMPtr()); - uint32 mptrAddr = *((uint32*)valPtrAddr); // + POINTER_SIZE_INT mptrAddr = *((POINTER_SIZE_INT*)valPtrAddr); // //find base, calculate offset and report to GC if (gcOpnd->getMPtrOffset() == MPTR_OFFSET_UNKNOWN) { //we looking for a base that a) located before mptr in memory b) nearest to mptr GCSafePointOpnd* baseOpnd = NULL; - uint32 basePtrAddr = 0, baseAddr = 0; + POINTER_SIZE_INT basePtrAddr = 0, baseAddr = 0; for (uint32 j =0; jisObject()) { - uint32 tmpPtrAddr = getOpndSaveAddr(context, stackInfo, tmpOpnd); - uint32 tmpBaseAddr = *((uint32*)tmpPtrAddr); + POINTER_SIZE_INT tmpPtrAddr = getOpndSaveAddr(context, stackInfo, tmpOpnd); + POINTER_SIZE_INT tmpBaseAddr = *((POINTER_SIZE_INT*)tmpPtrAddr); if (tmpBaseAddr <= mptrAddr) { if (baseOpnd == NULL || tmpBaseAddr > baseAddr) { baseOpnd = tmpOpnd; @@ -370,8 +381,8 @@ #ifdef ENABLE_GC_RT_CHECKS #endif gcInterface->enumerateRootManagedReferenceWithBase((void**)valPtrAddr, (void**)basePtrAddr); } else { // mptr - base == static_offset - int32 offset = gcOpnd->getMPtrOffset(); - assert(offset>=0); + POINTER_SIZE_INT offset = gcOpnd->getMPtrOffset(); + //assert(offset>=0); #ifdef ENABLE_GC_RT_CHECKS char* mptrAddr = *(char**)valPtrAddr; GCMap::checkObject(tm, mptrAddr - offset); @@ -382,28 +393,32 @@ #endif } } -uint32 GCSafePoint::getOpndSaveAddr(const JitFrameContext* ctx,const StackInfo& stackInfo,const GCSafePointOpnd *gcOpnd)const { - uint32 addr = 0; +POINTER_SIZE_INT GCSafePoint::getOpndSaveAddr(const JitFrameContext* ctx,const StackInfo& stackInfo,const GCSafePointOpnd *gcOpnd)const { + POINTER_SIZE_INT addr = 0; if (gcOpnd->isOnRegister()) { RegName regName = gcOpnd->getRegName(); - uint32* stackPtr = stackInfo.getRegOffset(ctx, regName); - addr = (uint32)stackPtr; + POINTER_SIZE_INT* stackPtr = stackInfo.getRegOffset(ctx, regName); + addr = (POINTER_SIZE_INT)stackPtr; } else { assert(gcOpnd->isOnStack()); +#ifdef _EM64T_ + addr = ctx->rsp + gcOpnd->getDistFromInstESP(); +#else addr = ctx->esp + gcOpnd->getDistFromInstESP(); +#endif } return addr; } void GCMapCreator::runImpl() { - MemoryManager& mm=irManager.getMemoryManager(); + MemoryManager& mm=irManager->getMemoryManager(); GCMap * gcMap=new(mm) GCMap(mm); - irManager.calculateOpndStatistics(); - gcMap->registerInsts(irManager); - irManager.setInfo("gcMap", gcMap); + irManager->calculateOpndStatistics(); + gcMap->registerInsts(*irManager); + irManager->setInfo("gcMap", gcMap); - if (Log::cat_cg()->isIREnabled()) { + if (Log::isEnabled()) { gcMap->getGCSafePointsInfo()->dump(getTagName()); } } @@ -413,11 +428,11 @@ void GCMapCreator::runImpl() { // RuntimeInterface //____________________________________________________ ___________________ -static Timer *enumerateTimer=NULL; +static CountTime enumerateTimer("ia32::gcmap::rt_enumerate"); void RuntimeInterface::getGCRootSet(MethodDesc* methodDesc, GCInterface* gcInterface, const JitFrameContext* context, bool isFirst) { - PhaseTimer tm(enumerateTimer, "ia32::gcmap::rt_enumerate"); + AutoTimer tm(enumerateTimer); /* Class_Handle parentClassHandle = method_get_class(((DrlVMMethodDesc*)methodDesc)->getDrlVMMethod()); const char* methodName = methodDesc->getName(); @@ -429,7 +444,11 @@ void RuntimeInterface::getGCRootSet(Meth uint32 stackInfoSize = StackInfo::getByteSize(methodDesc); Byte* infoBlock = methodDesc->getInfoBlock(); Byte* gcBlock = infoBlock + stackInfoSize; - const uint32* gcPointImage = GCMap::findGCSafePointStart((uint32*)gcBlock, *context->p_eip); +#ifdef _EM64T_ + const POINTER_SIZE_INT* gcPointImage = GCMap::findGCSafePointStart((POINTER_SIZE_INT*)gcBlock, *context->p_rip); +#else + const POINTER_SIZE_INT* gcPointImage = GCMap::findGCSafePointStart((POINTER_SIZE_INT*)gcBlock, *context->p_eip); +#endif if (gcPointImage != NULL) { MemoryManager mm(128,"RuntimeInterface::getGCRootSet"); GCSafePoint gcSite(mm, gcPointImage); @@ -437,7 +456,11 @@ void RuntimeInterface::getGCRootSet(Meth //this is a performance filter for empty points // and debug filter for hardware exception point that have no stack info assigned. StackInfo stackInfo(mm); +#ifdef _EM64T_ + stackInfo.read(methodDesc, *context->p_rip, false); +#else stackInfo.read(methodDesc, *context->p_eip, false); +#endif gcSite.enumerate(gcInterface, context, stackInfo); } } else { @@ -453,4 +476,39 @@ bool RuntimeInterface::canEnumerate(Meth return FALSE; } + +void InfoBlockWriter::runImpl() { + StackInfo * stackInfo = (StackInfo*)irManager->getInfo("stackInfo"); + assert(stackInfo != NULL); + GCMap * gcMap = (GCMap*)irManager->getInfo("gcMap"); + assert(gcMap != NULL); + BcMap *bcMap = (BcMap*)irManager->getInfo("bcMap"); + assert(bcMap != NULL); + InlineInfoMap * inlineInfo = (InlineInfoMap*)irManager->getInfo("inlineInfo"); + assert(inlineInfo !=NULL); + + CompilationInterface& compIntf = irManager->getCompilationInterface(); + + if ( !inlineInfo->isEmpty() ) { + inlineInfo->write(compIntf.allocateJITDataBlock(inlineInfo->computeSize(), 8)); + } + + uint32 stackInfoSize = stackInfo->getByteSize(); + uint32 gcInfoSize = gcMap->getByteSize(); + uint32 bcMapSize = bcMap->getByteSize(); // we should write at least the size of map in the info block + assert(bcMapSize >= sizeof(POINTER_SIZE_INT)); // so bcMapSize should be more than 4 for ia32 + + Byte* infoBlock = compIntf.allocateInfoBlock(stackInfoSize + gcInfoSize + bcMapSize); + stackInfo->write(infoBlock); + gcMap->write(infoBlock+stackInfoSize); + + if (compIntf.isBCMapInfoRequired()) { + bcMap->write(infoBlock + stackInfoSize + gcInfoSize); + } else { + // if no bc info write size equal to zerro + // this will make possible handle errors in case + bcMap->writeZerroSize(infoBlock + stackInfoSize + gcInfoSize); + } +} + }} //namespace diff --git vm/jitrino/src/codegenerator/ia32/Ia32GCMap.h vm/jitrino/src/codegenerator/ia32/Ia32GCMap.h index d2da129..d9ae3e3 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32GCMap.h +++ vm/jitrino/src/codegenerator/ia32/Ia32GCMap.h @@ -46,17 +46,17 @@ #endif void registerInsts(IRManager& irm); - uint32 getByteSize() const ; - static uint32 readByteSize(const Byte* input); + POINTER_SIZE_INT getByteSize() const ; + static POINTER_SIZE_INT readByteSize(const Byte* input); void write(Byte*); const GCSafePointsInfo* getGCSafePointsInfo() const {return offsetsInfo;} - static const uint32* findGCSafePointStart(const uint32* image, uint32 ip); + static const POINTER_SIZE_INT* findGCSafePointStart(const POINTER_SIZE_INT* image, POINTER_SIZE_INT ip); static void checkObject(DrlVMTypeManager& tm, const void* p); private: - void processBasicBlock(IRManager& irm, const BasicBlock* block); - void registerGCSafePoint(IRManager& irm, const LiveSet& ls, Inst* inst); + void processBasicBlock(IRManager& irm, const Node* block); + void registerGCSafePoint(IRManager& irm, const BitSet& ls, Inst* inst); void registerHardwareExceptionPoint(Inst* inst); bool isHardwareExceptionPoint(const Inst* inst) const; @@ -72,28 +72,28 @@ #endif friend class GCMap; typedef StlVector GCOpnds; public: - GCSafePoint(MemoryManager& mm, uint32 _ip):gcOpnds(mm), ip(_ip) { + GCSafePoint(MemoryManager& mm, POINTER_SIZE_INT _ip):gcOpnds(mm), ip(_ip) { #ifdef _DEBUG instId = 0; hardwareExceptionPoint = false; #endif } - GCSafePoint(MemoryManager& mm, const uint32* image); + GCSafePoint(MemoryManager& mm, const POINTER_SIZE_INT* image); - uint32 getUint32Size() const; - void write(uint32* image) const; + POINTER_SIZE_INT getUint32Size() const; + void write(POINTER_SIZE_INT* image) const; uint32 getNumOpnds() const {return gcOpnds.size();} - static uint32 getIP(const uint32* image); + static POINTER_SIZE_INT getIP(const POINTER_SIZE_INT* image); void enumerate(GCInterface* gcInterface, const JitFrameContext* c, const StackInfo& stackInfo) const; private: //return address in memory where opnd value is saved - uint32 getOpndSaveAddr(const JitFrameContext* ctx, const StackInfo& sInfo,const GCSafePointOpnd* gcOpnd) const; + POINTER_SIZE_INT getOpndSaveAddr(const JitFrameContext* ctx, const StackInfo& sInfo,const GCSafePointOpnd* gcOpnd) const; GCOpnds gcOpnds; - uint32 ip; + POINTER_SIZE_INT ip; #ifdef _DEBUG - uint32 instId; + POINTER_SIZE_INT instId; bool hardwareExceptionPoint; public: bool isHardwareExceptionPoint() const {return hardwareExceptionPoint;} @@ -104,18 +104,26 @@ #endif friend class GCSafePoint; static const uint32 OBJ_MASK = 0x1; static const uint32 REG_MASK = 0x2; +#ifdef _EM64T_ + static const uint32 COMPRESSED_MASK = 0x4; +#endif #ifdef _DEBUG // flags + val + mptrOffset + firstId static const uint32 IMAGE_SIZE_UINT32 = 4; //do not use sizeof due to the potential struct layout problems #else // flags + val + mptrOffset - static const uint32 IMAGE_SIZE_UINT32 = 3; + static const POINTER_SIZE_INT IMAGE_SIZE_UINT32 = 3; #endif public: +#ifdef _EM64T_ + GCSafePointOpnd(bool isObject, bool isOnRegister, int32 _val, int32 _mptrOffset, bool isCompressed=false) : val(_val), mptrOffset(_mptrOffset) { + flags = flags | (isCompressed ? COMPRESSED_MASK: 0); +#else GCSafePointOpnd(bool isObject, bool isOnRegister, int32 _val, int32 _mptrOffset) : val(_val), mptrOffset(_mptrOffset) { +#endif flags = isObject ? OBJ_MASK : 0; flags = flags | (isOnRegister ? REG_MASK: 0); #ifdef _DEBUG @@ -129,6 +137,9 @@ #endif bool isOnRegister() const { return (flags & REG_MASK)!=0;} bool isOnStack() const {return !isOnRegister();} +#ifdef _EM64T_ + bool isCompressed() const { return (flags & COMPRESSED_MASK)!=0;} +#endif RegName getRegName() const { assert(isOnRegister()); return RegName(val);} int32 getDistFromInstESP() const { assert(isOnStack()); return val;} @@ -149,60 +160,24 @@ #endif }; - BEGIN_DECLARE_IRTRANSFORMER(GCMapCreator, "gcmap", "GC map creation") - IRTRANSFORMER_CONSTRUCTOR(GCMapCreator) - void runImpl(); - uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo;} + class GCMapCreator : public SessionAction { + void runImpl(); + uint32 getNeedInfo()const{ return NeedInfo_LivenessInfo;} #ifdef GC_MAP_DUMP_ENABLED - uint32 getSideEffects() {return Log::cat_cg()->isIREnabled();} + uint32 getSideEffects() {return Log::isEnabled();} bool isIRDumpEnabled(){ return true;} #else uint32 getSideEffects() {return 0;} bool isIRDumpEnabled(){ return false;} #endif - - END_DECLARE_IRTRANSFORMER(GCMapCreator) - - BEGIN_DECLARE_IRTRANSFORMER(InfoBlockWriter, "info", "Creation of method info block") - IRTRANSFORMER_CONSTRUCTOR(InfoBlockWriter) - void runImpl() - { - StackInfo * stackInfo = (StackInfo*)irManager.getInfo("stackInfo"); - assert(stackInfo != NULL); - GCMap * gcMap = (GCMap*)irManager.getInfo("gcMap"); - assert(gcMap != NULL); - BcMap *bcMap = (BcMap*)irManager.getInfo("bcMap"); - assert(bcMap != NULL); - InlineInfoMap * inlineInfo = (InlineInfoMap*)irManager.getInfo("inlineInfo"); - assert(inlineInfo !=NULL); - - CompilationInterface& compIntf = irManager.getCompilationInterface(); - - if ( !inlineInfo->isEmpty() ) { - inlineInfo->write(compIntf.allocateJITDataBlock(inlineInfo->computeSize(), 8)); - } - - uint32 stackInfoSize = stackInfo->getByteSize(); - uint32 gcInfoSize = gcMap->getByteSize(); - uint32 bcMapSize = bcMap->getByteSize(); // we should write at least the size of map in the info block - assert(bcMapSize >= 4); // so bcMapSize should be more than 4 for ia32 - - Byte* infoBlock = compIntf.allocateInfoBlock(stackInfoSize + gcInfoSize + bcMapSize); - stackInfo->write(infoBlock); - gcMap->write(infoBlock+stackInfoSize); - - if (compIntf.isBCMapInfoRequired()) { - bcMap->write(infoBlock + stackInfoSize + gcInfoSize); - } else { - // if no bc info write size equal to zerro - // this will make possible handle errors in case - bcMap->writeZerroSize(infoBlock + stackInfoSize + gcInfoSize); - } - } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - bool isIRDumpEnabled(){ return false; } - END_DECLARE_IRTRANSFORMER(InfoBlockWriter) + }; + + class InfoBlockWriter : public SessionAction { + void runImpl(); + uint32 getNeedInfo()const{ return 0; } + uint32 getSideEffects()const{ return 0; } + bool isIRDumpEnabled(){ return false; } + }; }} //namespace diff --git vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp index 2d33cba..d9f7630 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ /** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.14.12.2.4.4 $ - */ +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ #include "Ia32Inst.h" #include "Ia32GCSafePoints.h" -#include "Timer.h" +#include "XTimer.h" #include "BitSet.h" @@ -30,10 +30,17 @@ namespace Jitrino #define LIVENESS_FILTER_INST_INTERVAL 128 #define LIVENESS_FILTER_OBJ_INST_INTERVAL 64 -static Timer *phase0Timer=NULL, *phase1Timer=NULL, *phase1Checker = NULL, *phase2Timer=NULL, *phase2Checker = NULL, *saveResultsTimer=NULL; +static CountTime phase0Timer("ia32::gcpointsinfo::phase0"), + phase1Timer("ia32::gcpointsinfo::phase1"), + phase1Checker("ia32::gcpointsinfo::phase1Checker"), + phase2Timer("ia32::gcpointsinfo::phase2"), + phase2Checker("ia32::gcpointsinfo::phase2Checker"), + saveResultsTimer("ia32::gcpoints::saveResults"); namespace Ia32 { +static ActionFactory _gcpoints ("gcpoints"); + // does nothing except allows to debugger to not loose local stack if method called is last in code static void dbg_point() {} @@ -50,6 +57,7 @@ static void removeElementAt(GCSafePointP pairs.resize(newSize); } + void GCSafePointsInfo::removePairByMPtrOpnd(GCSafePointPairs& pairs, const Opnd* mptr) const { #ifdef _DEBUG_ uint32 nPairs = 0; @@ -81,7 +89,7 @@ MPtrPair* GCSafePointsInfo::findPairByMP } GCSafePointsInfo::GCSafePointsInfo(MemoryManager& _mm, IRManager& _irm, Mode _mode) : -mm(_mm), irm(_irm), pairsByNodeId(_mm), pairsByGCSafePointInstId(mm), +mm(_mm), irm(_irm), pairsByNode(_mm), pairsByGCSafePointInstId(mm), livenessFilter(mm), ambiguityFilters(mm), staticMptrs(mm), allowMerging(false), opndsAdded(0), instsAdded(0), mode(_mode) { _calculate(); @@ -89,10 +97,10 @@ livenessFilter(mm), ambiguityFilters(mm) bool GCSafePointsInfo::graphHasSafePoints(const IRManager& irm){ - const Nodes& nodes = irm.getNodes(); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { + if (node->isBlockNode()) { if (blockHasSafePoints((BasicBlock*)node)) { return true; } @@ -101,9 +109,8 @@ bool GCSafePointsInfo::graphHasSafePoint return false; } -bool GCSafePointsInfo::blockHasSafePoints(const BasicBlock* b) { - const Insts& insts = b->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ +bool GCSafePointsInfo::blockHasSafePoints(const Node* b) { + for (Inst * inst=(Inst*)b->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ if (isGCSafePoint(inst)) { return true; } @@ -112,10 +119,9 @@ bool GCSafePointsInfo::blockHasSafePoint } -uint32 GCSafePointsInfo::getNumSafePointsInBlock(const BasicBlock* b, const GCSafePointPairsMap* pairsMap ) { +uint32 GCSafePointsInfo::getNumSafePointsInBlock(const Node* b, const GCSafePointPairsMap* pairsMap ) { uint32 n = 0; - const Insts& insts = b->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ + for (Inst * inst=(Inst*)b->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ if (isGCSafePoint(inst)) { if (pairsMap!=NULL) { // if pairs!=NULL counts only gcpoints with non-empty pairs GCSafePointPairsMap::const_iterator it = pairsMap->find(inst->getId()); @@ -133,7 +139,7 @@ uint32 GCSafePointsInfo::getNumSafePoint void GCSafePointsInfo::_calculate() { - assert(pairsByNodeId.empty()); + assert(pairsByNode.empty()); assert(pairsByGCSafePointInstId.empty()); //check if there are no safepoints in cfg at all @@ -160,17 +166,19 @@ void GCSafePointsInfo::_calculate() { void GCSafePointsInfo::insertLivenessFilters() { - PhaseTimer tm(phase0Timer, "ia32::gcpointsinfo::phase0"); - const Nodes& nodes = irm.getNodes(); + AutoTimer tm(phase0Timer); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)) { - const Insts& insts = ((BasicBlock*)node)->getInsts(); - if (insts.getCount() < LIVENESS_FILTER_INST_INTERVAL) { + if (node->isBlockNode()) { + uint32 numInsts = node->getInstCount(); + if (numInsts < LIVENESS_FILTER_INST_INTERVAL) { continue; } uint32 objOps = 0; - for (Inst * inst=insts.getLast(); inst != NULL ; inst=insts.getPrev(inst)) { + for (Inst* inst = (Inst*)node->getLastInst(); inst!=NULL; inst = inst->getPrevInst()) { + if (inst->getOpndCount() == 0 && ((inst->getKind() == Inst::Kind_MethodEndPseudoInst) + || (inst->getKind() == Inst::Kind_MethodEntryPseudoInst))) continue; Opnd* opnd = inst->getOpnd(0); // VSH: 0 - ???? if (opnd->getType()->isObject() || opnd->getType()->isManagedPtr()) { objOps++; @@ -183,12 +191,12 @@ void GCSafePointsInfo::insertLivenessFil continue; } // insert liveness filter for every n-th inst in block - int nFilters = insts.getCount() / LIVENESS_FILTER_INST_INTERVAL; - LiveSet* ls = new (mm) LiveSet(mm, irm.getOpndCount()); + int nFilters = numInsts / LIVENESS_FILTER_INST_INTERVAL; + BitSet* ls = new (mm) BitSet(mm, irm.getOpndCount()); irm.getLiveAtExit(node, *ls); int nFiltersLeft = nFilters; int instsInInterval = 0; - for (Inst * inst=insts.getLast(); nFiltersLeft > 0; inst=insts.getPrev(inst)) { + for (Inst* inst = (Inst*)node->getLastInst(); nFiltersLeft>0; inst = inst->getPrevInst()) { assert(inst!=NULL); irm.updateLiveness(inst, *ls); instsInInterval++; @@ -197,7 +205,7 @@ void GCSafePointsInfo::insertLivenessFil instsInInterval = 0; setLivenessFilter(inst, ls); if (nFiltersLeft != 0) { - ls = new (mm) LiveSet(*ls); + ls = new (mm) BitSet(*ls); } } } @@ -205,12 +213,12 @@ void GCSafePointsInfo::insertLivenessFil } } -void GCSafePointsInfo::setLivenessFilter(const Inst* inst, const LiveSet* ls) { +void GCSafePointsInfo::setLivenessFilter(const Inst* inst, const BitSet* ls) { livenessFilter[inst] = ls; } -const LiveSet* GCSafePointsInfo::findLivenessFilter(const Inst* inst) const { - StlMap::const_iterator it = livenessFilter.find(inst); +const BitSet* GCSafePointsInfo::findLivenessFilter(const Inst* inst) const { + StlMap::const_iterator it = livenessFilter.find(inst); if (it == livenessFilter.end()) { return NULL; } @@ -218,28 +226,24 @@ const LiveSet* GCSafePointsInfo::findLiv } void GCSafePointsInfo::calculateMPtrs() { - PhaseTimer tm(phase1Timer, "ia32::gcpointsinfo::phase1"); - assert(pairsByNodeId.empty()); - pairsByNodeId.resize(irm.getMaxNodeId()); - Nodes nodes(mm); - irm.getNodes(nodes, CFG::OrderType_Topological); - assert(nodes.back() == irm.getExitNode()); - nodes.pop_back(); - for (Nodes::iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + AutoTimer tm(phase1Timer); + assert(pairsByNode.empty()); + ControlFlowGraph* fg = irm.getFlowGraph(); + LoopTree* lt =fg->getLoopTree(); + + const Nodes& postOrderedNodes = fg->getNodesPostOrder(); + + //prepare structures + pairsByNode.resize(fg->getNodeCount()); + for (Nodes::const_iterator it = postOrderedNodes.begin(), end = postOrderedNodes.end(); it!=end; ++it) { Node* node = *it; - const Edges& outEdges = node->getEdges(Direction_Out); - if (outEdges.getCount() == 1 && outEdges.getFirst()->getNode(Direction_Head) == irm.getExitNode()) { - if (!node->hasKind(Node::Kind_BasicBlock) || !blockHasSafePoints((BasicBlock*)node)) { - *it = NULL; - continue; - } + if (node!=fg->getExitNode() && node!=fg->getUnwindNode()) { + pairsByNode[node->getDfNum()] = new (mm) GCSafePointPairs(mm); } - pairsByNodeId[node->getId()] = new (mm) GCSafePointPairs(mm); } - nodes.erase(std::remove(nodes.begin(), nodes.end(), (Node*)NULL), nodes.end()); - + GCSafePointPairs tmpPairs(mm); - uint32 nIterations = irm.getMaxLoopDepth() + 1; + uint32 nIterations = lt->getMaxLoopDepth() + 1; bool changed = true; bool restart = false; @@ -248,8 +252,11 @@ #ifdef _DEBUG #endif for (uint32 iteration = 0; iteration < nIterations ; ) { changed = false; - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + for (Nodes::const_reverse_iterator it = postOrderedNodes.rbegin(), end = postOrderedNodes.rend(); it!=end; ++it) { Node* node = *it; + if (node == fg->getExitNode() || node == fg->getUnwindNode()) { + continue; + } tmpPairs.clear(); uint32 instsBefore = instsAdded; derivePairsOnEntry(node, tmpPairs); @@ -257,10 +264,9 @@ #endif restart = true; break; } - GCSafePointPairs& nodePairs = *pairsByNodeId[node->getId()]; - if (node->hasKind(Node::Kind_BasicBlock)) { - const Insts& insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ + GCSafePointPairs& nodePairs = *pairsByNode[node->getDfNum()]; + if (node->isBlockNode()) { + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ updatePairsOnInst(inst, tmpPairs); if (isGCSafePoint(inst)) { //saving results on safepoint GCSafePointPairs* instPairs = NULL; @@ -277,15 +283,18 @@ #endif changed = true; nodePairs.swap(tmpPairs); } - } else { + } else { nodePairs.swap(tmpPairs); } } if (restart) { //clear all cached pairs and restart all iterations - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - GCSafePointPairs& pairs = *pairsByNodeId[node->getId()]; - pairs.clear(); + for (Nodes::const_iterator it2 = postOrderedNodes.begin(), end2 = postOrderedNodes.end(); it2!=end2; ++it2) { + Node* node = *it2; + GCSafePointPairs* pairs = pairsByNode[node->getDfNum()]; + assert(pairs!=NULL || node->isExitNode() || node == fg->getUnwindNode()); + if (pairs!=NULL) { + pairs->clear(); + } } iteration = 0; restart = false; @@ -298,7 +307,7 @@ #endif } #ifdef _DEBUG assert(!changed); - checkPairsOnNodeExits(nodes); + checkPairsOnNodeExits(); #endif } @@ -317,7 +326,11 @@ int32 GCSafePointsInfo::getOffsetFromImm if (offsetOpnd->getImmValue() == 0 && offsetOpnd->getRuntimeInfo()!=NULL) { irm.resolveRuntimeInfo(offsetOpnd); } +#ifndef _EM64T_ return (int32)offsetOpnd->getImmValue(); +#else + return offsetOpnd->getImmValue() == (int64)irm.getCompilationInterface().getHeapBase()?0:(int32)offsetOpnd->getImmValue(); +#endif } return MPTR_OFFSET_UNKNOWN; } @@ -325,11 +338,11 @@ int32 GCSafePointsInfo::getOffsetFromImm void GCSafePointsInfo::runLivenessFilter(Inst* inst, GCSafePointPairs& pairs) const { if (!pairs.empty()) { - const LiveSet* livenessFilter = findLivenessFilter(inst); + const BitSet* livenessFilter = findLivenessFilter(inst); if (livenessFilter!=NULL) { for (int i = pairs.size(); --i>=0;) { MPtrPair& p = pairs[i]; - if (!livenessFilter->isLive(p.mptr)) { + if (!livenessFilter->getBit(p.mptr->getId())) { removeElementAt(pairs, i); } } @@ -376,7 +389,7 @@ void GCSafePointsInfo::updateMptrInfoInP pair->base = fromPair->base; pair->mptr = newMptr; } else { // new mptr, was not used before - MPtrPair toPair(newMptr, getBaseAccordingMode(fromPair->base), newOffset); + MPtrPair toPair(newMptr, fromPair->base, newOffset); res.push_back(toPair); } } else { @@ -435,48 +448,39 @@ #endif } else { // mode == MODE_2_CALC_OFFSETS - 2 addr form //we can't rely on base/mptr type info here. //algorithm: - // if fromOpnd is Mptr -> result is Mptr - // else -> analyze inst - Opnd* fromOpnd = inst->getOpnd(useIndex1); - bool fromIsMptrOrObj = fromOpnd->getType()->isObject() || fromOpnd->getType()->isManagedPtr(); - MPtrPair* fromPair = fromIsMptrOrObj ? findPairByMPtrOpnd(res, fromOpnd) : NULL; - if (fromPair!=NULL) { // ok result is mptr + if (inst->hasKind(Inst::Kind_ControlTransferInst)) { + //Do nothing, calls return only bases + } else { + Opnd* fromOpnd = NULL; int32 offset = 0; - if (!fromIsMptrOrObj) { - assert(inst->getMnemonic() == Mnemonic_ADD); - if (fromOpnd->isPlacedIn(OpndKind_Immediate)) { - Opnd* offsetOpnd = fromOpnd; - offset = getOffsetFromImmediate(offsetOpnd); - } else { - assert(fromOpnd->isPlacedIn(OpndKind_Memory) || fromOpnd->isPlacedIn(OpndKind_Reg)); - offset = MPTR_OFFSET_UNKNOWN; - } - } - updateMptrInfoInPairs(res, opnd, fromOpnd, offset, fromPair == NULL); - dbg_point(); - } else { // try to detect if opnd is mptr or obj - if (!inst->hasKind(Inst::Kind_ControlTransferInst)) { - int32 offset = 0; - bool createNewPair = false; - if (fromIsMptrOrObj) { - MPtrPair* fromPair = findPairByMPtrOpnd(res, fromOpnd); - if (fromPair != NULL) { - offset = fromPair->getOffset(); - createNewPair = true; - } else { - processStaticFieldMptr(opnd, fromOpnd, false); + Mnemonic mn = inst->getMnemonic(); + switch (mn) { + case Mnemonic_XOR: + case Mnemonic_MOV: + assert(mn != Mnemonic_XOR || inst->getOpnd(useIndex1)==opnd); + fromOpnd = inst->getOpnd(useIndex1); + break; + case Mnemonic_ADD: { +#ifdef _EM64T_ + case Mnemonic_SUB: +#endif + fromOpnd = opnd; + Opnd* offsetOpnd = inst->getOpnd(useIndex1); + if (offsetOpnd->isPlacedIn(OpndKind_Immediate)) { + offset = getOffsetFromImmediate(offsetOpnd); + } else { + assert(offsetOpnd->isPlacedIn(OpndKind_Memory) || offsetOpnd->isPlacedIn(OpndKind_Reg)); +#ifdef _EM64T_ + if(offsetOpnd->getDefiningInst() && offsetOpnd->getDefiningInst()->getMnemonic() == Mnemonic_MOV && offsetOpnd->getDefiningInst()->getOpnd(1)->isPlacedIn(OpndKind_Immediate)) + offset = getOffsetFromImmediate(offsetOpnd->getDefiningInst()->getOpnd(1)); + else +#endif + offset = MPTR_OFFSET_UNKNOWN; + } } - } else if (staticMptrs.find(opnd) == staticMptrs.end()) { - if (inst->getMnemonic() == Mnemonic_ADD) { - if (fromOpnd->isPlacedIn(OpndKind_Immediate)) { - offset = getOffsetFromImmediate(fromOpnd); - assert(offset!=MPTR_OFFSET_UNKNOWN); - } else { - offset=MPTR_OFFSET_UNKNOWN; - } - //when offset is added to base in 2 address form -> mptr is created - createNewPair = offset!=0; - } else if (inst->getMnemonic() == Mnemonic_LEA) { + break; + case Mnemonic_LEA: { + fromOpnd = inst->getOpnd(useIndex1); assert(fromOpnd->isPlacedIn(OpndKind_Memory)); Opnd* scaleOpnd = fromOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Scale); if (scaleOpnd == NULL) { @@ -486,17 +490,24 @@ #endif } else { offset = MPTR_OFFSET_UNKNOWN; } - createNewPair = true; - } else { - assert(0); } - } - if (createNewPair) { - assert(staticMptrs.find(opnd) == staticMptrs.end()); - MPtrPair p(opnd, NULL, offset); - res.push_back(p); - } - } + break; + default: assert(0); + } + bool fromIsMptrOrObj = fromOpnd->getType()->isObject() || fromOpnd->getType()->isManagedPtr(); + MPtrPair* fromPair = fromIsMptrOrObj ? findPairByMPtrOpnd(res, fromOpnd) : NULL; + + if (fromPair != NULL || offset!=0) {//opnd is mptr -> update pairs + updateMptrInfoInPairs(res, opnd, fromOpnd, offset, fromPair == NULL); + } else { + //new def of base -> we must to remove all pairs where opnd acts as base or mptr + //the problem is that in MODE2 we do not save info about bases (no ambiguity resolution is done) + //so we can't match pairs where opnd is a base. + //Solution: let pairs derived from this base to live, due to the fact that + //such pairs must have static offset and base redefinition will not corrupt info. + //For pairs with unknown offset there is a live base -> MODE1 cares about it + removePairByMPtrOpnd(res, opnd); + } } } // else mode2 } @@ -508,17 +519,20 @@ void GCSafePointsInfo::derivePairsOnEntr // optimization: filter out those mptrs that are not live at entry. // this situation is possible because of updatePairsOnInst() function does not track liveness // and allows dead operands in pairs for block end; - const LiveSet* ls = irm.getLiveAtEntry(node); - const Edges& edges=node->getEdges(Direction_In); + const BitSet* ls = irm.getLiveAtEntry(node); + const Edges& edges=node->getInEdges(); + assert(irm.getFlowGraph()->hasValidOrdering()); + //step1: add all live pairs from pred edges into res - for (Edge* edge= edges.getFirst(); edge!=NULL; edge=edges.getNext(edge)){ - Node * predNode =edge->getNode(Direction_Tail); - const GCSafePointPairs& predPairs = *pairsByNodeId[predNode->getId()]; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node * predNode =edge->getSourceNode(); + const GCSafePointPairs& predPairs = *pairsByNode[predNode->getDfNum()]; res.reserve(res.size() + predPairs.size()); for (GCSafePointPairs::const_iterator it = predPairs.begin(), end = predPairs.end(); it!=end; ++it) { const MPtrPair& predPair = *it; - if (ls->isLive(predPair.mptr)) { + if (ls->getBit(predPair.mptr->getId())) { res.push_back(predPair);//by value } } @@ -545,22 +559,23 @@ void GCSafePointsInfo::derivePairsOnEntr newBase = irm.newOpnd(p1.base->getType()); opndsAdded++; uint32 dInsts = 0; - for (Edge* edge= edges.getFirst(); edge!=NULL; edge=edges.getNext(edge)) { - Node * predNode =edge->getNode(Direction_Tail); - GCSafePointPairs& predPairs = *pairsByNodeId[predNode->getId()]; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node * predNode =edge->getSourceNode(); + GCSafePointPairs& predPairs = *pairsByNode[predNode->getDfNum()]; for (GCSafePointPairs::iterator it = predPairs.begin(), end = predPairs.end(); it!=end; ++it) { MPtrPair& predPair = *it; if (predPair.mptr == p1.mptr) { //ok remove this pair, add vardef, add new pair Opnd* oldBase = predPair.base; - assert(predNode->hasKind(Node::Kind_BasicBlock)); + assert(predNode->isBlockNode()); BasicBlock* predBlock = (BasicBlock*)predNode; //add var def inst to predBlock Inst* baseDefInst = irm.newCopyPseudoInst(Mnemonic_MOV, newBase, oldBase); - Inst* lastInst = predBlock->getInsts().getLast(); + Inst* lastInst = (Inst*)predBlock->getLastInst(); if (lastInst!=NULL && lastInst->hasKind(Inst::Kind_ControlTransferInst)) { - predBlock->prependInsts(baseDefInst, lastInst); + baseDefInst->insertBefore(lastInst); } else { - predBlock->appendInsts(baseDefInst, lastInst); + predBlock->appendInst(baseDefInst); } if (predPair.offset!=p1.offset) { p1.offset = MPTR_OFFSET_UNKNOWN; @@ -599,14 +614,14 @@ void GCSafePointsInfo::derivePairsOnEntr } void GCSafePointsInfo::filterLiveMPtrsOnGCSafePoints() { - PhaseTimer tm(phase2Timer, "ia32::gcpointsinfo::phase2"); - assert(!pairsByNodeId.empty()); + AutoTimer tm(phase2Timer); + assert(!pairsByNode.empty()); //unoptimized impl -> analyzing all blocks -> could be moved to GCMap - const Nodes& nodes = irm.getNodes(); - LiveSet ls(mm, irm.getOpndCount()); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); + BitSet ls(mm, irm.getOpndCount()); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (!node->hasKind(Node::Kind_BasicBlock)) { + if (!node->isBlockNode()) { continue; } uint32 nSafePoints = getNumSafePointsInBlock((BasicBlock*)node, &pairsByGCSafePointInstId); @@ -614,13 +629,12 @@ void GCSafePointsInfo::filterLiveMPtrsOn continue; } // ok this basic block has safepoints - const Insts& insts=((BasicBlock*)node)->getInsts(); uint32 nSafePointsTmp = nSafePoints; // remove pairs with dead mptr, use liveness to do it; ls.clear(); irm.getLiveAtExit(node, ls); nSafePointsTmp = nSafePoints; - for (Inst * inst=insts.getLast();;inst=insts.getPrev(inst)) { + for (Inst * inst=(Inst*)node->getLastInst();;inst=inst->getPrevInst()) { assert(inst!=NULL); if (isGCSafePoint(inst)) { GCSafePointPairs& pairs = *pairsByGCSafePointInstId[inst->getId()]; @@ -628,7 +642,7 @@ void GCSafePointsInfo::filterLiveMPtrsOn nSafePointsTmp--; for (int i =pairs.size(); --i>=0;) { MPtrPair& p = pairs[i]; - if (!ls.isLive(p.mptr)) { + if (!ls.getBit(p.mptr->getId())) { removeElementAt(pairs, i); } } @@ -646,25 +660,31 @@ #endif } /// checks that sets of mptrs that come to any node from any edge are equal -void GCSafePointsInfo::checkPairsOnNodeExits(const Nodes& nodes) const { - PhaseTimer tm(phase1Checker, "ia32::gcpointsinfo::phase1Checker"); - assert(!pairsByNodeId.empty()); +void GCSafePointsInfo::checkPairsOnNodeExits() const { + AutoTimer tm(phase1Checker); + assert(!pairsByNode.empty()); + ControlFlowGraph* fg = irm.getFlowGraph(); + const Nodes& nodes = fg->getNodes(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it ) { Node* node = *it; - const LiveSet* ls = irm.getLiveAtEntry(node); - const Edges& edges=node->getEdges(Direction_In); - if(edges.getCount() > 1) { - Edge* edge1 = edges.getFirst(); - Node * predNode1 =edge1->getNode(Direction_Tail); - const GCSafePointPairs& pairs1 = *pairsByNodeId[predNode1->getId()]; + if (node == fg->getUnwindNode() || node==fg->getExitNode()) { + continue; + } + const BitSet* ls = irm.getLiveAtEntry(node); + if(node->hasTwoOrMorePredEdges()) { + const Edges& edges=node->getInEdges(); + Edge* edge1 = edges.front(); + Node * predNode1 =edge1->getSourceNode(); + const GCSafePointPairs& pairs1 = *pairsByNode[predNode1->getDfNum()]; //ensure that first edge mptr set is equal to edge2..N set - for (Edge* edge2 = edges.getNext(edge1); edge2!=NULL; edge2=edges.getNext(edge2)){ - Node * predNode2 =edge2->getNode(Direction_Tail); - const GCSafePointPairs& pairs2 = *pairsByNodeId[predNode2->getId()]; + for (Edges::const_iterator ite = edges.begin() + 1, ende = edges.end(); ite!=ende; ++ite) { + Edge* edge2 = *ite; + Node * predNode2 =edge2->getSourceNode(); + const GCSafePointPairs& pairs2 = *pairsByNode[predNode2->getDfNum()]; //now check that for every mptr in pairs1 there is a pair in pairs2 with the same mptr for (uint32 i1 = 0, n1 = pairs1.size();i1isLive(p1.mptr)) { + if (ls->getBit(p1.mptr->getId())) { for (uint32 i2 = 0; ; i2++) { assert(i2 < pairs2.size()); const MPtrPair& p2 = pairs2[i2]; @@ -677,7 +697,7 @@ void GCSafePointsInfo::checkPairsOnNodeE // and vice versa for (uint32 i2 = 0, n2 = pairs2.size();i2isLive(p2.mptr)) { + if (ls->getBit(p2.mptr->getId())) { for (uint32 i1 = 0; ; i1++) { assert(i1 < pairs1.size()); const MPtrPair& p1 = pairs1[i1]; @@ -697,13 +717,13 @@ void GCSafePointsInfo::checkPairsOnGCSaf if (mode == MODE_2_CALC_OFFSETS) { // check is done using type info. Type info is not available for mode2 return; } - PhaseTimer tm(phase2Checker, "ia32::gcpointsinfo::phase2Checker"); - const Nodes& nodes = irm.getNodes(); + AutoTimer tm(phase2Checker); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); uint32 nOpnds = irm.getOpndCount(); - LiveSet ls(mm, nOpnds); + BitSet ls(mm, nOpnds); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - if (!node->hasKind(Node::Kind_BasicBlock)) { + if (!node->isBlockNode()) { continue; } uint32 nSafePoints = getNumSafePointsInBlock((BasicBlock*)node); @@ -711,16 +731,15 @@ void GCSafePointsInfo::checkPairsOnGCSaf continue; } uint32 nSafePointsTmp = nSafePoints; - const Insts& insts=((BasicBlock*)node)->getInsts(); irm.getLiveAtExit(node, ls); - for (Inst * inst=insts.getLast(); nSafePointsTmp > 0; inst=insts.getPrev(inst)) { + for (Inst * inst=(Inst*)node->getLastInst(); nSafePointsTmp > 0; inst=inst->getPrevInst()) { assert(inst!=NULL); if (isGCSafePoint(inst)) { nSafePointsTmp--; GCSafePointPairsMap::const_iterator mit = pairsByGCSafePointInstId.find(inst->getId()); assert(mit!=pairsByGCSafePointInstId.end()); const GCSafePointPairs& pairs = *mit->second; - LiveSet::IterB liveOpnds(ls); + BitSet::IterB liveOpnds(ls); for (int i = liveOpnds.getNext(); i != -1; i = liveOpnds.getNext()) { Opnd* opnd = irm.getOpnd(i); if (opnd->getType()->isManagedPtr()) { @@ -746,9 +765,9 @@ static uint32 select_1st(const std::pair void GCSafePointsInfo::dump(const char* stage) const { - Log::cat_cg()->out()<<"========================================================================"<out()<<"__IR_DUMP_BEGIN__: pairs dump"<out()<<"========================================================================"< insts(mm, map.size()); @@ -759,49 +778,47 @@ void GCSafePointsInfo::dump(const char* for (size_t i = 0; isecond; - Log::cat_cg_gc()->out()<<"inst="<out()<<"__IR_DUMP_END__: pairs dump"<out()<<"========================================================================"< (b)) ? (a) : (b)) void GCPointsBaseLiveRangeFixer::runImpl() { - const char* params = getParameters(); - bool disableStaticOffsets = params!=NULL && !strcmp(params, "disable_static_offsets"); - MemoryManager mm(MAX(512, irManager.getOpndCount()), "GCSafePointsMarker"); - GCSafePointsInfo info(mm, irManager, GCSafePointsInfo::MODE_1_FIX_BASES); + bool disableStaticOffsets = false; + getArg("disable_static_offsets", disableStaticOffsets); + MemoryManager mm(MAX(512, irManager->getOpndCount()), "GCSafePointsMarker"); + GCSafePointsInfo info(mm, *irManager, GCSafePointsInfo::MODE_1_FIX_BASES); - if (Log::cat_cg()->isIREnabled()) { + if (Log::isEnabled()) { info.dump(getTagName()); } if(!info.hasPairs()) { return; } - PhaseTimer tm(saveResultsTimer, "ia32::gcpoints::saveResults"); - const Nodes& nodes = irManager.getNodes(); + AutoTimer tm(saveResultsTimer); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); StlVector basesAndMptrs(mm); StlVector offsets(mm); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node *node = *it; - if (!node->hasKind(Node::Kind_BasicBlock)) { + if (!node->isBlockNode()) { continue; } - BasicBlock* block = (BasicBlock*)node; - const Insts& insts=block->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)) { + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()) { if (IRManager::isGCSafePoint(inst)) { const GCSafePointPairs& pairs = info.getGCSafePointPairs(inst); if (pairs.empty()) { @@ -814,8 +831,6 @@ void GCPointsBaseLiveRangeFixer::runImpl //bases to adjust liveness info. No bases from pairs with valid static offsets get into this set for (GCSafePointPairs::const_iterator it = pairs.begin(), end = pairs.end(); it!=end; ++it) { const MPtrPair& p = *it; - //basesAndMptrs.push_back(p.getMptr()); - //offsets.push_back(p.getOffset()); if (p.getOffset() == MPTR_OFFSET_UNKNOWN) { // adjust base live range Opnd* base = p.getBase(); if (std::find(basesAndMptrs.begin(), basesAndMptrs.end(), base) == basesAndMptrs.end()) { @@ -833,11 +848,11 @@ void GCPointsBaseLiveRangeFixer::runImpl std::fill(offsets.begin(), offsets.end(), 0); } if (!basesAndMptrs.empty()) { - GCInfoPseudoInst* gcInst = irManager.newGCInfoPseudoInst(basesAndMptrs); + GCInfoPseudoInst* gcInst = irManager->newGCInfoPseudoInst(basesAndMptrs); gcInst->desc = getTagName(); gcInst->offsets.resize(offsets.size()); std::copy(offsets.begin(), offsets.end(), gcInst->offsets.begin()); - block->appendInsts(gcInst, inst); + gcInst->insertAfter(inst); } } //if inst is gc safe point } //for insts diff --git vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.h vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.h index f95698a..7b00a26 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.h +++ vm/jitrino/src/codegenerator/ia32/Ia32GCSafePoints.h @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.11.12.1.4.4 $ + * @author Mikhail Y. Fursov + * @version $Revision$ */ @@ -28,14 +28,14 @@ namespace Jitrino namespace Ia32 { -BEGIN_DECLARE_IRTRANSFORMER(GCPointsBaseLiveRangeFixer, "gcpoints", "GC Safe Points Info") - GCPointsBaseLiveRangeFixer(IRManager& irm, const char * params=0): IRTransformer(irm, params), sideEffect(0){} +class GCPointsBaseLiveRangeFixer: public SessionAction { +public: void runImpl(); uint32 getSideEffects() const {return sideEffect;} uint32 getNeedInfo()const{ return 0;} private: - uint32 sideEffect; -END_DECLARE_IRTRANSFORMER(GCPointsBaseLiveRangeFixer) + uint32 sideEffect; +}; class GCSafePointsInfo; @@ -75,7 +75,7 @@ public: if (offset!=p.offset) { return offset < p.offset; } - return &(*this) < &p; + return false; } inline bool equalBaseAndMptr(const MPtrPair& p) const {return p.mptr == mptr && p.base == base;} @@ -112,9 +112,9 @@ public: static bool isGCSafePoint(const Inst* inst) {return IRManager::isGCSafePoint(inst);} static bool graphHasSafePoints(const IRManager& irm); - static bool blockHasSafePoints(const BasicBlock* b); + static bool blockHasSafePoints(const Node* b); /** if pairs!=NULL counts only gcpoints with non-empty pairs*/ - static uint32 getNumSafePointsInBlock(const BasicBlock* b, const GCSafePointPairsMap* pairsMap = NULL); + static uint32 getNumSafePointsInBlock(const Node* b, const GCSafePointPairsMap* pairsMap = NULL); static MPtrPair* findPairByMPtrOpnd(GCSafePointPairs& pairs, const Opnd* mptr); private: @@ -123,7 +123,7 @@ private: void calculateMPtrs(); void filterLiveMPtrsOnGCSafePoints(); - void checkPairsOnNodeExits(const Nodes& nodes) const ; + void checkPairsOnNodeExits() const ; void checkPairsOnGCSafePoints() const ; /** fills res with pairs on 'node' entry, merges equal pairs and resolves ambiguous mptrs. @@ -131,7 +131,7 @@ private: */ void derivePairsOnEntry(const Node* node, GCSafePointPairs& res); void updatePairsOnInst(Inst* inst, GCSafePointPairs& res) ; - void addAllLive(const LiveSet* ls, GCSafePointPairs& res, const GCSafePointPairs& predBlockPairs) const ; + void addAllLive(const BitSet* ls, GCSafePointPairs& res, const GCSafePointPairs& predBlockPairs) const ; void processStaticFieldMptr(Opnd* opnd, Opnd* from, bool forceStatic); bool hasEqualElements(GCSafePointPairs& p1, GCSafePointPairs& p2) const { @@ -143,8 +143,8 @@ private: return std::equal(p1.begin(), p1.end(), p2.begin()); }; - void setLivenessFilter(const Inst* inst, const LiveSet* ls); - const LiveSet* findLivenessFilter(const Inst* inst) const; + void setLivenessFilter(const Inst* inst, const BitSet* ls); + const BitSet* findLivenessFilter(const Inst* inst) const; void removePairByMPtrOpnd(GCSafePointPairs& pairs, const Opnd* mptr) const; void runLivenessFilter(Inst* inst, GCSafePointPairs& res) const; Opnd* getBaseAccordingMode(Opnd* opnd) const; @@ -156,9 +156,9 @@ private: IRManager& irm; - StlVector pairsByNodeId; + StlVector pairsByNode; GCSafePointPairsMap pairsByGCSafePointInstId; - StlMap livenessFilter; + StlMap livenessFilter; StlMap ambiguityFilters; StlSet staticMptrs; bool allowMerging; diff --git vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp index ec8d2be..b991bcb 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp @@ -18,428 +18,515 @@ * @version $Revision: 1.12.6.2.4.3 $ */ -#include "Ia32I8Lowerer.h" +#include "Ia32IRManager.h" #include "Ia32Inst.h" + namespace Jitrino { namespace Ia32 { +class I8Lowerer : public SessionAction { + void runImpl(); +protected: + void processOpnds(Inst * inst, StlMap& pairs); + void prepareNewOpnds(Opnd * longOpnd, StlMap& pairs, Opnd*& newOp1, Opnd*& newOp2); + bool isI8Type(Type * t){ return t->tag==Type::Int64 || t->tag==Type::UInt64; } + uint32 getNeedInfo () const {return 0;} + virtual uint32 getSideEffects()const {return foundI8Opnds;} + + void buildShiftSubGraph(Inst * inst, Opnd * src1_1, Opnd * src1_2, Opnd * src2, Opnd * dst_1, Opnd * dst_2, Mnemonic mnem, Mnemonic opMnem); + void buildComplexSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); + void buildSetSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); + void buildJumpSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); + + uint32 foundI8Opnds; +}; + +static ActionFactory _i8l("i8l"); + //_______________________________________________________________________________________________________________ // I8 operation internal helpers int64 __stdcall imul64(const int64 src1, const int64 src2) stdcall__; int64 __stdcall imul64(const int64 src1, const int64 src2) -{ return src1*src2; } +{ return src1*src2; } int64 __stdcall idiv64(const int64 src1, const int64 src2) stdcall__; int64 __stdcall idiv64(const int64 src1, const int64 src2) -{ return src1/src2; } - -int __stdcall cmp64 (int64 src1, int64 src2) stdcall__; -int __stdcall cmp64 (int64 src1, int64 src2) -{ return src1src2?1:0; } +{ return src1/src2; } //_______________________________________________________________________________________________________________ void I8Lowerer::runImpl() { // I8 operation internal helpers - irManager.registerInternalHelperInfo("imul64", IRManager::InternalHelperInfo((void*)&imul64,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("idiv64", IRManager::InternalHelperInfo((void*)&idiv64,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("cmp64", IRManager::InternalHelperInfo((void*)&cmp64, &CallingConvention_STDCALL)); - - - StlMap pairs(irManager.getMemoryManager()); - StlVector i8Insts(irManager.getMemoryManager()); - - for(CFG::NodeIterator it(irManager, CFG::OrderType_Topological); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)) { - BasicBlock * bb = (BasicBlock*)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst = insts.getNext(inst)) { - if (inst->hasKind(Inst::Kind_I8PseudoInst) || (inst->getMnemonic()==Mnemonic_CALL || inst->getMnemonic()==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst))){ - i8Insts.push_back(inst); - foundI8Opnds = ~(uint32)0; - } - } - } - } - - for(StlVector::iterator it = i8Insts.begin(); it != i8Insts.end(); it++) { - processOpnds(*it, pairs); - } - irManager.purgeEmptyBlocks(); + irManager->registerInternalHelperInfo("imul64", IRManager::InternalHelperInfo((void*)&imul64,&CallingConvention_STDCALL)); + irManager->registerInternalHelperInfo("idiv64", IRManager::InternalHelperInfo((void*)&idiv64,&CallingConvention_STDCALL)); + + StlMap pairs(irManager->getMemoryManager()); + StlVector i8Insts(irManager->getMemoryManager()); + + ControlFlowGraph* fg = irManager->getFlowGraph(); + const Nodes* postOrder = &fg->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrder->rbegin(), end = postOrder->rend(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { + if (inst->hasKind(Inst::Kind_I8PseudoInst) || (inst->getMnemonic()==Mnemonic_CALL + || inst->getMnemonic()==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst)) + || inst->hasKind(Inst::Kind_AliasPseudoInst)){ + i8Insts.push_back(inst); + foundI8Opnds = ~(uint32)0; + } + } + } + } + + for(StlVector::iterator it = i8Insts.begin(); it != i8Insts.end(); it++) { + processOpnds(*it, pairs); + } + + fg->purgeEmptyNodes(); + + postOrder = &fg->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = postOrder->rbegin(), end = postOrder->rend(); it!=end; ++it) { + Node * node= *it; + if (node->isBlockNode()) { + Inst * cdq = NULL; + for (Inst* inst = (Inst*)node->getFirstInst(),*nextInst=NULL; inst!=NULL; inst = nextInst) { + nextInst = inst->getNextInst(); + uint32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); + if(inst->getMnemonic() == Mnemonic_CDQ) { + if (inst->getNextInst()!=NULL && inst->getNextInst()->getMnemonic() == Mnemonic_IDIV) { + continue; + } + cdq = inst; + } else if ( cdq && inst->getMnemonic() == Mnemonic_AND && + inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm) && + inst->getOpnd(defCount+1)->getImmValue() == 0 && + cdq->getOpnd(0)==inst->getOpnd(defCount)) { + Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), irManager->newImmOpnd(inst->getOpnd(0)->getType(),0)); + tmpInst->insertAfter(inst); + inst->unlink(); + inst = tmpInst; + cdq->unlink(); + cdq = NULL; + } else if ( inst->getMnemonic() == Mnemonic_AND && + inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm) && + inst->getOpnd(defCount+1)->getImmValue() == 0xFFFFFFFF) { + Inst * tmpInst = irManager->newCopyPseudoInst(Mnemonic_MOV,inst->getOpnd(0), inst->getOpnd(defCount)); + tmpInst->insertAfter(inst); + inst->unlink(); + inst = tmpInst; + } + } + } + } } void I8Lowerer::processOpnds(Inst * inst, StlMap& pairs) { - Opnd * newOp1 = NULL, *newOp2 = NULL; - Opnd * dst_1 = NULL, * dst_2 = NULL, * src1_1 = NULL, * src1_2 = NULL, * src2_1 = NULL, * src2_2 = NULL; - Mnemonic mn = inst->getMnemonic(); - if (mn==Mnemonic_CALL || mn==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst)) { - for(uint32 i = 0; i < inst->getOpndCount(); i++) { - Opnd * opnd = inst->getOpnd(i); - if (!isI8Type(opnd->getType())) - continue; - prepareNewOpnds(opnd,pairs,newOp1,newOp2); - uint32 roles = inst->getOpndRoles(i); - inst->setOpnd(i++, newOp1); - inst->insertOpnd(i, newOp2, roles); - } - } else if (inst->hasKind(Inst::Kind_I8PseudoInst)){ - uint32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def), - useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); - Opnd * dst = defCount > 0 ? inst->getOpnd(0) : NULL; - Opnd * src1 = useCount> 0 ? inst->getOpnd(defCount): NULL; - Opnd * src2 = useCount> 1 ? inst->getOpnd(defCount+1): NULL; - - if ( - mn!=Mnemonic_SAL && mn!=Mnemonic_SAR && mn!=Mnemonic_SHR && mn!=Mnemonic_IDIV && mn!=Mnemonic_IMUL) { - if (dst) - prepareNewOpnds(dst,pairs,dst_1,dst_2); - if (src1) - prepareNewOpnds(src1,pairs,src1_1,src1_2); - if (src2) - prepareNewOpnds(src2,pairs,src2_1,src2_2); - } - - BasicBlock * bb=inst->getBasicBlock(); - - switch(mn) { - case Mnemonic_ADD : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - bb->prependInsts(irManager.newInstEx(Mnemonic_ADD, 1, dst_1, src1_1, src2_1),inst); - bb->prependInsts(irManager.newInstEx(Mnemonic_ADC, 1, dst_2, src1_2, src2_2),inst); - bb->removeInst(inst); - break; - case Mnemonic_SUB : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - bb->prependInsts(irManager.newInstEx(Mnemonic_SUB, 1, dst_1, src1_1, src2_1),inst); - bb->prependInsts(irManager.newInstEx(Mnemonic_SBB, 1, dst_2, src1_2, src2_2),inst); - bb->removeInst(inst); - break; - case Mnemonic_AND : - case Mnemonic_OR : - case Mnemonic_XOR : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - case Mnemonic_NOT : - assert(dst_1 && src1_1); - assert(dst_2 && src1_2); - bb->prependInsts(irManager.newInstEx(mn, 1, dst_1, src1_1, src2_1),inst); - bb->prependInsts(irManager.newInstEx(mn, 1, dst_2, src1_2, src2_2),inst); - bb->removeInst(inst); - break; - case Mnemonic_MOV : - assert(dst_1 && src1_1); - bb->prependInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1), inst); - if (dst_2 && src1_2) - bb->prependInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2), inst); - bb->removeInst(inst); - break; - case Mnemonic_MOVSX : - case Mnemonic_MOVZX : - assert(dst_1 && dst_2 && src1_1); - assert(!src1_2); - if (src1_1->getSize()prependInsts(irManager.newInstEx(mn, 1, dst_1, src1_1), inst); - }else{ - assert(src1_1->getSize()==OpndSize_32); - bb->prependInsts(irManager.newInstEx(Mnemonic_MOV, 1, dst_1, src1_1), inst); - } - if (mn==Mnemonic_MOVSX){ - bb->prependInsts(irManager.newInstEx(Mnemonic_CDQ, 1, dst_2, dst_1), inst); - bb->removeInst(inst); - } - break; - case Mnemonic_PUSH : - assert(src1_1); - assert(src1_2); - bb->prependInsts(irManager.newInstEx(Mnemonic_PUSH, 0, src1_2),inst); - bb->prependInsts(irManager.newInstEx(Mnemonic_PUSH, 0, src1_1),inst); - bb->removeInst(inst); - break; - case Mnemonic_POP : - assert(dst_1); - assert(dst_2); - bb->prependInsts(irManager.newInstEx(Mnemonic_POP, 1, dst_1),inst); - bb->prependInsts(irManager.newInstEx(Mnemonic_POP, 1, dst_2),inst); - bb->removeInst(inst); - break; - case Mnemonic_SHL : - { - assert(dst && src1 && src2); - Opnd * args[2]={ src1, src2 }; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_ShlI64, 2, args, dst); - bb->prependInsts(callInst,inst); - processOpnds(callInst, pairs); - bb->removeInst(inst); - break; - } - case Mnemonic_SHR : - case Mnemonic_SAR : - { - assert(dst && src1 && src2); - Opnd * args[2]={ src1, src2 }; - CallInst * callInst=irManager.newRuntimeHelperCallInst(mn==Mnemonic_SAR?CompilationInterface::Helper_ShrI64:CompilationInterface::Helper_ShruI64, 2, args, dst); - bb->prependInsts(callInst,inst); - processOpnds(callInst, pairs); - bb->removeInst(inst); - break; - } - case Mnemonic_CMP : - { - assert(src1 && src2); - const Insts& insts = bb->getInsts(); - Inst * condInst = insts.getNext(inst); - Mnemonic mnem = getBaseConditionMnemonic(condInst->getMnemonic()); - if (condInst->getMnemonic() == Mnemonic_MOV) { - condInst = insts.getNext(condInst); - mnem = getBaseConditionMnemonic(condInst->getMnemonic()); - } - if (mnem != Mnemonic_NULL) { - if(condInst->hasKind(Inst::Kind_BranchInst)) { - buildJumpSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); - } else { - buildSetSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); - } - } else { - buildComplexSubGraph(inst,src1_1,src1_2,src2_1,src2_2); - } - inst->getBasicBlock()->removeInst(inst); - break; - } - case Mnemonic_IMUL : - { - assert(dst && src1 && src2); - Opnd * args[2]={ src1, src2 }; - CallInst * callInst = irManager.newInternalRuntimeHelperCallInst("imul64", 2, args, dst); - bb->prependInsts(callInst,inst); - processOpnds(callInst, pairs); - bb->removeInst(inst); - break; - } - case Mnemonic_IDIV : - { - assert(dst && src1 && src2); - Opnd * args[2]={ src1, src2 }; - CallInst * callInst = irManager.newInternalRuntimeHelperCallInst("idiv64", 2, args, dst); - bb->prependInsts(callInst,inst); - processOpnds(callInst, pairs); - bb->removeInst(inst); - break; - } - default : - assert(0); - }//end switch by mnemonics - } + Opnd * newOp1 = NULL, *newOp2 = NULL; + Opnd * dst_1 = NULL, * dst_2 = NULL, * src1_1 = NULL, * src1_2 = NULL, * src2_1 = NULL, * src2_2 = NULL; + Mnemonic mn = inst->getMnemonic(); + if (mn==Mnemonic_CALL || mn==Mnemonic_RET ||inst->hasKind(Inst::Kind_EntryPointPseudoInst) + || inst->hasKind(Inst::Kind_AliasPseudoInst)) { + for(uint32 i = 0; i < inst->getOpndCount(); i++) { + Opnd * opnd = inst->getOpnd(i); + if (!isI8Type(opnd->getType())) + continue; + uint32 roles = inst->getOpndRoles(i); + if (inst->hasKind(Inst::Kind_AliasPseudoInst)) { + if (roles & Inst::OpndRole_Use) { + prepareNewOpnds(opnd,pairs,newOp1,newOp2); + inst->setOpnd(i, newOp1); + inst->insertOpnd(i+1, newOp2, roles); + inst->setConstraint(i, Constraint(OpndKind_Mem, OpndSize_32)); + inst->setConstraint(i+1, Constraint(OpndKind_Mem, OpndSize_32)); + i++; + } + } else { + prepareNewOpnds(opnd,pairs,newOp1,newOp2); + inst->setOpnd(i++, newOp1); + inst->insertOpnd(i, newOp2, roles); + } + } + } else if (inst->hasKind(Inst::Kind_I8PseudoInst)){ + uint32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def), + useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); + Opnd * dst = defCount > 0 ? inst->getOpnd(0) : NULL; + Opnd * src1 = useCount> 0 ? inst->getOpnd(defCount): NULL; + Opnd * src2 = useCount> 1 ? inst->getOpnd(defCount+1): NULL; + + if (mn!=Mnemonic_IDIV && mn!=Mnemonic_IMUL) { + if (dst) + prepareNewOpnds(dst,pairs,dst_1,dst_2); + if (src1) + prepareNewOpnds(src1,pairs,src1_1,src1_2); + if (src2) + prepareNewOpnds(src2,pairs,src2_1,src2_2); + } + + switch(mn) { + case Mnemonic_ADD : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + irManager->newInstEx(Mnemonic_ADD, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_ADC, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + inst->unlink(); + break; + case Mnemonic_SUB : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + irManager->newInstEx(Mnemonic_SUB, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_SBB, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + inst->unlink(); + break; + case Mnemonic_AND : + case Mnemonic_OR : + case Mnemonic_XOR : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + case Mnemonic_NOT : + assert(dst_1 && src1_1); + assert(dst_2 && src1_2); + irManager->newInstEx(mn, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(mn, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + inst->unlink(); + break; + case Mnemonic_MOV : + assert(dst_1 && src1_1); + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1)->insertBefore(inst); + if (dst_2 && src1_2) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2)->insertBefore(inst); + } + inst->unlink(); + break; + case Mnemonic_MOVSX : + case Mnemonic_MOVZX : + assert(dst_1 && dst_2 && src1_1); + assert(!src1_2); + if (src1_1->getSize()newInstEx(mn, 1, dst_1, src1_1)->insertBefore(inst); + }else{ + assert(src1_1->getSize()==OpndSize_32); + irManager->newInstEx(Mnemonic_MOV, 1, dst_1, src1_1)->insertBefore(inst); + } + if (mn==Mnemonic_MOVSX){ + irManager->newInstEx(Mnemonic_CDQ, 1, dst_2, dst_1)->insertBefore(inst); + inst->unlink(); + } + break; + case Mnemonic_PUSH : + assert(src1_1); + assert(src1_2); + irManager->newInstEx(Mnemonic_PUSH, 0, src1_2)->insertBefore(inst); + irManager->newInstEx(Mnemonic_PUSH, 0, src1_1)->insertBefore(inst); + inst->unlink(); + break; + case Mnemonic_POP : + assert(dst_1); + assert(dst_2); + irManager->newInstEx(Mnemonic_POP, 1, dst_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_POP, 1, dst_2)->insertBefore(inst); + inst->unlink(); + break; + case Mnemonic_SHL : + { + assert(dst && src1 && src2); + buildShiftSubGraph(inst, src1_2, src1_1, src2, dst_2, dst_1, mn, Mnemonic_SHR); + inst->unlink(); + break; + } + case Mnemonic_SHR : + case Mnemonic_SAR : + { + assert(dst && src1 && src2); + buildShiftSubGraph(inst, src1_1, src1_2, src2, dst_1, dst_2, mn, Mnemonic_SHL); + inst->unlink(); + break; + } + case Mnemonic_CMP : + { + assert(src1 && src2); + Inst * condInst = inst->getNextInst(); + Mnemonic mnem = getBaseConditionMnemonic(condInst->getMnemonic()); + if (condInst->getMnemonic() == Mnemonic_MOV) { + condInst = condInst->getNextInst(); + mnem = getBaseConditionMnemonic(condInst->getMnemonic()); + } + if (mnem != Mnemonic_NULL) { + if(condInst->hasKind(Inst::Kind_BranchInst)) { + buildJumpSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); + } else { + buildSetSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); + } + } else { + buildComplexSubGraph(inst,src1_1,src1_2,src2_1,src2_2); + } + inst->unlink(); + break; + } + case Mnemonic_IMUL : + { + assert(dst && src1 && src2); + Opnd * args[2]={ src1, src2 }; + CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("imul64", 2, args, dst); + callInst->insertBefore(inst); + processOpnds(callInst, pairs); + inst->unlink(); + break; + } + case Mnemonic_IDIV : + { + assert(dst && src1 && src2); + Opnd * args[2]={ src1, src2 }; + CallInst * callInst = irManager->newInternalRuntimeHelperCallInst("idiv64", 2, args, dst); + callInst->insertBefore(inst); + processOpnds(callInst, pairs); + inst->unlink(); + break; + } + default : + assert(0); + }//end switch by mnemonics + } } -void I8Lowerer::buildSimpleSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2) { - CFG* subCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock* bbHMain = subCFG->getPrologNode(); - - BasicBlock* bbLMain = subCFG->newBasicBlock(); - - bbHMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_2, src2_2)); - bbHMain->appendInsts(irManager.newBranchInst(Mnemonic_JNZ)); - - bbLMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_1, src2_1)); - //TODO: sink node is useless - BasicBlock* sinkNode = subCFG->newBasicBlock(); - - ExitNode* exit = subCFG->getExitNode(); - - subCFG->newDirectBranchEdge(bbHMain, sinkNode, 0.1); - subCFG->newFallThroughEdge(bbHMain, bbLMain, 0.9); - subCFG->newFallThroughEdge(bbLMain,sinkNode, 1); - subCFG->newEdge(sinkNode, exit, 1); - irManager.mergeGraphs(&irManager, subCFG, inst, 0); +void I8Lowerer::buildShiftSubGraph(Inst * inst, Opnd * src1_1, Opnd * src1_2, Opnd * src2, Opnd * dst_1, Opnd * dst_2, Mnemonic mnem, Mnemonic opMnem) { + Opnd * dst1_1 = irManager->newOpnd(dst_2->getType()), + * dst1_2 = irManager->newOpnd(dst_2->getType()), + * tmpSrc2 = irManager->newOpnd(src2->getType()); + + if(src2->isPlacedIn(OpndKind_Imm)) { + int64 immVal = src2->getImmValue(); + immVal &= 63; + if (immVal == 32) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_2)->insertBefore(inst); + if (mnem != Mnemonic_SAR) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, irManager->newImmOpnd(src1_1->getType(), 0))->insertBefore(inst); + } else { + irManager->newInstEx(mnem, 1, dst_2, src1_2, irManager->newImmOpnd(src2->getType(), 31))->insertBefore(inst); + } + } else if(immVal > 31) { + if (mnem != Mnemonic_SAR) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, irManager->newImmOpnd(src1_1->getType(), 0))->insertBefore(inst); + } else { + irManager->newInstEx(mnem, 1, dst_2, src1_2, irManager->newImmOpnd(src2->getType(), 31))->insertBefore(inst); + } + irManager->newInstEx(mnem, 1, dst_1, src1_2, src2)->insertBefore(inst); + } else if (immVal == 0) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2)->insertBefore(inst); + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1)->insertBefore(inst); + } else { + irManager->newInstEx(mnem == Mnemonic_SAR?Mnemonic_SHR:mnem, 1, dst1_1, src1_1, src2)->insertBefore(inst); + irManager->newInstEx(opMnem, 1, dst1_2, src1_2, irManager->newImmOpnd(src2->getType(), 32-immVal))->insertBefore(inst); + irManager->newInstEx(Mnemonic_OR, 1, dst_1, dst1_2, dst1_1)->insertBefore(inst); + irManager->newInstEx(mnem, 1, dst_2, src1_2, src2)->insertBefore(inst); + } + } else { + ControlFlowGraph* subCFG = irManager->createSubCFG(true, false); + + Node* bbMain = subCFG->getEntryNode(), + * lNode = subCFG->createBlockNode(), + * gNode = subCFG->createBlockNode(), + * nullNode = subCFG->createBlockNode(), + * cmpNullNode = subCFG->createBlockNode(); + + bbMain->appendInst(irManager->newInstEx(Mnemonic_AND, 1, src2, src2, irManager->newImmOpnd(src2->getType(), 63))); + bbMain->appendInst(irManager->newInst(Mnemonic_CMP, src2, irManager->newImmOpnd(src2->getType(), 31))); + bbMain->appendInst(irManager->newBranchInst(getMnemonic(Mnemonic_Jcc, ConditionMnemonic_LE), cmpNullNode, gNode)); + + cmpNullNode->appendInst(irManager->newInst(Mnemonic_CMP, src2, irManager->newImmOpnd(src2->getType(), 0))); + cmpNullNode->appendInst(irManager->newBranchInst(getMnemonic(Mnemonic_Jcc, ConditionMnemonic_E), nullNode, lNode)); + + nullNode->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1)); + nullNode->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2)); + + if (mnem == Mnemonic_SAR) + gNode->appendInst(irManager->newInstEx(mnem, 1, dst_2, src1_2, irManager->newImmOpnd(src2->getType(), 31))); + else + gNode->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, irManager->newImmOpnd(dst_2->getType(), 0))); + gNode->appendInst(irManager->newInstEx(mnem == Mnemonic_SAR?Mnemonic_SHR:mnem, 1, dst_1, src1_2, src2)); + + lNode->appendInst(irManager->newInstEx(mnem == Mnemonic_SAR?Mnemonic_SHR:mnem, 1, dst1_1, src1_1, src2)); + lNode->appendInst(irManager->newInstEx(Mnemonic_SUB, 1, tmpSrc2, irManager->newImmOpnd(src2->getType(), 32), src2)); + lNode->appendInst(irManager->newInstEx(opMnem, 1, dst1_2, src1_2, tmpSrc2)); + lNode->appendInst(irManager->newInstEx(Mnemonic_OR, 1, dst_1, dst1_2, dst1_1)); + lNode->appendInst(irManager->newInstEx(mnem, 1, dst_2, src1_2, src2)); + + Node* sinkNode = subCFG->getReturnNode(); + + subCFG->addEdge(bbMain, cmpNullNode, 0.5); + subCFG->addEdge(bbMain, gNode, 0.5); + subCFG->addEdge(cmpNullNode, nullNode, 0.5); + subCFG->addEdge(cmpNullNode, lNode, 0.5); + subCFG->addEdge(gNode, sinkNode, 1); + subCFG->addEdge(lNode, sinkNode, 1); + subCFG->addEdge(nullNode, sinkNode, 1); + + irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG); + } } void I8Lowerer::buildJumpSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst) { - BasicBlock * bb=inst->getBasicBlock(); - - CFG* subCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock* bbHMain = subCFG->getPrologNode(); - - BasicBlock* bbLMain = subCFG->newBasicBlock(); - - bbHMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_2, src2_2)); - bbHMain->appendInsts(irManager.newBranchInst(Mnemonic_JNZ)); - - bbLMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_1, src2_1)); - //todo: sinkNode is useless - BasicBlock* sinkNode = subCFG->newBasicBlock(); - - ExitNode* exit = subCFG->getExitNode(); - - subCFG->newEdge(sinkNode, exit, 1); - - Edge * ftEdge = bb->getFallThroughEdge(); - Edge * dbEdge = bb->getDirectBranchEdge(); - BasicBlock * bbFT = (BasicBlock *)ftEdge->getNode(Direction_Head); - BasicBlock * bbDB = (BasicBlock *)dbEdge->getNode(Direction_Head); - - Mnemonic mnem = Mnemonic_NULL; - switch(condInst->getMnemonic()) { - case Mnemonic_JL : mnem = Mnemonic_JB; break; - case Mnemonic_JLE : mnem = Mnemonic_JBE; break; - case Mnemonic_JG : mnem = Mnemonic_JA; break; - case Mnemonic_JGE : mnem = Mnemonic_JAE; break; - default: mnem = condInst->getMnemonic(); break; - } - bbLMain->appendInsts(irManager.newBranchInst(mnem)); - - subCFG->newDirectBranchEdge(bbHMain, sinkNode, 0.1); - subCFG->newFallThroughEdge(bbHMain, bbLMain, 0.9); - subCFG->newFallThroughEdge(bbLMain, bbFT, 0.1); - subCFG->newDirectBranchEdge(bbLMain, bbDB, 0.9); - - irManager.mergeGraphs(&irManager, subCFG, inst, 0); + Node * bb=inst->getNode(); + + ControlFlowGraph* subCFG = irManager->createSubCFG(true, false); + Node* bbHMain = subCFG->getEntryNode(); + Node* bbLMain = subCFG->createBlockNode(); + Node* sinkNode = subCFG->getReturnNode(); + + bbHMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_2, src2_2)); + bbHMain->appendInst(irManager->newBranchInst(Mnemonic_JNZ, sinkNode, bbLMain)); + + bbLMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_1, src2_1)); + + + Node* bbFT = bb->getFalseEdgeTarget(); + Node* bbDB = bb->getTrueEdgeTarget(); + + Mnemonic mnem = Mnemonic_NULL; + switch(condInst->getMnemonic()) { + case Mnemonic_JL : mnem = Mnemonic_JB; break; + case Mnemonic_JLE : mnem = Mnemonic_JBE; break; + case Mnemonic_JG : mnem = Mnemonic_JA; break; + case Mnemonic_JGE : mnem = Mnemonic_JAE; break; + default: mnem = condInst->getMnemonic(); break; + } + bbLMain->appendInst(irManager->newBranchInst(mnem, bbDB, bbFT)); + + subCFG->addEdge(bbHMain, sinkNode, 0.1); + subCFG->addEdge(bbHMain, bbLMain, 0.9); + subCFG->addEdge(bbLMain, bbFT, 0.1); + subCFG->addEdge(bbLMain, bbDB, 0.9); + + irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG); } + void I8Lowerer::buildSetSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst) { - CFG* subCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock* bbHMain = subCFG->getPrologNode(); - - BasicBlock* bbLMain = subCFG->newBasicBlock(); - - bbHMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_2, src2_2)); - bbHMain->appendInsts(irManager.newBranchInst(Mnemonic_JNZ)); - - bbLMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_1, src2_1)); - //TODO: sinkNode is useless - BasicBlock* sinkNode = subCFG->newBasicBlock(); - - ExitNode* exit = subCFG->getExitNode(); - - - //TODO: add split-block-on-inst functionality to CFG - CFG* tmpSubCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock* tmpBB = tmpSubCFG->getPrologNode(); - ExitNode* tmpExit = tmpSubCFG->getExitNode(); - tmpSubCFG->newEdge(tmpBB, tmpExit, 1); - irManager.mergeGraphs(&irManager, tmpSubCFG, condInst, 0); - - BasicBlock* bbHF = subCFG->newBasicBlock(); - - Mnemonic mnem = getBaseConditionMnemonic(condInst->getMnemonic()); - - Inst * nextInst = inst->getBasicBlock()->getInsts().getNext(inst); - if(nextInst->getMnemonic() == Mnemonic_MOV) { - bbHF->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, nextInst->getOpnd(0), nextInst->getOpnd(1))); - bbLMain->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, nextInst->getOpnd(0), nextInst->getOpnd(1))); - nextInst->getBasicBlock()->removeInst(nextInst); - } else { - assert(nextInst == condInst); - } - bbHF->appendInsts(irManager.newInst(condInst->getMnemonic(), condInst->getOpnd(0), mnem == Mnemonic_CMOVcc? condInst->getOpnd(1): NULL)); - bbHF->appendInsts(irManager.newBranchInst(Mnemonic_JMP)); - - ConditionMnemonic condMnem = ConditionMnemonic(condInst->getMnemonic()-mnem); - switch(condMnem) { - case ConditionMnemonic_L : condMnem = ConditionMnemonic_B; break; - case ConditionMnemonic_LE : condMnem = ConditionMnemonic_BE; break; - case ConditionMnemonic_G : condMnem = ConditionMnemonic_A; break; - case ConditionMnemonic_GE : condMnem = ConditionMnemonic_AE; break; - default: break; - } - bbLMain->appendInsts(irManager.newInst(Mnemonic(mnem+condMnem), condInst->getOpnd(0), mnem == Mnemonic_CMOVcc? condInst->getOpnd(1): NULL)); - bbLMain->appendInsts(irManager.newBranchInst(Mnemonic_JMP)); - - subCFG->newDirectBranchEdge(bbHMain, bbHF, 0.1); - subCFG->newFallThroughEdge(bbHMain, bbLMain, 0.9); - subCFG->newDirectBranchEdge(bbLMain, sinkNode, 1); - subCFG->newDirectBranchEdge(bbHF, sinkNode, 1); - subCFG->newEdge(sinkNode, exit, 1); - condInst->getBasicBlock()->removeInst(condInst); - - irManager.mergeGraphs(&irManager, subCFG, inst, 0); + ControlFlowGraph* subCFG = irManager->createSubCFG(true, false); + + Node* bbHMain = subCFG->getEntryNode(); + Node* bbHF = subCFG->createBlockNode(); + Node* bbLMain = subCFG->createBlockNode(); + Node* sinkNode = subCFG->getReturnNode(); + + bbHMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_2, src2_2)); + bbHMain->appendInst(irManager->newBranchInst(Mnemonic_JNZ, bbHF, bbLMain)); + + bbLMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_1, src2_1)); + + irManager->getFlowGraph()->splitNodeAtInstruction(condInst, false, true, NULL); + + Mnemonic mnem = getBaseConditionMnemonic(condInst->getMnemonic()); + + Inst * nextInst = inst->getNextInst(); + if(nextInst->getMnemonic() == Mnemonic_MOV) { + bbHF->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, nextInst->getOpnd(0), nextInst->getOpnd(1))); + bbLMain->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, nextInst->getOpnd(0), nextInst->getOpnd(1))); + nextInst->unlink(); + } else { + assert(nextInst == condInst); + } + bbHF->appendInst(irManager->newInst(condInst->getMnemonic(), condInst->getOpnd(0), mnem == Mnemonic_CMOVcc? condInst->getOpnd(1): NULL)); + + ConditionMnemonic condMnem = ConditionMnemonic(condInst->getMnemonic()-mnem); + switch(condMnem) { + case ConditionMnemonic_L : condMnem = ConditionMnemonic_B; break; + case ConditionMnemonic_LE : condMnem = ConditionMnemonic_BE; break; + case ConditionMnemonic_G : condMnem = ConditionMnemonic_A; break; + case ConditionMnemonic_GE : condMnem = ConditionMnemonic_AE; break; + default: break; + } + bbLMain->appendInst(irManager->newInst(Mnemonic(mnem+condMnem), condInst->getOpnd(0), mnem == Mnemonic_CMOVcc? condInst->getOpnd(1): NULL)); + + subCFG->addEdge(bbHMain, bbHF, 0.1); + subCFG->addEdge(bbHMain, bbLMain, 0.9); + subCFG->addEdge(bbLMain, sinkNode, 1); + subCFG->addEdge(bbHF, sinkNode, 1); + + condInst->unlink(); + + irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG); } void I8Lowerer::buildComplexSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst) { - Opnd * dst_1 = irManager.newOpnd(irManager.getTypeManager().getInt32Type()); - CFG* subCFG = new(irManager.getMemoryManager()) CFG(irManager.getMemoryManager()); - BasicBlock* bbHMain = subCFG->getPrologNode(); - BasicBlock* bbHF = subCFG->newBasicBlock(); - BasicBlock* bbHS = subCFG->newBasicBlock(); - - BasicBlock* bbLMain = subCFG->newBasicBlock(); - BasicBlock* bbLF = subCFG->newBasicBlock(); - BasicBlock* bbLS = subCFG->newBasicBlock(); - - bbHMain->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), 0))); - bbHMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_2, src2_2)); - bbHMain->appendInsts(irManager.newBranchInst(Mnemonic_JZ)); - - bbHF->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), -1))); - bbHF->appendInsts(irManager.newBranchInst(Mnemonic_JG)); - - bbHS->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), 1))); - bbHS->appendInsts(irManager.newBranchInst(Mnemonic_JMP)); - - bbLMain->appendInsts(irManager.newInst(Mnemonic_CMP, src1_1, src2_1)); - bbLMain->appendInsts(irManager.newBranchInst(Mnemonic_JZ)); - - bbLF->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), -1))); - bbLF->appendInsts(irManager.newBranchInst(Mnemonic_JA)); - - bbLS->appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), 1))); - bbLS->appendInsts(irManager.newBranchInst(Mnemonic_JMP)); - - BasicBlock* sinkNode = subCFG->newBasicBlock(); - sinkNode->appendInsts(irManager.newInst(Mnemonic_CMP, dst_1, irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), 0))); - - ExitNode* exit = subCFG->getExitNode(); - - subCFG->newFallThroughEdge(bbHMain, bbHF, 0.1); - subCFG->newDirectBranchEdge(bbHMain, bbLMain, 0.9); - subCFG->newFallThroughEdge(bbHF, sinkNode, 0.5); - subCFG->newDirectBranchEdge(bbHF, bbHS, 0.5); - subCFG->newDirectBranchEdge(bbHS, sinkNode, 1); - subCFG->newFallThroughEdge(bbLMain, bbLF, 0.1); - subCFG->newDirectBranchEdge(bbLMain, sinkNode, 0.9); - subCFG->newFallThroughEdge(bbLF, sinkNode, 0.5); - subCFG->newDirectBranchEdge(bbLF, bbLS, 0.5); - subCFG->newDirectBranchEdge(bbLS, sinkNode, 1); - subCFG->newEdge(sinkNode, exit, 1); - - irManager.mergeGraphs(&irManager, subCFG, inst, 0); + Opnd * dst_1 = irManager->newOpnd(irManager->getTypeManager().getInt32Type()); + ControlFlowGraph* subCFG = irManager->createSubCFG(true, false); + Node* bbHMain = subCFG->getEntryNode(); + Node* bbHF = subCFG->createBlockNode(); + Node* bbHS = subCFG->createBlockNode(); + + Node* bbLMain = subCFG->createBlockNode(); + Node* bbLF = subCFG->createBlockNode(); + Node* bbLS = subCFG->createBlockNode(); + Node* sinkNode = subCFG->getReturnNode(); + + bbHMain->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0))); + bbHMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_2, src2_2)); + bbHMain->appendInst(irManager->newBranchInst(Mnemonic_JZ, bbLMain, bbHF)); + + bbHF->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), -1))); + bbHF->appendInst(irManager->newBranchInst(Mnemonic_JG, bbHS, sinkNode)); + + bbHS->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 1))); + + bbLMain->appendInst(irManager->newInst(Mnemonic_CMP, src1_1, src2_1)); + bbLMain->appendInst(irManager->newBranchInst(Mnemonic_JZ, sinkNode, bbLF)); + + bbLF->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), -1))); + bbLF->appendInst(irManager->newBranchInst(Mnemonic_JA, bbLS, sinkNode)); + + bbLS->appendInst(irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 1))); + + sinkNode->appendInst(irManager->newInst(Mnemonic_CMP, dst_1, irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0))); + + + subCFG->addEdge(bbHMain, bbHF, 0.1); + subCFG->addEdge(bbHMain, bbLMain, 0.9); + subCFG->addEdge(bbHF, sinkNode, 0.5); + subCFG->addEdge(bbHF, bbHS, 0.5); + subCFG->addEdge(bbHS, sinkNode, 1); + subCFG->addEdge(bbLMain, bbLF, 0.1); + subCFG->addEdge(bbLMain, sinkNode, 0.9); + subCFG->addEdge(bbLF, sinkNode, 0.5); + subCFG->addEdge(bbLF, bbLS, 0.5); + subCFG->addEdge(bbLS, sinkNode, 1); + + irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG); } void I8Lowerer::prepareNewOpnds(Opnd * longOpnd, StlMap& pairs, Opnd*& newOp1, Opnd*& newOp2) { - if (!isI8Type(longOpnd->getType())){ - newOp1=longOpnd; - newOp2=NULL; - return; - } - - if(pairs.find(longOpnd)!=pairs.end()) { - newOp1 = pairs[longOpnd][0]; - newOp2 = pairs[longOpnd][1]; - } else { - if(longOpnd->isPlacedIn(OpndKind_Memory)) { - newOp1 = irManager.newOpnd(irManager.getTypeManager().getUInt32Type()); - newOp2 = irManager.newOpnd(irManager.getTypeManager().getInt32Type()); - Opnd * opnds[2] = { newOp1, newOp2 }; - irManager.assignInnerMemOpnds(longOpnd, opnds, 2); - } else if(longOpnd->isPlacedIn(OpndKind_Imm)){ - newOp1 = irManager.newImmOpnd(irManager.getTypeManager().getUInt32Type(), (uint32)longOpnd->getImmValue()); - newOp2 = irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), (int32)(longOpnd->getImmValue()>>32)); - } else { - newOp1 = irManager.newOpnd(irManager.getTypeManager().getUInt32Type()); - newOp2 = irManager.newOpnd(irManager.getTypeManager().getInt32Type()); - } - pairs[longOpnd] = new(irManager.getMemoryManager()) Opnd*[2]; - pairs[longOpnd][0]=newOp1; - pairs[longOpnd][1]=newOp2; - } + if (!isI8Type(longOpnd->getType())){ + newOp1=longOpnd; + newOp2=NULL; + return; + } + + if(pairs.find(longOpnd)!=pairs.end()) { + newOp1 = pairs[longOpnd][0]; + newOp2 = pairs[longOpnd][1]; + } else { + if(longOpnd->isPlacedIn(OpndKind_Memory)) { + newOp1 = irManager->newOpnd(irManager->getTypeManager().getUInt32Type()); + newOp2 = irManager->newOpnd(irManager->getTypeManager().getInt32Type()); + Opnd * opnds[2] = { newOp1, newOp2 }; + irManager->assignInnerMemOpnds(longOpnd, opnds, 2); + } else if(longOpnd->isPlacedIn(OpndKind_Imm)){ + newOp1 = irManager->newImmOpnd(irManager->getTypeManager().getUInt32Type(), (uint32)longOpnd->getImmValue()); + newOp2 = irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), (int32)(longOpnd->getImmValue()>>32)); + } else { + newOp1 = irManager->newOpnd(irManager->getTypeManager().getUInt32Type()); + newOp2 = irManager->newOpnd(irManager->getTypeManager().getInt32Type()); + } + pairs[longOpnd] = new(irManager->getMemoryManager()) Opnd*[2]; + pairs[longOpnd][0]=newOp1; + pairs[longOpnd][1]=newOp2; + } } }} diff --git vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.h vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.h deleted file mode 100644 index 8ba043f..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Nikolay A. Sidelnikov - * @version $Revision: 1.8.20.3 $ - */ - -#ifndef _IA32_I8_LOWERER_H_ -#define _IA32_I8_LOWERER_H_ - -#include "Ia32IRManager.h" -namespace Jitrino -{ -namespace Ia32{ - -BEGIN_DECLARE_IRTRANSFORMER(I8Lowerer, "i8l", "8-byte instructions lowerer") - I8Lowerer(IRManager& irm, const char * params=0): IRTransformer(irm, params),foundI8Opnds(0) {} - void runImpl(); -protected: - void processOpnds(Inst * inst, StlMap& pairs); - void prepareNewOpnds(Opnd * longOpnd, StlMap& pairs, Opnd*& newOp1, Opnd*& newOp2); - bool isI8Type(Type * t){ return t->tag==Type::Int64 || t->tag==Type::UInt64; } - uint32 getNeedInfo () const {return 0;} - virtual uint32 getSideEffects()const {return foundI8Opnds;} - - void buildComplexSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); - void buildSetSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); - void buildJumpSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2, Inst * condInst = NULL); - void buildSimpleSubGraph(Inst * inst, Opnd * src1_1,Opnd * src1_2,Opnd * src2_1,Opnd * src2_2); - - uint32 foundI8Opnds; - -END_DECLARE_IRTRANSFORMER(I8Lowerer) - -}} //namespace Ia32 -#endif //_IA32_I8_LOWERER_H_ - diff --git vm/jitrino/src/codegenerator/ia32/Ia32IRConstants.cpp vm/jitrino/src/codegenerator/ia32/Ia32IRConstants.cpp index e252417..67ed0ea 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32IRConstants.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32IRConstants.cpp @@ -30,75 +30,75 @@ namespace Ia32{ //_________________________________________________________________________________________________ ConditionMnemonic reverseConditionMnemonics[ConditionMnemonic_Count]= { - ConditionMnemonic_NO, - ConditionMnemonic_O, - ConditionMnemonic_NB, - ConditionMnemonic_NAE, - ConditionMnemonic_NZ, - ConditionMnemonic_Z, - ConditionMnemonic_NBE, - ConditionMnemonic_NA, + ConditionMnemonic_NO, + ConditionMnemonic_O, + ConditionMnemonic_NB, + ConditionMnemonic_NAE, + ConditionMnemonic_NZ, + ConditionMnemonic_Z, + ConditionMnemonic_NBE, + ConditionMnemonic_NA, - ConditionMnemonic_NS, - ConditionMnemonic_S, - ConditionMnemonic_NP, - ConditionMnemonic_P, - ConditionMnemonic_NL, - ConditionMnemonic_NGE, - ConditionMnemonic_NLE, - ConditionMnemonic_NG, + ConditionMnemonic_NS, + ConditionMnemonic_S, + ConditionMnemonic_NP, + ConditionMnemonic_P, + ConditionMnemonic_NL, + ConditionMnemonic_NGE, + ConditionMnemonic_NLE, + ConditionMnemonic_NG, }; //_________________________________________________________________________________________________ ConditionMnemonic swappedConditionMnemonics[ConditionMnemonic_Count]= { - ConditionMnemonic_NO, - ConditionMnemonic_O, - ConditionMnemonic_A, - ConditionMnemonic_BE, - ConditionMnemonic_Z, - ConditionMnemonic_NZ, - ConditionMnemonic_AE, - ConditionMnemonic_B, + ConditionMnemonic_NO, + ConditionMnemonic_O, + ConditionMnemonic_A, + ConditionMnemonic_BE, + ConditionMnemonic_Z, + ConditionMnemonic_NZ, + ConditionMnemonic_AE, + ConditionMnemonic_B, - ConditionMnemonic_NS, - ConditionMnemonic_S, - ConditionMnemonic_P, - ConditionMnemonic_NP, - ConditionMnemonic_G, - ConditionMnemonic_LE, - ConditionMnemonic_GE, - ConditionMnemonic_L, + ConditionMnemonic_NS, + ConditionMnemonic_S, + ConditionMnemonic_P, + ConditionMnemonic_NP, + ConditionMnemonic_G, + ConditionMnemonic_LE, + ConditionMnemonic_GE, + ConditionMnemonic_L, }; //_________________________________________________________________________________________________ -Mnemonic getBaseConditionMnemonic(Mnemonic mn) +Mnemonic getBaseConditionMnemonic(Mnemonic mn) { - return - mn>=Mnemonic_Jcc && mn=Mnemonic_CMOVcc && mn=Mnemonic_SETcc && mn=Mnemonic_Jcc && mn=Mnemonic_CMOVcc && mn=Mnemonic_SETcc && mnfield)-4) +#define offsetof(cls, field) ((POINTER_SIZE_INT)&(((cls*)4)->field)-4) const uint32 EmptyUint32=((uint32)-1); const uint32 UnknownId=EmptyUint32; @@ -47,19 +47,6 @@ const uint32 IRMaxInstOpnds=512; const uint32 IRMaxOperandByteSize = 16; -//========================================================================================================= -/** enum Direction is widely used in CFG methods to indicate -directions or a particular end of a CFG nodes and edges */ -enum Direction -{ - Direction_Backward=0x0, - Direction_Tail=Direction_Backward, - Direction_In=Direction_Backward, - Direction_Forward=0x1, - Direction_Head=Direction_Forward, - Direction_Out=Direction_Forward -}; - //========================================================================================================= const uint32 IRNumRegKinds=5; @@ -70,36 +57,36 @@ const uint32 IRMaxRegNames=IRMaxRegNames //========================================================================================================= enum MemOpndKind { - MemOpndKind_Null=0, - MemOpndKind_StackAutoLayout=0xf, - MemOpndKind_StackManualLayout=0x10, - MemOpndKind_Stack=0x1f, - MemOpndKind_Heap=0x20, - MemOpndKind_ConstantArea=0x40, - MemOpndKind_Any=0xff, + MemOpndKind_Null=0, + MemOpndKind_StackAutoLayout=0xf, + MemOpndKind_StackManualLayout=0x10, + MemOpndKind_Stack=0x1f, + MemOpndKind_Heap=0x20, + MemOpndKind_ConstantArea=0x40, + MemOpndKind_Any=0xff, }; //========================================================================================================= enum MemOpndSubOpndKind { - MemOpndSubOpndKind_Base=0, - MemOpndSubOpndKind_Index, - MemOpndSubOpndKind_Scale, - MemOpndSubOpndKind_Displacement, - MemOpndSubOpndKind_Count + MemOpndSubOpndKind_Base=0, + MemOpndSubOpndKind_Index, + MemOpndSubOpndKind_Scale, + MemOpndSubOpndKind_Displacement, + MemOpndSubOpndKind_Count }; -uint32 countOnes(uint32 mask); +uint32 countOnes(uint32 mask); //========================================================================================================= -inline uint32 getByteSize(OpndSize size) +inline uint32 getByteSize(OpndSize size) { return size <= OpndSize_64 ? size : size == OpndSize_128 ? 16 : size==OpndSize_80 ? 10 : 0; } -ConditionMnemonic reverseConditionMnemonic(ConditionMnemonic cm); -ConditionMnemonic swapConditionMnemonic(ConditionMnemonic cm); +ConditionMnemonic reverseConditionMnemonic(ConditionMnemonic cm); +ConditionMnemonic swapConditionMnemonic(ConditionMnemonic cm); /** returns base condition mnemonic like Jcc for JNZ, SETcc for SETZ, etc. */ -Mnemonic getBaseConditionMnemonic(Mnemonic mn); -inline Mnemonic getMnemonic(Mnemonic mnBase, ConditionMnemonic cm){ return (Mnemonic)(mnBase+cm); } +Mnemonic getBaseConditionMnemonic(Mnemonic mn); +inline Mnemonic getMnemonic(Mnemonic mnBase, ConditionMnemonic cm){ return (Mnemonic)(mnBase+cm); } }}; // namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp index 1d8e0f7..33c5c5f 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp @@ -15,7 +15,7 @@ */ /** * @author Vyacheslav P. Shakin - * @version $Revision: 1.24.8.4.4.3 $ + * @version $Revision: 1.24.8.5.2.23 $ */ #include "Ia32IRManager.h" @@ -24,527 +24,607 @@ #include "Ia32Printer.h" #include "Log.h" #include "Ia32Printer.h" #include "Ia32CodeGenerator.h" +#include "float.h" +#include + namespace Jitrino { -namespace Ia32{ +namespace Ia32 +{ + +using namespace std; + +//========================================================================================================= +static void appendToInstList(Inst *& head, Inst * listToAppend) { + if (head==NULL) { + head=listToAppend; + } else if (listToAppend!=NULL){ + listToAppend->insertBefore(head); + } +} //_________________________________________________________________________________________________ const char * newString(MemoryManager& mm, const char * str, uint32 length) { - assert(str!=NULL); - if (length==EmptyUint32) - length=strlen(str); - char * psz=new(mm) char[length+1]; - strncpy(psz, str, length); - psz[length]=0; - return psz; + assert(str!=NULL); + if (length==EmptyUint32) + length=strlen(str); + char * psz=new(mm) char[length+1]; + strncpy(psz, str, length); + psz[length]=0; + return psz; } //_____________________________________________________________________________________________ IRManager::IRManager(MemoryManager& memManager, TypeManager& tm, MethodDesc& md, CompilationInterface& compIface) - :CFG(memManager), typeManager(tm), methodDesc(md), compilationInterface(compIface), - opndId(0), instId(0), - opnds(memManager), gpTotalRegUsage(0), entryPointInst(NULL), _hasLivenessInfo(false), - internalHelperInfos(memManager), infoMap(memManager), verificationLevel(0), - hasCalls(false), hasNonExceptionCalls(false) + :memoryManager(memManager), typeManager(tm), methodDesc(md), compilationInterface(compIface), + opndId(0), instId(0), + opnds(memManager), gpTotalRegUsage(0), entryPointInst(NULL), _hasLivenessInfo(false), + internalHelperInfos(memManager), infoMap(memManager), verificationLevel(0), + hasCalls(false), hasNonExceptionCalls(false), laidOut(false), codeStartAddr(NULL) { - for (uint32 i=0; isetEntryNode(fg->createBlockNode()); + fg->setLoopTree(new (memManager) LoopTree(memManager, fg)); + initInitialConstraints(); + registerInternalHelperInfo("printRuntimeOpndInternalHelper", IRManager::InternalHelperInfo((void*)&printRuntimeOpndInternalHelper, &CallingConvention_STDCALL)); } //_____________________________________________________________________________________________ void IRManager::addOpnd(Opnd * opnd) { - assert(opnd->id>=opnds.size()); - opnds.push_back(opnd); - opnd->id=opnds.size()-1; + assert(opnd->id>=opnds.size()); + opnds.push_back(opnd); + opnd->id=opnds.size()-1; } //_____________________________________________________________________________________________ Opnd * IRManager::newOpnd(Type * type) { - Opnd * opnd=new(memoryManager) Opnd(opndId++, type, getInitialConstraint(type)); - addOpnd(opnd); - return opnd; + Opnd * opnd=new(memoryManager) Opnd(opndId++, type, getInitialConstraint(type)); + addOpnd(opnd); + return opnd; } //_____________________________________________________________________________________________ Opnd * IRManager::newOpnd(Type * type, Constraint c) { - c.intersectWith(Constraint(OpndKind_Any, getTypeSize(type))); - assert(!c.isNull()); - Opnd * opnd=new(memoryManager) Opnd(opndId++, type, c); - addOpnd(opnd); - return opnd; + c.intersectWith(Constraint(OpndKind_Any, getTypeSize(type))); + assert(!c.isNull()); + Opnd * opnd=new(memoryManager) Opnd(opndId++, type, c); + addOpnd(opnd); + return opnd; } //_____________________________________________________________________________________________ Opnd * IRManager::newImmOpnd(Type * type, int64 immediate) { - Opnd * opnd = newOpnd(type); - opnd->assignImmValue(immediate); - return opnd; + Opnd * opnd = newOpnd(type); + opnd->assignImmValue(immediate); + return opnd; } //____________________________________________________________________________________________ Opnd * IRManager::newImmOpnd(Type * type, Opnd::RuntimeInfo::Kind kind, void * arg0, void * arg1, void * arg2, void * arg3) { - Opnd * opnd=newImmOpnd(type, 0); - opnd->setRuntimeInfo(new(memoryManager) Opnd::RuntimeInfo(kind, arg0, arg1, arg2, arg3)); - return opnd; + Opnd * opnd=newImmOpnd(type, 0); + opnd->setRuntimeInfo(new(memoryManager) Opnd::RuntimeInfo(kind, arg0, arg1, arg2, arg3)); + return opnd; } //_____________________________________________________________________________________________ ConstantAreaItem * IRManager::newConstantAreaItem(float f) { - return new(memoryManager) ConstantAreaItem( - ConstantAreaItem::Kind_FPSingleConstantAreaItem, sizeof(float), - new(memoryManager) float(f) - ); + return new(memoryManager) ConstantAreaItem( + ConstantAreaItem::Kind_FPSingleConstantAreaItem, sizeof(float), + new(memoryManager) float(f) + ); } //_____________________________________________________________________________________________ -ConstantAreaItem * IRManager::newConstantAreaItem(double d) +ConstantAreaItem * IRManager::newConstantAreaItem(double d) { - return new(memoryManager) ConstantAreaItem( - ConstantAreaItem::Kind_FPDoubleConstantAreaItem, sizeof(double), - new(memoryManager) double(d) - ); + return new(memoryManager) ConstantAreaItem( + ConstantAreaItem::Kind_FPDoubleConstantAreaItem, sizeof(double), + new(memoryManager) double(d) + ); } //_____________________________________________________________________________________________ -ConstantAreaItem * IRManager::newSwitchTableConstantAreaItem(uint32 numTargets) +ConstantAreaItem * IRManager::newSwitchTableConstantAreaItem(uint32 numTargets) { - return new(memoryManager) ConstantAreaItem( - ConstantAreaItem::Kind_SwitchTableConstantAreaItem, sizeof(BasicBlock*)*numTargets, - new(memoryManager) BasicBlock*[numTargets] - ); + return new(memoryManager) ConstantAreaItem( + ConstantAreaItem::Kind_SwitchTableConstantAreaItem, sizeof(BasicBlock*)*numTargets, + new(memoryManager) BasicBlock*[numTargets] + ); } //_____________________________________________________________________________________________ -ConstantAreaItem * IRManager::newInternalStringConstantAreaItem(const char * str) +ConstantAreaItem * IRManager::newInternalStringConstantAreaItem(const char * str) { - if (str==NULL) - str=""; - return new(memoryManager) ConstantAreaItem( - ConstantAreaItem::Kind_InternalStringConstantAreaItem, strlen(str)+1, - (void*)newInternalString(str) - ); + if (str==NULL) + str=""; + return new(memoryManager) ConstantAreaItem( + ConstantAreaItem::Kind_InternalStringConstantAreaItem, strlen(str)+1, + (void*)newInternalString(str) + ); } //_____________________________________________________________________________________________ ConstantAreaItem * IRManager::newBinaryConstantAreaItem(uint32 size, const void * pv) { - return new(memoryManager) ConstantAreaItem(ConstantAreaItem::Kind_BinaryConstantAreaItem, size, pv); + return new(memoryManager) ConstantAreaItem(ConstantAreaItem::Kind_BinaryConstantAreaItem, size, pv); } //_____________________________________________________________________________________________ -Opnd * IRManager::newFPConstantMemOpnd(float f) -{ - ConstantAreaItem * item=newConstantAreaItem(f); - Opnd * addr=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); - return newMemOpndAutoKind(typeManager.getSingleType(), MemOpndKind_ConstantArea, addr); +Opnd * IRManager::newFPConstantMemOpnd(float f, Opnd * baseOpnd, BasicBlock* bb) +{ + ConstantAreaItem * item=newConstantAreaItem(f); + Opnd * addr=newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getSingleType()), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); +#ifdef _EM64T_ + bb->appendInst(newCopyPseudoInst(Mnemonic_MOV, baseOpnd, addr)); + return newMemOpndAutoKind(typeManager.getSingleType(), MemOpndKind_ConstantArea, baseOpnd); +#else + return newMemOpndAutoKind(typeManager.getSingleType(), MemOpndKind_ConstantArea, addr); +#endif } //_____________________________________________________________________________________________ -Opnd * IRManager::newFPConstantMemOpnd(double d) -{ - ConstantAreaItem * item=newConstantAreaItem(d); - Opnd * addr=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); - return newMemOpndAutoKind(typeManager.getDoubleType(), MemOpndKind_ConstantArea, addr); +Opnd * IRManager::newFPConstantMemOpnd(double d, Opnd * baseOpnd, BasicBlock* bb) +{ + ConstantAreaItem * item=newConstantAreaItem(d); + Opnd * addr=newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getDoubleType()), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); +#ifdef _EM64T_ + bb->appendInst(newCopyPseudoInst(Mnemonic_MOV, baseOpnd, addr)); + return newMemOpndAutoKind(typeManager.getDoubleType(), MemOpndKind_ConstantArea, baseOpnd); +#else + return newMemOpndAutoKind(typeManager.getDoubleType(), MemOpndKind_ConstantArea, addr); +#endif } //_____________________________________________________________________________________________ Opnd * IRManager::newSwitchTableConstantMemOpnd(uint32 numTargets, Opnd * index) { - ConstantAreaItem * item=newSwitchTableConstantAreaItem(numTargets); - Opnd * switchTable=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); - return newMemOpnd(typeManager.getIntPtrType(), MemOpndKind_ConstantArea, 0, index, newImmOpnd(typeManager.getInt32Type(), 4), switchTable); + ConstantAreaItem * item=newSwitchTableConstantAreaItem(numTargets); +#ifdef _EM64T_ + Opnd * switchTable=newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); +#else + Opnd * switchTable=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); +#endif + return newMemOpnd(typeManager.getIntPtrType(), MemOpndKind_ConstantArea, 0, index, newImmOpnd(typeManager.getInt32Type(), sizeof(POINTER_SIZE_INT)), switchTable); } //_____________________________________________________________________________________________ Opnd * IRManager::newInternalStringConstantImmOpnd(const char * str) { - ConstantAreaItem * item=newInternalStringConstantAreaItem(str); - return newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); + ConstantAreaItem * item=newInternalStringConstantAreaItem(str); + return newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getIntPtrType()), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); } //_____________________________________________________________________________________________ Opnd * IRManager::newBinaryConstantImmOpnd(uint32 size, const void * pv) { - ConstantAreaItem * item=newBinaryConstantAreaItem(size, pv); - return newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); + ConstantAreaItem * item=newBinaryConstantAreaItem(size, pv); + return newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getIntPtrType()), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); } //_____________________________________________________________________________________________ SwitchInst * IRManager::newSwitchInst(uint32 numTargets, Opnd * index) { - SwitchInst * inst=new(memoryManager, 1) SwitchInst(Mnemonic_JMP, instId++); - assert(numTargets>0); - assert(index!=NULL); - Opnd * targetOpnd=newSwitchTableConstantMemOpnd(numTargets, index); - inst->insertOpnd(0, targetOpnd, Inst::OpndRole_Explicit); - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + Inst * instList = NULL; +#ifndef _EM64T_ + SwitchInst * inst=new(memoryManager, 1) SwitchInst(Mnemonic_JMP, instId++); + assert(numTargets>0); + assert(index!=NULL); + Opnd * targetOpnd=newSwitchTableConstantMemOpnd(numTargets, index); +#else + + ConstantAreaItem * item=newSwitchTableConstantAreaItem(numTargets); + Opnd * tableAddr = newImmOpnd(typeManager.getInt64Type(), Opnd::RuntimeInfo::Kind_ConstantAreaItem, item); + + SwitchInst * inst=new(memoryManager, 1) SwitchInst(Mnemonic_JMP, instId++, tableAddr); + assert(numTargets>0); + assert(index!=NULL); + Opnd * baseOpnd = newOpnd(typeManager.getInt64Type()); + appendToInstList(instList, newCopyPseudoInst(Mnemonic_MOV, baseOpnd, tableAddr)); + Opnd * targetOpnd = newMemOpnd(typeManager.getUnmanagedPtrType(typeManager.getIntPtrType()), MemOpndKind_ConstantArea, baseOpnd, index, newImmOpnd(typeManager.getInt32Type(), sizeof(POINTER_SIZE_INT)), 0); +#endif + inst->insertOpnd(0, targetOpnd, Inst::OpndRole_Explicit); + inst->assignOpcodeGroup(this); + appendToInstList(instList, inst); + return (SwitchInst *)instList; } //_____________________________________________________________________________________________ Opnd * IRManager::newRegOpnd(Type * type, RegName reg) { - Opnd * opnd = newOpnd(type, Constraint(getRegKind(reg))); - opnd->assignRegName(reg); - return opnd; + Opnd * opnd = newOpnd(type, Constraint(getRegKind(reg))); + opnd->assignRegName(reg); + return opnd; } //_____________________________________________________________________________________________ -Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd * index, Opnd * scale, Opnd * displacement, RegName baseReg) +Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd * index, Opnd * scale, Opnd * displacement, RegName segReg) { - Opnd * opnd = newOpnd(type); - opnd->assignMemLocation(k,base,index,scale,displacement); - if (baseReg != RegName_Null) - opnd->setBaseReg(baseReg); - return opnd; + Opnd * opnd = newOpnd(type); + opnd->assignMemLocation(k,base,index,scale,displacement); + if (segReg != RegName_Null) + opnd->setSegReg(segReg); + return opnd; } //_________________________________________________________________________________________________ -Opnd * IRManager::newMemOpnd(Type * type, Opnd * base, Opnd * index, Opnd * scale, Opnd * displacement, RegName baseReg) +Opnd * IRManager::newMemOpnd(Type * type, Opnd * base, Opnd * index, Opnd * scale, Opnd * displacement, RegName segReg) { - return newMemOpnd(type, MemOpndKind_Heap, base, index, scale, displacement, baseReg); + return newMemOpnd(type, MemOpndKind_Heap, base, index, scale, displacement, segReg); } //_____________________________________________________________________________________________ -Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, int32 displacement, RegName baseReg) +Opnd * IRManager::newMemOpnd(Type * type, MemOpndKind k, Opnd * base, int32 displacement, RegName segReg) { - return newMemOpnd(type, k, base, 0, 0, newImmOpnd(typeManager.getInt32Type(), displacement), baseReg); + return newMemOpnd(type, k, base, 0, 0, newImmOpnd(typeManager.getInt32Type(), displacement), segReg); } //_____________________________________________________________________________________________ Opnd * IRManager::newMemOpndAutoKind(Type * type, MemOpndKind k, Opnd * opnd0, Opnd * opnd1, Opnd * opnd2) { - Opnd * base=NULL, * displacement=NULL; - - Constraint c=opnd0->getConstraint(Opnd::ConstraintKind_Current); - if (!(c&OpndKind_GPReg).isNull()){ - base=opnd0; - }else if (!(c&OpndKind_Imm).isNull()){ - displacement=opnd0; - }else - assert(0); - - if (opnd1!=NULL){ - c=opnd1->getConstraint(Opnd::ConstraintKind_Current); - if (!(c&OpndKind_GPReg).isNull()){ - base=opnd1; - }else if (!(c&OpndKind_Imm).isNull()){ - displacement=opnd1; - }else - assert(0); - } + Opnd * base=NULL, * displacement=NULL; + + Constraint c=opnd0->getConstraint(Opnd::ConstraintKind_Current); + if (!(c&OpndKind_GPReg).isNull()){ + base=opnd0; + }else if (!(c&OpndKind_Imm).isNull()){ + displacement=opnd0; + }else + assert(0); + + if (opnd1!=NULL){ + c=opnd1->getConstraint(Opnd::ConstraintKind_Current); + if (!(c&OpndKind_GPReg).isNull()){ + base=opnd1; + }else if (!(c&OpndKind_Imm).isNull()){ + displacement=opnd1; + }else + assert(0); + } - return newMemOpnd(type, k, base, 0, 0, displacement); + return newMemOpnd(type, k, base, 0, 0, displacement); } //_____________________________________________________________________________________________ void IRManager::initInitialConstraints() { - for (uint32 i=0; igetOpnds(); - uint32 * roles = inst->getOpndRoles(); - if (opnd0!=NULL){ opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd1!=NULL){ opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd2!=NULL){ opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; - }}} - inst->opndCount = i; - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + Inst * inst = new(memoryManager, 4) Inst(mnemonic, instId++, Inst::Form_Native); + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + uint32 * roles = inst->getOpndRoles(); + if (opnd0!=NULL){ opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd1!=NULL){ opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd2!=NULL){ opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; + }}} + inst->opndCount = i; + inst->assignOpcodeGroup(this); + return inst; } //_____________________________________________________________________________________________ Inst * IRManager::newInst(Mnemonic mnemonic, - Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, - Opnd * opnd4, Opnd * opnd5, Opnd * opnd6, Opnd * opnd7 - ) -{ - Inst * inst = new(memoryManager, 8) Inst(mnemonic, instId++, Inst::Form_Native); - uint32 i=0; - Opnd ** opnds = inst->getOpnds(); - uint32 * roles = inst->getOpndRoles(); - if (opnd0!=NULL){ opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd1!=NULL){ opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd2!=NULL){ opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd3!=NULL){ opnds[i] = opnd3; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd4!=NULL){ opnds[i] = opnd4; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd5!=NULL){ opnds[i] = opnd5; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd6!=NULL){ opnds[i] = opnd6; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd7!=NULL){ opnds[i] = opnd7; roles[i] = Inst::OpndRole_Explicit; i++; - }}}}}}}}; - inst->opndCount = i; - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, + Opnd * opnd4, Opnd * opnd5, Opnd * opnd6, Opnd * opnd7 + ) +{ + Inst * inst = new(memoryManager, 8) Inst(mnemonic, instId++, Inst::Form_Native); + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + uint32 * roles = inst->getOpndRoles(); + if (opnd0!=NULL){ opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd1!=NULL){ opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd2!=NULL){ opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd3!=NULL){ opnds[i] = opnd3; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd4!=NULL){ opnds[i] = opnd4; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd5!=NULL){ opnds[i] = opnd5; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd6!=NULL){ opnds[i] = opnd6; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd7!=NULL){ opnds[i] = opnd7; roles[i] = Inst::OpndRole_Explicit; i++; + }}}}}}}}; + inst->opndCount = i; + inst->assignOpcodeGroup(this); + return inst; } //_____________________________________________________________________________________________ Inst * IRManager::newInstEx(Mnemonic mnemonic, uint32 defCount, Opnd * opnd0, Opnd * opnd1, Opnd * opnd2) { - Inst * inst = new(memoryManager, 4) Inst(mnemonic, instId++, Inst::Form_Extended); - uint32 i=0; - Opnd ** opnds = inst->getOpnds(); - uint32 * roles = inst->getOpndRoles(); - if (opnd0!=NULL){ - opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd1!=NULL){ - opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd2!=NULL){ - opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; - }}} - inst->opndCount = i; - inst->defOpndCount=defCount; - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + Inst * inst = new(memoryManager, 4) Inst(mnemonic, instId++, Inst::Form_Extended); + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + uint32 * roles = inst->getOpndRoles(); + if (opnd0!=NULL){ + opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd1!=NULL){ + opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd2!=NULL){ + opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; + }}} + inst->opndCount = i; + inst->defOpndCount=defCount; + inst->assignOpcodeGroup(this); + return inst; } //_____________________________________________________________________________________________ Inst * IRManager::newInstEx(Mnemonic mnemonic, uint32 defCount, - Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, - Opnd * opnd4, Opnd * opnd5, Opnd * opnd6, Opnd * opnd7 - ) -{ - Inst * inst = new(memoryManager, 8) Inst(mnemonic, instId++, Inst::Form_Extended); - uint32 i=0; - Opnd ** opnds = inst->getOpnds(); - uint32 * roles = inst->getOpndRoles(); - if (opnd0!=NULL){ - opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd1!=NULL){ - opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd2!=NULL){ - opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd3!=NULL){ - opnds[i] = opnd3; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd4!=NULL){ - opnds[i] = opnd4; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd5!=NULL){ - opnds[i] = opnd5; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd6!=NULL){ - opnds[i] = opnd6; roles[i] = Inst::OpndRole_Explicit; i++; - if (opnd7!=NULL){ - opnds[i] = opnd7; roles[i] = Inst::OpndRole_Explicit; i++; - }}}}}}}}; - inst->opndCount = i; - inst->defOpndCount=defCount; - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, + Opnd * opnd4, Opnd * opnd5, Opnd * opnd6, Opnd * opnd7 + ) +{ + Inst * inst = new(memoryManager, 8) Inst(mnemonic, instId++, Inst::Form_Extended); + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + uint32 * roles = inst->getOpndRoles(); + if (opnd0!=NULL){ + opnds[i] = opnd0; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd1!=NULL){ + opnds[i] = opnd1; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd2!=NULL){ + opnds[i] = opnd2; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd3!=NULL){ + opnds[i] = opnd3; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd4!=NULL){ + opnds[i] = opnd4; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd5!=NULL){ + opnds[i] = opnd5; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd6!=NULL){ + opnds[i] = opnd6; roles[i] = Inst::OpndRole_Explicit; i++; + if (opnd7!=NULL){ + opnds[i] = opnd7; roles[i] = Inst::OpndRole_Explicit; i++; + }}}}}}}}; + inst->opndCount = i; + inst->defOpndCount=defCount; + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ Inst * IRManager::newI8PseudoInst(Mnemonic mnemonic, uint32 defCount, - Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3 - ) -{ - Inst * inst=new (memoryManager, 4) Inst(mnemonic, instId++, Inst::Form_Extended); - inst->kind = Inst::Kind_I8PseudoInst; - uint32 i=0; - Opnd ** opnds = inst->getOpnds(); - assert(opnd0->getType()->isInteger()); - if (opnd0!=NULL){ opnds[i] = opnd0; i++; - if (opnd1!=NULL){ opnds[i] = opnd1; i++; - if (opnd2!=NULL){ opnds[i] = opnd2; i++; - if (opnd3!=NULL){ opnds[i] = opnd3; i++; assert(opnd3->getSize()==OpndSize_64); - }}}}; - inst->defOpndCount=defCount; - inst->opndCount = i; - inst->assignOpcodeGroup(this); - return inst; + Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3 + ) +{ + Inst * inst=new (memoryManager, 4) Inst(mnemonic, instId++, Inst::Form_Extended); + inst->kind = Inst::Kind_I8PseudoInst; + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + assert(opnd0->getType()->isInteger()); + if (opnd0!=NULL){ opnds[i] = opnd0; i++; + if (opnd1!=NULL){ opnds[i] = opnd1; i++; + if (opnd2!=NULL){ opnds[i] = opnd2; i++; + if (opnd3!=NULL){ opnds[i] = opnd3; i++; assert(opnd3->getSize()==OpndSize_64); + }}}}; + inst->defOpndCount=defCount; + inst->opndCount = i; + inst->assignOpcodeGroup(this); + return inst; } //_____________________________________________________________________________________________ SystemExceptionCheckPseudoInst * IRManager::newSystemExceptionCheckPseudoInst(CompilationInterface::SystemExceptionId exceptionId, Opnd * opnd0, Opnd * opnd1, bool checksThisForInlinedMethod) { - SystemExceptionCheckPseudoInst * inst=new (memoryManager, 8) SystemExceptionCheckPseudoInst(exceptionId, instId++, checksThisForInlinedMethod); - uint32 i=0; - Opnd ** opnds = inst->getOpnds(); - if (opnd0!=NULL){ opnds[i++] = opnd0; - if (opnd1!=NULL){ opnds[i++] = opnd1; - }} - inst->opndCount = i; - inst->assignOpcodeGroup(this); - return inst; + SystemExceptionCheckPseudoInst * inst=new (memoryManager, 8) SystemExceptionCheckPseudoInst(exceptionId, instId++, checksThisForInlinedMethod); + uint32 i=0; + Opnd ** opnds = inst->getOpnds(); + if (opnd0!=NULL){ opnds[i++] = opnd0; + if (opnd1!=NULL){ opnds[i++] = opnd1; + }} + inst->opndCount = i; + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ -BranchInst * IRManager::newBranchInst(Mnemonic mnemonic, Opnd * targetOpnd) +BranchInst * IRManager::newBranchInst(Mnemonic mnemonic, Node* trueTarget, Node* falseTarget, Opnd * targetOpnd) +{ + BranchInst * inst=new(memoryManager, 2) BranchInst(mnemonic, instId++); + if (targetOpnd==0) + targetOpnd=newImmOpnd(typeManager.getInt32Type(), 0); + inst->insertOpnd(0, targetOpnd, Inst::OpndRole_Explicit); + inst->assignOpcodeGroup(this); + inst->setFalseTarget(falseTarget); + inst->setTrueTarget(trueTarget); + return inst; +} + +//_________________________________________________________________________________________________ +JumpInst * IRManager::newJumpInst(Opnd * targetOpnd) { - BranchInst * inst=new(memoryManager, 2) BranchInst(mnemonic, instId++); - if (targetOpnd==0) - targetOpnd=newImmOpnd(typeManager.getIntPtrType(), 0); - inst->insertOpnd(0, targetOpnd, Inst::OpndRole_Explicit); - inst->assignOpcodeGroup(this); - inst->verify(); - return inst; + JumpInst * inst=new(memoryManager, 2) JumpInst(instId++); + if (targetOpnd==0) { + targetOpnd=newImmOpnd(typeManager.getInt32Type(), 0); + } + inst->insertOpnd(0, targetOpnd, Inst::OpndRole_Explicit); + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ EntryPointPseudoInst * IRManager::newEntryPointPseudoInst(const CallingConvention * cc) { - // there is nothing wrong with calling this method several times. - // it's just a self-check, as the currently assumed behaviour is that this method is invoked only once. - assert(NULL == entryPointInst); + // there is nothing wrong with calling this method several times. + // it's just a self-check, as the currently assumed behaviour is that this method is invoked only once. + assert(NULL == entryPointInst); - EntryPointPseudoInst * inst=new(memoryManager, methodDesc.getMethodSig()->getNumParams() * 2) EntryPointPseudoInst(this, instId++, cc); - getPrologNode()->appendInsts( inst ); + EntryPointPseudoInst * inst=new(memoryManager, methodDesc.getMethodSig()->getNumParams() * 2) EntryPointPseudoInst(this, instId++, cc); + fg->getEntryNode()->appendInst(inst); - inst->assignOpcodeGroup(this); - entryPointInst = inst; - return inst; + inst->assignOpcodeGroup(this); + entryPointInst = inst; + + if (getCompilationInterface().getCompilationParams().exe_notify_method_entry) { + Opnd **hlpArgs = new (memoryManager) Opnd* [1]; + hlpArgs[0] = newImmOpnd(typeManager.getIntPtrType(), + Opnd::RuntimeInfo::Kind_MethodRuntimeId, &methodDesc); + Node* prolog = getFlowGraph()->getEntryNode(); + prolog->appendInst(newRuntimeHelperCallInst(CompilationInterface::Helper_MethodEntry, + 1, (Opnd**)hlpArgs, NULL)); + } + + + return inst; } //_________________________________________________________________________________________________ CallInst * IRManager::newCallInst(Opnd * targetOpnd, const CallingConvention * cc, - uint32 argCount, Opnd ** args, Opnd * retOpnd, InlineInfo* ii) -{ - CallInst * callInst=new(memoryManager, (argCount + (retOpnd ? 1 : 0)) * 2 + 1) CallInst(this, instId++, cc, ii); - CallingConventionClient & ccc = callInst->callingConventionClient; - uint32 i=0; - if (retOpnd!=NULL){ - ccc.pushInfo(Inst::OpndRole_Def, retOpnd->getType()->tag); - callInst->insertOpnd(i++, retOpnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Def); - } - callInst->defOpndCount = i; - callInst->insertOpnd(i++, targetOpnd, Inst::OpndRole_Explicit|Inst::OpndRole_Use); - - if (argCount>0){ - for (uint32 j=0; jgetType()->tag); - callInst->insertOpnd(i++, args[j], Inst::OpndRole_Auxilary|Inst::OpndRole_Use); - } - } - callInst->opndCount = i; - callInst->assignOpcodeGroup(this); - return callInst; + uint32 argCount, Opnd ** args, Opnd * retOpnd, InlineInfo* ii) +{ + CallInst * callInst=new(memoryManager, (argCount + (retOpnd ? 1 : 0)) * 2 + 1) CallInst(this, instId++, cc, ii); + CallingConventionClient & ccc = callInst->callingConventionClient; + uint32 i=0; + if (retOpnd!=NULL){ + ccc.pushInfo(Inst::OpndRole_Def, retOpnd->getType()->tag); + callInst->insertOpnd(i++, retOpnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Def); + } + callInst->defOpndCount = i; + callInst->insertOpnd(i++, targetOpnd, Inst::OpndRole_Explicit|Inst::OpndRole_Use); + + if (argCount>0){ + for (uint32 j=0; jgetType()->tag); + callInst->insertOpnd(i++, args[j], Inst::OpndRole_Auxilary|Inst::OpndRole_Use); + } + } + callInst->opndCount = i; + callInst->assignOpcodeGroup(this); + return callInst; } //_________________________________________________________________________________________________ CallInst * IRManager::newRuntimeHelperCallInst(CompilationInterface::RuntimeHelperId helperId, - uint32 numArgs, Opnd ** args, Opnd * retOpnd) + uint32 numArgs, Opnd ** args, Opnd * retOpnd, InlineInfo* ii) { - Opnd * target=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_HelperAddress, (void*)helperId); - const CallingConvention * cc=getCallingConvention(helperId); - return newCallInst(target, cc, numArgs, args, retOpnd); + Inst * instList = NULL; + Opnd * target=newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getIntPtrType()), Opnd::RuntimeInfo::Kind_HelperAddress, (void*)helperId); + const CallingConvention * cc=getCallingConvention(helperId); + appendToInstList(instList,newCallInst(target, cc, numArgs, args, retOpnd)); + return (CallInst *)instList; } //_________________________________________________________________________________________________ CallInst * IRManager::newInternalRuntimeHelperCallInst(const char * internalHelperID, uint32 numArgs, Opnd ** args, Opnd * retOpnd) { - const InternalHelperInfo * info=getInternalHelperInfo(internalHelperID); - assert(info!=NULL); - Opnd * target=newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_InternalHelperAddress, (void*)newInternalString(internalHelperID)); - const CallingConvention * cc=info->callingConvention; - return newCallInst(target, cc, numArgs, args, retOpnd); + const InternalHelperInfo * info=getInternalHelperInfo(internalHelperID); + assert(info!=NULL); + Inst * instList = NULL; + Opnd * target=newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getIntPtrType()), Opnd::RuntimeInfo::Kind_InternalHelperAddress, (void*)newInternalString(internalHelperID)); + const CallingConvention * cc=info->callingConvention; + appendToInstList(instList,newCallInst(target, cc, numArgs, args, retOpnd)); + return (CallInst *)instList; +} +//_________________________________________________________________________________________________ +Inst* IRManager::newEmptyPseudoInst() { + return new(memoryManager, 0) EmptyPseudoInst(instId++); +} +//_________________________________________________________________________________________________ +MethodMarkerPseudoInst* IRManager::newMethodEntryPseudoInst(MethodDesc* mDesc) { + return new(memoryManager, 0) MethodMarkerPseudoInst(mDesc, instId++, Inst::Kind_MethodEntryPseudoInst); +} +//_________________________________________________________________________________________________ +MethodMarkerPseudoInst* IRManager::newMethodEndPseudoInst(MethodDesc* mDesc) { + return new(memoryManager, 0) MethodMarkerPseudoInst(mDesc, instId++, Inst::Kind_MethodEndPseudoInst); } - //_________________________________________________________________________________________________ void IRManager::registerInternalHelperInfo(const char * internalHelperID, const InternalHelperInfo& info) { - assert(internalHelperID!=NULL && internalHelperID[0]!=0); - internalHelperInfos[newInternalString(internalHelperID)]=info; + assert(internalHelperID!=NULL && internalHelperID[0]!=0); + internalHelperInfos[newInternalString(internalHelperID)]=info; } //_________________________________________________________________________________________________ RetInst * IRManager::newRetInst(Opnd * retOpnd) { - RetInst * retInst=new (memoryManager, 4) RetInst(this, instId++); - assert( NULL != entryPointInst && NULL != entryPointInst->getCallingConventionClient().getCallingConvention() ); - retInst->insertOpnd(0, newImmOpnd(typeManager.getInt16Type(), 0), Inst::OpndRole_Explicit|Inst::OpndRole_Use); - if (retOpnd!=NULL){ - retInst->insertOpnd(1, retOpnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Use); - retInst->getCallingConventionClient().pushInfo(Inst::OpndRole_Use, retOpnd->getType()->tag); - retInst->opndCount = 2; - } else retInst->opndCount = 1; + RetInst * retInst=new (memoryManager, 4) RetInst(this, instId++); + assert( NULL != entryPointInst && NULL != entryPointInst->getCallingConventionClient().getCallingConvention() ); + retInst->insertOpnd(0, newImmOpnd(typeManager.getInt16Type(), 0), Inst::OpndRole_Explicit|Inst::OpndRole_Use); + if (retOpnd!=NULL){ + retInst->insertOpnd(1, retOpnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Use); + retInst->getCallingConventionClient().pushInfo(Inst::OpndRole_Use, retOpnd->getType()->tag); + retInst->opndCount = 2; + } else retInst->opndCount = 1; - retInst->assignOpcodeGroup(this); - return retInst; + retInst->assignOpcodeGroup(this); + return retInst; } //_________________________________________________________________________________________________ void IRManager::applyCallingConventions() { - for (NodeIterator it(*this); it!=NULL; ++it){ - if (((Node*)it)->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock*)(Node*)it; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - if (inst->hasKind(Inst::Kind_EntryPointPseudoInst)){ - EntryPointPseudoInst * eppi=(EntryPointPseudoInst*)inst; - eppi->callingConventionClient.finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_InArg); - eppi->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Def, OpndKind_Memory); - - }else if (inst->hasKind(Inst::Kind_CallInst)){ - CallInst * callInst=(CallInst*)inst; - - callInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Use, CallingConvention::ArgKind_InArg); - callInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Use, OpndKind_Any); - - callInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_RetArg); - callInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Def, OpndKind_Null); - - }else if (inst->hasKind(Inst::Kind_RetInst)){ - RetInst * retInst=(RetInst*)inst; - retInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Use, CallingConvention::ArgKind_RetArg); - retInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Use, OpndKind_Null); - - if (retInst->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()){ - uint32 stackDepth=getEntryPointInst()->getArgStackDepth(); - retInst->getOpnd(0)->assignImmValue(stackDepth); - } - } - } - } - } + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst * inst= (Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + if (inst->hasKind(Inst::Kind_EntryPointPseudoInst)){ + EntryPointPseudoInst * eppi=(EntryPointPseudoInst*)inst; + eppi->callingConventionClient.finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_InArg); + eppi->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Def, OpndKind_Memory); + }else if (inst->hasKind(Inst::Kind_CallInst)){ + CallInst * callInst=(CallInst*)inst; + + callInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Use, CallingConvention::ArgKind_InArg); + callInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Use, OpndKind_Any); + + callInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_RetArg); + callInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Def, OpndKind_Null); + + }else if (inst->hasKind(Inst::Kind_RetInst)){ + RetInst * retInst=(RetInst*)inst; + retInst->callingConventionClient.finalizeInfos(Inst::OpndRole_Use, CallingConvention::ArgKind_RetArg); + retInst->callingConventionClient.layoutAuxilaryOpnds(Inst::OpndRole_Use, OpndKind_Null); + + if (retInst->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()){ + uint32 stackDepth=getEntryPointInst()->getArgStackDepth(); + retInst->getOpnd(0)->assignImmValue(stackDepth); + } + } + } + } + } } //_________________________________________________________________________________________________ CatchPseudoInst * IRManager::newCatchPseudoInst(Opnd * exception) { - CatchPseudoInst * inst=new (memoryManager, 1) CatchPseudoInst(instId++); - inst->insertOpnd(0, exception, Inst::OpndRole_Def); - inst->setConstraint(0, RegName_EAX); - inst->defOpndCount = 1; - inst->opndCount = 1; - inst->assignOpcodeGroup(this); - return inst; + CatchPseudoInst * inst=new (memoryManager, 1) CatchPseudoInst(instId++); + inst->insertOpnd(0, exception, Inst::OpndRole_Def); + inst->setConstraint(0, RegName_EAX); + inst->defOpndCount = 1; + inst->opndCount = 1; + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ @@ -556,14 +636,14 @@ #ifdef _DEBUG } #endif GCInfoPseudoInst* inst = new(memoryManager, basesAndMptrs.size()) GCInfoPseudoInst(this, instId++); - Opnd ** opnds = inst->getOpnds(); - Constraint * constraints = inst->getConstraints(); - for (uint32 i = 0, n = basesAndMptrs.size(); i < n; i++){ - Opnd * opnd = basesAndMptrs[i]; - opnds[i] = opnd; - constraints[i] = Constraint(OpndKind_Any, opnd->getSize()); - } - inst->opndCount = basesAndMptrs.size(); + Opnd ** opnds = inst->getOpnds(); + Constraint * constraints = inst->getConstraints(); + for (uint32 i = 0, n = basesAndMptrs.size(); i < n; i++){ + Opnd * opnd = basesAndMptrs[i]; + opnds[i] = opnd; + constraints[i] = Constraint(OpndKind_Any, opnd->getSize()); + } + inst->opndCount = basesAndMptrs.size(); inst->assignOpcodeGroup(this); return inst; } @@ -571,291 +651,301 @@ #endif //_________________________________________________________________________________________________ Inst * IRManager::newCopyPseudoInst(Mnemonic mn, Opnd * opnd0, Opnd * opnd1) { - assert(mn==Mnemonic_MOV||mn==Mnemonic_PUSH||mn==Mnemonic_POP); - Inst * inst=new (memoryManager, 2) Inst(mn, instId++, Inst::Form_Extended); - inst->kind = Inst::Kind_CopyPseudoInst; - assert(opnd0!=NULL); - assert(opnd1==NULL||opnd0->getSize()<=opnd1->getSize()); - - Opnd ** opnds = inst->getOpnds(); - Constraint * opndConstraints = inst->getConstraints(); - - opnds[0] = opnd0; - opndConstraints[0] = Constraint(OpndKind_Any, opnd0->getSize()); - if (opnd1!=NULL){ - opnds[1] = opnd1; - opndConstraints[1] = Constraint(OpndKind_Any, opnd0->getSize()); - inst->opndCount = 2; - }else - inst->opndCount = 1; - if (mn != Mnemonic_PUSH) - inst->defOpndCount = 1; - inst->assignOpcodeGroup(this); - return inst; + assert(mn==Mnemonic_MOV||mn==Mnemonic_PUSH||mn==Mnemonic_POP); + uint32 allOpndCnt = opnd0->getType()->isInt8() ? 4 : 2; + Inst * inst=new (memoryManager, allOpndCnt) Inst(mn, instId++, Inst::Form_Extended); + inst->kind = Inst::Kind_CopyPseudoInst; + assert(opnd0!=NULL); + assert(opnd1==NULL||opnd0->getSize()<=opnd1->getSize()); + + Opnd ** opnds = inst->getOpnds(); + Constraint * opndConstraints = inst->getConstraints(); + + opnds[0] = opnd0; + opndConstraints[0] = Constraint(OpndKind_Any, opnd0->getSize()); + if (opnd1!=NULL){ + opnds[1] = opnd1; + opndConstraints[1] = Constraint(OpndKind_Any, opnd0->getSize()); + inst->opndCount = 2; + }else + inst->opndCount = 1; + if (mn != Mnemonic_PUSH) + inst->defOpndCount = 1; + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ AliasPseudoInst * IRManager::newAliasPseudoInst(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 offset) { - assert(sourceOpnd->isPlacedIn(OpndKind_Memory)); - assert(!targetOpnd->hasAssignedPhysicalLocation()); - assert(targetOpnd->canBePlacedIn(OpndKind_Memory)); + assert(sourceOpnd->isPlacedIn(OpndKind_Memory)); + assert(!targetOpnd->hasAssignedPhysicalLocation()); + assert(targetOpnd->canBePlacedIn(OpndKind_Memory)); - Type * sourceType=sourceOpnd->getType(); - OpndSize sourceSize=getTypeSize(sourceType); + Type * sourceType=sourceOpnd->getType(); + OpndSize sourceSize=getTypeSize(sourceType); - Type * targetType=targetOpnd->getType(); - OpndSize targetSize=getTypeSize(targetType); + Type * targetType=targetOpnd->getType(); + OpndSize targetSize=getTypeSize(targetType); #ifdef _DEBUG - uint32 sourceByteSize=getByteSize(sourceSize); - uint32 targetByteSize=getByteSize(targetSize); - assert(getByteSize(sourceSize)>0 && getByteSize(targetSize)>0); - assert(offset+targetByteSize<=sourceByteSize); + uint32 sourceByteSize=getByteSize(sourceSize); + uint32 targetByteSize=getByteSize(targetSize); + assert(getByteSize(sourceSize)>0 && getByteSize(targetSize)>0); + assert(offset+targetByteSize<=sourceByteSize); #endif - AliasPseudoInst * inst=new (memoryManager, 2) AliasPseudoInst(instId++); + uint32 allocOpndNum = sourceOpnd->getType()->isInt8() ? 3 : 2; + AliasPseudoInst * inst=new (memoryManager, allocOpndNum) AliasPseudoInst(instId++); - inst->getOpnds()[0] = targetOpnd; - inst->getConstraints()[0] = Constraint(OpndKind_Mem, targetSize); + inst->getOpnds()[0] = targetOpnd; + inst->getConstraints()[0] = Constraint(OpndKind_Mem, targetSize); - inst->getOpnds()[1] = sourceOpnd; - inst->getConstraints()[1] = Constraint(OpndKind_Mem, sourceSize); + inst->getOpnds()[1] = sourceOpnd; + inst->getConstraints()[1] = Constraint(OpndKind_Mem, sourceSize); + if (sourceOpnd->getType()->isInt8()) { + inst->getConstraints()[2] = Constraint(OpndKind_Mem, targetSize); + } - inst->defOpndCount = 1; - inst->opndCount = 2; + inst->defOpndCount = 1; + inst->opndCount = 2; - inst->offset=offset; + inst->offset=offset; - layoutAliasPseudoInstOpnds(inst); + layoutAliasPseudoInstOpnds(inst); - inst->assignOpcodeGroup(this); - return inst; + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ AliasPseudoInst * IRManager::newAliasPseudoInst(Opnd * targetOpnd, uint32 sourceOpndCount, Opnd ** sourceOpnds) { - assert(targetOpnd->isPlacedIn(OpndKind_Memory)); + assert(targetOpnd->isPlacedIn(OpndKind_Memory)); - Type * targetType=targetOpnd->getType(); - OpndSize targetSize=getTypeSize(targetType); - assert(getByteSize(targetSize)>0); + Type * targetType=targetOpnd->getType(); + OpndSize targetSize=getTypeSize(targetType); + assert(getByteSize(targetSize)>0); + uint32 allocOpnNum = 0; + for (uint32 i=0; igetType())); - AliasPseudoInst * inst=new (memoryManager, sourceOpndCount + 1) AliasPseudoInst(instId++); + allocOpnNum += getByteSize(getTypeSize(targetOpnd->getType())); + AliasPseudoInst * inst=new (memoryManager, allocOpnNum) AliasPseudoInst(instId++); - Opnd ** opnds = inst->getOpnds(); - Constraint * opndConstraints = inst->getConstraints(); + Opnd ** opnds = inst->getOpnds(); + Constraint * opndConstraints = inst->getConstraints(); - opnds[0] = targetOpnd; - opndConstraints[0] = Constraint(OpndKind_Mem, targetSize); + opnds[0] = targetOpnd; + opndConstraints[0] = Constraint(OpndKind_Mem, targetSize); - uint32 offset=0; - for (uint32 i=0; ihasAssignedPhysicalLocation()); - assert(sourceOpnds[i]->canBePlacedIn(OpndKind_Memory)); - Type * sourceType=sourceOpnds[i]->getType(); - OpndSize sourceSize=getTypeSize(sourceType); - uint32 sourceByteSize=getByteSize(sourceSize); - assert(sourceByteSize>0); - assert(offset+sourceByteSize<=getByteSize(targetSize)); + uint32 offset=0; + for (uint32 i=0; ihasAssignedPhysicalLocation() || + (sourceOpnds[i]->isPlacedIn(OpndKind_Memory) && + sourceOpnds[i]->getMemOpndKind() == targetOpnd->getMemOpndKind()) + ); + assert(sourceOpnds[i]->canBePlacedIn(OpndKind_Memory)); + Type * sourceType=sourceOpnds[i]->getType(); + OpndSize sourceSize=getTypeSize(sourceType); + uint32 sourceByteSize=getByteSize(sourceSize); + assert(sourceByteSize>0); + assert(offset+sourceByteSize<=getByteSize(targetSize)); - opnds[1 + i] = sourceOpnds[i]; - opndConstraints[1 + i] = Constraint(OpndKind_Mem, sourceSize); + opnds[1 + i] = sourceOpnds[i]; + opndConstraints[1 + i] = Constraint(OpndKind_Mem, sourceSize); - offset+=sourceByteSize; - } - inst->defOpndCount = 1; - inst->opndCount = sourceOpndCount + 1; + offset+=sourceByteSize; + } + inst->defOpndCount = 1; + inst->opndCount = sourceOpndCount + 1; - layoutAliasPseudoInstOpnds(inst); - inst->assignOpcodeGroup(this); - return inst; + layoutAliasPseudoInstOpnds(inst); + inst->assignOpcodeGroup(this); + return inst; } //_________________________________________________________________________________________________ void IRManager::layoutAliasPseudoInstOpnds(AliasPseudoInst * inst) { - assert(inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def) == 1); - Opnd * const * opnds = inst->getOpnds(); - Opnd * defOpnd=opnds[0]; - Opnd * const * useOpnds = opnds + 1; - uint32 useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); - assert(useCount > 0); - if (inst->offset==EmptyUint32){ - uint32 offset=0; - for (uint32 i=0; igetSize()); - } - }else - assignInnerMemOpnd(useOpnds[0], defOpnd, inst->offset); + assert(inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def) == 1); + Opnd * const * opnds = inst->getOpnds(); + Opnd * defOpnd=opnds[0]; + Opnd * const * useOpnds = opnds + 1; + uint32 useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); + assert(useCount > 0); + if (inst->offset==EmptyUint32){ + uint32 offset=0; + for (uint32 i=0; igetSize()); + } + }else + assignInnerMemOpnd(useOpnds[0], defOpnd, inst->offset); } //_________________________________________________________________________________________________ void IRManager::addAliasRelation(AliasRelation * relations, Opnd * outerOpnd, Opnd * innerOpnd, uint32 offset) { - if (outerOpnd==innerOpnd){ - assert(offset==0); - return; - } + if (outerOpnd==innerOpnd){ + assert(offset==0); + return; + } - const AliasRelation& outerRel=relations[outerOpnd->getId()]; - if (outerRel.outerOpnd!=NULL){ - addAliasRelation(relations, outerRel.outerOpnd, innerOpnd, outerRel.offset+offset); - return; - } + const AliasRelation& outerRel=relations[outerOpnd->getId()]; + if (outerRel.outerOpnd!=NULL){ + addAliasRelation(relations, outerRel.outerOpnd, innerOpnd, outerRel.offset+offset); + return; + } - AliasRelation& innerRel=relations[innerOpnd->getId()]; - if (innerRel.outerOpnd!=NULL){ - addAliasRelation(relations, outerOpnd, innerRel.outerOpnd, offset-(int)innerRel.offset); - } + AliasRelation& innerRel=relations[innerOpnd->getId()]; + if (innerRel.outerOpnd!=NULL){ + addAliasRelation(relations, outerOpnd, innerRel.outerOpnd, offset-(int)innerRel.offset); + } #ifdef _DEBUG - Type * outerType=outerOpnd->getType(); - OpndSize outerSize=getTypeSize(outerType); - uint32 outerByteSize=getByteSize(outerSize); - assert(offsetgetType(); - OpndSize innerSize=getTypeSize(innerType); - uint32 innerByteSize=getByteSize(innerSize); - assert(outerByteSize>0 && innerByteSize>0); - assert(offset+innerByteSize<=outerByteSize); + Type * outerType=outerOpnd->getType(); + OpndSize outerSize=getTypeSize(outerType); + uint32 outerByteSize=getByteSize(outerSize); + assert(offsetgetType(); + OpndSize innerSize=getTypeSize(innerType); + uint32 innerByteSize=getByteSize(innerSize); + assert(outerByteSize>0 && innerByteSize>0); + assert(offset+innerByteSize<=outerByteSize); #endif - innerRel.outerOpnd=outerOpnd; - innerRel.offset=offset; + innerRel.outerOpnd=outerOpnd; + innerRel.offset=offset; } //_________________________________________________________________________________________________ void IRManager::getAliasRelations(AliasRelation * relations) { - for(CFG::NodeIterator it(*this); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)) { - BasicBlock * bb = (BasicBlock*)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)) { - if (inst->hasKind(Inst::Kind_AliasPseudoInst)){ - AliasPseudoInst * aliasInst=(AliasPseudoInst *)inst; - Opnd * const * opnds = inst->getOpnds(); - uint32 useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); - assert(inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def) == 1 && useCount > 0); - Opnd * defOpnd=opnds[0]; - Opnd * const * useOpnds = opnds + 1; - if (aliasInst->offset==EmptyUint32){ - uint32 offset=0; - for (uint32 i=0; igetSize()); - } - }else{ - addAliasRelation(relations, useOpnds[0], defOpnd, aliasInst->offset); - } - } - } - } - } + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()) { + if (inst->hasKind(Inst::Kind_AliasPseudoInst)){ + AliasPseudoInst * aliasInst=(AliasPseudoInst *)inst; + Opnd * const * opnds = inst->getOpnds(); + uint32 useCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Use); + assert(inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def) == 1 && useCount > 0); + Opnd * defOpnd=opnds[0]; + Opnd * const * useOpnds = opnds + 1; + if (aliasInst->offset==EmptyUint32){ + uint32 offset=0; + for (uint32 i=0; igetSize()); + } + }else{ + addAliasRelation(relations, useOpnds[0], defOpnd, aliasInst->offset); + } + } + } + } + } } //_________________________________________________________________________________________________ void IRManager::layoutAliasOpnds() { - MemoryManager mm(0x1000, "layoutAliasOpnds"); - uint32 opndCount=getOpndCount(); - AliasRelation * relations=new (memoryManager) AliasRelation[opndCount]; - getAliasRelations(relations); - for (uint32 i=0; iisPlacedIn(OpndKind_Mem)); - assert(relations[i].outerOpnd->isPlacedIn(OpndKind_Mem)); - Opnd * innerDispOpnd=innerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - if (innerDispOpnd==NULL){ - innerDispOpnd=newImmOpnd(typeManager.getInt32Type(), 0); - innerOpnd->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, innerDispOpnd); - } - Opnd * outerDispOpnd=relations[i].outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - uint32 outerDispValue=(uint32)(outerDispOpnd!=NULL?outerDispOpnd->getImmValue():0); - innerDispOpnd->assignImmValue(outerDispValue+relations[i].offset); - } - } + MemoryManager mm(0x1000, "layoutAliasOpnds"); + uint32 opndCount=getOpndCount(); + AliasRelation * relations=new (memoryManager) AliasRelation[opndCount]; + getAliasRelations(relations); + for (uint32 i=0; iisPlacedIn(OpndKind_Mem)); + assert(relations[i].outerOpnd->isPlacedIn(OpndKind_Mem)); + Opnd * innerDispOpnd=innerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + if (innerDispOpnd==NULL){ + innerDispOpnd=newImmOpnd(typeManager.getInt32Type(), 0); + innerOpnd->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, innerDispOpnd); + } + Opnd * outerDispOpnd=relations[i].outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + uint32 outerDispValue=(uint32)(outerDispOpnd!=NULL?outerDispOpnd->getImmValue():0); + innerDispOpnd->assignImmValue(outerDispValue+relations[i].offset); + } + } } //_________________________________________________________________________________________________ uint32 IRManager::assignInnerMemOpnd(Opnd * outerOpnd, Opnd* innerOpnd, uint32 offset) { - assert(outerOpnd->isPlacedIn(OpndKind_Memory)); - - Opnd * outerDisp=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - MemOpndKind outerMemOpndKind=outerOpnd->getMemOpndKind(); - Opnd::RuntimeInfo * outerDispRI=outerDisp!=NULL?outerDisp->getRuntimeInfo():NULL; - uint64 outerDispValue=outerDisp!=NULL?outerDisp->getImmValue():0; - - Opnd * outerBase=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); - Opnd * outerIndex=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); - Opnd * outerScale=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Scale); - - OpndSize innerSize = innerOpnd->getSize(); - uint32 innerByteSize = getByteSize(innerSize); - - Opnd * innerDisp=newImmOpnd(outerDisp!=NULL?outerDisp->getType():typeManager.getInt32Type(), outerDispValue+offset); - if (outerDispRI){ - Opnd::RuntimeInfo * innerDispRI=new(memoryManager) - Opnd::RuntimeInfo( - outerDispRI->getKind(), - outerDispRI->getValue(0), - outerDispRI->getValue(1), - outerDispRI->getValue(2), - outerDispRI->getValue(3), - offset - ); - innerDisp->setRuntimeInfo(innerDispRI); - } - innerOpnd->assignMemLocation(outerMemOpndKind, outerBase, outerIndex, outerScale, innerDisp); - return innerByteSize; + assert(outerOpnd->isPlacedIn(OpndKind_Memory)); + + Opnd * outerDisp=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + MemOpndKind outerMemOpndKind=outerOpnd->getMemOpndKind(); + Opnd::RuntimeInfo * outerDispRI=outerDisp!=NULL?outerDisp->getRuntimeInfo():NULL; + uint64 outerDispValue=outerDisp!=NULL?outerDisp->getImmValue():0; + + Opnd * outerBase=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + Opnd * outerIndex=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); + Opnd * outerScale=outerOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Scale); + + OpndSize innerSize = innerOpnd->getSize(); + uint32 innerByteSize = getByteSize(innerSize); + + Opnd * innerDisp=newImmOpnd(outerDisp!=NULL?outerDisp->getType():typeManager.getInt32Type(), outerDispValue+offset); + if (outerDispRI){ + Opnd::RuntimeInfo * innerDispRI=new(memoryManager) + Opnd::RuntimeInfo( + outerDispRI->getKind(), + outerDispRI->getValue(0), + outerDispRI->getValue(1), + outerDispRI->getValue(2), + outerDispRI->getValue(3), + offset + ); + innerDisp->setRuntimeInfo(innerDispRI); + } + innerOpnd->assignMemLocation(outerMemOpndKind, outerBase, outerIndex, outerScale, innerDisp); + return innerByteSize; } //_________________________________________________________________________________________________ void IRManager::assignInnerMemOpnds(Opnd * outerOpnd, Opnd** innerOpnds, uint32 innerOpndCount) { #ifdef _DEBUG - uint32 outerByteSize = getByteSize(outerOpnd->getSize()); + uint32 outerByteSize = getByteSize(outerOpnd->getSize()); #endif - for (uint32 i=0, offset=0; igetSize(); - if (size==OpndSize_80 || size==OpndSize_128) - return 16; - if (size==OpndSize_64) - return 8; - else - return 4; + OpndSize size=opnd->getSize(); + if (size==OpndSize_80 || size==OpndSize_128) + return 16; + if (size==OpndSize_64) + return 8; + else + return 4; } //_________________________________________________________________________________________________ -Inst * IRManager::newCopySequence(Mnemonic mn, Opnd * opnd0, Opnd * opnd1, uint32 regUsageMask) +Inst * IRManager::newCopySequence(Mnemonic mn, Opnd * opnd0, Opnd * opnd1, uint32 gpRegUsageMask, uint32 flagsRegUsageMask) { - if (mn==Mnemonic_MOV) - return newCopySequence(opnd0, opnd1, regUsageMask); - else if (mn==Mnemonic_PUSH||mn==Mnemonic_POP) - return newPushPopSequence(mn, opnd0, regUsageMask); - assert(0); - return NULL; + if (mn==Mnemonic_MOV) + return newCopySequence(opnd0, opnd1, gpRegUsageMask, flagsRegUsageMask); + else if (mn==Mnemonic_PUSH||mn==Mnemonic_POP) + return newPushPopSequence(mn, opnd0, gpRegUsageMask); + assert(0); + return NULL; } @@ -864,133 +954,186 @@ Inst * IRManager::newCopySequence(Mnemon Inst * IRManager::newMemMovSequence(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 regUsageMask, bool checkSource) { - Inst * instList=NULL; - RegName tmpRegName=RegName_Null, unusedTmpRegName=RegName_Null; - bool registerSetNotLocked = !isRegisterSetLocked(OpndKind_GPReg); - - for (uint32 reg = RegName_EAX; reg<=(uint32)(targetOpnd->getSize()getMemOpndSubOpnd(MemOpndSubOpndKind_Base); - if(subOpnd && subOpnd->isPlacedIn(regName)) - continue; - subOpnd = targetOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); - if(subOpnd && subOpnd->isPlacedIn(regName)) - continue; - - if (checkSource){ - subOpnd = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); - if(subOpnd && subOpnd->isPlacedIn(regName)) - continue; - subOpnd = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); - if(subOpnd && subOpnd->isPlacedIn(regName)) - continue; - } - - tmpRegName=regName; - if (registerSetNotLocked || (getRegMask(tmpRegName)®UsageMask)==0){ - unusedTmpRegName=tmpRegName; - break; - } - } + Inst * instList=NULL; + RegName tmpRegName=RegName_Null, unusedTmpRegName=RegName_Null; + bool registerSetNotLocked = !isRegisterSetLocked(OpndKind_GPReg); + +#ifdef _EM64T_ + for (uint32 reg = RegName_RAX; reg<=RegName_R15/*(uint32)(targetOpnd->getSize()getSize()getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + if(subOpnd && subOpnd->isPlacedIn(regName)) + continue; + subOpnd = targetOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); + if(subOpnd && subOpnd->isPlacedIn(regName)) + continue; + + if (checkSource){ + subOpnd = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + if(subOpnd && subOpnd->isPlacedIn(regName)) + continue; + subOpnd = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Index); + if(subOpnd && subOpnd->isPlacedIn(regName)) + continue; + } + + tmpRegName=regName; + if (registerSetNotLocked || (getRegMask(tmpRegName)®UsageMask)==0){ + unusedTmpRegName=tmpRegName; + break; + } + } assert(tmpRegName!=RegName_Null); - Opnd * tmp=getRegOpnd(tmpRegName); - Opnd * tmpAdjusted=newRegOpnd(targetOpnd->getType(), tmpRegName); - Opnd * tmpRegStackOpnd = newMemOpnd(tmp->getType(), MemOpndKind_StackAutoLayout, getRegOpnd(RegName_ESP), 0); + Opnd * tmp=getRegOpnd(tmpRegName); + Opnd * tmpAdjusted=newRegOpnd(targetOpnd->getType(), tmpRegName); + Opnd * tmpRegStackOpnd = newMemOpnd(tmp->getType(), MemOpndKind_StackAutoLayout, getRegOpnd(STACK_REG), 0); - if (unusedTmpRegName==RegName_Null) - appendToInstList(instList, newInst(Mnemonic_MOV, tmpRegStackOpnd, tmp)); + if (unusedTmpRegName==RegName_Null) + appendToInstList(instList, newInst(Mnemonic_MOV, tmpRegStackOpnd, tmp)); - appendToInstList(instList, newInst(Mnemonic_MOV, tmpAdjusted, sourceOpnd)); // must satisfy constraints - appendToInstList(instList, newInst(Mnemonic_MOV, targetOpnd, tmpAdjusted)); // must satisfy constraints + appendToInstList(instList, newInst(Mnemonic_MOV, tmpAdjusted, sourceOpnd)); // must satisfy constraints + appendToInstList(instList, newInst(Mnemonic_MOV, targetOpnd, tmpAdjusted)); // must satisfy constraints - if (unusedTmpRegName==RegName_Null) - appendToInstList(instList, newInst(Mnemonic_MOV, tmp, tmpRegStackOpnd)); + if (unusedTmpRegName==RegName_Null) + appendToInstList(instList, newInst(Mnemonic_MOV, tmp, tmpRegStackOpnd)); - return instList; + return instList; } //_________________________________________________________________________________________________ -Inst * IRManager::newCopySequence(Opnd * targetBOpnd, Opnd * sourceBOpnd, uint32 regUsageMask) +Inst * IRManager::newCopySequence(Opnd * targetBOpnd, Opnd * sourceBOpnd, uint32 regUsageMask, uint32 flagsRegUsageMask) { - Opnd * targetOpnd=(Opnd*)targetBOpnd, * sourceOpnd=(Opnd*)sourceBOpnd; - - Constraint targetConstraint = targetOpnd->getConstraint(Opnd::ConstraintKind_Location); - Constraint sourceConstraint = sourceOpnd->getConstraint(Opnd::ConstraintKind_Location); - - if (targetConstraint.isNull() || sourceConstraint.isNull()){ - return newCopyPseudoInst(Mnemonic_MOV, targetOpnd, sourceOpnd); - } - - OpndSize targetSize=targetConstraint.getSize(); - OpndSize sourceSize=sourceConstraint.getSize(); - uint32 sourceByteSize=getByteSize(sourceSize); - uint32 targetByteSize=getByteSize(targetSize); - OpndKind targetKind=(OpndKind)targetConstraint.getKind(); - OpndKind sourceKind=(OpndKind)sourceConstraint.getKind(); - - assert(targetSize<=sourceSize); // only same size or truncating conversions are allowed - - if ( (targetKind==OpndKind_GPReg||targetKind==OpndKind_Mem) && - (sourceKind==OpndKind_GPReg||sourceKind==OpndKind_Mem||sourceKind==OpndKind_Imm) - ){ - if (sourceKind==OpndKind_Mem && targetKind==OpndKind_Mem){ - Inst * instList=NULL; - if (sourceByteSize<=4){ - instList=newMemMovSequence(targetOpnd, sourceOpnd, regUsageMask); - }else{ - Opnd * targetOpnds[IRMaxOperandByteSize/4]; // limitation because we are currently don't support large memory operands - uint32 targetOpndCount = 0; - for (uint32 cb=0; cbgetType(), MemOpndKind_StackAutoLayout, getRegOpnd(RegName_ESP), 0); - appendToInstList(instList, newCopySequence(tmp, sourceOpnd, regUsageMask)); - appendToInstList(instList, newCopySequence(targetOpnd, tmp, regUsageMask)); - return instList; - } - assert(0); - return NULL; + Opnd * targetOpnd=(Opnd*)targetBOpnd, * sourceOpnd=(Opnd*)sourceBOpnd; + + Constraint targetConstraint = targetOpnd->getConstraint(Opnd::ConstraintKind_Location); + Constraint sourceConstraint = sourceOpnd->getConstraint(Opnd::ConstraintKind_Location); + + if (targetConstraint.isNull() || sourceConstraint.isNull()){ + return newCopyPseudoInst(Mnemonic_MOV, targetOpnd, sourceOpnd); + } + + OpndSize sourceSize=sourceConstraint.getSize(); + uint32 sourceByteSize=getByteSize(sourceSize); + OpndKind targetKind=(OpndKind)targetConstraint.getKind(); + OpndKind sourceKind=(OpndKind)sourceConstraint.getKind(); + +#if defined(_DEBUG) || !defined(_EM64T_) + OpndSize targetSize=targetConstraint.getSize(); + assert(targetSize<=sourceSize); // only same size or truncating conversions are allowed +#endif + + if (targetKind&OpndKind_Reg) { + if(sourceOpnd->isPlacedIn(OpndKind_Imm) && sourceOpnd->getImmValue()==0 && targetKind==OpndKind_GPReg && + !sourceOpnd->getRuntimeInfo() && !(getRegMask(RegName_EFLAGS)&flagsRegUsageMask)) { + return newInst(Mnemonic_XOR,targetOpnd, targetOpnd); + } + else if (targetKind==OpndKind_XMMReg && sourceOpnd->getMemOpndKind()==MemOpndKind_ConstantArea) { +#ifdef _EM64T_ + Opnd * addr = NULL; + Opnd * base = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Base); + if(base) { + Inst * defInst = base->getDefiningInst(); + if(defInst && defInst->getMnemonic() == Mnemonic_MOV) { + addr = defInst->getOpnd(1); + if(!addr->getRuntimeInfo()) + addr = NULL; + } + } +#else + Opnd * addr = sourceOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); +#endif + void * fpPtr = (void *)((ConstantAreaItem *)addr->getRuntimeInfo()->getValue(0))->getValue(); + if( addr && addr->getRuntimeInfo()->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem) { + if (sourceByteSize==4) { + float val = *(float *)fpPtr; + if(val == 0 && !signbit(val)) { + return newInst(Mnemonic_XORPS,targetOpnd, targetOpnd); + } + }else if (sourceByteSize==8) { + double val = *(double *)fpPtr; + if(val == 0 && !signbit(val)) { + return newInst(Mnemonic_XORPD,targetOpnd, targetOpnd); + } + } + } + } + } + + if ( (targetKind==OpndKind_GPReg||targetKind==OpndKind_Mem) && + (sourceKind==OpndKind_GPReg||sourceKind==OpndKind_Mem||sourceKind==OpndKind_Imm) + ){ + if (sourceKind==OpndKind_Mem && targetKind==OpndKind_Mem){ + Inst * instList=NULL; +#ifndef _EM64T_ + uint32 targetByteSize=getByteSize(targetSize); + if (sourceByteSize<=4){ + instList=newMemMovSequence(targetOpnd, sourceOpnd, regUsageMask); + }else{ + Opnd * targetOpnds[IRMaxOperandByteSize/4]; // limitation because we are currently don't support large memory operands + uint32 targetOpndCount = 0; + for (uint32 cb=0; cbgetMemOpndKind() == MemOpndKind_StackAutoLayout) && (sourceKind==OpndKind_Imm) && (sourceOpnd->getSize() == OpndSize_64)) + return newMemMovSequence(targetOpnd, sourceOpnd, regUsageMask, false); + else +#else + assert(sourceByteSize<=4); +#endif + return newInst(Mnemonic_MOV, targetOpnd, sourceOpnd); // must satisfy constraints + } + }else if ( + (targetKind==OpndKind_XMMReg||targetKind==OpndKind_Mem) && + (sourceKind==OpndKind_XMMReg||sourceKind==OpndKind_Mem) + ){ + if (sourceByteSize==4){ + return newInst(Mnemonic_MOVSS,targetOpnd, sourceOpnd); + }else if (sourceByteSize==8){ + return newInst(Mnemonic_MOVSD,targetOpnd, sourceOpnd); + } + }else if (targetKind==OpndKind_FPReg && sourceKind==OpndKind_Mem){ + return newInst(Mnemonic_FLD, targetOpnd, sourceOpnd); + }else if (targetKind==OpndKind_Mem && sourceKind==OpndKind_FPReg){ + return newInst(Mnemonic_FSTP, targetOpnd, sourceOpnd); + }else if ( + (targetKind==OpndKind_FPReg && sourceKind==OpndKind_XMMReg)|| + (targetKind==OpndKind_XMMReg && sourceKind==OpndKind_FPReg) + ){ + Inst * instList=NULL; + Opnd * tmp = newMemOpnd(targetOpnd->getType(), MemOpndKind_StackAutoLayout, getRegOpnd(STACK_REG), 0); + appendToInstList(instList, newCopySequence(tmp, sourceOpnd, regUsageMask)); + appendToInstList(instList, newCopySequence(targetOpnd, tmp, regUsageMask)); + return instList; + } + assert(0); + return NULL; } @@ -999,177 +1142,228 @@ Inst * IRManager::newCopySequence(Opnd * Inst * IRManager::newPushPopSequence(Mnemonic mn, Opnd * opnd, uint32 regUsageMask) { - assert(opnd!=NULL); - - Constraint constraint = opnd->getConstraint(Opnd::ConstraintKind_Location); - if (constraint.isNull()) - return newCopyPseudoInst(mn, opnd); - - OpndKind kind=(OpndKind)constraint.getKind(); - OpndSize size=constraint.getSize(); - - Inst * instList=NULL; - - if ( kind==OpndKind_GPReg||kind==OpndKind_Mem||kind==OpndKind_Imm ){ - if (size==OpndSize_32){ - return newInst(mn, opnd); - }else if (sizegetType(), MemOpndKind_StackManualLayout, espOpnd, 0); - uint32 cb=getByteSize(size); - uint32 slotSize=4; - cb=(cb+slotSize-1)&~(slotSize-1); - Opnd * sizeOpnd=newImmOpnd(typeManager.getInt32Type(), cb); - if (mn==Mnemonic_PUSH){ - appendToInstList(instList, newInst(Mnemonic_SUB, espOpnd, sizeOpnd)); - appendToInstList(instList, newCopySequence(tmp, opnd, regUsageMask)); - }else{ - appendToInstList(instList, newCopySequence(opnd, tmp, regUsageMask)); - appendToInstList(instList, newInst(Mnemonic_ADD, espOpnd, sizeOpnd)); - } - - return instList; + assert(opnd!=NULL); + + Constraint constraint = opnd->getConstraint(Opnd::ConstraintKind_Location); + if (constraint.isNull()) + return newCopyPseudoInst(mn, opnd); + + OpndKind kind=(OpndKind)constraint.getKind(); + OpndSize size=constraint.getSize(); + + Inst * instList=NULL; + +#ifdef _EM64T_ + if ( ((kind==OpndKind_GPReg ||kind==OpndKind_Mem)&& size!=OpndSize_32)||(kind==OpndKind_Imm && sizegetType(), MemOpndKind_StackManualLayout, espOpnd, 0); +#ifdef _EM64T_ + Opnd * sizeOpnd=newImmOpnd(typeManager.getInt32Type(), sizeof(POINTER_SIZE_INT)); + if(kind==OpndKind_Imm) { + assert(mn==Mnemonic_PUSH); + appendToInstList(instList, newInst(Mnemonic_SUB, espOpnd, sizeOpnd)); + appendToInstList(instList, newMemMovSequence(tmp, opnd, regUsageMask)); + } else if (kind == OpndKind_GPReg){ + assert(mn==Mnemonic_PUSH); + appendToInstList(instList, newInst(Mnemonic_SUB, espOpnd, sizeOpnd)); + appendToInstList(instList, newInst(Mnemonic_MOV, tmp, opnd)); + } else { + if (mn==Mnemonic_PUSH){ + appendToInstList(instList, newInst(Mnemonic_SUB, espOpnd, sizeOpnd)); + appendToInstList(instList, newCopySequence(tmp, opnd, regUsageMask)); + }else{ + appendToInstList(instList, newCopySequence(opnd, tmp, regUsageMask)); + appendToInstList(instList, newInst(Mnemonic_ADD, espOpnd, sizeOpnd)); + } + } +#else + uint32 cb=getByteSize(size); + uint32 slotSize=4; + cb=(cb+slotSize-1)&~(slotSize-1); + Opnd * sizeOpnd=newImmOpnd(typeManager.getInt32Type(), cb); + if (mn==Mnemonic_PUSH){ + appendToInstList(instList, newInst(Mnemonic_SUB, espOpnd, sizeOpnd)); + appendToInstList(instList, newCopySequence(tmp, opnd, regUsageMask)); + }else{ + appendToInstList(instList, newCopySequence(opnd, tmp, regUsageMask)); + appendToInstList(instList, newInst(Mnemonic_ADD, espOpnd, sizeOpnd)); + } +#endif + return instList; } //_________________________________________________________________________________________________ const CallingConvention * IRManager::getCallingConvention(CompilationInterface::RuntimeHelperId helperId)const { - CompilationInterface::VmCallingConvention callConv=compilationInterface.getRuntimeHelperCallingConvention(helperId); - switch (callConv){ - case CompilationInterface::CallingConvention_Drl: - return &CallingConvention_DRL; - case CompilationInterface::CallingConvention_Stdcall: - return &CallingConvention_STDCALL; - case CompilationInterface::CallingConvention_Cdecl: - return &CallingConvention_CDECL; - default: - assert(0); - return NULL; - } + CompilationInterface::VmCallingConvention callConv=compilationInterface.getRuntimeHelperCallingConvention(helperId); + switch (callConv){ + case CompilationInterface::CallingConvention_Drl: + return &CallingConvention_DRL; + case CompilationInterface::CallingConvention_Stdcall: + return &CallingConvention_STDCALL; + case CompilationInterface::CallingConvention_Cdecl: + return &CallingConvention_CDECL; + default: + assert(0); + return NULL; + } } //_________________________________________________________________________________________________ const CallingConvention * IRManager::getCallingConvention(MethodDesc * methodDesc)const { - return &CallingConvention_DRL; + return &CallingConvention_DRL; } //_________________________________________________________________________________________________ Opnd * IRManager::defArg(Type * type, uint32 position) { - assert(NULL != entryPointInst); - Opnd * opnd=newOpnd(type); - entryPointInst->insertOpnd(position, opnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Def); - entryPointInst->callingConventionClient.pushInfo(Inst::OpndRole_Def, type->tag); - return opnd; + assert(NULL != entryPointInst); + Opnd * opnd=newOpnd(type); + entryPointInst->insertOpnd(position, opnd, Inst::OpndRole_Auxilary|Inst::OpndRole_Def); + entryPointInst->callingConventionClient.pushInfo(Inst::OpndRole_Def, type->tag); + return opnd; } //_________________________________________________________________________________________________ Opnd * IRManager::getRegOpnd(RegName regName) { - assert(getRegSize(regName)==Constraint::getDefaultSize(getRegKind(regName))); // are we going to change this? - uint32 idx=( (getRegKind(regName) & 0x1f) << 4 ) | ( getRegIndex(regName)&0xf ); - if (!regOpnds[idx]){ - regOpnds[idx]=newRegOpnd(typeManager.getUInt32Type(), regName); - } - return regOpnds[idx]; + assert(getRegSize(regName)==Constraint::getDefaultSize(getRegKind(regName))); // are we going to change this? + uint32 idx=( (getRegKind(regName) & 0x1f) << 4 ) | ( getRegIndex(regName)&0xf ); + if (!regOpnds[idx]){ +#ifdef _EM64T_ + Type * t = (getRegSize(regName) == OpndSize_64 ? typeManager.getUInt64Type() : typeManager.getUInt32Type()); + regOpnds[idx]=newRegOpnd(t, regName); +#else + regOpnds[idx]=newRegOpnd(typeManager.getUInt32Type(), regName); +#endif + } + return regOpnds[idx]; } void IRManager::calculateTotalRegUsage(OpndKind regKind) { - assert(regKind == OpndKind_GPReg); - uint32 opndCount=getOpndCount(); - for (uint32 i=0; iisPlacedIn(regKind)) - gpTotalRegUsage |= getRegMask(opnd->getRegName()); - } + assert(regKind == OpndKind_GPReg); + uint32 opndCount=getOpndCount(); + for (uint32 i=0; iisPlacedIn(regKind)) + gpTotalRegUsage |= getRegMask(opnd->getRegName()); + } +#ifdef _EM64T_ + //FIXME!! + gpTotalRegUsage |= getRegMask(RegName_R15); + gpTotalRegUsage |= getRegMask(RegName_R13); + gpTotalRegUsage |= getRegMask(RegName_R14); +#endif } //_________________________________________________________________________________________________ uint32 IRManager::getTotalRegUsage(OpndKind regKind)const { - return gpTotalRegUsage; + return gpTotalRegUsage; } //_________________________________________________________________________________________________ bool IRManager::isPreallocatedRegOpnd(Opnd * opnd) { - RegName regName=opnd->getRegName(); - if (regName==RegName_Null || getRegSize(regName)!=Constraint::getDefaultSize(getRegKind(regName))) - return false; - uint32 idx=( (getRegKind(regName) & 0x1f) << 4 ) | ( getRegIndex(regName)&0xf ); - return regOpnds[idx]==opnd; + RegName regName=opnd->getRegName(); + if (regName==RegName_Null || getRegSize(regName)!=Constraint::getDefaultSize(getRegKind(regName))) + return false; + uint32 idx=( (getRegKind(regName) & 0x1f) << 4 ) | ( getRegIndex(regName)&0xf ); + return regOpnds[idx]==opnd; } //_______________________________________________________________________________________________________________ Type * IRManager::getManagedPtrType(Type * sourceType) { - return typeManager.getManagedPtrType(sourceType); + return typeManager.getManagedPtrType(sourceType); } //_________________________________________________________________________________________________ Type * IRManager::getTypeFromTag(Type::Tag tag)const { switch (tag) { - case Type::Void: - case Type::Tau: - case Type::Int8: - case Type::Int16: - case Type::Int32: - case Type::IntPtr: - case Type::Int64: - case Type::UInt8: - case Type::UInt16: - case Type::UInt32: - case Type::UInt64: - case Type::Single: - case Type::Double: - case Type::Boolean: - case Type::Float: return typeManager.getPrimitiveType(tag); - default: return new(memoryManager) Type(tag); - } + case Type::Void: + case Type::Tau: + case Type::Int8: + case Type::Int16: + case Type::Int32: + case Type::IntPtr: + case Type::Int64: + case Type::UInt8: + case Type::UInt16: + case Type::UInt32: + case Type::UInt64: + case Type::Single: + case Type::Double: + case Type::Boolean: + case Type::Float: return typeManager.getPrimitiveType(tag); + default: return new(memoryManager) Type(tag); + } } //_____________________________________________________________________________________________ OpndSize IRManager::getTypeSize(Type::Tag tag) { - OpndSize size; + OpndSize size; switch (tag) { case Type::Int8: case Type::UInt8: case Type::Boolean: - size = OpndSize_8; + size = OpndSize_8; break; case Type::Int16: case Type::UInt16: case Type::Char: - size = OpndSize_16; + size = OpndSize_16; + break; + case Type::Int32: + case Type::UInt32: + size = OpndSize_32; break; +#ifdef _EM64T_ + case Type::IntPtr: + case Type::UIntPtr: +#endif case Type::Int64: case Type::UInt64: - size = OpndSize_64; + size = OpndSize_64; + break; + case Type::Single: + size = OpndSize_32; break; case Type::Double: - size = OpndSize_64; - break; + size = OpndSize_64; + break; case Type::Float: - size = OpndSize_80; - break; + size = OpndSize_80; + break; default: - size = OpndSize_32; +#ifdef _EM64T_ + size = (tag>=Type::CompressedSystemObject && tag<=Type::CompressedVTablePtr)?OpndSize_32:OpndSize_64; +#else + size = OpndSize_32; +#endif break; } return size; @@ -1177,138 +1371,145 @@ OpndSize IRManager::getTypeSize(Type::Ta } //_____________________________________________________________________________________________ -void IRManager::indexInsts(OrderType order) -{ - Direction dir=order==CFG::OrderType_Postorder?Direction_Backward:Direction_Forward; - - uint32 idx=0; - for (NodeIterator it(*this, order); it!=NULL; ++it){ - Node * node=it.getNode(); - if (node->hasKind(Node::Kind_BasicBlock)){ - const Insts& insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getFirst(dir); inst!=NULL; inst=insts.getNext(dir, inst)) - inst->index=idx++; - } - } +void IRManager::indexInsts() { + const Nodes& postOrder = fg->getNodesPostOrder(); + uint32 idx=0; + for (Nodes::const_reverse_iterator it = postOrder.rbegin(), end = postOrder.rend(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst* inst = (Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()) { + inst->index=idx++; + } + } + } } //_____________________________________________________________________________________________ uint32 IRManager::calculateOpndStatistics(bool reindex) { - POpnd * arr=&opnds.front(); - for (uint32 i=0, n=opnds.size(); idefScope=Opnd::DefScope_Temporary; - opnd->definingInst=NULL; - opnd->refCount=0; - if (reindex) - opnd->id=EmptyUint32; - } - - uint32 index=0; - uint32 instIdx=0; - for (NodeIterator it(*this, CFG::OrderType_Topological); it!=NULL; ++it){ - Node * node=it; - if (!node->hasKind(Node::Kind_BasicBlock)) continue; - int32 execCount=(int32)node->getExecCnt()*100; - if (execCount<=1) - execCount=1; - const Insts& insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - inst->index=instIdx++; - for (uint32 i=0, n=inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_UseDef); igetOpnd(i); - opnd->addRefCount(index, execCount); - if ((inst->getOpndRoles(i)&Inst::OpndRole_Def)!=0){ - opnd->setDefiningInst(inst); - } - } - } - } - - for (uint32 i=0; iaddRefCount(index, 1); - } - return index; + POpnd * arr=&opnds.front(); + for (uint32 i=0, n=opnds.size(); idefScope=Opnd::DefScope_Temporary; + opnd->definingInst=NULL; + opnd->refCount=0; + if (reindex) { + opnd->id=EmptyUint32; + } + } + + uint32 index=0; + uint32 instIdx=0; + const Nodes& nodes = fg->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + if (!node->isBlockNode()) { + continue; + } + int32 execCount=1;//(int32)node->getExecCount()*100; + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + inst->index=instIdx++; + for (uint32 i=0, n=inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_UseDef); igetOpnd(i); + opnd->addRefCount(index, execCount); + if ((inst->getOpndRoles(i)&Inst::OpndRole_Def)!=0){ + opnd->setDefiningInst(inst); + } + } + } + } + + for (uint32 i=0; iaddRefCount(index, 1); + } + } + return index; } //_____________________________________________________________________________________________ void IRManager::packOpnds() { - static CountTime packOpndsTimer("timer:ia32::packOpnds"); - AutoTimer tm(packOpndsTimer); + static CountTime packOpndsTimer("ia32::packOpnds"); + AutoTimer tm(packOpndsTimer); _hasLivenessInfo=false; - uint32 maxIndex=calculateOpndStatistics(true); + uint32 maxIndex=calculateOpndStatistics(true); - uint32 opndsBefore=opnds.size(); - opnds.resize(opnds.size()+maxIndex); - POpnd * arr=&opnds.front(); - for (uint32 i=0; iid!=EmptyUint32) - arr[opndsBefore+opnd->id]=opnd; - } - opnds.erase(opnds.begin(), opnds.begin()+opndsBefore); + uint32 opndsBefore=opnds.size(); + opnds.resize(opnds.size()+maxIndex); + POpnd * arr=&opnds.front(); + for (uint32 i=0; iid!=EmptyUint32) + arr[opndsBefore+opnd->id]=opnd; + } + opnds.erase(opnds.begin(), opnds.begin()+opndsBefore); - _hasLivenessInfo=false; + _hasLivenessInfo=false; } //_____________________________________________________________________________________________ void IRManager::fixLivenessInfo( uint32 * map ) { - uint32 opndCount = getOpndCount(); - for (NodeIterator it(*this); it!=NULL; ++it){ - Node * node=it; - LiveSet * ls = node->getLiveAtEntry(); - ls->resize(opndCount); - } + uint32 opndCount = getOpndCount(); + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + CGNode* node = (CGNode*)*it; + BitSet * ls = node->getLiveAtEntry(); + ls->resize(opndCount); + } } //_____________________________________________________________________________________________ void IRManager::calculateLivenessInfo() { - static CountTime livenessTimer("timer:ia32::liveness"); - AutoTimer tm(livenessTimer); + static CountTime livenessTimer("ia32::liveness"); + AutoTimer tm(livenessTimer); _hasLivenessInfo=false; - updateLoopInfo(); - const uint32 opndCount = getOpndCount(); + LoopTree* lt = fg->getLoopTree(); + lt->rebuild(false); + const uint32 opndCount = getOpndCount(); - const Nodes& nodes = getNodesPostorder(); + const Nodes& nodes = fg->getNodesPostOrder(); //clean all prev. liveness info for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { - Node* node = *it; + CGNode* node = (CGNode*)*it; node->getLiveAtEntry()->resizeClear(opndCount); } - uint32 loopDepth = getMaxLoopDepth(); + uint32 loopDepth = lt->getMaxLoopDepth(); uint32 nIterations = loopDepth + 1; #ifdef _DEBUG nIterations++; //one more extra iteration to prove that nothing changed #endif - LiveSet tmpLs(memoryManager, opndCount); + BitSet tmpLs(memoryManager, opndCount); bool changed = true; + Node* exitNode = fg->getExitNode(); for (uint32 iteration=0; iteration < nIterations; iteration++) { changed = false; for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { - Node* node = *it; - if (node==exitNode) { - if (!methodDesc.isStatic() + CGNode* node = (CGNode*)*it; + if (node == exitNode) { +#ifndef _EM64T_ + if (!methodDesc.isStatic() && (methodDesc.isSynchronized() || methodDesc.isMethodClassIsLikelyExceptionType())) { - LiveSet * exitLs = node->getLiveAtEntry(); - EntryPointPseudoInst * entryPointInst = getEntryPointInst(); - Opnd * thisOpnd = entryPointInst->getOpnd(0); - exitLs->setBit(thisOpnd->getId(), true); - } - continue; + BitSet * exitLs = node->getLiveAtEntry(); + EntryPointPseudoInst * entryPointInst = getEntryPointInst(); + Opnd * thisOpnd = entryPointInst->getOpnd(0); + exitLs->setBit(thisOpnd->getId(), true); + } +#endif + continue; } bool processNode = true; if (iteration > 0) { - uint32 depth = node->getLoopDepth(); + uint32 depth = lt->getLoopDepth(node); processNode = iteration <= depth; #ifdef _DEBUG processNode = processNode || iteration == nIterations-1; //last iteration will check all blocks @@ -1316,13 +1517,12 @@ #endif } if (processNode) { getLiveAtExit(node, tmpLs); - if (node->hasKind(Node::Kind_BasicBlock)){ - const Insts& insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getLast(); inst!=NULL; inst=insts.getPrev(inst)){ + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()){ updateLiveness(inst, tmpLs); } } - LiveSet * ls = node->getLiveAtEntry(); + BitSet * ls = node->getLiveAtEntry(); if (iteration == 0 || !ls->isEqual(tmpLs)) { changed = true; ls->copyFrom(tmpLs); @@ -1341,394 +1541,399 @@ #endif //_____________________________________________________________________________________________ bool IRManager::ensureLivenessInfoIsValid() { - return true; + return true; } //_____________________________________________________________________________________________ -void IRManager::getLiveAtExit(const Node * node, LiveSet & ls) const -{ - assert(ls.getSetSize()<=getOpndCount()); - const Edges& edges=node->getEdges(Direction_Out); - uint32 i=0; - for (Edge * edge=edges.getFirst(); edge!=NULL; edge=edges.getNext(edge), i++){ - Node * succ=edge->getNode(Direction_Head); - const LiveSet * succLs=succ->getLiveAtEntry(); - if (i==0) { - ls.copyFrom(*succLs); +void IRManager::getLiveAtExit(const Node * node, BitSet & ls) const +{ + assert(ls.getSetSize()<=getOpndCount()); + const Edges& edges=node->getOutEdges(); + uint32 i=0; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite, ++i) { + Edge* edge = *ite; + CGNode * succ=(CGNode*)edge->getTargetNode(); + const BitSet * succLs=succ->getLiveAtEntry(); + if (i==0) { + ls.copyFrom(*succLs); } else { - ls.unionWith(*succLs); + ls.unionWith(*succLs); } - } + } } //_____________________________________________________________________________________________ -void IRManager::updateLiveness(const Inst * inst, LiveSet & ls) const -{ - const Opnd * const * opnds = inst->getOpnds(); - const uint32 * roles = inst->getOpndRoles(); - uint32 opndCount = inst->getOpndCount(); - uint32 properties = inst->getProperties(); - - for (uint32 i = 0; i < opndCount; i++){ - uint32 r = roles [i]; - const Opnd * opnd = opnds[i]; - uint32 id = opnd->getId(); - if ( (r & Inst::OpndRole_UseDef) == Inst::OpndRole_Def && (properties & Inst::Properties_Conditional) == 0 ) - ls.setBit(id, false); - else if ( opnd->isSubjectForLivenessAnalysis() ) - ls.setBit(id, true); - } - for (uint32 i = 0; i < opndCount; i++){ - const Opnd * opnd = opnds[i]; - if (opnd->getMemOpndKind() != MemOpndKind_Null){ - const Opnd * const * subOpnds = opnd->getMemOpndSubOpnds(); - for (uint32 j = 0; j < MemOpndSubOpndKind_Count; j++){ - const Opnd * subOpnd = subOpnds[j]; - if (subOpnd != NULL && subOpnd->isSubjectForLivenessAnalysis()) - ls.setBit(subOpnd->getId(), true); - } - } - } +void IRManager::updateLiveness(const Inst * inst, BitSet & ls) const +{ + const Opnd * const * opnds = inst->getOpnds(); + uint32 opndCount = inst->getOpndCount(); + + for (uint32 i = 0; i < opndCount; i++){ + const Opnd * opnd = opnds[i]; + uint32 id = opnd->getId(); + if (inst->isLiveRangeEnd(i)) + ls.setBit(id, false); + else if (inst->isLiveRangeStart(i)) + ls.setBit(id, true); + } + for (uint32 i = 0; i < opndCount; i++){ + const Opnd * opnd = opnds[i]; + if (opnd->getMemOpndKind() != MemOpndKind_Null){ + const Opnd * const * subOpnds = opnd->getMemOpndSubOpnds(); + for (uint32 j = 0; j < MemOpndSubOpndKind_Count; j++){ + const Opnd * subOpnd = subOpnds[j]; + if (subOpnd != NULL && subOpnd->isSubjectForLivenessAnalysis()) + ls.setBit(subOpnd->getId(), true); + } + } + } } //_____________________________________________________________________________________________ -uint32 IRManager::getRegUsageFromLiveSet(LiveSet * ls, OpndKind regKind)const -{ - assert(ls->getSetSize()<=getOpndCount()); - uint32 mask=0; - LiveSet::IterB ib(*ls); - for (int i = ib.getNext(); i != -1; i = ib.getNext()){ - Opnd * opnd=getOpnd(i); - if (opnd->isPlacedIn(regKind)) - mask |= getRegMask(opnd->getRegName()); - } - return mask; +uint32 IRManager::getRegUsageFromLiveSet(BitSet * ls, OpndKind regKind)const +{ + assert(ls->getSetSize()<=getOpndCount()); + uint32 mask=0; + BitSet::IterB ib(*ls); + for (int i = ib.getNext(); i != -1; i = ib.getNext()){ + Opnd * opnd=getOpnd(i); + if (opnd->isPlacedIn(regKind)) + mask |= getRegMask(opnd->getRegName()); + } + return mask; } //_____________________________________________________________________________________________ void IRManager::getRegUsageAtExit(const Node * node, OpndKind regKind, uint32 & mask)const { - const Edges& edges=node->getEdges(Direction_Out); - mask=0; - for (Edge * edge=edges.getFirst(); edge!=NULL; edge=edges.getNext(edge)) - mask |= getRegUsageAtEntry(edge->getNode(Direction_Head), regKind); + assert(node->isBlockNode()); + const Edges& edges=node->getOutEdges(); + mask=0; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + mask |= getRegUsageAtEntry(edge->getTargetNode(), regKind); + } } //_____________________________________________________________________________________________ void IRManager::updateRegUsage(const Inst * inst, OpndKind regKind, uint32 & mask)const { - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * opnd=inst->getOpnd(it); - if (opnd->isPlacedIn(regKind)){ - uint32 m=getRegMask(opnd->getRegName()); - if (inst->isLiveRangeEnd(it)) - mask &= ~m; - else if (inst->isLiveRangeStart(it)) - mask |= m; - } - } + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + Opnd * opnd=inst->getOpnd(it); + if (opnd->isPlacedIn(regKind)){ + uint32 m=getRegMask(opnd->getRegName()); + if (inst->isLiveRangeEnd(it)) + mask &= ~m; + else if (inst->isLiveRangeStart(it)) + mask |= m; + } + } } //_____________________________________________________________________________________________ void IRManager::resetOpndConstraints() { - for (uint32 i=0, n=getOpndCount(); isetCalculatedConstraint(opnd->getConstraint(Opnd::ConstraintKind_Initial)); - } -} - -//_____________________________________________________________________________________________ -void IRManager::addToOpndCalculatedConstraints(Constraint c) -{ - for (uint32 i=0, n=getOpndCount(); isetCalculatedConstraint(opnd->getConstraint(Opnd::ConstraintKind_Calculated)|c); - } + for (uint32 i=0, n=getOpndCount(); isetCalculatedConstraint(opnd->getConstraint(Opnd::ConstraintKind_Initial)); + } } void IRManager::finalizeCallSites() { - for(CFG::NodeIterator it(*this); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)) { - BasicBlock * bb = (BasicBlock*)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getLast(), * prevInst=NULL; inst!=NULL; inst=prevInst) { - prevInst=insts.getPrev(inst); - if (inst->getMnemonic() == Mnemonic_CALL) { - const CallInst * callInst=(const CallInst*)inst; - const StlVector& stackOpndInfos = - callInst->getCallingConventionClient().getStackOpndInfos(Inst::OpndRole_Use); - Inst * instToPrepend=inst; - Opnd * const * opnds = callInst->getOpnds(); - for (uint32 i=0, n=stackOpndInfos.size(); iprependInsts(pushInst, instToPrepend); - instToPrepend=pushInst; - } - if(!((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { - bb->appendInsts(newInst(Mnemonic_ADD, getRegOpnd(RegName_ESP), newImmOpnd(typeManager.getInt32Type(), ((CallInst *)inst)->getArgStackDepth())), inst); - } - } - } - } - } -} +#ifdef _EM64T_ + if (!getMethodDesc().isStatic()) { + entryPointInst->thisOpnd = newMemOpnd(getTypeFromTag(Type::UnmanagedPtr), MemOpndKind_StackAutoLayout, getRegOpnd(STACK_REG), 0); + entryPointInst->getBasicBlock()->appendInst(newCopyPseudoInst(Mnemonic_MOV, entryPointInst->thisOpnd, entryPointInst->getOpnd(0))); + } +#endif -//_____________________________________________________________________________________________ -void IRManager::removeRedundantStackOperations() -{ - for(CFG::NodeIterator it(*this); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)) { - BasicBlock * bb = (BasicBlock*)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; ){ - Inst * nextInst = insts.getNext(inst); - if(nextInst && ((inst->getMnemonic() == Mnemonic_PUSH && nextInst->getMnemonic() == Mnemonic_POP && inst->getOpnd(0) == nextInst->getOpnd(0))|| - (inst->getMnemonic() == Mnemonic_POP && nextInst->getMnemonic() == Mnemonic_PUSH && inst->getOpnd(0) == nextInst->getOpnd(0)))) { - Inst * tmpInst = insts.getPrev(inst); - bb->removeInst(inst); - bb->removeInst(nextInst); - nextInst = tmpInst; - } - inst = nextInst; - } - } - } + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + for (Inst * inst=(Inst*)node->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst) { + prevInst=inst->getPrevInst(); + if (inst->getMnemonic() == Mnemonic_CALL) { + const CallInst * callInst=(const CallInst*)inst; + const StlVector& stackOpndInfos = + callInst->getCallingConventionClient().getStackOpndInfos(Inst::OpndRole_Use); + Inst * instToPrepend=inst; + Opnd * const * opnds = callInst->getOpnds(); +#ifdef _EM64T_ + unsigned sz = 0; + for (uint32 i=0, n=stackOpndInfos.size(); iprependInst(newInst(Mnemonic_SUB, getRegOpnd(STACK_REG), newImmOpnd(typeManager.getInt32Type(), corr)), inst); + node->appendInst(newInst(Mnemonic_ADD, getRegOpnd(STACK_REG), newImmOpnd(typeManager.getInt32Type(), corr)), inst); + } + sz = 0; +#endif + for (uint32 i=0, n=stackOpndInfos.size(); igetCallingConventionClient().getCallingConvention()->pushLastToFirst()?i:n-1-i; + Inst * pushInst=newCopyPseudoInst(Mnemonic_PUSH, opnds[stackOpndInfos[index].opndIndex]); + sz+=sizeof(POINTER_SIZE_INT);//getByteSize(opnds[stackOpndInfos[index].opndIndex]->getSize()); +#else + Inst * pushInst=newCopyPseudoInst(Mnemonic_PUSH, opnds[stackOpndInfos[i].opndIndex]); +#endif + pushInst->insertBefore(instToPrepend); + instToPrepend=pushInst; + } +#ifdef _EM64T_ + if(sz && !((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { + Inst* newIns = newInst(Mnemonic_ADD, getRegOpnd(STACK_REG), newImmOpnd(typeManager.getInt32Type(), sz)); + newIns->insertAfter(inst); + } +#else + if(!((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { + Inst* newIns = newInst(Mnemonic_ADD, getRegOpnd(RegName_ESP), newImmOpnd(typeManager.getInt32Type(), ((CallInst *)inst)->getArgStackDepth())); + newIns->insertAfter(inst); + } +#endif + } + } + } + } } //_____________________________________________________________________________________________ void IRManager::calculateStackDepth() { - MemoryManager mm(0x100, "calculateStackDepth"); - StlVector stackDepths(mm, getMaxNodeId()); - for (uint32 i=0; ihasKind(Node::Kind_BasicBlock)||node->hasKind(Node::Kind_DispatchNode)) { - - int32 stackDepth=-1; - const Edges& edges=node->getEdges(Direction_In); - for (Edge * edge=edges.getFirst(); edge!=NULL; edge=edges.getNext(edge)){ - Node * pred=edge->getNode(Direction_Tail); - int32 predStackDepth=stackDepths[pred->getId()]; - if (predStackDepth>=0){ - assert(stackDepth==-1 || stackDepth==predStackDepth); - stackDepth=predStackDepth; - } - } - - if (stackDepth<0) - stackDepth=0; - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb = (BasicBlock*)node; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - inst->setStackDepth(stackDepth); - - Inst::Opnds opnds(inst, Inst::OpndRole_Explicit | Inst::OpndRole_Auxilary | Inst::OpndRole_UseDef); - Inst::Opnds::iterator it = opnds.begin(); - if (it != opnds.end() && inst->getOpnd(it)->isPlacedIn(RegName_ESP)) { - if (inst->getMnemonic()==Mnemonic_ADD) - stackDepth -= (uint32)inst->getOpnd(opnds.next(it))->getImmValue(); - else if (inst->getMnemonic()==Mnemonic_SUB) - stackDepth += (uint32)inst->getOpnd(opnds.next(it))->getImmValue(); - else - assert(0); - }else{ - if(inst->getMnemonic()==Mnemonic_PUSH) { - stackDepth+=getByteSize(inst->getOpnd(it)->getSize()); - } else if (inst->getMnemonic() == Mnemonic_POP) { - stackDepth-=getByteSize(inst->getOpnd(it)->getSize()); - } else if (inst->getMnemonic() == Mnemonic_CALL && ((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { - stackDepth -= ((CallInst *)inst)->getArgStackDepth(); - } - } - } - assert(stackDepth>=0); - } - stackDepths[node->getId()]=stackDepth; - } - } + MemoryManager mm(0x100, "calculateStackDepth"); + StlVector stackDepths(mm, fg->getNodeCount(), -1); + + + const Nodes& nodes = fg->getNodesPostOrder(); + //iterating in topological (reverse postorder) order + for (Nodes::const_reverse_iterator itn = nodes.rbegin(), endn = nodes.rend(); itn!=endn; ++itn) { + Node* node = *itn; + if (node->isBlockNode() || (node->isDispatchNode() && node!=fg->getUnwindNode())) { + int32 stackDepth=-1; + const Edges& edges=node->getInEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node * pred=edge->getSourceNode(); + int32 predStackDepth=stackDepths[pred->getDfNum()]; + if (predStackDepth>=0){ + assert(stackDepth==-1 || stackDepth==predStackDepth); + stackDepth=predStackDepth; + } + } + + if (stackDepth<0) { + stackDepth=0; + } + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + inst->setStackDepth(stackDepth); + + Inst::Opnds opnds(inst, Inst::OpndRole_Explicit | Inst::OpndRole_Auxilary | Inst::OpndRole_UseDef); + Inst::Opnds::iterator it = opnds.begin(); + if (it != opnds.end() && inst->getOpnd(it)->isPlacedIn(STACK_REG)) { + if (inst->getMnemonic()==Mnemonic_ADD) + stackDepth -= (int32)inst->getOpnd(opnds.next(it))->getImmValue(); + else if (inst->getMnemonic()==Mnemonic_SUB) + stackDepth += (int32)inst->getOpnd(opnds.next(it))->getImmValue(); + else + assert(0); + }else{ + if(inst->getMnemonic()==Mnemonic_PUSH) { + stackDepth+=getByteSize(inst->getOpnd(it)->getSize()); + } else if (inst->getMnemonic() == Mnemonic_POP) { + stackDepth-=getByteSize(inst->getOpnd(it)->getSize()); + } else if (inst->getMnemonic() == Mnemonic_CALL && ((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->calleeRestoresStack()) { + stackDepth -= ((CallInst *)inst)->getArgStackDepth(); + } + } + } + assert(stackDepth>=0); + } + stackDepths[node->getDfNum()]=stackDepth; + } + } } //_____________________________________________________________________________________________ -bool IRManager::isOnlyPrologSuccessor(BasicBlock * bb) { - BasicBlock * predBB = bb; - for(; ; ) { - if(predBB == getPrologNode()) - return true; - if (predBB != bb) { - const Edges& outedges=predBB->getEdges(Direction_Out); - uint32 i=0; - for (Edge * edge=outedges.getFirst(); edge!=NULL; edge=outedges.getNext(edge), i++){ - } - if (i>1) { - return false; - } - } - const Edges& inedges=predBB->getEdges(Direction_In); - uint32 i=0; - for (Edge * edge=inedges.getFirst(); edge!=NULL; edge=inedges.getNext(edge), i++){ - predBB = (BasicBlock *)edge->getNode(Direction_Tail); - } - if (i>1) { - return false; - } - } +bool IRManager::isOnlyPrologSuccessor(Node * bb) { + Node * predBB = bb; + for(; ; ) { + if(predBB == fg->getEntryNode()) { + return true; + } + if (predBB != bb && predBB->getOutDegree() > 1) { + return false; + } + if (predBB->getInDegree() > 1) { + return false; + } + predBB = predBB->getInEdges().front()->getSourceNode(); + } } //_____________________________________________________________________________________________ void IRManager::expandSystemExceptions(uint32 reservedForFlags) -{ // this is a temporary prototype implementation to be improved in the nearest future and moved into a separate transformer - calculateOpndStatistics(); - StlMap checkOpnds(getMemoryManager()); - StlVector excInsts(getMemoryManager()); - for (CFG::NodeIterator it(*this); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock*)node; - - const Insts& insts=bb->getInsts(); - Inst * inst=insts.getLast(); - if (inst && inst->hasKind(Inst::Kind_SystemExceptionCheckPseudoInst)) { - Node * dispatchNode = bb->getNode(Direction_Out, (Node::Kind)(Node::Kind_DispatchNode)); - excInsts.push_back(inst); - if (!dispatchNode) - checkOpnds[inst->getOpnd(0)] = - ((SystemExceptionCheckPseudoInst*)inst)->checksThisOfInlinedMethod() ? - -1: - (int32)inst; - - } - - if(checkOpnds.size() == 0) - continue; - - for (inst=insts.getFirst(); inst!=NULL; inst = insts.getNext(inst)){ - if (inst->getMnemonic() == Mnemonic_CALL && !inst->hasKind(Inst::Kind_SystemExceptionCheckPseudoInst) && ((CallInst *)inst)->isDirect()) { - Opnd::RuntimeInfo * rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); - if(rt->getKind() == Opnd::RuntimeInfo::Kind_MethodDirectAddr && !((MethodDesc *)rt->getValue(0))->isStatic()) { - Inst::Opnds opnds(inst, Inst::OpndRole_Auxilary | Inst::OpndRole_Use); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - Opnd * opnd = inst->getOpnd(it); - if(checkOpnds.find(opnd) != checkOpnds.end()) - checkOpnds[opnd] = -1; - } - } - } - } - } - } - for(StlVector::iterator it = excInsts.begin(); it != excInsts.end(); it++) { - Inst * lastInst = *it; - BasicBlock * bb = lastInst->getBasicBlock(); - bb->removeInst(lastInst); - switch (((SystemExceptionCheckPseudoInst*)lastInst)->getExceptionId()){ - case CompilationInterface::Exception_NullPointer: - { - Node * dispatchNode = bb->getNode(Direction_Out, (Node::Kind)(Node::Kind_DispatchNode)); - Opnd * opnd = lastInst->getOpnd(0); - if (dispatchNode!=NULL || (checkOpnds[opnd] == -1)){ - BasicBlock * throwBasicBlock = newBasicBlock(0); - throwBasicBlock->appendInsts(newRuntimeHelperCallInst( - CompilationInterface::Helper_NullPtrException, 0, NULL, NULL)); - bb->appendInsts(newInst(Mnemonic_CMP, opnd, newImmOpnd(opnd->getType(), 0))); - bb->appendInsts(newBranchInst(Mnemonic_JZ)); - newDirectBranchEdge(bb, throwBasicBlock, EdgeProbValue_Exception); - newEdge(throwBasicBlock, dispatchNode ? dispatchNode : bb->getNode(Direction_Out, (Node::Kind)(Node::Kind_UnwindNode)), 1 - EdgeProbValue_Exception); - if((checkOpnds[opnd] == -1) && (opnd->getDefScope() == Opnd::DefScope_Temporary) && isOnlyPrologSuccessor(bb)) { - checkOpnds[opnd] = (int32)lastInst; - } - } - break; - } - default: - assert(0); - } - } +{ + calculateOpndStatistics(); + StlMap checkOpnds(getMemoryManager()); + StlVector excInsts(memoryManager); + const Nodes& nodes = fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + Inst * inst=(Inst*)node->getLastInst(); + if (inst && inst->hasKind(Inst::Kind_SystemExceptionCheckPseudoInst)) { + excInsts.push_back(inst); + Node* dispatchNode = node->getExceptionEdgeTarget(); + if (dispatchNode==NULL || dispatchNode==fg->getUnwindNode()) { + checkOpnds[inst->getOpnd(0)] = + ((SystemExceptionCheckPseudoInst*)inst)->checksThisOfInlinedMethod() ? + (POINTER_SIZE_INT)-1: + (POINTER_SIZE_INT)inst; + } + + } + + if(checkOpnds.size() == 0) + continue; + + for (inst=(Inst*)node->getFirstInst(); inst!=NULL; inst = inst->getNextInst()){ + if (inst->getMnemonic() == Mnemonic_CALL && !inst->hasKind(Inst::Kind_SystemExceptionCheckPseudoInst) && ((CallInst *)inst)->isDirect()) { + Opnd::RuntimeInfo * rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); + if(rt->getKind() == Opnd::RuntimeInfo::Kind_MethodDirectAddr && !((MethodDesc *)rt->getValue(0))->isStatic()) { + Inst::Opnds opnds(inst, Inst::OpndRole_Auxilary | Inst::OpndRole_Use); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + Opnd * opnd = inst->getOpnd(it); + if(checkOpnds.find(opnd) != checkOpnds.end()) + checkOpnds[opnd] = (POINTER_SIZE_INT)-1; + } + } + } + } + } + } + for(StlVector::iterator it = excInsts.begin(); it != excInsts.end(); it++) { + Inst * lastInst = *it; + Node* bb = lastInst->getNode(); + switch (((SystemExceptionCheckPseudoInst*)lastInst)->getExceptionId()){ + case CompilationInterface::Exception_NullPointer: + { + Node* oldTarget = bb->getUnconditionalEdge()->getTargetNode(); //must exist + Opnd * opnd = lastInst->getOpnd(0); + Edge* dispatchEdge = bb->getExceptionEdge(); + assert(dispatchEdge!=NULL); + Node* dispatchNode= dispatchEdge->getTargetNode(); + if ((dispatchNode!=fg->getUnwindNode()) ||(checkOpnds[opnd] == (POINTER_SIZE_INT)-1 +#ifdef _EM64T_ + ||!Type::isCompressedReference(opnd->getType()->tag) +#endif + )){ + Node* throwBasicBlock = fg->createBlockNode(); + throwBasicBlock->appendInst(newRuntimeHelperCallInst(CompilationInterface::Helper_NullPtrException, 0, NULL, NULL)); +#ifndef _EM64T_ + bb->appendInst(newInst(Mnemonic_CMP, opnd, newImmOpnd(opnd->getType(), 0))); +#else + bb->appendInst(newInst(Mnemonic_CMP, opnd,newImmOpnd(opnd->getType(), (Type::isCompressedReference(opnd->getType()->tag) || !opnd->getType()->isReference())? 0: (POINTER_SIZE_INT)compilationInterface.getHeapBase()))); +#endif + bb->appendInst(newBranchInst(Mnemonic_JZ, throwBasicBlock, oldTarget)); + fg->addEdge(bb, throwBasicBlock, 0); + + assert(dispatchNode!=NULL); + fg->addEdge(throwBasicBlock, dispatchNode, 1); + if((checkOpnds[opnd] == (POINTER_SIZE_INT)-1) && (opnd->getDefScope() == Opnd::DefScope_Temporary) && isOnlyPrologSuccessor(bb)) { + checkOpnds[opnd] = (POINTER_SIZE_INT)lastInst; + } + } else { //hardware exception handling + if (bb->getFirstInst() == lastInst) { + fg->removeEdge(dispatchEdge); + } + } + break; + } + default: + assert(0); + } + lastInst->unlink(); + } } //_____________________________________________________________________________________________ void IRManager::translateToNativeForm() { - const Nodes& nodes = getNodes(); + const Nodes& nodes = fg->getNodes(); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)){ - const Insts & insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ if (inst->getForm()==Inst::Form_Extended) { - inst->makeNative(this); + inst->makeNative(this); } - } - } - } + } + } + } } //_____________________________________________________________________________________________ void IRManager::eliminateSameOpndMoves() { - const Nodes& nodes = getNodes(); + const Nodes& nodes = fg->getNodes(); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)){ - const Insts & insts=((BasicBlock*)node)->getInsts(); - for (Inst * inst=insts.getFirst(), * nextInst=NULL; inst!=NULL; inst=nextInst){ - nextInst=insts.getNext(inst); + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(), *nextInst=NULL; inst!=NULL; inst=nextInst){ + nextInst=inst->getNextInst(); if (inst->getMnemonic()==Mnemonic_MOV && inst->getOpnd(0)==inst->getOpnd(1)) { - ((BasicBlock*)node)->removeInst(inst); + inst->unlink(); } - } - } - } + } + } + } } //_____________________________________________________________________________________________ void IRManager::resolveRuntimeInfo() { - for (uint32 i=0, n=getOpndCount(); iisPlacedIn(OpndKind_Imm)) - return; + if (!opnd->isPlacedIn(OpndKind_Imm)) + return; Opnd::RuntimeInfo * info=opnd->getRuntimeInfo(); if (info==NULL) - return; - int32 value=0; + return; + int64 value=0; switch(info->getKind()){ case Opnd::RuntimeInfo::Kind_HelperAddress: /** The value of the operand is compilationInterface->getRuntimeHelperAddress */ - value=(int32)compilationInterface.getRuntimeHelperAddress( - (CompilationInterface::RuntimeHelperId)(uint32)info->getValue(0) + value=(POINTER_SIZE_INT)compilationInterface.getRuntimeHelperAddress( + (CompilationInterface::RuntimeHelperId)(POINTER_SIZE_INT)info->getValue(0) ); assert(value!=0); break; case Opnd::RuntimeInfo::Kind_InternalHelperAddress: /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ - value=(int32)getInternalHelperInfo((const char*)info->getValue(0))->pfn; + value=(POINTER_SIZE_INT)getInternalHelperInfo((const char*)info->getValue(0))->pfn; assert(value!=0); break; case Opnd::RuntimeInfo::Kind_TypeRuntimeId: - /* The value of the operand is [0]->ObjectType::getRuntimeIdentifier() */ - value=(int32)((NamedType*)info->getValue(0))->getRuntimeIdentifier(); + /* The value of the operand is [0]->ObjectType::getRuntimeIdentifier() */ + value=(POINTER_SIZE_INT)((NamedType*)info->getValue(0))->getRuntimeIdentifier(); + break; + case Opnd::RuntimeInfo::Kind_MethodRuntimeId: + value=(POINTER_SIZE_INT)compilationInterface.getRuntimeMethodHandle((MethodDesc*)info->getValue(0)); break; - case Opnd::RuntimeInfo::Kind_MethodRuntimeId: - value=(int32)compilationInterface.getRuntimeMethodHandle((MethodDesc*)info->getValue(0)); - break; case Opnd::RuntimeInfo::Kind_AllocationHandle: /* The value of the operand is [0]->ObjectType::getAllocationHandle() */ - value=(int32)((ObjectType*)info->getValue(0))->getAllocationHandle(); + value=(POINTER_SIZE_INT)((ObjectType*)info->getValue(0))->getAllocationHandle(); break; case Opnd::RuntimeInfo::Kind_StringDescription: /* [0] - Type * - the containing class, [1] - string token */ @@ -1736,284 +1941,271 @@ void IRManager::resolveRuntimeInfo(Opnd* break; case Opnd::RuntimeInfo::Kind_Size: /* The value of the operand is [0]->ObjectType::getObjectSize() */ - value=(int32)((ObjectType*)info->getValue(0))->getObjectSize(); + value=(POINTER_SIZE_INT)((ObjectType*)info->getValue(0))->getObjectSize(); break; + case Opnd::RuntimeInfo::Kind_StringAddress: + /** The value of the operand is the address where the interned version of the string is stored*/ + { + MethodDesc* mDesc = (MethodDesc*)info->getValue(0); + POINTER_SIZE_INT token = (POINTER_SIZE_INT)info->getValue(1); + value = (POINTER_SIZE_INT) compilationInterface.loadStringObject(mDesc,token); + }break; case Opnd::RuntimeInfo::Kind_StaticFieldAddress: /** The value of the operand is [0]->FieldDesc::getAddress() */ - value=(int32)((FieldDesc*)info->getValue(0))->getAddress(); + value=(POINTER_SIZE_INT)((FieldDesc*)info->getValue(0))->getAddress(); break; case Opnd::RuntimeInfo::Kind_FieldOffset: /** The value of the operand is [0]->FieldDesc::getOffset() */ - value=(int32)((FieldDesc*)info->getValue(0))->getOffset(); + value=(POINTER_SIZE_INT)((FieldDesc*)info->getValue(0))->getOffset(); break; case Opnd::RuntimeInfo::Kind_VTableAddrOffset: /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ - value=(int32)compilationInterface.getVTableOffset(); + value=(POINTER_SIZE_INT)compilationInterface.getVTableOffset(); break; case Opnd::RuntimeInfo::Kind_VTableConstantAddr: /** The value of the operand is [0]->ObjectType::getVTable() */ - value=(int32)((ObjectType*)info->getValue(0))->getVTable(); + value=(POINTER_SIZE_INT)((ObjectType*)info->getValue(0))->getVTable(); break; case Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset: /** The value of the operand is [0]->MethodDesc::getOffset() */ - value=(int32)((MethodDesc*)info->getValue(0))->getOffset(); + value=(POINTER_SIZE_INT)((MethodDesc*)info->getValue(0))->getOffset(); break; case Opnd::RuntimeInfo::Kind_MethodIndirectAddr: /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ - value=(int32)((MethodDesc*)info->getValue(0))->getIndirectAddress(); + value=(POINTER_SIZE_INT)((MethodDesc*)info->getValue(0))->getIndirectAddress(); break; case Opnd::RuntimeInfo::Kind_MethodDirectAddr: /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ - value=*(int32*)((MethodDesc*)info->getValue(0))->getIndirectAddress(); + value=*(POINTER_SIZE_INT*)((MethodDesc*)info->getValue(0))->getIndirectAddress(); break; case Opnd::RuntimeInfo::Kind_ConstantAreaItem: /** The value of the operand is address of constant pool item ((ConstantPoolItem*)[0])->getAddress() */ - value=(uint32)((ConstantAreaItem*)info->getValue(0))->getAddress(); + value=(POINTER_SIZE_INT)((ConstantAreaItem*)info->getValue(0))->getAddress(); break; default: assert(0); } - opnd->assignImmValue(value+info->getAdditionalOffset()); + opnd->assignImmValue(value+info->getAdditionalOffset()); } //_____________________________________________________________________________________________ bool IRManager::verify() { - updateLivenessInfo(); - if (!verifyLiveness()) - return false; - if (!verifyHeapAddressTypes()) - return false; - return true; + updateLivenessInfo(); + if (!verifyLiveness()) + return false; + if (!verifyHeapAddressTypes()) + return false; + + +#ifdef _DEBUG + //check unwind node; + Node* unwind = fg->getUnwindNode(); + Node* exit = fg->getExitNode(); + assert(exit!=NULL); + assert(unwind == NULL || unwind->getOutDegree() == 1 && unwind->isConnectedTo(true, exit)); + const Edges& exitInEdges = exit->getInEdges(); + for (Edges::const_iterator ite = exitInEdges.begin(), ende = exitInEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node* source = edge->getSourceNode(); + assert(source == unwind || source->isBlockNode()); + } + const Nodes& nodes = fg->getNodesPostOrder();//check only reachable nodes. + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + CGNode* node = (CGNode*)*it; + node->verify(); + } +#endif + return true; } //_____________________________________________________________________________________________ bool IRManager::verifyLiveness() { - BasicBlock * prolog=getPrologNode(); - bool failed=false; - LiveSet * ls=getLiveAtEntry(prolog); - assert(ls!=NULL); - Constraint calleeSaveRegs=Constraint(OpndKind_GPReg, Constraint::getDefaultSize(OpndKind_GPReg), getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg)); - - LiveSet::IterB lives(*ls); - for (int i = lives.getNext(); i != -1; i = lives.getNext()){ - Opnd * opnd=getOpnd(i); - assert(opnd!=NULL); - if ( - opnd->isSubjectForLivenessAnalysis() && - (opnd->isPlacedIn(RegName_EFLAGS)||!isPreallocatedRegOpnd(opnd)) - ){ - VERIFY_OUT("Operand live at entry: " << opnd << ::std::endl); - VERIFY_OUT("This means there is a use of the operand when it is not yet defined" << ::std::endl); - failed=true; - }; - } - if (failed) - VERIFY_OUT(::std::endl << "Liveness verification failure" << ::std::endl); - return !failed; + Node* prolog=fg->getEntryNode(); + bool failed=false; + BitSet * ls=getLiveAtEntry(prolog); + assert(ls!=NULL); + Constraint calleeSaveRegs=getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg); + + BitSet::IterB lives(*ls); + for (int i = lives.getNext(); i != -1; i = lives.getNext()){ + Opnd * opnd=getOpnd(i); + assert(opnd!=NULL); + if ( + opnd->isSubjectForLivenessAnalysis() && + (opnd->isPlacedIn(RegName_EFLAGS)||!isPreallocatedRegOpnd(opnd)) + ){ + VERIFY_OUT("Operand live at entry: " << opnd << ::std::endl); + VERIFY_OUT("This means there is a use of the operand when it is not yet defined" << ::std::endl); + failed=true; + }; + } + if (failed) + VERIFY_OUT(::std::endl << "Liveness verification failure" << ::std::endl); + return !failed; } //_____________________________________________________________________________________________ bool IRManager::verifyHeapAddressTypes() { - bool failed=false; - for (uint32 i=0, n=getOpndCount(); iisPlacedIn(OpndKind_Mem) && opnd->getMemOpndKind()==MemOpndKind_Heap){ - Opnd * properTypeSubOpnd=NULL; - for (uint32 j=0; jgetMemOpndSubOpnd((MemOpndSubOpndKind)j); - if (subOpnd!=NULL){ - Type * type=subOpnd->getType(); - if (type->isManagedPtr()||type->isObject()||type->isMethodPtr()||type->isVTablePtr()||type->isUnmanagedPtr()){ - if (properTypeSubOpnd!=NULL){ - VERIFY_OUT("Heap operand " << opnd << " contains more than 1 sub-operands of type Object or ManagedPointer "<<::std::endl); - VERIFY_OUT("Opnd 1: " << properTypeSubOpnd << ::std::endl); - VERIFY_OUT("Opnd 2: " << subOpnd << ::std::endl); - failed=true; - break; - } + bool failed=false; + for (uint32 i=0, n=getOpndCount(); iisPlacedIn(OpndKind_Mem) && opnd->getMemOpndKind()==MemOpndKind_Heap){ + Opnd * properTypeSubOpnd=NULL; + for (uint32 j=0; jgetMemOpndSubOpnd((MemOpndSubOpndKind)j); + if (subOpnd!=NULL){ + Type * type=subOpnd->getType(); + if (type->isManagedPtr()||type->isObject()||type->isMethodPtr()||type->isVTablePtr()||type->isUnmanagedPtr()){ + if (properTypeSubOpnd!=NULL){ + VERIFY_OUT("Heap operand " << opnd << " contains more than 1 sub-operands of type Object or ManagedPointer "<<::std::endl); + VERIFY_OUT("Opnd 1: " << properTypeSubOpnd << ::std::endl); + VERIFY_OUT("Opnd 2: " << subOpnd << ::std::endl); + failed=true; + break; + } properTypeSubOpnd=subOpnd; - } - } - } - if (failed) - break; - if (properTypeSubOpnd==NULL){ - VERIFY_OUT("Heap operand " << opnd << " contains no sub-operands of type Object or ManagedPointer "<<::std::endl); - failed=true; - break; - } - } - } - if (failed) - VERIFY_OUT(::std::endl << "Heap address type verification failure" << ::std::endl); - return !failed; + } + } + } + if (failed) + break; + if (properTypeSubOpnd==NULL){ + VERIFY_OUT("Heap operand " << opnd << " contains no sub-operands of type Object or ManagedPointer "<<::std::endl); + failed=true; + break; + } + } + } + if (failed) + VERIFY_OUT(::std::endl << "Heap address type verification failure" << ::std::endl); + return !failed; +} + +ControlFlowGraph* IRManager::createSubCFG(bool withReturn, bool withUnwind) { + ControlFlowGraph* cfg = new (memoryManager) ControlFlowGraph(memoryManager, this); + cfg->setEntryNode(cfg->createBlockNode()); + cfg->setExitNode(cfg->createExitNode()); + if (withReturn) { + cfg->setReturnNode(cfg->createBlockNode()); + cfg->addEdge(cfg->getReturnNode(), cfg->getExitNode(), 1); + } + if (withUnwind) { + cfg->setUnwindNode(cfg->createDispatchNode()); + cfg->addEdge(cfg->getUnwindNode(), cfg->getExitNode(), 1); + } + return cfg; } -//============================================================================================= -// class IRTransformer implementation -//============================================================================================= -uint32 IRTransformer::registerIRTransformer(const char * tag, CreateFunction pfn) -{ - assert(tableLengthcreateFunction(irm, params); - tr->record=trr; - return tr; - } - return NULL; +// factory method for ControlFlowGraph +Edge* IRManager::createEdge(MemoryManager& mm, Node::Kind srcKind, Node::Kind dstKind) { + if (srcKind == Node::Kind_Dispatch && dstKind == Node::Kind_Block) { + return new (mm) CatchEdge(); + } + return ControlFlowGraphFactory::createEdge(mm, srcKind, dstKind); } -void IRTransformer::run() -{ - stageId=Log::getNextStageId(); - if (Log::cat_cg()->isIREnabled()) - Log::printStageBegin(stageId, "IA32", getName(), getTagName()); - uint32 needInfo=getNeedInfo(); - if (needInfo & NeedInfo_LivenessInfo) - irManager.updateLivenessInfo(); - if (needInfo & NeedInfo_LoopInfo) - irManager.updateLoopInfo(); +//============================================================================================= +// class Ia32::SessionAction implementation +//============================================================================================= - if (record){ - record->xtimer.start(); - runImpl(); - record->xtimer.stop(); - }else - runImpl(); +void SessionAction::run() +{ + irManager = &getIRManager(); - uint32 sideEffects=getSideEffects(); - if (sideEffects & SideEffect_InvalidatesLivenessInfo) - irManager.invalidateLivenessInfo(); - if (sideEffects & SideEffect_InvalidatesLoopInfo) - irManager.invalidateLoopInfo(); + stageId=Log::getStageId(); - debugOutput("after"); + if (isLogEnabled(LogStream::IRDUMP)) + Log::printStageBegin(log(LogStream::IRDUMP).out(), stageId, "IA32", getName(), getTagName()); - if (!verify()){ - VERIFY_OUT(::std::endl<<"Verification failure after "<updateLivenessInfo(); + if (needInfo & NeedInfo_LoopInfo) + irManager->updateLoopInfo(); - if (Log::cat_cg()->isIREnabled()) - Log::printStageEnd(stageId, "IA32", getName(), getTagName()); -} + runImpl(); -//_________________________________________________________________________________________________ -uint32 IRTransformer::getSideEffects()const -{ - return ~(uint32)0; -} + uint32 sideEffects=getSideEffects(); + if (sideEffects & SideEffect_InvalidatesLivenessInfo) + irManager->invalidateLivenessInfo(); + if (sideEffects & SideEffect_InvalidatesLoopInfo) + irManager->invalidateLoopInfo(); -//_________________________________________________________________________________________________ -uint32 IRTransformer::getNeedInfo()const -{ - return ~(uint32)0; -} + debugOutput("after"); -//_________________________________________________________________________________________________ -bool IRTransformer::verify(bool force) -{ - if (force||irManager.getVerificationLevel()>=2) - return irManager.verify(); - return true; -} + if (!verify()) + crash("\nVerification failure after %s\n", getName()); -//_________________________________________________________________________________________________ -void IRTransformer::printIRDumpBegin(const char * subKind) -{ - if (Log::cat_cg()->isIREnabled()) - Log::printIRDumpBegin(stageId, getName(), subKind); + if (isLogEnabled(LogStream::IRDUMP)) + Log::printStageEnd(log(LogStream::IRDUMP).out(), stageId, "IA32", getName(), getTagName()); } -//_________________________________________________________________________________________________ -void IRTransformer::printIRDumpEnd(const char * subKind) + +uint32 SessionAction::getSideEffects()const { - if (Log::cat_cg()->isIREnabled()) - Log::printIRDumpEnd(stageId, getName(), subKind); + return ~(uint32)0; } -//_________________________________________________________________________________________________ -void IRTransformer::dumpIR(const char * subKind1, const char * subKind2) +uint32 SessionAction::getNeedInfo()const { - Ia32::dumpIR(&irManager, stageId, "IA32 LIR CFG after ", getName(), getTagName(), - subKind1, subKind2); + return ~(uint32)0; } -//_________________________________________________________________________________________________ -void IRTransformer::printDot(const char * subKind1, const char * subKind2) +bool SessionAction::verify(bool force) +{ + if (force || getVerificationLevel()>=2) + return getIRManager().verify(); + return true; +} + +void SessionAction::dumpIR(const char * subKind1, const char * subKind2) { - Ia32::printDot(&irManager, stageId, "IA32 LIR CFG after ", getName(), getTagName(), - subKind1, subKind2); + Ia32::dumpIR(irManager, stageId, "IA32 LIR CFG after ", getName(), getTagName(), + subKind1, subKind2); } -//_________________________________________________________________________________________________ -void IRTransformer::debugOutput(const char * subKind) +void SessionAction::printDot(const char * subKind1, const char * subKind2) { - if (isIRDumpEnabled() && Log::cat_cg()->isIREnabled()){ - irManager.updateLoopInfo(); - - if (Log::cat_cg()->isIR2Enabled()){ - irManager.updateLivenessInfo(); - dumpIR(subKind, "opnds"); - dumpIR(subKind, "liveness"); - } - dumpIR(subKind); - - if (irManager.getCompilationContext()->getIa32CGFlags()->dumpdot) { - printDot(subKind); - if (Log::cat_cg()->isIR2Enabled()){ - irManager.updateLivenessInfo(); - printDot(subKind, "liveness"); - } - } - } + Ia32::printDot(irManager, stageId, "IA32 LIR CFG after ", getName(), getTagName(), + subKind1, subKind2); } - -struct IRTimers : public CounterBase +void SessionAction::debugOutput(const char * subKind) { - IRTimers () :CounterBase("IRTimers") {} - - void write (CountWriter&); -}; + if (!isIRDumpEnabled()) + return; + if (isLogEnabled(LogStream::IRDUMP)) { + irManager->updateLoopInfo(); + irManager->updateLivenessInfo(); + dumpIR(subKind, "opnds"); + dumpIR(subKind, "liveness"); + dumpIR(subKind); + } -void IRTimers::write (CountWriter& cw) -{ - char key[128] = "timer:ia32::"; - size_t pref = strlen(key); - for (size_t i = 0; i < IRTransformer::tableLength; i++) - { - IRTransformer::IRTransformerRecord& r = IRTransformer::table[i]; - strncpy(key + pref, r.tag, sizeof(key) - pref - 1); - cw.write(key, r.xtimer.getSeconds()); - } + if (isLogEnabled(LogStream::DOTDUMP)) { + irManager->updateLoopInfo(); + irManager->updateLivenessInfo(); + printDot(subKind); + printDot(subKind, "liveness"); + } } -static IRTimers irtimers; - -}}; //namespace Ia32 +} //namespace Ia32 +} //namespace Jitrino diff --git vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h index 869456f..3ede621 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h +++ vm/jitrino/src/codegenerator/ia32/Ia32IRManager.h @@ -29,26 +29,37 @@ #include "CodeGenIntfc.h" #include "Ia32Inst.h" #include "Ia32CFG.h" #include "BitSet.h" -#include "Timer.h" #include "XTimer.h" #include "Log.h" #include "../../shared/PlatformDependant.h" #include "CGSupport.h" #include "CompilationContext.h" +#include "JITInstanceContext.h" +#include "PMFAction.h" +#include "Ia32CodeGeneratorFlags.h" + +#include "LoopTree.h" namespace Jitrino { -namespace Ia32{ +namespace Ia32 +{ const char * newString(MemoryManager& mm, const char * str, uint32 length=EmptyUint32); +#ifdef _EM64T_ + #define STACK_REG RegName_RSP +#else + #define STACK_REG RegName_ESP +#endif + //======================================================================================== // STL aux classes (need to be moved somewhere) //======================================================================================== struct ConstCharStringLess -{ - bool operator()(const char * l, const char * r) const - { return (l==0?(r==0?0:-1):r==0?1:strcmp(l,r))<0; } +{ + bool operator()(const char * l, const char * r) const + { return (l==0?(r==0?0:-1):r==0?1:strcmp(l,r))<0; } }; @@ -56,255 +67,273 @@ struct ConstCharStringLess // class IRManager //======================================================================================== /** - class IRManager is used to create elements of the LIR, to change the LIR's structure, - and to access various information which is considered worth to be tracked LIR-wide - + class IRManager is used to create elements of the LIR, to change the LIR's structure, + and to access various information which is considered worth to be tracked LIR-wide + */ -class IRManager: public CFG +class IRManager : protected ControlFlowGraphFactory { public: - typedef StlMap ConstCharStringToVoidPtrMap; + ControlFlowGraph* getFlowGraph() const {return fg;} - struct InternalHelperInfo - { - const void * pfn; - const CallingConvention * callingConvention; - InternalHelperInfo(const void * _pfn=NULL, const CallingConvention * _callingConvention=NULL) - :pfn(_pfn), callingConvention(_callingConvention){} - }; + typedef StlMap ConstCharStringToVoidPtrMap; - typedef StlMap InternalHelperInfos; + struct InternalHelperInfo + { + const void * pfn; + const CallingConvention * callingConvention; + InternalHelperInfo(const void * _pfn=NULL, const CallingConvention * _callingConvention=NULL) + :pfn(_pfn), callingConvention(_callingConvention){} + }; - //--------------------------------------------------------------------------------------- - /** Creates IRManager */ - - IRManager(MemoryManager& memManager, TypeManager& tm, MethodDesc& md, - CompilationInterface& compIface); + typedef StlMap InternalHelperInfos; + + //--------------------------------------------------------------------------------------- + /** Creates IRManager */ + + IRManager(MemoryManager& memManager, TypeManager& tm, MethodDesc& md, CompilationInterface& compIface); - //------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------- - /** Returns the type manager used for LIR */ - TypeManager& getTypeManager()const{ return typeManager; } + /** Returns the type manager used for LIR */ + TypeManager& getTypeManager()const{ return typeManager; } - /** Returns the MethodDesc for the method represented by this IR */ - MethodDesc& getMethodDesc()const{ return methodDesc; } + /** Returns the MethodDesc for the method represented by this IR */ + MethodDesc& getMethodDesc()const{ return methodDesc; } - /** Returns the CompilationInterface for this compilation session */ - CompilationInterface& getCompilationInterface()const{ return compilationInterface; } + MemoryManager& getMemoryManager() const {return memoryManager;} + + /** Returns the CompilationInterface for this compilation session */ + CompilationInterface& getCompilationInterface()const{ return compilationInterface; } CompilationContext* getCompilationContext()const{ return compilationInterface.getCompilationContext();} - CGFlags* getCGFlags() const {return getCompilationContext()->getIa32CGFlags();} + JITInstanceContext* getCurrentJITContext() const {return getCompilationContext()->getCurrentJITContext();} + ProfilingInterface* getProfilingInterface()const{ return getCurrentJITContext()->getProfilingInterface();} + CGFlags* getCGFlags() {return &flags;} + + //----------------------------------------------------------------------------------------------- + void setInfo(const char * key, void * info) + { infoMap[newInternalString(key)]=info; } - //----------------------------------------------------------------------------------------------- - void setInfo(const char * key, void * info) - { infoMap[newInternalString(key)]=info; } + const void * getInfo(const char * key) + { ConstCharStringToVoidPtrMap::const_iterator it=infoMap.find(key); return it!=infoMap.end()?it->second:NULL; } - const void * getInfo(const char * key) - { ConstCharStringToVoidPtrMap::const_iterator it=infoMap.find(key); return it!=infoMap.end()?it->second:NULL; } + //------------------------------------------------------------------------------------- + struct AliasRelation + { + Opnd * outerOpnd; + uint32 offset; + AliasRelation(Opnd * oo =0, uint32 offs=0) + :outerOpnd(oo), offset(offs){} + }; - //------------------------------------------------------------------------------------- - struct AliasRelation - { - Opnd * outerOpnd; - uint32 offset; - AliasRelation(Opnd * oo =0, uint32 offs=0) - :outerOpnd(oo), offset(offs){} - }; + //------------------------------------------------------------------------------------- + /** Creates a new unassigned operand (virtual register) of type ta*/ + Opnd * newOpnd(Type * type); + /** Creates a new unassigned operand (virtual register) of type ta, with additional constraint c */ + Opnd * newOpnd(Type * type, Constraint c); - //------------------------------------------------------------------------------------- - /** Creates a new unassigned operand (virtual register) of type ta*/ - Opnd * newOpnd(Type * type); - /** Creates a new unassigned operand (virtual register) of type ta, with additional constraint c */ - Opnd * newOpnd(Type * type, Constraint c); + /** Creates a new operand assigned with immediate value */ + Opnd * newImmOpnd(Type * type, int64 immediate); - /** Creates a new operand assigned with immediate value */ - Opnd * newImmOpnd(Type * type, int64 immediate); + /** Creates a new immediate operand associated with + runtime info of the specified kind */ + Opnd * newImmOpnd(Type * type, Opnd::RuntimeInfo::Kind kind, void * arg0=0, void * arg1=0, void * arg2=0, void * arg3=0); - /** Creates a new immediate operand associated with - runtime info of the specified kind */ - Opnd * newImmOpnd(Type * type, Opnd::RuntimeInfo::Kind kind, void * arg0=0, void * arg1=0, void * arg2=0, void * arg3=0); + ConstantAreaItem * newConstantAreaItem(float f); + ConstantAreaItem * newConstantAreaItem(double d); + ConstantAreaItem * newSwitchTableConstantAreaItem(uint32 numTargets); + ConstantAreaItem * newInternalStringConstantAreaItem(const char * str); + ConstantAreaItem * newBinaryConstantAreaItem(uint32 size, const void * pv); - ConstantAreaItem * newConstantAreaItem(float f); - ConstantAreaItem * newConstantAreaItem(double d); - ConstantAreaItem * newSwitchTableConstantAreaItem(uint32 numTargets); - ConstantAreaItem * newInternalStringConstantAreaItem(const char * str); - ConstantAreaItem * newBinaryConstantAreaItem(uint32 size, const void * pv); + Opnd * newFPConstantMemOpnd(float f, Opnd * baseOpnd=0, BasicBlock * bb=0); + Opnd * newFPConstantMemOpnd(double f, Opnd * baseOpnd=0, BasicBlock * bb=0); + Opnd * newSwitchTableConstantMemOpnd(uint32 numTargets, Opnd * index); - Opnd * newFPConstantMemOpnd(float f); - Opnd * newFPConstantMemOpnd(double f); - Opnd * newSwitchTableConstantMemOpnd(uint32 numTargets, Opnd * index); + Opnd * newInternalStringConstantImmOpnd(const char * str); + Opnd * newBinaryConstantImmOpnd(uint32 size, const void * pv); - Opnd * newInternalStringConstantImmOpnd(const char * str); - Opnd * newBinaryConstantImmOpnd(uint32 size, const void * pv); + /** Creates a new operand assigned to a physical register */ + Opnd * newRegOpnd(Type * type, RegName reg); - /** Creates a new operand assigned to a physical register */ - Opnd * newRegOpnd(Type * type, RegName reg); + /** Creates a new operand assigned to a memory location of kind k */ + Opnd * newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd * index=0, Opnd * scale=0, Opnd * displacement=0, RegName segReg=RegName_Null); + /** Shortcut: Creates a new operand assigned to a memory location of kind Heap */ + Opnd * newMemOpnd(Type * type, Opnd * base, Opnd * index=0, Opnd * scale=0, Opnd * displacement=0, RegName segReg=RegName_Null); + /** Shortcut: Creates a new operand assigned to a memory location of kind k */ + Opnd * newMemOpnd(Type * type, MemOpndKind k, Opnd * base, int32 displacement, RegName segReg=RegName_Null); - /** Creates a new operand assigned to a memory location of kind k */ - Opnd * newMemOpnd(Type * type, MemOpndKind k, Opnd * base, Opnd * index=0, Opnd * scale=0, Opnd * displacement=0, RegName baseReg=RegName_Null); - /** Shortcut: Creates a new operand assigned to a memory location of kind Heap */ - Opnd * newMemOpnd(Type * type, Opnd * base, Opnd * index=0, Opnd * scale=0, Opnd * displacement=0, RegName baseReg=RegName_Null); - /** Shortcut: Creates a new operand assigned to a memory location of kind k */ - Opnd * newMemOpnd(Type * type, MemOpndKind k, Opnd * base, int32 displacement, RegName baseReg=RegName_Null); + Opnd * newMemOpndAutoKind(Type * type, MemOpndKind k, Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0); + Opnd * newMemOpndAutoKind(Type * type, Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0) + { return newMemOpndAutoKind(type, MemOpndKind_Heap, opnd0, opnd1, opnd2); } - Opnd * newMemOpndAutoKind(Type * type, MemOpndKind k, Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0); - Opnd * newMemOpndAutoKind(Type * type, Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0) - { return newMemOpndAutoKind(type, MemOpndKind_Heap, opnd0, opnd1, opnd2); } + //------------------------------------------------------------------------------------- + /** Creates a new Native Inst defined by mnemonic with up to 8 operands */ + Inst * newInst(Mnemonic mnemonic, Opnd * opnd0=0, Opnd * opnd1=0, Opnd * opnd2=0); - //------------------------------------------------------------------------------------- - /** Creates a new Native Inst defined by mnemonic with up to 8 operands */ - Inst * newInst(Mnemonic mnemonic, Opnd * opnd0=0, Opnd * opnd1=0, Opnd * opnd2=0); + Inst * newInst(Mnemonic mnemonic, + Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, + Opnd * opnd4, Opnd * opnd5=0, Opnd * opnd6=0, Opnd * opnd7=0 + ); - Inst * newInst(Mnemonic mnemonic, - Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, - Opnd * opnd4, Opnd * opnd5=0, Opnd * opnd6=0, Opnd * opnd7=0 - ); + /** Creates a new Extended Inst defined by mnemonic with up to 8 operands */ + Inst * newInstEx(Mnemonic mnemonic, uint32 defCount, Opnd * opnd0=0, Opnd * opnd1=0, Opnd * opnd2=0); - /** Creates a new Extended Inst defined by mnemonic with up to 8 operands */ - Inst * newInstEx(Mnemonic mnemonic, uint32 defCount, Opnd * opnd0=0, Opnd * opnd1=0, Opnd * opnd2=0); + Inst * newInstEx(Mnemonic mnemonic, uint32 defCount, + Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, + Opnd * opnd4, Opnd * opnd5=0, Opnd * opnd6=0, Opnd * opnd7=0 + ); - Inst * newInstEx(Mnemonic mnemonic, uint32 defCount, - Opnd * opnd0, Opnd * opnd1, Opnd * opnd2, Opnd * opnd3, - Opnd * opnd4, Opnd * opnd5=0, Opnd * opnd6=0, Opnd * opnd7=0 - ); + /** Creates a new branch instruction + The source of the targetMemOpnd can be defined by its RuntimInfo - /** Creates a new branch instruction - The source of the targetMemOpnd can be defined by its RuntimInfo + if the targetOpnd is null, implicit immediate operand is created and initialized to 0, + meaning that the branch is direct. Branch address will be updated during code emission + */ + BranchInst * newBranchInst(Mnemonic mnemonic, Node* trueTarget, Node* falseTarget, Opnd * targetOpnd=0); - if the targetOpnd is null, implicit immediate operand is created and initialized to 0, - meaning that the branch is direct. Branch address will be updated during code emission - */ - BranchInst * newBranchInst(Mnemonic mnemonic, Opnd * targetOpnd=0); + SwitchInst * newSwitchInst(uint32 numTargets, Opnd * index); - SwitchInst * newSwitchInst(uint32 numTargets, Opnd * index); + JumpInst * newJumpInst(Opnd * targetOpnd=0); - /** Creates a CallInst instance. */ - CallInst * newCallInst(Opnd * targetOpnd, const CallingConvention * cc, - uint32 numArgs, Opnd ** args, Opnd * retOpnd, InlineInfo* ii = NULL); + /** Creates a CallInst instance. */ + CallInst * newCallInst(Opnd * targetOpnd, const CallingConvention * cc, + uint32 numArgs, Opnd ** args, Opnd * retOpnd, InlineInfo* ii = NULL); - /** A specialization of the newCallInst to create a VM Helper CallInst. */ - CallInst * newRuntimeHelperCallInst(CompilationInterface::RuntimeHelperId helperId, - uint32 numArgs, Opnd ** args, Opnd * retOpnd); - /** A specialization of the newCallInst to create an internal helper CallInst. */ - CallInst * newInternalRuntimeHelperCallInst(const char * internalHelperID, uint32 numArgs, Opnd ** args, Opnd * retOpnd); + /** A specialization of the newCallInst to create a VM Helper CallInst. */ + CallInst * newRuntimeHelperCallInst(CompilationInterface::RuntimeHelperId helperId, + uint32 numArgs, Opnd ** args, Opnd * retOpnd, InlineInfo* ii = NULL); + /** A specialization of the newCallInst to create an internal helper CallInst. */ + CallInst * newInternalRuntimeHelperCallInst(const char * internalHelperID, uint32 numArgs, Opnd ** args, Opnd * retOpnd); - void registerInternalHelperInfo(const char * internalHelperID, const InternalHelperInfo& info); - const InternalHelperInfo * getInternalHelperInfo(const char * internalHelperID)const - { InternalHelperInfos::const_iterator it=internalHelperInfos.find(internalHelperID); return it!=internalHelperInfos.end()?&it->second:NULL; } + void registerInternalHelperInfo(const char * internalHelperID, const InternalHelperInfo& info); + const InternalHelperInfo * getInternalHelperInfo(const char * internalHelperID)const + { InternalHelperInfos::const_iterator it=internalHelperInfos.find(internalHelperID); return it!=internalHelperInfos.end()?&it->second:NULL; } - const char * newInternalString(const char * originalString)const - { return newString(memoryManager, originalString); } + const char * newInternalString(const char * originalString)const + { return newString(memoryManager, originalString); } - AliasPseudoInst * newAliasPseudoInst(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 offset); - AliasPseudoInst * newAliasPseudoInst(Opnd * targetOpnd, uint32 sourceOpndCount, Opnd ** sourceOpnds); + AliasPseudoInst * newAliasPseudoInst(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 offset); + AliasPseudoInst * newAliasPseudoInst(Opnd * targetOpnd, uint32 sourceOpndCount, Opnd ** sourceOpnds); - CatchPseudoInst * newCatchPseudoInst(Opnd * exception); + CatchPseudoInst * newCatchPseudoInst(Opnd * exception); - Inst * newI8PseudoInst(Mnemonic mnemonic, uint32 defCount, - Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0, Opnd * opnd3=0 - ); + Inst * newI8PseudoInst(Mnemonic mnemonic, uint32 defCount, + Opnd * opnd0, Opnd * opnd1=0, Opnd * opnd2=0, Opnd * opnd3=0 + ); GCInfoPseudoInst* newGCInfoPseudoInst(const StlVector& basesAndMptr); - SystemExceptionCheckPseudoInst* newSystemExceptionCheckPseudoInst(CompilationInterface::SystemExceptionId exceptionId, Opnd * opnd0, Opnd * opnd1=0, bool checksThisForInlinedMethod=false); + SystemExceptionCheckPseudoInst* newSystemExceptionCheckPseudoInst(CompilationInterface::SystemExceptionId exceptionId, Opnd * opnd0, Opnd * opnd1=0, bool checksThisForInlinedMethod=false); - Inst * newCopyPseudoInst(Mnemonic mn, Opnd * opnd0, Opnd * opnd1=NULL); + Inst * newCopyPseudoInst(Mnemonic mn, Opnd * opnd0, Opnd * opnd1=NULL); - /** Creates the ret instruction - using the primary calling convention associated with this method in IRManager's constructor - */ - RetInst * newRetInst(Opnd * retOpnd); + /** Creates the ret instruction + using the primary calling convention associated with this method in IRManager's constructor + */ + RetInst * newRetInst(Opnd * retOpnd); - /** Creates an EntryPointPseudoInst pseudo instruction representing the entry point of a method. - */ - EntryPointPseudoInst * newEntryPointPseudoInst(const CallingConvention * cc); + /** Creates an EntryPointPseudoInst pseudo instruction representing the entry point of a method. + */ + EntryPointPseudoInst * newEntryPointPseudoInst(const CallingConvention * cc); - Inst * newCopySequence(Mnemonic mn, Opnd * opnd0, Opnd * opnd1=NULL, uint32 regUsageMask=(uint32)~0); + Inst * newCopySequence(Mnemonic mn, Opnd * opnd0, Opnd * opnd1=NULL, uint32 regUsageMask=(uint32)~0, uint32 flagsRegUsageMask=(uint32)~0); - //--------------------------------------------------------------------------------------- - void setHasCalls(){ hasCalls=true; } - bool getHasCalls()const{ return hasCalls; } - void setHasNonExceptionCalls(){ hasNonExceptionCalls=true; } - bool getHasNonExceptionCalls()const{ return hasNonExceptionCalls; } - //----------------------------------------------------------------------------------------------- - const CallingConvention * getCallingConvention(CompilationInterface::RuntimeHelperId helperId)const; + /** Creates an EmptyPseudoInst instruction to fill BB, which shoud not be cosidered as an empty one. + */ + Inst* IRManager::newEmptyPseudoInst(); - const CallingConvention * getCallingConvention(MethodDesc * methodDesc)const; + /** Creates an MethodEntryPseudoInst pseudo instruction representing the inlined method entry/end markers. + */ + MethodMarkerPseudoInst* newMethodEntryPseudoInst(MethodDesc* mDesc); + MethodMarkerPseudoInst* newMethodEndPseudoInst(MethodDesc* mDesc); + //--------------------------------------------------------------------------------------- + void setHasCalls(){ hasCalls=true; } + bool getHasCalls()const{ return hasCalls; } + void setHasNonExceptionCalls(){ hasNonExceptionCalls=true; } + bool getHasNonExceptionCalls()const{ return hasNonExceptionCalls; } + //----------------------------------------------------------------------------------------------- + const CallingConvention * getCallingConvention(CompilationInterface::RuntimeHelperId helperId)const; - const CallingConvention * getDefaultManagedCallingConvention() const { return &CallingConvention_DRL; } + const CallingConvention * getCallingConvention(MethodDesc * methodDesc)const; - EntryPointPseudoInst * getEntryPointInst()const { return entryPointInst; } + const CallingConvention * getDefaultManagedCallingConvention() const { return &CallingConvention_DRL; } - const CallingConvention * getCallingConvention()const { assert(NULL!=entryPointInst); return getEntryPointInst()->getCallingConventionClient().getCallingConvention(); } + EntryPointPseudoInst * getEntryPointInst()const { return entryPointInst; } - Opnd * defArg(Type * type, uint32 position); + const CallingConvention * getCallingConvention()const { assert(NULL!=entryPointInst); return getEntryPointInst()->getCallingConventionClient().getCallingConvention(); } - void applyCallingConventions(); + Opnd * defArg(Type * type, uint32 position); - uint32 getMaxInstId() { return instId; } + void applyCallingConventions(); - //----------------------------------------------------------------------------------------------- - /** Updates operands resolving their RuntimeInfo */ + uint32 getMaxInstId() { return instId; } + + //----------------------------------------------------------------------------------------------- + /** Updates operands resolving their RuntimeInfo */ void resolveRuntimeInfo(); void resolveRuntimeInfo(Opnd* opnd) const; - /** AOT support: serializes inst into stream */ - Byte * serialize(Byte * stream, Inst * inst); - /** AOT support: deserializes inst from stream */ - Byte * deserialize(Byte * stream, Inst *& inst); + /** AOT support: serializes inst into stream */ + Byte * serialize(Byte * stream, Inst * inst); + /** AOT support: deserializes inst from stream */ + Byte * deserialize(Byte * stream, Inst *& inst); - //----------------------------------------------------------------------------------------------- - /** calculate liveness information */ - void calculateLivenessInfo(); + //----------------------------------------------------------------------------------------------- + /** calculate liveness information */ + void calculateLivenessInfo(); - void fixLivenessInfo( uint32 * map = NULL ); + void fixLivenessInfo( uint32 * map = NULL ); bool hasLivenessInfo()const - { - if (!_hasLivenessInfo) - return false; - LiveSet * ls = getPrologNode()->getLiveAtEntry(); - return ls != NULL && ls->getSetSize()==getOpndCount(); - } + { + if (!_hasLivenessInfo) + return false; + BitSet * ls = ((CGNode*)fg->getEntryNode())->getLiveAtEntry(); + return ls != NULL && ls->getSetSize()==getOpndCount(); + } /** calculate liveness information if needed*/ void updateLivenessInfo() { if (!hasLivenessInfo()) calculateLivenessInfo();} - void invalidateLivenessInfo(){ _hasLivenessInfo=false; } + void invalidateLivenessInfo(){ _hasLivenessInfo=false; } + + void updateLoopInfo() const {fg->getLoopTree()->rebuild(false);} + void invalidateLoopInfo() {/*do nothing*/} - /** returns the live set for node entry */ - LiveSet * getLiveAtEntry(const Node * node)const - { return node->getLiveAtEntry(); } - /** initializes ls with liveness info at node exit */ - void getLiveAtExit(const Node * node, LiveSet & ls)const; - /** use this function to update ls in a single bakrward pass through a node when liveness info is calculated */ - void updateLiveness(const Inst * inst, LiveSet & ls)const; + /** returns the live set for node entry */ + BitSet * getLiveAtEntry(const Node * node)const + { return ((const CGNode*)node)->getLiveAtEntry(); } + /** initializes ls with liveness info at node exit */ + void getLiveAtExit(const Node * node, BitSet & ls)const; + /** use this function to update ls in a single bakrward pass through a node when liveness info is calculated */ + void updateLiveness(const Inst * inst, BitSet & ls)const; - /** returns the reg usage information for node entry - as uint32containing bit mask for used registers */ - uint32 getRegUsageAtEntry(const Node * node, OpndKind regKind)const - { return getRegUsageFromLiveSet(getLiveAtEntry(node), regKind); } + /** returns the reg usage information for node entry + as uint32containing bit mask for used registers */ + uint32 getRegUsageAtEntry(const Node * node, OpndKind regKind)const + { return getRegUsageFromLiveSet(getLiveAtEntry(node), regKind); } - /** returns the reg usage information for node exit - as uint32 containing bit mask for used registers */ - void getRegUsageAtExit(const Node * node, OpndKind regKind, uint32 & mask)const; + /** returns the reg usage information for node exit + as uint32 containing bit mask for used registers */ + void getRegUsageAtExit(const Node * node, OpndKind regKind, uint32 & mask)const; /** use this function to update reg usage in a single postorder pass when liveness info is calculated */ - void updateRegUsage(const Inst * inst, OpndKind regKind, uint32 & mask)const; + void updateRegUsage(const Inst * inst, OpndKind regKind, uint32 & mask)const; - uint32 getRegUsageFromLiveSet(LiveSet * ls, OpndKind regKind)const; + uint32 getRegUsageFromLiveSet(BitSet * ls, OpndKind regKind)const; - /** returns Constraint containing bit mask for all registers used in the method */ - uint32 getTotalRegUsage(OpndKind regKind)const; + /** returns Constraint containing bit mask for all registers used in the method */ + uint32 getTotalRegUsage(OpndKind regKind)const; - void calculateTotalRegUsage(OpndKind regKind); + void calculateTotalRegUsage(OpndKind regKind); - static bool isGCSafePoint(const Inst* inst) {return inst->getMnemonic() == Mnemonic_CALL;} + static bool isGCSafePoint(const Inst* inst) {return inst->getMnemonic() == Mnemonic_CALL;} - static bool isThreadInterruptablePoint(const Inst* inst) { + static bool isThreadInterruptablePoint(const Inst* inst) { if ( inst->getMnemonic() == Mnemonic_CALL ) { Opnd::RuntimeInfo* ri = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); return ri ? ri->getKind() == Opnd::RuntimeInfo::Kind_HelperAddress : false; @@ -313,154 +342,183 @@ public: } } - //----------------------------------------------------------------------------------------------- - bool isOnlyPrologSuccessor(BasicBlock * bb) ; - - /** expands SystemExceptionCheckPseudoInst */ - void expandSystemExceptions(uint32 reservedForFlags); - - /** changes all Extended insts to Native form by calling makeInstNative */ - void translateToNativeForm(); - - void eliminateSameOpndMoves(); - - //----------------------------------------------------------------------------------------------- - /**this function performs the following things in a single postorder pass: - 1) indexes instruction in topological (reverse post-order) - 2) (re-)calculates operand statistics (ref counts) - 3) If reindex is true it sets new sequential Opnd::id - for all operands with refcount>0(used for packOpnds)*/ - uint32 calculateOpndStatistics(bool reindex=false); - - /** this function performs the following: - 1) calls calculateOpndStatistics(). - 2) removes operands with zero ref counts from the internal - array of all operands accessed via IRManager::getOpnd(uint32). - */ - void packOpnds(); - - /** returns the number of operands in the internal - array of all operands accessed via IRManager::getOpnd(uint32). - This number is affected by packOpnds which removes from the array all operands which - are no longer in the LIR. - */ - uint32 getOpndCount()const - { return opnds.size(); } - - /** returns an operand from the internal array of all operands by its ID. */ - Opnd * getOpnd(uint32 id)const - { - assert(idtag]; } - - /** converts Type::Tag into pointer to Type instance */ - Type * getTypeFromTag(Type::Tag)const; - - Type * getManagedPtrType(Type * sourceType); - - /** returns the size of location occupied by an operand of type type */ - static OpndSize getTypeSize(Type::Tag tag); - static OpndSize getTypeSize(Type * type){ return getTypeSize(type->tag); } + //----------------------------------------------------------------------------------------------- + bool isOnlyPrologSuccessor(Node * bb) ; + + /** returns true if the specified node is an epilog basic block + A node is considered epilog if it is a basic block and is connected to the exit node of the CFG + */ + bool isEpilog(const Node * node) const + { return node->isBlockNode() && node->isConnectedTo(true, fg->getExitNode());} + + + /** fix edge profile + if CFG is not annotated with edge profile assigns heuristics based (loops-only) + profile to CFG. + CFG has valid profile after this method call. + */ + void fixEdgeProfile(); + + /** returns true if the CFG has been laid out + (layout successor attributes of nodes are valid) */ + bool isLaidOut() const {return laidOut;} + void setLaidOut(bool v) {laidOut = true;} + + /** returns the pointer to the native code for this basic block */ + void * getCodeStartAddr() const {return codeStartAddr;} + void setCodeStartAddr(void* addr) {codeStartAddr = addr;} + + ControlFlowGraph* createSubCFG(bool withReturn, bool withUnwind); + + /** expands SystemExceptionCheckPseudoInst */ + void expandSystemExceptions(uint32 reservedForFlags); + + /** changes all Extended insts to Native form by calling makeInstNative */ + void translateToNativeForm(); + + void eliminateSameOpndMoves(); + + //----------------------------------------------------------------------------------------------- + /**this function performs the following things in a single postorder pass: + 1) indexes instruction in topological (reverse post-order) + 2) (re-)calculates operand statistics (ref counts) + 3) If reindex is true it sets new sequential Opnd::id + for all operands with refcount>0(used for packOpnds)*/ + uint32 calculateOpndStatistics(bool reindex=false); + + /** this function performs the following: + 1) calls calculateOpndStatistics(). + 2) removes operands with zero ref counts from the internal + array of all operands accessed via IRManager::getOpnd(uint32). + */ + void packOpnds(); + + /** returns the number of operands in the internal + array of all operands accessed via IRManager::getOpnd(uint32). + This number is affected by packOpnds which removes from the array all operands which + are no longer in the LIR. + */ + uint32 getOpndCount()const + { return opnds.size(); } + + /** returns an operand from the internal array of all operands by its ID. */ + Opnd * getOpnd(uint32 id)const + { + assert(idtag]; } + + /** converts Type::Tag into pointer to Type instance */ + Type * getTypeFromTag(Type::Tag)const; + + Type * getManagedPtrType(Type * sourceType); + + /** returns the size of location occupied by an operand of type type */ + static OpndSize getTypeSize(Type::Tag tag); + static OpndSize getTypeSize(Type * type){ return getTypeSize(type->tag); } /** checks loop info, returns FALSE if loop info is not valid, should be used in debug assert checks*/ bool ensureLivenessInfoIsValid(); - /** returns true if regs of kind regKind cannot be assigned anymore to operands - This means reg allocations is done and the new assignment can conflict with existing ones - */ - bool isRegisterSetLocked(OpndKind regKind){ return true; } - void lockRegisterSet(OpndKind regKind){ } - - void setVerificationLevel(uint32 v){ verificationLevel=v; } - uint32 getVerificationLevel()const{ return verificationLevel; } + /** returns true if regs of kind regKind cannot be assigned anymore to operands + This means reg allocations is done and the new assignment can conflict with existing ones + */ + bool isRegisterSetLocked(OpndKind regKind){ return true; } + void lockRegisterSet(OpndKind regKind){ } - - static void selfUnitTest(TypeManager & tm, MethodDesc & md, CompilationInterface & compInterface); + void setVerificationLevel(uint32 v){ verificationLevel=v; } + uint32 getVerificationLevel()const{ return verificationLevel; } protected: - void addOpnd(Opnd * opnd); + //control flow graph factory methods + virtual Node* createNode(MemoryManager& mm, Node::Kind kind); + virtual Edge* createEdge(MemoryManager& mm, Node::Kind srcKind, Node::Kind dstKind); + + void addOpnd(Opnd * opnd); - void addAliasRelation(AliasRelation * relations, Opnd * opndOuter, Opnd * opndInner, uint32 offset); + void addAliasRelation(AliasRelation * relations, Opnd * opndOuter, Opnd * opndInner, uint32 offset); - Inst * newCopySequence(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 regUsageMask=(uint32)~0); - Inst * newPushPopSequence(Mnemonic mn, Opnd * opnd, uint32 regUsageMask=(uint32)~0); - Inst * newMemMovSequence(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 regUsageMask, bool checkSource=false); + Inst * newCopySequence(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 regUsageMask=(uint32)~0, uint32 flagsRegUsageMask=(uint32)~0); + Inst * newPushPopSequence(Mnemonic mn, Opnd * opnd, uint32 regUsageMask=(uint32)~0); + Inst * newMemMovSequence(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 regUsageMask, bool checkSource=false); - void initInitialConstraints(); - Constraint createInitialConstraint(Type::Tag t)const; + void initInitialConstraints(); + Constraint createInitialConstraint(Type::Tag t)const; - //------------------------------------------------------------------------------------- - TypeManager & typeManager; + //------------------------------------------------------------------------------------- + MemoryManager& memoryManager; + ControlFlowGraph* fg; + TypeManager & typeManager; - MethodDesc & methodDesc; - CompilationInterface & compilationInterface; + MethodDesc & methodDesc; + CompilationInterface & compilationInterface; - uint32 opndId; - uint32 instId; + uint32 opndId; + uint32 instId; - OpndVector opnds; + OpndVector opnds; - uint32 gpTotalRegUsage; + uint32 gpTotalRegUsage; - EntryPointPseudoInst * entryPointInst; + EntryPointPseudoInst * entryPointInst; - Opnd * regOpnds[IRMaxRegNames]; + Opnd * regOpnds[IRMaxRegNames]; - bool _hasLivenessInfo; + bool _hasLivenessInfo; - InternalHelperInfos internalHelperInfos; + InternalHelperInfos internalHelperInfos; - ConstCharStringToVoidPtrMap infoMap; + ConstCharStringToVoidPtrMap infoMap; - uint32 verificationLevel; + uint32 verificationLevel; - bool hasCalls; - bool hasNonExceptionCalls; + bool hasCalls; + bool hasNonExceptionCalls; - Constraint initialConstraints[Type::NumTypeTags]; + Constraint initialConstraints[Type::NumTypeTags]; + bool laidOut; + void * codeStartAddr; + CGFlags flags; }; -#define VERIFY_OUT(s) { if (Log::cat_cg()->isFailEnabled()) Log::out() << s; ::std::cerr << s; } +#define VERIFY_OUT(s) { if (Log::isEnabled()) Log::out() << s; std::cerr << s; } /** MapHandler is auxilary class to eliminate direct usage of map handlers between HLO and codegenerator */ @@ -503,177 +561,83 @@ private: //======================================================================================== -// class IRTransformer +// class Ia32::SessionAction //======================================================================================== /** - class IRTransformer is the base class for all IR transformations external to IRManager: - optimizations, etc. + class Ia32::SessionAction is the base class for all IR transformations external to IRManager: + optimizations, etc. */ -class IRTransformer +class SessionAction : public ::Jitrino::SessionAction { - //============================================================================= public: - typedef IRTransformer * (*CreateFunction)(IRManager& irm, const char * params); - const static uint32 MaxIRTransformers=100; - - const static uint32 MaxTagLength=31; - struct IRTransformerRecord - { - const char * tag; - CreateFunction createFunction; + enum SideEffect + { + SideEffect_InvalidatesLivenessInfo=0x1, + SideEffect_InvalidatesLoopInfo=0x2, + }; - XTimer xtimer; + enum NeedInfo + { + NeedInfo_LivenessInfo=0x1, + NeedInfo_LoopInfo=0x2, + }; - IRTransformerRecord(const char * _tag=NULL, CreateFunction _createFunction=NULL) - :tag(_tag), createFunction(_createFunction) - { - } - }; - static uint32 registerIRTransformer(const char * tag, CreateFunction pfn); + SessionAction () :irManager(0) {} - static IRTransformerRecord * findIRTransformer(const char * tag); + void run (); - static IRTransformer * newIRTransformer(const char * tag, IRManager& irm, const char * params); - -private: + IRManager& getIRManager() const {return *getCompilationContext()->getLIRManager();} - static IRTransformerRecord table[]; - static uint32 tableLength; + const char * getTagName() const {return getName();} - //============================================================================= -public: - enum SideEffect - { - SideEffect_InvalidatesLivenessInfo=0x1, - SideEffect_InvalidatesLoopInfo=0x2, - }; - - enum NeedInfo - { - NeedInfo_LivenessInfo=0x1, - NeedInfo_LoopInfo=0x2, - }; - - IRTransformer(IRManager & irm, const char * params=0) - : irManager(irm), parameters(params), stageId(0), record(NULL){} - virtual ~IRTransformer(){}; - virtual void destroy(){}; - - void run(); - - IRManager& getIRManager()const{ return irManager; } - - const char * getParameters()const {return parameters; } - - /** Implementors override getName() to return the full - printable name of the pass. - - Required */ - virtual const char * getName()=0; - - /** Implementors override getTagName() to return the short tag - name of the pass (used in log file names). - - Required */ - virtual const char * getTagName()=0; - protected: - /** Implementors override runImpl() to perform all operations of the pass - - Required */ - virtual void runImpl()=0; - /** Implementors override getNeedInfo() to indicate what info - must be up to date for the pass. + /** Implementors override run() to perform all operations of the pass - The returned value is |-ed from the NeedInfo enum - - Optional, defaults to all possible info */ - virtual uint32 getNeedInfo()const; + Required */ + virtual void runImpl () = 0; + + + /** Implementors override getNeedInfo() to indicate what info + must be up to date for the pass. - /** Implementors override getSideEffects() to indicate the side effect - of the pass (currently in terms of common info like liveness, loop, etc.) - - The returned value is |-ed from the SideEffect enum + The returned value is |-ed from the NeedInfo enum - Optional, defaults to all possible side effects */ - virtual uint32 getSideEffects()const; + Optional, defaults to all possible info */ + virtual uint32 getNeedInfo()const; - virtual bool verify(bool force=false); + /** Implementors override getSideEffects() to indicate the side effect + of the pass (currently in terms of common info like liveness, loop, etc.) + + The returned value is |-ed from the SideEffect enum - virtual void debugOutput(const char * subKind); - - virtual void dumpIR(const char * subKind1, const char * subKind2=0); - virtual void printDot(const char * subKind1, const char * subKind2=0); + Optional, defaults to all possible side effects */ + virtual uint32 getSideEffects()const; - void printIRDumpBegin(const char * subKind); - void printIRDumpEnd(const char * subKind); + virtual bool verify(bool force=false); - virtual bool isIRDumpEnabled(){ return true; } -protected: + virtual void debugOutput(const char * subKind); + + virtual void dumpIR(const char * subKind1, const char * subKind2=0); + virtual void printDot(const char * subKind1, const char * subKind2=0); - IRManager & irManager; - const char * parameters; + virtual bool isIRDumpEnabled(){ return true; } - uint32 stageId; + int getVerificationLevel() const + { + return getIntArg("verify", irManager->getVerificationLevel()); + } -private: - IRTransformerRecord * record; -friend struct IRTimers; + IRManager * irManager; + uint32 stageId; }; -//======================================================================================== -#define IRTRANSFORMER_CONSTRUCTOR(cls) \ - cls(IRManager& irm, const char * params=0): IRTransformer(irm, params){} \ - - - -#define BEGIN_DECLARE_IRTRANSFORMER(cls, tag, name) \ -class cls: public IRTransformer \ -{ \ -public: \ - static const char * getMyTag(){ return tag; } \ - static cls * create(IRManager & irm, const char * params){ return new cls(irm, params); } \ - void destroy(){ delete this; } \ - const char * getName(){ return name; } \ - const char * getTagName(){ return getMyTag(); } \ - - - - -#ifdef IRTRANSFORMER_REGISTRATION_ON - -IRTransformer::IRTransformerRecord IRTransformer::table[IRTransformer::MaxIRTransformers]={}; -uint32 IRTransformer::tableLength=0; - -#define REGISTER_IRTRANSFORMER(cls) \ -uint32 _register_##cls = IRTransformer::registerIRTransformer(cls::getMyTag(), (IRTransformer::CreateFunction)&cls::create); - -#else - -#define REGISTER_IRTRANSFORMER(cls) - -#endif - -#define END_DECLARE_IRTRANSFORMER(cls) \ -}; \ -REGISTER_IRTRANSFORMER(cls) - - - -#define DECLARE_IRTRANSFORMER(cls, tag, name) \ - BEGIN_DECLARE_IRTRANSFORMER(cls, tag, name) \ - IRTRANSFORMER_CONSTRUCTOR(cls) \ - void runImpl(); \ - END_DECLARE_IRTRANSFORMER(cls) - - }}; // namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp index 1f64e5d..258e218 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32Inst.cpp @@ -19,14 +19,15 @@ */ #include "Ia32Inst.h" -#include "Ia32CFG.h" #include "Ia32IRManager.h" +#include "InlineInfo.h" +#include "Ia32CFG.h" + namespace Jitrino { namespace Ia32{ - //================================================================================================= // class Opnd //================================================================================================= @@ -34,93 +35,93 @@ namespace Ia32{ //_________________________________________________________________________________________________ void Opnd::assignRegName(RegName r) { - r=constraints[ConstraintKind_Calculated].getAliasRegName(r); - assert(r!=RegName_Null); - memOpndKind=MemOpndKind_Null; - regName=r; - constraints[ConstraintKind_Location]=Constraint(r); - checkConstraints(); + r=constraints[ConstraintKind_Calculated].getAliasRegName(r); + assert(r!=RegName_Null); + memOpndKind=MemOpndKind_Null; + regName=r; + constraints[ConstraintKind_Location]=Constraint(r); + checkConstraints(); } //_________________________________________________________________________________________________ void Opnd::assignImmValue(int64 v) { - memOpndKind=MemOpndKind_Null; - if (constraints[ConstraintKind_Location].getKind() != OpndKind_Imm) - runtimeInfo=NULL; - immValue=v; - constraints[ConstraintKind_Location]=Constraint(OpndKind_Imm, constraints[ConstraintKind_Initial].getSize()); - checkConstraints(); + memOpndKind=MemOpndKind_Null; + if (constraints[ConstraintKind_Location].getKind() != OpndKind_Imm) + runtimeInfo=NULL; + immValue=v; + constraints[ConstraintKind_Location]=Constraint(OpndKind_Imm, constraints[ConstraintKind_Initial].getSize()); + checkConstraints(); } //_________________________________________________________________________________________________ void Opnd::assignMemLocation(MemOpndKind k, Opnd * _base, Opnd * _index, Opnd * _scale, Opnd * _displacement) { - assert(_base||_index||_displacement); - assert(!_scale||_index); + assert(_base||_index||_displacement); + assert(!_scale||_index); - constraints[ConstraintKind_Location]=Constraint(OpndKind_Mem, constraints[ConstraintKind_Initial].getSize()); - memOpndKind=k; + constraints[ConstraintKind_Location]=Constraint(OpndKind_Mem, constraints[ConstraintKind_Initial].getSize()); + memOpndKind=k; - checkConstraints(); + checkConstraints(); - if (_base) - setMemOpndSubOpnd(MemOpndSubOpndKind_Base, _base); - else - memOpndSubOpnds[MemOpndSubOpndKind_Base]=NULL; - if (_index) - setMemOpndSubOpnd(MemOpndSubOpndKind_Index, _index); - else - memOpndSubOpnds[MemOpndSubOpndKind_Index]=NULL; - if (_scale) - setMemOpndSubOpnd(MemOpndSubOpndKind_Scale, _scale); - else - memOpndSubOpnds[MemOpndSubOpndKind_Scale]=NULL; - if (_displacement) - setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, _displacement); - else - memOpndSubOpnds[MemOpndSubOpndKind_Displacement]=NULL; + if (_base) + setMemOpndSubOpnd(MemOpndSubOpndKind_Base, _base); + else + memOpndSubOpnds[MemOpndSubOpndKind_Base]=NULL; + if (_index) + setMemOpndSubOpnd(MemOpndSubOpndKind_Index, _index); + else + memOpndSubOpnds[MemOpndSubOpndKind_Index]=NULL; + if (_scale) + setMemOpndSubOpnd(MemOpndSubOpndKind_Scale, _scale); + else + memOpndSubOpnds[MemOpndSubOpndKind_Scale]=NULL; + if (_displacement) + setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, _displacement); + else + memOpndSubOpnds[MemOpndSubOpndKind_Displacement]=NULL; } //_________________________________________________________________________________________________ void Opnd::setMemOpndSubOpnd(MemOpndSubOpndKind so, Opnd * opnd) { - assert(opnd); - assert(!(opnd->getConstraint(ConstraintKind_Initial)&getMemOpndSubOpndConstraint(so)).isNull()); // first-level filter - assert(Constraint(OpndKind_Any, getMemOpndSubOpndConstraint(so).getSize()).contains(opnd->getConstraint(ConstraintKind_Location))); - assert(memOpndKind!=MemOpndKind_Null); - memOpndSubOpnds[so]=opnd; + assert(opnd); + assert((so != MemOpndSubOpndKind_Displacement) || (abs((int32)opnd->getImmValue()) <= 0xffffffff)); + assert((so != MemOpndSubOpndKind_Scale) || ((uint64)opnd->getImmValue() <= 8)); + assert(memOpndKind!=MemOpndKind_Null); + memOpndSubOpnds[so]=opnd; } //_________________________________________________________________________________________________ bool Opnd::replaceMemOpndSubOpnd(Opnd * opndOld, Opnd * opndNew) { - bool replaced = false; - if (memOpndKind != MemOpndKind_Null){ - assert(isPlacedIn(OpndKind_Mem)); - for (uint32 i=0; iid]!=NULL){ - setMemOpndSubOpnd((MemOpndSubOpndKind)i, opndMap[memOpndSubOpnds[i]->id]); - replaced = true; - } - } - return replaced; + bool replaced = false; + if (memOpndKind != MemOpndKind_Null){ + assert(isPlacedIn(OpndKind_Mem)); + for (uint32 i=0; iid]!=NULL){ + setMemOpndSubOpnd((MemOpndSubOpndKind)i, opndMap[memOpndSubOpnds[i]->id]); + replaced = true; + } + } + return replaced; } @@ -128,439 +129,453 @@ #ifdef _DEBUG //_________________________________________________________________________________________________ void Opnd::checkConstraints() { - assert(getConstraint(ConstraintKind_Size).contains(getConstraint(ConstraintKind_Initial))); - assert(constraints[ConstraintKind_Initial].contains(constraints[ConstraintKind_Calculated])); - assert(constraints[ConstraintKind_Calculated].contains(constraints[ConstraintKind_Location])); + assert(constraints[ConstraintKind_Initial].contains(constraints[ConstraintKind_Calculated])); + assert(constraints[ConstraintKind_Calculated].contains(constraints[ConstraintKind_Location])); } #endif //_________________________________________________________________________________________________ void Opnd::setCalculatedConstraint(Constraint c) { - constraints[ConstraintKind_Calculated]=c & constraints[ConstraintKind_Initial]; - checkConstraints(); + constraints[ConstraintKind_Calculated]=c & constraints[ConstraintKind_Initial]; + checkConstraints(); + assert(!constraints[ConstraintKind_Calculated].isNull()); } //_________________________________________________________________________________________________ void Opnd::addRefCount(uint32& index, uint32 blockExecCount) { - if (blockExecCount==0) - blockExecCount=1; - refCount++; - if (id==EmptyUint32) - id=index++; - if (memOpndKind != MemOpndKind_Null){ - for (uint32 i=0; iaddRefCount(index, blockExecCount); - } - } + if (blockExecCount==0) + blockExecCount=1; + refCount++; + if (id==EmptyUint32) + id=index++; + if (memOpndKind != MemOpndKind_Null){ + for (uint32 i=0; iaddRefCount(index, blockExecCount); + } + } } //_________________________________________________________________________________________________ void Opnd::setDefiningInst(Inst * inst) { - if (defScope==DefScope_Temporary||defScope==DefScope_Null){ - if (definingInst==NULL){ - defScope=DefScope_Temporary; - definingInst=inst; - }else{ - if (inst->getBasicBlock()==definingInst->getBasicBlock()) - defScope=DefScope_SemiTemporary; - else{ - defScope=DefScope_Variable; - definingInst=NULL; - } - } - }else if (defScope==DefScope_SemiTemporary){ - assert(definingInst!=NULL); - if (inst->getBasicBlock()!=definingInst->getBasicBlock()){ - defScope=DefScope_Variable; - definingInst=NULL; - } - } + if (defScope==DefScope_Temporary||defScope==DefScope_Null){ + if (definingInst==NULL){ + defScope=DefScope_Temporary; + definingInst=inst; + }else{ + if (inst->getNode()==definingInst->getNode()) + defScope=DefScope_SemiTemporary; + else{ + defScope=DefScope_Variable; + definingInst=NULL; + } + } + }else if (defScope==DefScope_SemiTemporary){ + assert(definingInst!=NULL); + if (inst->getNode()!=definingInst->getNode()){ + defScope=DefScope_Variable; + definingInst=NULL; + } + } } //================================================================================================= // class Inst //================================================================================================= +void* Inst::operator new(size_t sz, MemoryManager& mm, uint32 opndCount) +{ + Inst * p = (Inst*)mm.alloc(sz + Inst::getOpndChunkSize(opndCount)); + p->allocatedOpndCount = opndCount; p->opnds = (Opnd**)((uint8*)p + sz); + return p; +} //_________________________________________________________________________________________________ void Inst::insertOpnd(uint32 idx, Opnd * opnd, uint32 roles) { - assert(opndCount < allocatedOpndCount); - - if (idx < defOpndCount) - roles |= OpndRole_Def; + assert(opndCount < allocatedOpndCount); + + if (idx < defOpndCount) + roles |= OpndRole_Def; - if (roles & OpndRole_Def){ - if (idx > defOpndCount) - idx = defOpndCount; - defOpndCount++; - } - - if (idx > opndCount) - idx = opndCount; + if (roles & OpndRole_Def){ + if (idx > defOpndCount) + idx = defOpndCount; + defOpndCount++; + } + + if (idx > opndCount) + idx = opndCount; - uint32 * opndRoles = getOpndRoles(); - Constraint * opndConstraints = getConstraints(); + uint32 * opndRoles = getOpndRoles(); + Constraint * opndConstraints = getConstraints(); - for (uint32 i = opndCount; i > idx; i--){ - opnds[i] = opnds[i - 1]; - opndRoles[i] = opndRoles[i - 1]; - opndConstraints[i] = opndConstraints[i - 1]; - } + for (uint32 i = opndCount; i > idx; i--){ + opnds[i] = opnds[i - 1]; + opndRoles[i] = opndRoles[i - 1]; + opndConstraints[i] = opndConstraints[i - 1]; + } - opnds[idx] = opnd; - opndRoles[idx] = roles; - - opndCount++; + opnds[idx] = opnd; + opndRoles[idx] = roles; + + opndCount++; } //_________________________________________________________________________________________________ uint32 Inst::countOpnds(uint32 roles)const { - uint32 count=0; - if ( (roles & OpndRole_InstLevel) != 0 ){ - const uint32 * opndRoles = getOpndRoles(); - for (uint32 i = 0, n = opndCount; i < n; i++){ - uint32 r = opndRoles [i]; - if ( (r & roles & OpndRole_FromEncoder) != 0 && (r & roles & OpndRole_ForIterator) != 0 ) - count++; - } - } - if ( (roles & OpndRole_OpndLevel) != 0 && (roles & OpndRole_Use) != 0 ){ - for (uint32 i = 0, n = opndCount; i < n; i++){ - const Opnd * opnd = opnds[i]; - if ( opnd->memOpndKind != MemOpndKind_Null ){ - const Opnd * const * subOpnds = opnd->getMemOpndSubOpnds(); - for (uint32 j = 0; j < MemOpndSubOpndKind_Count; j++){ - const Opnd * subOpnd = subOpnds[j]; - if (subOpnd != NULL) - count++; - } - } - } - } - return count; -} - -//_________________________________________________________________________________________________ -Constraint Inst::getConstraint(ConstraintKind ck, uint32 idx, OpndSize size)const + uint32 count=0; + if ( (roles & OpndRole_InstLevel) != 0 ){ + const uint32 * opndRoles = getOpndRoles(); + for (uint32 i = 0, n = opndCount; i < n; i++){ + uint32 r = opndRoles [i]; + if ( (r & roles & OpndRole_FromEncoder) != 0 && (r & roles & OpndRole_ForIterator) != 0 ) + count++; + } + } + if ( (roles & OpndRole_OpndLevel) != 0 && (roles & OpndRole_Use) != 0 ){ + for (uint32 i = 0, n = opndCount; i < n; i++){ + const Opnd * opnd = opnds[i]; + if ( opnd->memOpndKind != MemOpndKind_Null ){ + const Opnd * const * subOpnds = opnd->getMemOpndSubOpnds(); + for (uint32 j = 0; j < MemOpndSubOpndKind_Count; j++){ + const Opnd * subOpnd = subOpnds[j]; + if (subOpnd != NULL) + count++; + } + } + } + } + return count; +} + +//_________________________________________________________________________________________________ +Constraint Inst::getConstraint(uint32 idx, uint32 memOpndMask, OpndSize size) { - Constraint c(OpndKind_Any); - if (idxextendedToNativeMap[idx]; - assert(idxopcodeDescriptionCount; iopcodeDescriptions + i, fi)) - c.unionWith(opcodeGroupDescription->opcodeDescriptions[i].opndConstraints[idx]); - assert(!c.isNull()); - }else{ - if (form==Form_Extended) - idx=opcodeGroupDescription->extendedToNativeMap[idx]; - assert(idxweakOpndConstraints[idx]; - else - c=opcodeGroupDescription->strongOpndConstraints[idx]; - } - } - }else{ - uint32 diffIndex = idx - opndCount; - Opnd * instOpnd = *(Opnd * const *)(((Byte*)opnds) + (diffIndex & ~3)); - c = instOpnd->getMemOpndSubOpndConstraint((MemOpndSubOpndKind)(diffIndex & 3)); - } - return size==OpndSize_Null?c:c.getAliasConstraint(size); + Constraint c(OpndKind_Any); + if (idx < opndCount){ + const uint32 * opndRoles = getOpndRoles(); + const Constraint * constraints = getConstraints(); + c = constraints[idx]; + if ((opndRoles[idx] & OpndRole_Explicit) && (properties & Inst::Properties_MemoryOpndConditional)){ + bool removeMemory = false; + if (memOpndMask == 0xFFFFFFFF){// Strong constraint requested + removeMemory = true; + } else if (memOpndMask != 0) { + for (unsigned j = 0; j < opndCount; j++) { + if (j != idx && ((1 << j) & memOpndMask) && (opndRoles[j] & OpndRole_Explicit)) { + if (getOpnd(j)->getConstraint(Opnd::ConstraintKind_Location).getKind() == OpndKind_Mem){ + removeMemory = true; + break; + } + } + } + } + if (removeMemory) + c = Constraint((OpndKind)(c.getKind() &~ OpndKind_Mem), c.getSize(), c.getMask()); + } + }else{ + c = opnds[(idx - opndCount) / 4]->getMemOpndSubOpndConstraint((MemOpndSubOpndKind)((idx - opndCount) & 3)); + } + return size==OpndSize_Null?c:c.getAliasConstraint(size); } //_________________________________________________________________________________________________ void Inst::setOpnd(uint32 index, Opnd * opnd) { - Opnd ** opnds = getOpnds(); - if (index < opndCount) - opnds[index] = opnd; - else{ - uint32 diffIndex = index - opndCount; - Opnd * instOpnd = *(Opnd * const *)(((Byte*)opnds) + (diffIndex & ~3)); - instOpnd->setMemOpndSubOpnd((MemOpndSubOpndKind)(diffIndex & 3), opnd); - } - verify(); + Opnd ** opnds = getOpnds(); + if (index < opndCount) { + Constraint cc = opnds[index]->getConstraint(Opnd::ConstraintKind_Initial); + opnds[index] = opnd; + if(!hasKind(Kind_PseudoInst) + && (getOpndRoles()[index] & OpndRole_Explicit) + && cc != opnd->getConstraint(Opnd::ConstraintKind_Initial) + && !Encoder::isOpndAllowed(opcodeGroup, getExplicitOpndIndexFromOpndRoles(getOpndRoles()[index]), opnd->getConstraint(Opnd::ConstraintKind_Initial), getForm()==Form_Extended, true) + ) { + + BasicBlock * bb = getBasicBlock(); + + //instruction must be inserted into a basic block to be modifiable. + //it caused by necessity of reference to irManager for implicit operands + //assigning (flags, for example) + assert(bb); + assignOpcodeGroup(&bb->getIRManager()); + assert(opcodeGroup); + } + + } else{ + opnds[(index - opndCount) / 4]->setMemOpndSubOpnd((MemOpndSubOpndKind)((index - opndCount) & 3), opnd); + } + verify(); } //_________________________________________________________________________________________________ bool Inst::replaceOpnd(Opnd * oldOpnd, Opnd * newOpnd, uint32 opndRoleMask) { - bool replaced = false; - assert(newOpnd != NULL); - for (uint32 i=0, n=getOpndCount(OpndRole_InstLevel|OpndRole_UseDef); ireplaceMemOpndSubOpnd(oldOpnd, newOpnd); - } - } - - return replaced; + bool replaced = false; + assert(newOpnd != NULL); + for (uint32 i=0, n=getOpndCount(); ireplaceMemOpndSubOpnd(oldOpnd, newOpnd); + } + } + + return replaced; } +bool Inst::getPureDefProperty() const { + if (getProperties() & Properties_PureDef) { + Opnd * use = NULL; + for (uint32 i=0, n=getOpndCount(); igetId()]; - if (newOpnd!=NULL){ - assert((opndRole&OpndRole_Changeable)!=0); - setOpnd(i, newOpnd); - opnd=newOpnd; - replaced = true; - } - if ((opndRoleMask&OpndRole_OpndLevel)!=0) - replaced |= opnd->replaceMemOpndSubOpnds(opndMap); - } - } - return replaced; + bool replaced = false; + for (uint32 i=0, n=getOpndCount(); igetId()]; + if (newOpnd!=NULL){ + assert((opndRole&OpndRole_Changeable)!=0); + setOpnd(i, newOpnd); + opnd=newOpnd; + replaced = true; + } + if ((opndRoleMask&OpndRole_OpndLevel)!=0) + replaced |= opnd->replaceMemOpndSubOpnds(opndMap); + } + } + return replaced; } //_________________________________________________________________________________________________ void Inst::swapOperands(uint32 idx0, uint32 idx1) { - Opnd * opnd0=getOpnd(idx0), * opnd1=getOpnd(idx1); - setOpnd(idx1, opnd0); - setOpnd(idx0, opnd1); - verify(); + Opnd * opnd0=getOpnd(idx0), * opnd1=getOpnd(idx1); + setOpnd(idx1, opnd0); + setOpnd(idx0, opnd1); + verify(); } //_________________________________________________________________________________________________ void Inst::changeInstCondition(ConditionMnemonic cc, IRManager * irManager) { - assert(getProperties()&Properties_Conditional); - Mnemonic baseMnemonic=getBaseConditionMnemonic(mnemonic); - assert(baseMnemonic!=Mnemonic_Null); - mnemonic=(Mnemonic)(baseMnemonic+cc); - assignOpcodeGroup(irManager); - assert(opcodeGroupDescription!=NULL); + assert(getProperties()&Properties_Conditional); + Mnemonic baseMnemonic=getBaseConditionMnemonic(mnemonic); + assert(baseMnemonic!=Mnemonic_Null); + mnemonic=(Mnemonic)(baseMnemonic+cc); + assignOpcodeGroup(irManager); + assert(opcodeGroup!=NULL); } //_________________________________________________________________________________________________ void Inst::reverse(IRManager * irManager) { - assert(canReverse()); - Mnemonic baseMnemonic=getBaseConditionMnemonic(mnemonic); - assert(baseMnemonic!=Mnemonic_Null); - changeInstCondition(reverseConditionMnemonic((ConditionMnemonic)(mnemonic-baseMnemonic)), irManager); + assert(canReverse()); + Mnemonic baseMnemonic=getBaseConditionMnemonic(mnemonic); + assert(baseMnemonic!=Mnemonic_Null); + changeInstCondition(reverseConditionMnemonic((ConditionMnemonic)(mnemonic-baseMnemonic)), irManager); } //_________________________________________________________________________________________________ -uint8* Inst::emit(uint8* stream)const +uint8* Inst::emit(uint8* stream) { - if (hasKind(Inst::Kind_PseudoInst)) - return stream; - assert(mnemonic!=Mnemonic_Null); - assert(form==Form_Native); - return Encoder::emit(stream, this); + uint8 * instEnd = stream; + if (!hasKind(Inst::Kind_PseudoInst)){ + assert(mnemonic!=Mnemonic_Null); + assert(form==Form_Native); + instEnd = Encoder::emit(stream, this); + } + setCodeSize(instEnd - stream); + return instEnd; } //_________________________________________________________________________________________________ void Inst::initFindInfo(Encoder::FindInfo& fi, Opnd::ConstraintKind opndConstraintKind)const { - Opnd * const * opnds = getOpnds(); - const uint32 * roles = getOpndRoles(); - uint32 count = 0, defCount = 0, defCountFromInst = defOpndCount; - for (uint32 i=0, n=opndCount; igetConstraint(opndConstraintKind); - if (i < defCountFromInst) - defCount++; - } - } - fi.defOpndCount = defCount; - fi.opndCount = count; - fi.opcodeGroupDescription = opcodeGroupDescription; - fi.mnemonic = mnemonic; - fi.isExtended = (Form)form == Form_Extended; + Opnd * const * opnds = getOpnds(); + const uint32 * roles = getOpndRoles(); + uint32 count = 0, defCount = 0, defCountFromInst = defOpndCount; + for (uint32 i=0, n=opndCount; igetConstraint(opndConstraintKind); + if (i < defCountFromInst) + defCount++; + } + } + fi.defOpndCount = defCount; + fi.opndCount = count; + fi.opcodeGroup= opcodeGroup; + fi.mnemonic = mnemonic; + fi.isExtended = (Form)form == Form_Extended; } //_________________________________________________________________________________________________ void Inst::fixOpndsForOpcodeGroup(IRManager * irManager) { - uint32 handledExplicitOpnds = 0, handledImplicitOpnds = 0; - - uint32 * roles = getOpndRoles(); - Constraint * constraints = getConstraints(); - - Form f = getForm(); - - for (uint32 i=0, n=opndCount; iopndRoles, idx); - if ( (r & OpndRole_Def) != 0 && defOpndCount<=i) - defOpndCount = i + 1; - }else{ - idx = opcodeGroupDescription->extendedToNativeMap[handledExplicitOpnds]; - r = i < defOpndCount ? OpndRole_Def : OpndRole_Use; - } - r |= Inst::OpndRole_Explicit | (handledExplicitOpnds << 16); - roles[i] = r; - constraints[i] = opcodeGroupDescription->weakOpndConstraints[idx]; - handledExplicitOpnds++; - }else if (roles[i] & Inst::OpndRole_Implicit){ - assert(handledImplicitOpnds < opcodeGroupDescription->implicitOpndRoles.count); - assert(opnds[i]->getRegName() == opcodeGroupDescription->implicitOpndRegNames[handledImplicitOpnds]); - handledImplicitOpnds++; - } - } - - for (uint32 i = handledImplicitOpnds; i < opcodeGroupDescription->implicitOpndRoles.count; i++){ - RegName iorn = opcodeGroupDescription->implicitOpndRegNames[i]; - Opnd * implicitOpnd = irManager->getRegOpnd(iorn); - uint32 implicitOpndRoles = - Encoder::getOpndRoles(opcodeGroupDescription->implicitOpndRoles, i) | Inst::OpndRole_Implicit; - if (implicitOpndRoles & OpndRole_Def){ - insertOpnd(defOpndCount, implicitOpnd, implicitOpndRoles); - constraints[defOpndCount - 1] = Constraint(iorn); - }else{ - insertOpnd(opndCount, implicitOpnd, implicitOpndRoles); - constraints[opndCount - 1] = Constraint(iorn); - } - } + uint32 handledExplicitOpnds = 0, handledImplicitOpnds = 0; + + uint32 * roles = getOpndRoles(); + Constraint * constraints = getConstraints(); + + Form f = getForm(); + + for (uint32 i=0, n=opndCount; iopndRoles, idx); + if ( (r & OpndRole_Def) != 0 && defOpndCount<=i) + defOpndCount = i + 1; + }else{ + idx = opcodeGroup->extendedToNativeMap[handledExplicitOpnds]; + r = i < defOpndCount ? OpndRole_Def : OpndRole_Use; + } + r |= Inst::OpndRole_Explicit | (handledExplicitOpnds << 16); + roles[i] = r; + constraints[i] = opcodeGroup->opndConstraints[idx]; + handledExplicitOpnds++; + }else if (roles[i] & Inst::OpndRole_Implicit){ + assert(handledImplicitOpnds < opcodeGroup->implicitOpndRoles.count); + assert(opnds[i]->getRegName() == opcodeGroup->implicitOpndRegNames[handledImplicitOpnds]); + handledImplicitOpnds++; + } + } + + for (uint32 i = handledImplicitOpnds; i < opcodeGroup->implicitOpndRoles.count; i++){ + RegName iorn = opcodeGroup->implicitOpndRegNames[i]; + Opnd * implicitOpnd = irManager->getRegOpnd(iorn); + uint32 implicitOpndRoles = + Encoder::getOpndRoles(opcodeGroup->implicitOpndRoles, i) | Inst::OpndRole_Implicit; + if (implicitOpndRoles & OpndRole_Def){ + insertOpnd(defOpndCount, implicitOpnd, implicitOpndRoles); + constraints[defOpndCount - 1] = Constraint(iorn); + }else{ + insertOpnd(opndCount, implicitOpnd, implicitOpndRoles); + constraints[opndCount - 1] = Constraint(iorn); + } + } } //_________________________________________________________________________________________________ void Inst::assignOpcodeGroup(IRManager * irManager) -{ - if (hasKind(Inst::Kind_PseudoInst)){ - assert(getForm() == Form_Extended); - opcodeGroupDescription = Encoder::getDummyOpcodeGroupDescription(); - uint32 * roles = getOpndRoles(); - uint32 i = 0; - for (uint32 n = defOpndCount; i < n; i++) - roles[i] = OpndRole_Auxilary | OpndRole_Def; - for (uint32 n = opndCount; i < n; i++) - roles[i] = OpndRole_Auxilary | OpndRole_Use; - }else{ - Encoder::FindInfo fi; - initFindInfo(fi, Opnd::ConstraintKind_Initial); - opcodeGroupDescription=Encoder::findOpcodeGroupDescription(fi); - assert(opcodeGroupDescription); // Checks that the requested mnemonic is implemented in Ia32EncodingTable - fixOpndsForOpcodeGroup(irManager); - } - properties = opcodeGroupDescription->properties; +{ + if (hasKind(Inst::Kind_PseudoInst)){ + assert(getForm() == Form_Extended); + opcodeGroup= (Encoder::OpcodeGroup *)Encoder::getDummyOpcodeGroup(); + uint32 * roles = getOpndRoles(); + uint32 i = 0; + for (uint32 n = defOpndCount; i < n; i++) + roles[i] = OpndRole_Auxilary | OpndRole_Def; + for (uint32 n = opndCount; i < n; i++) + roles[i] = OpndRole_Auxilary | OpndRole_Use; + }else{ + Encoder::FindInfo fi; + initFindInfo(fi, Opnd::ConstraintKind_Initial); + opcodeGroup=(Encoder::OpcodeGroup *)Encoder::findOpcodeGroup(fi); + assert(opcodeGroup); // Checks that the requested mnemonic is implemented in Ia32EncodingTable + fixOpndsForOpcodeGroup(irManager); + } + properties = opcodeGroup->properties; } //_________________________________________________________________________________________________ void Inst::makeNative(IRManager * irManager) { - if (getForm()==Form_Native || hasKind(Kind_PseudoInst) ) - return; - assert(opcodeGroupDescription); - - BasicBlock * bb = basicBlock; - - uint32 * opndRoles = getOpndRoles(); - Constraint * constraints = getConstraints(); - - int32 defs[IRMaxNativeOpnds]={ -1, -1, -1, -1 }; - for (uint32 i=0; i> 16; - uint32 nativeIdx = opcodeGroupDescription->extendedToNativeMap[extendedIdx]; - assert(nativeIdx < IRMaxNativeOpnds); - int32 defNativeIdx = defs[nativeIdx]; - if (defNativeIdx != -1){ - assert(i >= defOpndCount); - opndRoles[defNativeIdx] |= OpndRole_Use; - if (bb && opnds[defNativeIdx] != opnds[i]){ - Inst * moveInst=irManager->newCopySequence(Mnemonic_MOV, opnds[defNativeIdx], opnds[i]); - bb->prependInsts(moveInst, this); - } - opnds[i] = NULL; - }else - defs[nativeIdx] = i; - } - - uint32 packedOpnds = 0, explicitOpnds = 0; - for (uint32 i = 0, n = opndCount; i < n; i++){ - if (opnds[i] == NULL) continue; - uint32 r = opndRoles[i]; - if ((r & OpndRole_Explicit) != 0){ - r = (r & 0xffff) | (explicitOpnds << 16); - explicitOpnds++; - } - if (i > packedOpnds){ - opnds[packedOpnds] = opnds[i]; - constraints[packedOpnds] = constraints[i]; - opndRoles[packedOpnds] = r; - } - packedOpnds++; - } - - opndCount=packedOpnds; - form = Form_Native; -} - -//_________________________________________________________________________________________________ -void * Inst::getCodeStartAddr()const -{ - return basicBlock!=NULL?(uint8*)basicBlock->getCodeStartAddr()+codeOffset:0; + if (getForm()==Form_Native || hasKind(Kind_PseudoInst) ) + return; + assert(opcodeGroup); + + Node* bb = getNode(); + + uint32 * opndRoles = getOpndRoles(); + Constraint * constraints = getConstraints(); + + int32 defs[IRMaxNativeOpnds]={ -1, -1, -1, -1 }; + for (uint32 i=0; i> 16; + uint32 nativeIdx = opcodeGroup->extendedToNativeMap[extendedIdx]; + assert(nativeIdx < IRMaxNativeOpnds); + int32 defNativeIdx = defs[nativeIdx]; + if (defNativeIdx != -1){ + assert(i >= defOpndCount); + opndRoles[defNativeIdx] |= OpndRole_Use; + if (bb && opnds[defNativeIdx] != opnds[i]){ + Inst * moveInst=irManager->newCopySequence(Mnemonic_MOV, opnds[defNativeIdx], opnds[i]); + moveInst->insertBefore(this); + } + opnds[i] = NULL; + }else + defs[nativeIdx] = i; + } + + uint32 packedOpnds = 0, explicitOpnds = 0; + for (uint32 i = 0, n = opndCount; i < n; i++){ + if (opnds[i] == NULL) continue; + uint32 r = opndRoles[i]; + if ((r & OpndRole_Explicit) != 0){ + r = (r & 0xffff) | (explicitOpnds << 16); + explicitOpnds++; + } + if (i > packedOpnds){ + opnds[packedOpnds] = opnds[i]; + constraints[packedOpnds] = constraints[i]; + opndRoles[packedOpnds] = r; + } + packedOpnds++; + } + + opndCount=packedOpnds; + form = Form_Native; } -#ifdef _DEBUG //_________________________________________________________________________________________________ -void Inst::verify() +void * Inst::getCodeStartAddr() const { + BasicBlock* bb = getBasicBlock(); + return bb!=NULL?(uint8*)bb->getCodeStartAddr()+codeOffset:0; } -#endif -//========================================================================================================= -void appendToInstList(Inst *& head, Inst * listToAppend) -{ - if (head==NULL) - head=listToAppend; - else if (listToAppend!=NULL){ - Inst * inst=NULL, * nextInst=listToAppend, * lastInst=listToAppend->getPrev(); - Inst * after=head->getPrev(); - do { - inst=nextInst; - nextInst=inst->getNext(); - assert(inst->basicBlock==NULL); - inst->unlink(); - inst->insertAfter(after); - after=inst; - } while (inst!=lastInst); - } + +//_________________________________________________________________________________________________ +Edge::Kind Inst::getEdgeKind(const Edge* edge) const +{ + assert(edge->getSourceNode()->isBlockNode() && edge->getTargetNode()->isBlockNode()); + assert (!hasKind(Inst::Kind_BranchInst) && !hasKind(Inst::Kind_SwitchInst)); + return Edge::Kind_Unconditional; } //========================================================================================================= @@ -578,74 +593,200 @@ offsets(irm->getMemoryManager()), desc(N // class BranchInst //================================================================================================= +void BranchInst::reverse(IRManager * irManager) +{ + assert(canReverse()); + assert(node->isConnectedTo(true, trueTarget) && node->isConnectedTo(true, falseTarget)); + ControlTransferInst::reverse(irManager); + Node* tmp = trueTarget; + trueTarget = falseTarget; + falseTarget = tmp; +} + //_________________________________________________________________________________________________ -BasicBlock * BranchInst::getDirectBranchTarget()const +Edge::Kind BranchInst::getEdgeKind(const Edge* edge) const { - assert(basicBlock!=NULL); - Edge * directBranchEdge=basicBlock->getDirectBranchEdge(); - return directBranchEdge?(BasicBlock*)directBranchEdge->getNode(Direction_Head):0; + Node* node = edge->getTargetNode(); + if (node == trueTarget) { + return Edge::Kind_True; + } + assert(node == falseTarget); + return Edge::Kind_False; } //_________________________________________________________________________________________________ -void BranchInst::reverse(IRManager * irManager) +bool BranchInst::canReverse() const +{ + return node!=NULL && isDirect() && ControlTransferInst::canReverse(); +} + +//_________________________________________________________________________________________________ +// called from CFG when edge target is replaced +void BranchInst::updateControlTransferInst(Node* oldTarget, Node* newTarget) { - ControlTransferInst::reverse(irManager); - Edge * fte=basicBlock->getFallThroughEdge(); - assert(basicBlock->getDirectBranchEdge()!=NULL && fte!=NULL); - basicBlock->makeEdgeDirectBranch(fte); + if (!newTarget->isBlockNode()) { + assert(newTarget->isDispatchNode()); + return; + } + if (oldTarget == trueTarget) { + trueTarget = newTarget; + } else { + assert(oldTarget == falseTarget); + falseTarget = newTarget; + } } //_________________________________________________________________________________________________ -bool BranchInst::canReverse()const +// called from CFG when 2 blocks are merging and one of the branches is redundant. +void BranchInst::removeRedundantBranch() { - return basicBlock!=NULL&&isDirect()&&ControlTransferInst::canReverse(); + unlink(); +}; + +//_________________________________________________________________________________________________ +void BranchInst::verify() const +{ + Inst::verify(); + assert(trueTarget!=NULL && falseTarget!=NULL); + assert(trueTarget->isBlockNode() && falseTarget->isBlockNode()); + assert(node->isConnectedTo(true, trueTarget)); + assert(node->isConnectedTo(true, falseTarget)); } //========================================================================================================= // class SwitchInst //========================================================================================================= + +Node* SwitchInst::getTarget(uint32 i)const +{ + Opnd * tableAddr=getTableAddress(); + Opnd::RuntimeInfo * ri=tableAddr->getRuntimeInfo(); + assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); + ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); + assert(igetSize()/sizeof(Node*)); + return ((Node**)cai->getValue())[i]; +} + +//_________________________________________________________________________________________________ +Edge::Kind SwitchInst::getEdgeKind(const Edge* edge) const +{ +#ifdef _DEBUG + Node* target = edge->getTargetNode(); + assert(target->isBlockNode()); + bool found = false; + for (uint32 i =0 ; i < getNumTargets(); i++) { + Node* myTarget = getTarget(i); + if (myTarget == target) { + found = true; + break; + } + } + assert(found); +#endif + return Edge::Kind_Unconditional; +} + //_________________________________________________________________________________________________ -BasicBlock * SwitchInst::getTarget(uint32 i)const +uint32 SwitchInst::getNumTargets() const { - Opnd * opnd=getOpnd(0); - Opnd * tableAddr=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - Opnd::RuntimeInfo * ri=tableAddr->getRuntimeInfo(); - assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); - ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); - assert(igetSize()/sizeof(BasicBlock*)); - return ((BasicBlock**)cai->getValue())[i]; + Opnd * tableAddr=getTableAddress(); + Opnd::RuntimeInfo * ri= tableAddr->getRuntimeInfo(); + assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); + ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); + return cai->getSize() / sizeof(Node*); } //_________________________________________________________________________________________________ -void SwitchInst::setTarget(uint32 i, BasicBlock * bb) +void SwitchInst::setTarget(uint32 i, Node* bb) { - Opnd * opnd=getOpnd(0); - Opnd * tableAddr=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - Opnd::RuntimeInfo * ri=tableAddr->getRuntimeInfo(); - assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); - ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); - assert(igetSize()/sizeof(BasicBlock*)); - ((BasicBlock**)cai->getValue())[i]=bb; + assert(bb->isBlockNode()); + Opnd * tableAddr=getTableAddress(); + Opnd::RuntimeInfo * ri=tableAddr->getRuntimeInfo(); + assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); + ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); + assert(igetSize()/sizeof(Node*)); + ((Node**)cai->getValue())[i]=bb; } //_________________________________________________________________________________________________ -void SwitchInst::replaceTarget(BasicBlock * bbFrom, BasicBlock * bbTo) +void SwitchInst::replaceTarget(Node * bbFrom, Node * bbTo) { - Opnd * opnd=getOpnd(0); - Opnd * tableAddr=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + assert(bbTo->isBlockNode()); + Opnd * tableAddr=getTableAddress(); Opnd::RuntimeInfo * ri=tableAddr->getRuntimeInfo(); assert(ri->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); ConstantAreaItem * cai = (ConstantAreaItem *)ri->getValue(0); - BasicBlock ** bbs=(BasicBlock**)cai->getValue(); - for (uint32 i=0, n=cai->getSize()/sizeof(BasicBlock*); igetValue(); +#ifdef _DEBUG + bool found = false; +#endif + for (uint32 i=0, n=cai->getSize()/sizeof(Node*); iisBlockNode()) { + assert(newTarget->isDispatchNode()); + return; + } + replaceTarget(oldTarget, newTarget); +} + +//_________________________________________________________________________________________________ +// called from CFG when 2 blocks are merging and one of the branches is redundant. +void SwitchInst::removeRedundantBranch() +{ assert(0); } +//_________________________________________________________________________________________________ +Opnd * SwitchInst::getTableAddress() const +{ +#ifdef _EM64T_ + return tableAddr; +#else + return getOpnd(0)->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); +#endif +} + +//_________________________________________________________________________________________________ +void SwitchInst::verify() const +{ + Inst::verify(); +#ifdef _DEBUG + for (uint32 i=0, n = getNumTargets(); iisBlockNode()); + assert(node->isConnectedTo(true, target)); + } +#endif +} + + +//========================================================================================================= +// class CallingConventionClient +//========================================================================================================= +//_________________________________________________________________________________________________ +void JumpInst::verify() const { + Inst::verify(); +#ifdef _DEBUG + if (node!=NULL) { + assert(node->getOutDegree()==1 || node->getOutDegree()==2); + assert(node->getUnconditionalEdge()!=NULL); + assert(node->getOutDegree() == 1 || node->getExceptionEdge()!=NULL); + } +#endif +} //========================================================================================================= // class CallingConventionClient @@ -653,85 +794,85 @@ void SwitchInst::replaceTarget(BasicBloc //_________________________________________________________________________________________________ void CallingConventionClient::finalizeInfos(Inst::OpndRole role, CallingConvention::ArgKind argKind) { - assert(callingConvention!=NULL); - StlVector & infos = getInfos(role); - callingConvention->getOpndInfo(argKind, infos.size(), &infos.front()); - bool lastToFirst=callingConvention->pushLastToFirst(); - uint32 slotNumber=0; - for ( - uint32 i=lastToFirst?0:infos.size()-1, - end=lastToFirst?infos.size():(uint32)-1, - inc=lastToFirst?1:-1; - i!=end; - i+=inc - ){ - CallingConvention::OpndInfo & info=infos[i]; - for (uint32 j=0; j & infos = getInfos(role); + callingConvention->getOpndInfo(argKind, infos.size(), &infos.front()); + bool lastToFirst=callingConvention->pushLastToFirst(); + uint32 slotNumber=0; + for ( + uint32 i=lastToFirst?0:infos.size()-1, + end=lastToFirst?infos.size():(uint32)-1, + inc=lastToFirst?1:-1; + i!=end; + i+=inc + ){ + CallingConvention::OpndInfo & info=infos[i]; + for (uint32 j=0; j & infos = getInfos(role); - StlVector & stackOpndInfos = getStackOpndInfos(role); - uint32 slotSize=4; - uint32 regArgCount=0, stackArgCount=0; - Inst::Opnds opnds(ownerInst, Inst::OpndRole_Auxilary|role); - Inst::Opnds::iterator handledOpnds=opnds.begin(); - for (uint32 i=0, n=infos.size(); i & infos = getInfos(role); + StlVector & stackOpndInfos = getStackOpndInfos(role); + uint32 slotSize=sizeof(POINTER_SIZE_INT); + uint32 regArgCount=0, stackArgCount=0; + Inst::Opnds opnds(ownerInst, Inst::OpndRole_Auxilary|role); + Inst::Opnds::iterator handledOpnds=opnds.begin(); + for (uint32 i=0, n=infos.size(); igetSize(); - uint32 cb=getByteSize(sz); - RegName r=info.slots[j]; - if ((getRegKind(r)&OpndKind_Reg)!=0) { - r=Constraint::getAliasRegName(r,sz); - assert(r!=RegName_Null); + uint32 offset=0; + for (uint32 j=0, cbCurrent=0; jgetSize(); + uint32 cb=getByteSize(sz); + RegName r=(RegName)info.slots[j]; + if (info.isReg) { + r=Constraint::getAliasRegName(r,sz); + assert(r!=RegName_Null); #ifdef _DEBUG - eachSlotRequiresOpnd=true; + eachSlotRequiresOpnd=true; #endif - cbCurrent+=getByteSize(getRegSize(r)); - }else{ - if (cbCurrent==0) - offset=(info.slots[j] & 0xffff)*slotSize; - cbCurrent+=slotSize; - } - - if (cbCurrent>=cb){ - if ((getRegKind(r)&OpndKind_Reg)!=0){ - ownerInst->setConstraint(handledOpnds, r); - regArgCount++; - }else{ - ownerInst->setConstraint(handledOpnds, Constraint(kindForStackArgs, sz)); - stackArgCount++; - StackOpndInfo sainfo={ handledOpnds, offset }; - stackOpndInfos.push_back(sainfo); - } - handledOpnds = opnds.next(handledOpnds); + cbCurrent+=getByteSize(getRegSize(r)); + }else{ + if (cbCurrent==0) + offset=(info.slots[j] & 0xffff)*slotSize; + cbCurrent+=slotSize; + } + + if (cbCurrent>=cb){ + if (info.isReg){ + ownerInst->setConstraint(handledOpnds, r); + regArgCount++; + }else{ + ownerInst->setConstraint(handledOpnds, Constraint(kindForStackArgs, sz)); + stackArgCount++; + StackOpndInfo sainfo={ handledOpnds, offset }; + stackOpndInfos.push_back(sainfo); + } + handledOpnds = opnds.next(handledOpnds); #ifdef _DEBUG - eachSlotRequiresOpnd=false; + eachSlotRequiresOpnd=false; #endif - cbCurrent=0; - } + cbCurrent=0; + } #ifdef _DEBUG - assert(!eachSlotRequiresOpnd); + assert(!eachSlotRequiresOpnd); #endif - } - } - if (stackArgCount>0) - sort(stackOpndInfos.begin(), stackOpndInfos.end()); - assert(handledOpnds == opnds.end()); - assert(stackArgCount==stackOpndInfos.size()); + } + } + if (stackArgCount>0) + sort(stackOpndInfos.begin(), stackOpndInfos.end()); + assert(handledOpnds == opnds.end()); + assert(stackArgCount==stackOpndInfos.size()); } @@ -739,13 +880,16 @@ #endif // class EntryPointPseudoInst //========================================================================================================= EntryPointPseudoInst::EntryPointPseudoInst(IRManager * irm, int id, const CallingConvention * cc) - : Inst(Mnemonic_NULL, id, Inst::Form_Extended), callingConventionClient(irm->getMemoryManager(), cc) -{ kind=Kind_EntryPointPseudoInst; callingConventionClient.setOwnerInst(this); } - +#ifdef _EM64T_ + : Inst(Mnemonic_NULL, id, Inst::Form_Extended), thisOpnd(0), callingConventionClient(irm->getMemoryManager(), cc) +#else + : Inst(Mnemonic_NULL, id, Inst::Form_Extended), callingConventionClient(irm->getMemoryManager(), cc) +#endif +{ kind=Kind_EntryPointPseudoInst; callingConventionClient.setOwnerInst(this); } //_________________________________________________________________________________________________________ Opnd * EntryPointPseudoInst::getDefArg(uint32 i)const { - return NULL; + return NULL; } @@ -754,38 +898,25 @@ Opnd * EntryPointPseudoInst::getDefArg(u //================================================================================================= //_________________________________________________________________________________________________ CallInst::CallInst(IRManager * irm, int id, const CallingConvention * cc, InlineInfo* ii) - : ControlTransferInst(Mnemonic_CALL, id), callingConventionClient(irm->getMemoryManager(), cc), inlineInfo(NULL) + : ControlTransferInst(Mnemonic_CALL, id), callingConventionClient(irm->getMemoryManager(), cc), inlineInfo(NULL) { if (ii && (!ii->isEmpty()) ) { inlineInfo = ii; } - kind=Kind_CallInst; - callingConventionClient.setOwnerInst(this); -} - -//_________________________________________________________________________________________________ -Constraint CallInst::getCallerSaveRegs(OpndKind regKind)const -{ - Constraint calleeSaveRegs=getCalleeSaveRegs(regKind); - Constraint allRegs=Encoder::getAllRegs(regKind); - uint32 mask=allRegs.getMask()&~calleeSaveRegs.getMask(); - if (regKind==OpndKind_GPReg){ - mask&=~getRegMask(RegName_ESP); - } - return mask!=0?Constraint(regKind, allRegs.getSize(), mask):Constraint(); + kind=Kind_CallInst; + callingConventionClient.setOwnerInst(this); } - //================================================================================================= // class RetInst //================================================================================================= //_________________________________________________________________________________________________ RetInst::RetInst(IRManager * irm, int id) - : ControlTransferInst(Mnemonic_RET, id), - callingConventionClient(irm->getMemoryManager(), irm->getCallingConvention()) + : ControlTransferInst(Mnemonic_RET, id), + callingConventionClient(irm->getMemoryManager(), irm->getCallingConvention()) { - kind=Kind_RetInst; - callingConventionClient.setOwnerInst(this); + kind=Kind_RetInst; + callingConventionClient.setOwnerInst(this); } diff --git vm/jitrino/src/codegenerator/ia32/Ia32Inst.h vm/jitrino/src/codegenerator/ia32/Ia32Inst.h index 3611ac6..924723f 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Inst.h +++ vm/jitrino/src/codegenerator/ia32/Ia32Inst.h @@ -27,7 +27,7 @@ #include "MemoryManager.h" #include "Type.h" #include "CodeGenIntfc.h" #include "MemoryAttribute.h" - +#include "ControlFlowGraph.h" #include "Ia32Encoder.h" #include "Ia32CallingConvention.h" @@ -37,29 +37,30 @@ namespace Ia32{ //========================================================================================================= class CodeEmitter; -class CfgNode; -class BasicBlock; class IRManager; class Opnd; class Inst; +class BasicBlock; +class I8Lowerer; //========================================================================================================= -// class Opnd +// class Opnd //========================================================================================================= /** class Opnd represents an operand in the LIR. Instructions contain pointers to Opnd instances for their operands. For example the following LIR pseudo-code: - I0: mov t1, t0 - I1: add t1, t3 + I0: mov t1, t0 + I1: add t1, t3 instructions I0 and I1 will contain pointers (at index 0) to the same Opnd instance with id==1 -Operands behavior is managed by an array of 3 constraints: - ConstraintKind_Initial, - ConstraintKind_Calculated, - ConstraintKind_Location, +Physical locations where an operand can be placed is controlled +by an array of 3 constraints: + ConstraintKind_Initial, + ConstraintKind_Calculated, + ConstraintKind_Location, When an operand is created it is assigned ConstraintKind_Initial for the rest of its live At opnd creation time ConstraintKind_Calculated is also set to ConstraintKind_Initial @@ -77,251 +78,290 @@ class Opnd: public CG_OpndHandle { public: - /** enum Scope defines properties of the set of definitions of an operand */ - enum DefScope{ - DefScope_Null=0, - /** The operand has single definition */ - DefScope_Temporary, - /** The operand has multiple defs all withing one basic block (occures after convertion into 2-operand form) */ - DefScope_SemiTemporary, - /** The operand has merging defs */ - DefScope_Variable, - }; - - /** enum ConstraintKind is used to indicate a particular constraint of an operand - Used in getConstraint() - */ - enum ConstraintKind{ - /** The outer-most constraint assigned during Opnd creation basing on Opnd size*/ - ConstraintKind_Size=-1, - /** An additional constraint assigned during Opnd creation */ - ConstraintKind_Initial=0, - /** A constraint calculated during special pass from instruction properties */ - ConstraintKind_Calculated=1, - /** A constraint defining assigned physical location of an operand */ - ConstraintKind_Location=2, - /** The current constraint. If an operand is not assigned with physical storage, - getConstraint will return the Calculated constraint, - otherwise, it will return the Location constraint - */ - ConstraintKind_Current - }; - - //------------------------------------------------------------------------- - /** class RuntimeInfo contains information allowing CG to determine operand value from the current runtime information - Initially added to support AOT compiler the class is used to annotate operands with runtime info - */ - class RuntimeInfo - { - public: - enum Kind{ - Kind_Null=0, - /** The value of the operand is [0]->ObjectType::getAllocationHandle() */ - Kind_AllocationHandle, - /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ - Kind_TypeRuntimeId, - /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ - Kind_MethodRuntimeId, - /** The value of the operand is [1], but the information can be used to serialize/deserizalize - this value: [0] - Type * - the containing class, [1] - string token */ - Kind_StringDescription, - /** The value of the operand is [0]->ObjectType::getObjectSize() */ - Kind_Size, - /** The value of the operand is compilationInterface->getRuntimeHelperAddress([0]) */ - Kind_HelperAddress, - /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ - Kind_InternalHelperAddress, - /** The value of the operand is [0]->FieldDesc::getAddress() */ - Kind_StaticFieldAddress, - /** The value of the operand is [0]->FieldDesc::getOffset() */ - Kind_FieldOffset, - /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ - Kind_VTableAddrOffset, - /** The value of the operand is [0]->ObjectType::getVTable() */ - Kind_VTableConstantAddr, - /** The value of the operand is [0]->MethodDesc::getOffset() */ - Kind_MethodVtableSlotOffset, - /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ - Kind_MethodIndirectAddr, - /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ - Kind_MethodDirectAddr, - - /** The value of the operand is address of constant pool item ((ConstantPoolItem*)[0])->getAddress() */ - Kind_ConstantAreaItem=0x80, - - /** more ... */ - }; - - /** Constructs a RuntimeInfo instance of RuntimeInfo::Type t and initialize it with given values */ - RuntimeInfo(RuntimeInfo::Kind k, void * value0, void * value1=0, void * value2=0, void * value3=0, uint32 addOffset=0) - :kind(k), additionalOffset(addOffset) - { value[0]=value0; value[1]=value1; value[2]=value2; value[3]=value3; } - - /** Returns the the value at index i */ - void * getValue(uint32 i)const{ assert(iObjectType::getAllocationHandle() */ + Kind_AllocationHandle, + /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ + Kind_TypeRuntimeId, + /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ + Kind_MethodRuntimeId, + /** The value of the operand is [1], but the information can be used to serialize/deserizalize + this value: [0] - Type * - the containing class, [1] - string token */ + Kind_StringDescription, + /** The value of the operand is [0]->ObjectType::getObjectSize() */ + Kind_Size, + /** The value of the operand is compilationInterface->getRuntimeHelperAddress([0]) */ + Kind_HelperAddress, + /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ + Kind_InternalHelperAddress, + /** The value of the operand is the address where the interned version of the string is stored*/ + Kind_StringAddress, + /** The value of the operand is [0]->FieldDesc::getAddress() */ + Kind_StaticFieldAddress, + /** The value of the operand is [0]->FieldDesc::getOffset() */ + Kind_FieldOffset, + /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ + Kind_VTableAddrOffset, + /** The value of the operand is [0]->ObjectType::getVTable() */ + Kind_VTableConstantAddr, + /** The value of the operand is [0]->MethodDesc::getOffset() */ + Kind_MethodVtableSlotOffset, + /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ + Kind_MethodIndirectAddr, + /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ + Kind_MethodDirectAddr, + + /** The value of the operand is address of constant pool item ((ConstantPoolItem*)[0])->getAddress() */ + Kind_ConstantAreaItem=0x80, + + /** more ... */ + }; + + /** Constructs a RuntimeInfo instance of RuntimeInfo::Type t and initialize it with given values */ + RuntimeInfo(RuntimeInfo::Kind k, void * value0, void * value1=0, void * value2=0, void * value3=0, uint32 addOffset=0) + :kind(k), additionalOffset(addOffset) + { value[0]=value0; value[1]=value1; value[2]=value2; value[3]=value3; } + + /** Returns the the value at index i */ + void * getValue(uint32 i)const{ assert(i OpndVector; //========================================================================================================= @@ -331,7 +371,7 @@ typedef StlVector OpndVector; class Inst represents an instruction of the LIR. -Each instruction contains an array of its explicit operands (pointers to Opnd instances). +Each instruction contains an array of all its operands (pointers to Opnd instances). Each instruction contains a pointer to the basic block it is attached to. @@ -343,359 +383,442 @@ in a particular order. Inst provides Opnds collection allowing it to iterate over all the operands the instruction uses or defines explicitly or implicitly. -Inst also provides an interface to operand constraints (weak and strong constraints). -Initially operand constraints are defined for each occurence of an operand in an instruction, -but can be calculated for operands (using all their occurences) in a separate pass - +Inst also provides an interface to instruction-level operand constraints defined by ISA. */ -class Inst: protected Dlink +class Inst: public CFGInst { public: - //--------------------------------------------------------------- - /** enum Kind represents dynamic type info of Inst and descendants. - This enumeration is hierarchical and is used in getKind and hasKind Inst methods. - */ - enum Kind - { - Kind_Inst=0x7fffffff, - Kind_PseudoInst=0x7f000000, - Kind_EntryPointPseudoInst=0x40000000, - Kind_AliasPseudoInst=0x20000000, - Kind_CatchPseudoInst=0x10000000, - Kind_CopyPseudoInst=0x01000000, - Kind_I8PseudoInst=0x02000000, + //--------------------------------------------------------------- + /** enum Kind represents dynamic type info of Inst and descendants. + This enumeration is hierarchical and is used in getKind and hasKind Inst methods. + */ + enum Kind + { + Kind_Inst=0x7fffffff, + Kind_PseudoInst=0x7ff00000, + Kind_EntryPointPseudoInst=0x40000000, + Kind_AliasPseudoInst=0x20000000, + Kind_CatchPseudoInst=0x10000000, + Kind_CopyPseudoInst=0x01000000, + Kind_I8PseudoInst=0x02000000, Kind_GCInfoPseudoInst=0x04000000, - Kind_SystemExceptionCheckPseudoInst=0x08000000, - Kind_ControlTransferInst=0x0000fff0, - Kind_BranchInst=0x000003f0, - Kind_SwitchInst=0x00000300, - Kind_InterProceduralControlTransferInst=0x0000fc00, - Kind_CallInst=0x00000f000, - Kind_RetInst=0x000000c00, - }; - - /** misc properties of an instruction */ - enum Properties{ - /** The operation of the instruction is commutative regarding its uses */ - Properties_Symmetric=0x10, - Properties_Conditional=0x20, - }; - - /** enum OpndRole defines the role of an operand in an instruction - The structure of the enumeration is filter-like allowing to combine its values with '|' - */ - enum OpndRole - { - OpndRole_Null=0, - /** Instruction uses this operand */ - OpndRole_Use=0x1, - /** Instruction defines this operand */ - OpndRole_Def=0x2, - /** both uses and defs */ - OpndRole_UseDef=OpndRole_Use|OpndRole_Def, - /** Roles set by Encoder */ - OpndRole_FromEncoder=OpndRole_UseDef, - - /** Explicit operand, must be explicitly provided into newInstruction - Such operands can be replaced in instructions and can be virtual registers - */ - OpndRole_Explicit=0x10, - - /** Auxilary operand, - These operands can also be replaced in instructions and can be virtual registers - Examples are: - return values, arguments of a call instruction, and so on - */ - OpndRole_Auxilary=0x20, - - /** Operands which can be set or replaced directly in an instruction */ - OpndRole_Changeable=OpndRole_Explicit|OpndRole_Auxilary, - - /** Implicit operand, must not be explicitly provided into newInstruction - These operands are assigned with location from the moment of creation, - cannot be replaced in instructions, and fully defined by the semantics of an instruction. - Examples are: - EFLAG, and affected registers of a call instructions - - */ - OpndRole_Implicit=0x40, - - /** Operands contained directly in the instruction - (as oppsed to sub-operands of the InstLevel operands) - - InstLevel operands can be read directly from the instruction using - common indexing space - */ - OpndRole_InstLevel=OpndRole_Changeable|OpndRole_Implicit, - - /** Sub-operand of an instruction memory operand (base, index, scale, displacement) */ - OpndRole_MemOpndSubOpnd=0x80, - /** sub-operands of the InstLevel operands */ - OpndRole_OpndLevel=OpndRole_MemOpndSubOpnd, - - OpndRole_ForIterator=OpndRole_InstLevel|OpndRole_OpndLevel, - - OpndRole_All=0xff, - OpndRole_AllDefs=OpndRole_ForIterator|OpndRole_Def, - OpndRole_AllUses=OpndRole_ForIterator|OpndRole_Use, - }; - - /** enum Form represents the form of an instruction - Inst can be in either Extended ("3-address") form or Native ("2-address") form - */ - enum Form - { - /** Instructions's operands are in the "2-address" native form, e.g. add t0, t1 */ - Form_Native, - /** Instructions's operands are in the "3-address" extended form, e.g. t2=add t0, t1 */ - Form_Extended, - }; - - /** Constraint kind for an operand of an instruction */ - enum ConstraintKind - { - ConstraintKind_Weak=0, - ConstraintKind_Strong=1, - ConstraintKind_Current=2 - }; - - //--------------------------------------------------------------- + Kind_SystemExceptionCheckPseudoInst=0x08000000, + Kind_MethodEntryPseudoInst=0x00100000, + Kind_MethodEndPseudoInst=0x00200000, + Kind_EmptyPseudoInst=0x00400000, + Kind_ControlTransferInst=0x0000fff0, + Kind_LocalControlTransferInst=0x000003F0, + Kind_JmpInst=0x00000200, + Kind_BranchInst=0x000001C0, + Kind_SwitchInst=0x00000030, + Kind_InterProceduralControlTransferInst=0x0000fc00, + Kind_CallInst=0x00000f000, + Kind_RetInst=0x000000c00, + }; + + /** Misc properties of an instruction */ + enum Properties{ + /** The operation of the instruction is commutative regarding its uses */ + Properties_Symmetric=0x1, + /** The instruction is conditional (e.g. SETCC) */ + Properties_Conditional=0x2, + Properties_PureDef=0x4, + /** + * Memory operands of the instruction are conditional. + * This means different operands of the instructions can be assigned to memory + * but only one of them at the same time. This is a wide-known constraint of IA32 ISA. + */ + Properties_MemoryOpndConditional=0x8, + }; + + /** + * Enum OpndRole defines the role of an operand in an instruction. + * The structure of the enumeration is filter-like allowing to combine its values with '|'. + * + * It is important to notice that the role mask consists of two parts + * covered by OpndRole_FromEncoder and OpndRole_ForIterator. + * When used as filter values from each part are virtually combined by "and" + * meanding that an operand must satisfy filters from both parts. + * + * For example OpndRole_Use|OpndRole_Def|OpndRole_Explicit + * will filter explicit operand which are both uses and defs while + * OpndRole_Use|OpndRole_Explicit will filter only explicit operands which are uses. + */ + enum OpndRole + { + OpndRole_Null=0, + /** Instruction uses this operand. */ + OpndRole_Use=0x1, + /** Instruction defines this operand. */ + OpndRole_Def=0x2, + /** Both uses and defs. */ + OpndRole_UseDef=OpndRole_Use|OpndRole_Def, + + /** Roles retrieved from Encoder. */ + OpndRole_FromEncoder=OpndRole_UseDef, + + /** + * Explicit operand, defined by ISA, must be explicitly provided during inst creation. + */ + OpndRole_Explicit=0x10, + + /** + * Auxilary operand, not defined by ISA, + * e.g. return values, arguments of a call instruction, and so on. + */ + OpndRole_Auxilary=0x20, + + /** + * Implicit operand, defined by ISA, must not be explicitly provided during inst creation. + * These operands are assigned with a physical location from the moment of creation, + * cannot be replaced in instructions, and fully defined by the semantics of an instruction. + * Examples are: EFLAG. + * + * ESP could also be implicit operands of PUSH/POP + * but this is not done in the current implementation. + * + */ + OpndRole_Implicit=0x40, + + /** + * Operands contained directly in the instruction + * (as oppsed to sub-operands of memory InstLevel operands). + */ + OpndRole_InstLevel=OpndRole_Explicit|OpndRole_Auxilary|OpndRole_Implicit, + + /** Sub-operand of an instruction memory operand (base, index, scale, displacement). */ + OpndRole_MemOpndSubOpnd=0x80, + /** Sub-operands of the InstLevel operands. */ + OpndRole_OpndLevel=OpndRole_MemOpndSubOpnd, + + /** Operands which can be set or replaced directly in an instruction. */ + OpndRole_Changeable=OpndRole_Explicit|OpndRole_Auxilary|OpndRole_MemOpndSubOpnd, + + OpndRole_ForIterator=OpndRole_InstLevel|OpndRole_OpndLevel, + + OpndRole_All=0xff, + OpndRole_AllDefs=OpndRole_ForIterator|OpndRole_Def, + OpndRole_AllUses=OpndRole_ForIterator|OpndRole_Use, + }; + + /** enum Form represents the form of an instruction + Inst can be in either Extended ("3-address") form or Native ("2-address") form. + */ + enum Form + { + /** Instructions's operands are in the "2-address" native form, e.g. add t0, t1. */ + Form_Native, + /** Instructions's operands are in the "3-address" extended form, e.g. t2=add t0, t1. */ + Form_Extended, + }; + + //--------------------------------------------------------------- public: - /** returns the kind of the instruction representing its class */ - Kind getKind()const{ return kind; } - /** returns true if the instruction is of kind (class) k or its subclass */ - bool hasKind(Kind k)const{ return (kind&k)==kind; } - - /** returns the id of the instruction */ - uint32 getId()const{ return id; } - - /** returns the current form of the instruction */ - Form getForm()const{ return (Form)form; } - - /** returns the stack depth of the instruction */ - uint32 getStackDepth() const { return stackDepth; } - - /** returns the mnemonic of the instruction */ - Mnemonic getMnemonic()const{ return mnemonic; } - - /** Returns opcode group description associated with this instruction */ - const Encoder::OpcodeGroupDescription * getOpcodeGroupDescription()const - { assert(opcodeGroupDescription); return opcodeGroupDescription; } - - - /** Shortcut: returns the properties of the instruction (bit-mask of Properties) */ - uint32 getProperties()const - { return properties; } - - /** returns the sequential index of the instruction after ordering via IRManager::indexInsts */ - uint32 getIndex()const{ return index; } - - /** returns the basic block this instruction is appended to or NULL */ - BasicBlock * getBasicBlock()const{ return basicBlock; } - - /** Direct access to InstLevel operands - returns the number of InstLevel operands containing directly in the instruction - of the given role combination - */ - uint32 getOpndCount()const{ return opndCount; } - uint32 getOpndCount(uint32 roles)const - { return - roles == (OpndRole_InstLevel|OpndRole_UseDef) ? opndCount: - roles == (OpndRole_InstLevel|OpndRole_Def) ? defOpndCount: - roles == (OpndRole_InstLevel|OpndRole_Use) && (Form)form == Form_Extended ? opndCount - defOpndCount: - countOpnds(roles); - } - - /** Direct access to InstLevel operands including OpndLevel. - The indexing space is common for all operands. - Inst::Opnds::iterator can also be used as index in this method. - */ - Opnd * getOpnd(uint32 index)const - { - Opnd * const * opnds = getOpnds(); - if (index < opndCount) - return opnds[index]; - uint32 diffIndex = index - opndCount; - Opnd * instOpnd = *(Opnd * const *)(((Byte*)opnds) + (diffIndex & ~3)); - return instOpnd->getMemOpndSubOpnd((MemOpndSubOpndKind)(diffIndex & 3)); - } - - uint32 getInstLevelIndex(uint32 fullIndex)const - { return (fullIndex - opndCount) & ~3; } - - /** returns a mask describing operand roles (|-ed from OpndRole values) - for an InstLevel operand at idx - the indexing space is common for all operands including OpndLevel - */ - uint32 getOpndRoles(uint32 index) const - { return index < opndCount ? getOpndRoles()[index] : OpndRole_OpndLevel|OpndRole_Use; } - - Opnd * const * getOpnds()const { return opnds; } - const uint32 * getOpndRoles()const - { uint32 aoc = allocatedOpndCount; return (const uint32*)(opnds + aoc); } - const Constraint * getConstraints()const - { uint32 aoc = allocatedOpndCount; return (const Constraint*)((const uint32*)(opnds + aoc) + aoc); } - - /** returns a constraint for an InstLevel operand at idx - the indexing space is common for all operands including OpndLevel - */ - Constraint getConstraint(ConstraintKind ck, uint32 idx, OpndSize size=OpndSize_Null)const; - - bool isLiveRangeStart(uint32 idx)const - { return (getOpndRoles(idx) & Inst::OpndRole_Use) != 0 && getOpnd(idx)->isSubjectForLivenessAnalysis(); } - - bool isLiveRangeEnd(uint32 idx)const - { return (getOpndRoles(idx) & Inst::OpndRole_UseDef) == Inst::OpndRole_Def && (getProperties() & Inst::Properties_Conditional)==0; } - - /** Direct access to operands - Sets operand containing directly in the instruction at idx - the indexing space is common for all InstLevel operands - */ - void setOpnd(uint32 idx, Opnd * opnd); - - void insertOpnd(uint32 idx, Opnd * opnd, uint32 opndRoles); - - void setConstraint(uint32 idx, Constraint c) - { assert( (getOpndRoles()[idx] & OpndRole_Explicit) == 0 ); getConstraints()[idx] = c; } - - /** replaces all occurences of opndOld with roles matching opndRoleMask - to opndNew */ - bool replaceOpnd(Opnd * opndOld, Opnd * opndNew, uint32 opndRoleMask=OpndRole_All); - - /** replaces all occurences of operands with roles matching opndRoleMask - which has an entry in opndMap to the operand from that entry - - The opndMap map is organized as an array indexed by from-operand ID which contains to-operands. - The number of entries in the array must be no less than the value returned by IRManager::getOpndCount() - */ - bool replaceOpnds(Opnd * const * opndMap, uint32 opndRoleMask=OpndRole_All); - - /** returns true if the instruction has side effect not described by its operands */ - virtual bool hasSideEffect()const - { return false; } - - /** emits (encodes) the instruction into stream */ - uint8 * emit(uint8* stream)const; - - void initFindInfo(Encoder::FindInfo& fi, Opnd::ConstraintKind opndConstraintKind)const; - - /** Shortcut to get the next instruction in an Inst list */ - Inst * getNext()const{ return (Inst*)_next; } - /** Shortcut to get the prev instruction in an Inst list */ - Inst * getPrev()const{ return (Inst*)_prev; } - - /** swaps inst's operands at idx0 and idx1 */ - void swapOperands(uint32 idx0, uint32 idx1); - - /** changes instruction form to native - and makes all necessary changes in instruction operands - */ - void makeNative(IRManager * irManager); - - /** changes condition for a conditional instruction (SETcc, MOVcc, Jcc) - Conditional instruction has Properies_Conditional - */ - void changeInstCondition(ConditionMnemonic cc, IRManager * irManager); - - /* Reverses condition of a conditional inst and updates its opcode group appropriately */ - virtual void reverse(IRManager * irManager); - - /* Returns true if the condition of a conditional inst can be reverted */ - virtual bool canReverse()const - { return getProperties()&&Properties_Conditional; } - - /** sets the offset of native code for this instruction */ - void setCodeOffset(uint32 offset) {codeOffset = offset;} - /** returns the offset of native code for this instruction */ - uint32 getCodeOffset()const { return codeOffset; } - /** sets the size of native code for this instruction */ - void setCodeSize(uint32 size) {codeSize = size;} - /** returns the size of native code for this instruction */ - uint32 getCodeSize()const { return codeSize; } - - /** returns the pointer to the native code for this instruction */ - void * getCodeStartAddr()const; - - class Opnds; + + /** Returns the next inst in a double-linked list. */ + Inst* getNextInst() const {return (Inst*)next();} + /** Returns the previous inst in a double-linked list. */ + Inst* getPrevInst() const {return (Inst*)prev();} + + /** Returns the kind of the instruction representing its class. */ + Kind getKind()const{ return kind; } + /** Returns true if the instruction is of kind (class) k or its subclass. */ + bool hasKind(Kind k)const{ return (kind&k)==kind; } + + /** Returns the id of the instruction. */ + uint32 getId()const{ return id; } + + /** Returns the current form of the instruction. */ + Form getForm()const{ return (Form)form; } + + /** + * Returns the stack depth at the instruction. + * This information is calculated in IRManager::calculateStackDepth(). + */ + uint32 getStackDepth() const { return stackDepth; } + + /** Returns the mnemonic of the instruction. */ + Mnemonic getMnemonic()const{ return mnemonic; } + + /** Returns opcode group description associated with this instruction. */ + const Encoder::OpcodeGroup* getOpcodeGroup()const + { assert(opcodeGroup); return opcodeGroup; } + + + /** Shortcut: returns the properties of the instruction (bit-mask of Properties). */ + uint32 getProperties()const + { return properties; } + + bool getPureDefProperty() const; + + /** Returns the sequential index of the instruction after ordering via IRManager::indexInsts. */ + uint32 getIndex()const{ return index; } + + /** + * Returns the number of InstLevel operands in the instruction. + * This is an optimized version of getOpndCount(OpndRole_InstLevel|OpndRole_UseDef). + */ + uint32 getOpndCount()const{ return opndCount; } + + /** + * Returns the number of operands in the instruction satisfying the given mask. + * Please refer to documentation of enum OpndRole for description of usage of opnd roles as filters. + */ + uint32 getOpndCount(uint32 roles)const + { return + roles == (OpndRole_InstLevel|OpndRole_UseDef) ? opndCount: + roles == (OpndRole_InstLevel|OpndRole_Def) ? defOpndCount: + roles == (OpndRole_InstLevel|OpndRole_Use) && (Form)form == Form_Extended ? opndCount - defOpndCount: + countOpnds(roles); + } + + /** + * Returns the operand at the given index. + * The indexing space is sparce and common for all operands including both InstLevel and OpndLevel. + * + * The indexing space is organized as follows: + * - All InstLevel operands + * - OpndLevel operands for each InstLevel operand, + * organized in 4 slots for each InstLevel operand. + * If an InstLevel operand is not a memory operand the + * corresponding OpndLevel slots will contain undefined value. + * For example, for MOV op0, op1 ([op10(base)+op11(disp)]) the virtual array of operands will appear as + * { op0, op1, ?, ?, ?, ?, op10, ?, ?, op11 }. + * + * All defs in an instruction go before uses in the indexing space. + * + * Simple loops from 0 to getOpndCount() can be used to access InstLevel operands only. + * Inst::Opnds::iterator can also be used as index in this method and should be used to iterate + * over all operands including OpndLevel. + */ + Opnd * getOpnd(uint32 index)const + { + Opnd * const * opnds = getOpnds(); + if (index < opndCount) + return opnds[index]; + return opnds[(index - opndCount) / 4]->getMemOpndSubOpnd((MemOpndSubOpndKind)((index - opndCount) & 3)); + } + + /** + * Returns a mask describing operand roles (|-ed from OpndRole values). + * + * The indexing space is common for all operands including OpndLevel + * (please see comments to Opnd * getOpnd(uint32 index)const). + */ + uint32 getOpndRoles(uint32 index) const + { return index < opndCount ? getOpndRoles()[index] : OpndRole_OpndLevel|OpndRole_Use; } + + /** Returns a const array of all InstLevel operands. */ + Opnd * const * getOpnds()const { return opnds; } + + /** Returns a const array of InstLevel operand roles. */ + const uint32 * getOpndRoles()const + { uint32 aoc = allocatedOpndCount; return (const uint32*)(opnds + aoc); } + + /** Returns a const array of InstLevel operand constraints. */ + const Constraint * getConstraints()const + { uint32 aoc = allocatedOpndCount; return (const Constraint*)((const uint32*)(opnds + aoc) + aoc); } + + /** + * Returns the constraint imposed by the instruction for the operand at idx. + * + * The indexing space is common for all operands including OpndLevel + * (please see comments to Opnd * getOpnd(uint32 index)const). + * + * @param idx - operand index to get the constraint for. + * + * @param memOpndMask - the mask of the operands which are checked if + * they are assigned to memory when determining conditional constraints. + * memOpndMask is indexed in the standard operand indexing space, the same as idx. + * The method takes into account only those memOpndMask bits which correspond to + * Explicit operands and not the operand defined by idx. + * + * @param size - if this parameter is not OpndSize_Null the resulted constraint + * is adjusted to the requested size. + */ + Constraint getConstraint(uint32 idx, uint32 memOpndMask, OpndSize size = OpndSize_Null); + + /** + * Returns true if the position at idx starts or extends the operand live range + * (simplistically its a use of the operand). + */ + bool isLiveRangeStart(uint32 idx)const + { return (getOpndRoles(idx) & Inst::OpndRole_Use) != 0 && getOpnd(idx)->isSubjectForLivenessAnalysis() && !getPureDefProperty(); } + + + /** + * Returns true if the position at idx ends the operand live range + * (simplistically its a pure def of the operand). + */ + bool isLiveRangeEnd(uint32 idx)const + { return ((getOpndRoles(idx) & Inst::OpndRole_UseDef) == Inst::OpndRole_Def && (getProperties() & Inst::Properties_Conditional)==0) || ((getOpndRoles(idx) & Inst::OpndRole_Def)!=0 && getPureDefProperty()); } + + + /** + * Sets opnd in the instruction at idx. + * + * The indexing space is common for all operands including OpndLevel + * (please see comments to Opnd * getOpnd(uint32 index)const). + */ + void setOpnd(uint32 idx, Opnd * opnd); + + + /** + * Inserts opnd into the instruction at idx. + * + * Works only for InstLevel operands. The total number of operands cannot + * exceed pre-allocated capacity. + */ + void insertOpnd(uint32 idx, Opnd * opnd, uint32 opndRoles); + + /** Replaces all occurences of opndOld with roles matching opndRoleMask to opndNew */ + bool replaceOpnd(Opnd * opndOld, Opnd * opndNew, uint32 opndRoleMask=OpndRole_All); + + /** + * Replaces all occurences of operands with roles matching opndRoleMask + * which has an entry in opndMap to the operand from that entry. + * + * The opndMap map is organized as an array indexed by from-operand ID which contains to-operands. + * The number of entries in the array must be no less than the value returned by IRManager::getOpndCount() + */ + bool replaceOpnds(Opnd * const * opndMap, uint32 opndRoleMask=OpndRole_All); + + /** Returns true if the instruction has side effect not described by its operands */ + virtual bool hasSideEffect()const + { return false; } + + /* Checks that inst is valid*/ + virtual void verify() const { assert(node!=NULL);} + + /** Emits (encodes) the instruction into stream */ + uint8 * emit(uint8* stream); + + void initFindInfo(Encoder::FindInfo& fi, Opnd::ConstraintKind opndConstraintKind)const; + + /** Shortcut to get the next instruction in an Inst list */ + Inst * getNext()const{ return (Inst*)_next; } + /** Shortcut to get the prev instruction in an Inst list */ + Inst * getPrev()const{ return (Inst*)_prev; } + + /** Swaps inst's operands at idx0 and idx1 */ + void swapOperands(uint32 idx0, uint32 idx1); + + /** + * Changes instruction form to native + * and makes all necessary changes in instruction operands + */ + virtual void makeNative(IRManager * irManager); + + /** + * Changes condition for a conditional instruction (SETcc, MOVcc, Jcc) + * Conditional instructions have Properies_Conditional. + */ + void changeInstCondition(ConditionMnemonic cc, IRManager * irManager); + + /* Reverses condition of a conditional inst and updates its opcode group appropriately. */ + virtual void reverse(IRManager * irManager); + + /* Returns true if the condition of a conditional inst can be reversed. */ + virtual bool canReverse()const + { return getProperties()&&Properties_Conditional; } + + /** Sets the offset of native code for this instruction. */ + void setCodeOffset(uint32 offset) {codeOffset = offset;} + /** Returns the offset of native code for this instruction. */ + uint32 getCodeOffset()const { return codeOffset; } + /** Returns the size of native code for this instruction. */ + uint32 getCodeSize()const { return codeSize; } + + /** Returns the pointer to the native code for this instruction. */ + void * getCodeStartAddr()const; + + /** Returns the basic block this inst is inserted into or null. */ + BasicBlock* getBasicBlock() const + { + assert(node == NULL || node->isBlockNode()); + return (BasicBlock*)node; + } + + /** + * Returns the kind of edge according to the kind of the inst. + * Called by CFG to detect BB->BB block edges. + * ControlTransferInst descendants override this method. + */ + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + + class Opnds; protected: - //--------------------------------------------------------------- + //--------------------------------------------------------------- - static inline void* operator new(size_t sz, MemoryManager& mm, uint32 opndCount) - { - Inst * p = (Inst*)mm.alloc(sz + Inst::getOpndChunkSize(opndCount)); - p->allocatedOpndCount = opndCount; p->opnds = (Opnd**)((uint8*)p + sz); - return p; - } - static inline void operator delete(void * p, MemoryManager& mm, uint32 opndCount) {} - static inline void operator delete(void * p) {} + static void* operator new(size_t sz, MemoryManager& mm, uint32 opndCount); - Inst(Mnemonic m, uint32 _id, Form f) - :kind(Kind_Inst), id(_id), mnemonic(m), - form(f), reservedFlags(0), - opcodeGroupDescription(0), basicBlock(0), defOpndCount(0), opndCount(0) - {} - virtual ~Inst(){}; + static inline void operator delete(void * p, MemoryManager& mm, uint32 opndCount) {} + static inline void operator delete(void * p) {} - static uint32 getOpndChunkSize(uint32 opndCount){ return opndCount * (sizeof(Opnd*) + sizeof(uint32) * 2); } + Inst(Mnemonic m, uint32 _id, Form f) + :kind(Kind_Inst), id(_id), mnemonic(m), + form(f), reservedFlags(0), + opcodeGroup(0), index(0), defOpndCount(0), opndCount(0) + {} + virtual ~Inst(){}; + static uint32 getOpndChunkSize(uint32 opndCount){ return opndCount * (sizeof(Opnd*) + sizeof(uint32) * 2); } - Opnd ** getOpnds() { return opnds; } - uint32 * getOpndRoles() - { uint32 aoc = allocatedOpndCount; return (uint32*)(opnds + aoc); } - Constraint * getConstraints() - { uint32 aoc = allocatedOpndCount; return (Constraint*)((const uint32*)(opnds + aoc) + aoc); } - static uint32 getExplicitOpndIndexFromOpndRoles(uint32 roles) - { return roles>>16; } + /** sets the size of native code for this instruction */ + void setCodeSize(uint32 size) {codeSize = size;} + Opnd ** getOpnds() { return opnds; } + uint32 * getOpndRoles() + { uint32 aoc = allocatedOpndCount; return (uint32*)(opnds + aoc); } + Constraint * getConstraints() + { uint32 aoc = allocatedOpndCount; return (Constraint*)((const uint32*)(opnds + aoc) + aoc); } + static uint32 getExplicitOpndIndexFromOpndRoles(uint32 roles) + { return roles>>16; } - uint32 countOpnds(uint32 roles)const; - void fixOpndsForOpcodeGroup(IRManager * irManager); - void assignOpcodeGroup(IRManager * irManager); + uint32 countOpnds(uint32 roles)const; - void setStackDepth(const uint32 sd) { stackDepth = sd; } + void setConstraint(uint32 idx, Constraint c) + { assert( (getOpndRoles()[idx] & OpndRole_Explicit) == 0 ); getConstraints()[idx] = c; } - void verify() -#ifndef _DEBUG - {} -#else - ; -#endif + void fixOpndsForOpcodeGroup(IRManager * irManager); + void assignOpcodeGroup(IRManager * irManager); + + void setStackDepth(const uint32 sd) { stackDepth = sd; } - //--------------------------------------------------------------- - Kind kind; - uint32 id; - Mnemonic mnemonic; - uint32 form:1; - uint32 reservedFlags:7; - uint32 codeSize:8; - uint32 properties:8; - uint32 reservedFlags2:8; + //--------------------------------------------------------------- + Kind kind; + uint32 id; + Mnemonic mnemonic; - const Encoder::OpcodeGroupDescription * opcodeGroupDescription; - BasicBlock * basicBlock; + uint32 form:1; + uint32 reservedFlags:7; + uint32 codeSize:8; + uint32 properties:8; + uint32 reservedFlags2:8; - uint32 index; - uint32 codeOffset; + Encoder::OpcodeGroup * opcodeGroup; + BasicBlock * basicBlock; - uint32 allocatedOpndCount:16; - uint32 defOpndCount:16; - uint32 opndCount:16; - uint32 stackDepth:16; + uint32 index; + uint32 codeOffset; - Opnd ** opnds; + uint32 allocatedOpndCount:16; + uint32 defOpndCount:16; + uint32 opndCount:16; + uint32 stackDepth:16; - //--------------------------------------------------------------- - friend class Insts; - friend class IRManager; - friend class Encoder; - friend class BasicBlock; + Opnd ** opnds; - friend void appendToInstList(Inst *& head, Inst * listToAppend); + //--------------------------------------------------------------- + friend class IRManager; + friend class Encoder; + friend class CallingConventionClient; + friend class I8Lowerer; }; @@ -706,86 +829,85 @@ #endif class Inst::Opnds { public: - typedef uint32 iterator; - inline Opnds(const Inst * inst, uint32 r) - { - rolesToCheck = 0; - roles = NULL; - opnds = inst->getOpnds(); - - if (r & Inst::OpndRole_InstLevel) { - startIndex = 0; - if (r & Inst::OpndRole_Use){ - endIndex = instEndIndex = inst->opndCount; - if (r & Inst::OpndRole_OpndLevel) - endIndex += endIndex<<2; - }else if (r & Inst::OpndRole_Def) - endIndex = instEndIndex = inst->defOpndCount; - else - endIndex = instEndIndex = 0; - - if ((r & Inst::OpndRole_InstLevel) != Inst::OpndRole_InstLevel || - (r & Inst::OpndRole_UseDef) == Inst::OpndRole_Use - ){ - roles = inst->getOpndRoles(); - rolesToCheck = r; - startIndex = next(startIndex - 1); - } - }else{ - instEndIndex = inst->opndCount; - endIndex = instEndIndex + (instEndIndex<<2); - startIndex = skipNulls(instEndIndex); - } - } - - inline iterator begin()const{ return startIndex; } - inline iterator end()const{ return endIndex; } - - inline iterator next(iterator index)const - { - ++index; - if (index < instEndIndex){ - if (roles == NULL) - return index; - uint32 r = rolesToCheck; - do { - uint32 ri = roles[index] & r; - if ( (ri & Inst::OpndRole_ForIterator) && (ri & Inst::OpndRole_FromEncoder) ) return index; - }while (++index < instEndIndex); - } - return skipNulls(index); - } - - uint32 skipNulls(uint32 index)const - { - while (index < endIndex){ - uint32 diffIndex = index - instEndIndex; - Opnd * instOpnd = *(Opnd * const *)(((Byte*)opnds) + (diffIndex & ~3)); - uint32 subIndex = diffIndex & 3; - if (subIndex == 0 && instOpnd->getMemOpndKind()==MemOpndKind_Null) - index += 4; - else if (instOpnd->getMemOpndSubOpnd((MemOpndSubOpndKind)(subIndex))==NULL) index++; - else break; - } - return index; - } - - uint32 fill( Opnd ** opnds )const; - - Opnd * getOpnd(uint32 index)const - { - if (index < instEndIndex) - return opnds[index]; - else { - uint32 diffIndex = index - instEndIndex; - Opnd * instOpnd = *(Opnd * const *)(((Byte*)opnds) + (diffIndex & ~3)); - return instOpnd->getMemOpndSubOpnd((MemOpndSubOpndKind)(diffIndex & 3)); - } - } - - uint32 startIndex, endIndex, instEndIndex; - Opnd * const * opnds; const uint32 * roles; - uint32 rolesToCheck; + typedef uint32 iterator; + inline Opnds(const Inst * inst, uint32 r) + { + rolesToCheck = 0; + roles = NULL; + + opnds = inst->getOpnds(); + + if (r & Inst::OpndRole_InstLevel) { + startIndex = 0; + if (r & Inst::OpndRole_Use){ + endIndex = instEndIndex = inst->opndCount; + if (r & Inst::OpndRole_OpndLevel) + endIndex += endIndex<<2; + }else if (r & Inst::OpndRole_Def) + endIndex = instEndIndex = inst->defOpndCount; + else + endIndex = instEndIndex = 0; + + if ((r & Inst::OpndRole_InstLevel) != Inst::OpndRole_InstLevel || + (r & Inst::OpndRole_UseDef) == Inst::OpndRole_Use ) + { + roles = inst->getOpndRoles(); + rolesToCheck = r; + startIndex = next(startIndex - 1); + } + }else{ + instEndIndex = inst->opndCount; + endIndex = instEndIndex + (instEndIndex<<2); + startIndex = skipNulls(instEndIndex); + } + } + + inline iterator begin()const{ return startIndex; } + inline iterator end()const{ return endIndex; } + + inline iterator next(iterator index)const + { + ++index; + if (index < instEndIndex){ + if (roles == NULL) + return index; + uint32 r = rolesToCheck; + do { + uint32 ri = roles[index] & r; + if ( (ri & Inst::OpndRole_ForIterator) && (ri & Inst::OpndRole_FromEncoder) ) return index; + }while (++index < instEndIndex); + } + return skipNulls(index); + } + + uint32 skipNulls(iterator index)const + { + while (index < endIndex){ + uint32 diffIndex = index - instEndIndex; + Opnd * instOpnd = opnds[diffIndex / 4]; + uint32 subIndex = diffIndex & 3; + if (subIndex == 0 && instOpnd->getMemOpndKind()==MemOpndKind_Null) + index += 4; + else if (instOpnd->getMemOpndSubOpnd((MemOpndSubOpndKind)(subIndex))==NULL) index++; + else break; + } + return index; + } + + uint32 fill( Opnd ** opnds )const; + + Opnd * getOpnd(iterator index)const + { + if (index < instEndIndex) + return opnds[index]; + else { + return opnds[(index - instEndIndex) / 4]->getMemOpndSubOpnd((MemOpndSubOpndKind)((index - instEndIndex) & 3)); + } + } + + uint32 startIndex, endIndex, instEndIndex; + Opnd * const * opnds; const uint32 * roles; + uint32 rolesToCheck; }; @@ -794,35 +916,36 @@ public: // class AliasPseudoInst //========================================================================================================= /** - Class AliasPseudoInst represents ... + Class AliasPseudoInst represents ... */ class AliasPseudoInst: public Inst { protected: AliasPseudoInst(int id) - : Inst(Mnemonic_NULL, id, Inst::Form_Extended), offset(EmptyUint32) - {kind=Kind_AliasPseudoInst;} + : Inst(Mnemonic_NULL, id, Inst::Form_Extended), offset(EmptyUint32) + {kind=Kind_AliasPseudoInst;} - uint32 offset; + uint32 offset; - friend class IRManager; + friend class IRManager; }; //========================================================================================================= // class CatchPseudoInst //========================================================================================================= /** - Class CatchPseudoInst represents ... + Class CatchPseudoInst represents ... */ class CatchPseudoInst: public Inst { protected: CatchPseudoInst(int id) - : Inst(Mnemonic_NULL, id, Inst::Form_Extended) - {kind=Kind_CatchPseudoInst;} + : Inst(Mnemonic_NULL, id, Inst::Form_Extended) + {kind=Kind_CatchPseudoInst;} - virtual bool hasSideEffect()const{ return true; } - friend class IRManager; + virtual bool hasSideEffect()const{ return true; } + virtual bool isHeaderCriticalInst() const {return true;} + friend class IRManager; }; //========================================================================================================= @@ -835,7 +958,7 @@ staticMPtrs offsets contains resolved st */ class GCInfoPseudoInst: public Inst { - friend class IRManager; + friend class IRManager; protected: GCInfoPseudoInst(IRManager * irm, int id); @@ -853,18 +976,18 @@ public: class SystemExceptionCheckPseudoInst: public Inst { public: - CompilationInterface::SystemExceptionId getExceptionId()const{ return exceptionId; } + CompilationInterface::SystemExceptionId getExceptionId()const{ return exceptionId; } bool checksThisOfInlinedMethod() const { return checksThis; } protected: SystemExceptionCheckPseudoInst(CompilationInterface::SystemExceptionId eid, int id, bool chkThis) - : Inst(Mnemonic_CALL, id, Inst::Form_Extended), exceptionId(eid), checksThis(chkThis) - {kind=Kind_SystemExceptionCheckPseudoInst;} + : Inst(Mnemonic_CALL, id, Inst::Form_Extended), exceptionId(eid), checksThis(chkThis) + {kind=Kind_SystemExceptionCheckPseudoInst;} - CompilationInterface::SystemExceptionId exceptionId; + CompilationInterface::SystemExceptionId exceptionId; - virtual bool hasSideEffect()const{ return false; } + virtual bool hasSideEffect()const{ return false; } bool checksThis; - friend class IRManager; + friend class IRManager; }; @@ -878,75 +1001,118 @@ class ControlTransferInst: public Inst { public: - /** Sub-type: returns true if the instruction is a direct ConstrolTransferInst instance - (direct branch or direct call), which means that its operand is immediate */ - virtual bool isDirect()const - { return getOpndCount()>0 && getOpnd(getTargetOpndIndex())->isPlacedIn(OpndKind_Imm); } + /** Sub-type: returns true if the instruction is a direct ConstrolTransferInst instance + (direct branch or direct call), which means that its operand is immediate */ + virtual bool isDirect()const + { return getOpndCount()>0 && getOpnd(getTargetOpndIndex())->isPlacedIn(OpndKind_Imm); } - uint32 getTargetOpndIndex()const{ return getOpndCount(OpndRole_InstLevel|OpndRole_Def); } + uint32 getTargetOpndIndex()const{ return getOpndCount(OpndRole_InstLevel|OpndRole_Def); } - virtual bool hasSideEffect()const { return true; } + virtual bool hasSideEffect()const { return true; } protected: ControlTransferInst(Mnemonic mnemonic, int id) - : Inst(mnemonic, id, Form_Native){kind=Kind_ControlTransferInst;} + : Inst(mnemonic, id, Form_Native){kind=Kind_ControlTransferInst;} - friend class IRManager; + friend class IRManager; }; //========================================================================================================= // class BranchInst //========================================================================================================= -/** class BranchInst is used for all branch instructions: Jcc, JMP +/** class BranchInst is used for all branching (conditional control transfers) instructions */ class BranchInst: public ControlTransferInst { + friend class IRManager; public: - /** Returns the basic block this branch transfers control to - Works only for direct branches - */ - BasicBlock * getDirectBranchTarget()const; + /** Returns the basic block this branch transfers control to*/ + Node* getTrueTarget() const {return trueTarget;} + void setTrueTarget(Node* node) {trueTarget = node;} + Node* getFalseTarget() const {return falseTarget;} + void setFalseTarget(Node* node) { falseTarget = node;} - /* Reverses direct branch condition and updates target&fallthrough edges - does not affect layout. + /* Reverses direct branch condition and updates target&fallthrough edges + WARN: does not affect layout. */ void reverse(IRManager * irManager); - /* Returns true if the direct branch can be reverted, i.e. it is direct and is conditional */ - bool canReverse()const; + /* Returns true if the direct branch can be reverted, i.e. it is direct and is conditional */ + bool canReverse()const; + + virtual void verify() const; protected: - BranchInst(Mnemonic mnemonic, int id) : ControlTransferInst(mnemonic, id) - {kind=Kind_BranchInst; } - -private: - friend class IRManager; + BranchInst(Mnemonic mnemonic, int id) + : ControlTransferInst(mnemonic, id) , + trueTarget(NULL), falseTarget(NULL) + { + kind=Kind_BranchInst; + } + // called by CFG to detect BB->BB block edges + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + + // called from CFG when edge target is replaced + virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); + + // called from CFG when 2 blocks are merging and one of the branches is redundant. + virtual void removeRedundantBranch(); + + Node* trueTarget; + Node* falseTarget; +}; +//========================================================================================================= +// class JumpInst +//========================================================================================================= +/** class JumpInst is used for unconditional jumps +*/ +class JumpInst: public ControlTransferInst { + friend class IRManager; +protected: + JumpInst(int id) : ControlTransferInst(Mnemonic_JMP, id) { kind = Kind_JmpInst;} + virtual void verify() const; }; //========================================================================================================= // class SwitchInst //========================================================================================================= -/** class SwitchInst is used for all branch instructions: Jcc, JMP +/** class SwitchInst is used for unconditional indirect jumps that use table mapping for targets */ -class SwitchInst: public BranchInst +class SwitchInst : public ControlTransferInst { + friend class IRManager; public: - /** Returns the basic block for index i */ - BasicBlock * getTarget(uint32 i)const; + /** Returns the basic block for index i */ + uint32 getNumTargets() const; + Node* getTarget(uint32 i)const; + /** Sets the basic block for index i */ + void setTarget(uint32 i, Node* bb); - /** Sets the basic block for index i */ - void setTarget(uint32 i, BasicBlock * bb); + Opnd * getTableAddress() const; + + virtual void verify() const; +protected: + SwitchInst(Mnemonic mnemonic, int id, Opnd * addr = 0) : ControlTransferInst(mnemonic, id) +#ifdef _EM64T_ + , tableAddr(addr) +#endif + {kind=Kind_SwitchInst; } - void replaceTarget(BasicBlock * bbFrom, BasicBlock * bbTo); -protected: - SwitchInst(Mnemonic mnemonic, int id) : BranchInst(mnemonic, id) - {kind=Kind_SwitchInst; } + // called by CFG to detect BB->BB block edges + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + // called from CFG when edge target is replaced + virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); + // called from CFG when 2 blocks are merging and one of the branches is redundant. + virtual void removeRedundantBranch(); -private: - friend class IRManager; + void replaceTarget(Node* bbFrom, Node* bbTo); + +#ifdef _EM64T_ + Opnd * tableAddr; +#endif }; @@ -956,55 +1122,55 @@ private: class CallingConventionClient { public: - struct StackOpndInfo - { - uint32 opndIndex; - uint32 offset; - bool operator<(const StackOpndInfo& r)const{ return offset < r.offset; } - }; - - CallingConventionClient(MemoryManager& mm, const CallingConvention * cc) - :callingConvention(cc), defInfos(mm), useInfos(mm), defStackOpndInfos(mm), useStackOpndInfos(mm), defArgStackDepth(0), useArgStackDepth(0){} - - const StlVector & getInfos(Inst::OpndRole role)const - { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } - const StlVector & getStackOpndInfos(Inst::OpndRole role)const - { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } - - void pushInfo(Inst::OpndRole role, Type::Tag typeTag) - { - CallingConvention::OpndInfo info; - info.typeTag=(uint32)typeTag; info.slotCount=0; - StlVector & infos = getInfos(role); - infos.push_back(info); - } - - void finalizeInfos(Inst::OpndRole role, CallingConvention::ArgKind argKind); - void layoutAuxilaryOpnds(Inst::OpndRole role, OpndKind kindForStackArgs); - - const CallingConvention * getCallingConvention()const - { assert(callingConvention!=NULL); return callingConvention; } - - uint32 getArgStackDepth(Inst::OpndRole role)const - { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defArgStackDepth:useArgStackDepth; } - - void setOwnerInst(Inst * oi){ ownerInst = oi; } + struct StackOpndInfo + { + uint32 opndIndex; + uint32 offset; + bool operator<(const StackOpndInfo& r)const{ return offset < r.offset; } + }; + + CallingConventionClient(MemoryManager& mm, const CallingConvention * cc) + :callingConvention(cc), defInfos(mm), useInfos(mm), defStackOpndInfos(mm), useStackOpndInfos(mm), defArgStackDepth(0), useArgStackDepth(0){} + + const StlVector & getInfos(Inst::OpndRole role)const + { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } + const StlVector & getStackOpndInfos(Inst::OpndRole role)const + { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } + + void pushInfo(Inst::OpndRole role, Type::Tag typeTag) + { + CallingConvention::OpndInfo info; + info.typeTag=(uint32)typeTag; info.slotCount=0; + StlVector & infos = getInfos(role); + infos.push_back(info); + } + + void finalizeInfos(Inst::OpndRole role, CallingConvention::ArgKind argKind); + void layoutAuxilaryOpnds(Inst::OpndRole role, OpndKind kindForStackArgs); + + const CallingConvention * getCallingConvention()const + { assert(callingConvention!=NULL); return callingConvention; } + + uint32 getArgStackDepth(Inst::OpndRole role)const + { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defArgStackDepth:useArgStackDepth; } + + void setOwnerInst(Inst * oi){ ownerInst = oi; } protected: - StlVector & getInfos(Inst::OpndRole role) - { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } - StlVector & getStackOpndInfos(Inst::OpndRole role) - { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } + StlVector & getInfos(Inst::OpndRole role) + { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } + StlVector & getStackOpndInfos(Inst::OpndRole role) + { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } - const CallingConvention * callingConvention; + const CallingConvention * callingConvention; - Inst * ownerInst; + Inst * ownerInst; - StlVector defInfos; - StlVector useInfos; - StlVector defStackOpndInfos; - StlVector useStackOpndInfos; - - uint32 defArgStackDepth, useArgStackDepth; + StlVector defInfos; + StlVector useInfos; + StlVector defStackOpndInfos; + StlVector useStackOpndInfos; + + uint32 defArgStackDepth, useArgStackDepth; }; @@ -1012,63 +1178,67 @@ protected: // class EntryPointPseudoInst //========================================================================================================= /** - Class EntryPointPseudoInst represents an entry point for an instruction - and is used as definition point for all incoming arguments + Class EntryPointPseudoInst represents an entry point for an instruction + and is used as definition point for all incoming arguments */ class EntryPointPseudoInst: public Inst { public: - Opnd * getDefArg(uint32 i)const; + virtual bool isHeaderCriticalInst() const {return true;} + + Opnd * getDefArg(uint32 i)const; - uint32 getArgStackDepth()const - { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Def); } + uint32 getArgStackDepth()const + { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Def); } - CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } - const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } + CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } + const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } - virtual bool hasSideEffect()const { return true; } - //-------------------------------------------------------------------- + virtual bool hasSideEffect()const { return true; } + +#ifdef _EM64T_ + Opnd * thisOpnd; +#endif + //-------------------------------------------------------------------- protected: - CallingConventionClient callingConventionClient; + CallingConventionClient callingConventionClient; EntryPointPseudoInst(IRManager * irm, int id, const CallingConvention * cc); - friend class IRManager; + friend class IRManager; }; //========================================================================================================= // class CallInst //========================================================================================================= -/** class BranchInst is used for all calls instructions: CALL +/** class CallInst is used for all calls instructions: CALL */ class CallInst: public ControlTransferInst { public: - uint32 getArgStackDepth()const - { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Use); } - - CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } - const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } + uint32 getArgStackDepth()const + { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Use); } - Constraint getCalleeSaveRegs(OpndKind regKind=OpndKind_GPReg)const - { - return Constraint(regKind, Constraint::getDefaultSize(regKind), callingConventionClient.getCallingConvention()->getCalleeSavedRegs(regKind)); - } + CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } + const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } - Constraint getCallerSaveRegs(OpndKind regKind=OpndKind_GPReg)const; + Constraint getCalleeSaveRegs(OpndKind regKind=OpndKind_GPReg)const + { + return callingConventionClient.getCallingConvention()->getCalleeSavedRegs(regKind); + } - InlineInfo * getInlineInfo() const { return inlineInfo; } + InlineInfo * getInlineInfo() const { return inlineInfo; } protected: - CallingConventionClient callingConventionClient; + CallingConventionClient callingConventionClient; - CallInst(IRManager * irm, int id, const CallingConvention * cc, InlineInfo* ii); + CallInst(IRManager * irm, int id, const CallingConvention * cc, InlineInfo* ii); - //-------------------------------------------------------------------- - friend class IRManager; + //-------------------------------------------------------------------- + friend class IRManager; private: - InlineInfo * inlineInfo; + InlineInfo * inlineInfo; }; //========================================================================================================= @@ -1080,22 +1250,61 @@ class RetInst: public ControlTransferIns { public: RetInst(IRManager * irm, int id); - friend class IRManager; + friend class IRManager; - CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } - const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } + CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } + const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } protected: - CallingConventionClient callingConventionClient; + CallingConventionClient callingConventionClient; + +}; + +//================================================================================== +// class EmptyPseudoInst +//================================================================================== +/** class EmptyPseudoInst is used to fill blocks which should not be considered as an empty +*/ +class EmptyPseudoInst: public Inst { +public: + void makeNative(IRManager * irManager) {} +protected: + EmptyPseudoInst(int id): Inst(Mnemonic_NULL, id, Inst::Form_Extended) { + kind = Kind_EmptyPseudoInst; + } + virtual bool hasSideEffect()const{ return true; } +friend class IRManager; }; +//================================================================================== +// class MethodMarkerPseudoInst +//================================================================================== +/** class MethodMarkerPseudoInst is used to track inlined method boundaries +*/ +class MethodMarkerPseudoInst: public Inst { +public: + MethodDesc* getMethodDesc(){ return methDesc; } + void makeNative(IRManager * irManager) {} +protected: + MethodMarkerPseudoInst(MethodDesc* mDesc, int id, Kind k): Inst(Mnemonic_NULL, id, Inst::Form_Extended) { + kind = k; + methDesc = mDesc; + } + virtual bool hasSideEffect()const{ return true; } + +friend class IRManager; + +private: + MethodDesc* methDesc; + +}; }}; // namespace Ia32 //========================================================================================================= -// class ConstantAreaItem +// class ConstantAreaItem //========================================================================================================= /** class ConstantAreaItem @@ -1103,32 +1312,32 @@ protected: class ConstantAreaItem { public: - enum Kind{ - Kind_ConstantAreaItem=0xffffffff, - Kind_ValueConstantAreaItem=0xff, - Kind_FPSingleConstantAreaItem=0x1, - Kind_FPDoubleConstantAreaItem=0x2, - Kind_InternalStringConstantAreaItem=0x4, - Kind_BinaryConstantAreaItem=0x80, - Kind_SwitchTableConstantAreaItem=0x100, - }; - - ConstantAreaItem(Kind k, uint32 s, const void * v) - :kind(k), size(s), value(v), address(NULL){} - - Kind getKind()const{ return kind; } - bool hasKind(Kind k)const{ return (kind&k)==kind; } - - uint32 getSize()const{ return size; } - void const * getValue()const{ return value; } - - void * getAddress()const { return address; } - void setAddress(void * addr) { address=addr; } + enum Kind{ + Kind_ConstantAreaItem=0xffffffff, + Kind_ValueConstantAreaItem=0xff, + Kind_FPSingleConstantAreaItem=0x1, + Kind_FPDoubleConstantAreaItem=0x2, + Kind_InternalStringConstantAreaItem=0x4, + Kind_BinaryConstantAreaItem=0x80, + Kind_SwitchTableConstantAreaItem=0x100, + }; + + ConstantAreaItem(Kind k, uint32 s, const void * v) + :kind(k), size(s), value(v), address(NULL){} + + Kind getKind()const{ return kind; } + bool hasKind(Kind k)const{ return (kind&k)==kind; } + + uint32 getSize()const{ return size; } + void const * getValue()const{ return value; } + + void * getAddress()const { return address; } + void setAddress(void * addr) { address=addr; } protected: - const Kind kind; - const uint32 size; - void const * value; - void * address; + const Kind kind; + const uint32 size; + void const * value; + void * address; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp index e5d917b..c5817a8 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp @@ -25,6 +25,10 @@ #include "Log.h" #include "Ia32InstCodeSelector.h" #include "Ia32CodeGenerator.h" #include "Ia32Printer.h" +#include "EMInterface.h" +#include "DrlVMInterface.h" +#include "Opcode.h" + #include #include @@ -51,47 +55,47 @@ #define UNORD_FLAGS_MASK 0x4500 ConditionMnemonic getConditionMnemonicFromCompareOperator(CompareOp::Operators cmpOp, CompareOp::Types opType) { - switch(cmpOp){ - case CompareOp::Eq: // equal - return ConditionMnemonic_E; + switch(cmpOp){ + case CompareOp::Eq: // equal + return ConditionMnemonic_E; case CompareOp::Ne: // int: not equal; // fp: not equal or unordered - return ConditionMnemonic_NE; - case CompareOp::Gt: // greater than - return opType==CompareOp::F||opType==CompareOp::D||opType==CompareOp::S?ConditionMnemonic_A:ConditionMnemonic_G; - case CompareOp::Gtu: // int: greater than unsigned; // fp: greater than or unordered - return ConditionMnemonic_A; - case CompareOp::Ge: // greater than or equal - return opType==CompareOp::F||opType==CompareOp::D||opType==CompareOp::S?ConditionMnemonic_AE:ConditionMnemonic_GE; + return ConditionMnemonic_NE; + case CompareOp::Gt: // greater than + return opType==CompareOp::F||opType==CompareOp::D||opType==CompareOp::S?ConditionMnemonic_A:ConditionMnemonic_G; + case CompareOp::Gtu: // int: greater than unsigned; // fp: greater than or unordered + return ConditionMnemonic_A; + case CompareOp::Ge: // greater than or equal + return opType==CompareOp::F||opType==CompareOp::D||opType==CompareOp::S?ConditionMnemonic_AE:ConditionMnemonic_GE; case CompareOp::Geu: // int: greater than or equal unsigned; - return ConditionMnemonic_AE; - default: - assert(0); + return ConditionMnemonic_AE; + default: + assert(0); - } - return ConditionMnemonic_E; + } + return ConditionMnemonic_E; } CompareOp::Types getCompareOpTypesFromCompareZeroOpTypes(CompareZeroOp::Types t) { - switch (t){ - case CompareZeroOp::I4: return CompareOp::I4; - case CompareZeroOp::I8: return CompareOp::I8; - case CompareZeroOp::I: return CompareOp::I; - case CompareZeroOp::Ref: return CompareOp::Ref; - case CompareZeroOp::CompRef: return CompareOp::CompRef; - } - assert(0); - return CompareOp::I4; + switch (t){ + case CompareZeroOp::I4: return CompareOp::I4; + case CompareZeroOp::I8: return CompareOp::I8; + case CompareZeroOp::I: return CompareOp::I; + case CompareZeroOp::Ref: return CompareOp::Ref; + case CompareZeroOp::CompRef: return CompareOp::CompRef; + } + assert(0); + return CompareOp::I4; } bool swapIfLastIs(Opnd *& opnd0, Opnd *& opnd1, Constraint c=OpndKind_Imm) { - if (opnd1!=NULL && opnd0->isPlacedIn(c)){ - Opnd * opnd=opnd0; - opnd0=opnd1; opnd1=opnd; - return true; - } - return false; + if (opnd1!=NULL && opnd0->isPlacedIn(c)){ + Opnd * opnd=opnd0; + opnd0=opnd1; opnd1=opnd; + return true; + } + return false; } /////////////////////////////////////////////////////////////////////////////////// @@ -109,46 +113,62 @@ double dnan = *( double* )dNaNMask; unsigned long fNaNMask[1]={0x7fffffff}; float fnan = *( float* )dNaNMask; -double __stdcall convF4F8 (float v) stdcall__; -double __stdcall convF4F8 (float v) { return (double)v; } +double __stdcall convF4F8 (float v) stdcall__; +double __stdcall convF4F8 (float v) { return (double)v; } -float __stdcall convF8F4 (double v) stdcall__; -float __stdcall convF8F4 (double v) { return (float)v; } +float __stdcall convF8F4 (double v) stdcall__; +float __stdcall convF8F4 (double v) { return (float)v; } -double __stdcall convI4F8 (uint32 v) stdcall__; -double __stdcall convI4F8 (uint32 v) { - return (double)(int32)v; } +double __stdcall convI4F8 (uint32 v) stdcall__; +double __stdcall convI4F8 (uint32 v) { + return (double)(int32)v; } -float __stdcall convI4F4 (uint32 v) stdcall__; -float __stdcall convI4F4 (uint32 v) { return (float)(int32)v; } +float __stdcall convI4F4 (uint32 v) stdcall__; +float __stdcall convI4F4 (uint32 v) { return (float)(int32)v; } -double __stdcall convI8F8 (uint64 v) stdcall__; -double __stdcall convI8F8 (uint64 v) { return (double)(int64)v; } +double __stdcall convI8F8 (uint64 v) stdcall__; +double __stdcall convI8F8 (uint64 v) { return (double)(int64)v; } -float __stdcall convI8F4 (uint64 v) stdcall__; -float __stdcall convI8F4 (uint64 v) { return (float)(int64)v; } +float __stdcall convI8F4 (uint64 v) stdcall__; +float __stdcall convI8F4 (uint64 v) { return (float)(int64)v; } // FP remainder internal helpers (temp solution to be optimized) -float __stdcall remF4 (float v0, float v1)stdcall__; -float __stdcall remF4 (float v0, float v1) { - if(_isnan(v0) || _isnan(v1)|| (!_finite(v0)) || (v1==float(0.0))) { - return fnan; - } else if (!_finite(v1)){ - return v0; - } else { - return v0-float(int64(v0/v1))*v1; - } -} - -double __stdcall remF8 (double v0, double v1)stdcall__; -double __stdcall remF8 (double v0, double v1) { - if(_isnan(v0) || _isnan(v1) || (!_finite(v0)) || (v1==double(0.0))) { - return dnan; - } else if (!_finite(v1)){ - return v0; - } else { - return v0-double(int64(v0/v1))*v1; - } +float __stdcall remF4 (float v0, float v1)stdcall__; +float __stdcall remF4 (float v0, float v1) { + if(_isnan(v0) || _isnan(v1)|| (!_finite(v0)) || (v1==float(0.0))) { + return fnan; + } else if (!_finite(v1)){ + return v0; + } + float result = v0-float(int64(v0/v1))*v1; + if (result == 0 && v1 < 0) { +#ifdef PLATFORM_POSIX + return copysign(result, v1); +#else + return (float)_copysign(result, v1); +#endif + } else { + return result; + } +} + +double __stdcall remF8 (double v0, double v1)stdcall__; +double __stdcall remF8 (double v0, double v1) { + if(_isnan(v0) || _isnan(v1) || (!_finite(v0)) || (v1==double(0.0))) { + return dnan; + } else if (!_finite(v1)){ + return v0; + } + double result = v0-double(int64(v0/v1))*v1; + if (result == 0 && v1 < 0) { +#ifdef PLATFORM_POSIX + return copysign(result, v1); +#else + return _copysign(result, v1); +#endif + } else { + return result; + } } void __stdcall initialize_array(uint8* array, uint32 elems_offset, uint8* data, uint32 num_elems) stdcall__; @@ -166,16 +186,16 @@ uint32 InstCodeSelector::_tauUnsafe; void InstCodeSelector::onCFGInit(IRManager& irManager) { // FP conversion internal helpers (temp solution to be optimized) - irManager.registerInternalHelperInfo("convF4F8", IRManager::InternalHelperInfo((void*)&convF4F8,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("convF8F4", IRManager::InternalHelperInfo((void*)&convF8F4,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("convI4F8", IRManager::InternalHelperInfo((void*)&convI4F8,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("convI4F4", IRManager::InternalHelperInfo((void*)&convI4F4,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("convI8F8", IRManager::InternalHelperInfo((void*)&convI8F8,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("convI8F4", IRManager::InternalHelperInfo((void*)&convI8F4,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convF4F8", IRManager::InternalHelperInfo((void*)&convF4F8,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convF8F4", IRManager::InternalHelperInfo((void*)&convF8F4,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convI4F8", IRManager::InternalHelperInfo((void*)&convI4F8,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convI4F4", IRManager::InternalHelperInfo((void*)&convI4F4,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convI8F8", IRManager::InternalHelperInfo((void*)&convI8F8,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("convI8F4", IRManager::InternalHelperInfo((void*)&convI8F4,&CallingConvention_STDCALL)); // FP remainder internal helpers (temp solution to be optimized) - irManager.registerInternalHelperInfo("remF8", IRManager::InternalHelperInfo((void*)&remF8,&CallingConvention_STDCALL)); - irManager.registerInternalHelperInfo("remF4", IRManager::InternalHelperInfo((void*)&remF4,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("remF8", IRManager::InternalHelperInfo((void*)&remF8,&CallingConvention_STDCALL)); + irManager.registerInternalHelperInfo("remF4", IRManager::InternalHelperInfo((void*)&remF4,&CallingConvention_STDCALL)); irManager.registerInternalHelperInfo("initialize_array", IRManager::InternalHelperInfo((void*)&initialize_array,&CallingConvention_STDCALL)); } @@ -184,12 +204,12 @@ void InstCodeSelector::onCFGInit(IRManag // Constructor InstCodeSelector:: -InstCodeSelector(CompilationInterface& compIntfc, - CfgCodeSelector& codeSel, - IRManager& irM, - BasicBlock * currBasicBlock - ) -: compilationInterface(compIntfc), codeSelector(codeSel), +InstCodeSelector(CompilationInterface& compIntfc, + CfgCodeSelector& codeSel, + IRManager& irM, + Node * currBasicBlock + ) +: compilationInterface(compIntfc), codeSelector(codeSel), irManager(irM), typeManager(irM.getTypeManager()), memManager(0x2000, "InstCodeSelector"), currentBasicBlock(currBasicBlock), @@ -206,26 +226,25 @@ #endif //_______________________________________________________________________________________________________________ Inst * InstCodeSelector::appendInsts(Inst *inst) { - assert(currentBasicBlock); + assert(currentBasicBlock); if (compilationInterface.isBCMapInfoRequired()) { uint64 bcOffset = codeSelector.bc2HIRmapHandler->getVectorEntry(currentHIRInstrID); - //POINTER_SIZE_INT instAddr = (POINTER_SIZE_INT) inst; uint64 insID = inst->getId(); if (bcOffset != ILLEGAL_VALUE) codeSelector.bc2LIRmapHandler->setVectorEntry(insID, bcOffset); } - if (Log::cat_cg()->isIREnabled()){ - Inst * i=inst; - do { - Log::out()<<"\tIA32 inst: "; - IRPrinter::printInst(Log::out(), i); - Log::out()<<::std::endl; - i=i->getNext(); - }while (i!=inst); - } + if (Log::isEnabled()){ + Inst * i=inst; + do { + Log::out()<<"\tIA32 inst: "; + IRPrinter::printInst(Log::out(), i); + Log::out()<<::std::endl; + i=i->getNext(); + }while (i!=inst); + } - currentBasicBlock->appendInsts(inst); + currentBasicBlock->appendInst(inst); - return inst; + return inst; } //_______________________________________________________________________________________________________________ @@ -238,164 +257,170 @@ void InstCodeSelector::opndMaybeGlobal(C //_______________________________________________________________________________________________________________ void InstCodeSelector::copyOpndTrivialOrTruncatingConversion(Opnd *dst, Opnd *src) { - assert(dst->getSize()<=src->getSize()); - if (src->getType()->isInteger()&&src->getSize()==OpndSize_64) - appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV, 1, dst, src)); - else - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, src)); + assert(dst->getSize()<=src->getSize()); +#ifndef _EM64T_ + if (src->getType()->isInteger()&&src->getSize()==OpndSize_64) + appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV, 1, dst, src)); + else +#endif + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, src)); } //_______________________________________________________________________________________________________________ // Copy any kind of the operand void InstCodeSelector::copyOpnd(Opnd *dst, Opnd *src) { - convert(src, dst->getType(), dst); + convert(src, dst->getType(), dst); } //_______________________________________________________________________________________________________________ void InstCodeSelector::throwLinkingException(Class_Handle encClass, uint32 cp_ndx, uint32 opcode) { - Opnd* encClassArg = irManager.newImmOpnd(getRuntimeIdType(), (POINTER_SIZE_INT)encClass); - Opnd* cpIndexArg = irManager.newImmOpnd(typeManager.getUInt32Type(),cp_ndx); + Opnd* encClassArg = irManager.newImmOpnd(getRuntimeIdType(), (POINTER_SIZE_INT)encClass); + Opnd* cpIndexArg = irManager.newImmOpnd(typeManager.getUInt32Type(),cp_ndx); Opnd* opcodeArg = irManager.newImmOpnd(typeManager.getUInt32Type(), opcode); - Opnd* args[] = {encClassArg, cpIndexArg, opcodeArg}; - appendInsts(irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_Throw_LinkingException, lengthof(args), args, NULL)); + Opnd* args[] = {encClassArg, cpIndexArg, opcodeArg}; + appendInsts(irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_Throw_LinkingException, lengthof(args), args, NULL)); } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::convertIntToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd) { - Type * srcType=srcOpnd->getType(); - assert(isIntegerType(srcType) && isIntegerType(dstType)); + Type * srcType=srcOpnd->getType(); + assert(isIntegerType(srcType) && isIntegerType(dstType)); - OpndSize srcSize=irManager.getTypeSize(srcType); + OpndSize srcSize=irManager.getTypeSize(srcType); OpndSize dstSize=irManager.getTypeSize(dstType); - - if (dstSize==srcSize){ // trivial conversion without changing type - if (dstOpnd==NULL) - dstOpnd=srcOpnd; - else - copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); - }else if (dstSize<=srcSize){ // truncating conversion - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(dstType); - copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); - }else{ - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(dstType); - if (dstSizeisSignedInteger()?Mnemonic_MOVSX:Mnemonic_MOVZX, 1, dstOpnd, srcOpnd)); - }else{ - appendInsts(irManager.newI8PseudoInst(srcType->isSignedInteger()?Mnemonic_MOVSX:Mnemonic_MOVZX, 1, dstOpnd, srcOpnd)); - } - } - - return dstOpnd; + + if (dstSize==srcSize){ // trivial conversion without changing type + if (dstOpnd==NULL) + dstOpnd=srcOpnd; + else + copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); + }else if (dstSize<=srcSize){ // truncating conversion + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(dstType); + copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); + }else{ + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(dstType); +#ifdef _EM64T_ + appendInsts(irManager.newInstEx(srcType->isSignedInteger()?Mnemonic_MOVSX:Mnemonic_MOVZX, 1, dstOpnd, srcOpnd)); +#else + if (dstSizeisSignedInteger()?Mnemonic_MOVSX:Mnemonic_MOVZX, 1, dstOpnd, srcOpnd)); + }else{ + appendInsts(irManager.newI8PseudoInst(srcType->isSignedInteger()?Mnemonic_MOVSX:Mnemonic_MOVZX, 1, dstOpnd, srcOpnd)); + } +#endif + } + + return dstOpnd; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::convertIntToFp(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd) { - assert(srcOpnd->getType()->isInteger() && dstType->isFP()); - OpndSize srcSize=srcOpnd->getSize(); - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(dstType); - const char * helperName; - if (srcSize<=OpndSize_32){ - if (srcSizeisSingle()?"convI4F4":"convI4F8"; - }else{ - assert(srcSize==OpndSize_64); - helperName=dstType->isSingle()?"convI8F4":"convI8F8"; - } - Opnd * args[] = {srcOpnd}; - appendInsts(irManager.newInternalRuntimeHelperCallInst(helperName, 1, args, dstOpnd)); - return dstOpnd; + assert(srcOpnd->getType()->isInteger() && dstType->isFP()); + OpndSize srcSize=srcOpnd->getSize(); + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(dstType); + const char * helperName; + if (srcSize<=OpndSize_32){ + if (srcSizeisSingle()?"convI4F4":"convI4F8"; + }else{ + assert(srcSize==OpndSize_64); + helperName=dstType->isSingle()?"convI8F4":"convI8F8"; + } + Opnd * args[] = {srcOpnd}; + appendInsts(irManager.newInternalRuntimeHelperCallInst(helperName, 1, args, dstOpnd)); + return dstOpnd; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::convertFpToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd) { - assert(srcOpnd->getType()->isFP() && dstType->isInteger()); - CompilationInterface::RuntimeHelperId helperId; - OpndSize dstSize=irManager.getTypeSize(dstType); - if (dstSize<=OpndSize_32){ - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(typeManager.getInt32Type()); - helperId=srcOpnd->getType()->isSingle()?CompilationInterface::Helper_ConvStoI32:CompilationInterface::Helper_ConvDtoI32; - }else{ - assert(dstSize==OpndSize_64); - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(dstType); - helperId=srcOpnd->getType()->isSingle()?CompilationInterface::Helper_ConvStoI64:CompilationInterface::Helper_ConvDtoI64; - } + assert(srcOpnd->getType()->isFP() && dstType->isInteger()); + CompilationInterface::RuntimeHelperId helperId; + OpndSize dstSize=irManager.getTypeSize(dstType); + if (dstSize<=OpndSize_32){ + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(typeManager.getInt32Type()); + helperId=srcOpnd->getType()->isSingle()?CompilationInterface::Helper_ConvStoI32:CompilationInterface::Helper_ConvDtoI32; + }else{ + assert(dstSize==OpndSize_64); + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(dstType); + helperId=srcOpnd->getType()->isSingle()?CompilationInterface::Helper_ConvStoI64:CompilationInterface::Helper_ConvDtoI64; + } - Opnd * args[] = {srcOpnd}; - appendInsts(irManager.newRuntimeHelperCallInst(helperId, 1, args, dstOpnd)); + Opnd * args[] = {srcOpnd}; + appendInsts(irManager.newRuntimeHelperCallInst(helperId, 1, args, dstOpnd)); - if (dstSizegetType(); - assert(srcType->isFP() && dstType->isFP()); - if ((srcType->isSingle() && dstType->isSingle())||!(srcType->isSingle() || dstType->isSingle())){ - if (!dstOpnd) - return srcOpnd; - copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); - return dstOpnd; - } - if (dstOpnd==NULL) - dstOpnd=irManager.newOpnd(dstType); - const char * helperName=dstType->isSingle()?"convF8F4":"convF4F8"; - Opnd * args[] = {srcOpnd}; - appendInsts(irManager.newInternalRuntimeHelperCallInst(helperName, 1, args, dstOpnd)); - return dstOpnd; + Type * srcType=srcOpnd->getType(); + assert(srcType->isFP() && dstType->isFP()); + if ((srcType->isSingle() && dstType->isSingle())||!(srcType->isSingle() || dstType->isSingle())){ + if (!dstOpnd) + return srcOpnd; + copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); + return dstOpnd; + } + if (dstOpnd==NULL) + dstOpnd=irManager.newOpnd(dstType); + const char * helperName=dstType->isSingle()?"convF8F4":"convF4F8"; + Opnd * args[] = {srcOpnd}; + appendInsts(irManager.newInternalRuntimeHelperCallInst(helperName, 1, args, dstOpnd)); + return dstOpnd; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::convert(CG_OpndHandle * oph, Type * dstType, Opnd * dstOpnd) { - if (!oph) - return NULL; - Opnd * srcOpnd=(Opnd*)oph; - - Type * srcType=srcOpnd->getType(); - bool converted=false; - if (isIntegerType(srcType)){ - if (isIntegerType(dstType)){ - dstOpnd=convertIntToInt(srcOpnd, dstType, dstOpnd); - converted=true; - }else if (dstType->isFP()){ - dstOpnd=convertIntToFp(srcOpnd, dstType, dstOpnd); - converted=true; - } - }else if (srcType->isFP()){ - if (dstType->isInteger()){ - dstOpnd=convertFpToInt(srcOpnd, dstType, dstOpnd); - converted=true; - }else if (dstType->isFP()){ - dstOpnd=convertFpToFp(srcOpnd, dstType, dstOpnd); - converted=true; - } - } - - if (!converted){ - assert(irManager.getTypeSize(dstType)==srcOpnd->getSize()); - if (dstOpnd==NULL) - dstOpnd=srcOpnd; - else - copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); - } - - return dstOpnd; + if (!oph) + return NULL; + Opnd * srcOpnd=(Opnd*)oph; + + Type * srcType=srcOpnd->getType(); + bool converted=false; + if (isIntegerType(srcType)){ + if (isIntegerType(dstType)){ + dstOpnd=convertIntToInt(srcOpnd, dstType, dstOpnd); + converted=true; + }else if (dstType->isFP()){ + dstOpnd=convertIntToFp(srcOpnd, dstType, dstOpnd); + converted=true; + } + }else if (srcType->isFP()){ + if (dstType->isInteger()){ + dstOpnd=convertFpToInt(srcOpnd, dstType, dstOpnd); + converted=true; + }else if (dstType->isFP()){ + dstOpnd=convertFpToFp(srcOpnd, dstType, dstOpnd); + converted=true; + } + } + + if (!converted){ + assert(irManager.getTypeSize(dstType)==srcOpnd->getSize()); + if (dstOpnd==NULL) + dstOpnd=srcOpnd; + else + copyOpndTrivialOrTruncatingConversion(dstOpnd, srcOpnd); + } + + return dstOpnd; } @@ -408,25 +433,25 @@ CG_OpndHandle* InstCodeSelector::convToI Type* dstType, CG_OpndHandle* src) { - Type * sizeType=NULL; - switch (opType){ - case ConvertToIntOp::I1: - sizeType=isSigned?typeManager.getInt8Type():typeManager.getUInt8Type(); - break; - case ConvertToIntOp::I2: - sizeType=isSigned?typeManager.getInt16Type():typeManager.getUInt16Type(); - break; - case ConvertToIntOp::I: - case ConvertToIntOp::I4: - sizeType=isSigned?typeManager.getInt32Type():typeManager.getUInt32Type(); - break; - case ConvertToIntOp::I8: - sizeType=typeManager.getInt64Type(); - break; - default: assert(0); - } - Opnd * tmpOpnd=convert(src, sizeType); - return convert(tmpOpnd, dstType); + Type * sizeType=NULL; + switch (opType){ + case ConvertToIntOp::I1: + sizeType=isSigned?typeManager.getInt8Type():typeManager.getUInt8Type(); + break; + case ConvertToIntOp::I2: + sizeType=isSigned?typeManager.getInt16Type():typeManager.getUInt16Type(); + break; + case ConvertToIntOp::I: + case ConvertToIntOp::I4: + sizeType=isSigned?typeManager.getInt32Type():typeManager.getUInt32Type(); + break; + case ConvertToIntOp::I8: + sizeType=typeManager.getInt64Type(); + break; + default: assert(0); + } + Opnd * tmpOpnd=convert(src, sizeType); + return convert(tmpOpnd, dstType); } //_______________________________________________________________________________________________________________ @@ -436,64 +461,67 @@ CG_OpndHandle* InstCodeSelector::convTo Type* dstType, CG_OpndHandle* src) { - return convert(src, dstType); + return convert(src, dstType); } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::createResultOpnd(Type * dstType) { - if (dstType==NULL) - return NULL; + if (dstType==NULL) + return NULL; return irManager.newOpnd(dstType); } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::simpleOp_I8(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2) { - dstType=irManager.getTypeFromTag(Type::Int64); - src1=convert(src1, dstType); - - if (src2!=NULL){ - src2=convert(src2, dstType); - } - Opnd * dst = irManager.newOpnd(dstType); + src1=convert(src1, dstType); - switch(mn){ - case Mnemonic_ADD: - case Mnemonic_SUB: - case Mnemonic_AND: - case Mnemonic_OR: - case Mnemonic_XOR: - case Mnemonic_NOT: - appendInsts(irManager.newI8PseudoInst(mn, 1, dst, (Opnd *)src1, (Opnd *)src2)); - break; - default: - assert(0); - break; - } + if (src2!=NULL){ + src2=convert(src2, dstType); + } + Opnd * dst = irManager.newOpnd(dstType); + + switch(mn){ + case Mnemonic_ADD: + case Mnemonic_SUB: + case Mnemonic_AND: + case Mnemonic_OR: + case Mnemonic_XOR: + case Mnemonic_NOT: +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(mn, 1, dst, src1, src2)); +#else + appendInsts(irManager.newInstEx(mn, 1, dst, src1, src2)); +#endif + break; + default: + assert(0); + break; + } - return dst; + return dst; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::fpOp(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2) { - Opnd * dst=irManager.newOpnd(dstType); - Opnd * srcOpnd1=(Opnd*)convert(src1, dstType), * srcOpnd2=(Opnd*)convert(src2, dstType); - appendInsts(irManager.newInstEx(mn, 1, dst, srcOpnd1, srcOpnd2)); - return dst; + Opnd * dst=irManager.newOpnd(dstType); + Opnd * srcOpnd1=(Opnd*)convert(src1, dstType), * srcOpnd2=(Opnd*)convert(src2, dstType); + appendInsts(irManager.newInstEx(mn, 1, dst, srcOpnd1, srcOpnd2)); + return dst; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::simpleOp_I4(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2) { - Opnd * dst=irManager.newOpnd(dstType); - Opnd * srcOpnd1=(Opnd*)convert(src1, dstType), * srcOpnd2=src2==NULL?NULL:(Opnd*)convert(src2, dstType); - if (Encoder::getMnemonicProperties(mn)&Inst::Properties_Symmetric) - swapIfLastIs(srcOpnd1, srcOpnd2); - appendInsts(irManager.newInstEx(mn, 1, dst, srcOpnd1, srcOpnd2)); - return dst; + Opnd * dst=irManager.newOpnd(dstType); + Opnd * srcOpnd1=(Opnd*)convert(src1, dstType), * srcOpnd2=src2==NULL?NULL:(Opnd*)convert(src2, dstType); + if (Encoder::getMnemonicProperties(mn)&Inst::Properties_Symmetric) + swapIfLastIs(srcOpnd1, srcOpnd2); + appendInsts(irManager.newInstEx(mn, 1, dst, srcOpnd1, srcOpnd2)); + return dst; } //_______________________________________________________________________________________________________________ @@ -503,23 +531,23 @@ CG_OpndHandle* InstCodeSelector::add(Ari CG_OpndHandle* src1, CG_OpndHandle* src2) { - switch(opType){ - case ArithmeticOp::I4: - case ArithmeticOp::I:{ - Type * dstType=opType==ArithmeticOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_ADD, dstType, (Opnd*)src1, (Opnd*)src2); - } - case ArithmeticOp::I8: - return simpleOp_I8(Mnemonic_ADD, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); - case ArithmeticOp::D: - case ArithmeticOp::F: - return fpOp(Mnemonic_ADDSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); - case ArithmeticOp::S: - return fpOp(Mnemonic_ADDSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case ArithmeticOp::I4: + case ArithmeticOp::I:{ + Type * dstType=opType==ArithmeticOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_ADD, dstType, (Opnd*)src1, (Opnd*)src2); + } + case ArithmeticOp::I8: + return simpleOp_I8(Mnemonic_ADD, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); + case ArithmeticOp::D: + case ArithmeticOp::F: + return fpOp(Mnemonic_ADDSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); + case ArithmeticOp::S: + return fpOp(Mnemonic_ADDSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + return NULL; } //_______________________________________________________________________________________________________________ @@ -529,23 +557,23 @@ CG_OpndHandle* InstCodeSelector::sub(Ari CG_OpndHandle* src1, CG_OpndHandle* src2) { - switch(opType){ - case ArithmeticOp::I4: - case ArithmeticOp::I:{ - Type * dstType=opType==ArithmeticOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_SUB, dstType, (Opnd*)src1, (Opnd*)src2); - } - case ArithmeticOp::I8: - return simpleOp_I8(Mnemonic_SUB, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); - case ArithmeticOp::D: - case ArithmeticOp::F: - return fpOp(Mnemonic_SUBSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); - case ArithmeticOp::S: - return fpOp(Mnemonic_SUBSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case ArithmeticOp::I4: + case ArithmeticOp::I:{ + Type * dstType=opType==ArithmeticOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_SUB, dstType, (Opnd*)src1, (Opnd*)src2); + } + case ArithmeticOp::I8: + return simpleOp_I8(Mnemonic_SUB, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); + case ArithmeticOp::D: + case ArithmeticOp::F: + return fpOp(Mnemonic_SUBSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); + case ArithmeticOp::S: + return fpOp(Mnemonic_SUBSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + return NULL; } @@ -556,7 +584,7 @@ CG_OpndHandle* InstCodeSelector::addRef( CG_OpndHandle* refSrc, CG_OpndHandle* intSrc) { - return add(opType==RefArithmeticOp::I?ArithmeticOp::I:ArithmeticOp::I4, refSrc, intSrc); + return add(opType==RefArithmeticOp::I?ArithmeticOp::I:ArithmeticOp::I4, refSrc, intSrc); } //_______________________________________________________________________________________________________________ @@ -566,7 +594,7 @@ CG_OpndHandle* InstCodeSelector::subRef( CG_OpndHandle* refSrc, CG_OpndHandle* intSrc) { - return sub(opType==RefArithmeticOp::I?ArithmeticOp::I:ArithmeticOp::I4, refSrc, intSrc); + return sub(opType==RefArithmeticOp::I?ArithmeticOp::I:ArithmeticOp::I4, refSrc, intSrc); } //_______________________________________________________________________________________________________________ @@ -576,25 +604,27 @@ CG_OpndHandle* InstCodeSelector::diff CG_OpndHandle* ref1, CG_OpndHandle* ref2) { - return sub(ArithmeticOp::I4, ref1, ref2); + return sub(ArithmeticOp::I4, ref1, ref2); } //_______________________________________________________________________________________________________________ // Subtract reference from reference and scale down by element type. CG_OpndHandle* InstCodeSelector::scaledDiffRef(CG_OpndHandle* ref1, - CG_OpndHandle* ref2) + CG_OpndHandle* ref2, + Type* type1, + Type* type2) { Opnd* r1 = (Opnd*)ref1; - Type * elemRefType = r1->getType(); + Type * elemRefType = r1->getType(); #ifdef _DEBUG Opnd* r2 = (Opnd*)ref2; - assert( elemRefType->isManagedPtr() && elemRefType==r2->getType() ); + assert( elemRefType->isManagedPtr() && elemRefType==r2->getType() ); #endif Type * elemType = ((PtrType *)elemRefType)->getPointedToType(); - uint32 size = getByteSize(irManager.getTypeSize(elemType)); + uint32 size = getByteSize(irManager.getTypeSize(elemType)); assert(size > 0); uint32 shift; switch(size) { @@ -612,12 +642,12 @@ #endif return NULL; } - Opnd *dstOpnd = (Opnd *)diffRef(false, ref1, ref2); + Opnd *dstOpnd = (Opnd *)diffRef(false, ref1, ref2); if(shift == 0) { return dstOpnd; } else { - return shr(IntegerOp::I4,dstOpnd,irManager.newImmOpnd(typeManager.getUInt8Type(),shift)); + return shr(IntegerOp::I4,dstOpnd,irManager.newImmOpnd(typeManager.getUInt8Type(),shift)); } } @@ -628,39 +658,42 @@ CG_OpndHandle* InstCodeSelector::mul(Ari CG_OpndHandle* src1, CG_OpndHandle* src2) { - Type * dstType; - Opnd * dst, * srcOpnd1, * srcOpnd2; - switch(opType){ - case ArithmeticOp::I4: - case ArithmeticOp::I: - { - dstType=irManager.getTypeFromTag(Type::Int32); - dst=irManager.newOpnd(dstType); - srcOpnd1=(Opnd*)convert(src1, dstType); - srcOpnd2=(Opnd*)convert(src2, dstType); - swapIfLastIs(srcOpnd1, srcOpnd2); - appendInsts(irManager.newInstEx(Mnemonic_IMUL, 1, dst, srcOpnd1, srcOpnd2)); - return dst; - } - case ArithmeticOp::I8: - dstType=irManager.getTypeFromTag(Type::Int64); - dst=irManager.newOpnd(dstType); - srcOpnd1=(Opnd*)convert(src1, dstType); - srcOpnd2=(Opnd*)convert(src2, dstType); - swapIfLastIs(srcOpnd1, srcOpnd2); - - appendInsts(irManager.newI8PseudoInst(Mnemonic_IMUL,1,dst,srcOpnd1,srcOpnd2)); - return dst; - case ArithmeticOp::D: - case ArithmeticOp::F: - return fpOp(Mnemonic_MULSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); - case ArithmeticOp::S: - return fpOp(Mnemonic_MULSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - - return NULL; + Type * dstType; + Opnd * dst, * srcOpnd1, * srcOpnd2; + switch(opType){ + case ArithmeticOp::I4: + case ArithmeticOp::I: + { + dstType=irManager.getTypeFromTag(Type::Int32); + dst=irManager.newOpnd(dstType); + srcOpnd1=(Opnd*)convert(src1, dstType); + srcOpnd2=(Opnd*)convert(src2, dstType); + swapIfLastIs(srcOpnd1, srcOpnd2); + appendInsts(irManager.newInstEx(Mnemonic_IMUL, 1, dst, srcOpnd1, srcOpnd2)); + return dst; + } + case ArithmeticOp::I8: + dstType=irManager.getTypeFromTag(Type::Int64); + dst=irManager.newOpnd(dstType); + srcOpnd1=(Opnd*)convert(src1, dstType); + srcOpnd2=(Opnd*)convert(src2, dstType); + swapIfLastIs(srcOpnd1, srcOpnd2); +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(Mnemonic_IMUL,1,dst,srcOpnd1,srcOpnd2)); +#else + appendInsts(irManager.newInstEx(Mnemonic_IMUL,1,dst,srcOpnd1,srcOpnd2)); +#endif + return dst; + case ArithmeticOp::D: + case ArithmeticOp::F: + return fpOp(Mnemonic_MULSD, irManager.getTypeFromTag(Type::Double), (Opnd*)src1, (Opnd*)src2); + case ArithmeticOp::S: + return fpOp(Mnemonic_MULSS, irManager.getTypeFromTag(Type::Single), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + + return NULL; } //_______________________________________________________________________________________________________________ @@ -671,71 +704,81 @@ CG_OpndHandle* InstCodeSelector::mulhi(M CG_OpndHandle* src2) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::divOp(DivOp::Types opType, bool rem, Opnd * src1, Opnd * src2) { - Opnd * dst=NULL; - Type * dstType; - Opnd * srcOpnd1, * srcOpnd2; - switch(opType){ - case DivOp::I: - case DivOp::I4: - { - dstType=irManager.getTypeFromTag(Type::Int32); - Opnd * dstOpnd0=irManager.newOpnd(dstType); - Opnd * dstOpnd1=irManager.newOpnd(dstType); - Opnd * srcOpnd1=(Opnd*)convert(src1, dstType); - appendInsts(irManager.newInstEx(Mnemonic_CDQ, 1, dstOpnd1, srcOpnd1)); - appendInsts(irManager.newInstEx(Mnemonic_IDIV, 2, dstOpnd1, dstOpnd0, dstOpnd1, srcOpnd1, (Opnd*)convert(src2, dstType))); - dst=rem?dstOpnd1:dstOpnd0; - break; - } - case DivOp::I8: - dstType=irManager.getTypeFromTag(Type::Int64); - dst=irManager.newOpnd(dstType); - srcOpnd1=(Opnd*)convert(src1, dstType); - srcOpnd2=(Opnd*)convert(src2, dstType); - - if (rem) { - Opnd * args[]={ srcOpnd1, srcOpnd2 }; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_RemI64, 2, args, dst); - appendInsts(callInst); - } else { - appendInsts(irManager.newI8PseudoInst(Mnemonic_IDIV, 1, dst,srcOpnd1,srcOpnd2)); - } - break; - case DivOp::D: - case DivOp::F: - if(rem) { - dstType=irManager.getTypeFromTag(Type::Double); - dst=irManager.newOpnd(dstType); - Opnd * args[]={ (Opnd*)convert(src1, dstType), (Opnd*)convert(src2, dstType) }; - CallInst * callInst=irManager.newInternalRuntimeHelperCallInst("remF8", 2, args, dst); - appendInsts(callInst); - } else { - return fpOp(Mnemonic_DIVSD, irManager.getTypeFromTag(Type::Double), src1, src2); - } - break; - - case DivOp::S: - if(rem) { - dstType=irManager.getTypeFromTag(Type::Single); - dst=irManager.newOpnd(dstType); - Opnd * args[]={ (Opnd*)convert(src1, dstType), (Opnd*)convert(src2, dstType) }; - CallInst * callInst=irManager.newInternalRuntimeHelperCallInst("remF4", 2, args, dst); - appendInsts(callInst); - } else { - return fpOp(Mnemonic_DIVSS, irManager.getTypeFromTag(Type::Single), src1, src2); - } - break; - default: - ICS_ASSERT(0); - } - return dst; + Opnd * dst=NULL; + Type * dstType; + Opnd * srcOpnd1, * srcOpnd2; + switch(opType){ + case DivOp::I: + case DivOp::I4: + { + dstType=irManager.getTypeFromTag(Type::Int32); + Opnd * dstOpnd0=irManager.newOpnd(dstType); + Opnd * dstOpnd1=irManager.newOpnd(dstType); + Opnd * srcOpnd1=(Opnd*)convert(src1, dstType); + appendInsts(irManager.newInstEx(Mnemonic_CDQ, 1, dstOpnd1, srcOpnd1)); + appendInsts(irManager.newInstEx(Mnemonic_IDIV, 2, dstOpnd1, dstOpnd0, dstOpnd1, srcOpnd1, (Opnd*)convert(src2, dstType))); + dst=rem?dstOpnd1:dstOpnd0; + break; + } + case DivOp::I8: + { + dstType=irManager.getTypeFromTag(Type::Int64); + dst=irManager.newOpnd(dstType); + srcOpnd1=(Opnd*)convert(src1, dstType); + srcOpnd2=(Opnd*)convert(src2, dstType); + +#ifndef _EM64T_ + if (rem) { + Opnd * args[]={ srcOpnd1, srcOpnd2 }; + CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_RemI64, 2, args, dst); + appendInsts(callInst); + } else { + appendInsts(irManager.newI8PseudoInst(Mnemonic_IDIV, 1, dst,srcOpnd1,srcOpnd2)); + } +#else + Opnd * dstOpnd0=irManager.newOpnd(dstType); + Opnd * dstOpnd1=irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_CDQ, 1, dstOpnd1, srcOpnd1)); + appendInsts(irManager.newInstEx(Mnemonic_IDIV, 2, dstOpnd1, dstOpnd0, dstOpnd1, srcOpnd1, (Opnd*)convert(src2, dstType))); + dst=rem?dstOpnd1:dstOpnd0; +#endif + break; + } + case DivOp::D: + case DivOp::F: + if(rem) { + dstType=irManager.getTypeFromTag(Type::Double); + dst=irManager.newOpnd(dstType); + Opnd * args[]={ (Opnd*)convert(src1, dstType), (Opnd*)convert(src2, dstType) }; + CallInst * callInst=irManager.newInternalRuntimeHelperCallInst("remF8", 2, args, dst); + appendInsts(callInst); + } else { + return fpOp(Mnemonic_DIVSD, irManager.getTypeFromTag(Type::Double), src1, src2); + } + break; + + case DivOp::S: + if(rem) { + dstType=irManager.getTypeFromTag(Type::Single); + dst=irManager.newOpnd(dstType); + Opnd * args[]={ (Opnd*)convert(src1, dstType), (Opnd*)convert(src2, dstType) }; + CallInst * callInst=irManager.newInternalRuntimeHelperCallInst("remF4", 2, args, dst); + appendInsts(callInst); + } else { + return fpOp(Mnemonic_DIVSS, irManager.getTypeFromTag(Type::Single), src1, src2); + } + break; + default: + ICS_ASSERT(0); + } + return dst; } //_______________________________________________________________________________________________________________ @@ -746,7 +789,7 @@ CG_OpndHandle * InstCodeSelector::tau_di CG_OpndHandle* src2, CG_OpndHandle* tau_src1NonZero) { - return divOp(op, false, (Opnd *)src1, (Opnd *)src2); + return divOp(op, false, (Opnd *)src1, (Opnd *)src2); } //_______________________________________________________________________________________________________________ @@ -757,7 +800,7 @@ CG_OpndHandle* InstCodeSelector::tau_rem CG_OpndHandle* src2, CG_OpndHandle* tau_src2NonZero) { - return divOp(op, true, (Opnd *)src1, (Opnd *)src2); + return divOp(op, true, (Opnd *)src1, (Opnd *)src2); } //_______________________________________________________________________________________________________________ @@ -766,78 +809,76 @@ CG_OpndHandle* InstCodeSelector::tau_rem CG_OpndHandle* InstCodeSelector::neg(NegOp::Types opType, CG_OpndHandle* src) { - Opnd * dst=NULL; - switch(opType){ - case NegOp::I: - case NegOp::I4: - { - Type * dstType=irManager.getTypeFromTag(Type::Int32); - dst=irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(src, dstType))); - break; - } - case NegOp::I8: - { - Type * dstType=irManager.getTypeFromTag(Type::Int64); - Opnd * dstMOV = irManager.newOpnd(dstType); - Opnd * src_null = irManager.newImmOpnd(dstType, 0); - appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV,1,dstMOV,src_null)); - dst = (Opnd *)sub(ArithmeticOp::I8, dstMOV, src); - break; - } - case NegOp::D: - { - Type * dstType=irManager.getTypeFromTag(Type::Double); - dst = irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(Mnemonic_FCHS,1,dst,(Opnd*)src)); - break; - } - case NegOp::F: - { - Type * dstType=irManager.getTypeFromTag(Type::Float); - dst = irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(Mnemonic_FCHS,1,dst,(Opnd*)src)); - break; - } - case NegOp::S: - { - Type * dstType=irManager.getTypeFromTag(Type::Single); - dst = irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(Mnemonic_FCHS,1,dst,(Opnd*)src)); - break; - } - default: - ICS_ASSERT(0); - } - return dst; + Opnd * dst=NULL; + switch(opType){ + case NegOp::I: + case NegOp::I4: + { + Type * dstType=irManager.getTypeFromTag(Type::Int32); + dst=irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(src, dstType))); + break; + } + case NegOp::I8: + { + Type * dstType=irManager.getTypeFromTag(Type::Int64); + Opnd * dstMOV = irManager.newOpnd(dstType); + Opnd * src_null = irManager.newImmOpnd(dstType, 0); +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV,1,dstMOV,src_null)); +#else + appendInsts(irManager.newInstEx(Mnemonic_MOV,1,dstMOV,src_null)); +#endif + dst = (Opnd *)sub(ArithmeticOp::I8, dstMOV, src); + break; + } + case NegOp::D: + case NegOp::F: + { + Type * dstType=irManager.getTypeFromTag(Type::Double); + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_FCHS,1,dst,(Opnd*)src)); + break; + } + case NegOp::S: + { + Type * dstType=irManager.getTypeFromTag(Type::Single); + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_FCHS,1,dst,(Opnd*)src)); + break; + } + default: + ICS_ASSERT(0); + } + return dst; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::minMaxOp(NegOp::Types opType, bool max, Opnd * src1, Opnd * src2) { - Opnd * dst=NULL; - switch(opType){ - case NegOp::I: - case NegOp::I4: - { - Type * dstType=irManager.getTypeFromTag(Type::Int32); - src1=convert(src1, dstType); - src2=convert(src2, dstType); - dst=irManager.newOpnd(dstType); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, (Opnd*)src2)); - appendInsts(irManager.newInst(Mnemonic_CMP, (Opnd*)src1, dst)); - appendInsts(irManager.newInst(max?Mnemonic_CMOVG:Mnemonic_CMOVL, dst, (Opnd*)src1)); - break; - } - case NegOp::I8: - case NegOp::D: - case NegOp::F: - case NegOp::S: - ICS_ASSERT(0); - default: - ICS_ASSERT(0); - } - return dst; + Opnd * dst=NULL; + switch(opType){ + case NegOp::I: + case NegOp::I4: + { + Type * dstType=irManager.getTypeFromTag(Type::Int32); + src1=convert(src1, dstType); + src2=convert(src2, dstType); + dst=irManager.newOpnd(dstType); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, (Opnd*)src2)); + appendInsts(irManager.newInst(Mnemonic_CMP, (Opnd*)src1, dst)); + appendInsts(irManager.newInst(max?Mnemonic_CMOVG:Mnemonic_CMOVL, dst, (Opnd*)src1)); + break; + } + case NegOp::I8: + case NegOp::D: + case NegOp::F: + case NegOp::S: + ICS_ASSERT(0); + default: + ICS_ASSERT(0); + } + return dst; } //_______________________________________________________________________________________________________________ @@ -847,7 +888,7 @@ CG_OpndHandle* InstCodeSelector::min_op( CG_OpndHandle* src1, CG_OpndHandle* src2) { - return minMaxOp(opType, false, (Opnd*)src1, (Opnd*)src2); + return minMaxOp(opType, false, (Opnd*)src1, (Opnd*)src2); } //_______________________________________________________________________________________________________________ @@ -857,7 +898,7 @@ CG_OpndHandle* InstCodeSelector::max_op( CG_OpndHandle* src1, CG_OpndHandle* src2) { - return minMaxOp(opType, true, (Opnd*)src1, (Opnd*)src2); + return minMaxOp(opType, true, (Opnd*)src1, (Opnd*)src2); } //_______________________________________________________________________________________________________________ @@ -866,28 +907,28 @@ CG_OpndHandle* InstCodeSelector::max_op( CG_OpndHandle* InstCodeSelector::abs_op(NegOp::Types opType, CG_OpndHandle* src) { - Opnd * dst=NULL; - switch(opType){ - case NegOp::I: - case NegOp::I4: - { - Type * dstType=irManager.getTypeFromTag(Type::Int32); - dst=irManager.newOpnd(dstType); - Opnd * srcOpnd=convert(src, dstType); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, (Opnd*)srcOpnd)); - appendInsts(irManager.newInst(Mnemonic_NEG, dst)); - appendInsts(irManager.newInstEx(Mnemonic_CMOVL, 1, dst, (Opnd*)srcOpnd)); - break; - } - case NegOp::I8: - case NegOp::D: - case NegOp::F: - case NegOp::S: - ICS_ASSERT(0); - default: - ICS_ASSERT(0); - } - return dst; + Opnd * dst=NULL; + switch(opType){ + case NegOp::I: + case NegOp::I4: + { + Type * dstType=irManager.getTypeFromTag(Type::Int32); + dst=irManager.newOpnd(dstType); + Opnd * srcOpnd=convert(src, dstType); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, (Opnd*)srcOpnd)); + appendInsts(irManager.newInst(Mnemonic_NEG, dst)); + appendInsts(irManager.newInstEx(Mnemonic_CMOVL, 1, dst, (Opnd*)srcOpnd)); + break; + } + case NegOp::I8: + case NegOp::D: + case NegOp::F: + case NegOp::S: + ICS_ASSERT(0); + default: + ICS_ASSERT(0); + } + return dst; } @@ -896,7 +937,7 @@ CG_OpndHandle* InstCodeSelector::abs_op( CG_OpndHandle* InstCodeSelector::tau_ckfinite(CG_OpndHandle* src) { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -906,18 +947,18 @@ CG_OpndHandle* InstCodeSelector::and_(In CG_OpndHandle* src1, CG_OpndHandle* src2) { - switch(opType){ - case IntegerOp::I4: - case IntegerOp::I:{ - Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_AND, dstType, (Opnd*)src1, (Opnd*)src2); - } - case IntegerOp::I8: - return simpleOp_I8(Mnemonic_AND, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case IntegerOp::I4: + case IntegerOp::I:{ + Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_AND, dstType, (Opnd*)src1, (Opnd*)src2); + } + case IntegerOp::I8: + return simpleOp_I8(Mnemonic_AND, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + return NULL; } //_______________________________________________________________________________________________________________ @@ -927,18 +968,18 @@ CG_OpndHandle* InstCodeSelector::or_(Int CG_OpndHandle* src1, CG_OpndHandle* src2) { - switch(opType){ - case IntegerOp::I4: - case IntegerOp::I:{ - Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_OR, dstType, (Opnd*)src1, (Opnd*)src2); - } - case IntegerOp::I8: - return simpleOp_I8(Mnemonic_OR, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case IntegerOp::I4: + case IntegerOp::I:{ + Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_OR, dstType, (Opnd*)src1, (Opnd*)src2); + } + case IntegerOp::I8: + return simpleOp_I8(Mnemonic_OR, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + return NULL; } //_______________________________________________________________________________________________________________ @@ -948,18 +989,18 @@ CG_OpndHandle* InstCodeSelector::xor_ CG_OpndHandle* src1, CG_OpndHandle* src2) { - switch(opType){ - case IntegerOp::I4: - case IntegerOp::I:{ - Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_XOR, dstType, (Opnd*)src1, (Opnd*)src2); - } - case IntegerOp::I8: - return simpleOp_I8(Mnemonic_XOR, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case IntegerOp::I4: + case IntegerOp::I:{ + Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src1)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_XOR, dstType, (Opnd*)src1, (Opnd*)src2); + } + case IntegerOp::I8: + return simpleOp_I8(Mnemonic_XOR, irManager.getTypeFromTag(Type::Int64), (Opnd*)src1, (Opnd*)src2); + default: + ICS_ASSERT(0); + } + return NULL; } //_______________________________________________________________________________________________________________ @@ -968,43 +1009,47 @@ CG_OpndHandle* InstCodeSelector::xor_ CG_OpndHandle* InstCodeSelector::not_(IntegerOp::Types opType, CG_OpndHandle* src) { - switch(opType){ - case IntegerOp::I4: - case IntegerOp::I:{ - Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src)->getType()):irManager.getTypeFromTag(Type::Int32); - return simpleOp_I4(Mnemonic_NOT, dstType, (Opnd*)src, 0); - } - case IntegerOp::I8: - return simpleOp_I8(Mnemonic_NOT, irManager.getTypeFromTag(Type::Int64), (Opnd*)src, 0); - default: - ICS_ASSERT(0); - } - return NULL; + switch(opType){ + case IntegerOp::I4: + case IntegerOp::I:{ + Type * dstType=opType==IntegerOp::I?irManager.getManagedPtrType(((Opnd*)src)->getType()):irManager.getTypeFromTag(Type::Int32); + return simpleOp_I4(Mnemonic_NOT, dstType, (Opnd*)src, 0); + } + case IntegerOp::I8: + return simpleOp_I8(Mnemonic_NOT, irManager.getTypeFromTag(Type::Int64), (Opnd*)src, 0); + default: + ICS_ASSERT(0); + } + return NULL; } //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::shiftOp(IntegerOp::Types opType, Mnemonic mn, Opnd * value, Opnd * shiftAmount) { - Opnd * dst=NULL; - Type * dstType; - switch(opType){ - case IntegerOp::I: - case IntegerOp::I4: - { - dstType=irManager.getTypeFromTag(Type::Int32); - dst = irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(mn, 1, dst, (Opnd*)convert(value, dstType), (Opnd*)convert(shiftAmount, typeManager.getInt8Type()))); - break; - } - case IntegerOp::I8: - dstType=irManager.getTypeFromTag(Type::Int64); - dst=irManager.newOpnd(dstType); - appendInsts(irManager.newI8PseudoInst(mn,1,dst,(Opnd*)convert(value, dstType),(Opnd*)convert(shiftAmount, typeManager.getInt32Type()))); - return dst; - default: - ICS_ASSERT(0); - } - return dst; + Opnd * dst=NULL; + Type * dstType; + switch(opType){ + case IntegerOp::I: + case IntegerOp::I4: + { + dstType=irManager.getTypeFromTag(Type::Int32); + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(mn, 1, dst, (Opnd*)convert(value, dstType), (Opnd*)convert(shiftAmount, typeManager.getInt8Type()))); + break; + } + case IntegerOp::I8: + dstType=irManager.getTypeFromTag(Type::Int64); + dst=irManager.newOpnd(dstType); +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(mn,1,dst,(Opnd*)convert(value, dstType),(Opnd*)convert(shiftAmount, typeManager.getInt32Type()))); +#else + appendInsts(irManager.newInstEx(mn,1,dst,(Opnd*)convert(value, dstType),(Opnd*)convert(shiftAmount, typeManager.getInt32Type()))); +#endif + return dst; + default: + ICS_ASSERT(0); + } + return dst; } //_______________________________________________________________________________________________________________ @@ -1015,15 +1060,14 @@ CG_OpndHandle* InstCodeSelector::shla uint32 imm, CG_OpndHandle* addto) { -// ICS_ASSERT(0); - Opnd * shiftDest = (Opnd *)shl(opType, value, irManager.newImmOpnd(typeManager.getUInt8Type(), imm)); - ArithmeticOp::Types atype; - switch (opType) { - case IntegerOp::I : atype = ArithmeticOp::I; break; - case IntegerOp::I8 : atype = ArithmeticOp::I8; break; - default : atype = ArithmeticOp::I4; break; - } - return add(atype, addto, shiftDest); + Opnd * shiftDest = (Opnd *)shl(opType, value, irManager.newImmOpnd(typeManager.getUInt8Type(), imm)); + ArithmeticOp::Types atype; + switch (opType) { + case IntegerOp::I : atype = ArithmeticOp::I; break; + case IntegerOp::I8 : atype = ArithmeticOp::I8; break; + default : atype = ArithmeticOp::I4; break; + } + return add(atype, addto, shiftDest); } @@ -1034,7 +1078,7 @@ CG_OpndHandle* InstCodeSelector::shl( CG_OpndHandle* value, CG_OpndHandle* shiftAmount) { - return shiftOp(opType, Mnemonic_SHL, (Opnd*)value, (Opnd*)shiftAmount); + return shiftOp(opType, Mnemonic_SHL, (Opnd*)value, (Opnd*)shiftAmount); } //_______________________________________________________________________________________________________________ @@ -1044,7 +1088,7 @@ CG_OpndHandle* InstCodeSelector::shr(Int CG_OpndHandle* value, CG_OpndHandle* shiftAmount) { - return shiftOp(opType, Mnemonic_SAR, (Opnd*)value, (Opnd*)shiftAmount); + return shiftOp(opType, Mnemonic_SAR, (Opnd*)value, (Opnd*)shiftAmount); } //_______________________________________________________________________________________________________________ @@ -1054,7 +1098,7 @@ CG_OpndHandle* InstCodeSelector::shru CG_OpndHandle* value, CG_OpndHandle* shiftAmount) { - return shiftOp(opType, Mnemonic_SHR, (Opnd*)value, (Opnd*)shiftAmount); + return shiftOp(opType, Mnemonic_SHR, (Opnd*)value, (Opnd*)shiftAmount); } //_______________________________________________________________________________________________________________ @@ -1066,7 +1110,7 @@ CG_OpndHandle* InstCodeSelector::select CG_OpndHandle* src3) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -1077,17 +1121,19 @@ CG_OpndHandle* InstCodeSelector::cmp(Co CG_OpndHandle* src1, CG_OpndHandle* src2) { - Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); - bool swapped=cmpToEflags(cmpOp, opType, (Opnd*)src1, (Opnd*)src2); - ConditionMnemonic cm=getConditionMnemonicFromCompareOperator(cmpOp, opType); - if (swapped) - cm=swapConditionMnemonic(cm); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); - appendInsts(irManager.newInstEx(getMnemonic(Mnemonic_SETcc, cm), 1, dst)); - if (((opType==CompareOp::F) ||(opType==CompareOp::S) ||(opType==CompareOp::D)) && ((cmpOp == CompareOp::Geu) || (cmpOp == CompareOp::Gtu))) { - appendInsts(irManager.newInstEx(Mnemonic_CMOVP,1,dst,irManager.newImmOpnd(typeManager.getInt32Type(), 0))); - } - return dst; + Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); + bool swapped=cmpToEflags(cmpOp, opType, (Opnd*)src1, (Opnd*)src2); + ConditionMnemonic cm=getConditionMnemonicFromCompareOperator(cmpOp, opType); + if (swapped) + cm=swapConditionMnemonic(cm); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); + appendInsts(irManager.newInstEx(getMnemonic(Mnemonic_SETcc, cm), 1, dst)); +#ifndef _EM64T_ + if (((opType==CompareOp::F) ||(opType==CompareOp::S) ||(opType==CompareOp::D)) && ((cmpOp == CompareOp::Geu) || (cmpOp == CompareOp::Gtu))) { + appendInsts(irManager.newInstEx(Mnemonic_CMOVP,1,dst,irManager.newImmOpnd(typeManager.getInt32Type(), 0))); + } +#endif + return dst; } //_______________________________________________________________________________________________________________ @@ -1096,11 +1142,12 @@ CG_OpndHandle* InstCodeSelector::cmp(Co CG_OpndHandle* InstCodeSelector::czero(CompareZeroOp::Types opType, CG_OpndHandle* src) { - Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); - cmpToEflags(CompareOp::Eq, getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, NULL); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); - appendInsts(irManager.newInstEx(Mnemonic_CMOVZ, 1, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 1))); - return dst; + Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); + + cmpToEflags(CompareOp::Eq, getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, NULL); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); + appendInsts(irManager.newInstEx(Mnemonic_CMOVZ, 1, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 1))); + return dst; } //_______________________________________________________________________________________________________________ @@ -1109,83 +1156,107 @@ CG_OpndHandle* InstCodeSelector::czer CG_OpndHandle* InstCodeSelector::cnzero(CompareZeroOp::Types opType, CG_OpndHandle* src) { - Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); - cmpToEflags(CompareOp::Eq, getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, NULL); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); - appendInsts(irManager.newInstEx(Mnemonic_CMOVNZ, 1, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 1))); - return dst; + Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); + cmpToEflags(CompareOp::Eq, getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, NULL); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); + appendInsts(irManager.newInstEx(Mnemonic_CMOVNZ, 1, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 1))); + return dst; } //_______________________________________________________________________________________________________________ bool InstCodeSelector::cmpToEflags(CompareOp::Operators cmpOp, CompareOp::Types opType, - Opnd * src1, Opnd * src2 - ) -{ - bool swapped=false; - switch(opType){ - case CompareOp::I: - case CompareOp::I4: - case CompareOp::Ref: - { - Type * srcType=irManager.getTypeFromTag(Type::Int32); - Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); - if (!src2){ - appendInsts(irManager.newInst(Mnemonic_TEST, srcOpnd1, srcOpnd1)); - }else{ - Opnd * srcOpnd2=(Opnd*)convert(src2, srcType); - swapped=swapIfLastIs(srcOpnd1, srcOpnd2); - appendInsts(irManager.newInst(Mnemonic_CMP, srcOpnd1, srcOpnd2)); - } - break; - } - case CompareOp::I8: - { - Type * srcType=irManager.getTypeFromTag(Type::Int64); - Opnd * srcOpnd1=(Opnd*)convert(src1, srcType), * srcOpnd2; - if (!src2) { - srcOpnd2=irManager.newImmOpnd(srcType, 0); - } else { - srcOpnd2=(Opnd*)convert(src2, srcType); - } - swapped=swapIfLastIs(srcOpnd1, srcOpnd2); - Opnd * dst = irManager.getRegOpnd(RegName_EFLAGS); - appendInsts(irManager.newI8PseudoInst(Mnemonic_CMP,1,dst,srcOpnd1,srcOpnd2)); - irManager.getCGFlags()->earlyDCEOn = true; - break; - } - case CompareOp::D: - case CompareOp::F: - { - Type * srcType=irManager.getTypeFromTag(Type::Double); - Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); - Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((double)0.0); - appendInsts(irManager.newInst(Mnemonic_UCOMISD, srcOpnd1, srcOpnd2)); - if(cmpOp == CompareOp::Eq || cmpOp == CompareOp::Ne) { - Opnd * ah = irManager.newOpnd(typeManager.getInt32Type()); - appendInsts(irManager.newInst(Mnemonic_LAHF,ah)); - Opnd * dst = (Opnd *)and_(IntegerOp::I4, ah, irManager.newImmOpnd(typeManager.getInt32Type(),UNORD_FLAGS_MASK)); - appendInsts(irManager.newInst(Mnemonic_CMP, dst, irManager.newImmOpnd(typeManager.getInt32Type(),ZF))); - } - break; - } - case CompareOp::S: - { - Type * srcType=irManager.getTypeFromTag(Type::Single); - Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); - Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((float)0.0); - appendInsts(irManager.newInst(Mnemonic_UCOMISS, srcOpnd1, srcOpnd2)); - if(cmpOp == CompareOp::Eq || cmpOp == CompareOp::Ne) { - Opnd * ah = irManager.newOpnd(typeManager.getInt32Type()); - appendInsts(irManager.newInst(Mnemonic_LAHF,ah)); - Opnd * dst = (Opnd *)and_(IntegerOp::I4, ah, irManager.newImmOpnd(typeManager.getInt32Type(),UNORD_FLAGS_MASK)); - appendInsts(irManager.newInst(Mnemonic_CMP, dst, irManager.newImmOpnd(typeManager.getInt32Type(),ZF))); - } - break; - } - default: - ICS_ASSERT(0); - } - return swapped; + Opnd * src1, Opnd * src2 + ) +{ + bool swapped=false; + switch(opType){ + case CompareOp::I4: +#ifndef _EM64T_ + case CompareOp::I: + case CompareOp::Ref: +#endif + { + Type * srcType=irManager.getTypeFromTag(Type::Int32); + Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); + if (!src2){ + appendInsts(irManager.newInst(Mnemonic_TEST, srcOpnd1, srcOpnd1)); + }else{ + Opnd * srcOpnd2=(Opnd*)convert(src2, srcType); + swapped=swapIfLastIs(srcOpnd1, srcOpnd2); + appendInsts(irManager.newInst(Mnemonic_CMP, srcOpnd1, srcOpnd2)); + } + break; + } +#ifdef _EM64T_ + case CompareOp::I: + case CompareOp::Ref: +#endif + case CompareOp::I8: + { + Type * srcType=irManager.getTypeFromTag(Type::Int64); + Opnd * srcOpnd1=(Opnd*)convert(src1, srcType), * srcOpnd2; + if (!src2) { + srcOpnd2=irManager.newImmOpnd(srcType, 0); + } else { + srcOpnd2=(Opnd*)convert(src2, srcType); + } + swapped=swapIfLastIs(srcOpnd1, srcOpnd2); +#ifndef _EM64T_ + Opnd * dst = irManager.getRegOpnd(RegName_EFLAGS); + appendInsts(irManager.newI8PseudoInst(Mnemonic_CMP,1,dst,srcOpnd1,srcOpnd2)); +#else + appendInsts(irManager.newInst(Mnemonic_CMP,srcOpnd1,srcOpnd2)); +#endif + irManager.getCGFlags()->earlyDCEOn = true; + break; + } + case CompareOp::D: + case CompareOp::F: + { + Type * srcType=irManager.getTypeFromTag(Type::Double); + Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); +#ifdef _EM64T_ + Opnd * baseOpnd = irManager.newOpnd(typeManager.getUnmanagedPtrType(srcType)); + Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((double)0.0, baseOpnd, (BasicBlock*)currentBasicBlock); +#else + Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((double)0.0); +#endif + appendInsts(irManager.newInst(Mnemonic_UCOMISD, srcOpnd1, srcOpnd2)); +#ifndef _EM64T_ + if(cmpOp == CompareOp::Eq || cmpOp == CompareOp::Ne) { + Opnd * ah = irManager.newOpnd(typeManager.getInt32Type()); + appendInsts(irManager.newInst(Mnemonic_LAHF,ah)); + Opnd * dst = (Opnd *)and_(IntegerOp::I4, ah, irManager.newImmOpnd(typeManager.getInt32Type(),UNORD_FLAGS_MASK)); + appendInsts(irManager.newInst(Mnemonic_CMP, dst, irManager.newImmOpnd(typeManager.getInt32Type(),ZF))); + } +#endif + break; + } + case CompareOp::S: + { + Type * srcType=irManager.getTypeFromTag(Type::Single); + Opnd * srcOpnd1=(Opnd*)convert(src1, srcType); +#ifdef _EM64T_ + Opnd * baseOpnd = irManager.newOpnd(typeManager.getUnmanagedPtrType(srcType)); + Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((float)0.0, baseOpnd, (BasicBlock*)currentBasicBlock); +#else + Opnd * srcOpnd2=src2?(Opnd*)convert(src2, srcType):irManager.newFPConstantMemOpnd((float)0.0); +#endif + appendInsts(irManager.newInst(Mnemonic_UCOMISS, srcOpnd1, srcOpnd2)); +#ifndef _EM64T_ + if(cmpOp == CompareOp::Eq || cmpOp == CompareOp::Ne) { + Opnd * ah = irManager.newOpnd(typeManager.getInt32Type()); + appendInsts(irManager.newInst(Mnemonic_LAHF,ah)); + Opnd * dst = (Opnd *)and_(IntegerOp::I4, ah, irManager.newImmOpnd(typeManager.getInt32Type(),UNORD_FLAGS_MASK)); + appendInsts(irManager.newInst(Mnemonic_CMP, dst, irManager.newImmOpnd(typeManager.getInt32Type(),ZF))); + } +#endif + break; + } + default: + ICS_ASSERT(0); + } + return swapped; } //_______________________________________________________________________________________________________________ @@ -1196,12 +1267,16 @@ void InstCodeSelector::branch(CompareOp: CG_OpndHandle* src1, CG_OpndHandle* src2) { - bool swapped=cmpToEflags(cmpOp, opType, (Opnd*)src1, (Opnd*)src2); - ConditionMnemonic cm=getConditionMnemonicFromCompareOperator(cmpOp, opType); - if (((opType==CompareOp::F) ||(opType==CompareOp::S) ||(opType==CompareOp::D)) && ((cmpOp == CompareOp::Geu) || (cmpOp == CompareOp::Gtu))) { - appendInsts(irManager.newBranchInst(Mnemonic_JP)); - } - appendInsts(irManager.newBranchInst(getMnemonic(Mnemonic_Jcc, swapped?swapConditionMnemonic(cm):cm))); + bool swapped=cmpToEflags(cmpOp, opType, (Opnd*)src1, (Opnd*)src2); + ConditionMnemonic cm=getConditionMnemonicFromCompareOperator(cmpOp, opType); +#ifndef _EM64T_ + if (((opType==CompareOp::F) ||(opType==CompareOp::S) ||(opType==CompareOp::D)) && ((cmpOp == CompareOp::Geu) || (cmpOp == CompareOp::Gtu))) { + //! branch true&false edges & new block for this branch will be added in CodeSelector::fixNodeInfo + appendInsts(irManager.newBranchInst(Mnemonic_JP, NULL, NULL)); + } +#endif + //! branch true&false edges are added during genTrue|FalseEdge + appendInsts(irManager.newBranchInst(getMnemonic(Mnemonic_Jcc, swapped?swapConditionMnemonic(cm):cm), NULL, NULL)); } //_______________________________________________________________________________________________________________ @@ -1210,9 +1285,17 @@ void InstCodeSelector::branch(CompareOp: void InstCodeSelector::bzero(CompareZeroOp::Types opType, CG_OpndHandle* src) { - cmpToEflags(CompareOp::Eq, - getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, 0); - appendInsts(irManager.newBranchInst(Mnemonic_JZ)); +#ifdef _EM64T_ + CompareOp::Types zeroType = getCompareOpTypesFromCompareZeroOpTypes(opType); + Opnd * op = (Opnd*) src; + cmpToEflags(CompareOp::Eq, + zeroType, op, irManager.newImmOpnd(op->getType(),(zeroType == CompareOp::Ref) || (zeroType == CompareOp::CompRef) ? (POINTER_SIZE_INT)compilationInterface.getHeapBase() : 0)); +#else + cmpToEflags(CompareOp::Eq, + getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, 0); +#endif + //! branch true&false edges are added during genTrue|False edge calls + appendInsts(irManager.newBranchInst(Mnemonic_JZ, NULL, NULL)); } //_______________________________________________________________________________________________________________ @@ -1221,9 +1304,17 @@ void InstCodeSelector::bzero(CompareZero void InstCodeSelector::bnzero(CompareZeroOp::Types opType, CG_OpndHandle* src) { - cmpToEflags(CompareOp::Eq, - getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, 0); - appendInsts(irManager.newBranchInst(Mnemonic_JNZ)); +#ifdef _EM64T_ + CompareOp::Types zeroType = getCompareOpTypesFromCompareZeroOpTypes(opType); + Opnd * op = (Opnd*) src; + cmpToEflags(CompareOp::Eq, + zeroType, op, irManager.newImmOpnd(op->getType(),(zeroType == CompareOp::Ref) || (zeroType == CompareOp::CompRef) ? (POINTER_SIZE_INT)compilationInterface.getHeapBase() : 0)); +#else + cmpToEflags(CompareOp::Eq, + getCompareOpTypesFromCompareZeroOpTypes(opType), (Opnd*)src, 0); +#endif + //! branch true&false edges are added during genTrue|FalseEdge + appendInsts(irManager.newBranchInst(Mnemonic_JNZ, NULL, NULL)); } //_______________________________________________________________________________________________________________ @@ -1231,9 +1322,9 @@ void InstCodeSelector::bnzero(CompareZer void InstCodeSelector::tableSwitch(CG_OpndHandle* src, uint32 nTargets) { - switchSrcOpnd=(Opnd*)src; - switchNumTargets=nTargets; - branch(CompareOp::Geu, CompareOp::I4, src, irManager.newImmOpnd(typeManager.getUInt32Type(), nTargets)); + switchSrcOpnd=(Opnd*)src; + switchNumTargets=nTargets; + branch(CompareOp::Geu, CompareOp::I4, src, irManager.newImmOpnd(typeManager.getUInt32Type(), nTargets)); } //_______________________________________________________________________________________________________________ @@ -1242,7 +1333,13 @@ void InstCodeSelector::tableSwitch(CG_Op void InstCodeSelector::genSwitchDispatch(uint32 numTargets, Opnd *switchSrc) { - appendInsts(irManager.newSwitchInst(numTargets, switchSrc)); +#ifdef _EM64T_ + Opnd * opnd = irManager.newOpnd(typeManager.getUInt64Type()); + copyOpnd(opnd, switchSrc); + appendInsts(irManager.newSwitchInst(numTargets, opnd)); +#else + appendInsts(irManager.newSwitchInst(numTargets, switchSrc)); +#endif } //_______________________________________________________________________________________________________________ @@ -1250,14 +1347,14 @@ void InstCodeSelector::genSwitchDispatch void InstCodeSelector::throwException(CG_OpndHandle* exceptionObj, bool createStackTrace) { - Opnd * args[]={ (Opnd*)exceptionObj }; - CallInst * callInst=irManager.newRuntimeHelperCallInst( - createStackTrace ? - CompilationInterface::Helper_Throw_SetStackTrace : - CompilationInterface::Helper_Throw_KeepStackTrace, - lengthof(args), args, NULL - ); - appendInsts(callInst); + Opnd * args[]={ (Opnd*)exceptionObj }; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + createStackTrace ? + CompilationInterface::Helper_Throw_SetStackTrace : + CompilationInterface::Helper_Throw_KeepStackTrace, + lengthof(args), args, NULL + ); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -1266,28 +1363,28 @@ void InstCodeSelector::throwException(CG void InstCodeSelector::throwSystemException(CompilationInterface::SystemExceptionId id) { - CallInst * callInst=NULL; + CallInst * callInst=NULL; switch (id) { - case CompilationInterface::Exception_NullPointer: - callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_NullPtrException, 0, NULL, NULL); - break; - case CompilationInterface::Exception_ArrayIndexOutOfBounds: - callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL); - break; - case CompilationInterface::Exception_ArrayTypeMismatch: - callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_ElemTypeException, 0, NULL, NULL); - break; - case CompilationInterface::Exception_DivideByZero: - callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_DivideByZeroException, 0, NULL, NULL); - break; - default: - assert(0); + case CompilationInterface::Exception_NullPointer: + callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_NullPtrException, 0, NULL, NULL); + break; + case CompilationInterface::Exception_ArrayIndexOutOfBounds: + callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL); + break; + case CompilationInterface::Exception_ArrayTypeMismatch: + callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_ElemTypeException, 0, NULL, NULL); + break; + case CompilationInterface::Exception_DivideByZero: + callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_DivideByZeroException, 0, NULL, NULL); + break; + default: + assert(0); } - appendInsts(callInst); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -1295,23 +1392,36 @@ void InstCodeSelector::throwSystemExcept CG_OpndHandle* InstCodeSelector::ldc_i4(uint32 val) { - return irManager.newImmOpnd(typeManager.getInt32Type(), val); + return irManager.newImmOpnd(typeManager.getInt32Type(), val); } //_______________________________________________________________________________________________________________ // Load 64-bit integer constant CG_OpndHandle* InstCodeSelector::ldc_i8(uint64 val) -{ - return irManager.newImmOpnd(typeManager.getInt64Type(), val); -} +{ +#ifndef _EM64T_ + return irManager.newImmOpnd(typeManager.getInt64Type(), val); +#else + Opnd * tmp = irManager.newOpnd(typeManager.getInt64Type()); + copyOpnd(tmp, irManager.newImmOpnd(typeManager.getInt64Type(), val)); + return tmp; +#endif +} //_______________________________________________________________________________________________________________ // get vtable constant (a constant pointer) CG_OpndHandle* InstCodeSelector::getVTableAddr(Type * dstType, ObjectType * base) { - return irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_VTableConstantAddr, base); +#ifndef _EM64T_ + return irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_VTableConstantAddr, base); +#else + Opnd * acc = irManager.newOpnd(dstType); + copyOpnd(acc, irManager.newImmOpnd(dstType,(POINTER_SIZE_INT)compilationInterface.getVTableBase())); + + return simpleOp_I8(Mnemonic_ADD, dstType, acc, irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_VTableConstantAddr, base)); +#endif } //_______________________________________________________________________________________________________________ @@ -1319,7 +1429,14 @@ CG_OpndHandle* InstCodeSelector::getVTab CG_OpndHandle* InstCodeSelector::ldc_s(float val) { - return irManager.newFPConstantMemOpnd(val); +#ifndef _EM64T_ + return irManager.newFPConstantMemOpnd(val); +#else + Opnd * baseOpnd = irManager.newOpnd(typeManager.getUnmanagedPtrType(typeManager.getSingleType())); + Opnd * dst = irManager.newOpnd(typeManager.getSingleType()); + copyOpnd(dst, irManager.newFPConstantMemOpnd(val, baseOpnd, (BasicBlock*)currentBasicBlock)); + return dst; +#endif } //_______________________________________________________________________________________________________________ @@ -1327,14 +1444,29 @@ CG_OpndHandle* InstCodeSelector::ldc_s(f CG_OpndHandle* InstCodeSelector::ldc_d(double val) { - return irManager.newFPConstantMemOpnd(val); +#ifndef _EM64T_ + return irManager.newFPConstantMemOpnd(val); +#else + Opnd * baseOpnd = irManager.newOpnd(typeManager.getUnmanagedPtrType(typeManager.getDoubleType())); + Opnd * dst = irManager.newOpnd(typeManager.getDoubleType()); + copyOpnd(dst, irManager.newFPConstantMemOpnd(val, baseOpnd, (BasicBlock*)currentBasicBlock)); + return dst; +#endif } //_______________________________________________________________________________________________________________ // Load Null CG_OpndHandle* InstCodeSelector::ldnull(bool compressed) { - return irManager.newImmOpnd(typeManager.getNullObjectType(), 0); +#ifndef _EM64T_ + return irManager.newImmOpnd(typeManager.getNullObjectType(), 0); +#else + if (compressed) { + return irManager.newImmOpnd(typeManager.getCompressedNullObjectType(), 0); + } else { + return irManager.newImmOpnd(typeManager.getNullObjectType(), (POINTER_SIZE_INT)compilationInterface.getHeapBase()); + } +#endif } //_______________________________________________________________________________________________________________ @@ -1342,8 +1474,8 @@ CG_OpndHandle* InstCodeSelector::ldnu CG_OpndHandle* InstCodeSelector::tau_checkNull(CG_OpndHandle* base, bool checksThisForInlinedMethod) { - appendInsts(irManager.newSystemExceptionCheckPseudoInst(CompilationInterface::Exception_NullPointer, (Opnd*)base, 0, checksThisForInlinedMethod)); - return getTauUnsafe(); + appendInsts(irManager.newSystemExceptionCheckPseudoInst(CompilationInterface::Exception_NullPointer, (Opnd*)base, 0, checksThisForInlinedMethod)); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -1356,7 +1488,7 @@ CG_OpndHandle* InstCodeSelector::tau_che Type * type2 = ((Opnd*)index)->getType(); CompareOp::Types cmpType; - if (type1->isInt4() && type2->isInt4()) + if (type1->isInt4() && type2->isInt4()) cmpType = CompareOp::I4; else if (type1->isInt8()) { assert(type2->isInt8()); @@ -1364,13 +1496,13 @@ CG_OpndHandle* InstCodeSelector::tau_che } else cmpType = CompareOp::I; - BasicBlock * throwBasicBlock = irManager.newBasicBlock(0); - throwBasicBlock->appendInsts(irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL)); + Node* throwBasicBlock = irManager.getFlowGraph()->createBlockNode(); + throwBasicBlock->appendInst(irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL)); - branch(CompareOp::Geu, cmpType, (Opnd*)index, (Opnd*)arrayLen); - irManager.newDirectBranchEdge(currentBasicBlock, throwBasicBlock, 0.001); - return getTauUnsafe(); + branch(CompareOp::Geu, cmpType, (Opnd*)index, (Opnd*)arrayLen); + codeSelector.genTrueEdge(currentBasicBlock, throwBasicBlock, 0); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -1385,24 +1517,24 @@ CG_OpndHandle* InstCodeSelector::tau_che CompareOp::Types cmpType; CompareOp::Operators cmpOp; - if (type1->isInt4() && type2->isInt4()) { + if (type1->isInt4() && type2->isInt4()) { cmpType = CompareOp::I4; cmpOp = CompareOp::Gt; - }else if (type1->isInt8()) { + }else if (type1->isInt8()) { assert(type2->isInt8()); cmpType = CompareOp::I8; cmpOp = CompareOp::Gt; - } else { + } else { cmpType = CompareOp::I; cmpOp = CompareOp::Gtu; - } - BasicBlock * throwBasicBlock = irManager.newBasicBlock(0); - throwBasicBlock->appendInsts(irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL)); + } + Node* throwBasicBlock = irManager.getFlowGraph()->createBlockNode(); + throwBasicBlock->appendInst(irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_ArrayBoundsException, 0, NULL, NULL)); - branch(cmpOp, cmpType, (Opnd*)a, (Opnd*)b); - irManager.newDirectBranchEdge(currentBasicBlock, throwBasicBlock, 0.001); - return getTauUnsafe(); + branch(cmpOp, cmpType, (Opnd*)a, (Opnd*)b); + codeSelector.genTrueEdge(currentBasicBlock, throwBasicBlock, 0); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -1412,7 +1544,7 @@ CG_OpndHandle* InstCodeSelector::tau_che CG_OpndHandle* InstCodeSelector::tau_checkUpperBound(CG_OpndHandle* index, CG_OpndHandle* arrayLen) { - return tau_checkBounds(arrayLen, index); + return tau_checkBounds(arrayLen, index); } //_______________________________________________________________________________________________________________ @@ -1424,20 +1556,20 @@ CG_OpndHandle* InstCodeSelector::tau_che CG_OpndHandle* tauNullChecked, CG_OpndHandle* tauIsArray) { - BasicBlock * throwBasicBlock = irManager.newBasicBlock(0); - throwBasicBlock->appendInsts(irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_ElemTypeException, 0, NULL, NULL)); + Node* throwBasicBlock = irManager.getFlowGraph()->createBlockNode(); + throwBasicBlock->appendInst(irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_ElemTypeException, 0, NULL, NULL)); - Opnd * args[] = { (Opnd*)src, (Opnd*)array }; - Opnd * flag = irManager.newOpnd(typeManager.getInt32Type()); + Opnd * args[] = { (Opnd*)src, (Opnd*)array }; + Opnd * flag = irManager.newOpnd(typeManager.getInt32Type()); - appendInsts(irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_IsValidElemType, lengthof(args), args, flag)); + appendInsts(irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_IsValidElemType, lengthof(args), args, flag)); - bzero(CompareZeroOp::Ref, flag); - irManager.newDirectBranchEdge(currentBasicBlock, throwBasicBlock, 0.001); + bzero(CompareZeroOp::Ref, flag); + codeSelector.genTrueEdge(currentBasicBlock, throwBasicBlock, 0); - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -1445,25 +1577,25 @@ CG_OpndHandle* InstCodeSelector::tau_che CG_OpndHandle* InstCodeSelector::tau_checkZero(CG_OpndHandle* src) { - BasicBlock * throwBasicBlock = irManager.newBasicBlock(0); - throwBasicBlock->appendInsts(irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_DivideByZeroException, 0, NULL, NULL)); + Node* throwBasicBlock = irManager.getFlowGraph()->createBlockNode(); + throwBasicBlock->appendInst(irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_DivideByZeroException, 0, NULL, NULL)); Opnd * srcOpnd = (Opnd*)src; Type * type = srcOpnd->getType(); CompareZeroOp::Types opType = CompareZeroOp::I; switch (type->tag) { - case Type::Int32: - opType = CompareZeroOp::I4; break; - case Type::Int64: - opType = CompareZeroOp::I8; break; - case Type::IntPtr: - opType = CompareZeroOp::I; break; - default: - assert(0); + case Type::Int32: + opType = CompareZeroOp::I4; break; + case Type::Int64: + opType = CompareZeroOp::I8; break; + case Type::IntPtr: + opType = CompareZeroOp::I; break; + default: + assert(0); } - bzero(opType, src); - irManager.newDirectBranchEdge(currentBasicBlock, throwBasicBlock, 0.001); - return getTauUnsafe(); + bzero(opType, src); + codeSelector.genTrueEdge(currentBasicBlock, throwBasicBlock, 0); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -1475,7 +1607,7 @@ CG_OpndHandle* InstCodeSelector::tau_che CG_OpndHandle* src2) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -1486,83 +1618,83 @@ Opnd* InstCodeSelector::addOffset(Opnd * uint32 offset) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle* InstCodeSelector::uncompressRef(CG_OpndHandle *compref) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle* InstCodeSelector::compressRef(CG_OpndHandle *ref) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } //_______________________________________________________________________________________________________________ Opnd* InstCodeSelector::buildOffset(uint32 offset, MemoryAttribute::Context context) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } //_______________________________________________________________________________________________________________ Opnd* InstCodeSelector::buildOffsetPlusHeapbase(uint32 offset, MemoryAttribute::Context context) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldFieldOffset(FieldDesc *fieldDesc) -{ - return irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_FieldOffset, fieldDesc); +{ + return irManager.newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_FieldOffset, fieldDesc); } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldFieldOffsetPlusHeapbase(FieldDesc *fieldDesc) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldArrayBaseOffset(Type *elemType) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldArrayBaseOffsetPlusHeapbase(Type *elemType) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldArrayLenOffset(Type *elemType) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::ldArrayLenOffsetPlusHeapbase(Type *elemType) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle * InstCodeSelector::addOffset(Type *pointerType, CG_OpndHandle* refHandle, CG_OpndHandle* offsetHandle) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -1571,7 +1703,7 @@ CG_OpndHandle * InstCodeSelector::addOff CG_OpndHandle* compRefHandle, CG_OpndHandle* offsetPlusHeapbaseHandle) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -1582,8 +1714,12 @@ CG_OpndHandle* InstCodeSelector::ldField CG_OpndHandle* base, FieldDesc * fieldDesc) { - Opnd * offsetOpnd=(Opnd*)ldFieldOffset(fieldDesc); - return simpleOp_I4(Mnemonic_ADD, fieldRefType, (Opnd*)base, offsetOpnd); + Opnd * offsetOpnd=(Opnd*)ldFieldOffset(fieldDesc); +#ifdef _EM64T_ + return simpleOp_I8(Mnemonic_ADD, fieldRefType, (Opnd*)base, offsetOpnd); +#else + return simpleOp_I4(Mnemonic_ADD, fieldRefType, (Opnd*)base, offsetOpnd); +#endif } //_______________________________________________________________________________________________________________ @@ -1591,8 +1727,18 @@ CG_OpndHandle* InstCodeSelector::ldField CG_OpndHandle* InstCodeSelector::ldStaticAddr(Type* fieldRefType, FieldDesc *fieldDesc) { - Opnd * addr=irManager.newImmOpnd(fieldRefType, Opnd::RuntimeInfo::Kind_StaticFieldAddress, fieldDesc); - return addr; +#ifndef _EM64T_ + Opnd * addr=irManager.newImmOpnd(fieldRefType, Opnd::RuntimeInfo::Kind_StaticFieldAddress, fieldDesc); +#else + Opnd * addr; + if(!fieldRefType->isReference()) { + addr = irManager.newOpnd(fieldRefType); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, addr, irManager.newImmOpnd(fieldRefType, Opnd::RuntimeInfo::Kind_StaticFieldAddress, fieldDesc))); + } else { + addr = irManager.newImmOpnd(irManager.getTypeFromTag(Type::CompressedObject), Opnd::RuntimeInfo::Kind_StaticFieldAddress, fieldDesc); + } +#endif + return addr; } //_______________________________________________________________________________________________________________ @@ -1600,38 +1746,57 @@ CG_OpndHandle* InstCodeSelector::ldSt CG_OpndHandle* InstCodeSelector::ldElemBaseAddr(CG_OpndHandle* array) { - ArrayType * arrayType=((Opnd*)array)->getType()->asArrayType(); - Type * elemType=arrayType->getElementType(); - Type * dstType=irManager.getManagedPtrType(elemType); - Opnd * dst=irManager.newOpnd(dstType); - appendInsts(irManager.newInstEx(Mnemonic_ADD, 1, dst, (Opnd*)array, irManager.newImmOpnd(typeManager.getInt32Type(), arrayType->getArrayElemOffset()))); - return dst; + ArrayType * arrayType=((Opnd*)array)->getType()->asArrayType(); + Type * elemType=arrayType->getElementType(); +#ifdef _EM64T_ + if (elemType->isReference() + && Type::isCompressedReference(elemType->tag, compilationInterface) + && !elemType->isCompressedReference()) { + elemType = typeManager.compressType(elemType); + } + Type * offType = typeManager.getInt64Type(); +#else + Type * offType = typeManager.getInt32Type(); +#endif + Type * dstType=irManager.getManagedPtrType(elemType); + Opnd * dst=irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_ADD, 1, dst, (Opnd*)array, irManager.newImmOpnd(offType, arrayType->getArrayElemOffset()))); + return dst; } //_______________________________________________________________________________________________________________ // Compute address of the array element given // address of the first element and index -CG_OpndHandle* InstCodeSelector::addElemIndex(CG_OpndHandle * elemBase, - CG_OpndHandle * index) +CG_OpndHandle* InstCodeSelector::addElemIndex(Type * eType, + CG_OpndHandle * elemBase, + CG_OpndHandle * index) { - PtrType * ptrType=((Opnd*)elemBase)->getType()->asPtrType(); + PtrType * ptrType=((Opnd*)elemBase)->getType()->asPtrType(); Type * elemType = ptrType->getPointedToType(); - uint32 elemSize=getByteSize(irManager.getTypeSize(elemType)); + uint32 elemSize=getByteSize(irManager.getTypeSize(elemType)); - Opnd * indexOpnd=(Opnd *)index; - - Opnd * scaledIndexOpnd=NULL; - if (indexOpnd->isPlacedIn(OpndKind_Imm)){ - scaledIndexOpnd=irManager.newImmOpnd(indexOpnd->getType(), indexOpnd->getImmValue()*elemSize); - }else{ - scaledIndexOpnd=irManager.newOpnd(indexOpnd->getType()); - appendInsts(irManager.newInstEx(Mnemonic_IMUL, 1, scaledIndexOpnd, indexOpnd, irManager.newImmOpnd(typeManager.getInt32Type(), elemSize))); - } - Opnd * dst=irManager.newOpnd(ptrType); - appendInsts(irManager.newInstEx(Mnemonic_ADD, 1, dst, (Opnd*)elemBase, scaledIndexOpnd)); - return dst; + Type * indexType = +#ifdef _EM64T_ + typeManager.getInt64Type(); +#else + typeManager.getInt32Type(); +#endif + + Opnd * indexOpnd=(Opnd *)index; + indexOpnd=convert(indexOpnd, indexType); + + Opnd * scaledIndexOpnd=NULL; + if (indexOpnd->isPlacedIn(OpndKind_Imm)){ + scaledIndexOpnd=irManager.newImmOpnd(indexType, indexOpnd->getImmValue()*elemSize); + }else{ + scaledIndexOpnd=irManager.newOpnd(indexType); + appendInsts(irManager.newInstEx(Mnemonic_IMUL, 1, scaledIndexOpnd, indexOpnd, irManager.newImmOpnd(indexType, elemSize))); + } + Opnd * dst=irManager.newOpnd(ptrType); + appendInsts(irManager.newInstEx(Mnemonic_ADD, 1, dst, (Opnd*)elemBase, scaledIndexOpnd)); + return dst; } //_______________________________________________________________________________________________________________ @@ -1644,11 +1809,11 @@ CG_OpndHandle* InstCodeSelector::tau_ CG_OpndHandle* tauArrayNonNull, CG_OpndHandle* tauIsArray) { - Opnd * offset=irManager.newImmOpnd(typeManager.getInt32Type(), arrayType->getArrayLengthOffset()); - Opnd * addr=irManager.newMemOpnd(lenType, (Opnd*)base, 0, 0, offset); - Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, addr)); - return dst; + Opnd * offset=irManager.newImmOpnd(typeManager.getInt32Type(), arrayType->getArrayLengthOffset()); + Opnd * addr=irManager.newMemOpnd(lenType, (Opnd*)base, 0, 0, offset); + Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, addr)); + return dst; } //_______________________________________________________________________________________________________________ @@ -1659,10 +1824,28 @@ CG_OpndHandle* InstCodeSelector::simpleL Opnd * baseTau, Opnd * offsetTau) { - Opnd * opnd = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); - Opnd * dst = irManager.newOpnd(dstType); - copyOpnd(dst, opnd); - return dst; +#ifndef _EM64T_ + Opnd * opnd = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); + Opnd * dst = irManager.newOpnd(dstType); + copyOpnd(dst, opnd); + return dst; +#else + if(memType > Type::Float) { + Opnd * opnd = irManager.newMemOpndAutoKind(typeManager.getInt32Type(), addr); + Opnd * tmp = irManager.newOpnd(typeManager.getInt32Type()); + Opnd * dst = irManager.newOpnd(typeManager.getInt64Type()); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt64Type(),0))); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, tmp, opnd)); + copyOpnd(dst, tmp); + dst = simpleOp_I8(Mnemonic_ADD, dstType, dst, irManager.newImmOpnd(dstType, (POINTER_SIZE_INT)compilationInterface.getHeapBase())); + return dst; + } else { + Opnd * opnd = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); + Opnd * dst = irManager.newOpnd(dstType); + copyOpnd(dst, opnd); + return dst; + } +#endif } //_______________________________________________________________________________________________________________ @@ -1675,8 +1858,19 @@ void InstCodeSelector::simpleStInd(Opnd Opnd * baseTau, Opnd * offsetAndTypeTau) { - Opnd * dst = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); - copyOpnd(dst, src); +#ifndef _EM64T_ + Opnd * dst = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); + copyOpnd(dst, src); +#else + if(memType > Type::Float) { + src = simpleOp_I8(Mnemonic_SUB, src->getType(), src, irManager.newImmOpnd(typeManager.getIntPtrType(), (POINTER_SIZE_INT)compilationInterface.getHeapBase())); + Opnd * opnd = irManager.newMemOpndAutoKind(typeManager.compressType(src->getType()), addr); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, opnd, src)); + } else { + Opnd * dst = irManager.newMemOpndAutoKind(irManager.getTypeFromTag(memType), addr); + copyOpnd(dst, src); + } +#endif } @@ -1687,7 +1881,7 @@ Type * InstCodeSelector::getFieldRefType Type::Tag fieldTypeTag) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -1696,10 +1890,10 @@ Type * InstCodeSelector::getFieldRefType CG_OpndHandle* InstCodeSelector::ldStatic(Type * dstType, FieldDesc* fieldDesc, Type::Tag fieldType, - bool autoUncompressRef) + bool autoUncompressRef) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ @@ -1714,21 +1908,21 @@ CG_OpndHandle* InstCodeSelector::tau_ldF CG_OpndHandle* tauBaseTypeHasField) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ // Load array element CG_OpndHandle* InstCodeSelector::tau_ldElem(Type * dstType, - CG_OpndHandle* array, - CG_OpndHandle* index, - bool autoUncompressRef, - CG_OpndHandle* tauBaseNonNull, - CG_OpndHandle* tauIdxIsInBounds) + CG_OpndHandle* array, + CG_OpndHandle* index, + bool autoUncompressRef, + CG_OpndHandle* tauBaseNonNull, + CG_OpndHandle* tauIdxIsInBounds) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -1780,7 +1974,7 @@ void InstCodeSelector::tau_stElem(CG_Opn void InstCodeSelector::compressOpnd(Opnd *dst, Opnd *src) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -1788,7 +1982,7 @@ void InstCodeSelector::compressOpnd(Opnd void InstCodeSelector::decompressOpnd(Opnd *dst, Opnd *src) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -1798,7 +1992,7 @@ void InstCodeSelector::decompressOpnd(Op void InstCodeSelector::makeComparable(Opnd*& srcOpnd1, Opnd*& srcOpnd2) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -1820,7 +2014,7 @@ CG_OpndHandle* InstCodeSelector::tau_ldI CG_OpndHandle* tauBaseNonNull, CG_OpndHandle* tauAddressInRange) { - return simpleLdInd(dstType, (Opnd*)ptr, memType, (Opnd*)tauBaseNonNull, (Opnd*)tauAddressInRange); + return simpleLdInd(dstType, (Opnd*)ptr, memType, (Opnd*)tauBaseNonNull, (Opnd*)tauAddressInRange); } //_______________________________________________________________________________________________________________ @@ -1834,7 +2028,7 @@ void InstCodeSelector::tau_stInd(CG_Opnd CG_OpndHandle* tauAddressInRange, CG_OpndHandle* tauElemTypeChecked) { - return simpleStInd((Opnd*)ptr, (Opnd*)src, memType, autoCompressRef, (Opnd*)tauBaseNonNull, (Opnd*)tauElemTypeChecked); + return simpleStInd((Opnd*)ptr, (Opnd*)src, memType, autoCompressRef, (Opnd*)tauBaseNonNull, (Opnd*)tauElemTypeChecked); } //_______________________________________________________________________________________________________________ @@ -1842,8 +2036,8 @@ void InstCodeSelector::tau_stInd(CG_Opnd CG_OpndHandle* InstCodeSelector::ldVarAddr(uint32 varId) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ @@ -1851,11 +2045,11 @@ CG_OpndHandle* InstCodeSelector::ldVarAd CG_OpndHandle * InstCodeSelector::ldVar(Type* dstType, uint32 varId) { - if (dstType->tag==Type::Tau) - return getTauUnsafe(); - Opnd * dst=irManager.newOpnd(dstType); - copyOpnd(dst, irManager.getOpnd(varId)); - return dst; + if (dstType->tag==Type::Tau) + return getTauUnsafe(); + Opnd * dst=irManager.newOpnd(dstType); + copyOpnd(dst, irManager.getOpnd(varId)); + return dst; } //_______________________________________________________________________________________________________________ @@ -1863,9 +2057,9 @@ CG_OpndHandle * InstCodeSelector::ldVar( void InstCodeSelector::stVar(CG_OpndHandle* src, uint32 varId) { - if (src==getTauUnsafe()) - return; - copyOpnd(irManager.getOpnd(varId), (Opnd*)src); + if (src==getTauUnsafe()) + return; + copyOpnd(irManager.getOpnd(varId), (Opnd*)src); } //_______________________________________________________________________________________________________________ @@ -1873,17 +2067,17 @@ void InstCodeSelector::stVar(CG_OpndHand CG_OpndHandle* InstCodeSelector::newObj(ObjectType* objType) { - Opnd * helperOpnds[] = { - irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_Size, objType), - irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_AllocationHandle, objType) - }; - Opnd * retOpnd=irManager.newOpnd(objType); + Opnd * helperOpnds[] = { + irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_Size, objType), + irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_AllocationHandle, objType) + }; + Opnd * retOpnd=irManager.newOpnd(objType); - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_NewObj_UsingVtable, - 2, helperOpnds, retOpnd); - appendInsts(callInst); - return retOpnd; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_NewObj_UsingVtable, + 2, helperOpnds, retOpnd); + appendInsts(callInst); + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -1893,16 +2087,16 @@ CG_OpndHandle* InstCodeSelector::newObj( CG_OpndHandle* InstCodeSelector::newArray(ArrayType* arrayType, CG_OpndHandle* numElems) { - Opnd * helperOpnds[] = { - irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_AllocationHandle, arrayType), - helperOpnds[1]=(Opnd*)numElems - }; - Opnd * retOpnd=irManager.newOpnd(arrayType); - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_NewVector_UsingVtable, - 2, helperOpnds, retOpnd); - appendInsts(callInst); - return retOpnd; + Opnd * helperOpnds[] = { + (Opnd*)numElems, + irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_AllocationHandle, arrayType) + }; + Opnd * retOpnd=irManager.newOpnd(arrayType); + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_NewVector_UsingVtable, + 2, helperOpnds, retOpnd); + appendInsts(callInst); + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -1913,38 +2107,85 @@ CG_OpndHandle* InstCodeSelector::newMul uint32 numDims, CG_OpndHandle** dims) { - Opnd ** helperOpnds = new (memManager) Opnd * [2+numDims]; - helperOpnds[0]=irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, arrayType); - helperOpnds[1]=irManager.newImmOpnd(typeManager.getInt32Type(), numDims); + Opnd ** helperOpnds = new (memManager) Opnd * [2+numDims]; + helperOpnds[0]=irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, arrayType); + helperOpnds[1]=irManager.newImmOpnd(typeManager.getInt32Type(), numDims); for (uint32 i = 0; i < numDims; i++) - helperOpnds[i + 2] = (Opnd*)dims[numDims - 1 - i]; - Opnd * retOpnd=irManager.newOpnd(arrayType); - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_NewMultiArray, - 2+numDims, helperOpnds, retOpnd); - appendInsts(callInst); - return retOpnd; -} - -//_______________________________________________________________________________________________________________ -// Load string + helperOpnds[i + 2] = (Opnd*)dims[numDims - 1 - i]; + Opnd * retOpnd=irManager.newOpnd(arrayType); + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_NewMultiArray, + 2+numDims, helperOpnds, retOpnd); + appendInsts(callInst); + return retOpnd; +} + +//_______________________________________________________________________________________________________________ +// Load reference (can also be a string) + +CG_OpndHandle* InstCodeSelector::ldRef(Type *dstType, + MethodDesc* enclosingMethod, + uint32 refToken, + bool uncompress) +{ + assert(dstType->isSystemString() || dstType->isSystemClass()); + Opnd * retOpnd=irManager.newOpnd(dstType); + + if (codeSelector.methodCodeSelector.slowLdString || dstType->isSystemClass()) { + NamedType * parentType=enclosingMethod->getParentType(); + #ifdef _EM64T_ + Opnd * st = irManager.getRegOpnd(RegName_RDI); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, st, irManager.newImmOpnd(typeManager.getInt64Type(), refToken))); + Opnd * tp = irManager.getRegOpnd(RegName_RSI); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, tp,irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, parentType))); + Opnd * helperOpnds[] = { + st, + tp + }; + #else + Opnd * helperOpnds[] = { + irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, parentType), + irManager.newImmOpnd(typeManager.getInt32Type(), refToken) + }; + #endif + + CallInst * callInst = irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_LdRef, 2, helperOpnds, retOpnd); + appendInsts(callInst); + } else { + // this optimized version is based on determinig item address at compile time. + // Respective compile time helper (class_get_const_string_intern_addr) is available for strings. + // Similar function for literal constants is not ready. + // TODO: rewrite this as soon as the helper for loading ref addr at compile time is ready. + +#ifdef _EM64T_ + Opnd * base = irManager.newOpnd(irManager.getTypeFromTag(Type::Object)); + copyOpnd(base, irManager.newImmOpnd(base->getType(), (POINTER_SIZE_INT)compilationInterface.getHeapBase())); + Opnd * tmp = irManager.newImmOpnd(irManager.getTypeFromTag(Type::UInt64), + Opnd::RuntimeInfo::Kind_StringAddress, + enclosingMethod, (void*)(POINTER_SIZE_INT)refToken); + Opnd * ptr; + if (uncompress) { + ptr = irManager.newOpnd(irManager.getTypeFromTag(Type::Object)); + copyOpnd(ptr,tmp); + } else { + ptr = simpleOp_I8(Mnemonic_ADD, irManager.getTypeFromTag(Type::Object),base,tmp); + } + + Opnd* memOpnd = irManager.newMemOpnd(typeManager.getSystemStringType(), MemOpndKind_Heap, + ptr, NULL, NULL, NULL); + retOpnd = simpleOp_I8(Mnemonic_ADD, memOpnd->getType(), memOpnd, base); -CG_OpndHandle* InstCodeSelector::ldString(MethodDesc* enclosingMethod, - uint32 stringToken, - bool uncompress) -{ - NamedType * parentType=enclosingMethod->getParentType(); - Opnd * helperOpnds[] = { - irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, parentType), - irManager.newImmOpnd(typeManager.getInt32Type(), stringToken) - }; - Opnd * retOpnd=irManager.newOpnd(typeManager.getSystemStringType()); +#else + Opnd* ptr = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getSystemStringType()), + Opnd::RuntimeInfo::Kind_StringAddress, + enclosingMethod, (void*)(POINTER_SIZE_INT)refToken); + Opnd* memOpnd = irManager.newMemOpnd(typeManager.getSystemStringType(), MemOpndKind_Heap, + NULL, NULL, NULL, ptr); + copyOpnd(retOpnd, memOpnd); +#endif + } - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_LdString, - 2, helperOpnds, retOpnd); - appendInsts(callInst); - return retOpnd; + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -1953,15 +2194,24 @@ CG_OpndHandle* InstCodeSelector::ldStrin CG_OpndHandle * InstCodeSelector::ldToken(Type *dstType,MethodDesc* enclosingMethod,uint32 token) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ // Increment counter for the program instrumentation -void InstCodeSelector::incCounter(Type *counterType,uint32 counter) +void InstCodeSelector::incCounter(Type *counterType,uint32 key) { - ICS_ASSERT(0); + assert( counterType->isUInt4() ); + EdgeMethodProfile* edgeProfile = this->codeSelector.methodCodeSelector.edgeProfile; + assert(edgeProfile!=NULL); + uint32* ptr = key == 0 ? edgeProfile->getEntryCounter() : edgeProfile->getCounter(key ); + assert( ptr != NULL /*&& *ptr == 0 if compilation is locked*/); + Opnd* baseOpnd = irManager.newImmOpnd(typeManager.getUnmanagedPtrType(typeManager.getUIntPtrType()), (POINTER_SIZE_INT)ptr); + Opnd* memOpnd = irManager.newMemOpnd(typeManager.getUIntPtrType(), MemOpndKind_Heap, baseOpnd, NULL, NULL, NULL); + const Mnemonic mn = Mnemonic_ADD; + Inst* inst = irManager.newInst(mn, memOpnd, irManager.newImmOpnd(typeManager.getUInt32Type(), 1)); + appendInsts(inst); } //_______________________________________________________________________________________________________________ @@ -1969,8 +2219,18 @@ void InstCodeSelector::incCounter(Type * void InstCodeSelector::ret(CG_OpndHandle* retValue) { + Opnd* ret_val = (Opnd*)retValue; + MethodDesc* mDesc = irManager.getCompilationInterface().getMethodToCompile(); + + if (irManager.getCompilationInterface().getCompilationParams().exe_notify_method_exit) { + if (ret_val == NULL) { + ret_val = irManager.newImmOpnd(typeManager.getInt32Type(), 0); + } + genExitHelper(ret_val, mDesc); + } + appendInsts(irManager.newRetInst((Opnd*)retValue)); - seenReturn = true; + seenReturn = true; } //_______________________________________________________________________________________________________________ @@ -1978,8 +2238,14 @@ void InstCodeSelector::ret(CG_OpndHandle void InstCodeSelector::ret() { - appendInsts(irManager.newRetInst(0)); - seenReturn = true; + MethodDesc* mDesc = irManager.getCompilationInterface().getMethodToCompile(); + + if (irManager.getCompilationInterface().getCompilationParams().exe_notify_method_exit) { + Opnd* ret_val = irManager.newImmOpnd(typeManager.getInt32Type(), 0); + genExitHelper(ret_val, mDesc); + } + appendInsts(irManager.newRetInst(0)); + seenReturn = true; } //_______________________________________________________________________________________________________________ @@ -1987,9 +2253,15 @@ void InstCodeSelector::ret() void InstCodeSelector::genReturn() { - if (!seenReturn){ - appendInsts(irManager.newRetInst(0)); - } + if (!seenReturn){ + MethodDesc* mDesc = irManager.getCompilationInterface().getMethodToCompile(); + + if (irManager.getCompilationInterface().getCompilationParams().exe_notify_method_exit) { + Opnd* ret_val = irManager.newImmOpnd(typeManager.getInt32Type(), 0); + genExitHelper(ret_val, mDesc); + } + appendInsts(irManager.newRetInst(0)); + } } //_______________________________________________________________________________________________________________ @@ -1997,7 +2269,7 @@ void InstCodeSelector::genReturn() CG_OpndHandle* InstCodeSelector::defArg(uint32 position, Type *type) { - return irManager.defArg(type, position); + return irManager.defArg(type, position); } //_______________________________________________________________________________________________________________ @@ -2006,8 +2278,8 @@ CG_OpndHandle* InstCodeSelector::defA CG_OpndHandle* InstCodeSelector::ldFunAddr(Type* dstType, MethodDesc * methodDesc) { - Opnd * addrOpnd=irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_MethodIndirectAddr, methodDesc); - return addrOpnd; + Opnd * addrOpnd=irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_MethodIndirectAddr, methodDesc); + return addrOpnd; } //_______________________________________________________________________________________________________________ @@ -2021,8 +2293,15 @@ CG_OpndHandle* InstCodeSelector::tau_ldV MethodDesc* methodDesc, CG_OpndHandle * tauVtableHasDesc) { - Opnd * offsetOpnd=irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset, methodDesc); - return simpleOp_I4(Mnemonic_ADD, dstType, (Opnd*)vtableAddr, offsetOpnd); +#ifdef _EM64T_ + Opnd * offsetOpnd=irManager.newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset, methodDesc); + Opnd * acc = irManager.newOpnd(dstType); + copyOpnd(acc, (Opnd*)vtableAddr); + return simpleOp_I8(Mnemonic_ADD, dstType, acc, offsetOpnd); +#else + Opnd * offsetOpnd=irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset, methodDesc); + return simpleOp_I4(Mnemonic_ADD, dstType, (Opnd*)vtableAddr, offsetOpnd); +#endif } //_______________________________________________________________________________________________________________ @@ -2032,12 +2311,24 @@ CG_OpndHandle* InstCodeSelector::tau_ldV CG_OpndHandle* base, CG_OpndHandle *tauBaseNonNull) { - Opnd * vtableAddr=irManager.newOpnd(dstType); - Opnd * sourceVTableAddr=irManager.newMemOpnd(dstType, (Opnd*)base, 0, 0, - irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_VTableAddrOffset) - ); - copyOpnd(vtableAddr, sourceVTableAddr); - return vtableAddr; +#ifndef _EM64T_ + Opnd * vtableAddr=irManager.newOpnd(dstType); + Opnd * sourceVTableAddr=irManager.newMemOpnd(dstType, (Opnd*)base, 0, 0, + irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_VTableAddrOffset) + ); + copyOpnd(vtableAddr, sourceVTableAddr); + return vtableAddr; +#else + Opnd * vtableAddr=irManager.newOpnd(dstType); + + int64 heapBase = (int64) compilationInterface.getVTableBase(); + Opnd * acc = simpleOp_I8(Mnemonic_ADD, dstType, (Opnd *)base, irManager.newImmOpnd(dstType, Opnd::RuntimeInfo::Kind_VTableAddrOffset)); + Opnd * sourceVTableAddr=irManager.newMemOpnd(typeManager.getInt32Type(), acc, 0, 0, irManager.newImmOpnd(typeManager.getUInt32Type(), 0)); + acc=irManager.newOpnd(typeManager.getInt64Type()); + copyOpnd(acc, sourceVTableAddr); + vtableAddr = simpleOp_I8(Mnemonic_ADD, dstType, acc, irManager.newImmOpnd(dstType, heapBase)); + return vtableAddr; +#endif } //_______________________________________________________________________________________________________________ @@ -2046,10 +2337,10 @@ CG_OpndHandle* InstCodeSelector::tau_ldV Opnd* InstCodeSelector::addVtableBaseAndOffset(Opnd * addr, CG_OpndHandle * compPtr, - uint32 offset) + uint32 offset) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ @@ -2059,21 +2350,20 @@ Opnd* InstCodeSelector::addVtableBaseAnd CG_OpndHandle* InstCodeSelector::tau_ldIntfTableAddr(Type * dstType, CG_OpndHandle* base, - NamedType* vtableType, - CG_OpndHandle* tauBaseHasIntf) + NamedType* vtableType) { - Opnd * helperOpnds[] = { - (Opnd*)base, - irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, vtableType) - }; + Opnd * helperOpnds[] = { + (Opnd*)base, + irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, vtableType) + }; - Opnd * retOpnd=irManager.newOpnd(dstType); + Opnd * retOpnd=irManager.newOpnd(dstType); - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_LdInterface, - 2, helperOpnds, retOpnd); - appendInsts(callInst); - return retOpnd; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_LdInterface, + 2, helperOpnds, retOpnd); + appendInsts(callInst); + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -2085,7 +2375,7 @@ CG_OpndHandle* InstCodeSelector::calli(u CG_OpndHandle* methodPtr, InlineInfo* ii) { - return tau_calli(numArgs, args, retType, methodPtr, getTauUnsafe(), getTauUnsafe()); + return tau_calli(numArgs, args, retType, methodPtr, getTauUnsafe(), getTauUnsafe()); } //_______________________________________________________________________________________________________________ @@ -2099,12 +2389,12 @@ CG_OpndHandle* InstCodeSelector::tau_cal CG_OpndHandle* tauTypesChecked, InlineInfo* ii) { - Opnd * target=irManager.newMemOpnd(typeManager.getIntPtrType(), (Opnd*)methodPtr); - Opnd * retOpnd=createResultOpnd(retType); - CallInst * callInst=irManager.newCallInst(target, irManager.getDefaultManagedCallingConvention(), - numArgs, (Opnd **)args, retOpnd, ii); - appendInsts(callInst); - return retOpnd; + Opnd * target=irManager.newMemOpnd(typeManager.getUnmanagedPtrType(typeManager.getUIntPtrType()), (Opnd*)methodPtr); + Opnd * retOpnd=createResultOpnd(retType); + CallInst * callInst=irManager.newCallInst(target, irManager.getDefaultManagedCallingConvention(), + numArgs, (Opnd **)args, retOpnd, ii); + appendInsts(callInst); + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -2118,7 +2408,7 @@ CG_OpndHandle* InstCodeSelector::call(ui MethodDesc * desc, InlineInfo* ii) { - return tau_call(numArgs, args, retType, desc, getTauUnsafe(), getTauUnsafe()); + return tau_call(numArgs, args, retType, desc, getTauUnsafe(), getTauUnsafe()); } //_______________________________________________________________________________________________________________ @@ -2134,12 +2424,12 @@ CG_OpndHandle* InstCodeSelector::tau_cal CG_OpndHandle* tauTypesChecked, InlineInfo* ii) { - Opnd * target=irManager.newImmOpnd(typeManager.getIntPtrType(), Opnd::RuntimeInfo::Kind_MethodDirectAddr, desc); - Opnd * retOpnd=createResultOpnd(retType); - CallInst * callInst=irManager.newCallInst(target, irManager.getDefaultManagedCallingConvention(), - numArgs, (Opnd **)args, retOpnd, ii); - appendInsts(callInst); - return retOpnd; + Opnd * target=irManager.newImmOpnd(typeManager.getInt32Type(), Opnd::RuntimeInfo::Kind_MethodDirectAddr, desc); + Opnd * retOpnd=createResultOpnd(retType); + CallInst * callInst=irManager.newCallInst(target, irManager.getDefaultManagedCallingConvention(), + numArgs, (Opnd **)args, retOpnd, ii); + appendInsts(callInst); + return retOpnd; } //_______________________________________________________________________________________________________________ @@ -2158,12 +2448,12 @@ CG_OpndHandle* InstCodeSelector::tau_cal NamedType* vtableType = desc->getParentType(); Type* vtableAddrType = typeManager.getVTablePtrType(vtableType); CG_OpndHandle * tauUnsafe = getTauUnsafe(); - if (vtableType->isInterface()) - vtableAddr = tau_ldIntfTableAddr(vtableAddrType, args[0], - vtableType, tauUnsafe); - else + if (vtableType->isInterface()) { + vtableAddr = tau_ldIntfTableAddr(vtableAddrType, args[0], vtableType); + } else { vtableAddr = tau_ldVTableAddr(vtableAddrType, args[0], tauNullChecked); - CG_OpndHandle * virtFunAddr = tau_ldVirtFunAddr(typeManager.getIntPtrType(), + } + CG_OpndHandle * virtFunAddr = tau_ldVirtFunAddr(typeManager.getUnmanagedPtrType(typeManager.getUIntPtrType()), vtableAddr, desc, tauUnsafe); return tau_calli(numArgs,args,retType,virtFunAddr,tauNullChecked, tauTypesChecked); } @@ -2177,7 +2467,7 @@ CG_OpndHandle* InstCodeSelector::callint IntrinsicCallOp::Id callId) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -2191,7 +2481,7 @@ CG_OpndHandle* InstCodeSelector::tau_cal CG_OpndHandle* tauTypesChecked) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ @@ -2202,12 +2492,67 @@ CG_OpndHandle* InstCodeSelector::callhel Type* retType, JitHelperCallOp::Id callId) { - Opnd * dstOpnd=createResultOpnd(retType); - switch(callId) { + Opnd * dstOpnd=createResultOpnd(retType); + switch(callId) { case InitializeArray: assert(numArgs == 4); appendInsts(irManager.newInternalRuntimeHelperCallInst("initialize_array", numArgs, (Opnd**)args, dstOpnd)); - break; + break; + case SaveThisState: + { + assert(numArgs == 1); +#ifdef PLATFORM_POSIX + // Not supported + assert(0); +#else // PLATFORM_POSIX + // TLS base can be obtained from [fs:0x14] + Opnd * tlsBaseReg = irManager.newOpnd(typeManager.getUnmanagedPtrType(typeManager.getInt32Type())); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, tlsBaseReg, + irManager.newMemOpnd(typeManager.getInt32Type(), + MemOpndKind_Any, + NULL, + 0x14, RegName_FS))); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, + irManager.newMemOpnd(typeManager.getUnmanagedPtrType(typeManager.getInt32Type()), + MemOpndKind_Any, + tlsBaseReg, + flagTLSThreadStateOffset()), + (Opnd*)args[0])); +#endif // PLATFORM_POSIX + + break; + } + case ReadThisState: + { + assert(numArgs == 0); +#ifdef PLATFORM_POSIX + // Not supported + assert(0); + // Not supported + assert(0); +#else // PLATFORM_POSIX + // TLS base can be obtained from [fs:0x14] + Opnd * tlsBaseReg = irManager.newOpnd(typeManager.getUnmanagedPtrType(typeManager.getInt32Type())); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, + tlsBaseReg, + irManager.newMemOpnd(typeManager.getInt32Type(), + MemOpndKind_Any, + NULL, 0x14, RegName_FS))); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dstOpnd, + irManager.newMemOpnd(typeManager.getInt32Type(), + MemOpndKind_Any, + tlsBaseReg, + flagTLSThreadStateOffset()))); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, + irManager.newMemOpnd(typeManager.getInt32Type(), + MemOpndKind_Any, + tlsBaseReg, + flagTLSThreadStateOffset()), + irManager.newImmOpnd(typeManager.getInt32Type(),1))); +#endif + + break; + } default: assert(0); } @@ -2220,7 +2565,8 @@ CG_OpndHandle* InstCodeSelector::callhel CG_OpndHandle* InstCodeSelector::callvmhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType, - VMHelperCallOp::Id callId) + VMHelperCallOp::Id callId, + InlineInfo* ii) { Opnd* dstOpnd=NULL; switch(callId) { @@ -2237,7 +2583,7 @@ CG_OpndHandle* InstCodeSelector::callvmh hlpArgs[numArgs] = irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_MethodRuntimeId, md); appendInsts(irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_Throw_Lazy, - numArgs+1, (Opnd**)hlpArgs, dstOpnd)); + numArgs+1, (Opnd**)hlpArgs, dstOpnd, ii)); break; } default: @@ -2252,7 +2598,7 @@ CG_OpndHandle* InstCodeSelector::callvmh CG_OpndHandle* InstCodeSelector::box(ObjectType * boxedType, CG_OpndHandle * val) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -2261,7 +2607,7 @@ CG_OpndHandle* InstCodeSelector::box(Obj CG_OpndHandle* InstCodeSelector::unbox(Type * dstType, CG_OpndHandle* objHandle) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -2270,7 +2616,7 @@ CG_OpndHandle* InstCodeSelector::unbox(T CG_OpndHandle* InstCodeSelector::ldValueObj(Type* objType, CG_OpndHandle *srcAddr) { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -2279,7 +2625,7 @@ CG_OpndHandle* InstCodeSelector::ldValue void InstCodeSelector::stValueObj(CG_OpndHandle *dstAddr, CG_OpndHandle *src) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -2287,7 +2633,7 @@ void InstCodeSelector::stValueObj(CG_Opn void InstCodeSelector::initValueObj(Type* objType, CG_OpndHandle *objAddr) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -2295,7 +2641,7 @@ void InstCodeSelector::initValueObj(Type void InstCodeSelector::copyValueObj(Type* objType, CG_OpndHandle *dstAddr, CG_OpndHandle *srcAddr) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -2309,7 +2655,7 @@ #define FAST_PATH_MONITOR_EXIT_SUCCESS_P bool InstCodeSelector::inlineSync(CompilationInterface::ObjectSynchronizationInfo& syncInfo) { - return false; + return false; } //_______________________________________________________________________________________________________________ @@ -2317,10 +2663,10 @@ bool InstCodeSelector::inlineSync(Compil void InstCodeSelector::tau_monitorEnter(CG_OpndHandle* obj, CG_OpndHandle* tauIsNonNull) { - Opnd * helperOpnds[] = { (Opnd*)obj }; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_ObjMonitorEnter, - 1, helperOpnds, NULL); - appendInsts(callInst); + Opnd * helperOpnds[] = { (Opnd*)obj }; + CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_ObjMonitorEnter, + 1, helperOpnds, NULL); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -2329,10 +2675,10 @@ void InstCodeSelector::tau_monitorEnter( void InstCodeSelector::tau_monitorExit(CG_OpndHandle* obj, CG_OpndHandle* tauIsNonNull) { - Opnd * helperOpnds[] = { (Opnd*)obj }; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_ObjMonitorExit, - 1, helperOpnds, NULL); - appendInsts(callInst); + Opnd * helperOpnds[] = { (Opnd*)obj }; + CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_ObjMonitorExit, + 1, helperOpnds, NULL); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -2342,37 +2688,37 @@ void InstCodeSelector::tau_monitorExit(C CG_OpndHandle* InstCodeSelector::ldLockAddr(CG_OpndHandle* obj) { ICS_ASSERT(0); - return 0; + return 0; } //_______________________________________________________________________________________________________________ CG_OpndHandle* InstCodeSelector::tau_balancedMonitorEnter(CG_OpndHandle* obj, CG_OpndHandle* lockAddr, CG_OpndHandle* tauIsNonNull) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ void InstCodeSelector::balancedMonitorExit(CG_OpndHandle* obj, CG_OpndHandle* lockAddr, CG_OpndHandle* oldLock) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ CG_OpndHandle* InstCodeSelector::tau_optimisticBalancedMonitorEnter(CG_OpndHandle* obj, CG_OpndHandle* lockAddr, CG_OpndHandle* tauIsNonNull) { - ICS_ASSERT(0); - return 0; + ICS_ASSERT(0); + return 0; } //_______________________________________________________________________________________________________________ void InstCodeSelector::optimisticBalancedMonitorExit(CG_OpndHandle* obj, CG_OpndHandle* lockAddr, CG_OpndHandle* oldLock) { - ICS_ASSERT(0); + ICS_ASSERT(0); } //_______________________________________________________________________________________________________________ @@ -2380,7 +2726,7 @@ void InstCodeSelector::optimis uint32 InstCodeSelector::getSyncFenceFlag() { - ICS_ASSERT(0); + ICS_ASSERT(0); return 0; } @@ -2399,27 +2745,27 @@ void InstCodeSelector::monitorExitFence( } //_______________________________________________________________________________________________________________ -// Acquire monitor for a class -// Helper_TypeMonitorEnter(typeRuntimeId) +// Acquire monitor for a class +// Helper_TypeMonitorEnter(typeRuntimeId) void InstCodeSelector::typeMonitorEnter(NamedType *type) { - Opnd * helperOpnds[]={irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type)}; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_TypeMonitorEnter, - 1, helperOpnds, NULL); - appendInsts(callInst); + Opnd * helperOpnds[]={irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type)}; + CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_TypeMonitorEnter, + 1, helperOpnds, NULL); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ // Release monitor for a class -// Helper_TypeMonitorExit(typeRuntimeId) +// Helper_TypeMonitorExit(typeRuntimeId) void InstCodeSelector::typeMonitorExit(NamedType *type) { - Opnd * helperOpnds[]={irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type)}; - CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_TypeMonitorExit, - 1, helperOpnds, NULL); - appendInsts(callInst); + Opnd * helperOpnds[]={irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type)}; + CallInst * callInst=irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_TypeMonitorExit, + 1, helperOpnds, NULL); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -2430,28 +2776,28 @@ CG_OpndHandle* InstCodeSelector::tau_sta CG_OpndHandle* obj, CG_OpndHandle* tauIsType) { - Opnd * dst=irManager.newOpnd(toType); - copyOpnd(dst, (Opnd*)obj); - return (Opnd*)dst; + Opnd * dst=irManager.newOpnd(toType); + copyOpnd(dst, (Opnd*)obj); + return (Opnd*)dst; } //_______________________________________________________________________________________________________________ -// Cast object to type and return the object if casting is legal, -// otherwise throw an exception. -// The cast operation does not produce a tau. +// Cast object to type and return the object if casting is legal, +// otherwise throw an exception. +// The cast operation does not produce a tau. CG_OpndHandle* InstCodeSelector::tau_cast(ObjectType *toType, CG_OpndHandle* obj, CG_OpndHandle* tauCheckedNull) { - Opnd * dst=irManager.newOpnd(toType); - Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, toType) }; - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_Cast, - lengthof(args), args, dst - ); - appendInsts(callInst); - return dst; + Opnd * dst=irManager.newOpnd(toType); + Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, toType) }; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_Cast, + lengthof(args), args, dst + ); + appendInsts(callInst); + return dst; } //_______________________________________________________________________________________________________________ @@ -2465,14 +2811,14 @@ CG_OpndHandle* InstCodeSelector::tau_che CG_OpndHandle* obj, CG_OpndHandle* tauCheckedNull) { - Opnd * dst=irManager.newOpnd(toType); - Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, toType) }; - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_Cast, - lengthof(args), args, dst - ); - appendInsts(callInst); - return getTauUnsafe(); + Opnd * dst=irManager.newOpnd(toType); + Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, toType) }; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_Cast, + lengthof(args), args, dst + ); + appendInsts(callInst); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2483,12 +2829,12 @@ CG_OpndHandle* InstCodeSelector::tau_asT CG_OpndHandle* obj, CG_OpndHandle* tauCheckedNull) { - Opnd * instanceOfResult=(Opnd*)tau_instanceOf(type, obj, tauCheckedNull); - Opnd * dst=irManager.newOpnd(type); - cmpToEflags(CompareOp::Eq, CompareOp::Ref, (Opnd*)instanceOfResult, NULL); - appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); - appendInsts(irManager.newInstEx(Mnemonic_CMOVZ, 1, dst, (Opnd*)obj)); - return dst; + Opnd * instanceOfResult=(Opnd*)tau_instanceOf(type, obj, tauCheckedNull); + Opnd * dst=irManager.newOpnd(type); + cmpToEflags(CompareOp::Eq, CompareOp::Ref, (Opnd*)instanceOfResult, NULL); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, dst, irManager.newImmOpnd(typeManager.getInt32Type(), 0))); + appendInsts(irManager.newInstEx(Mnemonic_CMOVZ, 1, dst, (Opnd*)obj)); + return dst; } //_______________________________________________________________________________________________________________ @@ -2499,14 +2845,18 @@ CG_OpndHandle* InstCodeSelector::tau_ins CG_OpndHandle* obj, CG_OpndHandle* tauCheckedNull) { - Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); - Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type) }; - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_IsInstanceOf, - lengthof(args), args, dst - ); - appendInsts(callInst); - return dst; +#ifdef _EM64T_ + Opnd * dst=irManager.newOpnd(typeManager.getInt64Type()); +#else + Opnd * dst=irManager.newOpnd(typeManager.getInt32Type()); +#endif + Opnd * args[]={ (Opnd*)obj, irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, type) }; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_IsInstanceOf, + lengthof(args), args, dst + ); + appendInsts(callInst); + return dst; } //_______________________________________________________________________________________________________________ @@ -2516,12 +2866,12 @@ void InstCodeSelector::initType(Type* ty { assert(type->isObject()); NamedType * namedType = type->asNamedType(); - Opnd * args[]={ irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, namedType) }; - CallInst * callInst=irManager.newRuntimeHelperCallInst( - CompilationInterface::Helper_InitType, - lengthof(args), args, NULL - ); - appendInsts(callInst); + Opnd * args[]={ irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_TypeRuntimeId, namedType) }; + CallInst * callInst=irManager.newRuntimeHelperCallInst( + CompilationInterface::Helper_InitType, + lengthof(args), args, NULL + ); + appendInsts(callInst); } //_______________________________________________________________________________________________________________ @@ -2530,7 +2880,7 @@ void InstCodeSelector::initType(Type* ty CG_OpndHandle* InstCodeSelector::catchException(Type * exceptionType) { Opnd * exceptionObj = irManager.newOpnd(exceptionType); - appendInsts(irManager.newCatchPseudoInst(exceptionObj)); + appendInsts(irManager.newCatchPseudoInst(exceptionObj)); return exceptionObj; } @@ -2541,11 +2891,11 @@ CG_OpndHandle* InstCodeSelector::catchE // CG_OpndHandle * InstCodeSelector::copy(CG_OpndHandle *src) { - if (src==getTauUnsafe()) - return src; - Opnd * dst=irManager.newOpnd(((Opnd*)src)->getType()); - copyOpnd(dst, (Opnd*)src); - return dst; + if (src==getTauUnsafe()) + return src; + Opnd * dst=irManager.newOpnd(((Opnd*)src)->getType()); + copyOpnd(dst, (Opnd*)src); + return dst; } @@ -2561,7 +2911,7 @@ void InstCodeSelector::prefetch(CG_OpndH CG_OpndHandle* InstCodeSelector::tauPoint() { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2569,7 +2919,7 @@ CG_OpndHandle* InstCodeSelector::tauPoi CG_OpndHandle * InstCodeSelector::genTauSplit(BranchInst *br) { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2577,7 +2927,7 @@ CG_OpndHandle * InstCodeSelector::genTau CG_OpndHandle* InstCodeSelector::tauEdge() { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2585,7 +2935,7 @@ CG_OpndHandle* InstCodeSelector::tauEdg CG_OpndHandle* InstCodeSelector::tauAnd(uint32 numArgs, CG_OpndHandle** args) { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2594,7 +2944,7 @@ CG_OpndHandle* InstCodeSelector::tauAnd CG_OpndHandle* InstCodeSelector::tauUnsafe() { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2602,7 +2952,7 @@ CG_OpndHandle* InstCodeSelector::tauUns CG_OpndHandle* InstCodeSelector::tauSafe() { - return getTauUnsafe(); + return getTauUnsafe(); } //_______________________________________________________________________________________________________________ @@ -2635,6 +2985,68 @@ void InstCodeSelector::pred_btrue(CG_Opn // END new tau instructions +//____________________________________________________________________________________________________ +// Pseudo instruction + +void InstCodeSelector::pseudoInst() { + appendInsts(irManager.newEmptyPseudoInst()); +} +//____________________________________________________________________________________________________ +// Method entry/end marker instructions + +void InstCodeSelector::methodEntry(MethodDesc* mDesc) { + appendInsts(irManager.newMethodEntryPseudoInst(mDesc)); + Opnd* dstOpnd = NULL; + if (irManager.getCompilationInterface().getCompilationParams().exe_notify_method_entry) { + Opnd **hlpArgs = new (memManager) Opnd* [1]; + hlpArgs[0] = irManager.newImmOpnd(getRuntimeIdType(), + Opnd::RuntimeInfo::Kind_MethodRuntimeId, mDesc); + appendInsts(irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_MethodEntry, + 1, (Opnd**)hlpArgs, dstOpnd)); + } +} +void InstCodeSelector::methodEnd(MethodDesc* mDesc, CG_OpndHandle* retOpnd) { + Opnd* ret_val = (Opnd*)retOpnd; + if (ret_val == NULL) { + ret_val = irManager.newImmOpnd(typeManager.getInt32Type(), 0); + } + if (irManager.getCompilationInterface().getCompilationParams().exe_notify_method_exit) { + genExitHelper(ret_val, mDesc); + } + appendInsts(irManager.newMethodEndPseudoInst(mDesc)); +} + +void InstCodeSelector::genExitHelper(Opnd* ret_val, MethodDesc* mDesc) { + Opnd* bufOpnd = irManager.newOpnd(typeManager.getIntPtrType()); + + if ((ret_val->getType()->isInt8())) { + Opnd* longOpnd = (Opnd*)NULL; + + longOpnd = irManager.newMemOpnd(ret_val->getType(), MemOpndKind_StackAutoLayout, + irManager.getRegOpnd(STACK_REG), 0); + + appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV, 1, longOpnd, ret_val)); + Opnd* zOpnd = irManager.newMemOpnd(ret_val->getType(), MemOpndKind_StackAutoLayout, + irManager.getRegOpnd(STACK_REG), 0); + Opnd* longArr[] = {longOpnd}; + appendInsts(irManager.newAliasPseudoInst(zOpnd, 1, longArr)); + appendInsts(irManager.newInst(Mnemonic_LEA, bufOpnd, zOpnd)); + } else { + Opnd* stackLayOutedOpnd = irManager.newMemOpnd(ret_val->getType(), + MemOpndKind_StackAutoLayout, + irManager.getRegOpnd(STACK_REG), + 0); + appendInsts(irManager.newCopyPseudoInst(Mnemonic_MOV, stackLayOutedOpnd, ret_val)); + appendInsts(irManager.newInst(Mnemonic_LEA, bufOpnd, stackLayOutedOpnd)); + + } + Opnd* hlpArgs[] = { irManager.newImmOpnd(getRuntimeIdType(), Opnd::RuntimeInfo::Kind_MethodRuntimeId, mDesc), + bufOpnd }; + + appendInsts(irManager.newRuntimeHelperCallInst(CompilationInterface::Helper_MethodExit, + 2, (Opnd**)hlpArgs, NULL)); +} +//____________________________________________________________________________________________________ }}; // namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h index 7ab86c3..713cf27 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.h @@ -23,7 +23,6 @@ #define _IA32_INST_SELECTOR_H #include "CodeGenIntfc.h" #include "Ia32CodeSelector.h" -#include "Timer.h" #include "CGSupport.h" namespace Jitrino { @@ -46,13 +45,13 @@ class InstCodeSelector : public Instruct public: virtual void throwLinkingException(Class_Handle encClass, uint32 cp_ndx, uint32 opcode); - static void onCFGInit(IRManager& irManager); + static void onCFGInit(IRManager& irManager); - InstCodeSelector(CompilationInterface& compIntfc, - CfgCodeSelector& codeSel, - IRManager& irM, - BasicBlock * currentBasicBlock - ); + InstCodeSelector(CompilationInterface& compIntfc, + CfgCodeSelector& codeSel, + IRManager& irM, + Node * currentBasicBlock + ); virtual ~InstCodeSelector () {} @@ -81,7 +80,7 @@ public: CG_OpndHandle* sub(ArithmeticOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2); CG_OpndHandle* subRef(RefArithmeticOp::Types,CG_OpndHandle* refSrc, CG_OpndHandle* intSrc); CG_OpndHandle* diffRef(bool ovf, CG_OpndHandle* ref1,CG_OpndHandle* ref2); - CG_OpndHandle* scaledDiffRef(CG_OpndHandle* ref1,CG_OpndHandle* ref2); + CG_OpndHandle* scaledDiffRef(CG_OpndHandle* ref1,CG_OpndHandle* ref2, Type*, Type*); CG_OpndHandle* mul(ArithmeticOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2); CG_OpndHandle* tau_div(DivOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2,CG_OpndHandle *tauSrc1NonZero); CG_OpndHandle* tau_rem(DivOp::Types,CG_OpndHandle* src1,CG_OpndHandle* src2,CG_OpndHandle *tauSrc2NonZero); @@ -110,7 +109,7 @@ public: void jump() { // do nothing } - void tableSwitch(CG_OpndHandle* src, uint32 nTargets); + void tableSwitch(CG_OpndHandle* src, uint32 nTargets); void throwException(CG_OpndHandle* exceptionObj, bool createStackTrace); void throwSystemException(CompilationInterface::SystemExceptionId); CG_OpndHandle* convToInt(ConvertToIntOp::Types,bool isSigned, @@ -151,9 +150,9 @@ public: CG_OpndHandle* ldFieldAddr(Type* fieldRefType,CG_OpndHandle* base,FieldDesc *desc); CG_OpndHandle* ldStaticAddr(Type* fieldRefType,FieldDesc *desc); CG_OpndHandle* ldElemBaseAddr(CG_OpndHandle *array); - CG_OpndHandle* addElemIndex(CG_OpndHandle *elemBase,CG_OpndHandle* index); + CG_OpndHandle* addElemIndex(Type*, CG_OpndHandle *elemBase,CG_OpndHandle* index); CG_OpndHandle* ldElemAddr(CG_OpndHandle* array,CG_OpndHandle* index) { - return addElemIndex(ldElemBaseAddr(array),index); + return addElemIndex(NULL,ldElemBaseAddr(array),index); } CG_OpndHandle* tau_ldInd(Type* dstType, CG_OpndHandle* ptr, Type::Tag memType, bool autoUncompressRef,bool speculative, @@ -186,7 +185,7 @@ public: CG_OpndHandle* newObj(ObjectType* objType); CG_OpndHandle* newArray(ArrayType* arrayType, CG_OpndHandle* numElems); CG_OpndHandle* newMultiArray(ArrayType* arrayType, uint32 numDims, CG_OpndHandle** dims); - CG_OpndHandle* ldString(MethodDesc* enclosingMethod,uint32 stringToken, bool uncompress); + CG_OpndHandle* ldRef(Type *dstType, MethodDesc* enclosingMethod,uint32 stringToken, bool uncompress); CG_OpndHandle* ldToken(Type *dstType,MethodDesc* enclosingMethod,uint32 token); void incCounter(Type *counterType,uint32 counter); @@ -199,8 +198,7 @@ public: MethodDesc *desc, CG_OpndHandle *tauVtableHasDesc); CG_OpndHandle* tau_ldVTableAddr(Type *dstType, CG_OpndHandle* base, CG_OpndHandle *tauBaseNonNull); CG_OpndHandle* getVTableAddr(Type *dstType, ObjectType *base); - CG_OpndHandle* tau_ldIntfTableAddr(Type *dstType, CG_OpndHandle* base,NamedType* vtableTypeDesc, - CG_OpndHandle *tauBaseHasIntf); + CG_OpndHandle* tau_ldIntfTableAddr(Type *dstType, CG_OpndHandle* base,NamedType* vtableTypeDesc); CG_OpndHandle* calli(uint32 numArgs,CG_OpndHandle** args, Type* retType, CG_OpndHandle* methodPtr, InlineInfo* ii = NULL); CG_OpndHandle* tau_calli(uint32 numArgs,CG_OpndHandle** args, Type* retType, @@ -211,11 +209,12 @@ public: CG_OpndHandle* tau_call(uint32 numArgs, CG_OpndHandle** args, Type* retType, MethodDesc *desc, CG_OpndHandle *nonNullFirstArgTau, CG_OpndHandle *tauTypesChecked, InlineInfo* ii = NULL); - CG_OpndHandle* tau_callvirt(uint32 numArgs,CG_OpndHandle** args, Type* retType, MethodDesc *desc, CG_OpndHandle* tauNullChecked, CG_OpndHandle* tauTypesChecked, InlineInfo* ii = NULL); + CG_OpndHandle* tau_callvirt(uint32 numArgs,CG_OpndHandle** args, Type* retType, MethodDesc *desc, CG_OpndHandle* tauNullChecked, CG_OpndHandle* tauTypesChecked, InlineInfo* ii = NULL); CG_OpndHandle* callintr(uint32 numArgs, CG_OpndHandle** args, Type* retType,IntrinsicCallOp::Id callId); - CG_OpndHandle* tau_callintr(uint32 numArgs, CG_OpndHandle** args, Type* retType,IntrinsicCallOp::Id callId, CG_OpndHandle *tauNullsChecked, CG_OpndHandle *tauTypesChecked); + CG_OpndHandle* tau_callintr(uint32 numArgs, CG_OpndHandle** args, Type* retType,IntrinsicCallOp::Id callId, CG_OpndHandle *tauNullsChecked, CG_OpndHandle *tauTypesChecked); CG_OpndHandle* callhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType,JitHelperCallOp::Id callId); - CG_OpndHandle* callvmhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType,VMHelperCallOp::Id callId); + CG_OpndHandle* callvmhelper(uint32 numArgs, CG_OpndHandle** args, Type* retType, + VMHelperCallOp::Id callId, InlineInfo* ii = NULL); CG_OpndHandle* box(ObjectType * boxedType, CG_OpndHandle* val); CG_OpndHandle* unbox(Type * dstType, CG_OpndHandle* objHandle); CG_OpndHandle* ldValueObj(Type* objType, CG_OpndHandle *srcAddr); @@ -254,6 +253,12 @@ public: CG_OpndHandle* catchException(Type * exceptionType); CG_OpndHandle* copy(CG_OpndHandle *src); void prefetch(CG_OpndHandle *src, uint32 offset, int hints); + + void pseudoInst(); + + void methodEntry(MethodDesc* mDesc); + void methodEnd(MethodDesc* mDesc, CG_OpndHandle* retOpnd = NULL); + // // Set/clear current persistent id to be assigned to the generated instructions // @@ -273,6 +278,7 @@ public: CompilationInterface::RuntimeHelperId helper, Type *typeArgument, Opnd * nonNullFirstArgTau); + void genExitHelper(Opnd* retOpnd, MethodDesc* meth); // // Block information instructions @@ -299,35 +305,36 @@ private: // uint64 currentHIRInstrID; - Opnd * convertIntToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); - Opnd * convertIntToFp(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); - Opnd * convertFpToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); - Opnd * convertFpToFp(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); + Opnd * convertIntToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); + Opnd * convertIntToFp(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); + Opnd * convertFpToInt(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); + Opnd * convertFpToFp(Opnd * srcOpnd, Type * dstType, Opnd * dstOpnd=NULL); - bool isIntegerType(Type * type) - { return type->isInteger()||type->isBoolean()||type->isChar(); } - void copyOpnd(Opnd *dst, Opnd *src); - void copyOpndTrivialOrTruncatingConversion(Opnd *dst, Opnd *src); + bool isIntegerType(Type * type) + { return type->isInteger()||type->isBoolean()||type->isChar(); } + void copyOpnd(Opnd *dst, Opnd *src); + void copyOpndTrivialOrTruncatingConversion(Opnd *dst, Opnd *src); - Opnd * convert(CG_OpndHandle * oph, Type * dstType, Opnd * dstOpnd=NULL); + Opnd * convert(CG_OpndHandle * oph, Type * dstType, Opnd * dstOpnd=NULL); - Opnd * simpleOp_I8(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); + Opnd * simpleOp_I8(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); - Opnd * simpleOp_I4(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); - Opnd * fpOp(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); + Opnd * simpleOp_I4(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); + + Opnd * fpOp(Mnemonic mn, Type * dstType, Opnd * src1, Opnd * src2); - Opnd * createResultOpnd(Type * dstType); + Opnd * createResultOpnd(Type * dstType); - Opnd * divOp(DivOp::Types op, bool rem, Opnd * src1, Opnd * src2); + Opnd * divOp(DivOp::Types op, bool rem, Opnd * src1, Opnd * src2); - Opnd * minMaxOp(NegOp::Types opType, bool max, Opnd * src1, Opnd * src2); + Opnd * minMaxOp(NegOp::Types opType, bool max, Opnd * src1, Opnd * src2); - Opnd * shiftOp(IntegerOp::Types opType, Mnemonic mn, Opnd * value, Opnd * shiftAmount); + Opnd * shiftOp(IntegerOp::Types opType, Mnemonic mn, Opnd * value, Opnd * shiftAmount); - bool cmpToEflags(CompareOp::Operators cmpOp, CompareOp::Types opType, - Opnd * src1, Opnd * src2 - ); - // + bool cmpToEflags(CompareOp::Operators cmpOp, CompareOp::Types opType, + Opnd * src1, Opnd * src2 + ); + // // Enums // enum XmulKind {XmulKind_Low, XmulKind_High, XmulKind_HighUnsigned}; @@ -338,13 +345,12 @@ private: MethodDesc * getMethodDesc() { return codeSelector.methodCodeSelector.getMethodDesc(); } - CodeProfiler * getCodeProfiler(){ return codeSelector.methodCodeSelector.getProfileInfo(); } - MemoryManager& getCodeSelectorMemoryManager(){ return codeSelector.methodCodeSelector.codeSelectorMemManager; } - + MemoryManager& getCodeSelectorMemoryManager(){ return codeSelector.methodCodeSelector.codeSelectorMemManager; } + Type * getMethodReturnType() { return getMethodDesc()->getMethodSig()->getReturnType(); } - Opnd * sxtInt32(Opnd *opnd); - Opnd * zxtInt32(Opnd *opnd); + Opnd * sxtInt32(Opnd *opnd); + Opnd * zxtInt32(Opnd *opnd); void sxtOneInt32(Opnd*& opnd1, Opnd*& opnd2); void zxtOneInt32(Opnd*& opnd1, Opnd*& opnd2); bool opndIsFoldableImm(Opnd * opnd, uint32 nbits, @@ -370,7 +376,7 @@ private: bool autoCompressRef, Opnd *baseTau, Opnd *offsetAndTypeTau); Type * getFieldRefType(Type *dstType, Type::Tag memType); void simplifyTypeTag(Type::Tag& tag,Type *ptr); - Opnd ** createReturnArray(Type * retType, uint32& numRegRet); + Opnd ** createReturnArray(Type * retType, uint32& numRegRet); void assignCallArgs(CallInst *call, uint32 numArgs, CG_OpndHandle **args, Type *retType, bool isHelperCall); CG_OpndHandle* assignCallRet(CallInst *call, Type *retType, bool isHelperCall); @@ -384,13 +390,13 @@ private: CG_OpndHandle* src); CG_OpndHandle * genTauSplit(BranchInst * br); - Type * getRuntimeIdType() {return typeManager.getIntPtrType();} + Type * getRuntimeIdType() {return typeManager.getUnmanagedPtrType(typeManager.getIntPtrType());} - // Check if we should inline synchronization + // Check if we should inline synchronization bool inlineSync(CompilationInterface::ObjectSynchronizationInfo& syncInfo); - // Check if we should generate tau instructions - bool suppressTauInsts(){ return true; }; + // Check if we should generate tau instructions + bool suppressTauInsts(){ return true; }; // // Synchronization fence flag // @@ -410,36 +416,33 @@ private: Opnd * createIntReg(Type * type); Opnd * createFloatReg(Type * type); - CG_OpndHandle* getTauUnsafe()const - { return (CG_OpndHandle*)&_tauUnsafe; } - + CG_OpndHandle* getTauUnsafe()const + { return (CG_OpndHandle*)&_tauUnsafe; } - // + // // Fields // - CompilationInterface& compilationInterface; - CfgCodeSelector& codeSelector; - IRManager& irManager; - TypeManager& typeManager; - MemoryManager memManager; // for local data - BasicBlock * currentBasicBlock; - Opnd ** vars; - uint32 inArgPos; - int persistentId; + CompilationInterface& compilationInterface; + CfgCodeSelector& codeSelector; + IRManager& irManager; + TypeManager& typeManager; + MemoryManager memManager; // for local data + Node* currentBasicBlock; + Opnd ** vars; + uint32 inArgPos; + int persistentId; #ifdef _DEBUG - uint32 nextInArg; + uint32 nextInArg; #endif - bool seenReturn; - Opnd * switchSrcOpnd; - uint32 switchNumTargets; - PersistentInstructionId currPersistentId; - Opnd * currPredOpnd; - static CompilationInterface::RuntimeHelperId + bool seenReturn; + Opnd * switchSrcOpnd; + uint32 switchNumTargets; + PersistentInstructionId currPersistentId; + Opnd * currPredOpnd; + static CompilationInterface::RuntimeHelperId divOpHelperIds[], remOpHelperIds[]; - - - static uint32 _tauUnsafe; + static uint32 _tauUnsafe; }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.cpp vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.cpp index 45a0c47..777c4fc 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.cpp @@ -17,809 +17,985 @@ * @author Nikolay A. Sidelnikov * @version $Revision: 1.2.12.3.4.3 $ */ +#include "Ia32IRManager.h" -#include "Ia32InternalProfiler.h" namespace Jitrino { namespace Ia32{ -const AttrDesc opndRoles[] = { - {Inst::OpndRole_Null,"Null"}, - {Inst::OpndRole_Use,"Use"}, - {Inst::OpndRole_Def, "Def"}, - {Inst::OpndRole_UseDef,"UseDef"}, - {Inst::OpndRole_FromEncoder, "FromEncoder"}, - {Inst::OpndRole_Explicit, "Explicit"}, - {Inst::OpndRole_Auxilary, "Auxilary"}, - {Inst::OpndRole_Changeable, "Changeable"}, - {Inst::OpndRole_Implicit, "Implicit"}, - {Inst::OpndRole_InstLevel, "InstLevel"}, - {Inst::OpndRole_MemOpndSubOpnd, "MemOpndSubOpnd"}, - {Inst::OpndRole_OpndLevel, "OpndLevel"}, - {Inst::OpndRole_ForIterator, "ForIterator"}, - {Inst::OpndRole_All, "All"}, - {Inst::OpndRole_AllDefs, "AllDefs"}, - {Inst::OpndRole_AllUses, "AllUses"}, + template struct AttrDesc { + T value; + char * name; + }; + + struct BBStats { + int64 * bbExecCount; + uint32 * counters; + + BBStats() : bbExecCount(NULL), counters(NULL) {} + }; + + struct MethodStats { + std::string methodName; + StlMap bbStats; //bbID, bbExecCount, array of counters + MethodStats(std::string s, MemoryManager& mm) : methodName(s), bbStats(mm) {} + }; + +typedef StlVector Statistics; + +template class FilterAttr { + public: + T value; + bool isInitialized; + bool isNegative; + + FilterAttr(T v, bool i = false, bool n = false) : value(v), isInitialized(i), isNegative(n) {}; + + FilterAttr& operator=(const FilterAttr& c) { + FilterAttr& f = *this; + f.value = c.value; + f.isInitialized = c.isInitialized; + f.isNegative = c.isNegative; + return f; + } }; -const AttrDesc memOpndKinds[] = { - {MemOpndKind_Null, "Null"}, - {MemOpndKind_StackAutoLayout, "StackAutoLayout"}, - {MemOpndKind_StackManualLayout, "StackManualLayout"}, - {MemOpndKind_Stack, "Stack"}, - {MemOpndKind_Heap, "Heap"}, - {MemOpndKind_ConstantArea, "ConstantArea"}, - {MemOpndKind_Any, "Any"}, +struct OpndFilter { + bool isInitialized; + int opNum; + FilterAttr opndRole; + FilterAttr opndKind; + FilterAttr regName; + FilterAttr memOpndKind; + + OpndFilter() : isInitialized(false), opNum(-1), opndRole(Inst::OpndRole_Null), opndKind(OpndKind_Null), regName(RegName_Null), memOpndKind(MemOpndKind_Null) {} + + OpndFilter& operator=(const OpndFilter& c) { + OpndFilter& f = *this; + f.isInitialized = c.isInitialized; + f.opNum = c.opNum; + f.opndRole =c.opndRole; + f.opndKind =c.opndKind; + f.regName =c.regName; + f.memOpndKind =c.memOpndKind; + return f; + } + }; -const AttrDesc rtKinds[] = { - {Opnd::RuntimeInfo::Kind_Null, "Null"}, - {Opnd::RuntimeInfo::Kind_AllocationHandle, "AllocationHandle"}, - {Opnd::RuntimeInfo::Kind_TypeRuntimeId, "TypeRuntimeId" }, - {Opnd::RuntimeInfo::Kind_MethodRuntimeId,"MethodRuntimeId" }, - {Opnd::RuntimeInfo::Kind_StringDescription, "StringDescription" }, - {Opnd::RuntimeInfo::Kind_Size, "Size" }, - {Opnd::RuntimeInfo::Kind_HelperAddress, "HelperAddress"}, - {Opnd::RuntimeInfo::Kind_InternalHelperAddress, "InternalHelperAddress"}, - {Opnd::RuntimeInfo::Kind_StaticFieldAddress,"StaticFieldAddress"}, - {Opnd::RuntimeInfo::Kind_FieldOffset,"FieldOffset"}, - {Opnd::RuntimeInfo::Kind_VTableAddrOffset,"VTableAddrOffset"}, - {Opnd::RuntimeInfo::Kind_VTableConstantAddr,"VTableConstantAddr"}, - {Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset,"MethodVtableSlotOffset"}, - {Opnd::RuntimeInfo::Kind_MethodIndirectAddr,"MethodIndirectAddr"}, - {Opnd::RuntimeInfo::Kind_MethodDirectAddr,"MethodDirectAddr"}, - {Opnd::RuntimeInfo::Kind_ConstantAreaItem,"ConstantAreaItem"}, +struct Filter { + bool isInitialized; + bool isNegative; + bool isOR; + + FilterAttr mnemonic; + FilterAttr operandNumber; + FilterAttr rtKind; + FilterAttr rtHelperID; + FilterAttr rtIntHelperName; + FilterAttr isNative; + FilterAttr isStatic; + FilterAttr isSynchronized; + FilterAttr isNoInlining; + FilterAttr isInstance; + FilterAttr isFinal; + FilterAttr isVirtual; + FilterAttr isAbstract; + FilterAttr isClassInitializer; + FilterAttr isInstanceInitializer; + FilterAttr isStrict; + FilterAttr isRequireSecObject; + FilterAttr isInitLocals; + FilterAttr isOverridden; + + StlMap operandFilters; + + Filter() : isInitialized(false), isNegative(false), isOR(false), mnemonic(Mnemonic_NULL), operandNumber(-1), rtKind(Opnd::RuntimeInfo::Kind_Null),rtHelperID(CompilationInterface::Helper_Null), rtIntHelperName("none"), isNative(false), isStatic(false), isSynchronized(false), isNoInlining(false), isInstance(false), isFinal(false), isVirtual(false), isAbstract(false), isClassInitializer(false), isInstanceInitializer(false), isStrict(false), isRequireSecObject(false), isInitLocals(false), isOverridden(false), operandFilters(Jitrino::getGlobalMM()) {} + + Filter& operator=(const Filter& c) { + Filter& f = *this; + f.isNegative = c.isNegative; + f.isInitialized = c.isInitialized; + f.isOR = c.isOR; + f.mnemonic=c.mnemonic; + f.operandNumber=c.operandNumber; + f.rtKind=c.rtKind; + f.rtHelperID=c.rtHelperID; + f.rtIntHelperName=c.rtIntHelperName; + f.isNative=c.isNative; + f.isStatic=c.isStatic; + f.isSynchronized=c.isSynchronized; + f.isNoInlining = c.isNoInlining; + f.isInstance = c.isInstance; + f.isFinal = c.isFinal; + f.isVirtual = c.isVirtual; + f.isAbstract = c.isAbstract; + f.isClassInitializer = c.isClassInitializer; + f.isInstanceInitializer = c.isInstanceInitializer; + f.isStrict = c.isStrict; + f.isRequireSecObject = c.isRequireSecObject; + f.isInitLocals = c.isInitLocals; + f.isOverridden = c.isOverridden; + + for(StlMap::const_iterator it = c.operandFilters.begin(); it !=c.operandFilters.end(); it++) { + f.operandFilters[it->first] = it->second; + } + return f; + } +}; + +struct Counter { + std::string name; + std::string title; + bool isSorting; + Filter filter; + + Counter() : isSorting(false) {} }; +class Config { +public: + StlVector counters; + + bool printBBStats; + Config(MemoryManager& mm) : counters(mm), printBBStats(false) {}; +}; + + //======================================================================================== // class InternalProfiler //======================================================================================== /** - class InternalProfiler collects information about methods - + class InternalProfiler collects information about methods + */ -Config * InternalProfiler::config = NULL; -Statistics * InternalProfiler::statistics = NULL; - -void InternalProfiler::init() { - if(config) - return; - MemoryManager& mm = Jitrino::getGlobalMM(); - config = new(mm) Config(mm); - statistics = new(mm) Statistics(mm); - readConfig(config); + +class InternalProfilerAct : public Action { +public: + void init(); + void deinit() { dumpIt(); config = NULL; } + +protected: + void readConfig(Config * config); + void dumpIt(); + + Config * config; + Statistics * statistics; + +friend class InternalProfiler; +}; + + +class InternalProfiler : public SessionAction { +public: + void runImpl(); + +protected: + void addCounters(MethodDesc& methodDesc); + + bool passFilter(Inst * inst, Filter& filter); + bool passOpndFilter(Inst * inst, Opnd * opnd, Filter& filter, OpndFilter& opndFltr); +}; + +const AttrDesc opndRoles[] = { + {Inst::OpndRole_Null,"Null"}, + {Inst::OpndRole_Use,"Use"}, + {Inst::OpndRole_Def, "Def"}, + {Inst::OpndRole_UseDef,"UseDef"}, + {Inst::OpndRole_FromEncoder, "FromEncoder"}, + {Inst::OpndRole_Explicit, "Explicit"}, + {Inst::OpndRole_Auxilary, "Auxilary"}, + {Inst::OpndRole_Changeable, "Changeable"}, + {Inst::OpndRole_Implicit, "Implicit"}, + {Inst::OpndRole_InstLevel, "InstLevel"}, + {Inst::OpndRole_MemOpndSubOpnd, "MemOpndSubOpnd"}, + {Inst::OpndRole_OpndLevel, "OpndLevel"}, + {Inst::OpndRole_ForIterator, "ForIterator"}, + {Inst::OpndRole_All, "All"}, + {Inst::OpndRole_AllDefs, "AllDefs"}, + {Inst::OpndRole_AllUses, "AllUses"}, +}; + +const AttrDesc memOpndKinds[] = { + {MemOpndKind_Null, "Null"}, + {MemOpndKind_StackAutoLayout, "StackAutoLayout"}, + {MemOpndKind_StackManualLayout, "StackManualLayout"}, + {MemOpndKind_Stack, "Stack"}, + {MemOpndKind_Heap, "Heap"}, + {MemOpndKind_ConstantArea, "ConstantArea"}, + {MemOpndKind_Any, "Any"}, +}; + +const AttrDesc rtKinds[] = { + {Opnd::RuntimeInfo::Kind_Null, "Null"}, + {Opnd::RuntimeInfo::Kind_AllocationHandle, "AllocationHandle"}, + {Opnd::RuntimeInfo::Kind_TypeRuntimeId, "TypeRuntimeId" }, + {Opnd::RuntimeInfo::Kind_MethodRuntimeId,"MethodRuntimeId" }, + {Opnd::RuntimeInfo::Kind_StringDescription, "StringDescription" }, + {Opnd::RuntimeInfo::Kind_Size, "Size" }, + {Opnd::RuntimeInfo::Kind_HelperAddress, "HelperAddress"}, + {Opnd::RuntimeInfo::Kind_InternalHelperAddress, "InternalHelperAddress"}, + {Opnd::RuntimeInfo::Kind_StaticFieldAddress,"StaticFieldAddress"}, + {Opnd::RuntimeInfo::Kind_FieldOffset,"FieldOffset"}, + {Opnd::RuntimeInfo::Kind_VTableAddrOffset,"VTableAddrOffset"}, + {Opnd::RuntimeInfo::Kind_VTableConstantAddr,"VTableConstantAddr"}, + {Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset,"MethodVtableSlotOffset"}, + {Opnd::RuntimeInfo::Kind_MethodIndirectAddr,"MethodIndirectAddr"}, + {Opnd::RuntimeInfo::Kind_MethodDirectAddr,"MethodDirectAddr"}, + {Opnd::RuntimeInfo::Kind_ConstantAreaItem,"ConstantAreaItem"}, +}; + +static ActionFactory _iprof("iprof"); + +void InternalProfilerAct::init() { + MemoryManager& mm = Jitrino::getGlobalMM(); + config = new(mm) Config(mm); + statistics = new(mm) Statistics(mm); + readConfig(config); } -void InternalProfiler::readConfig(Config * config) { - std::string configString; - std::ifstream configFile; - configFile.open("iprof.cfg", std::ios::in); +void InternalProfilerAct::readConfig(Config * config) { + std::string configString; + std::ifstream configFile; + const char* fname; + if ((fname = getArg("config")) == 0) + fname = "iprof.cfg"; + configFile.open(fname, std::ios::in); + bool rc = false; if (configFile.is_open()) { std::string line; - uint32 ln = 0; - bool opened = false; - int num = -1; - while (std::getline(configFile, line)) { - ln++; - if(!line.empty() && (line.find("#")!= 0)) { - const char * c_line = line.c_str(); - if(std::strstr(c_line, "Config") == c_line) { - if(((int)line.find("PrintBBStats") != -1) && ((int)line.find("true")!=-1)) - config->printBBStats = true; - } else if (line.find("Counter.") == 0) { - if(!opened) { - opened = true; - num = config->counters.size(); - config->counters.push_back(Counter()); - int pos1 = line.find("."); - int pos2 = line.find_first_of(".=" , pos1+1); - - config->counters[num].name = line.substr(pos1+1, pos2-pos1-1); - } - if((int)line.find(".Title=")!=-1) { - char * val = std::strstr(line.c_str(),"=")+1; - config->counters[num].title=std::string(val); - } else if (((int)line.find(".IsOR=")!=-1) && ((int)line.find("true")!=-1)) { - config->counters[num].filter.isOR=true; - } else if ((int)line.find(std::string(config->counters[num].name)+"=")!=-1) { - char * val = std::strstr(line.c_str(),"=")+1; - for(uint32 i = 0; i < config->counters.size(); i++) { - if(std::string(config->counters[i].name) == val) { - config->counters[num].filter = config->counters[i].filter; - break; - } - } - } else if((int)line.find(".Mnemonic")!=-1) { - char * mnem = std::strstr(line.c_str(),"=")+1; - if ((std::string(mnem) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.mnemonic.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.mnemonic.value=EncoderBase::str2mnemonic(mnem); - config->counters[num].filter.mnemonic.isInitialized=true; - } - } else if (std::strstr(line.c_str(), ".OpndNumber")) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.operandNumber.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.operandNumber.value=atoi(val); - config->counters[num].filter.operandNumber.isInitialized=true; - } - } else if ((int)line.find(".Operand.") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - int pos = int(line.find(".Operand.")+9); - std::string v = line.substr(pos, line.find_first_of(".", pos)-pos); - int opNum; - if(v == "*") - opNum = -1; - else - opNum = atoi(v.c_str()); - config->counters[num].filter.operandFilters[opNum].opNum = opNum; - config->counters[num].filter.operandFilters[opNum].isInitialized = true; - if ((int)line.find(".OpndRole") != -1) { - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].opndRole.isInitialized=true; - for (uint32 i = 0; icounters[num].filter.operandFilters[opNum].opndRole.value=opndRoles[i].value; - } - } - } else if ((int)line.find(".OpndKind") != -1) { - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.operandFilters[opNum].opndKind.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].opndKind.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].opndKind.value=getOpndKind(val); - } - } else if ((int)line.find(".RegName") != -1) { - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].regName.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].regName.value = getRegName(val); - } - } else if ((int)line.find(".MemOpndKind") != -1) { - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.operandFilters[opNum].memOpndKind.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.operandFilters[opNum].memOpndKind.isInitialized=true; - for (uint32 i = 0; icounters[num].filter.operandFilters[opNum].memOpndKind.value=memOpndKinds[i].value; - } - } - } - } else if ((int)line.find(".RuntimeInfo.Kind") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.rtKind.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - for (uint32 i = 0; icounters[num].filter.rtKind.value=rtKinds[i].value; - } - //CompilationInterface::str2rid(val); - config->counters[num].filter.rtKind.isInitialized=true; - } - } else if ((int)line.find(".RuntimeInfo.HelperID") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.rtHelperID.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.rtHelperID.value=CompilationInterface::str2rid(val); - config->counters[num].filter.rtHelperID.isInitialized=true; - } - } else if ((int)line.find(".RuntimeInfo.IntHelperName") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.rtIntHelperName.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.rtIntHelperName.value=std::string(val); - config->counters[num].filter.rtIntHelperName.isInitialized=true; - } - } else if ((int)line.find(".isNative") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isNative.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isNative.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isNative.isInitialized=true; - } - } else if ((int)line.find(".isStatic") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isStatic.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isStatic.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isStatic.isInitialized=true; - } - } else if ((int)line.find(".isSynchronized") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isSynchronized.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isSynchronized.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isSynchronized.isInitialized=true; - } - } else if ((int)line.find(".isNoInlining") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isNoInlining.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isNoInlining.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isNoInlining.isInitialized=true; - } - } else if ((int)line.find(".isInstance") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isInstance.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isInstance.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isInstance.isInitialized=true; - } - } else if ((int)line.find(".isFinal") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isFinal.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isFinal.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isFinal.isInitialized=true; - } - } else if ((int)line.find(".isVirtual") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isVirtual.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isVirtual.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isVirtual.isInitialized=true; - } - } else if ((int)line.find(".isAbstract") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isAbstract.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isAbstract.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isAbstract.isInitialized=true; - } - } else if ((int)line.find(".isClassInitializer") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isClassInitializer.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isClassInitializer.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isClassInitializer.isInitialized=true; - } - } else if ((int)line.find(".isInstanceInitializer") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isInstanceInitializer.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isInstanceInitializer.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isInstanceInitializer.isInitialized=true; - } - } else if ((int)line.find(".isStrict") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isStrict.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isStrict.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isStrict.isInitialized=true; - } - } else if ((int)line.find(".isRequireSecObject") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isRequireSecObject.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isRequireSecObject.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isRequireSecObject.isInitialized=true; - } - } else if ((int)line.find(".isInitLocals") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isInitLocals.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isInitLocals.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isInitLocals.isInitialized=true; - } - } else if ((int)line.find(".isOverridden") != -1) { - char * val = std::strstr(line.c_str(),"=")+1; - if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { - config->counters[num].filter.isOverridden.isNegative=true; - } else { - config->counters[num].filter.isInitialized=true; - config->counters[num].filter.isOverridden.value=(std::string(val) == "true")? true : false; - config->counters[num].filter.isOverridden.isInitialized=true; - } - } - } else if (std::strstr(c_line, "[begin]") == c_line) { - } else if (std::strstr(c_line, "[end]") == c_line) { - opened = false; - } else if (std::strstr(c_line, "#") == c_line) { - } else { - ::std::cerr<<"iprof: BAD LINE("<printBBStats = true; + } else if (line.find("Counter.") == 0) { + if(!opened) { + opened = true; + num = config->counters.size(); + config->counters.push_back(Counter()); + int pos1 = line.find("."); + int pos2 = line.find_first_of(".=" , pos1+1); + + config->counters[num].name = line.substr(pos1+1, pos2-pos1-1); + } + if((int)line.find(".Title=")!=-1) { + char * val = std::strstr(line.c_str(),"=")+1; + config->counters[num].title=std::string(val); + } else if (((int)line.find(".IsOR=")!=-1) && ((int)line.find("true")!=-1)) { + config->counters[num].filter.isOR=true; + } else if ((int)line.find(std::string(config->counters[num].name)+"=")!=-1) { + char * val = std::strstr(line.c_str(),"=")+1; + for(uint32 i = 0; i < config->counters.size(); i++) { + if(std::string(config->counters[i].name) == val) { + config->counters[num].filter = config->counters[i].filter; + break; + } + } + } else if((int)line.find(".Mnemonic")!=-1) { + char * mnem = std::strstr(line.c_str(),"=")+1; + if ((std::string(mnem) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.mnemonic.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.mnemonic.value=EncoderBase::str2mnemonic(mnem); + config->counters[num].filter.mnemonic.isInitialized=true; + } + } else if (std::strstr(line.c_str(), ".OpndNumber")) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.operandNumber.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.operandNumber.value=atoi(val); + config->counters[num].filter.operandNumber.isInitialized=true; + } + } else if ((int)line.find(".Operand.") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + int pos = int(line.find(".Operand.")+9); + std::string v = line.substr(pos, line.find_first_of(".", pos)-pos); + int opNum; + if(v == "*") + opNum = -1; + else + opNum = atoi(v.c_str()); + config->counters[num].filter.operandFilters[opNum].opNum = opNum; + config->counters[num].filter.operandFilters[opNum].isInitialized = true; + if ((int)line.find(".OpndRole") != -1) { + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].opndRole.isInitialized=true; + for (uint32 i = 0; icounters[num].filter.operandFilters[opNum].opndRole.value=opndRoles[i].value; + } + } + } else if ((int)line.find(".OpndKind") != -1) { + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.operandFilters[opNum].opndKind.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].opndKind.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].opndKind.value=getOpndKind(val); + } + } else if ((int)line.find(".RegName") != -1) { + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.operandFilters[opNum].opndRole.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].regName.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].regName.value = getRegName(val); + } + } else if ((int)line.find(".MemOpndKind") != -1) { + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.operandFilters[opNum].memOpndKind.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.operandFilters[opNum].memOpndKind.isInitialized=true; + for (uint32 i = 0; icounters[num].filter.operandFilters[opNum].memOpndKind.value=memOpndKinds[i].value; + } + } + } + } else if ((int)line.find(".RuntimeInfo.Kind") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.rtKind.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + for (uint32 i = 0; icounters[num].filter.rtKind.value=rtKinds[i].value; + } + //CompilationInterface::str2rid(val); + config->counters[num].filter.rtKind.isInitialized=true; + } + } else if ((int)line.find(".RuntimeInfo.HelperID") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.rtHelperID.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.rtHelperID.value=CompilationInterface::str2rid(val); + config->counters[num].filter.rtHelperID.isInitialized=true; + } + } else if ((int)line.find(".RuntimeInfo.IntHelperName") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.rtIntHelperName.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.rtIntHelperName.value=std::string(val); + config->counters[num].filter.rtIntHelperName.isInitialized=true; + } + } else if ((int)line.find(".isNative") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isNative.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isNative.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isNative.isInitialized=true; + } + } else if ((int)line.find(".isStatic") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isStatic.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isStatic.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isStatic.isInitialized=true; + } + } else if ((int)line.find(".isSynchronized") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isSynchronized.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isSynchronized.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isSynchronized.isInitialized=true; + } + } else if ((int)line.find(".isNoInlining") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isNoInlining.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isNoInlining.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isNoInlining.isInitialized=true; + } + } else if ((int)line.find(".isInstance") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isInstance.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isInstance.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isInstance.isInitialized=true; + } + } else if ((int)line.find(".isFinal") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isFinal.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isFinal.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isFinal.isInitialized=true; + } + } else if ((int)line.find(".isVirtual") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isVirtual.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isVirtual.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isVirtual.isInitialized=true; + } + } else if ((int)line.find(".isAbstract") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isAbstract.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isAbstract.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isAbstract.isInitialized=true; + } + } else if ((int)line.find(".isClassInitializer") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isClassInitializer.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isClassInitializer.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isClassInitializer.isInitialized=true; + } + } else if ((int)line.find(".isInstanceInitializer") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isInstanceInitializer.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isInstanceInitializer.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isInstanceInitializer.isInitialized=true; + } + } else if ((int)line.find(".isStrict") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isStrict.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isStrict.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isStrict.isInitialized=true; + } + } else if ((int)line.find(".isRequireSecObject") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isRequireSecObject.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isRequireSecObject.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isRequireSecObject.isInitialized=true; + } + } else if ((int)line.find(".isInitLocals") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isInitLocals.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isInitLocals.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isInitLocals.isInitialized=true; + } + } else if ((int)line.find(".isOverridden") != -1) { + char * val = std::strstr(line.c_str(),"=")+1; + if ((std::string(val) == "true") && (std::strstr(line.c_str(), "IsNegative"))) { + config->counters[num].filter.isOverridden.isNegative=true; + } else { + config->counters[num].filter.isInitialized=true; + config->counters[num].filter.isOverridden.value=(std::string(val) == "true")? true : false; + config->counters[num].filter.isOverridden.isInitialized=true; + } + } + } else if (std::strstr(c_line, "[begin]") == c_line) { + } else if (std::strstr(c_line, "[end]") == c_line) { + opened = false; + } else if (std::strstr(c_line, "#") == c_line) { + } else { + ::std::cerr<<"iprof: BAD LINE("<counters.size()) - return; - std::ofstream outFile("iprof.stat", std::ios::ate); - outFile << "Method name\t"; - for(uint32 i = 0; i < config->counters.size(); i++) { - std::string fName = config->counters[i].title != "" ? config->counters[i].title : config->counters[i].name; - outFile << fName << "\t"; - } - outFile << "\n"; - - for(Statistics::const_iterator it = statistics->begin(); it != statistics->end(); it++) { - MethodStats * stats = *it; - outFile << stats->methodName.c_str() << "\t"; - BBStats bbs = stats->bbStats[-1]; - for(uint32 i = 0; i < config->counters.size(); i++) { - int64 count; - std::string name = config->counters[i].name; - if((name == "ByteCodeSize") || (name == "ExcHandlersNum")) { - count = bbs.counters[i]; - } else if (name == "MaxBBExec") { - count = 0; - for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { - if(iter->second.counters[i]*(*(iter->second.bbExecCount)) > count) { - count = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; - } - } - } else if (name == "HottestBBNum") { - int64 c = 0; - count = 0; - for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { - if(iter->first != -1) { - int64 j = iter->second.counters[i]*(*(iter->second.bbExecCount)) ; - if(j > c) { - c = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; - count = iter->first; - } - } - } - } else if (name == "MethodExec") { - count = *(stats->bbStats[0].bbExecCount); - } else { - count = 0; - for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { - if(iter->first != -1) - count += iter->second.counters[i] * (*(iter->second.bbExecCount)) ; - } - } - outFile << count << "\t"; - } - outFile << std::endl; - if(config->printBBStats) { - for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { - if(iter->first == -1) - continue; - outFile << "BB_" << iter->first << "_" << stats->methodName.c_str() << "\t"; - for(uint32 i = 0; i < config->counters.size(); i++) { - outFile << iter->second.counters[i] * (*(iter->second.bbExecCount)) << "\t"; - } - outFile << std::endl; - } - } - } +void InternalProfilerAct::dumpIt() { + if(!config || !config->counters.size()) + return; + const char* fname; + if ((fname = getArg("out")) == 0) + fname = "iprof.stat"; + std::ofstream outFile(fname, std::ios::ate); + outFile << "Method name\t"; + for(uint32 i = 0; i < config->counters.size(); i++) { + std::string fName = config->counters[i].title != "" ? config->counters[i].title : config->counters[i].name; + outFile << fName << "\t"; + } + outFile << "\n"; + + for(Statistics::const_iterator it = statistics->begin(); it != statistics->end(); it++) { + MethodStats * stats = *it; + outFile << stats->methodName.c_str() << "\t"; + BBStats bbs = stats->bbStats[-1]; + for(uint32 i = 0; i < config->counters.size(); i++) { + int64 count; + std::string name = config->counters[i].name; + if((name == "ByteCodeSize") || (name == "ExcHandlersNum")) { + count = bbs.counters[i]; + } else if (name == "MaxBBExec") { + count = 0; + for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { + if(iter->second.counters[i]*(*(iter->second.bbExecCount)) > count) { + count = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; + } + } + } else if (name == "HottestBBNum") { + int64 c = 0; + count = 0; + for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { + if(iter->first != -1) { + int64 j = iter->second.counters[i]*(*(iter->second.bbExecCount)) ; + if(j > c) { + c = iter->second.counters[i] * (*(iter->second.bbExecCount)) ; + count = iter->first; + } + } + } + } else if (name == "MethodExec") { + count = *(stats->bbStats[0].bbExecCount); + } else { + count = 0; + for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { + if(iter->first != -1) + count += iter->second.counters[i] * (*(iter->second.bbExecCount)) ; + } + } + outFile << count << "\t"; + } + outFile << std::endl; + if(config->printBBStats) { + for(StlMap::iterator iter = stats->bbStats.begin(); iter != stats->bbStats.end(); iter++) { + if(iter->first == -1) + continue; + outFile << "BB_" << iter->first << "_" << stats->methodName.c_str() << "\t"; + for(uint32 i = 0; i < config->counters.size(); i++) { + int64 outValue = iter->second.counters[i] * (*(iter->second.bbExecCount)); + outFile << outValue << "\t"; + } + outFile << std::endl; + } + } + } } void InternalProfiler::runImpl() { - init(); - addCounters(irManager.getMethodDesc()); + addCounters(irManager->getMethodDesc()); } void InternalProfiler::addCounters(MethodDesc& methodDesc) { - MemoryManager& mm = Jitrino::getGlobalMM(); - MethodStats* ms = new(mm) MethodStats(std::string(methodDesc.getParentType()->getName())+"::"+methodDesc.getName()+methodDesc.getSignatureString(), mm); - statistics->push_back(ms); - //method external properties, no need to count - uint32 cSize = config->counters.size(); - if (!cSize) - return; - ms->bbStats[-1].counters= new(mm) uint32[cSize]; - for(uint32 i = 0; i < cSize ; i++) { - ms->bbStats[-1].counters[i] = 0; - } - ms->bbStats[-1].bbExecCount= new(mm) int64[1]; - *(ms->bbStats[-1].bbExecCount) = 0; - for(uint32 i = 0; i < cSize ; i++) { - Counter c = config->counters[i]; - if(c.name == std::string("ByteCodeSize")) { - ms->bbStats[-1].bbExecCount= new(mm) int64[1]; - *(ms->bbStats[-1].bbExecCount) = 0; - - ms->bbStats[-1].counters[i] = methodDesc.getByteCodeSize(); - } else if (c.name == std::string("ExcHandlersNum")) { - int n = methodDesc.getNumHandlers(); - ms->bbStats[-1].counters[i] = n; - } - } - //cycle by all insts - IRManager & irm=getIRManager(); - const Nodes& nodes = irm.getNodes(); + MemoryManager& mm = Jitrino::getGlobalMM(); + MethodStats* ms = new(mm) MethodStats(std::string(methodDesc.getParentType()->getName())+"::"+methodDesc.getName()+methodDesc.getSignatureString(), mm); + + InternalProfilerAct& storage = *static_cast(getAction()); + storage.statistics->push_back(ms); + //method external properties, no need to count + uint32 cSize = storage.config->counters.size(); + if (!cSize) + return; + ms->bbStats[-1].counters= new(mm) uint32[cSize]; + for(uint32 i = 0; i < cSize ; i++) { + ms->bbStats[-1].counters[i] = 0; + } + ms->bbStats[-1].bbExecCount= new(mm) int64[1]; + *(ms->bbStats[-1].bbExecCount) = 0; + for(uint32 i = 0; i < cSize ; i++) { + Counter c = storage.config->counters[i]; + if(c.name == std::string("ByteCodeSize")) { + ms->bbStats[-1].bbExecCount= new(mm) int64[1]; + *(ms->bbStats[-1].bbExecCount) = 0; + + ms->bbStats[-1].counters[i] = methodDesc.getByteCodeSize(); + } else if (c.name == std::string("ExcHandlersNum")) { + int n = methodDesc.getNumHandlers(); + ms->bbStats[-1].counters[i] = n; + } + } + //cycle by all insts + IRManager & irm=getIRManager(); + const Nodes& nodes = irm.getFlowGraph()->getNodes(); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end();it!=end; ++it) { Node* node = *it; - if (node->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock *)node; - ms->bbStats[bb->getId()].counters= new(mm) uint32[cSize]; - for(uint32 i = 0; i < cSize ; i++) { - ms->bbStats[bb->getId()].counters[i] = 0; - } - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - if(!inst->hasKind(Inst::Kind_PseudoInst)) { - for(uint32 i = 0; i < cSize ; i++) { - Counter c = config->counters[i]; - if(std::string(c.name) == "MaxBBExec" || std::string(c.name) == "HottestBBNum" || std::string(c.name) == "BBExec" ) { - ms->bbStats[bb->getId()].counters[i] =1; - } - bool matched = passFilter(inst, c.filter); - if (matched) { - ms->bbStats[bb->getId()].counters[i]++; - ms->bbStats[-1].counters[i]++; - } - } - } - } - ms->bbStats[bb->getId()].bbExecCount= new(mm) int64[1]; - *(ms->bbStats[bb->getId()].bbExecCount) = 0; - bb->prependInsts(irManager.newInst(Mnemonic_POPFD)); - bb->prependInsts(irManager.newInst(Mnemonic_ADC, irManager.newMemOpnd(irManager.getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[bb->getId()].bbExecCount + 4)), irManager.newImmOpnd(irManager.getTypeFromTag(Type::Int32),0))); - bb->prependInsts(irManager.newInst(Mnemonic_ADD, irManager.newMemOpnd(irManager.getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[bb->getId()].bbExecCount)), irManager.newImmOpnd(irManager.getTypeFromTag(Type::Int32),1))); - bb->prependInsts(irManager.newInst(Mnemonic_PUSHFD)); - } - } - ((BasicBlock *)irManager.getPrologNode())->prependInsts(irManager.newInst(Mnemonic_ADD, irManager.newMemOpnd(irManager.getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[-1].bbExecCount)), irManager.newImmOpnd(irManager.getTypeFromTag(Type::Int32),1))); + if (node->isBlockNode()){ + ms->bbStats[node->getId()].counters= new(mm) uint32[cSize]; + for(uint32 i = 0; i < cSize ; i++) { + ms->bbStats[node->getId()].counters[i] = 0; + } + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + if(!inst->hasKind(Inst::Kind_PseudoInst) || inst->hasKind(Inst::Kind_EntryPointPseudoInst)) { + for(uint32 i = 0; i < cSize ; i++) { + Counter c = storage.config->counters[i]; + if(std::string(c.name) == "MaxBBExec" || std::string(c.name) == "HottestBBNum" || std::string(c.name) == "BBExec" ) { + ms->bbStats[node->getId()].counters[i] =1; + } else { + bool matched = passFilter(inst, c.filter); + if (matched) { + ms->bbStats[node->getId()].counters[i]++; + ms->bbStats[-1].counters[i]++; + } + } + } + } + } + ms->bbStats[node->getId()].bbExecCount= new(mm) int64[1]; + *(ms->bbStats[node->getId()].bbExecCount) = 0; + node->prependInst(irManager->newInst(Mnemonic_POPFD)); +#ifndef _EM64T_ + node->prependInst(irManager->newInst(Mnemonic_ADC, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int((Byte*)(ms->bbStats[node->getId()].bbExecCount) + 4)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),0))); + + node->prependInst(irManager->newInst(Mnemonic_ADD, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[node->getId()].bbExecCount)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),1))); +#endif + node->prependInst(irManager->newInst(Mnemonic_PUSHFD)); + } + } +#ifndef _EM64T_ + ((BasicBlock *)irManager->getFlowGraph()->getEntryNode())->prependInst(irManager->newInst(Mnemonic_ADD, irManager->newMemOpnd(irManager->getTypeFromTag(Type::Int32), MemOpndKind_Heap, NULL, int(ms->bbStats[-1].bbExecCount)), irManager->newImmOpnd(irManager->getTypeFromTag(Type::Int32),1))); +#endif } - bool InternalProfiler::passOpndFilter(Inst * inst, Opnd * opnd, Filter& filter, OpndFilter& opndFltr) { - bool res = false; - if(opndFltr.opndKind.isInitialized) { - res = opnd->isPlacedIn(opndFltr.opndKind.value); - if(opndFltr.opndKind.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(opndFltr.opndRole.isInitialized) { - res = inst->getOpndRoles(opndFltr.opNum) & opndFltr.opndRole.value; - if(opndFltr.opndRole.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(opndFltr.regName.isInitialized) { - res = opndFltr.regName.value == opnd->getRegName(); - if(opndFltr.regName.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(opndFltr.memOpndKind.isInitialized) { - res = opndFltr.memOpndKind.value == opnd->getMemOpndKind(); - if(opndFltr.memOpndKind.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - return filter.isOR ? false : true; + bool res = false; + if(opndFltr.opndKind.isInitialized) { + res = opnd->isPlacedIn(opndFltr.opndKind.value); + if(opndFltr.opndKind.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(opndFltr.opndRole.isInitialized) { + res = inst->getOpndRoles(opndFltr.opNum) & opndFltr.opndRole.value; + if(opndFltr.opndRole.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(opndFltr.regName.isInitialized) { + res = opndFltr.regName.value == opnd->getRegName(); + if(opndFltr.regName.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(opndFltr.memOpndKind.isInitialized) { + res = opndFltr.memOpndKind.value == opnd->getMemOpndKind(); + if(opndFltr.memOpndKind.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + return filter.isOR ? false : true; } bool InternalProfiler::passFilter(Inst * inst, Filter& filter) { - if(!filter.isInitialized) - return false; - bool res = false; - if(filter.mnemonic.isInitialized) { - res = (filter.mnemonic.value == inst->getMnemonic()) || (filter.mnemonic.value == Mnemonic_Null); - if(filter.mnemonic.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.operandNumber.isInitialized) { - res = filter.operandNumber.value == (int)inst->getOpndCount(); - if(filter.operandNumber.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - - if(filter.operandFilters.size()) { - for(StlMap::const_iterator it = filter.operandFilters.begin(); it !=filter.operandFilters.end(); it++) { - OpndFilter opndFltr = it->second; - if(!opndFltr.isInitialized) - continue; - if(opndFltr.opNum == -1) { - for(uint32 i = 0; i < inst->getOpndCount(Inst::OpndRole_All) ; i++) { - Opnd * opnd = inst->getOpnd(i); - res = passOpndFilter(inst, opnd, filter, opndFltr); - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - } else if (opndFltr.opNum >= 0) { - Opnd * opnd = opndFltr.opNum<(int)inst->getOpndCount(Inst::OpndRole_All) ? inst->getOpnd(opndFltr.opNum) : NULL; - if(!opnd) - return false; - res = passOpndFilter(inst, opnd, filter, opndFltr); - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } else { - return false; - } - } - } - Opnd::RuntimeInfo * rt = NULL; - if (inst->getMnemonic() == Mnemonic_CALL) { - rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); - } - - if(filter.rtKind.isInitialized) { - if(!rt) - return false; - res = filter.rtKind.value == rt->getKind(); - if(filter.rtKind.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.rtHelperID.isInitialized) { - if(!rt) - return false; - res = filter.rtHelperID.value == (CompilationInterface::RuntimeHelperId)(uint32)rt->getValue(0); - if(filter.rtHelperID.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.rtIntHelperName.isInitialized) { - if(!rt) - return false; - res = filter.rtIntHelperName.value == (char*)irManager.getInternalHelperInfo((const char*)rt->getValue(0))->pfn; - if(filter.rtIntHelperName.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isNative.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isNative.value == ((MethodDesc *)rt->getValue(0))->isNative(); - if(filter.isNative.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isStatic.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isStatic.value == ((MethodDesc *)rt->getValue(0))->isStatic(); - if(filter.isStatic.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isSynchronized.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isSynchronized.value == ((MethodDesc *)rt->getValue(0))->isSynchronized(); - if(filter.isSynchronized.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isNoInlining.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isNoInlining.value == ((MethodDesc *)rt->getValue(0))->isNoInlining(); - if(filter.isNoInlining.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isInstance.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isInstance.value == ((MethodDesc *)rt->getValue(0))->isInstance(); - if(filter.isInstance.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isFinal.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isFinal.value == ((MethodDesc *)rt->getValue(0))->isFinal(); - if(filter.isFinal.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isVirtual.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isVirtual.value == ((MethodDesc *)rt->getValue(0))->isVirtual(); - if(filter.isVirtual.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isAbstract.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isAbstract.value == ((MethodDesc *)rt->getValue(0))->isAbstract(); - if(filter.isAbstract.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isClassInitializer.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isClassInitializer.value == ((MethodDesc *)rt->getValue(0))->isClassInitializer(); - if(filter.isClassInitializer.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isInstanceInitializer.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isInstanceInitializer.value == ((MethodDesc *)rt->getValue(0))->isInstanceInitializer(); - if(filter.isInstanceInitializer.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isStrict.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isStrict.value == ((MethodDesc *)rt->getValue(0))->isStrict(); - if(filter.isStrict.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isRequireSecObject.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isRequireSecObject.value == ((MethodDesc *)rt->getValue(0))->isRequireSecObject(); - if(filter.isRequireSecObject.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isInitLocals.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isInitLocals.value == ((MethodDesc *)rt->getValue(0))->isInitLocals(); - if(filter.isInitLocals.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - if(filter.isOverridden.isInitialized) { - if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) - return false; - res = filter.isOverridden.value == ((MethodDesc *)rt->getValue(0))->isOverridden(); - if(filter.isOverridden.isNegative) - res = !res; - - if(filter.isOR && res) - return true; - if(!(filter.isOR || res)) - return false; - } - - return filter.isOR ? false : true; + if(!filter.isInitialized) + return false; + bool res = false; + if(filter.mnemonic.isInitialized) { + res = (filter.mnemonic.value == inst->getMnemonic()) || (filter.mnemonic.value == Mnemonic_Null); + if(filter.mnemonic.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.operandNumber.isInitialized) { + res = filter.operandNumber.value == (int)inst->getOpndCount(); + if(filter.operandNumber.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + + if(filter.operandFilters.size()) { + for(StlMap::const_iterator it = filter.operandFilters.begin(); it !=filter.operandFilters.end(); it++) { + OpndFilter opndFltr = it->second; + if(!opndFltr.isInitialized) + continue; + if(opndFltr.opNum == -1) { + for(uint32 i = 0; i < inst->getOpndCount(Inst::OpndRole_All) ; i++) { + Opnd * opnd = inst->getOpnd(i); + res = passOpndFilter(inst, opnd, filter, opndFltr); + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + } else if (opndFltr.opNum >= 0) { + Opnd * opnd = opndFltr.opNum<(int)inst->getOpndCount(Inst::OpndRole_All) ? inst->getOpnd(opndFltr.opNum) : NULL; + if(!opnd) + return false; + res = passOpndFilter(inst, opnd, filter, opndFltr); + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } else { + return false; + } + } + } + Opnd::RuntimeInfo * rt = NULL; + if (inst->getMnemonic() == Mnemonic_CALL) { + rt = inst->getOpnd(((ControlTransferInst*)inst)->getTargetOpndIndex())->getRuntimeInfo(); + } + + if(filter.rtKind.isInitialized) { + if(!rt) + return false; + res = filter.rtKind.value == rt->getKind(); + if(filter.rtKind.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.rtHelperID.isInitialized) { + if(!rt) + return false; + res = filter.rtHelperID.value == (CompilationInterface::RuntimeHelperId)(POINTER_SIZE_INT)rt->getValue(0); + if(filter.rtHelperID.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.rtIntHelperName.isInitialized) { + if(!rt) + return false; + res = filter.rtIntHelperName.value == (char*)irManager->getInternalHelperInfo((const char*)rt->getValue(0))->pfn; + if(filter.rtIntHelperName.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isNative.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isNative.value == ((MethodDesc *)rt->getValue(0))->isNative(); + if(filter.isNative.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isStatic.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isStatic.value == ((MethodDesc *)rt->getValue(0))->isStatic(); + if(filter.isStatic.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isSynchronized.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isSynchronized.value == ((MethodDesc *)rt->getValue(0))->isSynchronized(); + if(filter.isSynchronized.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isNoInlining.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isNoInlining.value == ((MethodDesc *)rt->getValue(0))->isNoInlining(); + if(filter.isNoInlining.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isInstance.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isInstance.value == ((MethodDesc *)rt->getValue(0))->isInstance(); + if(filter.isInstance.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isFinal.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isFinal.value == ((MethodDesc *)rt->getValue(0))->isFinal(); + if(filter.isFinal.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isVirtual.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isVirtual.value == ((MethodDesc *)rt->getValue(0))->isVirtual(); + if(filter.isVirtual.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isAbstract.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isAbstract.value == ((MethodDesc *)rt->getValue(0))->isAbstract(); + if(filter.isAbstract.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isClassInitializer.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isClassInitializer.value == ((MethodDesc *)rt->getValue(0))->isClassInitializer(); + if(filter.isClassInitializer.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isInstanceInitializer.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isInstanceInitializer.value == ((MethodDesc *)rt->getValue(0))->isInstanceInitializer(); + if(filter.isInstanceInitializer.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isStrict.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isStrict.value == ((MethodDesc *)rt->getValue(0))->isStrict(); + if(filter.isStrict.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isRequireSecObject.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isRequireSecObject.value == ((MethodDesc *)rt->getValue(0))->isRequireSecObject(); + if(filter.isRequireSecObject.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isInitLocals.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isInitLocals.value == ((MethodDesc *)rt->getValue(0))->isInitLocals(); + if(filter.isInitLocals.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + if(filter.isOverridden.isInitialized) { + if(!rt || ((rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr) && (rt->getKind() != Opnd::RuntimeInfo::Kind_MethodDirectAddr))) + return false; + res = filter.isOverridden.value == ((MethodDesc *)rt->getValue(0))->isOverridden(); + if(filter.isOverridden.isNegative) + res = !res; + + if(filter.isOR && res) + return true; + if(!(filter.isOR || res)) + return false; + } + + return filter.isOR ? false : true; } }}; // namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.h vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.h deleted file mode 100644 index 4c270ba..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32InternalProfiler.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Nikolay A. Sidelnikov - * @version $Revision: 1.2.12.2.4.3 $ - */ - -#ifndef _IA32_INTERNAL_PROFILER_H_ -#define _IA32_INTERNAL_PROFILER_H_ - -#include "Ia32IRManager.h" -namespace Jitrino -{ -namespace Ia32{ - - template struct AttrDesc { - T value; - char * name; - }; - - struct BBStats { - int64 * bbExecCount; - uint32 * counters; - - BBStats() : bbExecCount(NULL), counters(NULL) {} - }; - - struct MethodStats { - std::string methodName; - StlMap bbStats; //bbID, bbExecCount, array of counters - MethodStats(std::string s, MemoryManager& mm) : methodName(s), bbStats(mm) {} - }; - -typedef StlVector Statistics; - -template class FilterAttr { - public: - T value; - bool isInitialized; - bool isNegative; - - FilterAttr(T v, bool i = false, bool n = false) : value(v), isInitialized(i), isNegative(n) {}; - - FilterAttr& operator=(const FilterAttr& c) { - FilterAttr& f = *this; - f.value = c.value; - f.isInitialized = c.isInitialized; - f.isNegative = c.isNegative; - return f; - } -}; - -struct OpndFilter { - bool isInitialized; - int opNum; - FilterAttr opndRole; - FilterAttr opndKind; - FilterAttr regName; - FilterAttr memOpndKind; - - OpndFilter() : isInitialized(false), opNum(-1), opndRole(Inst::OpndRole_Null), opndKind(OpndKind_Null), regName(RegName_Null), memOpndKind(MemOpndKind_Null) {} - - OpndFilter& operator=(const OpndFilter& c) { - OpndFilter& f = *this; - f.isInitialized = c.isInitialized; - f.opNum = c.opNum; - f.opndRole =c.opndRole; - f.opndKind =c.opndKind; - f.regName =c.regName; - f.memOpndKind =c.memOpndKind; - return f; - } - -}; - -struct Filter { - bool isInitialized; - bool isNegative; - bool isOR; - - FilterAttr mnemonic; - FilterAttr operandNumber; - FilterAttr rtKind; - FilterAttr rtHelperID; - FilterAttr rtIntHelperName; - FilterAttr isNative; - FilterAttr isStatic; - FilterAttr isSynchronized; - FilterAttr isNoInlining; - FilterAttr isInstance; - FilterAttr isFinal; - FilterAttr isVirtual; - FilterAttr isAbstract; - FilterAttr isClassInitializer; - FilterAttr isInstanceInitializer; - FilterAttr isStrict; - FilterAttr isRequireSecObject; - FilterAttr isInitLocals; - FilterAttr isOverridden; - - StlMap operandFilters; - - Filter() : isInitialized(false), isNegative(false), isOR(false), mnemonic(Mnemonic_NULL), operandNumber(-1), rtKind(Opnd::RuntimeInfo::Kind_Null),rtHelperID(CompilationInterface::Helper_Null), rtIntHelperName("none"), isNative(false), isStatic(false), isSynchronized(false), isNoInlining(false), isInstance(false), isFinal(false), isVirtual(false), isAbstract(false), isClassInitializer(false), isInstanceInitializer(false), isStrict(false), isRequireSecObject(false), isInitLocals(false), isOverridden(false), operandFilters(Jitrino::getGlobalMM()) {} - - Filter& operator=(const Filter& c) { - Filter& f = *this; - f.isNegative = c.isNegative; - f.isInitialized = c.isInitialized; - f.isOR = c.isOR; - f.mnemonic=c.mnemonic; - f.operandNumber=c.operandNumber; - f.rtKind=c.rtKind; - f.rtHelperID=c.rtHelperID; - f.rtIntHelperName=c.rtIntHelperName; - f.isNative=c.isNative; - f.isStatic=c.isStatic; - f.isSynchronized=c.isSynchronized; - f.isNoInlining = c.isNoInlining; - f.isInstance = c.isInstance; - f.isFinal = c.isFinal; - f.isVirtual = c.isVirtual; - f.isAbstract = c.isAbstract; - f.isClassInitializer = c.isClassInitializer; - f.isInstanceInitializer = c.isInstanceInitializer; - f.isStrict = c.isStrict; - f.isRequireSecObject = c.isRequireSecObject; - f.isInitLocals = c.isInitLocals; - f.isOverridden = c.isOverridden; - - for(StlMap::const_iterator it = c.operandFilters.begin(); it !=c.operandFilters.end(); it++) { - f.operandFilters[it->first] = it->second; - } - return f; - } -}; - -struct Counter { - std::string name; - std::string title; - bool isSorting; - Filter filter; - - Counter() : isSorting(false) {} -}; - -class Config { -public: - StlVector counters; - - bool printBBStats; - Config(MemoryManager& mm) : counters(mm), printBBStats(false) {}; -}; - - -//======================================================================================== -// class InternalProfiler -//======================================================================================== -/** - class InternalProfiler collects information about methods - -*/ -BEGIN_DECLARE_IRTRANSFORMER(InternalProfiler, "iprof", "Internal profiler") - IRTRANSFORMER_CONSTRUCTOR(InternalProfiler) -public: - void runImpl(); - - static void init(); - static void deinit() { dumpIt(); config = NULL; } - -protected: - void addCounters(MethodDesc& methodDesc); - - bool passFilter(Inst * inst, Filter& filter); - bool passOpndFilter(Inst * inst, Opnd * opnd, Filter& filter, OpndFilter& opndFltr); - - static void readConfig(Config * config); - static void dumpIt(); - - static Config * config; - static Statistics * statistics; - -END_DECLARE_IRTRANSFORMER(InternalProfiler) - - -}}; // namespace Ia32 - - -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.cpp vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.cpp index e5dc027..4bea2a7 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.cpp @@ -33,6 +33,8 @@ namespace Ia32{ // class InternalTrace //======================================================================================== +static ActionFactory _itrace("itrace"); + //_________________________________________________________________________________________________ static inline void m_assert(bool cond) { #ifdef _DEBUG @@ -54,14 +56,18 @@ void __stdcall methodEntry(const char * { JitFrameContext context; - context.esp=(uint32)(&methodName+4); // must point to the beginning of incoming stack args - ::std::ostream & os=Log::cat_rt()->out(); - os<<"__METHOD_ENTRY__:"<out(); + os<<"__METHOD_ENTRY__:"<init(); } for (uint32 i=0; iout(); - os<<"__METHOD_EXIT__:"<out(); + os<<"__METHOD_EXIT__:"<out(); - os<<"__FIELD_WRITE__:"<=heapCeiling){ - os<<"PROBABLY STATIC OR INVALID ADDRESS. DYNAMIC ADDRESSES MUST BE IN ["<out(); + os<<"__FIELD_WRITE__:"<=heapCeiling){ + os<<"PROBABLY STATIC OR INVALID ADDRESS. DYNAMIC ADDRESSES MUST BE IN ["<getName()); - strcat(methodFullName, "."); - strcat(methodFullName, md.getName()); - strcat(methodFullName, " "); - strcat(methodFullName, md.getSignatureString()); - - Opnd * methodNameOpnd=irManager.newInternalStringConstantImmOpnd(methodFullName); - irManager.setInfo("itraceMethodExitString", methodNameOpnd->getRuntimeInfo()->getValue(0)); - - BasicBlock * prolog=irManager.getPrologNode(); - - Inst * inst=prolog->getInsts().getFirst(); - if (inst->hasKind(Inst::Kind_EntryPointPseudoInst)){ - EntryPointPseudoInst * entryPointPseudoInst = (EntryPointPseudoInst *)inst; - entryPointPseudoInst->getCallingConventionClient().finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_InArg); - const StlVector & infos=((const EntryPointPseudoInst *)entryPointPseudoInst)->getCallingConventionClient().getInfos(Inst::OpndRole_Def); - Opnd * argInfoOpnd=irManager.newBinaryConstantImmOpnd(infos.size()*sizeof(CallingConvention::OpndInfo), &infos.front()); - Opnd * args[3]={ methodNameOpnd, - irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), infos.size()), - argInfoOpnd, - }; - Inst * internalTraceInst=irManager.newInternalRuntimeHelperCallInst("itrace_method_entry", 3, args, NULL); - prolog->prependInsts(internalTraceInst, inst); - }else{ - Opnd * args[3]={ methodNameOpnd, - irManager.newImmOpnd(irManager.getTypeManager().getInt32Type(), 0), - irManager.newImmOpnd(irManager.getTypeManager().getIntPtrType(), 0), - }; - Inst * internalTraceInst=irManager.newInternalRuntimeHelperCallInst("itrace_method_entry", 3, args, NULL); - prolog->prependInsts(internalTraceInst); - } - - const Edges& inEdges = irManager.getExitNode()->getEdges(Direction_In); - for (Edge * edge = inEdges.getFirst(); edge != NULL; edge = inEdges.getNext(edge)) {//check predecessors for epilog(s) - if (irManager.isEpilog(edge->getNode(Direction_Tail))) { - BasicBlock * epilog = (BasicBlock*)edge->getNode(Direction_Tail); - Inst * retInst=epilog->getInsts().getLast(); - assert(retInst->hasKind(Inst::Kind_RetInst)); - Opnd * args[1]={ methodNameOpnd }; - Inst * internalTraceInst=irManager.newInternalRuntimeHelperCallInst("itrace_method_exit", 1, args, NULL); - epilog->prependInsts(internalTraceInst, retInst); - } - } + MemoryManager mm(0x400, "InternalTrace"); + + irManager->registerInternalHelperInfo("itrace_method_entry", IRManager::InternalHelperInfo((void*)&methodEntry, &CallingConvention_STDCALL)); + irManager->registerInternalHelperInfo("itrace_method_exit", IRManager::InternalHelperInfo((void*)&methodExit, &CallingConvention_STDCALL)); + irManager->registerInternalHelperInfo("itrace_field_write", IRManager::InternalHelperInfo((void*)&fieldWrite, &CallingConvention_STDCALL)); + + char methodFullName[0x1000]=""; + MethodDesc & md=irManager->getMethodDesc(); + strcat(methodFullName, md.getParentType()->getName()); + strcat(methodFullName, "."); + strcat(methodFullName, md.getName()); + strcat(methodFullName, " "); + strcat(methodFullName, md.getSignatureString()); + + Opnd * methodNameOpnd=irManager->newInternalStringConstantImmOpnd(methodFullName); + irManager->setInfo("itraceMethodExitString", methodNameOpnd->getRuntimeInfo()->getValue(0)); + + Node* prolog=irManager->getFlowGraph()->getEntryNode(); + + Inst * inst=(Inst*)prolog->getFirstInst(); + if (inst->hasKind(Inst::Kind_EntryPointPseudoInst)){ + EntryPointPseudoInst * entryPointPseudoInst = (EntryPointPseudoInst *)inst; + entryPointPseudoInst->getCallingConventionClient().finalizeInfos(Inst::OpndRole_Def, CallingConvention::ArgKind_InArg); + const StlVector & infos=((const EntryPointPseudoInst *)entryPointPseudoInst)->getCallingConventionClient().getInfos(Inst::OpndRole_Def); + Opnd * argInfoOpnd=irManager->newBinaryConstantImmOpnd(infos.size()*sizeof(CallingConvention::OpndInfo), &infos.front()); + Opnd * args[3]={ methodNameOpnd, + irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), infos.size()), + argInfoOpnd, + }; + Inst * internalTraceInst=irManager->newInternalRuntimeHelperCallInst("itrace_method_entry", 3, args, NULL); + internalTraceInst->insertBefore(inst); + }else{ + Opnd * args[3]={ methodNameOpnd, + irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0), + irManager->newImmOpnd(irManager->getTypeManager().getUnmanagedPtrType(irManager->getTypeManager().getIntPtrType()), 0), + }; + Inst * internalTraceInst=irManager->newInternalRuntimeHelperCallInst("itrace_method_entry", 3, args, NULL); + prolog->prependInst(internalTraceInst); + } + + const Edges& inEdges = irManager->getFlowGraph()->getExitNode()->getInEdges(); + for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (irManager->isEpilog(edge->getSourceNode())) { + Node* epilog = edge->getSourceNode(); + Inst * retInst=(Inst*)epilog->getLastInst(); + assert(retInst->hasKind(Inst::Kind_RetInst)); + Opnd * args[1]={ methodNameOpnd }; + Inst * internalTraceInst=irManager->newInternalRuntimeHelperCallInst("itrace_method_exit", 1, args, NULL); + internalTraceInst->insertBefore(retInst); + } + } #ifdef IA32_EXTENDED_TRACE - for (CFG::NodeIterator it(irManager); it!=NULL; ++it){ - if (((Node*)it)->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock*)(Node*)it; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - if (inst->getMnemonic()==Mnemonic_MOV){ - Opnd * dest=inst->getOpnd(0); - if (dest->isPlacedIn(OpndKind_Memory) && dest->getMemOpndKind()==MemOpndKind_Heap){ - Opnd * opnd=irManager.newOpnd(Type::IntPtr); - bb->prependInsts(irManager.newInst(Mnemonic_LEA, opnd, dest), inst); - Opnd * args[1]={ opnd }; - bb->prependInsts(irManager.newInternalRuntimeHelperCallInst("itrace_field_write", 1, args, NULL), inst); - } - } - } - } - } + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + if (inst->getMnemonic()==Mnemonic_MOV){ + Opnd * dest=inst->getOpnd(0); + if (dest->isPlacedIn(OpndKind_Memory) && dest->getMemOpndKind()==MemOpndKind_Heap){ + Opnd * opnd=irManager->newOpnd(Type::UnmanagedPtr); + Inst* newIns = irManager->newInst(Mnemonic_LEA, opnd, dest); + newIns->insertBefore(inst); + Opnd * args[1]={ opnd }; + newIns = irManager->newInternalRuntimeHelperCallInst("itrace_field_write", 1, args, NULL); + newIns->insertBefore(inst); + } + } + } + } + } #endif } diff --git vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.h vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.h index c1a9703..e7d28ac 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.h +++ vm/jitrino/src/codegenerator/ia32/Ia32InternalTrace.h @@ -32,13 +32,12 @@ namespace Ia32{ // class InternalTrace //======================================================================================== /** - class InternalTrace inserts trace calls - + class InternalTrace inserts trace calls + */ -BEGIN_DECLARE_IRTRANSFORMER(InternalTrace, "itrace", "Internal trace") - IRTRANSFORMER_CONSTRUCTOR(InternalTrace) - void runImpl(); -END_DECLARE_IRTRANSFORMER(InternalTrace) +class InternalTrace : public SessionAction { + void runImpl(); +}; void __stdcall methodExit(const char * methodName) stdcall__; void __stdcall methodEntry(const char * methodName, uint32 argInfoCount, CallingConvention::OpndInfo * argInfos) stdcall__; diff --git vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp index 0a9bc3e..8046a6f 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32Printer.cpp @@ -36,79 +36,56 @@ namespace Ia32{ //_____________________________________________________________________________________________ Printer& Printer::setStream(::std::ostream& _os) { - assert(os==NULL); - os=&_os; - return *this; + assert(os==NULL); + os=&_os; + return *this; } - //_____________________________________________________________________________________________ -Printer& Printer::setDotFileName(const char * fileName) +Printer& Printer::open(char* fname) { - assert(os==NULL); - fs.open(fileName, ::std::ios::out|::std::ios::trunc); - os=&fs; - return *this; + logs.open(fname); + setStream(logs.out()); + return *this; } - //_____________________________________________________________________________________________ -Printer& Printer::createDotFileName(const char * dir, const char * fileSuffix) +void Printer::close() { - assert(os==NULL); - assert(irManager!=NULL); - if (dir==NULL) dir=""; - char fileNameBuffer[1024]; - if (dir==NULL||dir[0]==0) - dir="."; - sprintf(fileNameBuffer, "%s\\%s.dot", dir, fileSuffix); - char * fileName=fileNameBuffer+strlen(dir); - while (fileName != NULL) { - switch(*fileName) { - case '/': case '*': *fileName++ = '_'; break; - case '<': case '>': *fileName++ = '_'; break; - case '(': case ')': *fileName++ = '_'; break; - case '{': case '}': *fileName++ = '_'; break; - case ';': *fileName++ = '_'; break; - case 0: fileName=NULL; break; - default: fileName++; - } - } - return setDotFileName(fileNameBuffer); + logs.close(); } - //_____________________________________________________________________________________________ void Printer::print(uint32 indent) { - printHeader(indent); - printBody(indent); - printEnd(indent); + printHeader(indent); + printBody(indent); + printEnd(indent); } //_____________________________________________________________________________________________ void Printer::printHeader(uint32 indent) { - assert(irManager!=NULL); - ::std::ostream& os = getStream(); - os << ::std::endl; printIndent(indent); - os << "====================================================================" << ::std::endl; printIndent(indent); - os << irManager->getMethodDesc().getParentType()->getName()<<"."<getMethodDesc().getName()<<" " << (title?title:"") << ::std::endl; printIndent(indent); - os << "====================================================================" << ::std::endl; printIndent(indent); - os << ::std::endl; + assert(irManager!=NULL); + ::std::ostream& os = getStream(); + os << ::std::endl; printIndent(indent); + os << "====================================================================" << ::std::endl; printIndent(indent); + os << irManager->getMethodDesc().getParentType()->getName()<<"."<getMethodDesc().getName()<<" " << (title?title:"") << ::std::endl; printIndent(indent); + os << "====================================================================" << ::std::endl; printIndent(indent); + os << ::std::endl; } //_____________________________________________________________________________________________ void Printer::printEnd(uint32 indent) { - ::std::ostream& os = getStream(); - os << ::std::endl; - os.flush(); + ::std::ostream& os = getStream(); + os << ::std::endl; + os.flush(); } //_____________________________________________________________________________________________ void Printer::printBody(uint32 indent) { - ::std::ostream& os = getStream(); - os << "Printer::printBody is stub implementation"<< ::std::endl; - os.flush(); + ::std::ostream& os = getStream(); + os << "Printer::printBody is stub implementation"<< ::std::endl; + os.flush(); } //======================================================================================== @@ -117,152 +94,166 @@ void Printer::printBody(uint32 indent) //_____________________________________________________________________________________________ void IRPrinter::print(uint32 indent) { - Printer::print(); + Printer::print(); } //_____________________________________________________________________________________________ void IRPrinter::printBody(uint32 indent) { - printCFG(indent); + printCFG(indent); } //_____________________________________________________________________________________________ void IRPrinter::printCFG(uint32 indent) { - assert(irManager!=NULL); - ::std::ostream& os = getStream(); - for (CFG::NodeIterator it(*irManager, CFG::OrderType_Topological); it!=NULL; ++it){ - printNode(it.getNode(), indent); - os<<::std::endl; - } + assert(irManager!=NULL); + std::ostream& os = getStream(); + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + //topological ordering + for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + printNode(node, indent); + os<getKind(); - if (k&Node::Kind_BasicBlock) + ::std::ostream& os = getStream(); + if (!node){ + os<<"NULL"; + return; + } + + if (node->isBlockNode()) { os << "BB_"; - else if (k&Node::Kind_DispatchNode) - os << "DN_"; - else if (k&Node::Kind_UnwindNode) - os << "UN_"; - else if (k&Node::Kind_ExitNode) + } else if (node->isDispatchNode()) { + if (node!=irManager->getFlowGraph()->getUnwindNode()) { + os << "DN_"; + } else { + os << "UN_"; + } + } else { + assert(node->isExitNode()); os << "EN_"; - else - os << "??_"; + } os << node->getId(); - if (node == node->getCFG()->getPrologNode()) + if (node == irManager->getFlowGraph()->getEntryNode()) { os << "_prolog"; - else if (node->getCFG()->isEpilog(node)) + } else if (irManager->isEpilog(node)) { os << "_epilog"; + } } //_____________________________________________________________________________________________ void IRPrinter::printNodeHeader(const Node * node, uint32 indent) { - ::std::ostream& os = getStream(); - printIndent(indent); - printNodeName(node); - os<<::std::endl; printIndent(indent); - - if (node->getPersistentId()!=UnknownId){ - os << " PersistentId = " << node->getPersistentId() << ::std::endl; - printIndent(indent); - } - if (node->getExecCnt() >= 0.0) - os << " ExecCnt = " << node->getExecCnt() << ::std::endl; + std::ostream& os = getStream(); + printIndent(indent); + printNodeName(node); + os<<::std::endl; printIndent(indent); + + if (((CGNode*)node)->getPersistentId()!=UnknownId){ + os << " PersistentId = " << ((CGNode*)node)->getPersistentId() << std::endl; + printIndent(indent); + } + if (node->getExecCount() >= 0.0) + os << " ExecCnt = " << node->getExecCount() << std::endl; else - os << " ExecCnt = Unknown" << ::std::endl; - printIndent(indent); + os << " ExecCnt = Unknown" << std::endl; + printIndent(indent); - if (node->hasLoopInfo()) { - os << " Loop: Depth=" << node->getLoopDepth(); - if (node->isLoopHeader()) + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + if (lt->isValid()) { + os << " Loop: Depth=" << lt->getLoopDepth(node); + if (lt->isLoopHeader(node)) { os << ", hdr, hdr= "; - else + } else { os << ", !hdr, hdr="; - printNodeName(node->getLoopHeader()); - os << ::std::endl; printIndent(indent); - } - { - os << " Predcessors: "; - const Edges& es=node->getEdges(Direction_In); - for (const Edge * e=es.getFirst(); e!=NULL; e=es.getNext(e)) { - printNodeName(e->getNode(Direction_Tail)); - os << " "; + } + printNodeName(lt->getLoopHeader(node)); + os << std::endl; printIndent(indent); } - os << ::std::endl; printIndent(indent); - } - { - const Edges& es=node->getEdges(Direction_Out); - os << " Successors: "; - for (const Edge * e=es.getFirst(); e!=NULL; e=es.getNext(e)) { - const Node * succ = e->getNode(Direction_Head); - printNodeName(succ); - os << " [Prob=" << (double)e->getProbability() << "]"; - if (e->hasKind(Edge::Kind_CatchEdge)) { - os << "(" << ((CatchEdge *)e)->getPriority() << ","; - printType(((CatchEdge *)e)->getType()); - os << ")"; + { + os << " Predcessors: "; + const Edges& es=node->getInEdges(); + for (Edges::const_iterator ite = es.begin(), ende = es.end(); ite!=ende; ++ite) { + Edge* e= *ite; + printNodeName(e->getSourceNode()); + os << " "; } - if (e->isBackEdge()) - os << "(Backedge)"; - if (e->isLoopExit()) - os << "(LoopExit)"; - const BranchInst * br = e->getBranch(); - if (br) { - os << "(Br=I" << (int) br->getId() << ")"; + os << std::endl; printIndent(indent); + } + { + const Edges& es=node->getOutEdges(); + os << " Successors: "; + for (Edges::const_iterator ite = es.begin(), ende = es.end(); ite!=ende; ++ite) { + Edge* e= *ite; + const Node * succ = e->getTargetNode(); + printNodeName(succ); + os << " [Prob=" << (double)e->getEdgeProb() << "]"; + if (e->isCatchEdge()) { + os << "(" << ((CatchEdge *)e)->getPriority() << ","; + printType(((CatchEdge *)e)->getType()); + os << ")"; + } + if (lt->isValid()) { + if (lt->isBackEdge(e)) { + os << "(backedge)"; + } + if (lt->isLoopExit(e)) { + os << "(loopexit)"; + } + } + if (e->isFalseEdge() || e->isTrueEdge()) { + Inst* br = (Inst*)e->getSourceNode()->getLastInst(); + os << "(Br=I" << (int) br->getId() << ")"; + } + os << " "; + } + } + if (node->isBlockNode()) { + const BasicBlock * bb=(const BasicBlock*)node; + if (irManager->isLaidOut()){ + os << std::endl; printIndent(indent); + os << "Layout Succ: "; + printNodeName(bb->getLayoutSucc()); + if (irManager->getCodeStartAddr()!=NULL){ + os << std::endl; printIndent(indent); + os << "Block code address: " << (void*)bb->getCodeStartAddr(); + } } - os << " "; - } - } - if (node->hasKind(Node::Kind_BasicBlock)) { - const BasicBlock * bb=(const BasicBlock*)node; - if (node->getCFG()->isLaidOut()){ - os << ::std::endl; printIndent(indent); - os << "Layout Succ: "; - printNodeName(bb->getLayoutSucc()); - if (irManager->getCodeStartAddr()!=NULL){ - os << ::std::endl; printIndent(indent); - os << "Block code address: " << (void*)bb->getCodeStartAddr(); - } - } - } + } } //_____________________________________________________________________________________________ void IRPrinter::printNodeInstList(const BasicBlock * bb, uint32 indent) { - ::std::ostream& os = getStream(); - for (Inst * inst = bb->getInsts().getFirst(); inst != NULL; inst = bb->getInsts().getNext(inst)) { - Inst::Kind kind=inst->getKind(); - if ((kind & instFilter)==(uint32)kind){ - printIndent(indent+1); - if (irManager->getCodeStartAddr()!=NULL){ - os<<(void*)inst->getCodeStartAddr()<<' '; - } - printInst(inst); - os << ::std::endl; - } - } + ::std::ostream& os = getStream(); + for (Inst * inst = (Inst*)bb->getFirstInst(); inst != NULL; inst = inst->getNextInst()) { + Inst::Kind kind=inst->getKind(); + if ((kind & instFilter)==(uint32)kind){ + printIndent(indent+1); + if (irManager->getCodeStartAddr()!=NULL){ + os<<(void*)inst->getCodeStartAddr()<<' '; + } + printInst(inst); + os << std::endl; + } + } } //_____________________________________________________________________________________________ void IRPrinter::printNode(const Node * node, uint32 indent) { - ::std::ostream& os = getStream(); - printNodeHeader(node, indent); - if (node->hasKind(Node::Kind_BasicBlock)) { - os << ::std::endl; - printNodeInstList((BasicBlock*)node, indent); + std::ostream& os = getStream(); + printNodeHeader(node, indent); + if (node->isBlockNode()) { + os << std::endl; + printNodeInstList((BasicBlock*)node, indent); } - os << ::std::endl; + os << std::endl; } //_____________________________________________________________________________________________ @@ -273,82 +264,94 @@ void IRPrinter::printEdge(const Edge * e //_____________________________________________________________________________________________ const char * IRPrinter::getPseudoInstPrintName(Inst::Kind k) { - switch(k){ - case Inst::Kind_PseudoInst: return "PseudoInst"; - case Inst::Kind_EntryPointPseudoInst: return "EntryPointPseudoInst"; - case Inst::Kind_AliasPseudoInst: return "AliasPseudoInst"; - case Inst::Kind_CatchPseudoInst: return "CatchPseudoInst"; - case Inst::Kind_CopyPseudoInst: return "CopyPseudoInst"; - case Inst::Kind_I8PseudoInst: return "I8PseudoInst"; + switch(k){ + case Inst::Kind_PseudoInst: return "PseudoInst"; + case Inst::Kind_EntryPointPseudoInst: return "EntryPointPseudoInst"; + case Inst::Kind_AliasPseudoInst: return "AliasPseudoInst"; + case Inst::Kind_CatchPseudoInst: return "CatchPseudoInst"; + case Inst::Kind_CopyPseudoInst: return "CopyPseudoInst"; + case Inst::Kind_I8PseudoInst: return "I8PseudoInst"; case Inst::Kind_GCInfoPseudoInst: return "GCInfoPseudoInst"; - default: return ""; - } + case Inst::Kind_MethodEntryPseudoInst: return "MethodEntryPseudoInst"; + case Inst::Kind_MethodEndPseudoInst: return "MethodEndPseudoInst"; + case Inst::Kind_EmptyPseudoInst: return "EmptyPseudoInst"; + default: return ""; + } } //_____________________________________________________________________________________________ uint32 IRPrinter::printInstOpnds(const Inst * inst, uint32 orf) { - ::std::ostream& os = getStream(); - if (!(orf&Inst::OpndRole_ForIterator)) - return 0; - uint32 printedOpnds=0; - bool explicitOnly=(orf&Inst::OpndRole_ForIterator)==Inst::OpndRole_Explicit; - - Inst::Opnds opnds(inst, orf); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), printedOpnds++){ - if (printedOpnds) - os<<","; - else if (!explicitOnly){ - os<<"("; printOpndRoles(orf); os<<":"; - } - printOpnd(inst, it, false, false); - } - if (printedOpnds && !explicitOnly) - os<<")"; - return printedOpnds; + ::std::ostream& os = getStream(); + if (!(orf&Inst::OpndRole_ForIterator)) + return 0; + uint32 printedOpnds=0; + bool explicitOnly=(orf&Inst::OpndRole_ForIterator)==Inst::OpndRole_Explicit; + + Inst::Opnds opnds(inst, orf); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), printedOpnds++){ + if (printedOpnds) + os<<","; + else if (!explicitOnly){ + os<<"("; printOpndRoles(orf); os<<":"; + } + printOpnd(inst, it, false, false); + } + if (printedOpnds && !explicitOnly) + os<<")"; + return printedOpnds; } -//_____________________________________________________________________________________________ void IRPrinter::printInst(const Inst * inst) { - ::std::ostream& os = getStream(); - os<<"I"<getId()<<": "; - - if (opndRolesFilter & Inst::OpndRole_Def){ - uint32 printedOpndsTotal=0, printedOpnds=0; - if (inst->getForm()==Inst::Form_Extended) - printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Explicit)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } - printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Auxilary)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } - printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Implicit)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } - - if (printedOpndsTotal) - os<<"="; - } - - if (inst->hasKind(Inst::Kind_PseudoInst)){ - os<getKind()); - }else{ - if( inst->getMnemonic() != Mnemonic_Null ) - os<< Encoder::getMnemonicString( inst->getMnemonic() ); - if (inst->hasKind(Inst::Kind_BranchInst) && inst->getBasicBlock()!=NULL){ - BasicBlock * target=((BranchInst*)inst)->getDirectBranchTarget(); - if (target){ - os<<" "; printNodeName(target); - } - } - } - - os<<" "; - uint32 printedOpndsTotal=0, printedOpnds=0; - printedOpnds=printInstOpnds(inst, ((inst->getForm()==Inst::Form_Extended?Inst::OpndRole_Use:Inst::OpndRole_UseDef)|Inst::OpndRole_Explicit)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } - printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Use|Inst::OpndRole_Auxilary)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } - printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Use|Inst::OpndRole_Implicit)&opndRolesFilter); - if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + ::std::ostream& os = getStream(); + os<<"I"<getId()<<": "; + + if (opndRolesFilter & Inst::OpndRole_Def){ + uint32 printedOpndsTotal=0, printedOpnds=0; + if (inst->getForm()==Inst::Form_Extended) + printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Explicit)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Auxilary)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Def|Inst::OpndRole_Implicit)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + + if (printedOpndsTotal) + os<<"="; + } + + if (inst->hasKind(Inst::Kind_PseudoInst)){ + os<getKind()); + }else{ + if( inst->getMnemonic() != Mnemonic_Null ) + os<< Encoder::getMnemonicString( inst->getMnemonic() ); + if (inst->hasKind(Inst::Kind_BranchInst) && inst->getNode()!=NULL){ + Node* target=((BranchInst*)inst)->getTrueTarget(); + if (target){ + os<<" "; printNodeName(target); + } + } + } + if ((inst->getKind() == Inst::Kind_MethodEndPseudoInst || + inst->getKind() == Inst::Kind_MethodEntryPseudoInst)) { + MethodMarkerPseudoInst* methMarkerInst = (MethodMarkerPseudoInst*)inst; + os<<"["; + os<getMethodDesc()->getParentType()->getName(); + os<<"."<getMethodDesc()->getName(); + os<<"]"; + if (inst->getKind() == Inst::Kind_MethodEndPseudoInst) os << "+++"; + else os << "---"; + } + + os<<" "; + uint32 printedOpndsTotal=0, printedOpnds=0; + printedOpnds=printInstOpnds(inst, ((inst->getForm()==Inst::Form_Extended?Inst::OpndRole_Use:Inst::OpndRole_UseDef)|Inst::OpndRole_Explicit)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Use|Inst::OpndRole_Auxilary)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } + printedOpnds=printInstOpnds(inst, (Inst::OpndRole_Use|Inst::OpndRole_Implicit)&opndRolesFilter); + if (printedOpnds){ os<<" "; printedOpndsTotal+=printedOpnds; } if (inst->hasKind(Inst::Kind_GCInfoPseudoInst)) { const GCInfoPseudoInst* gcInst = (GCInfoPseudoInst*)inst; @@ -361,7 +364,7 @@ void IRPrinter::printInst(const Inst * i int32 offset = offsets[i]; Opnd* opnd = uses[i]; if (i>0) { - os<<","; + os<<","; } os << "["; printOpndName(opnd); os <<"," <getDefScope(); - os<<( - ds==Opnd::DefScope_Variable?"v": - ds==Opnd::DefScope_SemiTemporary?"s": - ds==Opnd::DefScope_Temporary?"t": - "o" - )<getFirstId(); + ::std::ostream& os = getStream(); + Opnd::DefScope ds=opnd->getDefScope(); + os<<( + ds==Opnd::DefScope_Variable?"v": + ds==Opnd::DefScope_SemiTemporary?"s": + ds==Opnd::DefScope_Temporary?"t": + "o" + )<getFirstId(); } //_________________________________________________________________________________________________ uint32 IRPrinter::getOpndNameLength(Opnd * opnd) { - uint32 id=opnd->getFirstId(); - uint32 idLength=id<10?1:id<100?2:id<1000?3:id<10000?4:5; - return 1+idLength; + uint32 id=opnd->getFirstId(); + uint32 idLength=id<10?1:id<100?2:id<1000?3:id<10000?4:5; + return 1+idLength; } //_____________________________________________________________________________________________ void IRPrinter::printOpnd(const Inst * inst, uint32 idx, bool isLiveBefore, bool isLiveAfter) { - printOpnd(inst->getOpnd(idx), inst->getOpndRoles(idx), isLiveBefore, isLiveAfter); + printOpnd(inst->getOpnd(idx), inst->getOpndRoles(idx), isLiveBefore, isLiveAfter); } //_____________________________________________________________________________________________ void IRPrinter::printRuntimeInfo(const Opnd::RuntimeInfo * info) { - ::std::ostream& os = getStream(); - switch(info->getKind()){ - case Opnd::RuntimeInfo::Kind_HelperAddress: - /** The value of the operand is compilationInterface->getRuntimeHelperAddress */ - { - os<<"h:"<< - irManager->getCompilationInterface().getRuntimeHelperName( - (CompilationInterface::RuntimeHelperId)(uint32)info->getValue(0) - ); - }break; - case Opnd::RuntimeInfo::Kind_InternalHelperAddress: - /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ - { - os<<"ih:"<<(const char*)info->getValue(0)<<":"<<(void*)irManager->getInternalHelperInfo((const char*)info->getValue(0))->pfn; - }break; - case Opnd::RuntimeInfo::Kind_TypeRuntimeId: - /* The value of the operand is [0]->ObjectType::getRuntimeIdentifier() */ - { - os<<"id:"; printType((NamedType*)info->getValue(0)); - }break; - case Opnd::RuntimeInfo::Kind_AllocationHandle: - /* The value of the operand is [0]->ObjectType::getAllocationHandle() */ - { - os<<"ah:"; printType((ObjectType*)info->getValue(0)); - }break; - case Opnd::RuntimeInfo::Kind_StringDescription: - /* [0] - Type * - the containing class, [1] - string token */ - assert(0); - break; - case Opnd::RuntimeInfo::Kind_Size: - /* The value of the operand is [0]->ObjectType::getObjectSize() */ - { - os<<"sz:"; printType((ObjectType*)info->getValue(0)); - }break; - case Opnd::RuntimeInfo::Kind_StaticFieldAddress: - /** The value of the operand is [0]->FieldDesc::getAddress() */ - { - FieldDesc * fd=(FieldDesc*)info->getValue(0); - os<<"&f:"; - os<getParentType()->getName()<<"."<getName(); - }break; - case Opnd::RuntimeInfo::Kind_FieldOffset: - /** The value of the operand is [0]->FieldDesc::getOffset() */ - { - FieldDesc * fd=(FieldDesc*)info->getValue(0); - os<<"fo:"; - os<getParentType()->getName()<<"."<getName(); - }break; - case Opnd::RuntimeInfo::Kind_VTableAddrOffset: - /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ - { - os<<"vtao"; - }break; - case Opnd::RuntimeInfo::Kind_VTableConstantAddr: - /** The value of the operand is [0]->ObjectType::getVTable() */ - { - os<<"vtca:"; printType((ObjectType*)info->getValue(0)); - }break; - case Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset: - /** The value of the operand is [0]->MethodDesc::getOffset() */ - { - MethodDesc * md=(MethodDesc*)info->getValue(0); - os<<"vtso:"; - os<getParentType()->getName()<<"."<getName(); - }break; - case Opnd::RuntimeInfo::Kind_MethodIndirectAddr: - /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ - { - MethodDesc * md=(MethodDesc*)info->getValue(0); - os<<"&m:"; - os<getParentType()->getName()<<"."<getName(); - }break; - case Opnd::RuntimeInfo::Kind_MethodDirectAddr: - /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ - { - MethodDesc * md=(MethodDesc*)info->getValue(0); - os<<"m:"; - os<getParentType()->getName()<<"."<getName(); - }break; - case Opnd::RuntimeInfo::Kind_ConstantAreaItem: - break; - case Opnd::RuntimeInfo::Kind_MethodRuntimeId: - { - MethodDesc * md=(MethodDesc*)info->getValue(0); - os<<"vtso:"; - os<getParentType()->getName()<<"."<getName(); - }break; - default: - assert(0); - } - uint32 additionalOffset=info->getAdditionalOffset(); - if (additionalOffset>0) - os<<"+"<getKind()){ + case Opnd::RuntimeInfo::Kind_HelperAddress: + /** The value of the operand is compilationInterface->getRuntimeHelperAddress */ + { + os<<"h:"<< + irManager->getCompilationInterface().getRuntimeHelperName( + (CompilationInterface::RuntimeHelperId)(POINTER_SIZE_INT)info->getValue(0) + ); + }break; + case Opnd::RuntimeInfo::Kind_InternalHelperAddress: + /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ + { + os<<"ih:"<<(const char*)info->getValue(0)<<":"<<(void*)irManager->getInternalHelperInfo((const char*)info->getValue(0))->pfn; + }break; + case Opnd::RuntimeInfo::Kind_TypeRuntimeId: + /* The value of the operand is [0]->ObjectType::getRuntimeIdentifier() */ + { + os<<"id:"; printType((NamedType*)info->getValue(0)); + }break; + case Opnd::RuntimeInfo::Kind_AllocationHandle: + /* The value of the operand is [0]->ObjectType::getAllocationHandle() */ + { + os<<"ah:"; printType((ObjectType*)info->getValue(0)); + }break; + case Opnd::RuntimeInfo::Kind_StringDescription: + /* [0] - Type * - the containing class, [1] - string token */ + assert(0); + break; + case Opnd::RuntimeInfo::Kind_Size: + /* The value of the operand is [0]->ObjectType::getObjectSize() */ + { + os<<"sz:"; printType((ObjectType*)info->getValue(0)); + }break; + case Opnd::RuntimeInfo::Kind_StringAddress: + /** The value of the operand is the address where the interned version of the string is stored*/ + { + os<<"&str:"; + os<<(POINTER_SIZE_INT)info->getValue(1); // string token + }break; + case Opnd::RuntimeInfo::Kind_StaticFieldAddress: + /** The value of the operand is [0]->FieldDesc::getAddress() */ + { + FieldDesc * fd=(FieldDesc*)info->getValue(0); + os<<"&f:"; + os<getParentType()->getName()<<"."<getName(); + }break; + case Opnd::RuntimeInfo::Kind_FieldOffset: + /** The value of the operand is [0]->FieldDesc::getOffset() */ + { + FieldDesc * fd=(FieldDesc*)info->getValue(0); + os<<"fo:"; + os<getParentType()->getName()<<"."<getName(); + }break; + case Opnd::RuntimeInfo::Kind_VTableAddrOffset: + /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ + { + os<<"vtao"; + }break; + case Opnd::RuntimeInfo::Kind_VTableConstantAddr: + /** The value of the operand is [0]->ObjectType::getVTable() */ + { + os<<"vtca:"; printType((ObjectType*)info->getValue(0)); + }break; + case Opnd::RuntimeInfo::Kind_MethodVtableSlotOffset: + /** The value of the operand is [0]->MethodDesc::getOffset() */ + { + MethodDesc * md=(MethodDesc*)info->getValue(0); + os<<"vtso:"; + os<getParentType()->getName()<<"."<getName(); + }break; + case Opnd::RuntimeInfo::Kind_MethodIndirectAddr: + /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ + { + MethodDesc * md=(MethodDesc*)info->getValue(0); + os<<"&m:"; + os<getParentType()->getName()<<"."<getName(); + }break; + case Opnd::RuntimeInfo::Kind_MethodDirectAddr: + /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ + { + MethodDesc * md=(MethodDesc*)info->getValue(0); + os<<"m:"; + os<getParentType()->getName()<<"."<getName(); + }break; + case Opnd::RuntimeInfo::Kind_ConstantAreaItem: + break; + case Opnd::RuntimeInfo::Kind_MethodRuntimeId: + { + MethodDesc * md=(MethodDesc*)info->getValue(0); + os<<"vtso:"; + os<getParentType()->getName()<<"."<getName(); + }break; + default: + assert(0); + } + uint32 additionalOffset=info->getAdditionalOffset(); + if (additionalOffset>0) + os<<"+"<isPlacedIn(OpndKind_Reg)){ - os<<"("; printRegName(opnd->getRegName()); os<<")"; - }else if(opnd->isPlacedIn(OpndKind_Mem)){ - os<<"["; - uint32 oldOpndFlavor=opndFlavor; - opndFlavor&=~OpndFlavor_Type; - bool append=false; - for (uint32 i=0; igetMemOpndSubOpnd((MemOpndSubOpndKind)i); - if (subOpnd){ - if (append){ - if ((MemOpndSubOpndKind)i==MemOpndSubOpndKind_Scale) - os<<"*"; - else - os<<"+"; - } - printOpnd(subOpnd); - append=true; - } - } - opndFlavor=oldOpndFlavor; - os<<"]"; - }else if(opnd->isPlacedIn(OpndKind_Imm)){ - os<<"("<getImmValue(); - if (opndFlavor & OpndFlavor_RuntimeInfo){ - Opnd::RuntimeInfo * ri=opnd->getRuntimeInfo(); - if (ri!=NULL){ - os<<":"; - printRuntimeInfo(ri); - } - } - os<<")"; - } - } - if (opndFlavor&OpndFlavor_Type){ - os<<":"; printType(opnd->getType()); - } + ::std::ostream& os = getStream(); + + if (isLiveBefore) os<<"."; + printOpndName(opnd); + if (isLiveAfter) os<<"."; + + if (opndFlavor&OpndFlavor_Location){ + if (opnd->isPlacedIn(OpndKind_Reg)){ + os<<"("; printRegName(opnd->getRegName()); os<<")"; + }else if(opnd->isPlacedIn(OpndKind_Mem)){ + os<<"["; + uint32 oldOpndFlavor=opndFlavor; + opndFlavor&=~OpndFlavor_Type; + bool append=false; + for (uint32 i=0; igetMemOpndSubOpnd((MemOpndSubOpndKind)i); + if (subOpnd){ + if (append){ + if ((MemOpndSubOpndKind)i==MemOpndSubOpndKind_Scale) + os<<"*"; + else + os<<"+"; + } + printOpnd(subOpnd); + append=true; + } + } + opndFlavor=oldOpndFlavor; + os<<"]"; + }else if(opnd->isPlacedIn(OpndKind_Imm)){ + os<<"("<getImmValue(); + if (opndFlavor & OpndFlavor_RuntimeInfo){ + Opnd::RuntimeInfo * ri=opnd->getRuntimeInfo(); + if (ri!=NULL){ + os<<":"; + printRuntimeInfo(ri); + } + } + os<<")"; + } + } + if (opndFlavor&OpndFlavor_Type){ + os<<":"; printType(opnd->getType()); + } } //_____________________________________________________________________________________________ void IRPrinter::printType(const Type * type) { - ::std::ostream& os = getStream(); - ((Type*)type)->print(os); + ::std::ostream& os = getStream(); + ((Type*)type)->print(os); } //======================================================================================== @@ -569,37 +578,37 @@ void IRPrinter::printType(const Type * t //_____________________________________________________________________________________________ void IRLivenessPrinter::printNode(const Node * node, uint32 indent) { - assert(irManager!=NULL); - ::std::ostream& os = getStream(); - printNodeHeader(node, indent); + assert(irManager!=NULL); + ::std::ostream& os = getStream(); + printNodeHeader(node, indent); os << ::std::endl; - LiveSet * ls=irManager->getLiveAtEntry(node); - os<<"Live at entry: "; printLiveSet(ls); os<<::std::endl; + BitSet * ls=irManager->getLiveAtEntry(node); + os<<"Live at entry: "; printLiveSet(ls); os<<::std::endl; - MemoryManager mm(0x100, "IRLivenessPrinter::printNode"); - ls=new(mm) LiveSet(mm, irManager->getOpndCount()); - irManager->getLiveAtExit(node, *ls); - os<<"Live at exit: "; printLiveSet(ls); os<<::std::endl; + MemoryManager mm(0x100, "IRLivenessPrinter::printNode"); + ls=new(mm) BitSet(mm, irManager->getOpndCount()); + irManager->getLiveAtExit(node, *ls); + os<<"Live at exit: "; printLiveSet(ls); os<<::std::endl; - os << ::std::endl; + os << ::std::endl; } //_____________________________________________________________________________________________ -void IRLivenessPrinter::printLiveSet(const LiveSet * ls) +void IRLivenessPrinter::printLiveSet(const BitSet * ls) { - ::std::ostream& os = getStream(); - assert(irManager!=NULL); - if (ls==NULL){ - os<<"Null"; - return; - } - for (uint32 i=0, n=irManager->getOpndCount(); igetOpnd(i); - if (ls->isLive(opnd)){ - printOpndName(opnd); os<<"("<getId()<<")"<<" "; - } - } + std::ostream& os = getStream(); + assert(irManager!=NULL); + if (ls==NULL){ + os<<"Null"; + return; + } + for (uint32 i=0, n=irManager->getOpndCount(); igetOpnd(i); + if (ls->getBit(opnd->getId())){ + printOpndName(opnd); os<<"("<getId()<<")"<<" "; + } + } } //======================================================================================== @@ -608,41 +617,41 @@ void IRLivenessPrinter::printLiveSet(con //_____________________________________________________________________________________________ void IROpndPrinter::printBody(uint32 indent) { - assert(irManager!=NULL); - ::std::ostream& os = getStream(); - for (uint32 i=0, n=irManager->getOpndCount(); igetOpnd(i); - printOpnd(opnd); - os<<'\t'; - os<<"addr="<getConstraint(Opnd::ConstraintKind_Initial)); - os<<::std::endl; - printIndent(indent+1); - os<<"Calculated constraint: "; - printConstraint(opnd->getConstraint(Opnd::ConstraintKind_Calculated)); - os<<::std::endl; - printIndent(indent+1); - os<<"Location constraint: "; - printConstraint(opnd->getConstraint(Opnd::ConstraintKind_Location)); - os<<::std::endl; - printIndent(indent); - } + assert(irManager!=NULL); + ::std::ostream& os = getStream(); + for (uint32 i=0, n=irManager->getOpndCount(); igetOpnd(i); + printOpnd(opnd); + os<<'\t'; + os<<"addr="<getConstraint(Opnd::ConstraintKind_Initial)); + os<<::std::endl; + printIndent(indent+1); + os<<"Calculated constraint: "; + printConstraint(opnd->getConstraint(Opnd::ConstraintKind_Calculated)); + os<<::std::endl; + printIndent(indent+1); + os<<"Location constraint: "; + printConstraint(opnd->getConstraint(Opnd::ConstraintKind_Location)); + os<<::std::endl; + printIndent(indent); + } } //_____________________________________________________________________________________________ void IROpndPrinter::printHeader(uint32 indent) { - assert(irManager!=NULL); - ::std::ostream& os = getStream(); - os << ::std::endl; printIndent(indent); - os << "...................................................................." << ::std::endl; printIndent(indent); - os << irManager->getMethodDesc().getParentType()->getName()<<"."<getMethodDesc().getName()<<": Operands in " << (title?title:"???") << ::std::endl; printIndent(indent); - os << "...................................................................." << ::std::endl; printIndent(indent); - os << ::std::endl; + assert(irManager!=NULL); + ::std::ostream& os = getStream(); + os << ::std::endl; printIndent(indent); + os << "...................................................................." << ::std::endl; printIndent(indent); + os << irManager->getMethodDesc().getParentType()->getName()<<"."<getMethodDesc().getName()<<": Operands in " << (title?title:"???") << ::std::endl; printIndent(indent); + os << "...................................................................." << ::std::endl; printIndent(indent); + os << ::std::endl; } @@ -653,12 +662,12 @@ void IROpndPrinter::printHeader(uint32 i //_____________________________________________________________________________________________ void IRInstConstraintPrinter::printOpnd(const Inst * inst, uint32 idx, bool isLiveBefore, bool isLiveAfter) { - ::std::ostream& os = getStream(); - Opnd * opnd=inst->getOpnd(idx); - printOpndName(opnd); - os<<"("; - printConstraint(inst->getConstraint(Inst::ConstraintKind_Current, idx)); - os<<")"; + ::std::ostream& os = getStream(); + Opnd * opnd=inst->getOpnd(idx); + printOpndName(opnd); + os<<"("; + printConstraint(((Inst *)inst)->getConstraint(idx, 0, OpndSize_Null)); + os<<")"; } @@ -669,118 +678,138 @@ void IRInstConstraintPrinter::printOpnd( //_____________________________________________________________________________________________ void OpcodeDescriptionPrinter::printConstraint(Constraint c) { - ::std::ostream& os = getStream(); - if (c.isNull()){ - os<<"Null"; - return; - } - os<count<<" (D:"<defCount<<",U:"<useCount<<"); roles: "; - for (uint32 i=0; icount; i++){ - if (i>0) - os<<','; - printOpndRoles(Encoder::getOpndRoles(*ord, i)); - } + ::std::ostream& os=getStream(); + os<<"count: "<<(uint32)ord->count<<" (D:"<defCount<<",U:"<useCount<<"); roles: "; + for (uint32 i=0; icount; i++){ + if (i>0) + os<<','; + printOpndRoles(Encoder::getOpndRoles(*ord, i)); + } +} + +//_________________________________________________________________________________________________ +void OpcodeDescriptionPrinter::printOpcodeDescription(const Encoder::OpcodeDescription * od, uint32 indent) +{ + assert( false ); +} + +//_________________________________________________________________________________________________ +void OpcodeDescriptionPrinter::printOpcodeGroup(const Encoder::OpcodeGroup* ogd, uint32 indent) +{ + assert( false ); } +//_________________________________________________________________________________________________ +void OpcodeDescriptionPrinter::print(uint32 indent) +{ + assert( false ); +} + + //======================================================================================== // class IRDotPrinter //======================================================================================== void IRDotPrinter::printNode(const Node * node) { - ::std::ostream& out=getStream(); + std::ostream& out=getStream(); printNodeName(node); out << " [label=\""; - BasicBlock * bb=node->hasKind(Node::Kind_BasicBlock)?(BasicBlock*)node:NULL; - if (bb)out << "{"; - printNodeName(node); - if (node->getPersistentId()!=UnknownId) - out << " pid: " << node->getPersistentId() << " "; - if(node->getExecCnt() > 0) - out << " ec:" << node->getExecCnt() << " "; - - if (node->hasLoopInfo() && (node->isLoopHeader()||node->getLoopHeader())) { - out << " Loop: Depth=" << node->getLoopDepth(); - if (node->isLoopHeader()) + BasicBlock * bb=node->isBlockNode()?(BasicBlock*)node:NULL; + if (bb)out << "{"; + printNodeName(node); + if (((CGNode*)node)->getPersistentId()!=UnknownId) + out << " pid: " << ((CGNode*)node)->getPersistentId() << " "; + if(node->getExecCount() > 0) + out << " ec:" << node->getExecCount() << " "; + + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + if (lt->isValid() && lt->getLoopHeader(node, false)!=NULL) { + out << " Loop: Depth=" << lt->getLoopDepth(node); + if (lt->isLoopHeader(node)) out << ", hdr, hdr= "; else out << ", !hdr, hdr="; - printNodeName(node->getLoopHeader()); + printNodeName(lt->getLoopHeader(node)); } - if (bb!=NULL && irManager->getCodeStartAddr()!=NULL){ - out<<", code="<<(void*)bb->getCodeStartAddr(); - } + if (bb!=NULL && irManager->getCodeStartAddr()!=NULL){ + out<<", code="<<(void*)bb->getCodeStartAddr(); + } - if (bb) { - out << "\\l|\\" << ::std::endl; + if (bb) { + out << "\\l|\\" << std::endl; VectorHandler* lirMapHandler = NULL; if (irManager->getCompilationInterface().isBCMapInfoRequired()) { MethodDesc* meth = irManager->getCompilationInterface().getMethodToCompile(); lirMapHandler = new(irManager->getMemoryManager()) VectorHandler(bcOffset2LIRHandlerName, meth); assert(lirMapHandler); } - for (Inst * inst = bb->getInsts().getFirst(); inst != NULL; inst = bb->getInsts().getNext(inst)) { - Inst::Kind kind=inst->getKind(); - if ((kind & instFilter)==(uint32)kind){ - printInst(inst); + for (Inst * inst = (Inst*)bb->getFirstInst(); inst != NULL; inst = inst->getNextInst()) { + Inst::Kind kind=inst->getKind(); + if ((kind & instFilter)==(uint32)kind){ + printInst(inst); if (lirMapHandler != NULL) { uint64 bcOffset = 0; uint64 instID = inst->getId(); @@ -788,72 +817,80 @@ void IRDotPrinter::printNode(const Node if (bcOffset != ILLEGAL_VALUE) out<<" bcOff: "<< (uint16)bcOffset << " "; } out << "\\l\\" << ::std::endl; - } - } + } + } out << "}"; } out << "\""; - if (node->hasKind(Node::Kind_DispatchNode)) - out << ",shape=diamond,color=blue"; - else if (node->hasKind(Node::Kind_UnwindNode)) - out << ",shape=diamond,color=red"; - else if (node->hasKind(Node::Kind_ExitNode)) + if (node->isDispatchNode()) { + if (node!=irManager->getFlowGraph()->getUnwindNode()) { + out << ",shape=diamond,color=blue"; + } else { + out << ",shape=diamond,color=red"; + } + } else if (node->isExitNode()) { out << ",shape=ellipse,color=green"; - out << "]" << ::std::endl; + } + out << "]" << std::endl; } //_________________________________________________________________________________________________ void IRDotPrinter::printEdge(const Edge * edge) { - ::std::ostream& out=getStream(); - Node * from=edge->getNode(Direction_Tail); - Node * to=edge->getNode(Direction_Head); - printNodeName(from); - out<<" -> "; - printNodeName(to); - out<<" [taillabel=\""; - if (edge->getProbability()>=0.0) - out<<"p: "<getProbability(); - out<<"\""; - - if (edge->isFallThroughEdge()) - out<<",style=bold"; - else if (edge->isDirectBranchEdge()) - ; - else if (to->hasKind(Node::Kind_DispatchNode)) - out<<",style=dotted,color=blue"; - else if (to->hasKind(Node::Kind_UnwindNode)||from->hasKind(Node::Kind_UnwindNode)) - out<<",style=dotted,color=red"; - else if (to->hasKind(Node::Kind_ExitNode)) - out<<",style=dotted,color=green"; - if (edge->isLoopExit()) - out<<",arrowtail=inv"; - - if (edge->hasKind(Edge::Kind_CatchEdge)){ - out<<",color=blue,headlabel=\"Type: "; - printType(((CatchEdge*)edge)->getType()); - out<<" pri:"<<((CatchEdge*)edge)->getPriority()<<"\""; - } - out<<"];"<<::std::endl; + std::ostream& out=getStream(); + Node * from=edge->getSourceNode(); + Node * to=edge->getTargetNode(); + printNodeName(from); + out<<" -> "; + printNodeName(to); + out<<" [taillabel=\""; + if (edge->getEdgeProb()>=0.0) + out<<"p: "<getEdgeProb(); + out<<"\""; + + Node* unwind = irManager->getFlowGraph()->getUnwindNode(); + if (edge->isFalseEdge()) { + out<<",style=bold"; + } else if (edge->isTrueEdge()) { + ; + } else if (edge->isDispatchEdge()) { + out<<",style=dotted,color=blue"; + } else if (to == unwind || from == unwind) { + out<<",style=dotted,color=red"; + } else if (to->isExitNode()) { + out<<",style=dotted,color=green"; + } + + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + if (lt->isValid() && lt->isLoopExit(edge)) { + out<<",arrowtail=inv"; + } + + if (edge->isCatchEdge()){ + out<<",color=blue,headlabel=\"Type: "; + printType(((CatchEdge*)edge)->getType()); + out<<" pri:"<<((CatchEdge*)edge)->getPriority()<<"\""; + } + out<<"];"< "; - printNodeName(to); - out<<" ["; - out<<"style=dotted,color=gray"; - out<<"]"; + ::std::ostream& out=getStream(); + printNodeName(from); + out<<" -> "; + printNodeName(to); + out<<" ["; + out<<"style=dotted,color=gray"; + out<<"]"; } //_________________________________________________________________________________________________ void IRDotPrinter::printHeader(uint32 indent) { - assert(irManager!=NULL); - getStream() << "digraph dotgraph {" << ::std::endl + assert(irManager!=NULL); + getStream() << "digraph dotgraph {" << ::std::endl << "center=TRUE;" << ::std::endl << "margin=\".2,.2\";" << ::std::endl << "ranksep=\".25\";" << ::std::endl @@ -867,7 +904,7 @@ void IRDotPrinter::printHeader(uint32 in << irManager->getMethodDesc().getParentType()->getName() << "::" << irManager->getMethodDesc().getName() - <<" - "<getLiveAtEntry(node); - out<<"liveness_"; printNodeName(node); - out << " [label=\""; printNodeName(node); out<<":"; - if (ls){ - for (uint32 i = 0; i < ls->getSetSize(); i++) { - if (ls->getBit(i)) - out << " " << i; - } - }else - out<<" UNKNOWN"; - out <<"\"]"; out<<::std::endl; - } - - Node * lastNode=0; - for(CFG::NodeIterator it(*irManager, CFG::OrderType_Topological); it!=NULL; ++it) { - if (lastNode){ - out<<"liveness_"; printNodeName(lastNode); - out<<" -> "; - out<<"liveness_"; printNodeName(it); - out<<";"<<::std::endl; - } - lastNode=it; - } - - out<<"}"<<::std::endl; + ::std::ostream& out=getStream(); + + out<<"subgraph cluster_liveness {"<<::std::endl; + out<<"label=liveness"<<::std::endl; + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + const BitSet * ls=irManager->getLiveAtEntry(node); + out<<"liveness_"; printNodeName(node); + out << " [label=\""; printNodeName(node); out<<":"; + if (ls){ + for (uint32 i = 0; i < ls->getSetSize(); i++) { + if (ls->getBit(i)) + out << " " << i; + } + }else + out<<" UNKNOWN"; + out <<"\"]"; out<<::std::endl; + } + + Node * lastNode=0; + for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + if (lastNode){ + out<<"liveness_"; printNodeName(lastNode); + out<<" -> "; + out<<"liveness_"; printNodeName(node); + out<<";"<<::std::endl; + } + lastNode=node; + } + + out<<"}"<<std::endl; } //_________________________________________________________________________________________________ -void IRDotPrinter::printTraversalOrder(CFG::OrderType orderType) +void IRDotPrinter::printTraversalOrder(CGNode::OrderType orderType) { - ::std::ostream& out=getStream(); - - const char * prefix= - orderType==CFG::OrderType_Topological?"topological": - orderType==CFG::OrderType_Postorder?"postorder": - orderType==CFG::OrderType_Layout?"layout": - orderType==CFG::OrderType_Arbitrary?"arbitrary": - "order"; - - out<<"subgraph cluster_"<<prefix<<" {"<<::std::endl; - out<<"label="<<prefix<<::std::endl; - - for(CFG::NodeIterator it(*irManager, orderType); it!=NULL; ++it) { - out<<prefix<<"_"; printNodeName(it); out<<"[label="; printNodeName(it); out<<"]"<<::std::endl; - } - - Node * lastNode=0; - for(CFG::NodeIterator it(*irManager, orderType); it!=NULL; ++it) { - if (lastNode){ - out<<prefix<<"_"; printNodeName(lastNode); - out<<" -> "; - out<<prefix<<"_"; printNodeName(it); - out<<";"<<::std::endl; - } - lastNode=it; - } - out<<"}"<<::std::endl; + std::ostream& out=getStream(); + + const char* prefix = NULL; + Nodes nodes(irManager->getMemoryManager()); + switch(orderType) { + case CGNode::OrderType_Topological: + { + prefix = "topological"; + const Nodes& postOrder = irManager->getFlowGraph()->getNodesPostOrder(); + nodes.insert(nodes.end(), postOrder.rbegin(), postOrder.rend()); + } + break; + case CGNode::OrderType_Postorder: + { + prefix = "postorder"; + const Nodes& postOrder = irManager->getFlowGraph()->getNodesPostOrder(); + nodes.insert(nodes.end(), postOrder.begin(), postOrder.end()); + } + break; + case CGNode::OrderType_Layout: + { + assert(irManager->isLaidOut()); + prefix = "layout"; + for (BasicBlock* bb = (BasicBlock*)irManager->getFlowGraph()->getEntryNode(); bb!=NULL; bb = bb->getLayoutSucc()) { + nodes.push_back(bb); + } + } + break; + default: + { + assert(orderType == CGNode::OrderType_Arbitrary); + prefix = "arbitrary"; + const Nodes& arbitrary = irManager->getFlowGraph()->getNodes(); + nodes.insert(nodes.end(), arbitrary.begin(), arbitrary.end()); + } + break; + } + + out<<"subgraph cluster_"<<prefix<<" {"<<std::endl; + out<<"label="<<prefix<<std::endl; + + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + out<<prefix<<"_"; printNodeName(node); out<<"[label="; printNodeName(node); out<<"]"<<std::endl; + } + + Node * prevNode=NULL; + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (prevNode){ + out<<prefix<<"_"; printNodeName(prevNode); + out<<" -> "; + out<<prefix<<"_"; printNodeName(node); + out<<";"<<std::endl; + } + prevNode=node; + } + out<<"}"<<std::endl; } //_________________________________________________________________________________________________ void IRDotPrinter::printBody(uint32 indent) { - assert(irManager!=NULL); + assert(irManager!=NULL); - printTraversalOrder(CFG::OrderType_Topological); - printTraversalOrder(CFG::OrderType_Postorder); - if (irManager->isLaidOut()) - printTraversalOrder(CFG::OrderType_Layout); - printCFG(0); - printLiveness(); + printTraversalOrder(CGNode::OrderType_Topological); + printTraversalOrder(CGNode::OrderType_Postorder); + if (irManager->isLaidOut()) + printTraversalOrder(CGNode::OrderType_Layout); + printCFG(0); + printLiveness(); } //_________________________________________________________________________________________________ void IRDotPrinter::printCFG(uint32 indent) { - assert(irManager!=NULL); - for(CFG::NodeIterator it(*irManager); it!=NULL; ++it) - printNode(it.getNode()); - for(CFG::NodeIterator it(*irManager); it!=NULL; ++it) { - const Edges& es=it.getNode()->getEdges(Direction_Out); - for(Edge * e=es.getFirst(); e!=NULL; e=es.getNext(e)) + assert(irManager!=NULL); + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + printNode(node); + } + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + const Edges& edges =node->getOutEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; printEdge(e); + } } - if (irManager->isLaidOut()){ - for(CFG::NodeIterator it(*irManager); it!=NULL; ++it) { - if (it.getNode()->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * from=(BasicBlock*)it.getNode(); - BasicBlock * to=from->getLayoutSucc(); - if (to!=NULL) - printLayoutEdge(from, to); - } - } - } + if (irManager->isLaidOut()){ + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + BasicBlock * from=(BasicBlock*)node; + BasicBlock * to=from->getLayoutSucc(); + if (to!=NULL) { + printLayoutEdge(from, to); + } + } + } + } } //_________________________________________________________________________________________________ void IRDotPrinter::print(uint32 indent) { - IRPrinter::print(); + IRPrinter::print(); } //_________________________________________________________________________________________________ @@ -1000,478 +1078,497 @@ void IRDotPrinter::print(uint32 indent) //_________________________________________________________________________________________________ void IRLivenessDotPrinter::printBody(uint32 indent) { - assert(irManager!=NULL); - setOpndFlavor(OpndFlavor_Location); - printCFG(0); + assert(irManager!=NULL); + setOpndFlavor(OpndFlavor_Location); + printCFG(0); } //_________________________________________________________________________________________________ char * IRLivenessDotPrinter::getRegString(char * str, Constraint c, StlVector<Opnd *> opnds) { - char * retStr=NULL; - uint32 si=0; - for (uint32 i=0, n=opnds.size(); i<n; i++){ - Opnd * o=opnds[i]; - if (o->isPlacedIn(c)){ - retStr=str; - RegName r=o->getRegName(); - str[si++]=(char)('0'+getRegIndex(r)); - }else - str[si++]='_'; - for (uint32 j=0, l=getOpndNameLength(o)-1; j<l; j++) - str[si++]='_'; - } - str[si++]=0; - return retStr; + char * retStr=NULL; + uint32 si=0; + for (uint32 i=0, n=opnds.size(); i<n; i++){ + Opnd * o=opnds[i]; + if (o->isPlacedIn(c)){ + retStr=str; + RegName r=o->getRegName(); + str[si++]=(char)('0'+getRegIndex(r)); + }else + str[si++]='_'; + for (uint32 j=0, l=getOpndNameLength(o)-1; j<l; j++) + str[si++]='_'; + } + str[si++]=0; + return retStr; } //_________________________________________________________________________________________________ void IRLivenessDotPrinter::printNode(const Node * node) { - ::std::ostream& out=getStream(); - MemoryManager mm(0x2000, "IRLivenessDotPrinter::printNode"); + ::std::ostream& out=getStream(); + MemoryManager mm(0x2000, "IRLivenessDotPrinter::printNode"); printNodeName(node); out << " [label=\""; - BasicBlock * bb=node->hasKind(Node::Kind_BasicBlock)?(BasicBlock*)node:NULL; - if (bb!=NULL) out << "{"; - printNodeName(node); - if (node->getPersistentId()!=UnknownId) - out << " pid: " << node->getPersistentId() << " "; - if(node->getExecCnt() > 0) - out << " ec:" << node->getExecCnt() << " "; - - if (node->hasLoopInfo() && (node->isLoopHeader()||node->getLoopHeader())) { - out << " Loop: Depth=" << node->getLoopDepth(); - if (node->isLoopHeader()) + BasicBlock * bb=node->isBlockNode()?(BasicBlock*)node:NULL; + if (bb!=NULL) out << "{"; + printNodeName(node); + if (((CGNode*)node)->getPersistentId()!=UnknownId) + out << " pid: " << ((CGNode*)node)->getPersistentId() << " "; + if(node->getExecCount() > 0) + out << " ec:" << node->getExecCount() << " "; + + LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); + if (lt->isValid() && lt->getLoopDepth(node)!=0) { + out << " Loop: Depth=" << lt->getLoopDepth(node); + if (lt->isLoopHeader(node)) { out << ", hdr, hdr= "; - else + } else { out << ", !hdr, hdr="; - printNodeName(node->getLoopHeader()); - } - - if (bb!=NULL && irManager->getCodeStartAddr()!=NULL){ - out<<", code="<<(void*)bb->getCodeStartAddr(); - } - - if (bb!=NULL){ - if (irManager->hasLivenessInfo()){ - - StlVector<LiveSet *> liveSets(mm); - StlVector<uint32> regUsages(mm); - LiveSet * lsAll=new (mm) LiveSet(mm, irManager->getOpndCount()); - - LiveSet * lsCurrent=new (mm) LiveSet(mm, irManager->getOpndCount()); - irManager->getLiveAtExit(node, *lsCurrent); - lsAll->copyFrom(*lsCurrent); - LiveSet * ls=new (mm) LiveSet(mm, irManager->getOpndCount()); - ls->copyFrom(*lsCurrent); - liveSets.push_back(ls); - - uint32 regUsage=0, regUsageAll=0; - irManager->getRegUsageAtExit(node, OpndKind_GPReg, regUsage); - regUsageAll|=regUsage; - regUsages.push_back(regUsage); - - const Insts& insts=bb->getInsts(); - for (Inst * inst = insts.getLast(); inst != NULL; inst = insts.getPrev(inst)) { - irManager->updateLiveness(inst, *lsCurrent); - lsAll->unionWith(*lsCurrent); - ls=new (mm) LiveSet(mm, irManager->getOpndCount()); - ls->copyFrom(*lsCurrent); - liveSets.push_back(ls); - - irManager->updateRegUsage(inst, OpndKind_GPReg, regUsage); - regUsageAll|=regUsage; - regUsages.push_back(regUsage); - } - - assert(irManager->getLiveAtEntry(node)->isEqual(*lsCurrent)); - - StlVector<Opnd *> opndsAll(mm); - - for (uint32 i=0, n=irManager->getOpndCount(); i<n; i++){ - Opnd * opnd=irManager->getOpnd(i); - if (lsAll->isLive(opnd)) - opndsAll.push_back(opnd); - } - char * regStrings[IRMaxRegKinds]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* VSH: TODO - reg kinds are masks now, not indexes ! + } + printNodeName(lt->getLoopHeader(node)); + } + + if (bb!=NULL && irManager->getCodeStartAddr()!=NULL){ + out<<", code="<<(void*)bb->getCodeStartAddr(); + } + + if (bb!=NULL){ + if (irManager->hasLivenessInfo()){ + + StlVector<BitSet *> liveSets(mm); + StlVector<uint32> regUsages(mm); + BitSet * lsAll=new (mm) BitSet(mm, irManager->getOpndCount()); + + BitSet * lsCurrent=new (mm) BitSet(mm, irManager->getOpndCount()); + irManager->getLiveAtExit(node, *lsCurrent); + lsAll->copyFrom(*lsCurrent); + BitSet * ls=new (mm) BitSet(mm, irManager->getOpndCount()); + ls->copyFrom(*lsCurrent); + liveSets.push_back(ls); + + uint32 regUsage=0, regUsageAll=0; + irManager->getRegUsageAtExit(node, OpndKind_GPReg, regUsage); + regUsageAll|=regUsage; + regUsages.push_back(regUsage); + + for (Inst * inst = (Inst*)bb->getLastInst(); inst != NULL; inst = inst->getPrevInst()) { + irManager->updateLiveness(inst, *lsCurrent); + lsAll->unionWith(*lsCurrent); + ls=new (mm) BitSet(mm, irManager->getOpndCount()); + ls->copyFrom(*lsCurrent); + liveSets.push_back(ls); + + irManager->updateRegUsage(inst, OpndKind_GPReg, regUsage); + regUsageAll|=regUsage; + regUsages.push_back(regUsage); + } + + assert(irManager->getLiveAtEntry(node)->isEqual(*lsCurrent)); + + StlVector<Opnd *> opndsAll(mm); + + for (uint32 i=0, n=irManager->getOpndCount(); i<n; i++){ + Opnd * opnd=irManager->getOpnd(i); + if (lsAll->getBit(opnd->getId())) { + opndsAll.push_back(opnd); + } + } + char * regStrings[IRMaxRegKinds]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* VSH: TODO - reg kinds are masks now, not indexes ! */ - out << "\\l|{\\" << ::std::endl; - - out<<"Operand Ids:\\l\\"<<::std::endl; - - uint32 regKindCount=0; - for (uint32 i=0; i<IRMaxRegKinds; i++){ - if (regStrings[i]!=NULL){ - regKindCount++; - out<<getOpndKindString((OpndKind)i) << "\\l\\" << ::std::endl; - } - } - - for (Inst * inst = insts.getFirst(); inst != NULL; inst = insts.getNext(inst)) { - printInst(inst); out<<"\\l\\"<<::std::endl; - } - - out << "|\\" << ::std::endl; - for (uint32 i=0, n=opndsAll.size(); i<n; i++){ - out<<opndsAll[i]->getFirstId()<<'_'; - } - out << "\\l\\" << ::std::endl; - - for (uint32 i=0; i<IRMaxRegKinds; i++){ - if (regStrings[i]!=NULL) - out << regStrings[i] << "\\l\\" << ::std::endl; - } - - uint32 idx=liveSets.size()-1; - - for (Inst * inst = insts.getFirst(); inst != NULL; inst = insts.getNext(inst), idx--) { - printLivenessForInst(opndsAll, liveSets[idx], liveSets[idx-1]); // output at entry - out << "\\l\\" << ::std::endl; - } - - if (regUsageAll!=0){ - out << "|\\" << ::std::endl; - - out << "01234567" << "\\l\\" << ::std::endl; - for (uint32 i=1; i<regKindCount; i++) - out << "\\l\\" << ::std::endl; - - for (int32 i=(int32)regUsages.size()-1; i>=0; i--) { - uint32 regUsage=regUsages[i]; - for (uint32 m=1; m!=0x100; m<<=1) - out << (m®Usage?'.':'_'); - out << "\\l\\" << ::std::endl; - } - } - - out << "}\\" << ::std::endl; - - }else{ - out<<"liveness info is outdated"; - } - } - if (bb!=NULL) out << "}"; - out << "\""; - if (node->hasKind(Node::Kind_DispatchNode)) - out << ",shape=diamond,color=blue"; - else if (node->hasKind(Node::Kind_UnwindNode)) - out << ",shape=diamond,color=red"; - else if (node->hasKind(Node::Kind_ExitNode)) + out << "\\l|{\\" << ::std::endl; + + out<<"Operand Ids:\\l\\"<<::std::endl; + + uint32 regKindCount=0; + for (uint32 i=0; i<IRMaxRegKinds; i++){ + if (regStrings[i]!=NULL){ + regKindCount++; + out<<getOpndKindString((OpndKind)i) << "\\l\\" << ::std::endl; + } + } + + for (Inst * inst = (Inst*)bb->getFirstInst(); inst != NULL; inst = inst->getNextInst()) { + printInst(inst); out<<"\\l\\"<<std::endl; + } + + out << "|\\" << std::endl; + for (uint32 i=0, n=opndsAll.size(); i<n; i++){ + out<<opndsAll[i]->getFirstId()<<'_'; + } + out << "\\l\\" << std::endl; + + for (uint32 i=0; i<IRMaxRegKinds; i++){ + if (regStrings[i]!=NULL) + out << regStrings[i] << "\\l\\" << ::std::endl; + } + + uint32 idx=liveSets.size()-1; + + for (Inst * inst = (Inst*)bb->getFirstInst(); inst != NULL; inst = inst->getNextInst(), idx--) { + printLivenessForInst(opndsAll, liveSets[idx], liveSets[idx-1]); // output at entry + out << "\\l\\" << ::std::endl; + } + + if (regUsageAll!=0){ + out << "|\\" << ::std::endl; + + out << "01234567" << "\\l\\" << std::endl; + for (uint32 i=1; i<regKindCount; i++) + out << "\\l\\" << std::endl; + + for (int32 i=(int32)regUsages.size()-1; i>=0; i--) { + uint32 regUsage=regUsages[i]; + for (uint32 m=1; m!=0x100; m<<=1) + out << (m®Usage?'.':'_'); + out << "\\l\\" << std::endl; + } + } + + out << "}\\" << ::std::endl; + + }else{ + out<<"liveness info is outdated"; + } + } + if (bb!=NULL) out << "}"; + out << "\""; + if (node->isDispatchNode()) { + if (node!=irManager->getFlowGraph()->getUnwindNode()) { + out << ",shape=diamond,color=blue"; + } else { + out << ",shape=diamond,color=red"; + } + } else if (node->isExitNode()) { out << ",shape=ellipse,color=green"; + } out << "]" << ::std::endl; } //_________________________________________________________________________________________________ -void IRLivenessDotPrinter::printLivenessForInst(const StlVector<Opnd*> opnds, const LiveSet * ls0, const LiveSet * ls1) +void IRLivenessDotPrinter::printLivenessForInst(const StlVector<Opnd*> opnds, const BitSet * ls0, const BitSet * ls1) { - ::std::ostream& out=getStream(); - for (uint32 i=0, n=opnds.size(); i<n; i++){ - Opnd * opnd=opnds[i]; - bool isLiveBefore=ls0!=NULL && ls0->isLive(opnd); - bool isLiveAfter=ls1!=NULL && ls1->isLive(opnd); - if (isLiveAfter && isLiveBefore) - out<<'I'; - else if (isLiveAfter) - out<<'.'; - else if (isLiveBefore) - out<<'\''; - else - out<<'_'; - for (uint32 j=0, l=getOpndNameLength(opnd)-1; j<l; j++) - out<<'_'; - } + ::std::ostream& out=getStream(); + for (uint32 i=0, n=opnds.size(); i<n; i++){ + Opnd * opnd=opnds[i]; + bool isLiveBefore=ls0!=NULL && ls0->getBit(opnd->getId()); + bool isLiveAfter=ls1!=NULL && ls1->getBit(opnd->getId()); + if (isLiveAfter && isLiveBefore) + out<<'I'; + else if (isLiveAfter) + out<<'.'; + else if (isLiveBefore) + out<<'\''; + else + out<<'_'; + for (uint32 j=0, l=getOpndNameLength(opnd)-1; j<l; j++) + out<<'_'; + } } //_________________________________________________________________________________________________ void dumpIR( - const IRManager * irManager, - uint32 stageId, - const char * readablePrefix, - const char * readableStageName, - const char * stageTagName, - const char * subKind1, - const char * subKind2, - uint32 instFilter, - uint32 opndFlavor, - uint32 opndRolesFilter - ) + const IRManager * irManager, + uint32 stageId, + const char * readablePrefix, + const char * readableStageName, + const char * stageTagName, + const char * subKind1, + const char * subKind2, + uint32 instFilter, + uint32 opndFlavor, + uint32 opndRolesFilter + ) { - Log::out() << "-------------------------------------------------------------" << ::std::endl; - - char title[128]; - strcpy(title, readablePrefix); - strcat(title, readableStageName); - - char subKind[128]; - assert(subKind1!=NULL); - strcpy(subKind, subKind1); - if (subKind2!=NULL && subKind2[0]!=0){ - strcat(subKind, "."); - strcat(subKind, subKind2); - } - - Log::printIRDumpBegin(stageId, readableStageName, subKind); - if (subKind2!=0){ - if (stricmp(subKind2, "opnds")==0){ - IROpndPrinter(irManager, title) - .setInstFilter(instFilter) - .setStream(Log::out()).print(); - }else if (stricmp(subKind2, "inst_constraints")==0){ - IRInstConstraintPrinter(irManager, title) - .setInstFilter(instFilter) - .setStream(Log::out()).print(); - }else if (stricmp(subKind2, "liveness")==0){ - IRLivenessPrinter(irManager, title) - .setInstFilter(instFilter) - .setStream(Log::out()).print(); - } - }else{ - IRPrinter(irManager, title) - .setInstFilter(instFilter) - .setStream(Log::out()).print(); - } - Log::printIRDumpEnd(stageId, readableStageName, subKind); + std::ostream& out = Log::log(LogStream::IRDUMP).out(); + out << "-------------------------------------------------------------" << ::std::endl; + + char title[128]; + strcpy(title, readablePrefix); + strcat(title, readableStageName); + + char subKind[128]; + assert(subKind1!=NULL); + strcpy(subKind, subKind1); + if (subKind2!=NULL && subKind2[0]!=0){ + strcat(subKind, "."); + strcat(subKind, subKind2); + } + + Log::printIRDumpBegin(out, stageId, readableStageName, subKind); + if (subKind2!=0){ + if (stricmp(subKind2, "opnds")==0){ + IROpndPrinter(irManager, title) + .setInstFilter(instFilter) + .setStream(out).print(); + }else if (stricmp(subKind2, "inst_constraints")==0){ + IRInstConstraintPrinter(irManager, title) + .setInstFilter(instFilter) + .setStream(out).print(); + }else if (stricmp(subKind2, "liveness")==0){ + IRLivenessPrinter(irManager, title) + .setInstFilter(instFilter) + .setStream(out).print(); + } + }else{ + IRPrinter(irManager, title) + .setInstFilter(instFilter) + .setStream(out).print(); + } + Log::printIRDumpEnd(out, stageId, readableStageName, subKind); } //_________________________________________________________________________________________________ void printDot( - const IRManager * irManager, - uint32 stageId, - const char * readablePrefix, - const char * readableStageName, - const char * stageTagName, - const char * subKind1, - const char * subKind2, - uint32 instFilter, - uint32 opndFlavor, - uint32 opndRolesFilter - ) + const IRManager * irManager, + uint32 stageId, + const char * readablePrefix, + const char * readableStageName, + const char * stageTagName, + const char * subKind1, + const char * subKind2, + uint32 instFilter, + uint32 opndFlavor, + uint32 opndRolesFilter + ) { - char title[128]; - strcpy(title, readablePrefix); - strcat(title, readableStageName); - - char subKind[256]; - assert(subKind1!=NULL); - sprintf(subKind, "%s.%d.%s", stageTagName, (int)stageId, subKind1); - if (subKind2!=NULL && subKind2[0]!=0){ - strcat(subKind, "."); - strcat(subKind, subKind2); - } - - if (subKind2!=0){ - if (stricmp(subKind2, "liveness")==0){ - IRLivenessDotPrinter(irManager, title) - .setInstFilter(instFilter) - .createDotFileName(Log::getDotFileDirName(), subKind).print(); - } - }else{ - IRDotPrinter(irManager, title) - .setInstFilter(instFilter) - .createDotFileName(Log::getDotFileDirName(), subKind).print(); - } + char title[128]; + strcpy(title, readablePrefix); + strcat(title, readableStageName); + + char subKind[256]; + assert(subKind1!=NULL); + sprintf(subKind, "%.2d.%s.%s", (int)stageId, stageTagName, subKind1); + if (subKind2!=NULL && subKind2[0]!=0){ + strcat(subKind, "."); + strcat(subKind, subKind2); + } + + char* dotfilename = 0; + + if (subKind2!=0){ + if (stricmp(subKind2, "liveness")==0){ + dotfilename = Log::makeDotFileName(subKind); + IRLivenessDotPrinter(irManager, title) + .setInstFilter(instFilter) + .open(dotfilename) + .print(); + } + }else{ + dotfilename = Log::makeDotFileName(subKind); + IRDotPrinter(irManager, title) + .setInstFilter(instFilter) + .open(dotfilename) + .print(); + } + + if (dotfilename != 0) + delete [] dotfilename; } //_________________________________________________________________________________________________ void printRuntimeArgs(::std::ostream& os, uint32 opndCount, CallingConvention::OpndInfo * infos, JitFrameContext * context) { - MemoryManager mm(0x1000, "printRuntimeOpndInternalHelper"); - DrlVMTypeManager tm(mm); tm.init(); - os<<opndCount<<" args: "; - for (uint32 i=0; i<opndCount; i++){ - CallingConvention::OpndInfo & info=infos[i]; - uint32 cb=0; - uint8 arg[4*sizeof(uint32)]; - for (uint32 j=0; j<info.slotCount; j++){ - if (getRegKind(info.slots[j])==OpndKind_Mem){ - *(uint32*)(arg+cb)=((uint32*)context->esp)[getRegIndex(info.slots[j])]; - cb+=sizeof(uint32); - }else{ - assert((getRegKind(info.slots[j])&OpndKind_Reg)!=0); - assert(0); - } - } - if (i>0) - os<<", "; - printRuntimeOpnd(os, tm, (Type::Tag)info.typeTag, (const void*)arg); - } + MemoryManager mm(0x1000, "printRuntimeOpndInternalHelper"); + DrlVMTypeManager tm(mm); tm.init(); + os<<opndCount<<" args: "; + for (uint32 i=0; i<opndCount; i++){ + CallingConvention::OpndInfo & info=infos[i]; + uint32 cb=0; + uint8 arg[4*sizeof(uint32)]; + for (uint32 j=0; j<info.slotCount; j++){ + if (!info.isReg){ +#ifdef _EM64T_ + *(POINTER_SIZE_INT*)(arg+cb)=((POINTER_SIZE_INT*)context->rsp)[info.slots[j]]; +#else + *(uint32*)(arg+cb)=((uint32*)context->esp)[info.slots[j]]; +#endif + cb+=sizeof(uint32); + }else{ + assert(info.isReg); + //assert(0); + } + } + if (i>0) + os<<", "; + printRuntimeOpnd(os, tm, (Type::Tag)info.typeTag, (const void*)arg); + } } //_________________________________________________________________________________________________ void printRuntimeOpnd(::std::ostream& os, TypeManager & tm, Type::Tag typeTag, const void * p) { - if (Type::isObject(typeTag)){ - printRuntimeObjectOpnd(os, tm, *(const void**)p); - }else{ - tm.getPrimitiveType(typeTag)->print(os); - os<<" "; - switch (typeTag){ - case Type::Int8: - os<<*(int8*)p; - break; - case Type::UInt8: - os<<*(uint8*)p; - break; - case Type::Boolean: - os<<(*(int8*)p?true:false); - break; - case Type::Int16: - os<<*(int16*)p; - break; - case Type::UInt16: - os<<*(uint16*)p; - break; - case Type::Char: - os<<*(uint16*)p<<*(char*)p; - break; - case Type::Int32: - os<<*(int32*)p; - break; - case Type::UInt32: - os<<*(uint32*)p; - break; - case Type::Int64: - os<<*(int64*)p; - break; - case Type::UInt64: - os<<*(uint64*)p; - break; - case Type::Double: - case Type::Float: - os<<*(double*)p; - break; - case Type::Single: - os<<*(float*)p; - break; - default: - assert(0); - break; - } - } + if (Type::isObject(typeTag)){ + printRuntimeObjectOpnd(os, tm, *(const void**)p); + }else{ + tm.getPrimitiveType(typeTag)->print(os); + os<<" "; + switch (typeTag){ + case Type::Int8: + os<<*(int8*)p; + break; + case Type::UInt8: + os<<*(uint8*)p; + break; + case Type::Boolean: + os<<(*(int8*)p?true:false); + break; + case Type::Int16: + os<<*(int16*)p; + break; + case Type::UInt16: + os<<*(uint16*)p; + break; + case Type::Char: + os<<*(uint16*)p<<*(char*)p; + break; + case Type::Int32: + os<<*(int32*)p; + break; + case Type::UInt32: + os<<*(uint32*)p; + break; + case Type::Int64: + os<<*(int64*)p; + break; + case Type::UInt64: + os<<*(uint64*)p; + break; + case Type::Double: + case Type::Float: + os<<*(double*)p; + break; + case Type::Single: + os<<*(float*)p; + break; + default: + assert(0); + break; + } + } } //_________________________________________________________________________________________________ void printRuntimeObjectOpnd(::std::ostream& os, TypeManager & tm, const void * p) { -// check for valid range for object pointer - if (p==NULL){ - os<<"Ref Null"; - return; - } - os<<"Ref "<<p; - if (p<(const void*)0x10000||p>(const void*)0x20000000){ - os<<"(INVALID PTR)"; - return; - } +// check for valid range for object pointer + if (p==NULL){ + os<<"Ref Null"; + return; + } + os<<"Ref "<<p; + if (p<(const void*)0x10000||p>(const void*)0x20000000){ + os<<"(INVALID PTR)"; + return; + } // check for valid alignment - if ((((uint32)p)&0x3)!=0){ - os<<"(INVALID PTR)"; - return; - } - uint32 vtableOffset=tm.getVTableOffset(); - - // assume that vtable pointer in object head is allocation handle - void * allocationHandle=*(void**)(((uint8*)p)+vtableOffset); - - if (allocationHandle<(void*)0x10000||allocationHandle>(void*)0x20000000||(((uint32)allocationHandle)&0x3)!=0){ - os<<"(INVALID VTABLE PTR: "<<allocationHandle<<")"; - return; - } - - ObjectType * type=tm.getObjectTypeFromAllocationHandle(allocationHandle); - if (type==NULL){ - os<<"(UNRECOGNIZED VTABLE PTR: "<<allocationHandle<<")"; - return; - } - os<<"("; - printRuntimeObjectContent(os, tm, type, p); - os<<":"<<type->getName(); - os<<")"; + if ((((POINTER_SIZE_INT)p)&0x3)!=0){ + os<<"(INVALID PTR)"; + return; + } + POINTER_SIZE_INT vtableOffset=tm.getVTableOffset(); + + // assume that vtable pointer in object head is allocation handle + void * allocationHandle=*(void**)(((uint8*)p)+vtableOffset); + + if (allocationHandle<(void*)0x10000||allocationHandle>(void*)0x20000000||(((POINTER_SIZE_INT)allocationHandle)&0x3)!=0){ + os<<"(INVALID VTABLE PTR: "<<allocationHandle<<")"; + return; + } + + ObjectType * type=tm.getObjectTypeFromAllocationHandle(allocationHandle); + if (type==NULL){ + os<<"(UNRECOGNIZED VTABLE PTR: "<<allocationHandle<<")"; + return; + } + os<<"("; + printRuntimeObjectContent(os, tm, type, p); + os<<":"<<type->getName(); + os<<")"; } //_________________________________________________________________________________________________ void printRuntimeObjectContent_Array(::std::ostream& os, TypeManager & tm, Type * type, const void * p) { - ArrayType * arrayType=(ArrayType *)type; - uint32 lengthOffset=arrayType->getArrayLengthOffset(); - uint32 length=*(uint32*)(((uint8*)p)+lengthOffset); - os<<"{"<<length<<" elems: "; - if (length>0){ - uint32 elemOffset=arrayType->getArrayElemOffset(); - printRuntimeOpnd(os, tm, arrayType->getElementType()->tag, (const void*)(((uint8*)p)+elemOffset)); - if (length>1) - os<<", ..."; - } - os<<"}"; + ArrayType * arrayType=(ArrayType *)type; + uint32 lengthOffset=arrayType->getArrayLengthOffset(); + uint32 length=*(uint32*)(((uint8*)p)+lengthOffset); + os<<"{"<<length<<" elems: "; + if (length>0){ + uint32 elemOffset=arrayType->getArrayElemOffset(); + printRuntimeOpnd(os, tm, arrayType->getElementType()->tag, (const void*)(((uint8*)p)+elemOffset)); + if (length>1) + os<<", ..."; + } + os<<"}"; } //_________________________________________________________________________________________________ void printRuntimeObjectContent_String(::std::ostream& os, TypeManager & tm, Type * type, const void * p) { #ifndef KNOWN_STRING_FORMAT - os<<"\"...\""; - return; + os<<"\"...\""; + return; #else - uint32 stringLengthOffset=8; - uint32 stringOffsetOffset=12; - uint32 stringBufferOffset=16; - uint32 bufferLengthOffset=8; - uint32 bufferElemsOffset=12; - - uint8 * string=(uint8*)p; - - uint32 stringLength=*(uint32*)(string+stringLengthOffset); - uint32 stringOffset=*(uint32*)(string+stringOffsetOffset); - uint8 * buffer=*(uint8**)(string+stringBufferOffset); - - if (buffer==NULL){ - if (stringLength==0) - os<<"\"\""; - else - os<<"INVALID STRING"; - return; - } - - uint32 bufferLength=*(uint32*)(buffer+bufferLengthOffset); - - uint16 * bufferElems=(uint16*)(buffer+bufferElemsOffset); - - if (stringOffset>bufferLength || stringLength>bufferLength || stringLength>bufferLength-stringOffset){ - os<<"INVALID STRING"; - return; - } - - os<<"\""; - for (uint32 i=stringOffset, n=stringOffset+stringLength; i<n; i++) - os<<(char)bufferElems[i]; - os<<"\""; + uint32 stringLengthOffset=8; + uint32 stringOffsetOffset=12; + uint32 stringBufferOffset=16; + uint32 bufferLengthOffset=8; + uint32 bufferElemsOffset=12; + + uint8 * string=(uint8*)p; + + uint32 stringLength=*(uint32*)(string+stringLengthOffset); + uint32 stringOffset=*(uint32*)(string+stringOffsetOffset); + uint8 * buffer=*(uint8**)(string+stringBufferOffset); + + if (buffer==NULL){ + if (stringLength==0) + os<<"\"\""; + else + os<<"INVALID STRING"; + return; + } + + uint32 bufferLength=*(uint32*)(buffer+bufferLengthOffset); + + uint16 * bufferElems=(uint16*)(buffer+bufferElemsOffset); + + if (stringOffset>bufferLength || stringLength>bufferLength || stringLength>bufferLength-stringOffset){ + os<<"INVALID STRING"; + return; + } + + os<<"\""; + for (uint32 i=stringOffset, n=stringOffset+stringLength; i<n; i++) + os<<(char)bufferElems[i]; + os<<"\""; #endif } //_________________________________________________________________________________________________ void printRuntimeObjectContent(::std::ostream& os, TypeManager & tm, Type * type, const void * p) { - if (type->isArray()){ - os<<" "; - printRuntimeObjectContent_Array(os, tm, type, p); - }else if (type->isSystemString()){ - os<<" "; - printRuntimeObjectContent_String(os, tm, type, p); - } + if (type->isArray()){ + os<<" "; + printRuntimeObjectContent_Array(os, tm, type, p); + }else if (type->isSystemString()){ + os<<" "; + printRuntimeObjectContent_String(os, tm, type, p); + } } //_________________________________________________________________________________________________ void __stdcall printRuntimeOpndInternalHelper(const void * p) { - MemoryManager mm(0x1000, "printRuntimeOpndInternalHelper"); - DrlVMTypeManager tm(mm); tm.init(); - printRuntimeObjectOpnd(::std::cout, tm, p); + MemoryManager mm(0x1000, "printRuntimeOpndInternalHelper"); + DrlVMTypeManager tm(mm); tm.init(); + printRuntimeObjectOpnd(::std::cout, tm, p); } diff --git vm/jitrino/src/codegenerator/ia32/Ia32Printer.h vm/jitrino/src/codegenerator/ia32/Ia32Printer.h index a442454..0efacde 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32Printer.h +++ vm/jitrino/src/codegenerator/ia32/Ia32Printer.h @@ -28,6 +28,7 @@ #include "Type.h" #include "CodeGenIntfc.h" #include "Ia32IRManager.h" #include "PrintDotFile.h" +#include "LogStream.h" #include <fstream> namespace Jitrino @@ -46,54 +47,46 @@ Each printXXX method receives the indent class Printer { public: - /** creates Printer instance for the specified IRManager - Allows to provide an optinal title - */ - Printer(const IRManager * irm=0, const char * _title=0) - :irManager(irm), title(_title), os(0){} + /** creates Printer instance for the specified IRManager + Allows to provide an optinal title + */ + Printer(const IRManager * irm=0, const char * _title=0) + :irManager(irm), title(_title), os(0){} - /** destructs Printer instance */ - virtual ~Printer() {} + /** destructs Printer instance */ + virtual ~Printer() {} - /** Sets os as the current output destination */ - Printer& setStream(::std::ostream& os); - /** Sets fileName as the current output destination */ - Printer& setDotFileName(const char * fileName); + /** Sets os as the current output destination */ + Printer& setStream(::std::ostream& os); - /** Sets dir fileSuffix for the file used as the current output destination + Printer& open(char* fname); + void close(); - This results to the file name composed according to the following pattern: - <dir>\\<class name>.<method name>.<method signature>.<fileSuffix> - where class,method,signature are retrieved from the IRManater - - */ - Printer& createDotFileName(const char * dir, const char * fileSuffix); - - /** print everything supposed to be printed to the current output */ - virtual void print(uint32 indent=0); + /** print everything supposed to be printed to the current output */ + virtual void print(uint32 indent=0); - virtual void printHeader(uint32 indent=0); + virtual void printHeader(uint32 indent=0); virtual void printEnd(uint32 indent=0); virtual void printBody(uint32 indent=0); - /** Prints indent tabs */ - virtual void printIndent(uint32 indent) - { while (indent--) getStream()<<'\t'; } - static void printIndent(::std::ostream& os, uint32 indent) - { Printer p; p.setStream(os); p.printIndent(indent); } + /** Prints indent tabs */ + virtual void printIndent(uint32 indent) + { while (indent--) getStream()<<'\t'; } + static void printIndent(::std::ostream& os, uint32 indent) + { Printer p; p.setStream(os); p.printIndent(indent); } - /** returns the current output desitnation */ - ::std::ostream& getStream(){ assert(os); return *os; } + /** returns the current output desitnation */ + ::std::ostream& getStream(){ assert(os); return *os; } - /** returns the title set in the constuctor */ - const char * getTitle(){ return title; } - /** returns a pointer to the IRManager associated with this printer */ - const IRManager * getIRManager(){ return irManager; } + /** returns the title set in the constuctor */ + const char * getTitle(){ return title; } + /** returns a pointer to the IRManager associated with this printer */ + const IRManager * getIRManager(){ return irManager; } protected: - const IRManager * irManager; - const char * title; - ::std::fstream fs; - ::std::ostream * os; + const IRManager * irManager; + const char * title; + LogStream logs; + ::std::ostream * os; }; @@ -107,24 +100,34 @@ LIR parts: Constraints, RegNames, opnd r class OpcodeDescriptionPrinter: public Printer { public: - OpcodeDescriptionPrinter(const IRManager * irm=0, const char * _title=0) - :Printer(irm, _title){} + OpcodeDescriptionPrinter(const IRManager * irm=0, const char * _title=0) + :Printer(irm, _title){} - virtual void printConstraint(Constraint constraint); - static void printConstraint(::std::ostream& os, Constraint constraint) - { OpcodeDescriptionPrinter p; p.setStream(os); p.printConstraint(constraint); } + virtual void printConstraint(Constraint constraint); + static void printConstraint(::std::ostream& os, Constraint constraint) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printConstraint(constraint); } virtual void printRegName(const RegName regName); - static void printRegName(::std::ostream& os, const RegName regName) - { OpcodeDescriptionPrinter p; p.setStream(os); p.printRegName(regName); } + static void printRegName(::std::ostream& os, const RegName regName) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printRegName(regName); } + + virtual void printOpndRoles(uint32 roles); + static void printOpndRoles(::std::ostream& os, uint32 roles) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpndRoles(roles); } + + virtual void printOpndRolesDescription(const Encoder::OpndRolesDescription * ord); + static void printOpndRolesDescription(::std::ostream& os, Encoder::OpndRolesDescription * ord) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpndRolesDescription(ord); } + + virtual void printOpcodeDescription(const Encoder::OpcodeDescription * od, uint32 indent=0); + static void printOpcodeDescription(::std::ostream& os, Encoder::OpcodeDescription * od, uint32 indent=0) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpcodeDescription(od, indent); } - virtual void printOpndRoles(uint32 roles); - static void printOpndRoles(::std::ostream& os, uint32 roles) - { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpndRoles(roles); } + virtual void printOpcodeGroup(const Encoder::OpcodeGroup* og, uint32 indent=0); + static void printOpcodeGroup(::std::ostream& os, Encoder::OpcodeGroup* og, uint32 indent=0) + { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpcodeGroup(og, indent); } - virtual void printOpndRolesDescription(const Encoder::OpndRolesDescription * ord); - static void printOpndRolesDescription(::std::ostream& os, Encoder::OpndRolesDescription * ord) - { OpcodeDescriptionPrinter p; p.setStream(os); p.printOpndRolesDescription(ord); } + virtual void print(uint32 indent=0); }; //======================================================================================== @@ -137,82 +140,82 @@ It also introduces methods to print LIR class IRPrinter: public OpcodeDescriptionPrinter { public: - enum OpndFlavor{ - OpndFlavor_Type=0x1, - OpndFlavor_Location=0x2, - OpndFlavor_RuntimeInfo=0x4, - OpndFlavor_All=0xffffffff, - OpndFlavor_Default=OpndFlavor_Type|OpndFlavor_Location - }; + enum OpndFlavor{ + OpndFlavor_Type=0x1, + OpndFlavor_Location=0x2, + OpndFlavor_RuntimeInfo=0x4, + OpndFlavor_All=0xffffffff, + OpndFlavor_Default=OpndFlavor_Type|OpndFlavor_Location + }; - IRPrinter(const IRManager * irm=0, const char * _title=0) - :OpcodeDescriptionPrinter(irm, _title), instFilter((uint32)Inst::Kind_Inst), - opndFlavor((uint32)OpndFlavor_All), opndRolesFilter((uint32)(Inst::OpndRole_InstLevel|Inst::OpndRole_Use|Inst::OpndRole_Def)) - {} + IRPrinter(const IRManager * irm=0, const char * _title=0) + :OpcodeDescriptionPrinter(irm, _title), instFilter((uint32)Inst::Kind_Inst), + opndFlavor((uint32)OpndFlavor_All), opndRolesFilter((uint32)(Inst::OpndRole_InstLevel|Inst::OpndRole_Use|Inst::OpndRole_Def)) + {} - IRPrinter & setInstFilter(uint32 kinds){ instFilter=kinds; return *this; } - IRPrinter & setOpndFlavor(uint32 f){ opndFlavor=f; return *this; } - IRPrinter & setOpndRolesFilter(uint32 orf){ opndRolesFilter=orf; return *this; } + IRPrinter & setInstFilter(uint32 kinds){ instFilter=kinds; return *this; } + IRPrinter & setOpndFlavor(uint32 f){ opndFlavor=f; return *this; } + IRPrinter & setOpndRolesFilter(uint32 orf){ opndRolesFilter=orf; return *this; } - virtual void printNodeName(const Node * node); - static void printNodeName(::std::ostream& os, const Node * node) - { IRPrinter p; p.setStream(os); p.printNodeName(node); } + virtual void printNodeName(const Node * node); + static void printNodeName(::std::ostream& os, const Node * node) + { IRPrinter p; p.setStream(os); p.printNodeName(node); } - virtual void printNodeHeader(const Node * node, uint32 indent=0); - virtual void printNodeInstList(const BasicBlock * bb, uint32 indent=0); + virtual void printNodeHeader(const Node * node, uint32 indent=0); + virtual void printNodeInstList(const BasicBlock * bb, uint32 indent=0); - virtual void printNode(const Node * node, uint32 indent=0); - static void printNode(::std::ostream& os, const Node * node, uint32 indent=0) - { IRPrinter p; p.setStream(os); p.printNode(node, indent); } + virtual void printNode(const Node * node, uint32 indent=0); + static void printNode(::std::ostream& os, const Node * node, uint32 indent=0) + { IRPrinter p; p.setStream(os); p.printNode(node, indent); } - virtual void printEdge(const Edge * edge); - static void printEdge(::std::ostream& os, const Edge * edge) - { IRPrinter p; p.setStream(os); p.printEdge(edge); } + virtual void printEdge(const Edge * edge); + static void printEdge(::std::ostream& os, const Edge * edge) + { IRPrinter p; p.setStream(os); p.printEdge(edge); } - virtual void printInst(const Inst * inst); - static void printInst(::std::ostream& os, const Inst * inst, - uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Use|Inst::OpndRole_Def, - uint32 opndFlavor=OpndFlavor_Default - ) - { IRPrinter p; p.setStream(os); p.setOpndRolesFilter(opndRolesFilter); p.setOpndFlavor(opndFlavor); p.printInst(inst); } + virtual void printInst(const Inst * inst); + static void printInst(::std::ostream& os, const Inst * inst, + uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Use|Inst::OpndRole_Def, + uint32 opndFlavor=OpndFlavor_Default + ) + { IRPrinter p; p.setStream(os); p.setOpndRolesFilter(opndRolesFilter); p.setOpndFlavor(opndFlavor); p.printInst(inst); } - virtual uint32 printInstOpnds(const Inst * inst, uint32 opndRolesFilter); + virtual uint32 printInstOpnds(const Inst * inst, uint32 opndRolesFilter); - virtual void printOpndRoles(uint32 roles); - static void printOpndRoles(::std::ostream& os, uint32 roles) - { IRPrinter p; p.setStream(os); p.printOpndRoles(roles); } + virtual void printOpndRoles(uint32 roles); + static void printOpndRoles(::std::ostream& os, uint32 roles) + { IRPrinter p; p.setStream(os); p.printOpndRoles(roles); } - void printOpndName(const Opnd * opnd); - static void printOpndName(::std::ostream& os, const Opnd * opnd) - { IRPrinter p; p.setStream(os); p.printOpndName(opnd); } + void printOpndName(const Opnd * opnd); + static void printOpndName(::std::ostream& os, const Opnd * opnd) + { IRPrinter p; p.setStream(os); p.printOpndName(opnd); } - virtual uint32 getOpndNameLength(Opnd * opnd); + virtual uint32 getOpndNameLength(Opnd * opnd); - virtual void printOpnd(const Inst * inst, uint32 idx, bool isLiveBefore=false, bool isLiveAfter=false); + virtual void printOpnd(const Inst * inst, uint32 idx, bool isLiveBefore=false, bool isLiveAfter=false); - virtual void printOpnd(const Opnd * opnd, uint32 roles=0, bool isLiveBefore=false, bool isLiveAfter=false); - static void printOpnd(::std::ostream& os, const Opnd * opnd, uint32 of=OpndFlavor_Default) - { IRPrinter p; p.setStream(os); p.setOpndFlavor(of); p.printOpnd(opnd); } + virtual void printOpnd(const Opnd * opnd, uint32 roles=0, bool isLiveBefore=false, bool isLiveAfter=false); + static void printOpnd(::std::ostream& os, const Opnd * opnd, uint32 of=OpndFlavor_Default) + { IRPrinter p; p.setStream(os); p.setOpndFlavor(of); p.printOpnd(opnd); } - virtual void printRuntimeInfo(const Opnd::RuntimeInfo * ri); - static void printRuntimeInfo(::std::ostream& os, const Opnd::RuntimeInfo * ri) - { IRPrinter p; p.setStream(os); p.printRuntimeInfo(ri); } + virtual void printRuntimeInfo(const Opnd::RuntimeInfo * ri); + static void printRuntimeInfo(::std::ostream& os, const Opnd::RuntimeInfo * ri) + { IRPrinter p; p.setStream(os); p.printRuntimeInfo(ri); } - virtual void printType(const Type * type); - static void printType(::std::ostream& os, const Type * type) - { IRPrinter p; p.setStream(os); p.printType(type); } + virtual void printType(const Type * type); + static void printType(::std::ostream& os, const Type * type) + { IRPrinter p; p.setStream(os); p.printType(type); } - virtual void printCFG(uint32 indent=0); + virtual void printCFG(uint32 indent=0); - virtual void printBody(uint32 indent=0); - virtual void print(uint32 indent=0); + virtual void printBody(uint32 indent=0); + virtual void print(uint32 indent=0); - static const char * getPseudoInstPrintName(Inst::Kind k); + static const char * getPseudoInstPrintName(Inst::Kind k); protected: - uint32 instFilter; - uint32 opndFlavor; - uint32 opndRolesFilter; + uint32 instFilter; + uint32 opndFlavor; + uint32 opndRolesFilter; }; inline ::std::ostream& operator << (::std::ostream& os, Opnd * opnd){ IRPrinter::printOpnd(os, opnd); return os; } @@ -223,11 +226,11 @@ inline ::std::ostream& operator << (::st class IROpndPrinter: public IRPrinter { public: - IROpndPrinter(const IRManager * irm=0, const char * _title=0) - :IRPrinter(irm, _title){} + IROpndPrinter(const IRManager * irm=0, const char * _title=0) + :IRPrinter(irm, _title){} - void printBody(uint32 indent=0); - void printHeader(uint32 indent=0); + void printBody(uint32 indent=0); + void printHeader(uint32 indent=0); }; //======================================================================================== @@ -236,13 +239,13 @@ public: class IRLivenessPrinter: public IRPrinter { public: - IRLivenessPrinter(const IRManager * irm=0, const char * _title=0) - :IRPrinter(irm, _title){} - void printNode(const Node * node, uint32 indent=0); + IRLivenessPrinter(const IRManager * irm=0, const char * _title=0) + :IRPrinter(irm, _title){} + void printNode(const Node * node, uint32 indent=0); - virtual void printLiveSet(const LiveSet * ls); - static void printLiveSet(::std::ostream& os, const IRManager& irm, const LiveSet * ls) - { IRLivenessPrinter p(&irm); p.setStream(os); p.printLiveSet(ls); } + virtual void printLiveSet(const BitSet * ls); + static void printLiveSet(::std::ostream& os, const IRManager& irm, const BitSet * ls) + { IRLivenessPrinter p(&irm); p.setStream(os); p.printLiveSet(ls); } }; //======================================================================================== @@ -251,10 +254,10 @@ public: class IRInstConstraintPrinter: public IRPrinter { public: - IRInstConstraintPrinter(const IRManager * irm=0, const char * _title=0) - :IRPrinter(irm, _title){} + IRInstConstraintPrinter(const IRManager * irm=0, const char * _title=0) + :IRPrinter(irm, _title){} - virtual void printOpnd(const Inst * inst, uint32 opndIdx, bool isLiveBefore=false, bool isLiveAfter=false); + virtual void printOpnd(const Inst * inst, uint32 opndIdx, bool isLiveBefore=false, bool isLiveAfter=false); }; //======================================================================================== @@ -267,23 +270,23 @@ It overrides certain methods to print LI class IRDotPrinter: public IRPrinter { public: - IRDotPrinter(const IRManager * irm=0, const char * _title=0) - :IRPrinter(irm, _title){} + IRDotPrinter(const IRManager * irm=0, const char * _title=0) + :IRPrinter(irm, _title){} - virtual void printNode(const Node * node); - virtual void printEdge(const Edge * edge); + virtual void printNode(const Node * node); + virtual void printEdge(const Edge * edge); - virtual void printLayoutEdge(const BasicBlock * from, const BasicBlock * to); + virtual void printLayoutEdge(const BasicBlock * from, const BasicBlock * to); - virtual void printTraversalOrder(CFG::OrderType orderType); - virtual void printLiveness(); + virtual void printTraversalOrder(CGNode::OrderType orderType); + virtual void printLiveness(); - virtual void printCFG(uint32 indent=0); + virtual void printCFG(uint32 indent=0); - virtual void printHeader(uint32 indent=0); - virtual void printEnd(uint32 indent=0); - virtual void printBody(uint32 indent=0); - virtual void print(uint32 indent=0); + virtual void printHeader(uint32 indent=0); + virtual void printEnd(uint32 indent=0); + virtual void printBody(uint32 indent=0); + virtual void print(uint32 indent=0); }; @@ -297,16 +300,16 @@ focusing in liveness information for ope class IRLivenessDotPrinter: public IRDotPrinter { public: - IRLivenessDotPrinter(const IRManager * irm=0, const char * _title=0) - :IRDotPrinter(irm, _title){} + IRLivenessDotPrinter(const IRManager * irm=0, const char * _title=0) + :IRDotPrinter(irm, _title){} - virtual void printNode(const Node * node); + virtual void printNode(const Node * node); - virtual void printBody(uint32 indent=0); + virtual void printBody(uint32 indent=0); private: - void printLivenessForInst(const StlVector<Opnd*> opnds, const LiveSet * ls0, const LiveSet * ls1); - char * getRegString(char * str, Constraint c, StlVector<Opnd *> opnds); + void printLivenessForInst(const StlVector<Opnd*> opnds, const BitSet * ls0, const BitSet * ls1); + char * getRegString(char * str, Constraint c, StlVector<Opnd *> opnds); }; @@ -315,30 +318,30 @@ private: // LIR logging helpers //======================================================================================== void dumpIR( - const IRManager * irManager, - uint32 stageId, - const char * readablePrefix, - const char * readableStageName, - const char * stageTagName, - const char * subKind1, - const char * subKind2=0, - uint32 instFilter=Inst::Kind_Inst, - uint32 opndFlavor=IRPrinter::OpndFlavor_All, - uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Implicit|Inst::OpndRole_Use|Inst::OpndRole_Def - ); + const IRManager * irManager, + uint32 stageId, + const char * readablePrefix, + const char * readableStageName, + const char * stageTagName, + const char * subKind1, + const char * subKind2=0, + uint32 instFilter=Inst::Kind_Inst, + uint32 opndFlavor=IRPrinter::OpndFlavor_All, + uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Implicit|Inst::OpndRole_Use|Inst::OpndRole_Def + ); void printDot( - const IRManager * irManager, - uint32 stageId, - const char * readablePrefix, - const char * readableStageName, - const char * stageTagName, - const char * subKind1, - const char * subKind2=0, - uint32 instFilter=Inst::Kind_Inst, - uint32 opndFlavor=IRPrinter::OpndFlavor_All, - uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Implicit|Inst::OpndRole_Use|Inst::OpndRole_Def - ); + const IRManager * irManager, + uint32 stageId, + const char * readablePrefix, + const char * readableStageName, + const char * stageTagName, + const char * subKind1, + const char * subKind2=0, + uint32 instFilter=Inst::Kind_Inst, + uint32 opndFlavor=IRPrinter::OpndFlavor_All, + uint32 opndRolesFilter=Inst::OpndRole_Explicit|Inst::OpndRole_Auxilary|Inst::OpndRole_Implicit|Inst::OpndRole_Use|Inst::OpndRole_Def + ); void printRuntimeArgs(::std::ostream& os, uint32 opndCount, CallingConvention::OpndInfo * infos, JitFrameContext * context); void printRuntimeOpnd(::std::ostream& os, TypeManager & tm, Type::Tag typeTag, const void * p); diff --git vm/jitrino/src/codegenerator/ia32/Ia32ProfileUtils.cpp vm/jitrino/src/codegenerator/ia32/Ia32ProfileUtils.cpp index 72cee5a..f9fafd3 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32ProfileUtils.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32ProfileUtils.cpp @@ -18,9 +18,8 @@ * @version $Revision: 1.8.12.1.4.4 $ */ -#include "Ia32CFG.h" -#include "Timer.h" - +#include "Ia32IRManager.h" +#include "LoopTree.h" #include "Ia32Printer.h" namespace Jitrino { @@ -32,73 +31,47 @@ namespace Ia32 { /* FREQUENCY CALCULATION */ /************************************************************************/ /************************************************************************/ -#define PROB_EXCEPTION 0.001 #define PROB_UNKNOWN_BB 0.5 -#define PROB_IN_LOOP 0.88 +#define PROB_LOOP_EXIT (PROB_UNKNOWN_BB * 0.1) +#define PROB_EXCEPTION 0.0000001 #define ACCEPTABLE_DOUBLE_PRECISION_LOSS 0.000000001 #define ABS(a) (((a) > (0)) ? (a) : -(a)) #define DEFAULT_ENTRY_NODE_FREQUENCY 10000 -class _CountFreqsContext { -public: - CFG* cfg; - MemoryManager& mm; - bool useCyclicFreqs; - double* cyclicFreqs; - bool* visitInfo; - StlVector<Edge*> exitEdges; - - _CountFreqsContext(MemoryManager& _mm, CFG* _cfg) : cfg(_cfg), mm(_mm), useCyclicFreqs(false), exitEdges(mm) { - uint32 n = cfg->getMaxNodeId(); - cyclicFreqs = new (mm) double[n]; - visitInfo = new (mm) bool[n]; - for (uint32 i=0; i< n; i++) { - cyclicFreqs[i]=1; - } - } - - inline void resetVisitInfo() { - memset(visitInfo, false, cfg->getMaxNodeId()); - } -}; - +static void fixEdgeProbs(ControlFlowGraph* cfg); -static void countFrequenciesFromProbs(CFG* fg); -static void fixEdgeProbs(CFG* cfg); -static void checkFrequencies(CFG* fg); -static void countLinearFrequency(const _CountFreqsContext* c, Node* node); -static void estimateCyclicFrequencies(_CountFreqsContext* c, Node* loopHead); -static void findLoopExits(_CountFreqsContext* c, Node* loopHead); - - -//static Timer *freqCalcTimer=NULL; -void CFG::updateExecCounts() { - assert(isLoopInfoValid()); - assert(hasEdgeProfile()); - if (!hasEdgeProfile()) { +void IRManager::fixEdgeProfile() { + + if (fg->hasEdgeProfile() && fg->isEdgeProfileConsistent()) { return; } - + //step1: fix edge-probs, try to reuse old probs as much as possible.. - fixEdgeProbs(this); + fixEdgeProbs(fg); //step2 : calculate frequencies - countFrequenciesFromProbs(this); + fg->smoothEdgeProfile(); } -void fixEdgeProbs(CFG* cfg) { +void fixEdgeProbs(ControlFlowGraph* cfg) { + LoopTree* lt = cfg->getLoopTree(); + lt->rebuild(false); + + //fix edge-probs, try to reuse old probs as much as possible.. - for (Nodes::const_iterator it = cfg->getNodes().begin(), end = cfg->getNodes().end(); it!=end; ++it) { + const Nodes& nodes = cfg->getNodesPostOrder(); //fix only reachable + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; - const Edges& edges = node->getEdges(Direction_Out); - if (edges.isEmpty()) { + const Edges& edges = node->getOutEdges(); + if (edges.empty()) { assert(node == cfg->getExitNode()); continue; } double sumProb = 0; bool foundNotEstimated = false; - for (Edge* e = edges.getFirst(); e!=NULL; e = edges.getNext(e)) { - double prob = e->getProbability(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + double prob = edge->getEdgeProb(); sumProb+=prob; foundNotEstimated = foundNotEstimated || prob <= 0; } @@ -106,179 +79,43 @@ void fixEdgeProbs(CFG* cfg) { continue; //ok, nothing to fix } //now fix probs.. - double mult = 1; - if (!foundNotEstimated) { - mult = 1 / sumProb; - } else { + if (foundNotEstimated) { sumProb = 0; - bool loopHead = node->isLoopHeader(); - for (Edge* e = edges.getFirst(); e!=NULL; e= edges.getNext(e)) { - double prob = e->getProbability(); - if (prob <= 0 || loopHead) { - Node* target = e->getNode(Direction_Head); - if (!target->hasKind(Node::Kind_BasicBlock)) { + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + double prob = edge->getEdgeProb(); + if (prob <= 0) { + Node* target = edge->getTargetNode(); + if (!target->isBlockNode() || prob == 0) { prob = PROB_EXCEPTION; } else { - if (loopHead) { //special processing of loop entrance nodes - if (target!=node && target->getLoopHeader()!=node) { - prob = 1 - PROB_IN_LOOP; - } else { - prob = PROB_IN_LOOP; - } - } else { - prob = PROB_UNKNOWN_BB; - } + prob = lt->isLoopExit(edge) ? PROB_LOOP_EXIT : PROB_UNKNOWN_BB; } - assert(prob > 0); - e->setProbability(prob); + edge->setEdgeProb(prob); } + assert(edge->getEdgeProb() > 0); sumProb+=prob; } - mult = 1 / sumProb; } + double mult = 1 / sumProb; + sumProb = 0; - for (Edge* e = edges.getFirst(); e!=NULL; e= edges.getNext(e)) { - double prob = e->getProbability(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + double prob = e->getEdgeProb(); prob = prob * mult; assert(prob > 0); - e->setProbability(prob); + e->setEdgeProb(prob); #ifdef _DEBUG sumProb+=prob; #endif } assert(ABS(1-sumProb) < ACCEPTABLE_DOUBLE_PRECISION_LOSS); } -} - -void countFrequenciesFromProbs(CFG* cfg) { - MemoryManager& mm = cfg->getMemoryManager(); - _CountFreqsContext c(mm, cfg); - c.resetVisitInfo(); - countLinearFrequency(&c, cfg->getPrologNode()); - if (cfg->getMaxLoopDepth() > 0) { //if there are loops in method - c.useCyclicFreqs = true; - for (Nodes::const_iterator it = cfg->getNodes().begin(), end = cfg->getNodes().end(); it!=end; ++it) { - Node* node = *it; - if (node->isLoopHeader() && node->getLoopHeader() == NULL) { - estimateCyclicFrequencies(&c, node); - } - } - c.resetVisitInfo(); - countLinearFrequency(&c, cfg->getPrologNode()); - } - checkFrequencies(cfg); -} - -static void checkFrequencies(CFG* cfg) { -#ifdef _DEBUG - const Nodes& nodes = cfg->getNodes(); - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - assert(node->getExecCnt() > 0); - const Edges& inEdges = node->getEdges(Direction_In); - if (inEdges.isEmpty()) { - assert(node == cfg->getPrologNode()); - continue; - } - double freq = 0.0; - for(Edge* edge = inEdges.getFirst(); edge!=NULL; edge = inEdges.getNext(edge)) { - Node* fromNode = edge->getNode(Direction_Tail); - double fromFreq = fromNode->getExecCnt(); - assert(fromFreq > 0); - freq += fromFreq * edge->getProbability(); - } - assert(ABS(node->getExecCnt() - freq)/freq < ACCEPTABLE_DOUBLE_PRECISION_LOSS); - } - Node* exitNode = cfg->getExitNode(); - double exitFreq = exitNode->getExecCnt(); - assert(ABS(exitFreq - DEFAULT_ENTRY_NODE_FREQUENCY) < ACCEPTABLE_DOUBLE_PRECISION_LOSS*DEFAULT_ENTRY_NODE_FREQUENCY); -#endif -} - - -static void countLinearFrequency(const _CountFreqsContext* c, Node* node) { - const Edges& inEdges = node->getEdges(Direction_In); - if (inEdges.isEmpty()) { //node is entry - if (node->getExecCnt() <= 1) { - node->setExecCnt(DEFAULT_ENTRY_NODE_FREQUENCY); - } //else leave profile value - } else { - double freq = 0.0; - for(Edge* edge = inEdges.getFirst(); edge!=NULL; edge = inEdges.getNext(edge)) { - if (edge->isBackEdge()) { - continue; //only linear freq estimation - } - Node* fromNode = edge->getNode(Direction_Tail); - if (c->visitInfo[fromNode->getId()] == false) { - return; - } - double fromFreq = fromNode->getExecCnt(); - freq += fromFreq * edge->getProbability(); - } - if (c->useCyclicFreqs && node->isLoopHeader()) { - freq *= c->cyclicFreqs[node->getId()]; - } - node->setExecCnt(freq); - } - c->visitInfo[node->getId()] = true; - const Edges& outEdges = node->getEdges(Direction_Out); - for(Edge* edge = outEdges.getFirst(); edge!=NULL; edge = outEdges.getNext(edge)) { - Node* toNode = edge->getNode(Direction_Head); - if (c->visitInfo[toNode->getId()] == false ) { - countLinearFrequency(c, toNode); - } - } -} - -static void estimateCyclicFrequencies(_CountFreqsContext* c, Node* loopHead) { - assert(loopHead->isLoopHeader()); - bool hasChildLoop = 0; - //process all child loops first - for (Nodes::const_iterator it = c->cfg->getNodes().begin(), end = c->cfg->getNodes().end(); it!=end; ++it) { - Node* node = *it; - if (node->getLoopHeader() == loopHead && node->isLoopHeader()) { - hasChildLoop = true; - estimateCyclicFrequencies(c, node); - } - } - findLoopExits(c, loopHead); - if (hasChildLoop) { - c->resetVisitInfo(); - countLinearFrequency(c, c->cfg->getPrologNode()); - } - double inFlow = loopHead->getExecCnt(); //node has linear freq here - double exitsFlow = 0; - //sum all exits flow - for (StlVector<Edge*>::const_iterator it = c->exitEdges.begin(), end = c->exitEdges.end(); it!=end; ++it) { - Edge* edge = *it; - Node* fromNode = edge->getNode(Direction_Tail); - exitsFlow += edge->getProbability() * fromNode->getExecCnt(); - } - - // if loop will do multiple iteration exitsFlow becomes equals to inFlow - double loopCycles = inFlow / exitsFlow; - assert(loopCycles > 1); - c->cyclicFreqs[loopHead->getId()] = loopCycles; -} - -static void findLoopExits(_CountFreqsContext* c, Node* loopHead) { - c->exitEdges.clear(); - const Nodes& nodes = c->cfg->getNodes(); - for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - Node* node = *it; - if (!node->isWithinLoop(loopHead)) { - continue; - } - const Edges& outEdges = node->getEdges(Direction_Out); - for(Edge* edge = outEdges.getFirst(); edge!=NULL; edge = outEdges.getNext(edge)) { - Node* targetNode = edge->getNode(Direction_Head); - if (!targetNode->isWithinLoop(loopHead)) { - c->exitEdges.push_back(edge); - continue; - } - - } + if (cfg->getEntryNode()->getExecCount()<=0) { + cfg->getEntryNode()->setExecCount(DEFAULT_ENTRY_NODE_FREQUENCY); } + cfg->setEdgeProfile(true); } }} //namespaces diff --git vm/jitrino/src/codegenerator/ia32/Ia32RCE.cpp vm/jitrino/src/codegenerator/ia32/Ia32RCE.cpp index 330ddda..39c5f39 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RCE.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32RCE.cpp @@ -18,139 +18,194 @@ * @version $Revision: 1.9.16.2.4.3 $ */ -#include "Ia32RCE.h" +#include "Ia32IRManager.h" + namespace Jitrino { namespace Ia32 { +//======================================================================================== +// class RCE +//======================================================================================== +/** + * class RCE performs removing comparisons following instructions which + * affected flags in the same way as CMP. In some cases instructions can be + * reordered for resolving comparison as available for removing + * + * The algorithm takes one-pass over CFG. + * + * This transformer ensures that + * + * 1) All conditional instructions get the same EFLAGS value as before + * transformation + * + * 2) All reordered instructions do the same effects as before transformation + * + * For example: + * + * Original code piece: + * I29: t50.:int32 (ID:v15(EFLGS):uint32) =AND .t28:int32,t49(1):int32 + * I30: (AD:v1:int32) =CopyPseudoInst (AU:t48:int32) + * I31: (AD:v2:int32) =CopyPseudoInst (AU:t25:int32) + * I32: (AD:v3:int8[]) =CopyPseudoInst (AU:t38:int8[]) + * I33: (ID:v15(EFLGS):uint32) =CMP .t50:int32,t51(0):int32 + * I34: JNZ BB_12 t52(0):intptr (IU:v15(EFLGS):uint32) + * + * After optimization: + * I29: t50:int32 (ID:v15(EFLGS):uint32) =AND .t28:int32,t49(1):int32 + * I30: (AD:v1:int32) =CopyPseudoInst (AU:t48:int32) + * I31: (AD:v2:int32) =CopyPseudoInst (AU:t25:int32) + * I32: (AD:v3:int8[]) =CopyPseudoInst (AU:t38:int8[]) + * I34: JNZ BB_12 t52(0):intptr (IU:v15(EFLGS):uint32) + * + * The implementation of this transformer is located in Ia32RCE.cpp + * + */ + +class RCE : public SessionAction { + void runImpl(); +protected: + + // check is flags using by conditional instruction affected by instruction + bool isUsingFlagsAffected(Inst * inst, Inst * condInst); + + // check instruction inst for possibility of removing + bool isSuitableToRemove(Inst * inst, Inst * condInst, Inst * cmpInst, Opnd * cmpOp); + +}; + +static ActionFactory<RCE> _rce("rce"); + /** - * The algorithm finds conditional instruction first, then corresponded - * CMP instruction and arithmetic instruction which affects flags in the same - * way as CMP. Combination is considered as available to be reduced if there - * are no instructions between CMP and arithmetic instruction which influence - * to flags or CMP operands. + * The algorithm finds conditional instruction first, then corresponded + * CMP instruction and arithmetic instruction which affects flags in the same + * way as CMP. Combination is considered as available to be reduced if there + * are no instructions between CMP and arithmetic instruction which influence + * to flags or CMP operands. * - * Also it tries to change improper conditional instruction to more optimizable - * kind. + * Also it tries to change improper conditional instruction to more optimizable + * kind. */ void RCE::runImpl() { - Inst * inst, * cmpInst, *condInst; - IRManager & irm=getIRManager(); - Opnd * cmpOp = NULL; - cmpInst = condInst = NULL; - for(CFG::NodeIterator it(irm); it!=NULL; ++it){ - Node * node=it; - if (node->hasKind(Node::Kind_BasicBlock)) { - BasicBlock * bb = (BasicBlock*)node; - if(bb->isEmpty()) - continue; - const Insts& insts=bb->getInsts(); - inst = insts.getLast(); - cmpInst = condInst = NULL; - for(inst = insts.getLast(); inst != NULL; inst = insts.getPrev(inst)) { - //find conditional instruction - Mnemonic baseMnem = getBaseConditionMnemonic(inst->getMnemonic()); - if (baseMnem != Mnemonic_NULL) { - condInst = inst; - cmpInst = NULL; - } else if (condInst) { - //find CMP instruction corresponds to conditional instruction - if(inst->getMnemonic() == Mnemonic_CMP || inst->getMnemonic() == Mnemonic_UCOMISD || inst->getMnemonic() == Mnemonic_UCOMISS) { - if (cmpInst) { - //this comparison is redundant because of overrided by cmpInst - inst->getBasicBlock()->removeInst(inst); - continue; - } - cmpInst = inst; - uint32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); - if(inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm)) { - //try to change conditional instruction to make combination available to optimize - cmpOp = inst->getOpnd(defCount); - Inst * newCondInst; Mnemonic mnem; - int64 val = inst->getOpnd(defCount+1)->getImmValue(); - - if (val == 0) { - continue; - } else if (val == 1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_L){ - mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_L)) + Mnemonic(ConditionMnemonic_LE)); - } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_G) { - mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_G)) + Mnemonic(ConditionMnemonic_GE)); - } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_B) { - mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_B)) + Mnemonic(ConditionMnemonic_BE)); - } else { - continue; - } - //replace old conditional instruction - newCondInst = - condInst->hasKind(Inst::Kind_BranchInst) ? - irm.newBranchInst(mnem,condInst->getOpnd(0)) : - (condInst->getForm() == Inst::Form_Native ? - irm.newInst(mnem, condInst->getOpnd(0), condInst->getOpnd(1)) : - irm.newInstEx(mnem, condInst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def), condInst->getOpnd(0), condInst->getOpnd(1))); - condInst->getBasicBlock()->appendInsts(newCondInst, condInst); - inst->getOpnd(defCount+1)->assignImmValue(0); - condInst->getBasicBlock()->removeInst(condInst); - condInst = newCondInst; - } - //find flags affected instruction precedes cmpInst - } else if (isUsingFlagsAffected(inst, condInst)) { - if (cmpInst) { - if (isSuitableToRemove(inst, condInst, cmpInst, cmpOp)) - { - bb->removeInst(cmpInst);//replace cmp - } - } - condInst = NULL; - } else { - if (inst->getOpndCount(Inst::OpndRole_Implicit|Inst::OpndRole_Def) || inst->getMnemonic() == Mnemonic_CALL) { - condInst = NULL; - } else { - //check for moving cmpInst operands - if ((inst->getMnemonic() == Mnemonic_MOV) && (inst->getOpnd(0) == cmpOp)) { - cmpOp = inst->getOpnd(1); - } - } - } - }//end if/else by condInst - }//end for() by Insts - }//end if BasicBlock - }//end for() by Nodes + Inst * inst, * cmpInst, *condInst; + Opnd * cmpOp = NULL; + cmpInst = condInst = NULL; + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) { + if(node->isEmpty()) { + continue; + } + cmpInst = condInst = NULL; + Inst* prevInst = NULL; + for(inst = (Inst*)node->getLastInst(); inst != NULL; inst = prevInst) { + prevInst = inst->getPrevInst(); + //find conditional instruction + Mnemonic baseMnem = getBaseConditionMnemonic(inst->getMnemonic()); + if (baseMnem != Mnemonic_NULL) { + condInst = inst; + cmpInst = NULL; + } else if (condInst) { + //find CMP instruction corresponds to conditional instruction + if(inst->getMnemonic() == Mnemonic_CMP || inst->getMnemonic() == Mnemonic_UCOMISD || inst->getMnemonic() == Mnemonic_UCOMISS) { + if (cmpInst) { + //this comparison is redundant because of overrided by cmpInst + inst->unlink(); + continue; + } + cmpInst = inst; + uint32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); + if(inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm)) { + //try to change conditional instruction to make combination available to optimize + cmpOp = inst->getOpnd(defCount); + Inst * newCondInst; Mnemonic mnem; + int64 val = inst->getOpnd(defCount+1)->getImmValue(); + + if (val == 0) { + continue; + } else if (val == 1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_L){ + mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_L)) + Mnemonic(ConditionMnemonic_LE)); + } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_G) { + mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_G)) + Mnemonic(ConditionMnemonic_GE)); + } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_B) { + mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_B)) + Mnemonic(ConditionMnemonic_BE)); + } else { + continue; + } + //replace old conditional instruction + if (condInst->hasKind(Inst::Kind_BranchInst)) { + BranchInst* br = (BranchInst*)condInst; + newCondInst = irManager->newBranchInst(mnem,br->getTrueTarget(), br->getFalseTarget(), condInst->getOpnd(0)); + } else if (condInst->getForm() == Inst::Form_Native ) { + newCondInst = irManager->newInst(mnem, condInst->getOpnd(0), condInst->getOpnd(1)); + } else { + newCondInst = irManager->newInstEx(mnem, condInst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def), condInst->getOpnd(0), condInst->getOpnd(1)); + } + newCondInst->insertAfter(condInst); + condInst->unlink(); + condInst = newCondInst; + inst->setOpnd(defCount+1, irManager->newImmOpnd(inst->getOpnd(defCount+1)->getType(),0)); + } + //find flags affected instruction precedes cmpInst + } else if (isUsingFlagsAffected(inst, condInst)) { + if (cmpInst) { + if (isSuitableToRemove(inst, condInst, cmpInst, cmpOp)) + { + cmpInst->unlink();//replace cmp + } + } + condInst = NULL; + } else { + if (inst->getOpndCount(Inst::OpndRole_Implicit|Inst::OpndRole_Def) || inst->getMnemonic() == Mnemonic_CALL) { + condInst = NULL; + } else { + //check for moving cmpInst operands + if ((inst->getMnemonic() == Mnemonic_MOV) && (inst->getOpnd(0) == cmpOp)) { + cmpOp = inst->getOpnd(1); + } + } + } + }//end if/else by condInst + }//end for() by Insts + }//end if BasicBlock + }//end for() by Nodes } bool RCE::isUsingFlagsAffected(Inst * inst, Inst * condInst) { - if (!inst->getOpndCount(Inst::OpndRole_Implicit|Inst::OpndRole_Def)) - //instruction doesn't change flags - return false; - switch (inst->getMnemonic()) { - case Mnemonic_SUB: - //instruction changes all flags - return true; - case Mnemonic_IDIV: - case Mnemonic_CALL: - //instruction changes flags in the way doesn't correspond CMP - return false; - default: - //instruction changes particular flags - ConditionMnemonic mn = ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())); - return ( mn == ConditionMnemonic_Z || mn == ConditionMnemonic_NZ) ? true : false; - } + if (!inst->getOpndCount(Inst::OpndRole_Implicit|Inst::OpndRole_Def)) + //instruction doesn't change flags + return false; + switch (inst->getMnemonic()) { + case Mnemonic_SUB: + //instruction changes all flags + return true; + case Mnemonic_IDIV: + case Mnemonic_CALL: + //instruction changes flags in the way doesn't correspond CMP + return false; + default: + //instruction changes particular flags + ConditionMnemonic mn = ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())); + return ( mn == ConditionMnemonic_Z || mn == ConditionMnemonic_NZ) ? true : false; + } } bool RCE::isSuitableToRemove(Inst * inst, Inst * condInst, Inst * cmpInst, Opnd * cmpOp) { - /* cmpInst can be removed if inst defines the same operand which will be - * compared with zero by cmpInst or inst is SUB with the same use-operands as cmpInst - * Required: Native form of insts - */ - uint32 cmpOpCount = cmpInst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_UseDef); - if ((cmpOp == inst->getOpnd(0)) && cmpInst->getOpnd(cmpOpCount -1)->isPlacedIn(OpndKind_Imm) && (cmpInst->getOpnd(cmpOpCount -1)->getImmValue() == 0)) { - return true; - } - return false; + /* cmpInst can be removed if inst defines the same operand which will be + * compared with zero by cmpInst or inst is SUB with the same use-operands as cmpInst + * Required: Native form of insts + */ + uint32 cmpOpCount = cmpInst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_UseDef); + if ((cmpOp == inst->getOpnd(0)) && cmpInst->getOpnd(cmpOpCount -1)->isPlacedIn(OpndKind_Imm) && (cmpInst->getOpnd(cmpOpCount -1)->getImmValue() == 0)) { + return true; + } + return false; } }} //end namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32RCE.h vm/jitrino/src/codegenerator/ia32/Ia32RCE.h deleted file mode 100644 index 6af2e10..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32RCE.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Nikolay A. Sidelnikov - * @version $Revision: 1.8.26.4 $ - */ - -#ifndef _IA32_RCE_H_ -#define _IA32_RCE_H_ - -#include "Ia32IRManager.h" -namespace Jitrino -{ -namespace Ia32{ - -//======================================================================================== -// class RCE -//======================================================================================== -/** - * class RCE performs removing comparisons following instructions which - * affected flags in the same way as CMP. In some cases instructions can be - * reordered for resolving comparison as available for removing - * - * The algorithm takes one-pass over CFG. - * - * This transformer ensures that - * - * 1) All conditional instructions get the same EFLAGS value as before - * transformation - * - * 2) All reordered instructions do the same effects as before transformation - * - * For example: - * - * Original code piece: - * I29: t50.:int32 (ID:v15(EFLGS):uint32) =AND .t28:int32,t49(1):int32 - * I30: (AD:v1:int32) =CopyPseudoInst (AU:t48:int32) - * I31: (AD:v2:int32) =CopyPseudoInst (AU:t25:int32) - * I32: (AD:v3:int8[]) =CopyPseudoInst (AU:t38:int8[]) - * I33: (ID:v15(EFLGS):uint32) =CMP .t50:int32,t51(0):int32 - * I34: JNZ BB_12 t52(0):intptr (IU:v15(EFLGS):uint32) - * - * After optimization: - * I29: t50:int32 (ID:v15(EFLGS):uint32) =AND .t28:int32,t49(1):int32 - * I30: (AD:v1:int32) =CopyPseudoInst (AU:t48:int32) - * I31: (AD:v2:int32) =CopyPseudoInst (AU:t25:int32) - * I32: (AD:v3:int8[]) =CopyPseudoInst (AU:t38:int8[]) - * I34: JNZ BB_12 t52(0):intptr (IU:v15(EFLGS):uint32) - * - * The implementation of this transformer is located in Ia32RCE.cpp - * - */ - -BEGIN_DECLARE_IRTRANSFORMER(RCE, "rce", "Redundant comparison elimination") - IRTRANSFORMER_CONSTRUCTOR(RCE) - void runImpl(); -protected: - - // check is flags using by conditional instruction affected by instruction - bool isUsingFlagsAffected(Inst * inst, Inst * condInst); - - // check instruction inst for possibility of removing - bool isSuitableToRemove(Inst * inst, Inst * condInst, Inst * cmpInst, Opnd * cmpOp); - -END_DECLARE_IRTRANSFORMER(RCE) -}} //end namespace Ia32 - -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.cpp vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.cpp index 6346226..706c6e3 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.cpp @@ -18,11 +18,22 @@ * @version $Revision: 1.13.20.3 $ */ -#include "Ia32RegAlloc2.h" +#include "Ia32IRManager.h" #include "Ia32RegAllocCheck.h" +#include "Interval.h" #include "Stl.h" #include "Log.h" +#ifdef _DEBUG__REGALLOC2 +#include "Ia32RegAllocWrite.h" +#include <iostream> +#include <iomanip> +#endif + +#ifdef _EM64T_ +#define _SKIP_CATCHED +#endif + namespace Jitrino { @@ -31,50 +42,109 @@ namespace Ia32 //======================================================================================== -// class RegAlloc2::Span +// class Ia32RegAlloc2 //======================================================================================== -struct RegAlloc2::Span -{ - Instnb beg, end; -}; +/** + * This class attempts to assign register for any operand (found in LIR) that can be + * allocated in register. + * + * Set of registers available for allocation is specified by input arguments and saved + * in 'constrs' class member. All operands that cannot be allocated in the registers + * available are simply ignored. + * + * So this allocator should be called for each set of the registers available (GPReg, XMM, + * FP) independently. + * + * It is not guaranteed that all operands which can be assigned will be assigned. + * Therefore, the companion class (SpillGen) must be used after this allocator. + * + * The main idea behind the allocator is well-known bin packing algorithm, but this + * implementation is completely independent of any published algorithms. + */ +static const char* help = +" regs=ALL_GP\n" +" regs=ALL_XMM\n" +" regs=<comma-separated list of available registers, e.g EAX,ECX,XMM0,>\n" +; -//======================================================================================== -// class RegAlloc2::Opand -//======================================================================================== -struct RegAlloc2::Opand +struct RegAlloc2 : public SessionAction { - Opnd* opnd; // 0 for fictious (preassigned) operand or pointer to LIR - Register* assigned; // 0 or register assigned + typedef uint32 RegMask; // used to represent set of registers + typedef size_t Instnb; // used to describe instruction number + + typedef Interval::Span Span; // interval of instructions not crossed basic block boundary + struct Register; // holds all operands assigned to this register + + // class RegAlloc2::Opand + struct Opand : public Interval + { + Opnd* opnd; // 0 for fictious (preassigned) operand or pointer to LIR + Register* assigned; // 0 or register assigned + + size_t length; // total length of all intervals + size_t weight; // weight coeff (taken from LIR) + + Opand* parentOpand; // another opand which is a source in a copy instruction defining this opand, hint for coalescing + bool ignore; + + Opand (MemoryManager& mm) :Interval(mm) {} + + void update (); + + static bool smaller (const RegAlloc2::Opand*& x, const RegAlloc2::Opand*& y) + { return x->end - x->beg < y->end - y->beg; } -// No two intervals can have one common point, so they can be ordered with Span::Less - typedef StlVector<Span> Spans; - Spans spans; // liveness data in form of list of intervals + static bool lighter (const RegAlloc2::Opand* x, const RegAlloc2::Opand* y) + { return x->weight < y->weight; } - Instnb beg, end; // start point of first interval and end point of last interval - size_t length; // total length of all intervals - size_t weight; // weight coeff (taken from LIR) + }; - Opand* parentOpand; // another opand which is a source in a copy instruction defining this opand, hint for coalescing + MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() + size_t opandcount; // total count of operands in LIR + Constraint constrs; // initial constraints (registers available) - Opand (MemoryManager& mm) :spans(mm) {} + typedef StlVector<Register*> Registers; + Registers registers; - bool startOrExtend (Instnb instIdx); - void stop (Instnb instIdx); + typedef StlVector<Opand*> Opands; + Opands opandmap; // mapping Ia32Opnd.id -> Opand* + size_t candidateCount; - void update (); - bool conflict (const Opand*, int&) const; + void buildRegs (); + void buildOpands (); + void allocateRegs (); + Register* findReg (RegMask) const; - static bool smaller (const RegAlloc2::Opand*& x, const RegAlloc2::Opand*& y) - { return x->end - x->beg < y->end - y->beg; } - static bool lighter (const RegAlloc2::Opand* x, const RegAlloc2::Opand* y) - { return x->weight < y->weight; } + RegAlloc2 () :mm(1000, "RegAlloc2"), registers(mm), opandmap(mm) {} + uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} + uint32 getSideEffects () const {return 0;} + + void runImpl(); + bool verify(bool force=false); +}; + + +static ActionFactory<RegAlloc2> _bp_regalloc("bp_regalloc", help); + + +static Counter<size_t> count_spilled("ia32:regalloc2:spilled", 0), + count_assigned("ia32:regalloc2:assigned", 0); + + +#ifdef _DEBUG_REGALLOC +struct Dbgout : public ::std::ofstream +{ + Dbgout (const char* s) {open(s);} + ~Dbgout () {close();} }; +static Dbgout dbgout("regalloc2.txt"); +#endif //======================================================================================== // class RegAlloc2::Register @@ -82,244 +152,171 @@ struct RegAlloc2::Opand struct RegAlloc2::Register { - RegMask regmask; // mask to identify this register (search key) - RegName regname; - Constraint constraint; // corresponding to this register + RegMask regmask; // mask to identify this register (search key) + RegName regname; + Constraint constraint; // corresponding to this register - Opand preassigned; // fictious operand to describe assignments by code selector + Opand preassigned; // fictious operand to describe assignments by code selector - typedef StlList<Opand*> Opands; - Opands assigned; // all operands assigned to this register by allocator + typedef StlList<Opand*> Opands; + Opands assigned; // all operands assigned to this register by allocator - size_t length; // total length of intervals of all operands + size_t length; // total length of intervals of all operands - Instnb beg, end; // start point of first interval and end point of last interval of all assigned operands + Instnb beg, end; // start point of first interval and end point of last interval of all assigned operands - Register (MemoryManager& mm) :preassigned(mm), assigned(mm) {} + Register (MemoryManager& mm) :preassigned(mm), assigned(mm) {} - bool canBeAssigned (const Opand*, int&) const; - void assign (Opand*); + bool canBeAssigned (const Opand*, int&) const; + void assign (Opand*); }; //======================================================================================== // Internal debug helpers //======================================================================================== + using ::std::endl; using ::std::ostream; #ifdef _DEBUG_REGALLOC -# define DBGOUT(x) if (Log::cat_cg()->isDebugEnabled()) Log::out()<<x; +# define DBGOUT(x) dbgout << x; #else -# define DBGOUT(x) +# define DBGOUT(x) #endif -static ostream& operator << (ostream& os, const RegAlloc2::Opand::Spans& x) -{ - for (RegAlloc2::Opand ::Spans::const_iterator i = x.begin(); i != x.end(); ++i) - os << " [" << i->beg << "," << i->end << "]"; - return os; -} - +#ifdef _DEBUG_REGALLOC static ostream& operator << (ostream& os, const RegAlloc2::Opand& x) { - os << "Opand{"; + os << "Opand{"; - if (x.opnd != 0) - os << "#" << x.opnd->getFirstId()<<"("<<x.opnd->getId()<<")"; - else - os << "~"; + if (x.opnd != 0) + os << "#" << x.opnd->getFirstId()<<"("<<x.opnd->getId()<<")"; + else + os << "~"; - os << " W:" << x.weight << " L:" << x.length; - os << " beg:" << x.beg << " end:" << x.end << " " << x.spans ; + os << " W:" << x.weight << " L:" << x.length; + os << " beg:" << x.beg << " end:" << x.end << " " << x.spans ; - if (x.assigned != 0) - os << " in " << getRegNameString(x.assigned->regname); + if (x.assigned != 0) + os << " in " << getRegNameString(x.assigned->regname); - return os << "}"; + return os << "}"; } static ostream& operator << (ostream& os, const RegAlloc2::Register& x) { - return os << "Reg{" << getRegNameString(x.regname) << " L:" << x.length << " beg:" << x.beg << " end:" << x.end << "}"; + return os << "Reg{" << getRegNameString(x.regname) << " L:" << x.length << " beg:" << x.beg << " end:" << x.end << "}"; } +#endif -//======================================================================================== -// class Ia32RegAlloc2::Opand -//======================================================================================== - -bool RegAlloc2::Opand::startOrExtend (Instnb instIdx) -{ - Span * last = spans.size() > 0 ? &spans.back() : NULL; - - if ( last != NULL && instIdx == last->beg ){ // open the last span - last->beg=0; - return true; - } - if (last == NULL || last->beg != 0) - {// insert open span - Span tmp={ 0, instIdx }; - spans.push_back(tmp); - return true; - } -// continue the same open use - return false; -} - -void RegAlloc2::Opand::stop (Instnb instIdx) -{ - Span * last=spans.size()>0?&spans.back():NULL; - if ( last==NULL || ( last->beg != 0 && last->beg !=instIdx ) ){ // closed - Span tmp={ instIdx, instIdx }; // probably dead def, add the shortest possible span - spans.push_back(tmp); - }else{ // last!=NULL && ( last->beg == 0 || last->beg ==instIdx ) - last->beg=instIdx; - } -} - -// Helper function for update() +// Helper function for update() // -static bool less (const RegAlloc2::Span& x, const RegAlloc2::Span& y) +static bool less (const Interval::Span& x, const Interval::Span& y) { - return x.beg < y.end; // to order properly spans like [124,130] [124,124] although there should not be such things + return x.beg < y.end; // to order properly spans like [124,130] [124,124] although there should not be such things } -// Complete liveness calculation - sort intervals and set endpoints +// Complete liveness calculation - sort intervals and set endpoints // void RegAlloc2::Opand::update () { - if ( opnd != NULL ){ // pre-assigned operands are not candidates anyway, no need to update their weight - Constraint c = opnd->getConstraint(Opnd::ConstraintKind_Calculated, OpndSize_Default); - weight *= (17 - countOnes(c.getMask())) * ( (c & Constraint(OpndKind_Mem, c.getSize())).isNull() ? 2 : 1); - } - - if (spans.size() != 0) - { - Span * pspans = &spans.front(); - sort(spans.begin(), spans.end(), less); - beg = spans.front().beg, - end = spans.back().end; - length=0; - for (int i=0, n=spans.size(); i<n; i++){ - assert(pspans[i].beg != 0); - length += pspans[i].end - pspans[i].beg; // no +1 as this is the number of instructions "hovered" by this opand + if ( opnd != NULL ){ // pre-assigned operands are not candidates anyway, no need to update their weight + Constraint c = opnd->getConstraint(Opnd::ConstraintKind_Calculated, OpndSize_Default); + weight *= (17 - countOnes(c.getMask())) * ( (c & Constraint(OpndKind_Mem, c.getSize())).isNull() ? 2 : 1); + } + if (spans.size() != 0) + { + Span * pspans = &spans.front(); + sort(spans.begin(), spans.end(), less); + beg = spans.front().beg, + end = spans.back().end; + length=0; + for (int i=0, n=spans.size(); i<n; i++){ + assert(pspans[i].beg != 0); + length += pspans[i].end - pspans[i].beg; // no +1 as this is the number of instructions "hovered" by this opand #ifdef _DEBUG - assert(pspans[i].beg <= pspans[i].end); - if ( i < n-1 ){ - assert(pspans[i].end < pspans[i+1].beg); - } + assert(pspans[i].beg <= pspans[i].end); + if ( i < n-1 ){ + assert(pspans[i].end < pspans[i+1].beg); + } #endif - } - assert( opnd == NULL || beg > 0); - } - else - { - assert(0); - } - assert(beg <= end); + } + assert( opnd == NULL || beg > 0); + assert(beg <= end); + } + else + { + //assert(0); + ignore = true; + } } - -// Determinate if two operands conflict (i.e. can be assigned to the same register) -// The algorithm executes in linear time -// -bool RegAlloc2::Opand::conflict (const RegAlloc2::Opand* x, int& adj) const -{ - int d; - if (beg <= x->end && x->beg <= end) - { - Spans::const_iterator - i = spans.begin(), iend = spans.end(), - k = x->spans.begin(), kend = x->spans.end(); - - while (i != iend && k != kend) - { - if ((d = i->end - k->beg) < 0) - { - if (d == -1) - ++adj; - ++i; - } - else if ((d = i->beg - k->end) > 0) - { - if (d == 1) - ++adj; - ++k; - } - else - return true; - } - } - - return false; -} - - //======================================================================================== // class Ia32RegAlloc2::Register //======================================================================================== -// Test if this register can be assigned to the operand 'x' +// Test if this register can be assigned to the operand 'x' // bool RegAlloc2::Register::canBeAssigned (const RegAlloc2::Opand* x, int& adj) const { - DBGOUT(" try " << *this;) - - if (!x->opnd->canBePlacedIn(constraint)) - { - DBGOUT(" -constraint" << endl;) - return false; - } - - if (preassigned.conflict(x, adj)) - { - DBGOUT(" -preassigned" << endl;) - return false; - } - - adj = 0; - - int d; - if ( (d = x->end - beg) < 0 ){ - if (d==-1) - adj=1; - DBGOUT(" -free (below lower bound)!" << endl;) - return true; - } - if ( (d = x->beg - end) > 0 ){ - if (d==1) - adj=1; - DBGOUT(" -free (above upper bound)!" << endl;) - return true; - } - - for (Opands::const_iterator i = assigned.begin(); i != assigned.end(); ++i) - if ((*i)->conflict(x, adj)) - { - DBGOUT(" -conflict " << **i << endl;) - return false; - } - - DBGOUT(" -free (full check)!" << endl;) - return true; + DBGOUT(" try " << *this;) + + if (!x->opnd->canBePlacedIn(constraint)) + { + DBGOUT(" -constraint" << endl;) + return false; + } + + if (preassigned.conflict(x, adj)) + { + DBGOUT(" -preassigned" << endl;) + return false; + } + + adj = 0; + + int d; + if ( (d = x->end - beg) < 0 ){ + if (d==-1) + adj=1; + DBGOUT(" -free (below lower bound)!" << endl;) + return true; + } + if ( (d = x->beg - end) > 0 ){ + if (d==1) + adj=1; + DBGOUT(" -free (above upper bound)!" << endl;) + return true; + } + + for (Opands::const_iterator i = assigned.begin(); i != assigned.end(); ++i) + if ((*i)->conflict(x, adj)) + { + DBGOUT(" -conflict " << **i << endl;) + return false; + } + + DBGOUT(" -free (full check)!" << endl;) + return true; } -// Assign opand 'x' to this register +// Assign opand 'x' to this register // void RegAlloc2::Register::assign (RegAlloc2::Opand* x) { - assigned.push_back(x); - x->assigned = this; - if (x->beg<beg) - beg=x->beg; - if (x->end>end) - end=x->end; - length += x->length; + assigned.push_back(x); + x->assigned = this; + if (x->beg<beg) + beg=x->beg; + if (x->end>end) + end=x->end; + length += x->length; } //======================================================================================== @@ -327,379 +324,408 @@ void RegAlloc2::Register::assign (RegAll //======================================================================================== -RegAlloc2::RegAlloc2 (IRManager& irm, const char* params) - :IRTransformer(irm, params), mm(1000, "RegAlloc2"), registers(mm), opandmap(mm) +void RegAlloc2::runImpl() { - if (Log::cat_cg()->isDebugEnabled()){ - MethodDesc& md=irManager.getMethodDesc(); - const char * methodName = md.getName(); - const char * methodTypeName = md.getParentType()->getName(); - const char * methodSignature= md.getSignatureString(); - Log::out() << "Contructed <" << methodTypeName << "::" << methodName << methodSignature << ">" << endl; - } -} +#ifdef _DEBUG_REGALLOC + MethodDesc& md=irManager->getMethodDesc(); + const char * methodName = md.getName(); + const char * methodTypeName = md.getParentType()->getName(); + const char * methodSignature= md.getSignatureString(); + dbgout << "Constructed <" << methodTypeName << "::" << methodName << methodSignature << ">" << endl; +#endif + irManager->fixEdgeProfile(); + + const char* parameters = getArg("regs"); + assert(parameters); + if (strcmp(parameters, "ALL_GP") == 0) + +#ifdef _EM64T_ + constrs = Constraint(RegName_R8) + |Constraint(RegName_RAX) + |Constraint(RegName_RDX) + |Constraint(RegName_RCX) + |Constraint(RegName_RBX) + |Constraint(RegName_RSI) + |Constraint(RegName_RDI) + |Constraint(RegName_RBP) + |Constraint(RegName_R9) + |Constraint(RegName_R10) + |Constraint(RegName_R11) + |Constraint(RegName_R12); +#else + constrs = Constraint(RegName_EAX) + |Constraint(RegName_ECX) + |Constraint(RegName_EDX) + |Constraint(RegName_EBX) + |Constraint(RegName_ESI) + |Constraint(RegName_EDI) + |Constraint(RegName_EBP); +#endif -RegAlloc2::~RegAlloc2 () -{ - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << "Destructed" << endl; - } -} + else if (strcmp(parameters, "ALL_XMM") == 0) + constrs = Constraint(RegName_XMM1) + |Constraint(RegName_XMM0) + |Constraint(RegName_XMM2) + |Constraint(RegName_XMM3) + |Constraint(RegName_XMM4) + |Constraint(RegName_XMM5) + |Constraint(RegName_XMM6) + |Constraint(RegName_XMM7); + else + { + constrs = Constraint(parameters); + constrs.intersectWith(Constraint(OpndKind_Reg, Constraint::getDefaultSize(constrs.getKind()))); + } + assert(!constrs.isNull()); -void RegAlloc2::runImpl() -{ - assert(parameters); - if (strcmp(parameters, "EAX|ECX|EDX|EBX|ESI|EDI|EBP") == 0) - constrs = Constraint(RegName_EAX) - |Constraint(RegName_ECX) - |Constraint(RegName_EDX) - |Constraint(RegName_EBX) - |Constraint(RegName_ESI) - |Constraint(RegName_EDI) - |Constraint(RegName_EBP); - - else if (strcmp(parameters, "XMM0|XMM1|XMM2|XMM3|XMM4|XMM5|XMM6|XMM7") == 0) - constrs = Constraint(RegName_XMM1) - |Constraint(RegName_XMM2) - |Constraint(RegName_XMM3) - |Constraint(RegName_XMM4) - |Constraint(RegName_XMM5) - |Constraint(RegName_XMM6) - |Constraint(RegName_XMM7); - - else - { - constrs = Constraint(parameters); - constrs.intersectWith(Constraint(OpndKind_Reg, Constraint::getDefaultSize(constrs.getKind()))); - } - assert(!constrs.isNull()); - - buildRegs(); - - buildOpands(); - - if (candidateCount == 0) - return; - - allocateRegs(); - - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << endl << "Result" << endl; - - int count1 = 0, count2 = 0; - - Opand* opand; - for (size_t i = 0; i != opandmap.size(); ++i) - if ((opand = opandmap[i]) != 0 && opand->opnd != 0) - { - Log::out() << " " << i << ") " << *opand << endl; - if (opand->assigned != 0) - { - Log::out() << " +assigned " << *opand->assigned << endl; - ++count1; - } - else - { - Log::out() << " -spilled " << endl; - ++count2; - } - } - - Log::out() << endl << "Registers" << endl; - for (Registers::const_iterator it = registers.begin(); it != registers.end(); ++it) - { - Register& r = **it; - Log::out() << r; - - if (!r.preassigned.spans.empty()) - Log::out() << " preassigned:" << r.preassigned.spans; - - if (!r.assigned.empty()) - { - Log::out() << " assigned:"; - for (Register::Opands::const_iterator kt = r.assigned.begin(); kt != r.assigned.end(); ++kt) - Log::out() << (*kt)->spans; - } - Log::out() << endl; - } - - Log::out() << endl << "Assigned: " << count1 << " spilled: " << count2 << endl; - } + buildRegs(); + + buildOpands(); + + if (candidateCount == 0) + return; + + allocateRegs(); + +#ifdef _DEBUG_REGALLOC + dbgout << endl << "Result" << endl; + + int count1 = 0, count2 = 0; + + Opand* opand; + for (size_t i = 0; i != opandmap.size(); ++i) + if ((opand = opandmap[i]) != 0 && opand->opnd != 0) + { + dbgout << " " << i << ") " << *opand << endl; + if (opand->assigned != 0) + { + dbgout << " +assigned " << *opand->assigned << endl; + ++count1; + } + else + { + dbgout << " -spilled " << endl; + ++count2; + } + } + + dbgout << endl << "Registers" << endl; + for (Registers::const_iterator it = registers.begin(); it != registers.end(); ++it) + { + Register& r = **it; + dbgout << r; + + if (!r.preassigned.spans.empty()) + dbgout << " preassigned:" << r.preassigned.spans; + + if (!r.assigned.empty()) + { + dbgout << " assigned:"; + for (Register::Opands::const_iterator kt = r.assigned.begin(); kt != r.assigned.end(); ++kt) + dbgout << (*kt)->spans; + } + dbgout << endl; + } + + dbgout << endl << "Assigned: " << count1 << " spilled: " << count2 << endl; + + dbgout << "Destructed" << endl; +#endif } bool RegAlloc2::verify (bool force) -{ - bool failed=false; - if (force||irManager.getVerificationLevel()>=2){ - RegAllocCheck chk(irManager); - if (!chk.run(false)) - failed=true; - if (!IRTransformer::verify(force)) - failed=true; - } - return !failed; -} - -// Initialize list of all available registers +{ + bool failed=false; + if (force||getVerificationLevel()>=2){ + RegAllocCheck chk(*irManager); + if (!chk.run(false)) + failed=true; + if (!SessionAction::verify(force)) + failed=true; + } + return !failed; +} + +// Initialize list of all available registers // -void RegAlloc2::buildRegs () +void RegAlloc2::buildRegs () { - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << endl << "buildRegs" << endl; - } - - OpndKind k = (OpndKind)constrs.getKind(); - OpndSize s = constrs.getSize(); - - registers.clear(); - RegMask mask = constrs.getMask(); - for (RegMask m = 1, x = 0; mask != 0; m <<= 1, ++x) - if ((mask & m)) - { - mask ^= m; - Register* r = new (mm) Register(mm); - r->regmask = m, - r->regname = getRegName(k, s, x); - r->constraint = Constraint(k, s, m); - r->length = 0; - r->beg=(Instnb)UINT_MAX; - r->end=(Instnb)0; - - Opand& op = r->preassigned; - op.opnd = 0; // because this is a fictious operand - op.length = 0; - op.weight = 0; - op.assigned = r; - op.parentOpand = 0; - registers.push_back(r); - } +#ifdef _DEBUG_REGALLOC + dbgout << endl << "buildRegs" << endl; +#endif + + OpndKind k = (OpndKind)constrs.getKind(); + OpndSize s = constrs.getSize(); + + registers.clear(); + RegMask mask = constrs.getMask(); + for (RegMask m = 1, x = 0; mask != 0; m <<= 1, ++x) + if ((mask & m)) + { + mask ^= m; + Register* r = new (mm) Register(mm); + r->regmask = m, + r->regname = getRegName(k, s, x); + r->constraint = Constraint(k, s, m); + r->length = 0; + r->beg=(Instnb)UINT_MAX; + r->end=(Instnb)0; + + Opand& op = r->preassigned; + op.opnd = 0; // because this is a fictious operand + op.length = 0; + op.weight = 0; + op.assigned = r; + op.parentOpand = 0; + registers.push_back(r); + } } RegAlloc2::Register* RegAlloc2::findReg (RegMask mask) const { - for (Registers::const_iterator it = registers.begin(); it != registers.end(); ++it) - if ((*it)->regmask == mask) - return *it; + for (Registers::const_iterator it = registers.begin(); it != registers.end(); ++it) + if ((*it)->regmask == mask) + return *it; - return 0; + return 0; } -void RegAlloc2::buildOpands () +void RegAlloc2::buildOpands () { - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << endl << "buildOpands" << endl; - } +#ifdef _DEBUG_REGALLOC + dbgout << endl << "buildOpands" << endl; +#endif - opandcount = irManager.getOpndCount(); + opandcount = irManager->getOpndCount(); candidateCount = 0; - int registerPressure = 0; - opandmap.clear(); - opandmap.reserve(opandcount); - - for (uint32 i = 0; i != opandcount; ++i) - { - Opnd* opnd = irManager.getOpnd(i); - Opand* opand = 0; - - if (opnd->isPlacedIn(constrs)) - { - Register* r = findReg(getRegMask(opnd->getRegName())); - if (r != 0) - opand = &r->preassigned; - } - - else if (opnd->isAllocationCandidate(constrs)) - { - opand = new (mm) Opand(mm); - opand->opnd = opnd; - opand->length = 0; - opand->weight = 0; - opand->assigned = 0; - opand->parentOpand = 0; + int registerPressure = 0; + opandmap.clear(); + opandmap.reserve(opandcount); + + for (uint32 i = 0; i != opandcount; ++i) + { + Opnd* opnd = irManager->getOpnd(i); + Opand* opand = 0; + + if (opnd->isPlacedIn(constrs)) + { + Register* r = findReg(getRegMask(opnd->getRegName())); + if (r != 0) + opand = &r->preassigned; + } + + else if (opnd->isAllocationCandidate(constrs)) + { + opand = new (mm) Opand(mm); + opand->opnd = opnd; + opand->length = 0; + opand->weight = 0; + opand->assigned = 0; + opand->parentOpand = 0; + opand->ignore = false; ++candidateCount; - } - - opandmap.push_back(opand); - } - if (candidateCount == 0) - return; - - const Node* node; - LiveSet lives(mm, opandcount); - - for (CFG::NodeIterator it(irManager, CFG::OrderType_Postorder); (node = it.getNode()) != 0; ++it) - if (node->hasKind(Node::Kind_BasicBlock)) - { - int execCount = (unsigned)node->getExecCnt(); - if (execCount < 1) - execCount = 1; - execCount *= 100; - - const Insts& insts = ((BasicBlock*)node)->getInsts(); - const Inst* inst = insts.getLast(); - if (inst == 0) - continue; - - uint32 instIndex=inst->getIndex(); - Opand * opand; - - // start with the operands at the block bottom - irManager.getLiveAtExit(node, lives); - LiveSet::IterB ib(lives); - for (int x = ib.getNext(); x != -1; x = ib.getNext()) - if ( (opand=opandmap[x]) != 0 ){ - if (opand->startOrExtend(instIndex + 1)) - ++registerPressure; - } - - // iterate over instructions towards the top of the block - - for (; inst != 0; inst = insts.getPrev(inst)) - { - instIndex=inst->getIndex(); - const Opnd* opnd; - Opand* definedInCopyOpand = 0; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - opnd = opnds.getOpnd(it); - if ( (opand=opandmap[opnd->getId()]) != 0 ) - { - opand->weight += execCount * (registerPressure > (int)registers.size() ? 4 : 1); - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << " Pressure: " << registerPressure << "/" << registers.size() << " Opand: " << *opand << endl; - } - - if (inst->isLiveRangeEnd(it)){ - opand->stop(instIndex + 1); - --registerPressure; - if (inst->getMnemonic() == Mnemonic_MOV) - definedInCopyOpand = opand; - }else{ - if (opand->startOrExtend(instIndex)){ - ++registerPressure; - if ( definedInCopyOpand != 0 && inst->getMnemonic() == Mnemonic_MOV && definedInCopyOpand->parentOpand == 0){ + } + + opandmap.push_back(opand); + } + if (candidateCount == 0) + return; + + //irManager->indexInsts(); + + BitSet lives(mm, opandcount); + + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) + { + double execCount = node->getExecCount() / irManager->getFlowGraph()->getEntryNode()->getExecCount(); + assert(execCount > 0); + + const Inst* inst = (const Inst*)node->getLastInst(); + if (inst == 0) + continue; + + uint32 instIndex=inst->getIndex(); + Opand * opand; + + // start with the operands at the block bottom + irManager->getLiveAtExit(node, lives); + BitSet::IterB ib(lives); + for (int x = ib.getNext(); x != -1; x = ib.getNext()) + if ( (opand=opandmap[x]) != 0 ){ + if (opand->startOrExtend(instIndex + 1)) + ++registerPressure; + } + + // iterate over instructions towards the top of the block + + for (; inst != 0; inst = inst->getPrevInst()) + { + instIndex=inst->getIndex(); + const Opnd* opnd; + Opand* definedInCopyOpand = 0; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + opnd = opnds.getOpnd(it); + if ( (opand=opandmap[opnd->getId()]) != 0 ) + { + opand->weight += (size_t)(execCount * (registerPressure > (int)registers.size() ? 4 : 1)); +#ifdef _DEBUG_REGALLOC + dbgout << " Pressure: " << registerPressure << "/" << registers.size() << " Opand: " << *opand << endl; +#endif + + if (inst->isLiveRangeEnd(it)){ + opand->stop(instIndex + 1); + --registerPressure; + if (inst->getMnemonic() == Mnemonic_MOV) + definedInCopyOpand = opand; + }else{ + if (opand->startOrExtend(instIndex)){ + ++registerPressure; + if ( definedInCopyOpand != 0 && inst->getMnemonic() == Mnemonic_MOV && definedInCopyOpand->parentOpand == 0){ definedInCopyOpand->parentOpand = opand; - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << *definedInCopyOpand << " => " << *opand << endl; - } - } - } - } - } - if (registerPressure<0) // if there were dead defs - registerPressure=0; - } - } - - // process operands at the top of the block - inst = insts.getFirst(); - instIndex=inst->getIndex(); - LiveSet* tmp = irManager.getLiveAtEntry(node); - - ib.init(*tmp); - for (int x = ib.getNext(); x != -1; x = ib.getNext()) - if ( (opand=opandmap[x]) != 0 ){ - opand->stop(instIndex); - --registerPressure; - } - - if (registerPressure<0) // TODO: why? - registerPressure=0; - } - -// for each operand, sort all its intervals (spans) - - for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it) - if (*it != 0) - (*it)->update(); - - for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it){ - Opand * opand = *it; - if (opand != 0){ - int adj; - if (opand->parentOpand != 0 && - opand->length < opand->parentOpand->length && - opand->length < 3 && - !opand->conflict(opand->parentOpand, adj) - ){ - // can coalesce - if (opand->weight >= opand->parentOpand->weight){ - opand->weight = opand->parentOpand->weight; // make sure it is handled after its parent operand - ++opand->parentOpand->weight; - } - } - } - } - - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << endl << "opandmap" << endl; - for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it) - { - Log::out() << " "; - if (*it != 0) - Log::out() << **it; - else - Log::out() << "-"; - Log::out() << endl; - } - } +#ifdef _DEBUG_REGALLOC + dbgout << *definedInCopyOpand << " => " << *opand << endl; +#endif + } + } + } + } + if (registerPressure<0) // if there were dead defs + registerPressure=0; + } + } + + // process operands at the top of the block + inst = (Inst*)node->getFirstInst(); + instIndex=inst->getIndex(); + BitSet* tmp = irManager->getLiveAtEntry(node); + + ib.init(*tmp); + for (int x = ib.getNext(); x != -1; x = ib.getNext()) + if ( (opand=opandmap[x]) != 0 ){ + opand->stop(instIndex); + --registerPressure; + } + + if (registerPressure<0) // TODO: why? + registerPressure=0; + } + +#ifdef _SKIP_CATCHED + else if (node->isDispatchNode()) + { + BitSet* tmp = irManager->getLiveAtEntry(node); + BitSet::IterB ib(*tmp); + Opand* opand; + for (int x = ib.getNext(); x != -1; x = ib.getNext()) + if ( (opand=opandmap[x]) != 0 ) + { + opand->ignore = true; + DBGOUT("catched " << *opand << endl;) + } + } +#endif + } + +// for each operand, sort all its intervals (spans) + + for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it) + if (*it != 0) + (*it)->update(); + + for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it){ + Opand * opand = *it; + if (opand != 0){ + int adj; + if (opand->parentOpand != 0 && + opand->length < opand->parentOpand->length && + opand->length < 3 && + !opand->conflict(opand->parentOpand, adj) + ){ + // can coalesce + if (opand->weight >= opand->parentOpand->weight){ + opand->weight = opand->parentOpand->weight; // make sure it is handled after its parent operand + ++opand->parentOpand->weight; + } + } + } + } + +#ifdef _DEBUG_REGALLOC + dbgout << endl << "opandmap" << endl; + for (Opands::iterator it = opandmap.begin(); it != opandmap.end(); ++it) + { + dbgout << " "; + if (*it != 0) + dbgout << **it; + else + dbgout << "-"; + dbgout << endl; + } +#endif } -void RegAlloc2::allocateRegs () +void RegAlloc2::allocateRegs () { - if (Log::cat_cg()->isDebugEnabled()){ - Log::out() << endl << "allocateRegs" << endl; - } - - Opands opands(mm); - opands.reserve(opandmap.size()); - - Opand* nxt; - for (Opands::const_iterator i = opandmap.begin(); i != opandmap.end(); ++i){ - if ((nxt = *i) != 0 && nxt->assigned == 0) - opands.push_back(nxt); - } - - sort(opands.begin(), opands.end(), Opand::lighter); - - for (Opands::reverse_iterator i = opands.rbegin(); i != opands.rend(); ++i) - { - nxt = *i; - - DBGOUT(" nxt " << *nxt << endl;) - - // try to find free regsiter for opand 'nxt' - Register* better = 0; - Register* best = 0; - int bestadj = 0, adj=0; - - for (Registers::iterator k = registers.begin(); k != registers.end(); ++k) - if ((*k)->canBeAssigned(nxt, adj)) - { - DBGOUT(" found " << **k << " adj:" << adj << endl;) - - if (better == 0 || better->length < (*k)->length) - better = *k; - - if (adj != 0) - if (best == 0 || adj > bestadj) - best = *k, bestadj = adj; - } - - if (best == 0) - best = better; - - if (best != 0) - { - DBGOUT(" assigned " << *best << endl;) - best->assign(nxt); - nxt->opnd->assignRegName(best->regname); - } - } +#ifdef _DEBUG_REGALLOC + dbgout << endl << "allocateRegs" << endl; +#endif + + Opands opands(mm); + opands.reserve(opandmap.size()); + + Opand* nxt; + for (Opands::const_iterator i = opandmap.begin(); i != opandmap.end(); ++i){ + if ((nxt = *i) != 0 && nxt->assigned == 0 && !nxt->ignore) + opands.push_back(nxt); + } + + sort(opands.begin(), opands.end(), Opand::lighter); + + for (Opands::reverse_iterator i = opands.rbegin(); i != opands.rend(); ++i) + { + nxt = *i; + + DBGOUT(" nxt " << *nxt << endl;) + + // try to find free regsiter for opand 'nxt' + Register* better = 0; + Register* best = 0; + int bestadj = 0, adj=0; + + for (Registers::iterator k = registers.begin(); k != registers.end(); ++k) + if ((*k)->canBeAssigned(nxt, adj)) + { + DBGOUT(" found " << **k << " adj:" << adj << endl;) + + if (better == 0 || better->length < (*k)->length) + better = *k; + + if (adj != 0) + if (best == 0 || adj > bestadj) + best = *k, bestadj = adj; + } + + if (best == 0) + best = better; + + if (best != 0) + { + DBGOUT(" assigned " << *best << endl;) + best->assign(nxt); + nxt->opnd->assignRegName(best->regname); + ++count_assigned; + } + else + ++count_spilled; + } } diff --git vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.h vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.h deleted file mode 100644 index b9a38a4..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc2.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Sergey L. Ivashin - * @version $Revision: 1.8.22.3 $ - */ -#if !defined(__IA32REGALLOC_H_INCLUDED__) -#define __IA32REGALLOC_H_INCLUDED__ - -#include "Ia32IRManager.h" -#include "Stl.h" - - -namespace Jitrino -{ -namespace Ia32 -{ - - -//======================================================================================== -// class Ia32RegAlloc2 -//======================================================================================== - -/** - * This class attempts to assign register for any operand (found in LIR) that can be - * allocated in register. - * - * Set of registers available for allocation is specified by input arguments and saved - * in 'constrs' class member. All operands that cannot be allocated in the registers - * available are simply ignored. - * - * So this allocator should be called for each set of the registers available (GPReg, XMM, - * FP) independently. - * - * It is not guaranteed that all operands which can be assigned will be assigned. - * Therefore, the companion class (SpillGen) must be used after this allocator. - * - * The main idea behind the allocator is well-known bin packing algorithm, but this - * implementation is completely independent of any published algorithms. - */ - -BEGIN_DECLARE_IRTRANSFORMER(RegAlloc2, "bp_regalloc", "Bin-pack register allocator") - - RegAlloc2 (IRManager&, const char * params); - ~RegAlloc2 (); - - uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} - uint32 getSideEffects () const {return 0;} - - void runImpl(); - bool verify(bool force=false); - -//protected: - - typedef uint32 RegMask; // used to represent set of registers - typedef size_t Instnb; // used to describe instruction number - - struct Span; // interval of instructions not crossed basic block boundary - struct Opand; // extension of the 'Opnd' structure - struct Register; // holds all operands assigned to this register - - MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() - size_t opandcount; // total count of operands in LIR - Constraint constrs; // initial constraints (registers available) - - typedef StlVector<Register*> Registers; - Registers registers; - - typedef StlVector<Opand*> Opands; - Opands opandmap; // mapping Ia32Opnd.id -> Opand* - size_t candidateCount; - - void buildRegs (); - void buildOpands (); - void allocateRegs (); - Register* findReg (RegMask) const; - -END_DECLARE_IRTRANSFORMER(RegAlloc2) - - -} //namespace Ia32 -} //namespace Jitrino - -#endif // ifndef __IA32REGALLOC_H_INCLUDED__ diff --git vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp new file mode 100644 index 0000000..fdb16dc --- /dev/null +++ vm/jitrino/src/codegenerator/ia32/Ia32RegAlloc3.cpp @@ -0,0 +1,1164 @@ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + +#include "Ia32IRManager.h" +#include "Ia32RegAllocCheck.h" +#include "Stl.h" +#include "Log.h" +#include "Ia32Printer.h" +#include <algorithm> +#include <iostream> +#include <iomanip> +#include <sstream> +#include <stdio.h> + +#ifdef _DEBUG__REGALLOC3 +#include "Ia32RegAllocWrite.h" +#ifdef _MSC_VER +#pragma warning(disable : 4505) //unreferenced local function has been removed +#endif //#ifdef _MSC_VER +#endif //#ifdef _DEBUG__REGALLOC3 + + +// +// Flags to tune +// +#define _VAR2_ +#define _REGALLOC3_NEIGBH +//#define _REGALLOC3_COALESCE + + + +using namespace std; + +namespace Jitrino +{ + +namespace Ia32 +{ + + +//======================================================================================== +// class Ia32RegAlloc3 +//======================================================================================== + +/** + * This class attempts to assign register for any operand (found in LIR) that can be + * allocated in register. + * + * Set of registers available for allocation is specified by input arguments and saved + * in 'constrs' class member. All operands that cannot be allocated in the registers + * available are simply ignored. + * + * So this allocator should be called for each set of the registers available (GPReg, XMM, + * FP) independently. + * + * It is not guaranteed that all operands which can be assigned will be assigned. + * Therefore, the companion class (SpillGen) must be used after this allocator. + * + */ + +struct RegAlloc3 : public SessionAction +{ + MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() + + int coalesceCount; + + class BoolMatrix; + typedef uint32 RegMask; // used to represent set of registers + + static void merge (Constraint& c, RegMask mk) {c.setMask(c.getMask() | mk);} + + // Table of all available registers sets. + // Each set (GPReg, FPReg, XMMReg and so on) is represented by the corresponding + // Constraint object. + struct Registers : public StlVector<Constraint> + { + Registers (MemoryManager& mm) :StlVector<Constraint>(mm) {} + + void parse (const char*); + + // register the new constraint (register) in the table. + // if table doesn't contain constraint of the specified kind, it will be ignored + // (add = false) or new table entry for the constraint will be created (add = true). + int merge (const Constraint&, bool add = false); + + // returns table index of the constraint of the specified kind or -1 + int index (const Constraint&) const; + + int indexes[IRMaxRegKinds]; + }; + Registers registers; + + struct Oprole + { + Inst* inst; + uint32 role; + }; + typedef StlVector<Oprole> Oproles; + + struct Opndx + { + typedef StlList<int> Indexes; + Indexes* adjacents, + * hiddens; + + Indexes* neighbs; + + Opnd* opnd; + Oproles* oproles; + + int ridx; // index in Registers of register assigned/will be assigned + RegMask alloc, // 0 or mask of the register assigned + avail; // if not assigned, then mask of the registers available + int nbavails; // number of the registers available for this operand + int spillcost; + bool spilled; + }; + + // Operand's graph to be colored + struct Graph : public StlVector<Opndx> + { + Graph (MemoryManager& m) : StlVector<Opndx>(m), mm(m) {} + + void connect (int x1, int x2) const; + int disconnect (int x) const; + void reconnect (int x) const; + void moveNodes (Opndx::Indexes& from, Opndx::Indexes& to, int x) const; + + MemoryManager& mm; + }; + Graph graph; + + int graphsize; + + StlVector<int> nstack; + + + RegAlloc3 () : mm(1000, "RegAlloc3"), registers(mm), graph(mm), nstack(mm) {} + + uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} + uint32 getSideEffects () const {return coalesceCount == 0 ? 0 : SideEffect_InvalidatesLivenessInfo;} + + void runImpl(); + bool verify(bool force=false); + + bool buildGraph (); + bool coalescing (int* opandmap, BoolMatrix& matrix); + void coalesce (int* opandmap, BoolMatrix& matrix, int, int); + void pruneGraph (); + void assignRegs (); + bool assignReg (int); +}; + + +static ActionFactory<RegAlloc3> _cg_regalloc("cg_regalloc"); + + +static Counter<size_t> count_spilled("ia32:regalloc3:spilled", 0), + count_assigned("ia32:regalloc3:assigned", 0), + count_coalesced("ia32:regalloc3:coalesced", 0); + + +//======================================================================================== +// Internal debug helpers +//======================================================================================== + + +using std::endl; +using std::ostream; + +#ifdef _DEBUG__REGALLOC3 + +#include "Ia32RegAllocWrite.h" + +static void onConstruct (const IRManager&); +static void onDestruct (); + +struct Sep +{ + Sep () :first(true) {} + + bool first; +}; + +static ostream& operator << (ostream&, Sep&); + +static ostream& operator << (ostream&, const Inst&); + +static ostream& operator << (ostream&, const Opnd&); + +static ostream& operator << (ostream&, Constraint); + +static ostream& operator << (ostream&, const RegAlloc3::Registers&); + +struct RegMasks +{ + RegMasks (Constraint x, RegAlloc3::RegMask mk) : c(x) {c.setMask(mk);} + + Constraint c; +}; + +static ostream& operator << (ostream&, RegMasks); + +static ostream& outRegMasks (ostream&, RegAlloc3::RegMask*, const RegAlloc3::Registers&); + +static ostream& operator << (ostream&, const RegAlloc3::Opndx&); + +static ostream& operator << (ostream&, const RegAlloc3::Graph&); + +struct Dbgout : public ::std::ofstream +{ + Dbgout (const char* s) {open(s);} + ~Dbgout () {close();} +}; + +static Dbgout dbgout("RegAlloc3.txt"); + +#define DBGOUT(s) dbgout << s + +#else + +#define DBGOUT(s) + +#endif + + +//======================================================================================== +// Utility +//======================================================================================== + + +static size_t bitCount (RegAlloc3::RegMask mk) +{ + size_t count = 0; + while (mk != 0) + { + if ((mk & 1) != 0) + ++count; + mk >>= 1; + } + return count; +} + + +static size_t bitNumber (RegAlloc3::RegMask mk) +{ + assert(mk != 0); + + size_t number = 0; + while (mk != 1) + { + ++number; + mk >>= 1; + } + return number; +} + + +static RegAlloc3::RegMask findHighest (RegAlloc3::RegMask mk) +{ + assert(mk != 0); + + RegAlloc3::RegMask high = 1, + highest = (RegAlloc3::RegMask)~1; + + while ((mk & highest) != 0) + { + high <<= 1, + highest <<= 1; + } + + return high; +} + + +//======================================================================================== +// Tokens - Utility class for (zero-terminated) strings parsing +//======================================================================================== + + +class Tokens +{ +public: + + Tokens (const char* s) :src(s) {;} + + void init (const char* s) {src = s;} + bool scan (); + bool isWord () const {return isw;} + const char* lex () const {return buff;} + +protected: + + const char* src; + char* dst; + char buff[64]; + bool isw; +}; + +//======================================================================================== +// BoolMatrix - Symmetric boolean matrix +//======================================================================================== + + +class RegAlloc3::BoolMatrix +{ +public: + + BoolMatrix (MemoryManager&, int); + + void clear (); + void clear (int i, int j) {at(i,j) = 0;} + void set (int i, int j) {at(i,j) = 1;} + bool test (int i, int j) const {return at(i,j) != 0;} + +private: + + char& at (int i, int j) const + { + assert(0 <= i && i < dim && 0 <= j && j < dim && i != j); + + return (i < j) ? *(i*dim + j + ptr) + : *(j*dim + i + ptr); + } + + int dim, dims; + char* ptr; +}; + + +RegAlloc3::BoolMatrix::BoolMatrix (MemoryManager& mm, int d) +{ + assert(d > 0); + dim = d; + ptr = new (mm) char[dims = dim*dim]; + clear(); +} + + +void RegAlloc3::BoolMatrix::clear () +{ + memset(ptr, 0, dims); +} + + +//======================================================================================== +// Registers implementation +//======================================================================================== + + +// Parse input parameters (registers available) and build table of the regsiters +// available for allocalion ('registers'). +// +void RegAlloc3::Registers::parse (const char* params) +{ + if (params == 0 || strcmp(params, "ALL") == 0) + { + push_back(Constraint(RegName_EAX) + |Constraint(RegName_ECX) + |Constraint(RegName_EDX) + |Constraint(RegName_EBX) + |Constraint(RegName_ESI) + |Constraint(RegName_EDI) + |Constraint(RegName_EBP)); + + push_back(Constraint(RegName_XMM1) + |Constraint(RegName_XMM2) + |Constraint(RegName_XMM3) + |Constraint(RegName_XMM4) + |Constraint(RegName_XMM5) + |Constraint(RegName_XMM6) + |Constraint(RegName_XMM7)); + + push_back(Constraint(RegName_FP0)); + } + else + { + Constraint c; + for (Tokens t(params); t.scan(); ) + if (t.isWord()) + { + RegName r = getRegName(t.lex()); + if (r != RegName_Null) + c = Constraint(r); + + merge(c, true); + } + } + + assert(!empty()); + + for (size_t i = 0; i != IRMaxRegKinds; ++i) + indexes[i] = -1; + + for (size_t i = 0; i != size(); ++i) + indexes[operator[](i).getKind()] = i; +} + + +int RegAlloc3::Registers::merge (const Constraint& c, bool add) +{ + if (c.getMask() != 0) + { + for (size_t i = 0; i != size(); ++i) + { + Constraint& r = operator[](i); + if (r.getKind() == c.getKind()) + { + r.setMask(r.getMask() | c.getMask()); + return i; + } + } + + if (add) + push_back(c); + } + + return -1; +} + + +int RegAlloc3::Registers::index (const Constraint& c) const +{ + return indexes[c.getKind() & OpndKind_Reg]; +} + + +//======================================================================================== +// Graph implementation +//======================================================================================== + + +void RegAlloc3::Graph::connect (int x1, int x2) const +{ + at(x1).adjacents->push_back(x2); + at(x2).adjacents->push_back(x1); +} + + +int RegAlloc3::Graph::disconnect (int x) const +{ +// Node to be disconnected + const Opndx& opndx = at(x); + if (opndx.adjacents->empty()) + return 0; + + int disc = 0; + + for (Opndx::Indexes::iterator k = opndx.adjacents->begin(); k != opndx.adjacents->end(); ++k) + { + // this node is adjacent to the node to be disconnected + const Opndx& adjopndx = at(*k); + if (!adjopndx.adjacents->empty()) + { + moveNodes(*adjopndx.adjacents, *adjopndx.hiddens, x); + if (adjopndx.adjacents->empty()) + disc++; + } + } + + opndx.hiddens->splice(opndx.hiddens->begin(), *opndx.adjacents); + + return ++disc; +} + + +void RegAlloc3::Graph::reconnect (int x) const +{ +// Node to be reconnected + const Opndx& opndx = at(x); + + for (Opndx::Indexes::iterator k = opndx.hiddens->begin(); k != opndx.hiddens->end(); ++k) + { + // this node was adjacent to the node to be reconnected + const Opndx& adjopndx = at(*k); + moveNodes(*adjopndx.hiddens, *adjopndx.adjacents, x); + } + + opndx.adjacents->splice(opndx.adjacents->begin(), *opndx.hiddens); +} + + +void RegAlloc3::Graph::moveNodes (Opndx::Indexes& from, Opndx::Indexes& to, int x) const +{ + Opndx::Indexes::iterator i; + while ((i = find(from.begin(), from.end(), x)) != from.end()) + to.splice(to.begin(), from, i); +} + + +//======================================================================================== +// RegAlloc3 implementation +//======================================================================================== + + +void RegAlloc3::runImpl () +{ +#ifdef _DEBUG__REGALLOC3 + onConstruct(*irManager); +#endif + + irManager->fixEdgeProfile(); + + registers.parse(getArg("regs")); + DBGOUT("parameters: " << registers << endl;) + + coalesceCount = 0; + + if (buildGraph()) + { + +#ifdef _DEBUG__REGALLOC3 + dbgout << "--- graph" << endl; + for (int x = 0; x != graphsize; ++x) + { + const Opndx& opndx = graph.at(x); + dbgout << "(" << x << ") " << opndx.opnd->getId() + << " " << *opndx.opnd << " ridx:" << opndx.ridx + << " avail:" << hex << opndx.avail << dec << " nbavails:" << opndx.nbavails + << " spillcost:" << opndx.spillcost; + + if (!opndx.adjacents->empty()) + { + Sep s; + dbgout << " adjacents{"; + for (RegAlloc3::Opndx::Indexes::const_iterator i = opndx.adjacents->begin(); i != opndx.adjacents->end(); ++i) + dbgout << s << *i; + dbgout << "}"; + } + + if (opndx.neighbs != 0) + { + Sep s; + dbgout << " neighbs{"; + for (RegAlloc3::Opndx::Indexes::const_iterator i = opndx.neighbs->begin(); i != opndx.neighbs->end(); ++i) + dbgout << s << *i; + dbgout << "}"; + } + + dbgout << endl; + } + dbgout << "---------" << endl; +#endif + + pruneGraph(); + assignRegs(); + } + + count_coalesced += coalesceCount; + +#ifdef _DEBUG__REGALLOC3 + RegAllocWrite raw(*irManager, "regalloc3.xml"); + raw.write(); + + onDestruct(); +#endif +} + + +bool RegAlloc3::verify (bool force) +{ + bool failed = false; + if (force || getVerificationLevel() >=2 ) + { + RegAllocCheck chk(getIRManager()); + if (!chk.run(false)) + failed = true; + if (!SessionAction::verify(force)) + failed = true; + } + + return !failed; +} + + +bool RegAlloc3::buildGraph () +{ + size_t opandcount = getIRManager().getOpndCount(); + graph.reserve(opandcount); + +// First, scan all the operands available and see if operand is already assigned +// or need to be assigned + + Opndx opndx; + int* opandmap = new (mm) int[opandcount]; + + for (size_t i = 0; i != opandcount; ++i) + { + Opnd* opnd = getIRManager().getOpnd(i); + int mapto = -1; + + int ridx; + Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if (!loc.isNull()) + {// this operand is already assigned to some location/register + if ((ridx = registers.index(loc)) != -1) + { + opndx.opnd = opnd; + opndx.ridx = ridx; + opndx.alloc = loc.getMask(); + mapto = (int)graph.size(); + graph.push_back(opndx); + } + } + else + {// this operand is not allocated yet + loc = opnd->getConstraint(Opnd::ConstraintKind_Calculated, OpndSize_Default); + if ((ridx = registers.index(loc)) != -1) + {// operand should be assigned to register + opndx.opnd = opnd; + opndx.ridx = ridx; + opndx.alloc = 0; + opndx.avail = loc.getMask() & registers[ridx].getMask(); + opndx.nbavails = bitCount(opndx.avail); + assert(opndx.nbavails != 0); + opndx.spillcost = 1; + opndx.spilled = false; + mapto = (int)graph.size(); + graph.push_back(opndx); + } + } + + opandmap[i] = mapto; + } + + if ((graphsize = (int)graph.size()) == 0) + return false; + + for (Graph::iterator i = graph.begin(); i != graph.end(); ++i) + { + i->adjacents = new (mm) Opndx::Indexes(mm); + i->hiddens = new (mm) Opndx::Indexes(mm); + i->oproles = new (mm) Oproles(mm); + i->neighbs = 0; + } + +// Second, iterate over all instructions in CFG and calculate which operands +// are live simultaneouesly (result stored in matrix) + + BoolMatrix matrix(mm, graphsize); + + BitSet lives(mm, opandcount); + + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) + { + Inst* inst = (Inst*)node->getLastInst(); + if (inst == 0) + continue; + + int excount = static_cast<int>(node->getExecCount()); + if (excount < 1) + excount = 1; + excount *= 100; + //int excount = 1; + + // start with the operands at the block bottom + getIRManager().getLiveAtExit(node, lives); + + // iterate over instructions towards the top of the block + for (;;) + { + int i, x; +#ifdef _OLD_ + Inst::Opnds defs(inst, Inst::OpndRole_AllDefs); + for (Inst::Opnds::iterator it = defs.begin(); it != defs.end(); it = defs.next(it)) + if ((x = opandmap[i = inst->getOpnd(it)->getId()]) != -1) + { + BitSet::IterB bsk(lives); + int k, y; + for (k = bsk.getNext(); k != -1; k = bsk.getNext()) + if (k != i && (y = opandmap[k]) != -1) + matrix.set(x, y); + } +#else + int defx = -1; + Oprole oprole; + const uint32* oproles = const_cast<const Inst*>(inst)->getOpndRoles(); + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) + if ((x = opandmap[i = inst->getOpnd(it)->getId()]) != -1) + { + Opndx& opndx = graph.at(x); + + oprole.inst = inst; + oprole.role = oproles[it]; + opndx.oproles->push_back(oprole); + + if (oprole.role & Inst::OpndRole_Def) + { + defx = x; + BitSet::IterB bsk(lives); + int k, y; + for (k = bsk.getNext(); k != -1; k = bsk.getNext()) + if (k != i && (y = opandmap[k]) != -1) + matrix.set(x, y); + } +#ifdef _REGALLOC3_NEIGBH + else if (defx != -1 && !lives.getBit(opndx.opnd->getId())) + { + Opndx& defopndx = graph.at(defx); + if (defopndx.neighbs == 0) + defopndx.neighbs = new (mm) Opndx::Indexes(mm); + defopndx.neighbs->push_back(x); + + if (opndx.neighbs ==0) + opndx.neighbs = new (mm) Opndx::Indexes(mm); + opndx.neighbs->push_back(defx); + } +#endif + + opndx.spillcost += excount; + } +#endif + + if (inst->getPrevInst() == 0) + break; + + getIRManager().updateLiveness(inst, lives); + inst = inst->getPrevInst(); + } + } + } + +// Do iterative coalescing + +#ifdef _REGALLOC3_COALESCE + while (coalescing(opandmap, matrix)) + /*nothing*/; +#endif + +// Third, connect nodes that represent simultaneouesly live operands + + for (int x1 = 1; x1 < graphsize; ++x1) + for (int x2 = 0; x2 < x1; ++x2) + if (matrix.test(x1, x2) && graph.at(x1).ridx == graph.at(x2).ridx) + graph.connect(x1, x2); + + return true; +} + + +bool RegAlloc3::coalescing (int* opandmap, BoolMatrix& matrix) +{ + int x0, x1; + + const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) + { + for (const Inst* inst = (Inst*)node->getLastInst(); inst != 0; inst = inst->getPrevInst()) + if (inst->getMnemonic() == Mnemonic_MOV) + if ((x0 = opandmap[inst->getOpnd(0)->getId()]) != -1 && + (x1 = opandmap[inst->getOpnd(1)->getId()]) != -1 && + x0 != x1 && !matrix.test(x0, x1)) + { + Opndx& opndx0 = graph.at(x0), + & opndx1 = graph.at(x1); + + if (opndx0.ridx == opndx1.ridx && opndx0.avail == opndx1.avail) + { + coalesce (opandmap, matrix, x0, x1); + return true; + } + } + } + } + + return false; +} + + +// Colalesce graph nodes (x0) and (x1) and the corresponding operands. +// Node (x1) not to be used anymore, (x0) must be used unstead. +// Note that (x1) remains in the graph +// +void RegAlloc3::coalesce (int* opandmap, BoolMatrix& matrix, int x0, int x1) +{ + DBGOUT("*coalescing (" << x0 << ") with (" << x1 << ")" << endl;) + + Opndx& opndx0 = graph.at(x0), + & opndx1 = graph.at(x1); + + opndx1.spilled = true; + + Opnd* opnd0 = opndx0.opnd, + * opnd1 = opndx1.opnd; + + opandmap[opnd1->getId()] = x0; + + Oproles::iterator it = opndx1.oproles->begin(), + end = opndx1.oproles->end(); + for (; it != end; ++it) + it->inst->replaceOpnd(opnd1, opnd0); + + opndx0.oproles->reserve(opndx0.oproles->size() + opndx1.oproles->size()); + opndx0.oproles->insert(opndx0.oproles->end(), opndx1.oproles->begin(), opndx1.oproles->end()); + opndx1.oproles->clear(); + + for (int x = 0; x < graphsize; ++x) + if (x != x1 && matrix.test(x, x1)) + { + matrix.set(x, x0); + matrix.clear(x, x1); + } + + ++coalesceCount; +} + + +#ifndef _VAR0 + +struct sortRule1 +{ + const RegAlloc3::Graph& graph; + + + sortRule1 (const RegAlloc3::Graph& g) :graph(g) {} + + + bool operator () (int x1, int x2) + { + const RegAlloc3::Opndx& opndx1 = graph.at(x1), + & opndx2 = graph.at(x2); + +#ifdef _VAR1_ + return opndx1.spillcost > opndx2.spillcost; +#endif +#ifdef _VAR2_ + return opndx1.spillcost < opndx2.spillcost; +#endif + + } +}; + +#endif + + +void RegAlloc3::pruneGraph () +{ + DBGOUT(endl << "pruneGraph - start"<< endl;) + + size_t nbnodes = 0; + for (int i = 0; i != graphsize; ++i) + if (!graph.at(i).adjacents->empty()) + nbnodes++; + + StlVector<int> tmp(mm); + + nstack.reserve(nbnodes); + while (nbnodes != 0) + { + // Apply degree < R rule + +#ifdef _VAR0_ + + for (bool succ = false; !succ;) + { + succ = true; + for (int i = 0; i != graphsize; ++i) + { + Opndx& opndx = graph.at(i); + const int n = (int)opndx.adjacents->size(); + if (n != 0 && n < opndx.nbavails) + { + nbnodes -= graph.disconnect(i); + nstack.push_back(i); + succ = false; + + DBGOUT(" rule#1 (" << i << ")" << endl;) + } + } + + } + +#else + + for (bool succ = false; !succ;) + { + succ = true; + + tmp.resize(0); + + for (int i = 0; i != graphsize; ++i) + { + Opndx& opndx = graph.at(i); + const int n = (int)opndx.adjacents->size(); + if (n != 0 && n < opndx.nbavails) + tmp.push_back(i); + } + + if (tmp.size() != 0) + { + DBGOUT("buck size:" << tmp.size() << endl;) + if (tmp.size() > 1) + sort(tmp.begin(), tmp.end(), sortRule1(graph)); + + for (StlVector<int>::iterator it = tmp.begin(); it != tmp.end(); ++it) + { + nbnodes -= graph.disconnect(*it); + nstack.push_back(*it); + + DBGOUT(" rule#1 (" << *it << ") cost:" << graph.at(*it).spillcost << endl;) + } + + succ = false; + } + } + +#endif + + // Apply degree >= R rule + + if (nbnodes != 0) + { + int x = -1, n; + double cost = 0, w; + + // Find some node to disconnect + for (int i = 0; i != graphsize; ++i) + { + Opndx& opndx = graph.at(i); + if ((n = (int)opndx.adjacents->size()) != 0) + { + w = (double)opndx.spillcost/(double)n; + DBGOUT(" (" << i << ") cost:" << w << endl;) + if (x == -1 || w < cost) + cost = w, + x = i; + } + } + + assert(x != -1); + if (x != -1) + { + nbnodes -= graph.disconnect(x); + nstack.push_back(x); + + DBGOUT(" rule#2 (" << x << ") cost:" << cost << endl;) + } + } + } + + DBGOUT("pruneGraph - stop"<< endl << graph;) +} + + +void RegAlloc3::assignRegs () +{ + while (!nstack.empty()) + { + int x = nstack.back(); + nstack.pop_back(); + + Opndx& opndx = graph.at(x); + graph.reconnect(x); + opndx.spilled = !assignReg(x); + } + + for (int x = 0; x != graphsize; ++x) + { + Opndx& opndx = graph.at(x); + if (opndx.alloc == 0 && !opndx.spilled ) + assignReg(x); + } +} + + +bool RegAlloc3::assignReg (int x) +{ + Opndx& opndx = graph.at(x); + RegMask alloc = 0; + + for (Opndx::Indexes::iterator i = opndx.adjacents->begin(); i != opndx.adjacents->end(); ++i) + alloc |= graph.at(*i).alloc; + + if ((alloc = opndx.avail & ~alloc) == 0) + { + ++count_spilled; + DBGOUT("spilled (" << x << ")" << endl;) + return false; + } + else + { + if (opndx.neighbs != 0) + { + RegMask neighbs = 0; + for (Opndx::Indexes::iterator i = opndx.neighbs->begin(); i != opndx.neighbs->end(); ++i) + { + Opndx& neigbx = graph.at(*i); + if (neigbx.ridx == opndx.ridx) + neighbs |= neigbx.alloc; + } + + if ((neighbs & alloc) != 0 && neighbs != alloc) + { + DBGOUT("! alloc:" << std::hex << alloc << " * neighbs:" << neighbs << " =" << (alloc & neighbs) << std::dec << endl); + alloc &= neighbs; + } + } + + opndx.alloc = findHighest(alloc); + opndx.opnd->assignRegName(getRegName((OpndKind)registers[opndx.ridx].getKind(), + opndx.opnd->getSize(), + bitNumber(opndx.alloc))); + + ++count_assigned; + DBGOUT("assigned (" << x << ") = <" << getRegNameString(opndx.opnd->getRegName()) << ">" << endl;) + return true; + } +} + + +//======================================================================================== +// Internal debug helpers +//======================================================================================== + + +#ifdef _DEBUG__REGALLOC3 + +static void onConstruct (const IRManager& irm) +{ + MethodDesc& md = irm.getMethodDesc(); + const char * methodName = md.getName(); + const char * methodTypeName = md.getParentType()->getName(); + dbgout << endl << "Constructed " << methodTypeName << "." << methodName + << "(" << md.getSignatureString() << ")" << endl; + +// sos = strcmp(methodTypeName, "spec/benchmarks/_213_javac/BatchEnvironment") == 0 && +// strcmp(methodName, "flushErrors") == 0; +} + + +static void onDestruct () +{ + dbgout << endl << "Destructed" << endl; +} + +#endif //#ifdef _DEBUG__REGALLOC3 + + +//======================================================================================== +// Output formatters +//======================================================================================== + + +#ifdef _DEBUG__REGALLOC3 + +static ostream& operator << (ostream& os, Sep& x) +{ + if (x.first) + x.first = false; + else + os << ","; + return os; +} + +static ostream& operator << (ostream& os, const Inst& x) +{ + return os << "I#" << x.getId(); +} + + +static ostream& operator << (ostream& os, const Opnd& x) +{ + os << "O#" << x.getFirstId(); + RegName rn = x.getRegName(); + if (rn != RegName_Null) + os << "<" << getRegNameString(rn) << ">"; + if (x.isPlacedIn(OpndKind_Memory)) + os << "<mem>"; + return os; +} + + +static ostream& operator << (ostream& os, Constraint c) +{ + IRPrinter::printConstraint(os, c); + return os; +} + + +static ostream& operator << (ostream& os, const RegAlloc3::Registers& x) +{ + Sep s;; + os << "{"; + for (RegAlloc3::Registers::const_iterator it = x.begin(); it != x.end(); ++it) + os << s << *it; + return os << "}"; +} + + +static ostream& operator << (ostream& os, RegMasks x) +{ + return os << x.c; +} + + +static ostream& outRegMasks (ostream& os, RegAlloc3::RegMask* x, const RegAlloc3::Registers& registers) +{ + Sep s;; + os << "{"; + for (size_t rk = 0; rk != registers.size(); ++rk) + { + RegAlloc3::RegMask msk = x[rk]; + + for (size_t rx = 0; msk != 0; ++rx, msk >>= 1) + if ((msk & 1) != 0) + { + RegName reg = getRegName((OpndKind)registers[rk].getKind(), registers[rk].getSize(), rx); + os<< s << getRegNameString(reg); + } + } + return os << "}"; +} + + +static ostream& operator << (ostream& os, const RegAlloc3::Opndx& opndx) +{ + RegName reg; + if ((reg = opndx.opnd->getRegName()) != RegName_Null) + os << " <" << getRegNameString(reg) << ">"; + + if (!opndx.adjacents->empty()) + { + Sep s; + os << " adjacents{"; + for (RegAlloc3::Opndx::Indexes::const_iterator i = opndx.adjacents->begin(); i != opndx.adjacents->end(); ++i) + os << s << *i; + os << "}"; + } + + if (!opndx.hiddens->empty()) + { + Sep s; + os << " hiddens{"; + for (RegAlloc3::Opndx::Indexes::const_iterator i = opndx.hiddens->begin(); i != opndx.hiddens->end(); ++i) + os << s << *i; + os << "}"; + } + + return os; +} + + +static ostream& operator << (ostream& os, const RegAlloc3::Graph& graph) +{ + int x = 0; + for (RegAlloc3::Graph::const_iterator i = graph.begin(); i != graph.end(); ++i) + os << x++ << ") " << *i << endl; + + return os; +} + + +#endif //#ifdef _DEBUG__REGALLOC3 + +} //namespace Ia32 +} //namespace Jitrino diff --git vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.cpp vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.cpp index 35f174d..a6e6235 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.cpp @@ -20,14 +20,12 @@ #include "Ia32RegAllocCheck.h" #include "Log.h" -#include "Timer.h" +#include "XTimer.h" namespace Jitrino { -Timer * regAllocCheckTimer=NULL; - namespace Ia32 { @@ -42,19 +40,19 @@ using ::std::ostream; static ostream& operator << (ostream& os, const Inst& x) { - return os << "I#" << x.getId(); + return os << "I#" << x.getId(); } static ostream& operator << (ostream& os, const Opnd& x) { - return os << "O#" << x.getFirstId(); + return os << "O#" << x.getFirstId(); } static ostream& operator << (ostream& os, RegName x) { - return os << getRegNameString(x); + return os << getRegNameString(x); } @@ -64,32 +62,34 @@ static ostream& operator << (ostream& os bool RegAllocCheck::run (bool checkloc) { - PhaseTimer tm(regAllocCheckTimer, "ia32::regAllocCheck"); + static CountTime regAllocCheckTimer("ia32::regAllocCheck"); + AutoTimer tm(regAllocCheckTimer); - opandcount = irm.getOpndCount(); - errors = 0; - headprinted = false; + opandcount = irm.getOpndCount(); + errors = 0; + headprinted = false; - if (checkloc) - checkLocations(); + if (checkloc) + checkLocations(); - const Node* node; - for (CFG::NodeIterator it(irm); (node = it.getNode()) != 0; ++it) - if (node->hasKind(Node::Kind_BasicBlock)) - { - bblock = static_cast<const BasicBlock*>(node); - binsts = &bblock->getInsts(); - checkLiveness(); - checkConstraints(); - } + const Nodes& nodes = irm.getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) + { + bblock = node; + checkLiveness(); + checkConstraints(); + } + } - if (errors != 0) - header() << endl << "ERRORS DETECTED: " << errors << endl; - else if (Log::cat_cg()->isDebugEnabled()) - header() << endl << "No errors detected" << endl; + if (errors != 0) + header() << endl << "ERRORS DETECTED: " << errors << endl; + else if (Log::isEnabled()) + header() << endl << "No errors detected" << endl; - return errors == 0; -} + return errors == 0; +} const size_t MaxRegs = IRMaxRegNamesSameKind*IRMaxRegKinds; @@ -97,206 +97,208 @@ const size_t MaxRegs = IRMaxRegNamesSame static RegName regName (int x) { - size_t k = x / IRMaxRegNamesSameKind; - return getRegName((OpndKind)k, Constraint::getDefaultSize(k), x % IRMaxRegNamesSameKind); + size_t k = x / IRMaxRegNamesSameKind; + return getRegName((OpndKind)k, Constraint::getDefaultSize(k), x % IRMaxRegNamesSameKind); } static size_t regIdx (const Opnd* opnd) { - RegName rn; - if ((rn = opnd->getRegName()) == RegName_Null) - return MaxRegs; + RegName rn; + if ((rn = opnd->getRegName()) == RegName_Null) + return MaxRegs; - size_t x = getRegIndex(rn), - k = getRegKind(rn); + size_t x = getRegIndex(rn), + k = getRegKind(rn); - assert(x < IRMaxRegNamesSameKind && k < IRMaxRegKinds); + assert(x < IRMaxRegNamesSameKind && k < IRMaxRegKinds); - return k*IRMaxRegNamesSameKind + x; + return k*IRMaxRegNamesSameKind + x; } void RegAllocCheck::checkLiveness () { - lastbb = 0; - - LiveSet lives(mm, opandcount); - irm.getLiveAtExit(bblock, lives); - - Opnd* regdefs[MaxRegs], - * reguses[MaxRegs], - * regnxts[MaxRegs]; - - size_t ridx; - - for (ridx = 0; ridx != MaxRegs; ++ridx) - regdefs[ridx] = 0, - reguses[ridx] = 0, - regnxts[ridx] = 0; - - Opnd* opnd; - LiveSet::IterB ls(lives); - for (int i = ls.getNext(); i != -1; i = ls.getNext()) - { - opnd = irm.getOpnd(i); - if ((ridx = regIdx(opnd)) < MaxRegs) - { - if (regnxts[ridx] == 0) - regnxts[ridx] = opnd; - else - if (regnxts[ridx] != opnd) - { - error() << "at end of block," << regName(ridx) - << " assigned to " << *regnxts[ridx] << " and " << *opnd << endl; - } - } - } - -// iterate over instructions towards the top of the block - - for (const Inst* inst = binsts->getLast(); inst != 0; inst = binsts->getPrev(inst)) - { - const uint32 props = inst->getProperties(); - - // In general, operands can be stored in arbitrary order - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ - opnd = opnds.getOpnd(it); - if ((ridx = regIdx(opnd)) < MaxRegs) - { - const uint32 roles = inst->getOpndRoles(it); - - if ((roles & Inst::OpndRole_Def) != 0) - { - if (regdefs[ridx] == 0) - regdefs[ridx] = opnd; - else - if (regdefs[ridx] != opnd) - { - error() << " Invalid definitions at " << *inst << " " << regName(ridx) - << " of " << *regdefs[ridx] << " or " << *opnd << endl; - } - } - - if ((roles & Inst::OpndRole_Use) != 0) - { - if (reguses[ridx] == 0) - reguses[ridx] = opnd; - else - if (reguses[ridx] != opnd) - { - error() << " Invalid usages at " << *inst << " " << regName(ridx) - << " of " << *reguses[ridx] << " or " << *opnd << endl; - } - } - } - } - for (ridx = 0; ridx != MaxRegs; ++ridx) - { - if (regdefs[ridx] != 0) - { - // conditional definitions are ignored - if ((props & Inst::Properties_Conditional) == 0) - { - if (regdefs[ridx] != regnxts[ridx]) - if (regnxts[ridx] != 0) - { - error() << " " << *inst << " " << regName(ridx) - << " invalid usage of " << *regnxts[ridx] - << " instead of " << *regdefs[ridx] << endl; - } - else - { - // dead def - } - - regnxts[ridx] = 0; // this register can used in the instruction - } - } - - else if (reguses[ridx] != 0) - { - if (reguses[ridx] != regnxts[ridx] && regnxts[ridx] != 0) - { - error() << " " << *inst << " " << regName(ridx) - << " invalid usage of " << *reguses[ridx] - << " or " << *regnxts[ridx] << endl; - } - - regnxts[ridx] = reguses[ridx]; - } - - // clear for next instruction to be processed - regdefs[ridx] = 0; - reguses[ridx] = 0; - } - } + lastbb = 0; + + BitSet lives(mm, opandcount); + irm.getLiveAtExit(bblock, lives); + + Opnd* regdefs[MaxRegs], + * reguses[MaxRegs], + * regnxts[MaxRegs]; + + size_t ridx; + + for (ridx = 0; ridx != MaxRegs; ++ridx) + regdefs[ridx] = 0, + reguses[ridx] = 0, + regnxts[ridx] = 0; + + Opnd* opnd; + BitSet::IterB ls(lives); + for (int i = ls.getNext(); i != -1; i = ls.getNext()) + { + opnd = irm.getOpnd(i); + if ((ridx = regIdx(opnd)) < MaxRegs) + { + if (regnxts[ridx] == 0) + regnxts[ridx] = opnd; + else + if (regnxts[ridx] != opnd) + { + error() << "at end of block," << regName(ridx) + << " assigned to " << *regnxts[ridx] << " and " << *opnd << endl; + } + } + } + +// iterate over instructions towards the top of the block + + for (Inst* inst = (Inst*)bblock->getLastInst(); inst != 0; inst = inst->getPrevInst()) + { + const uint32 props = inst->getProperties(); + + // In general, operands can be stored in arbitrary order + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ + opnd = opnds.getOpnd(it); + if ((ridx = regIdx(opnd)) < MaxRegs) + { + const uint32 roles = inst->getOpndRoles(it); + + if ((roles & Inst::OpndRole_Def) != 0) + { + if (regdefs[ridx] == 0) + regdefs[ridx] = opnd; + else + if (regdefs[ridx] != opnd) + { + error() << " Invalid definitions at " << *inst << " " << regName(ridx) + << " of " << *regdefs[ridx] << " or " << *opnd << endl; + } + } + + if ((roles & Inst::OpndRole_Use) != 0) + { + if (reguses[ridx] == 0) + reguses[ridx] = opnd; + else + if (reguses[ridx] != opnd) + { + error() << " Invalid usages at " << *inst << " " << regName(ridx) + << " of " << *reguses[ridx] << " or " << *opnd << endl; + } + } + } + } + for (ridx = 0; ridx != MaxRegs; ++ridx) + { + if (regdefs[ridx] != 0) + { + // conditional definitions are ignored + if ((props & Inst::Properties_Conditional) == 0) + { + if (regdefs[ridx] != regnxts[ridx]) + if (regnxts[ridx] != 0) + { + error() << " " << *inst << " " << regName(ridx) + << " invalid usage of " << *regnxts[ridx] + << " instead of " << *regdefs[ridx] << endl; + } + else + { + // dead def + } + + regnxts[ridx] = 0; // this register can used in the instruction + } + } + + else if (reguses[ridx] != 0) + { + if (reguses[ridx] != regnxts[ridx] && regnxts[ridx] != 0) + { + error() << " " << *inst << " " << regName(ridx) + << " invalid usage of " << *reguses[ridx] + << " or " << *regnxts[ridx] << endl; + } + + regnxts[ridx] = reguses[ridx]; + } + + // clear for next instruction to be processed + regdefs[ridx] = 0; + reguses[ridx] = 0; + } + } } void RegAllocCheck::checkLocations () { - for (size_t i = 0; i != opandcount; ++i) - { - Opnd* opnd = irm.getOpnd(i); - if (!opnd->hasAssignedPhysicalLocation()) - { - header() << "Not assigned opand " << *opnd << endl; - errors++; - } - } + for (size_t i = 0; i != opandcount; ++i) + { + Opnd* opnd = irm.getOpnd(i); + if (!opnd->hasAssignedPhysicalLocation()) + { + header() << "Not assigned opand " << *opnd << endl; + errors++; + } + } } void RegAllocCheck::checkConstraints () { - lastbb = 0; - for (const Inst* inst = binsts->getFirst(); inst != 0; inst = binsts->getNext(inst)) - { - Opnd* opnd; - Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) - { - opnd = opnds.getOpnd(it); - Constraint cloc = opnd->getConstraint(Opnd::ConstraintKind_Location); - Constraint c = inst->getConstraint(Inst::ConstraintKind_Current, it, cloc.getSize()); - if (!cloc.isNull()) - if (c.getSize() == cloc.getSize() && !c.contains(cloc)) - error() << "Constraint error " << *inst << " " << *opnd << endl; - } - } + lastbb = 0; + for (const Inst* inst = (Inst*)bblock->getFirstInst(); inst != 0; inst = inst->getNextInst()) + { + Opnd* opnd; + Inst::Opnds opnds(inst, Inst::OpndRole_AllDefs); + uint32 mask = 0; + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) + { + opnd = opnds.getOpnd(it); + Constraint cloc = opnd->getConstraint(Opnd::ConstraintKind_Location); + mask |= 1<<it; + Constraint c = ((Inst *)inst)->getConstraint(it, mask, cloc.getSize()); + if (!cloc.isNull()) + if (c.getSize() == cloc.getSize() && !c.contains(cloc)) + error() << "Constraint error " << *inst << " " << *opnd << endl; + } + } } ostream& RegAllocCheck::error () { - if (lastbb != bblock) - { - lastbb = bblock; - header() << "BasicBlock " << bblock->getId() - << "[" << binsts->getFirst()->getId() << " .. " - << binsts->getLast() ->getId() << "]" - << endl ; - } - errors++; - return Log::out(); + if (lastbb != bblock) + { + lastbb = bblock; + header() << "BasicBlock " << bblock->getId() + << "[" << ((Inst*)bblock->getFirstInst())->getId() << " .. " + << ((Inst*)bblock->getLastInst())->getId() << "]" + << endl ; + } + errors++; + return Log::out(); } ostream& RegAllocCheck::header () { - if (!headprinted) - { - headprinted = true; - - MethodDesc& md=irm.getMethodDesc(); - Log::out() << endl << "RegAllocCheck for " - << md.getParentType()->getName() - << "." << md.getName() << "(" << md.getSignatureString() << ")" - << endl; - } - return Log::out(); + if (!headprinted) + { + headprinted = true; + + MethodDesc& md=irm.getMethodDesc(); + Log::out() << endl << "RegAllocCheck for " + << md.getParentType()->getName() + << "." << md.getName() << "(" << md.getSignatureString() << ")" + << endl; + } + return Log::out(); } diff --git vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.h vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.h index 9581d51..57c0499 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.h +++ vm/jitrino/src/codegenerator/ia32/Ia32RegAllocCheck.h @@ -34,15 +34,15 @@ namespace Ia32 // class RegAllocCheck //======================================================================================== /** - * This class used for debug purposes; + * This class used for debug purposes; * - * (1) It checks that there are no two operands which are assigned to the same + * (1) It checks that there are no two operands which are assigned to the same * regsiter and both are alive at some instruction. * * (2) It checks that the operand assignment is consistent with the operand constraint. * - * (3) (if enabled by 'checkloc' argument) It checks that all operands are assigned - * to memory or register. + * (3) (if enabled by 'checkloc' argument) It checks that all operands are assigned + * to memory or register. * */ @@ -50,29 +50,28 @@ class RegAllocCheck { public: - - RegAllocCheck (const IRManager& x) :irm(x), mm(1000, "RegAllocCheck") {} + + RegAllocCheck (const IRManager& x) :irm(x), mm(1000, "RegAllocCheck") {} - bool run (bool checkloc); + bool run (bool checkloc); protected: - typedef uint32 RegMask; + typedef uint32 RegMask; - const IRManager& irm; - MemoryManager mm; - size_t opandcount; - const BasicBlock* bblock; - const Insts* binsts; - const BasicBlock* lastbb; - bool headprinted; - int errors; + const IRManager& irm; + MemoryManager mm; + size_t opandcount; + const Node* bblock; + const Node* lastbb; + bool headprinted; + int errors; - void checkLiveness (); - void checkLocations (); - void checkConstraints (); - ::std::ostream& error (); - ::std::ostream& header (); + void checkLiveness (); + void checkLocations (); + void checkConstraints (); + ::std::ostream& error (); + ::std::ostream& header (); }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp index 67c00e4..497b7f7 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.cpp @@ -30,8 +30,12 @@ namespace Jitrino namespace Ia32{ void RuntimeInterface::unwindStack(MethodDesc* methodDesc, JitFrameContext* context, bool isFirst) { - StackInfo stackInfo; + StackInfo stackInfo; +#ifdef _EM64T_ + stackInfo.read(methodDesc, *context->p_rip, isFirst); +#else stackInfo.read(methodDesc, *context->p_eip, isFirst); +#endif stackInfo.unwind(methodDesc, context, isFirst); } @@ -41,19 +45,28 @@ void* RuntimeInterface::getAddressOfThis static const uint64 default_this=0; return (void*)&default_this; } - assert(context); - StackInfo stackInfo; + assert(context); + StackInfo stackInfo; +#ifdef _EM64T_ + stackInfo.read(methodDesc, *context->p_rip, isFirst); + assert(isFirst || (POINTER_SIZE_INT)context->p_rip+8 == context->rsp); + return (void *)(context->rsp + stackInfo.getStackDepth() + (int)stackInfo.getOffsetOfThis()); +#else stackInfo.read(methodDesc, *context->p_eip, isFirst); - - assert(isFirst || (uint32)context->p_eip+4 == context->esp); - return (void *)(context->esp + stackInfo.getStackDepth() + stackInfo.getOffsetOfThis()); + assert(isFirst || (uint32)context->p_eip+4 == context->esp); + return (void *)(context->esp + stackInfo.getStackDepth() + stackInfo.getOffsetOfThis()); +#endif } void RuntimeInterface::fixHandlerContext(MethodDesc* methodDesc, JitFrameContext* context, bool isFirst) { - StackInfo stackInfo; + StackInfo stackInfo; +#ifdef _EM64T_ + stackInfo.read(methodDesc, *context->p_rip, isFirst); +#else stackInfo.read(methodDesc, *context->p_eip, isFirst); - stackInfo.fixHandlerContext(context); +#endif + stackInfo.fixHandlerContext(context); } bool RuntimeInterface::getBcLocationForNative(MethodDesc* method, uint64 native_pc, uint16 *bc_pc) @@ -70,9 +83,9 @@ bool RuntimeInterface::getBcLocationForN if (bcOffset != ILLEGAL_VALUE) { *bc_pc = (uint16)bcOffset; return true; - } else if (Log::cat_rt()->isWarnEnabled()) { + } else if (Log::isLogEnabled(LogStream::RT)) { methName = method->getName(); - Log::cat_rt()->out() << "Byte code for method: " << methName << " IP = " << native_pc + Log::log(LogStream::RT) << "Byte code for method: " << methName << " IP = " << native_pc << " not found " << std::endl; } return false; @@ -90,21 +103,26 @@ bool RuntimeInterface::getNativeLocation if (ncAddr != ILLEGAL_VALUE) { *native_pc = ncAddr; return true; - } else if (Log::cat_rt()->isWarnEnabled()) { + } else if (Log::isLogEnabled(LogStream::RT)) { methName = method->getName(); - Log::cat_rt()->out() << "Byte code for method: " << methName << " IP = " << native_pc + Log::log(LogStream::RT) << "Byte code for method: " << methName << " IP = " << native_pc << " not found " << std::endl; } return false; } -uint32 RuntimeInterface::getInlineDepth(InlineInfoPtr ptr, uint32 offset) { +uint32 RuntimeInterface::getInlineDepth(InlineInfoPtr ptr, uint32 offset) { return InlineInfoMap::get_inline_depth(ptr, offset); } -Method_Handle RuntimeInterface::getInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { +Method_Handle RuntimeInterface::getInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { return InlineInfoMap::get_inlined_method(ptr, offset, inline_depth); } +uint16 RuntimeInterface::getInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { + return InlineInfoMap::get_inlined_bc(ptr, offset, inline_depth); +} + + }}; //namespace Ia32 diff --git vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.h vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.h index 3040a78..01bffe4 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.h +++ vm/jitrino/src/codegenerator/ia32/Ia32RuntimeInterface.h @@ -39,14 +39,14 @@ stack unwinding, root set enumeration, a */ - class RuntimeInterface : public ::Jitrino::RuntimeInterface { + class RuntimeInterface : public ::Jitrino::RuntimeInterface { public: virtual void unwindStack(MethodDesc* methodDesc, JitFrameContext* context, bool isFirst) ; virtual void getGCRootSet(MethodDesc* methodDesc, GCInterface* gcInterface, - const JitFrameContext* context, bool isFirst); + const JitFrameContext* context, bool isFirst); - virtual bool canEnumerate(MethodDesc* methodDesc, NativeCodePtr eip); + virtual bool canEnumerate(MethodDesc* methodDesc, NativeCodePtr eip); virtual void fixHandlerContext(MethodDesc* methodDesc, JitFrameContext* context, bool isFirst); @@ -63,6 +63,7 @@ public: virtual uint32 getInlineDepth(InlineInfoPtr ptr, uint32 offset); virtual Method_Handle getInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth); + virtual uint16 getInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth); }; diff --git vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.cpp vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.cpp index 72f60fa..d288c8d 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.cpp @@ -18,18 +18,15 @@ * @version $Revision: 1.16.12.2.4.3 $ */ -#include "Ia32SpillGen.h" +#include "Ia32IRManager.h" #include "Ia32RegAllocCheck.h" #include "XTimer.h" #include "Counter.h" -//#include "algorithm" #include "Stl.h" #ifdef _DEBUG_SPILLGEN #include "Ia32SpillGenDbg.h" -#else -#define DBGOUT(s) -#endif +#endif //#ifdef _DEBUG_SPILLGEN namespace Jitrino @@ -37,1685 +34,1891 @@ namespace Jitrino namespace Ia32 { +static const char* help = +" regs=ALL\n" +" regs=<comma-separated list of available registers, e.g EAX,ECX,XMM0,>\n" +; -// Utility class for (zero-terminated) strings parsing -// -class Tokens -{ -public: - - Tokens (const char* s) :src(s) {;} - void init (const char* s) {src = s;} - bool scan (); - bool isWord () const {return isw;} - const char* lex () const {return buff;} +struct SpillGen : public SessionAction +{ -protected: +// Inter-blocks data +// ----------------- + + typedef uint32 RegMask; + typedef StlVector<Opnd*> Opnds; + + MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() + + // Table of all available registers sets. + // Each set (GPReg, FPReg, XMMReg and so on) is represented by the corresponding + // Constraint object. + struct Registers : public StlVector<Constraint> + { + Registers (MemoryManager& mm) :StlVector<Constraint>(mm) {} + + void parse (const char*); + + // clear mask fields in all elements of the table + void clearMasks (); + + void merge (const Registers&); + + // register the new constraint (register) in the table. + // if table doesn't contain constraint of the specified kind, it will be ignored + // (add = false) or new table entry for the constraint will be created (add = true). + int merge (const Constraint&, bool add = false); + + // returns table index of the constraint of the specified kind or -1 + int getIndex (const Constraint&) const; + + // returns pointer to the table element of the specified kind + Constraint* contains (const Constraint&); + + int indexes[IRMaxRegKinds]; + }; + Registers registers; + + size_t opndcount; // initial count of operands + size_t emitted; // extra instructions count + size_t fails; // if != 0, then SpillGen should be aborted + + // mapping operand -> its memory location + // every operand that was splitted to memory is registered in this table + typedef ::std::pair<const Opnd*, Opnd*> TwoOpnds; + typedef StlVector<TwoOpnds> MemOpnds; + MemOpnds memopnds; + + +// Block-specific data +// ------------------- + + enum + { + RoleDef = 1, + RoleUse = 2, + RoleCond = 4, // if (RoleCond == true) RoleUse = true; + RoleEnd = 8 + }; + typedef char OpRole; + + // extension of 'Inst' structure with some specific data + struct Instx + { + Instx () : nbopnds(0), evicts(0) {} + + Inst* inst; // pointer to the corresponding instruction + size_t nbopnds; // max number of operands in instruction + OpRole* oproles; // array of nbopnds size + Opnds* evicts; // can be null, can contain null pointers + RegMask regusage[IRMaxRegKinds];// masks of all registers that are busy at this instruction + RegMask regpress[IRMaxRegKinds]; + }; + + typedef StlVector<Instx> Instxs; + Instxs instxs; + + // created for all problem (needed to be allocated) operands + + struct Op + { + Instx* instx; + OpRole oprole; + }; + + + struct Opline + { + Opline () : ops(0) {} + + void clear (MemoryManager&); + void addOp (Instx*, OpRole); + + // iterator methods, work with the current instruction only + void start (); + void forw (); + void back (const Instx*); + bool go () const {return op != 0;} + bool isDef () const {return op->instx == instx && (op->oprole & RoleDef) != 0;} + bool isUse () const {return op->instx == instx && (op->oprole & RoleUse) != 0;} + bool isEnd () const {return op->instx == instx && (op->oprole & RoleEnd) != 0;} + bool isProc() const {return op->instx == instx;} + + // work with the specified instruction + bool isDef (const Inst*) const; + bool isUse (const Inst*) const; + + + bool at_start, // 'true' if this operand lives at the BB entry + at_exit, // 'true' if this operand lives at the BB exit + catched; // 'true' if this operand lives at entry to dispatch node + int idx; // -1 or index of the corresponding constraint in 'registers' array + Opnd* opnd; // original form of operand + Opnd* opnd_mem; // 0 or memory form of the operand (cached copy of the value from 'memopnds' array) + Instx* save_instx; // 0 or point where instruction to save operand should be inserted + bool save_before; // true if save must be before instruction (false is the default) + Opnd* save_opnd; // which operand should be saved + RegMask save_regmsk; + int save_regidx; + bool save_changed; + + typedef StlVector<Op> Ops; + Ops* ops; // array of all instructions that change/use value of the operand + + // current instruction + Op* op; + Instx* instx; + + static bool smaller (const Opline& x, const Opline& y) {return x.weight < y.weight;} + + Constraint initial; + int weight; + }; + + + typedef StlVector<Opline> Oplines; + Oplines actives; + StlVector<Opline*> actsmap; + + struct Evict; + typedef StlVector<Evict> Evicts; + + // current context + Node* bblock; // the basic block being processed + BitSet* lives_start, // liveness info for start and end of the block + * lives_exit; // + BitSet* lives_catch; // 0 or mask of operands live at the corresponding dispatch node + + bool evicts_known; + + +// Methods +// ------- + + + SpillGen () : mm(1000, "SpillGen") + , registers(mm), memopnds(mm) + , instxs(mm), actives(mm), actsmap(mm) + , lives_start(0), lives_exit(0) + {} + + uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} + uint32 getSideEffects () const {return SideEffect_InvalidatesLivenessInfo;} + + void runImpl(); + bool verify(bool force=false); + + size_t pass0 (); + size_t pass1 (); + RegMask lookPreffered (Opline&); + bool tryRegister (Opline&, Constraint, RegMask); + bool tryMemory (Opline&, Constraint); + bool tryEvict (Opline&, Constraint); + bool tryRepair (Opline&, Constraint); + bool simplify (Inst*, Opnd*); + RegMask usedRegs (const Instx*, int idx, bool isuse) const; + RegMask callRegs (const Instx*, int idx) const; + int update (const Inst*, const Opnd*, Constraint&) const; + void assignReg (Opline&, Instx* begx, Instx* endx, RegName); + void assignMem (Opline&, Instx* begx, Instx* endx); + void saveOpnd (Opline&, Instx*, Opnd*); + void saveOpnd (Opline&, Instx*, Opnd*, RegMask, int, bool); +#ifdef _OLD_ + void loadOpnd (Opline&, Instx*, Opnd*); +#else + bool loadOpnd (Opline&, Instx*, Opnd*); +#endif + void loadOpndMem (Opline&); + Opnd* opndMem (Opline&); + Opnd* opndMem (const Opnd*); + Opnd* opndReg (const Opnd*, RegName) const; + void emitPushPop (bool before, Inst*, Opnd* opnd, bool push); + Inst* emitMove (bool before, Inst*, Opnd* dst, Opnd* src); + RegName findFree (RegMask usable, int idx, Instx* begx); + RegName findEvict (RegMask usable, int idx, Instx* begx, Instx*& endx); + void setupEvicts (); + Evict* pickEvict (Evicts&); + bool isEvict (const Opnd*, const Instx*) const; + void killEvict (const Opnd*, Instx*) const; + RegMask getRegMaskConstr (const Opnd*, Constraint) const; - const char* src; - char* dst; - char buff[64]; - bool isw; }; -// Return 'false' if end of parsing string is reached and 'true' otherwise. -// isWord() will specify was it word or separator (one character). -// lex() will return zero-terminated lexem string scanned (for word or separator). -// -bool Tokens::scan () -{ - while (isspace(*src)) - src++; - - if (*src == 0) - return false; - - dst = buff; - isw = isalnum(*src) != 0; - if (!isw) - *dst++ = *src++; - else - while (isalnum(*src)) - { - assert(dst != &buff[sizeof(buff)-1]); - *dst++ = *src++; - } - - *dst = 0; - return true; -} +static ActionFactory<SpillGen> _spillgen("spillgen", help); -enum -{ - RoleDef = 1, - RoleUse = 2, - RoleCond = 4, // if (RoleCond == true) RoleUse = true; - RoleEnd = 8 -}; -typedef char OpRole; +#ifdef _DEBUG_SPILLGEN +#ifdef _MSC_VER +#pragma warning(disable : 4505) //unreferenced local function has been removed +#else +#endif //#ifdef _MSC_VER +#include "Ia32SpillGenDbgHead.h" +#else +#define DBGOUT(s) +#endif //#ifdef _DEBUG_SPILLGEN -const int MAXREGS = IRMaxRegNamesSameKind*IRMaxRegKinds; -// 'Inst' structure extension. -// Each basic block instruction has exactly one corresponding 'Instx' structure. +// Utility class for (zero-terminated) strings parsing // -struct SpillGen::Instx +class Tokens { - Instx () : nbopnds(0), evicts(0) {} - - Inst* inst; // pointer to the corresponding instruction - size_t nbopnds; // max number of operands in instruction - OpRole* oproles; // array of nbopnds size - Opnds* evicts; // can be null, can contain null pointers - RegMask regusage[IRMaxRegKinds];// masks of all registers that are busy at this instruction - RegMask regpress[IRMaxRegKinds]; -}; +public: + Tokens (const char* s) :src(s) {;} -// Block-specific information on a problem operand. -// + void init (const char* s) {src = s;} + bool scan (); + bool isWord () const {return isw;} + const char* lex () const {return buff;} -struct SpillGen::Op -{ - Instx* instx; - OpRole oprole; +protected: + + const char* src; + char* dst; + char buff[64]; + bool isw; }; -struct SpillGen::Opline +// Return 'false' if end of parsing string is reached and 'true' otherwise. +// isWord() will specify was it word or separator (one character). +// lex() will return zero-terminated lexem string scanned (for word or separator). +// +bool Tokens::scan () { - Opline () : ops(0) {} - - void clear (MemoryManager&); - void addOp (Instx*, OpRole); - -// iterator methods, work with the current instruction only - void start (); - void forw (); - void back (const Instx*); - bool go () const {return op != 0;} - bool isDef () const {return op->instx == instx && (op->oprole & RoleDef) != 0;} - bool isUse () const {return op->instx == instx && (op->oprole & RoleUse) != 0;} - bool isProc() const {return op->instx == instx;} - -// work with the specified instruction - bool isDef (const Inst*) const; - bool isUse (const Inst*) const; - - - bool at_start, // 'true' if this operand lives at the BB entry - at_exit, // 'true' if this operand lives at the BB exit - catched; // 'true' if this operand lives at entry to dispatch node - int idx; // -1 or index of the corresponding constraint in 'registers' array - Opnd* opnd; // original form of operand - Opnd* opnd_mem; // 0 or memory form of the operand (cached copy of the value from 'memopnds' array) - Instx* save_instx; // 0 or point where instruction to save operand should be inserted - bool save_before; // true if save must be before instruction (false is the default) - Opnd* save_opnd; // which operand should be saved - RegMask save_regmsk; - int save_regidx; - bool save_changed; - - typedef StlVector<Op> Ops; - Ops* ops; // array of all instructions that change/use value of the operand - -// current instruction - Op* op; - Instx* instx; - - static bool smaller (const Opline& x, const Opline& y) {return x.weight < y.weight;} - - Constraint initial; - int weight; -}; + while (isspace(*src)) + src++; + + if (*src == 0) + return false; + + dst = buff; + isw = isalnum(*src) != 0; + if (!isw) + *dst++ = *src++; + else + while (isalnum(*src)) + { + assert(dst != &buff[sizeof(buff)-1]); + *dst++ = *src++; + } + + *dst = 0; + return true; +} + + +const int MAXREGS = IRMaxRegNamesSameKind*IRMaxRegKinds; -// Temporary structure to describe operand that can be evicted. -// Used to choose the best operand to evict. +// Temporary structure to describe operand that can be evicted. +// Used to choose the best operand to evict. // struct SpillGen::Evict { - Opnd* opnd; - Instx* begx, * endx; - int weight; + Opnd* opnd; + Instx* begx, * endx; + int weight; - bool operator < (const Evict& x) const {return weight < x.weight;} + bool operator < (const Evict& x) const {return weight < x.weight;} }; -//// Misc helpers -///// ---------------------- +//// Misc helpers +///// ---------------------- static size_t bitCount (SpillGen::RegMask mk) { - size_t count = 0; - while (mk != 0) - { - if ((mk & 1) != 0) - ++count; - mk >>= 1; - } - return count; + size_t count = 0; + while (mk != 0) + { + if ((mk & 1) != 0) + ++count; + mk >>= 1; + } + return count; } static void merge (Constraint& c, SpillGen::RegMask mk) { - c.setMask(c.getMask() | mk); + c.setMask(c.getMask() | mk); } -// Parse input parameters (registers available) and build table of the regsiters -// available for allocalion ('registers'). +// Parse input parameters (registers available) and build table of the regsiters +// available for allocalion ('registers'). // void SpillGen::Registers::parse (const char* params) { - if (params == 0) - { - push_back(Constraint(RegName_EAX) - |Constraint(RegName_ECX) - |Constraint(RegName_EDX) - |Constraint(RegName_EBX) - |Constraint(RegName_ESI) - |Constraint(RegName_EDI) - |Constraint(RegName_EBP)); - - push_back(Constraint(RegName_XMM1) - |Constraint(RegName_XMM2) - |Constraint(RegName_XMM3) - |Constraint(RegName_XMM4) - |Constraint(RegName_XMM5) - |Constraint(RegName_XMM6) - |Constraint(RegName_XMM7)); - - push_back(Constraint(RegName_FP0)); - } - else - { - Constraint c; - for (Tokens t(params); t.scan(); ) - if (t.isWord()) - { - RegName r = getRegName(t.lex()); - if (r != RegName_Null) - c = Constraint(r); - - merge(c, true); - } - } - - assert(!empty()); - - for (size_t i = 0; i != IRMaxRegKinds; ++i) - indexes[i] = -1; - - for (size_t i = 0; i != size(); ++i) - indexes[operator[](i).getKind()] = i; + if (params == 0 || strcmp(params, "ALL") == 0) + { + +#ifdef _EM64T_ + push_back(Constraint(RegName_R8) + |Constraint(RegName_RAX) + |Constraint(RegName_RCX) + |Constraint(RegName_RBX) + |Constraint(RegName_RDX) + |Constraint(RegName_RSI) + |Constraint(RegName_RDI) + |Constraint(RegName_R9) + |Constraint(RegName_R10) + |Constraint(RegName_R11) + |Constraint(RegName_R12)); +#else + push_back(Constraint(RegName_EAX) + |Constraint(RegName_ECX) + |Constraint(RegName_EDX) + |Constraint(RegName_EBX) + |Constraint(RegName_ESI) + |Constraint(RegName_EDI) + |Constraint(RegName_EBP)); +#endif + + push_back(Constraint(RegName_XMM1) + |Constraint(RegName_XMM0) + |Constraint(RegName_XMM2) + |Constraint(RegName_XMM3) + |Constraint(RegName_XMM4) + |Constraint(RegName_XMM5) + |Constraint(RegName_XMM6) + |Constraint(RegName_XMM7)); + + push_back(Constraint(RegName_FP0)); + } + else + { + Constraint c; + for (Tokens t(params); t.scan(); ) + if (t.isWord()) + { + RegName r = getRegName(t.lex()); + if (r != RegName_Null) + c = Constraint(r); + + merge(c, true); + } + } + + assert(!empty()); + + for (size_t i = 0; i != IRMaxRegKinds; ++i) + indexes[i] = -1; + + for (size_t i = 0; i != size(); ++i) + indexes[operator[](i).getKind()] = i; } void SpillGen::Registers::clearMasks () { - for (size_t i = 0; i != size(); ++i) - operator[](i).setMask(0); + for (size_t i = 0; i != size(); ++i) + operator[](i).setMask(0); } void SpillGen::Registers::merge (const SpillGen::Registers& x) { - for (size_t i = 0; i != size(); ++i) - { - Constraint& r = operator[](i); - r.setMask(r.getMask() | x[i].getMask()); - } + for (size_t i = 0; i != size(); ++i) + { + Constraint& r = operator[](i); + r.setMask(r.getMask() | x[i].getMask()); + } } int SpillGen::Registers::merge (const Constraint& c, bool add) { - if (c.getMask() != 0) - { - for (size_t i = 0; i != size(); ++i) - { - Constraint& r = operator[](i); - if (r.getKind() == c.getKind()) - { - r.setMask(r.getMask() | c.getMask()); - return i; - } - } - - if (add) - push_back(c); - } - - return -1; + if (c.getMask() != 0) + { + for (size_t i = 0; i != size(); ++i) + { + Constraint& r = operator[](i); + if (r.getKind() == c.getKind()) + { + r.setMask(r.getMask() | c.getMask()); + return i; + } + } + + if (add) + push_back(c); + } + + return -1; } int SpillGen::Registers::getIndex (const Constraint& c) const { - return indexes[c.getKind() & OpndKind_Reg]; + return indexes[c.getKind() & OpndKind_Reg]; } Constraint* SpillGen::Registers::contains (const Constraint& c) { - for (size_t i = 0; i != size(); ++i) - { - Constraint& r = operator[](i); - if (r.getKind() == c.getKind() && (r.getMask() & c.getMask()) != 0) - return &r; - } - - return 0; + for (size_t i = 0; i != size(); ++i) + { + Constraint& r = operator[](i); + if (r.getKind() == c.getKind() && (r.getMask() & c.getMask()) != 0) + return &r; + } + + return 0; } void SpillGen::Opline::clear (MemoryManager& mm) { - if (ops == 0) - ops = new (mm) Ops(mm); - else - ops->clear(); + if (ops == 0) + ops = new (mm) Ops(mm); + else + ops->clear(); - opnd_mem = 0; - save_instx = 0; + opnd_mem = 0; + save_instx = 0; } void SpillGen::Opline::addOp (Instx* instx, OpRole oprole) { - if (ops->empty() || ops->back().instx != instx) - { - Op tmp; - tmp.instx = instx; - tmp.oprole = oprole; - ops->push_back(tmp); - } - else - { - ops->back().oprole |= oprole; - } - - op = 0; + if (ops->empty() || ops->back().instx != instx) + { + Op tmp; + tmp.instx = instx; + tmp.oprole = oprole; + ops->push_back(tmp); + } + else + { + ops->back().oprole |= oprole; + } + + op = 0; } void SpillGen::Opline::start () { - assert(!ops->empty()); - op = &ops->back(); - instx = op->instx; + assert(!ops->empty()); + op = &ops->back(); + instx = op->instx; } void SpillGen::Opline::forw () { - assert(op != 0); - if (op == &ops->front()) - { - op = 0; - return; - } - - assert(instx != ops->front().instx); - ++instx; - - Op* opx = op - 1; - if (opx->instx == instx) - op = opx; + assert(op != 0); + if (op == &ops->front()) + { + op = 0; + return; + } + + assert(instx != ops->front().instx); + ++instx; + + Op* opx = op - 1; + if (opx->instx == instx) + op = opx; } void SpillGen::Opline::back (const Instx* x) { - if (op == 0) - { - op = &ops->front(); - instx = op->instx; - } - - while (instx != x) - { - assert(instx != ops->back().instx); - if (op->instx == instx) - ++op; - - --instx; - } + if (op == 0) + { + op = &ops->front(); + instx = op->instx; + } + + while (instx != x) + { + assert(instx != ops->back().instx); + if (op->instx == instx) + ++op; + + --instx; + } } static bool operator == (const SpillGen::Op& op, const Inst* i) { - return op.instx->inst == i; + return op.instx->inst == i; } bool SpillGen::Opline::isDef (const Inst* i) const { - Ops::iterator end, ptr = find(ops->begin(), end = ops->end(), i); - return ptr != end && (ptr->oprole & RoleDef) != 0; + Ops::iterator end, ptr = find(ops->begin(), end = ops->end(), i); + return ptr != end && (ptr->oprole & RoleDef) != 0; } bool SpillGen::Opline::isUse (const Inst* i) const { - Ops::iterator end, ptr = find(ops->begin(), end = ops->end(), i); - return ptr != end && (ptr->oprole & RoleUse) != 0; + Ops::iterator end, ptr = find(ops->begin(), end = ops->end(), i); + return ptr != end && (ptr->oprole & RoleUse) != 0; } -///// SpillGen -///// ---------------------- - -SpillGen::SpillGen (IRManager& irm, const char * params) -: IRTransformer(irm, params), mm(1000, "SpillGen") -, registers(mm), memopnds(mm) -, instxs(mm), actives(mm), actsmap(mm) -, lives_start(0), lives_exit(0) -{ -#ifdef _DEBUG_SPILLGEN - onConstruct(irm); -#endif -} +///// SpillGen +///// ---------------------- -SpillGen::~SpillGen () +void SpillGen::runImpl() { #ifdef _DEBUG_SPILLGEN - onDestruct(); + onConstruct(*this); #endif -} - - -void SpillGen::runImpl() -{ - registers.parse(parameters); - DBGOUT("parameters: " << registers << endl;) - irManager.resetOpndConstraints(); - fails = 0; - emitted = 0; - - opndcount = irManager.getOpndCount(); - lives_exit = new (mm) LiveSet(mm, opndcount); - - actsmap.resize(opndcount); - for (size_t i = 0; i < opndcount; ++i) - actsmap[i] = 0; - - Node* node; - for (CFG::NodeIterator it(irManager); (node = it.getNode()) != 0; ++it) - if (node->hasKind(Node::Kind_BasicBlock)) - { - bblock = static_cast<BasicBlock*>(node); - if (bblock->getInsts().getCount() == 0) - continue; + registers.parse(getArg("regs")); + DBGOUT("parameters: " << registers << endl;) + irManager->resetOpndConstraints(); + + fails = 0; + emitted = 0; + + opndcount = irManager->getOpndCount(); + lives_exit = new (mm) BitSet(mm, opndcount); + + actsmap.resize(opndcount); + for (size_t i = 0; i < opndcount; ++i) + actsmap[i] = 0; + + const Nodes& nodes = irManager->getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()) + { + bblock = node; + if (bblock->isEmpty()) { + continue; + } + + lives_start = irManager->getLiveAtEntry(bblock); +#ifdef _OLD_ + lives_exit->resize(lives_start->getSetSize()); +#else + lives_exit->resize(opndcount); +#endif + irManager->getLiveAtExit(bblock, *lives_exit); - lives_start = irManager.getLiveAtEntry(bblock); - lives_exit->resize(lives_start->getSetSize()); - irManager.getLiveAtExit(bblock, *lives_exit); + size_t bfails = 0; - size_t bfails = 0; + for (;;) + { + if (pass0() == 0) + break; - for (;;) - { - if (pass0() == 0) - break; +#ifdef _DEBUG_SPILLGEN + if (log(LogStream::DBG).isEnabled()) + outInstxs(log(LogStream::DBG).out(), *this); +#endif size_t x; - if ((x = pass1()) == 0 || x == bfails) - { - bfails = x; + if ((x = pass1()) == 0 || x == bfails) + { + bfails = x; + + if (x != 0 && Log::isEnabled()) + Log::out() << "SpillGen cannot assign operand(s)" << std::endl; + + break; + } + bfails = x; + + DBGOUT(endl << "reiterating BB#"<< bblock->getId() << endl;) + + if (opndcount != irManager->getOpndCount()) + { + size_t oldcount = opndcount; + opndcount = irManager->getOpndCount(); + lives_exit->resize(opndcount); +#ifdef _OLD_ + lives_start->resize(opndcount); +#else + irManager->fixLivenessInfo(); +#endif - if (x != 0 && Log::cat_cg()->isWarnEnabled()) - Log::out() << "SpillGen cannot assign operand(s)" << std::endl; + actsmap.resize(opndcount); + for (; oldcount < opndcount; ++oldcount) + actsmap[oldcount] = 0; + } + } - break; - } - bfails = x; + fails += bfails; + } + } - DBGOUT(endl << "reiterating BB#"<< bblock->getId() << endl;) + static Counter<size_t> count_emits("ia32:spillgen:emits", 0); + count_emits += emitted; - if (opndcount != irManager.getOpndCount()) - { - size_t oldcount = opndcount; - opndcount = irManager.getOpndCount(); - lives_exit->resize(opndcount); - lives_start->resize(opndcount); - actsmap.resize(opndcount); - for (; oldcount < opndcount; ++oldcount) - actsmap[oldcount] = 0; - } - } +#ifdef _DEBUG_SPILLGEN + log(LogStream::DBG) << endl << "Emitted movs :" << emitted << endl; - fails += bfails; - } + if (fails) + log(LogStream::DBG) << endl << "FAILS: " << fails << endl; +#endif - static Counter<size_t> count_emits("ia32:spillgen:emits", 0); - count_emits += emitted; + if (fails != 0) + Jitrino::crash("SpillGen failed"); #ifdef _DEBUG_SPILLGEN - dbgout << endl << "Emitted movs :" << emitted << endl; - - if (fails) - { - dbgout << endl << "FAILS: " << fails << endl; - dbgout.close(); - } + onDestruct(*this); #endif - - if (fails != 0) - Jitrino::crash("SpillGen failed"); } bool SpillGen::verify (bool force) { - bool failed = false; + bool failed = false; - if (force || irManager.getVerificationLevel() >= 1) - { - irManager.packOpnds(); - irManager.updateLivenessInfo(); + if (force || getVerificationLevel() >= 1) + { + irManager->packOpnds(); + irManager->updateLivenessInfo(); - if (!RegAllocCheck(irManager).run(true)) - failed = true; + if (!RegAllocCheck(*irManager).run(true)) + failed = true; - if (!IRTransformer::verify(true)) - failed = true; - } + if (!SessionAction::verify(true)) + failed = true; + } - return !failed; -} + return !failed; +} -// Preprocessing phase. -// Scans all instructions in the basic block and create 'Instx' extension structure for -// every instruction with required information. -// Identifies all operands that needed to be allocated (problem operands) and fill 'Opline' -// structure for each. +// Preprocessing phase. +// Scans all instructions in the basic block and create 'Instx' extension structure for +// every instruction with required information. +// Identifies all operands that needed to be allocated (problem operands) and fill 'Opline' +// structure for each. // -size_t SpillGen::pass0 () +size_t SpillGen::pass0 () { - static CountTime pass0Timer("timer:ia32::spillgen:pass0"); - AutoTimer tm(pass0Timer); + static CountTime pass0Timer("ia32::spillgen:pass0"); + AutoTimer tm(pass0Timer); - actives.resize(0); + actives.resize(0); - evicts_known = false; + evicts_known = false; - const size_t regkinds = registers.size(); - assert(regkinds <= IRMaxRegKinds); + const size_t regkinds = registers.size(); + assert(regkinds <= IRMaxRegKinds); - const Insts& insts = bblock->getInsts(); - instxs.resize(insts.getCount() + 1); + instxs.resize(bblock->getInstCount() + 1); - instxs[0].inst = 0; - if (instxs[0].evicts == 0) - instxs[0].evicts = new (mm) Opnds(mm); - else - instxs[0].evicts->resize(0); + instxs[0].inst = 0; + if (instxs[0].evicts == 0) + instxs[0].evicts = new (mm) Opnds(mm); + else + instxs[0].evicts->resize(0); - Instxs::iterator instxp = instxs.end() - 1; + Instxs::iterator instxp = instxs.end() - 1; - for (size_t i = 0; i < regkinds; ++i) - instxp->regusage [i] = 0; + for (size_t i = 0; i < regkinds; ++i) + instxp->regusage [i] = 0; #ifdef _DEBUG_SPILLGEN - dbgout << endl << "BB#"<< bblock->getId(); - if (!instxs.empty()) - dbgout << " [" << *insts.getFirst() << " - " << *insts.getLast() << "] "; - dbgout << instxs.size() - 1; - dbgout << endl; + log(LogStream::DBG) << endl << "BB#"<< bblock->getId(); + if (!instxs.empty()) + log(LogStream::DBG) << " [" << *(Inst*)bblock->getFirstInst() << " - " << *(Inst*)bblock->getLastInst() << "] "; + log(LogStream::DBG) << instxs.size() - 1 + << endl; #endif -// calculate registers used at the block exit - - LiveSet lives_next = *lives_exit; - LiveSet::IterB ib(*lives_exit); - for (int i = ib.getNext(); i != -1; i = ib.getNext()) - { - Constraint loc = irManager.getOpnd(i)->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - int idx = registers.getIndex(loc); - if (!loc.isNull() && idx != -1) - {// this operand is already assigned to some location/register - instxp->regusage[idx] |= loc.getMask(); - } - } - -// iterate over instructions towards the top of the block - - for (Inst* inst = insts.getLast(); inst != 0; inst = insts.getPrev(inst)) - { - // Prepare processing of the next instruction - - Instxs::iterator instxq = instxp - 1; - for (size_t i = 0; i < regkinds; ++i) - instxq->regusage [i] = instxp->regusage[i]; - - // Process current instruction - - instxp->inst = inst; - - size_t nbopnds = inst->getOpndCount(Inst::OpndRole_All); - if (instxp->nbopnds < nbopnds) - instxp->oproles = new (mm) OpRole[instxp->nbopnds = (nbopnds + 8) & ~7]; - - for (size_t i = 0; i < regkinds; ++i) - instxp->regpress[i] = 0; - - Opnd* opnd; - size_t itx = 0; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), ++itx) - { - opnd = inst->getOpnd(it); - - uint32 roles = inst->getOpndRoles(it); - - OpRole oprole = 0; - - if ((roles & Inst::OpndRole_Def) != 0) - oprole |= RoleDef; - - if ((roles & Inst::OpndRole_Use) != 0 || (inst->getProperties() & Inst::Properties_Conditional) != 0) - oprole |= RoleUse; - - if ((inst->getProperties() & Inst::Properties_Conditional) != 0) - oprole |= RoleCond; - - if (!lives_next.isLive(opnd)) - oprole |= RoleEnd; - - assert(itx < instxp->nbopnds); - instxp->oproles[itx] = oprole; - - Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - if (!loc.isNull()) - {// this operand is already assigned to some location/register - int idx; - if ((idx = registers.getIndex(loc)) != -1) - { - RegMask msk = loc.getMask(); - assert(msk != 0); - RegMask was = instxp->regusage[idx]; - instxq->regusage [idx] |= msk; - if ((oprole & RoleUse) != 0) - { - } - else if ((oprole & (RoleDef | RoleCond)) == RoleDef) - { - instxq->regusage[idx] &= ~msk; - if ((was & msk) == 0) - { - DBGOUT("dead def " << *inst << " " << *opnd << endl;) - instxp->regusage [idx] |= msk; - } - } - } - } - else - {// this operand is not allocated yet - //loc = opnd->getConstraint(Opnd::ConstraintKind_Initial, OpndSize_Default); - loc = inst->getConstraint(Inst::ConstraintKind_Current, it, OpndSize_Default); - int idx = registers.getIndex(loc); - Opline* opline = actsmap[opnd->getId()]; - if (opline == 0) - {// Is this is a problem operand? - if (!(loc & Constraint(OpndKind_Memory)).isNull() || idx != -1) - {// operand can be assigned to memory or register - actives.resize(actives.size() + 1); - opline = &actives.back(); - actsmap[opnd->getId()] = opline; - - opline->clear(mm); - opline->opnd = opnd; - opline->at_start = lives_start->isLive(opnd); - opline->at_exit = lives_exit->isLive(opnd); - opline->initial = loc; - } - else - { - DBGOUT("Cannot assign " << *opnd << endl;) - } - } - else - { - opline->initial.intersectWith(loc); - } - - // this operand is tracked - if (opline != 0) - { - opline->addOp(&*instxp, oprole); - - if ((loc & Constraint(OpndKind_Memory)).isNull()) - {// Operand cannot assigned to memory - assert(idx != -1); - if (bitCount(loc.getMask()) == 1) - instxp->regpress[idx] |= loc.getMask(); - } - } - } - - if (inst->isLiveRangeEnd(it)) - lives_next.setBit(opnd->getId(), false); - else if (inst->isLiveRangeStart(it)) - lives_next.setBit(opnd->getId(), true); - } - - instxp = instxq; - } - - assert(instxp == instxs.begin()); - - return actives.size(); +// calculate registers used at the block exit + + BitSet lives_next = *lives_exit; + BitSet::IterB ib(*lives_exit); + for (int i = ib.getNext(); i != -1; i = ib.getNext()) + { + Constraint loc = irManager->getOpnd(i)->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + int idx = registers.getIndex(loc); + if (!loc.isNull() && idx != -1) + {// this operand is already assigned to some location/register + instxp->regusage[idx] |= loc.getMask(); + } + } + +// iterate over instructions towards the top of the block + + for (Inst* inst = (Inst*)bblock->getLastInst(); inst != 0; inst = inst->getPrevInst()) + { + // Prepare processing of the next instruction + + Instxs::iterator instxq = instxp - 1; + for (size_t i = 0; i < regkinds; ++i) + instxq->regusage [i] = instxp->regusage[i]; + + // Process current instruction + + instxp->inst = inst; + + size_t nbopnds = inst->getOpndCount(Inst::OpndRole_All); + if (instxp->nbopnds < nbopnds) + instxp->oproles = new (mm) OpRole[instxp->nbopnds = (nbopnds + 8) & ~7]; + + for (size_t i = 0; i < regkinds; ++i) + instxp->regpress[i] = 0; + + Opnd* opnd; + size_t itx = 0; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), ++itx) + { + opnd = inst->getOpnd(it); + + uint32 roles = inst->getOpndRoles(it); + + OpRole oprole = 0; + + if ((roles & Inst::OpndRole_Def) != 0) + oprole |= RoleDef; + + if ((roles & Inst::OpndRole_Use) != 0 || (inst->getProperties() & Inst::Properties_Conditional) != 0) + oprole |= RoleUse; + + if ((inst->getProperties() & Inst::Properties_Conditional) != 0) + oprole |= RoleCond; + + if (!lives_next.getBit(opnd->getId())) + oprole |= RoleEnd; + + assert(itx < instxp->nbopnds); + instxp->oproles[itx] = oprole; + + Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if (!loc.isNull()) + {// this operand is already assigned to some location/register + int idx; + if ((idx = registers.getIndex(loc)) != -1) + { + RegMask msk = loc.getMask(); + assert(msk != 0); + RegMask was = instxp->regusage[idx]; + instxq->regusage [idx] |= msk; + if ((oprole & RoleUse) != 0) + { + } + else if ((oprole & (RoleDef | RoleCond)) == RoleDef) + { + instxq->regusage[idx] &= ~msk; + if ((was & msk) == 0) + { + DBGOUT("dead def " << *inst << " " << *opnd << endl;) + instxp->regusage [idx] |= msk; + } + } + } + } + else + {// this operand is not allocated yet + unsigned mask = (1<<inst->getOpndCount())-1; + loc = ((Inst*)inst)->getConstraint(it, mask, OpndSize_Default); + int idx = registers.getIndex(loc); + Opline* opline = actsmap[opnd->getId()]; + if (opline == 0) + {// Is this is a problem operand? + if (!(loc & Constraint(OpndKind_Memory)).isNull() || idx != -1) + {// operand can be assigned to memory or register + actives.resize(actives.size() + 1); + opline = &actives.back(); + actsmap[opnd->getId()] = opline; + + opline->clear(mm); + opline->opnd = opnd; + opline->at_start = lives_start->getBit(opnd->getId()); + opline->at_exit = lives_exit->getBit(opnd->getId()); + opline->initial = loc; + } + else + { + DBGOUT("Cannot assign " << *opnd << endl;) + } + } + else + { + opline->initial.intersectWith(loc); + } + + // this operand is tracked + if (opline != 0) + { + opline->addOp(&*instxp, oprole); + + if ((loc & Constraint(OpndKind_Memory)).isNull()) + {// Operand cannot assigned to memory + assert(idx != -1); + if (bitCount(loc.getMask()) == 1) + instxp->regpress[idx] |= loc.getMask(); + } + } + } + + if (inst->isLiveRangeEnd(it)) + lives_next.setBit(opnd->getId(), false); + else if (inst->isLiveRangeStart(it)) + lives_next.setBit(opnd->getId(), true); + } + + instxp = instxq; + } + + assert(instxp == instxs.begin()); + + return actives.size(); } -// Allocation phase. -// Allocate all problem operands for the current block. +// Allocation phase. +// Allocate all problem operands for the current block. // -size_t SpillGen::pass1 () +size_t SpillGen::pass1 () { - static CountTime pass1Timer("timer:ia32::spillgen:pass1"); - AutoTimer tm(pass1Timer); - - size_t fails = 0; - - if (actives.size() > 1) - { - for (Oplines::iterator it = actives.begin(); it != actives.end(); ++it) - { - Opline& opline = *it; - opline.weight = bitCount(opline.initial.getMask()); - } - sort(actives.begin(), actives.end(), Opline::smaller); - } - - lives_catch = 0; - const Node* node; - if ((node = bblock->getNode(Direction_Out, Node::Kind_DispatchNode)) != 0) - if ((lives_catch = irManager.getLiveAtEntry(node))->isEmpty()) - lives_catch = 0; - - for (Oplines::reverse_iterator it = actives.rbegin(); it != actives.rend(); ++it) - { - Opline& opline = *it; - if (actsmap[opline.opnd->getId()] == 0) - continue; - - actsmap[opline.opnd->getId()] = 0; + static CountTime pass1Timer("ia32::spillgen:pass1"); + AutoTimer tm(pass1Timer); + + size_t fails = 0; + + if (actives.size() > 1) + { + for (Oplines::iterator it = actives.begin(); it != actives.end(); ++it) + { + Opline& opline = *it; + opline.weight = bitCount(opline.initial.getMask()); + } + sort(actives.begin(), actives.end(), Opline::smaller); + } + + lives_catch = 0; + Node* node = bblock->getExceptionEdgeTarget(); + if (node!=NULL) { + if ((lives_catch = irManager->getLiveAtEntry(node))->isEmpty()) { + lives_catch = 0; + } + } + + for (Oplines::reverse_iterator it = actives.rbegin(); it != actives.rend(); ++it) + { + Opline& opline = *it; + if (actsmap[opline.opnd->getId()] == 0) + continue; + + actsmap[opline.opnd->getId()] = 0; #ifdef _DEBUG_SPILLGEN - opruns.incr(opline.ops->size()); + opruns.incr(opline.ops->size()); #endif - opline.opnd_mem = 0; - opline.save_instx = 0; - opline.save_changed = false; - opline.start(); + opline.opnd_mem = 0; + opline.save_instx = 0; + opline.save_changed = false; + opline.start(); - // Is this operand lives at the corresponding Dispatch node entry ? - opline.catched = (lives_catch == 0) ? false : lives_catch->isLive(opline.opnd); + // Is this operand lives at the corresponding Dispatch node entry ? + opline.catched = (lives_catch == 0) ? false : lives_catch->getBit(opline.opnd->getId()); - DBGOUT(opline;) + DBGOUT(opline;) - // Begin-block processing + // Begin-block processing - RegMask prefreg = 0; + RegMask prefreg = 0; - // Is this operand lives at entry of this node ? - if (opline.at_start) - saveOpnd(opline, opline.instx, opndMem(opline)); - else - prefreg = lookPreffered(opline); + // Is this operand lives at entry of this node ? + if (opline.at_start) + saveOpnd(opline, opline.instx, opndMem(opline)); + else + prefreg = lookPreffered(opline); - // Process instructions that are using the operand + // Process instructions that are using the operand - while (opline.go()) - if (opline.isProc()) - { - Constraint c(opline.opnd->getConstraint(Opnd::ConstraintKind_Initial)); - //assert( !(c & OpndKind_Memory).isNull() ); ??? - update(opline.instx->inst, opline.opnd, c); - opline.idx = registers.getIndex(c); + while (opline.go()) + if (opline.isProc()) + { + Constraint c(opline.opnd->getConstraint(Opnd::ConstraintKind_Initial)); + update(opline.instx->inst, opline.opnd, c); + opline.idx = registers.getIndex(c); - if (!tryRegister(opline, c, prefreg)) - if (!tryMemory(opline, c)) - if (!tryEvict(opline, c)) - if (!tryRepair(opline, c)) - {// Cannot assign operand, so let it remains in the original form - DBGOUT("Cannot assign " << opline.opnd << endl;) - ++fails; + if (!tryRegister(opline, c, prefreg)) + if (!tryMemory(opline, c)) + if (!tryEvict(opline, c)) + if (!tryRepair(opline, c)) + {// Cannot assign operand, so let it remains in the original form + DBGOUT("Cannot assign " << opline.opnd << endl;) + ++fails; - if (simplify(opline.instx->inst, opline.opnd)) - break; + if (simplify(opline.instx->inst, opline.opnd)) + break; - loadOpnd(opline, opline.instx, opline.opnd); + loadOpnd(opline, opline.instx, opline.opnd); - if (opline.isDef()) - opline.save_changed = true; + if (opline.isDef()) + opline.save_changed = true; - saveOpnd(opline, opline.instx, opline.opnd); + saveOpnd(opline, opline.instx, opline.opnd); - opline.forw(); - } - } - else - { - opline.forw(); - } + opline.forw(); + } + } + else + { + opline.forw(); + } - // End-block processing + // End-block processing - assert(opline.instx == opline.ops->front().instx); + assert(opline.instx == opline.ops->front().instx); - if (opline.at_exit) - loadOpndMem(opline); - } + if (opline.at_exit) + loadOpndMem(opline); + } - return fails; + return fails; } SpillGen::RegMask SpillGen::lookPreffered (Opline& opline) { - Inst* inst = opline.instx->inst; - if (inst->getMnemonic() != Mnemonic_MOV || inst->getOpnd(0) != opline.opnd) - return 0; + Inst* inst = opline.instx->inst; + if (inst->getMnemonic() != Mnemonic_MOV || inst->getOpnd(0) != opline.opnd) + return 0; - if ((opline.instx->oproles[1] & RoleEnd) == 0) - return 0; + if ((opline.instx->oproles[1] & RoleEnd) == 0) + return 0; - Opnd* opnd1 = inst->getOpnd(1); + Opnd* opnd1 = inst->getOpnd(1); - RegMask msk; - Constraint loc = opnd1->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - if (!loc.isNull() && registers.getIndex(loc) != -1) - msk = loc.getMask(); - else - return 0; + RegMask msk; + Constraint loc = opnd1->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if (!loc.isNull() && registers.getIndex(loc) != -1) + msk = loc.getMask(); + else + return 0; - DBGOUT("COALESCE at " << *inst << " " << *opnd1 << endl;) - return msk; + DBGOUT("COALESCE at " << *inst << " " << *opnd1 << endl;) + return msk; } - + -// Attempt to allocate a register for the operand. +// Attempt to allocate a register for the operand. // bool SpillGen::tryRegister (Opline& opline, Constraint c, RegMask prefreg) { - if (opline.idx == -1) - return false; - - Constraint cx = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; - Constraint cr((OpndKind)cx.getKind(), c.getSize(), cx.getMask()); - -// handle first instruction of the interval - - RegMask mk = cr.getMask() & ~usedRegs(opline.instx, opline.idx, opline.isUse()); - if (mk == 0) - { - DBGOUT(" -No reg [" << *opline.instx->inst << "]" << c << endl;) - return false; - } - - RegMask mkpost = ~(RegMask)0; - if (!opline.isDef()) - mkpost = callRegs(opline.instx, opline.idx); - -// handle second and all others instructions - - Instx* begx = opline.instx; - Instx* endx = begx; - int count = 0; - for (opline.forw(); opline.go(); opline.forw()) - { - RegMask tmp = mk & mkpost & ~opline.instx->regusage[opline.idx]; - if (tmp == 0) - break; - - int cnt = 0; - if (opline.isProc()) - { - if (opline.isDef() && !opline.isUse()) - break; - - if ((cnt = update(opline.instx->inst, opline.opnd, cr)) != 0) - { - tmp &= cr.getMask(); - if (tmp == 0) - break; - endx = opline.instx; - } - } - - mk = tmp; - mkpost = callRegs(opline.instx, opline.idx); - count += cnt; - } - - DBGOUT(" -reg [" << *begx->inst << " - " << *endx->inst - << "] avail:" << RegMasks(cx, mk) << " count:" << count << endl;) - - if (count == 0) - { - assert(begx == endx); - Constraint cm = c & OpndKind_Memory; - if (!cm.isNull()) - { - DBGOUT(" -mem [" << *begx->inst << "]" << endl;) - assignMem(opline, begx, begx); - return true; - } - } - - if ((mk & prefreg) != 0) - { - mk &= prefreg; - static Counter<size_t> count_preffer("ia32:spillgen:preffered", 0); - count_preffer++; - } - RegName rn = findFree(mk, opline.idx, begx); - assignReg(opline, begx, endx, rn); - return true; + if (opline.idx == -1) + return false; + + Constraint cx = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; + Constraint cr((OpndKind)cx.getKind(), c.getSize(), cx.getMask()); + +// handle first instruction of the interval + + RegMask mk = cr.getMask() & ~usedRegs(opline.instx, opline.idx, opline.isUse()); + if (mk == 0) + { + DBGOUT(" -No reg [" << *opline.instx->inst << "]" << c << endl;) + return false; + } + + RegMask mkpost = ~(RegMask)0; + if (!opline.isDef()) + mkpost = callRegs(opline.instx, opline.idx); + +// handle second and all others instructions + + Instx* begx = opline.instx; + Instx* endx = begx; + int count = 0; + for (opline.forw(); opline.go(); opline.forw()) + { +#ifdef _OLD_ + RegMask tmp = mk & mkpost & ~opline.instx->regusage[opline.idx]; +#else + RegMask tmp = mk & mkpost; + if (opline.isEnd()) + tmp &= ~opline.instx->regusage[opline.idx-1]; + else + tmp &= ~opline.instx->regusage[opline.idx]; +#endif + + if (tmp == 0) + break; + + int cnt = 0; + if (opline.isProc()) + { + if (opline.isDef() && !opline.isUse()) + break; + + if ((cnt = update(opline.instx->inst, opline.opnd, cr)) != 0) + { + tmp &= cr.getMask(); + if (tmp == 0) + break; + endx = opline.instx; + } + } + + mk = tmp; + mkpost = callRegs(opline.instx, opline.idx); + count += cnt; + } + + DBGOUT(" -reg [" << *begx->inst << " - " << *endx->inst + << "] avail:" << RegMasks(cx, mk) << " count:" << count << endl;) + + if (count == 0) + { + assert(begx == endx); + Constraint cm = c & OpndKind_Memory; + if (!cm.isNull()) + { + DBGOUT(" -mem [" << *begx->inst << "]" << endl;) + assignMem(opline, begx, begx); + return true; + } + } + + if ((mk & prefreg) != 0) + { + mk &= prefreg; + static Counter<size_t> count_preffer("ia32:spillgen:preffered", 0); + count_preffer++; + } + RegName rn = findFree(mk, opline.idx, begx); + assignReg(opline, begx, endx, rn); + return true; } -// Attempt to assign operand to memory. +// Attempt to assign operand to memory. // bool SpillGen::tryMemory (Opline& opline, Constraint c) { - c.intersectWith(OpndKind_Memory); - if (c.isNull()) - { - DBGOUT(" -No mem [" << *opline.instx->inst << "]" << endl;) - return false; - } - - DBGOUT(" -mem [" << *opline.instx->inst << "]" << endl;) - assignMem(opline, opline.instx, opline.instx); - opline.forw(); - return true; + c.intersectWith(OpndKind_Memory); + if (c.isNull()) + { + DBGOUT(" -No mem [" << *opline.instx->inst << "]" << endl;) + return false; + } + + DBGOUT(" -mem [" << *opline.instx->inst << "]" << endl;) + assignMem(opline, opline.instx, opline.instx); + opline.forw(); + return true; } -// Attempt to find other operand that can be temporary saved to memory and use it's register -// for the operand processed. +// Attempt to find other operand that can be temporary saved to memory and use it's register +// for the operand processed. // bool SpillGen::tryEvict (Opline& opline, Constraint c) { - if (opline.idx == -1) - return false; + if (opline.idx == -1) + return false; - Constraint cx = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; - Constraint cr((OpndKind)cx.getKind(), c.getSize(), cx.getMask()); + Constraint cx = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; + Constraint cr((OpndKind)cx.getKind(), c.getSize(), cx.getMask()); - Instx* begx = opline.instx; - Instx* endx = begx; + Instx* begx = opline.instx; + Instx* endx = begx; - for (opline.forw(); opline.go(); opline.forw()) - { - Constraint cx = cr; - if (update(opline.instx->inst, opline.opnd, cx)) - if (cx.getMask() == 0) - break; + for (opline.forw(); opline.go(); opline.forw()) + { + Constraint cx = cr; + if (update(opline.instx->inst, opline.opnd, cx)) + if (cx.getMask() == 0) + break; - cr = cx; - endx = opline.instx; - } + cr = cx; + endx = opline.instx; + } - RegName rn = findEvict(cr.getMask(), opline.idx, begx, endx); - if (rn == RegName_Null) - { - DBGOUT(" -No evict [" << *begx->inst << " - " << *endx->inst << "]" << endl;) - opline.back(begx); - return false; - } + RegName rn = findEvict(cr.getMask(), opline.idx, begx, endx); + if (rn == RegName_Null) + { + DBGOUT(" -No evict [" << *begx->inst << " - " << *endx->inst << "]" << endl;) + opline.back(begx); + return false; + } - DBGOUT(" -evict [" << *begx->inst << " - " << *endx->inst - << "] " << getRegNameString(rn) << endl;) + DBGOUT(" -evict [" << *begx->inst << " - " << *endx->inst + << "] " << getRegNameString(rn) << endl;) - static Counter<size_t> count_evicts("ia32:spillgen:evicts", 0); - count_evicts++; + static Counter<size_t> count_evicts("ia32:spillgen:evicts", 0); + count_evicts++; - assignReg(opline, begx, endx, rn); + assignReg(opline, begx, endx, rn); - opline.back(endx); - opline.forw(); - return true; + opline.back(endx); + opline.forw(); + return true; } -// Attempt to change allocation that was previously made, i.e. reassign register that -// already used in the instruction for other operand because the processed operand -// requires already assigned register. +// Attempt to change allocation that was previously made, i.e. reassign register that +// already used in the instruction for other operand because the processed operand +// requires already assigned register. // bool SpillGen::tryRepair (Opline& opline, Constraint c) { - if (opline.idx == -1) - return false; - - Constraint ca = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; - Constraint cr((OpndKind)ca.getKind(), c.getSize(), ca.getMask()); - - Inst* inst = opline.instx->inst; - - RegMask mk = cr.getMask(); - - Opnd* ox = 0, *ox_out = 0; - RegName rx = RegName_Null; - bool need_load = false, - need_save = false; - - size_t itx = 0; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), ++itx) - { - ox = inst->getOpnd(it); - - RegMask rm = getRegMaskConstr(ox, cr); - if ((mk & rm) != 0) - { - OpRole oprole = opline.instx->oproles[itx]; - need_load = (oprole & RoleUse) != 0; - need_save = (oprole & RoleEnd) == 0; - - Constraint cx = inst->getConstraint(Inst::ConstraintKind_Current, it, OpndSize_Default); - RegMask used = usedRegs(opline.instx, opline.idx, need_load); - RegMask usable = (cx & registers[opline.idx]).getMask() & ~used & ~mk; - if (usable != 0) - { - rx = findFree(usable, opline.idx, opline.instx); - ox_out = opndReg(ox, rx); - break; - } - else - { - if (!(cx & OpndKind_Memory).isNull()) - { - ox_out = opndMem(ox); - break; - } - } - } - } - - if (ox_out == 0) - return false; - -// relocate operand 'ox' to new register 'rx' - - DBGOUT(" -repair [" << *inst << "] " << *opline.opnd - << " " << *ox << " " << *ox_out << endl;) - - static Counter<size_t> count_repairs("ia32:spillgen:repairs", 0); - count_repairs++; - - if (need_load) - emitMove(true, inst, ox_out, ox); - if (need_save) - emitMove(false, inst, ox, ox_out); - - inst->replaceOpnd(ox, ox_out); - if (rx != RegName_Null /*&& need_save*/) - opline.instx->regusage[opline.idx] |= getRegMask(rx); - -// assign the requsted operand to the register which was previosly assigned to ox - - assignReg(opline, opline.instx, opline.instx, ox->getRegName()); - opline.forw(); - return true; + if (opline.idx == -1) + return false; + + Constraint ca = c.getAliasConstraint(OpndSize_Default) & registers[opline.idx]; + Constraint cr((OpndKind)ca.getKind(), c.getSize(), ca.getMask()); + + Inst* inst = opline.instx->inst; + + RegMask mk = cr.getMask(); + + Opnd* ox = 0, *ox_out = 0; + RegName rx = RegName_Null; + bool need_load = false, + need_save = false; + + size_t itx = 0; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it), ++itx) + { + ox = inst->getOpnd(it); + + RegMask rm = getRegMaskConstr(ox, cr); + if ((mk & rm) != 0) + { + OpRole oprole = opline.instx->oproles[itx]; + need_load = (oprole & RoleUse) != 0; + need_save = (oprole & RoleEnd) == 0; + + unsigned mask = (1<<inst->getOpndCount())-1; + Constraint cx = ((Inst*)inst)->getConstraint(it, mask, OpndSize_Default); + RegMask used = usedRegs(opline.instx, opline.idx, need_load); + RegMask usable = (cx & registers[opline.idx]).getMask() & ~used & ~mk; + if (usable != 0) + { + rx = findFree(usable, opline.idx, opline.instx); + ox_out = opndReg(ox, rx); + break; + } + else + { + if (!(cx & OpndKind_Memory).isNull()) + { + ox_out = opndMem(ox); + break; + } + } + } + } + + if (ox_out == 0) + return false; + +// relocate operand 'ox' to new register 'rx' + + DBGOUT(" -repair [" << *inst << "] " << *opline.opnd + << " " << *ox << " " << *ox_out << endl;) + + static Counter<size_t> count_repairs("ia32:spillgen:repairs", 0); + count_repairs++; + + if (need_load) + emitMove(true, inst, ox_out, ox); + if (need_save) + emitMove(false, inst, ox, ox_out); + + inst->replaceOpnd(ox, ox_out); + if (rx != RegName_Null /*&& need_save*/) + opline.instx->regusage[opline.idx] |= getRegMask(rx); + +// assign the requsted operand to the register which was previosly assigned to ox + + assignReg(opline, opline.instx, opline.instx, ox->getRegName()); + opline.forw(); + return true; } bool SpillGen::simplify (Inst* inst, Opnd* opnd) { - if (inst->hasKind(Inst::Kind_BranchInst) && inst->getOpndCount() == 1) - { - Opnd* opndm = inst->getOpnd(0); - Opnd* opndx = irManager.newMemOpnd(opndm->getType(), - MemOpndKind_StackAutoLayout, - irManager.getRegOpnd(RegName_ESP), - 0); - DBGOUT("simplify " << *opndm << " -> mem " << *opndx << endl;); - emitMove(true, inst,opndx, opndm); - inst->replaceOpnd(opndm, opndx); - - for (int so = 0; so != MemOpndSubOpndKind_Count; ++so) - { - Opnd* sub = opndm->getMemOpndSubOpnd(static_cast<MemOpndSubOpndKind>(so)); - if (sub != 0) - actsmap[sub->getId()] = 0; - } - return true; - } - - return false; + if (inst->hasKind(Inst::Kind_LocalControlTransferInst) && inst->getOpndCount() == 1) + { + Opnd* opndm = inst->getOpnd(0); + Opnd* opndx = irManager->newMemOpnd(opndm->getType(), + MemOpndKind_StackAutoLayout, + irManager->getRegOpnd(RegName_ESP), + 0); + DBGOUT("simplify " << *opndm << " -> mem " << *opndx << endl;); + emitMove(true, inst,opndx, opndm); + inst->replaceOpnd(opndm, opndx); + + for (int so = 0; so != MemOpndSubOpndKind_Count; ++so) + { + Opnd* sub = opndm->getMemOpndSubOpnd(static_cast<MemOpndSubOpndKind>(so)); + if (sub != 0) + actsmap[sub->getId()] = 0; + } + return true; + } + + return false; } -// Return mask of all free registers at the instruction specified. -// If register will define value, set isuse=false. -// If regsiter will load value defined in some other instruction, set isuse=true +// Return mask of all free registers at the instruction specified. +// If register will define value, set isuse=false. +// If regsiter will load value defined in some other instruction, set isuse=true // SpillGen::RegMask SpillGen::usedRegs (const Instx* instx, int idx, bool isuse) const { - RegMask used = instx->regusage[idx]; - if (isuse) - used |= (used ^ (instx-1)->regusage[idx]); + RegMask used = instx->regusage[idx]; + if (isuse) + used |= (used ^ (instx-1)->regusage[idx]); - return used; + return used; } SpillGen::RegMask SpillGen::callRegs (const Instx* instx, int idx) const { - if (instx->inst->getMnemonic() == Mnemonic_CALL) - { - OpndKind k = static_cast<OpndKind>(registers[idx].getKind()); - Constraint ci = static_cast<CallInst*>(instx->inst)->getCalleeSaveRegs(k); - return ci.getMask(); - } - - return ~(RegMask)0; + if (instx->inst->getMnemonic() == Mnemonic_CALL) + { + OpndKind k = static_cast<OpndKind>(registers[idx].getKind()); + Constraint ci = static_cast<CallInst*>(instx->inst)->getCalleeSaveRegs(k); + return ci.getMask(); + } + + return ~(RegMask)0; } -// If currently handled operand is referenced by current instruction, then evaluate -// constraint of the operand imposed by this instruction and return 'true'. -// Otherwise, do nothing and return false. +// If currently handled operand is referenced by current instruction, then evaluate +// constraint of the operand imposed by this instruction and return 'true'. +// Otherwise, do nothing and return false. // int SpillGen::update (const Inst* inst, const Opnd* opnd, Constraint& constr) const { - int count = 0; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) - if ( inst->getOpnd(it) == opnd) - { - // if operand occures more than once then conservatively take - // the strong constraint for the operand - Constraint c = inst->getConstraint(count ? - Inst::ConstraintKind_Strong: - Inst::ConstraintKind_Current, - it, - constr.getSize()); - if (constr.isNull()) - constr = c; - else - constr.intersectWith(c); - - count++; - } - return count; + int count = 0; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) + if ( inst->getOpnd(it) == opnd) + { + // if operand occures more than once then conservatively take + // the strong constraint for the operand + Constraint c; + c = ((Inst*)inst)->getConstraint(it, count?0xFFFFFFFF:0x7FFFFFFF, constr.getSize()); + if (constr.isNull()) + constr = c; + else + constr.intersectWith(c); + + count++; + } + return count; } -// Split operand and assign register 'rn' to it in the interval specified +// Split operand and assign register 'rn' to it in the interval specified // ('begx' - 'endx', inclusive) // void SpillGen::assignReg (Opline& opline, Instx* begx, Instx* endx, RegName rn) { - assert(rn != RegName_Null); - RegMask mk = getRegMask(rn); - Opnd* opnd_reg = opndReg(opline.opnd, rn); - - int reguses = 0; - - DBGOUT("assignReg " << *opline.opnd << " [" << *begx->inst - << " - " << *endx->inst << "] to " << *opnd_reg << endl;) - - loadOpnd(opline, begx, opnd_reg); - - for (Instx* ptrx = begx; ptrx <= endx; ++ptrx) - { - if (opline.save_changed && opline.catched && ptrx->inst->hasKind(Inst::Kind_CallInst)) - { - emitMove(true, ptrx->inst, opndMem(opline), opnd_reg); - opline.save_changed = false; - } - - if (ptrx->inst->replaceOpnd(opline.opnd, opnd_reg)) - {// the operand is used in the instruction - ++reguses; - if (opline.isDef(ptrx->inst)) - opline.save_changed = true; - } - else - {// the operand is not used in the instruction, so it can be evicted - if (ptrx->evicts != 0) - ptrx->evicts->push_back(opnd_reg); - } - - ptrx->regusage[opline.idx] |= mk; - } - - if (begx != endx) - endx->regusage[opline.idx] &= ~mk; - - bool before = false; - if (endx->inst->getMnemonic() == Mnemonic_CALL && !opline.isDef(endx->inst)) - { - Constraint ci = static_cast<CallInst*>(endx->inst)->getCalleeSaveRegs(getRegKind(rn)); - before = (ci.getMask() & mk) == 0; - } - saveOpnd(opline, endx, opnd_reg, before ? 0 : mk, opline.idx, before); + assert(rn != RegName_Null); + RegMask mk = getRegMask(rn); + Opnd* opnd_reg = opndReg(opline.opnd, rn); + + int reguses = 0; + + DBGOUT("assignReg " << *opline.opnd << " [" << *begx->inst + << " - " << *endx->inst << "] to " << *opnd_reg << endl;) + +#ifdef _OLD_ + loadOpnd(opline, begx, opnd_reg); +#else + if (loadOpnd(opline, begx, opnd_reg)) + (begx-1)->regusage[opline.idx] |= mk; +#endif + + for (Instx* ptrx = begx; ptrx <= endx; ++ptrx) + { + if (opline.save_changed && opline.catched && ptrx->inst->hasKind(Inst::Kind_CallInst)) + { + emitMove(true, ptrx->inst, opndMem(opline), opnd_reg); + opline.save_changed = false; + } + + if (ptrx->inst->replaceOpnd(opline.opnd, opnd_reg)) + {// the operand is used in the instruction + ++reguses; + if (opline.isDef(ptrx->inst)) + opline.save_changed = true; + } + else + {// the operand is not used in the instruction, so it can be evicted + if (ptrx->evicts != 0) + ptrx->evicts->push_back(opnd_reg); + } + +#ifdef _OLD_ + ptrx->regusage[opline.idx] |= mk; + } + if (begx != endx) + endx->regusage[opline.idx] &= ~mk; +#else + if (ptrx != endx) + ptrx->regusage[opline.idx] |= mk; + } +#endif + + bool before = false; + if (endx->inst->getMnemonic() == Mnemonic_CALL && !opline.isDef(endx->inst)) + { + Constraint ci = static_cast<CallInst*>(endx->inst)->getCalleeSaveRegs(getRegKind(rn)); + before = (ci.getMask() & mk) == 0; + } + saveOpnd(opline, endx, opnd_reg, before ? 0 : mk, opline.idx, before); #ifdef _DEBUG_SPILLGEN - assigns.incr(reguses); + assigns.incr(reguses); #endif } -// Split operand and assign memory location to it in the interval specified +// Split operand and assign memory location to it in the interval specified // ('begx' - 'endx', inclusive) // void SpillGen::assignMem (Opline& opline, Instx* begx, Instx* endx) { - opndMem(opline); + opndMem(opline); - DBGOUT("assignMem " << *opline.opnd << " [" << *begx->inst - << " - " << *endx->inst << "] to " << *opline.opnd_mem << endl;) + DBGOUT("assignMem " << *opline.opnd << " [" << *begx->inst + << " - " << *endx->inst << "] to " << *opline.opnd_mem << endl;) - loadOpnd(opline, begx, opline.opnd_mem); + loadOpnd(opline, begx, opline.opnd_mem); - if (opline.opnd != opline.opnd_mem) - for (; begx <= endx; ++begx) - { - begx->inst->replaceOpnd(opline.opnd, opline.opnd_mem); - } + if (opline.opnd != opline.opnd_mem) + for (; begx <= endx; ++begx) + { + begx->inst->replaceOpnd(opline.opnd, opline.opnd_mem); + } - saveOpnd(opline, endx, opline.opnd_mem); - opline.save_changed = false; + saveOpnd(opline, endx, opline.opnd_mem); + opline.save_changed = false; } -// Lazy save 'opnd' to memory at the point 'instx' +// Lazy save 'opnd' to memory at the point 'instx' // void SpillGen::saveOpnd (Opline& opline, Instx* instx, Opnd* opnd) { - opline.save_instx = instx; - opline.save_before = false; - opline.save_opnd = opnd; - opline.save_regmsk = 0; - opline.save_regidx = -1; + opline.save_instx = instx; + opline.save_before = false; + opline.save_opnd = opnd; + opline.save_regmsk = 0; + opline.save_regidx = -1; } void SpillGen::saveOpnd (Opline& opline, Instx* instx, Opnd* opnd, RegMask regmsk, int regidx, bool before) { - opline.save_instx = instx; - opline.save_before = before; - opline.save_opnd = opnd; - opline.save_regmsk = regmsk; - opline.save_regidx = regidx; + opline.save_instx = instx; + opline.save_before = before; + opline.save_opnd = opnd; + opline.save_regmsk = regmsk; + opline.save_regidx = regidx; } -// Load operand from memory to 'opnd' at the poinr 'instx' +// Load operand from memory to 'opnd' at the poinr 'instx' // +#ifdef _OLD_ void SpillGen::loadOpnd (Opline& opline, Instx* instx, Opnd* opnd) { - if (opline.save_instx == 0) - return; - - if (!opline.isUse(instx->inst)) - return; - - if (opline.save_opnd->hasAssignedPhysicalLocation()) - { - opndMem(opline); - if (opline.save_changed) - { - emitMove(opline.save_before, - opline.save_instx->inst, - opline.opnd_mem, - opline.save_opnd); - if (opline.save_regmsk != 0) - opline.save_instx->regusage[opline.save_regidx] |= opline.save_regmsk; - opline.save_changed = false; - } - emitMove(true, instx->inst, opnd, opline.opnd_mem); - } - else - { - if (opnd->hasAssignedPhysicalLocation()) - {// Assigned <- UnAssigned - emitMove(true, instx->inst, opnd, opline.save_opnd); - } - else - {// UnAssigned <- UnAssigned - assert(opnd == opline.save_opnd); - opline.save_opnd = opnd; - opline.save_instx = instx; - } - } + if (opline.save_instx == 0) + return; + + if (!opline.isUse(instx->inst)) + return; + + if (opline.save_opnd->hasAssignedPhysicalLocation()) + { + opndMem(opline); + if (opline.save_changed) + { + emitMove(opline.save_before, + opline.save_instx->inst, + opline.opnd_mem, + opline.save_opnd); + if (opline.save_regmsk != 0) + opline.save_instx->regusage[opline.save_regidx] |= opline.save_regmsk; + opline.save_changed = false; + } + emitMove(true, instx->inst, opnd, opline.opnd_mem); + } + else + { + if (opnd->hasAssignedPhysicalLocation()) + {// Assigned <- UnAssigned + emitMove(true, instx->inst, opnd, opline.save_opnd); + } + else + {// UnAssigned <- UnAssigned + assert(opnd == opline.save_opnd); + opline.save_opnd = opnd; + opline.save_instx = instx; + } + } +} +#else +bool SpillGen::loadOpnd (Opline& opline, Instx* instx, Opnd* opnd) +{ + if (opline.save_instx == 0 || !opline.isUse(instx->inst)) + return false; + + if (opline.save_opnd->hasAssignedPhysicalLocation()) + { + opndMem(opline); + if (opline.save_changed) + { + emitMove(opline.save_before, + opline.save_instx->inst, + opline.opnd_mem, + opline.save_opnd); + if (opline.save_regmsk != 0) + opline.save_instx->regusage[opline.save_regidx] |= opline.save_regmsk; + opline.save_changed = false; + } + emitMove(true, instx->inst, opnd, opline.opnd_mem); + } + else + { + if (opnd->hasAssignedPhysicalLocation()) + {// Assigned <- UnAssigned + emitMove(true, instx->inst, opnd, opline.save_opnd); + } + else + {// UnAssigned <- UnAssigned + assert(opnd == opline.save_opnd); + opline.save_opnd = opnd; + opline.save_instx = instx; + } + } + return true; } +#endif -// Save operand to memory +// Save operand to memory // void SpillGen::loadOpndMem (Opline& opline) { - if (opline.save_instx == 0) - return; - - if (opline.save_opnd->hasAssignedPhysicalLocation()) - { - if (opline.save_changed) - { - emitMove(opline.save_before, - opline.save_instx->inst, - opndMem(opline), - opline.save_opnd); - if (opline.save_regmsk != 0) - opline.save_instx->regusage[opline.save_regidx] |= opline.save_regmsk; - opline.save_changed = false; - } - } + if (opline.save_instx == 0) + return; + + if (opline.save_opnd->hasAssignedPhysicalLocation()) + { + if (opline.save_changed) + { + emitMove(opline.save_before, + opline.save_instx->inst, + opndMem(opline), + opline.save_opnd); + if (opline.save_regmsk != 0) + opline.save_instx->regusage[opline.save_regidx] |= opline.save_regmsk; + opline.save_changed = false; + } + } } Opnd* SpillGen::opndMem (Opline& opline) { - if (opline.opnd_mem == 0) - opline.opnd_mem = opndMem(opline.opnd); + if (opline.opnd_mem == 0) + opline.opnd_mem = opndMem(opline.opnd); - return opline.opnd_mem; + return opline.opnd_mem; } static bool operator == (const SpillGen::TwoOpnds& p, const Opnd* o) { - return p.first == o; + return p.first == o; } Opnd* SpillGen::opndMem (const Opnd* opnd) { - Opnd* opnd_mem; - - MemOpnds::iterator ptr, end; - if ((ptr = find(memopnds.begin(), end = memopnds.end(), opnd)) == end) - { - opnd_mem = irManager.newMemOpnd(opnd->getType(), - MemOpndKind_StackAutoLayout, - irManager.getRegOpnd(RegName_ESP), - 0); - memopnds.push_back(TwoOpnds(opnd, opnd_mem)); + Opnd* opnd_mem; + + MemOpnds::iterator ptr, end; + if ((ptr = find(memopnds.begin(), end = memopnds.end(), opnd)) == end) + { + opnd_mem = irManager->newMemOpnd(opnd->getType(), + MemOpndKind_StackAutoLayout, + irManager->getRegOpnd(STACK_REG), + 0); + memopnds.push_back(TwoOpnds(opnd, opnd_mem)); #ifdef _DEBUG_SPILLGEN - DBGOUT("split " << *opnd << " -> mem " << *opnd_mem << endl;) - if (dbgraw != 0) - dbgraw->split(opnd, opnd_mem); + DBGOUT("split " << *opnd << " -> mem " << *opnd_mem << endl;) + //if (dbgraw != 0) + // dbgraw->split(opnd, opnd_mem); #endif - } - else - { - opnd_mem = ptr->second; - } + } + else + { + opnd_mem = ptr->second; + } - return opnd_mem; + return opnd_mem; } Opnd* SpillGen::opndReg (const Opnd* opnd, RegName rn) const { - Opnd* opnd_reg = irManager.newRegOpnd(opnd->getType(), rn); + Opnd* opnd_reg = irManager->newRegOpnd(opnd->getType(), getRegName(getRegKind(rn), opnd->getSize(), getRegIndex(rn))); #ifdef _DEBUG_SPILLGEN - DBGOUT("split " << *opnd << " -> reg " << *opnd_reg << endl;) - if (dbgraw != 0) - dbgraw->split(opnd, opnd_reg); + DBGOUT("split " << *opnd << " -> reg " << *opnd_reg << endl;) + //if (dbgraw != 0) + // dbgraw->split(opnd, opnd_reg); #endif - return opnd_reg; + return opnd_reg; } void SpillGen::emitPushPop (bool before, Inst* inst, Opnd* opnd, bool push) { - if (push) - emitMove(before, inst, opndMem(opnd), opnd); - else - emitMove(before, inst, opnd, opndMem(opnd)); + if (push) + emitMove(before, inst, opndMem(opnd), opnd); + else + emitMove(before, inst, opnd, opndMem(opnd)); } -// Emit 'mov' instruction before/after the instruction specified +// Emit 'mov' instruction before/after the instruction specified // Inst* SpillGen::emitMove (bool before, Inst* inst, Opnd* dst, Opnd* src) { - if (dst == src) - return 0; - - Inst* mov = irManager.newCopyPseudoInst(Mnemonic_MOV, dst, src); - if (before) - bblock->prependInsts(mov, inst); - else - { - // ensure we don't append after any branch instructions - // for example, after the last instruction in basic block - assert(!inst->hasKind(Inst::Kind_BranchInst)); - bblock->appendInsts(mov, inst); - } - - DBGOUT((before?"before":" after") << " " << *inst << " " - << *mov << " MOV " << *dst << " " << *src << endl;) - emitted++; - - return mov; -} - - -/* -RegName SpillGen::findFree (RegMask usable, int idx, Instx*) -{ - Constraint c = registers[idx]; - usable &= c.getMask(); // search only from available registers - -// Start search from the highest register number - size_t x = 15; - for (RegMask r = 1 << x; r != 0; r >>= 1, --x) - if ((usable & r) != 0) - return getRegName(static_cast<OpndKind>(c.getKind()), c.getSize(), x); - - return RegName_Null; + if (dst == src) + return 0; + + Inst* mov = irManager->newCopyPseudoInst(Mnemonic_MOV, dst, src); + if (before) { + mov->insertBefore(inst); + } else + { + // ensure we don't append after any branch instructions + // for example, after the last instruction in basic block + assert(!inst->hasKind(Inst::Kind_LocalControlTransferInst)); + mov->insertAfter(inst); + } + + DBGOUT((before?"before":" after") << " " << *inst << " " + << *mov << " MOV " << *dst << " " << *src << endl;) + emitted++; + + return mov; } -*/ - RegName SpillGen::findFree (RegMask usable, int idx, Instx* instx) { - Constraint c = registers[idx]; - usable &= c.getMask(); // search only from available registers - - Instx* begx = &*instxs.begin(); ++begx; - Instx* endx = &*instxs.end(); - Instx* ptrx; - - size_t xbest = INT_MAX, - xbest_free = INT_MAX, - xlgth_free = 0, - xbest_press = INT_MAX, - xlgth_press = 0; - - size_t x, found; - RegMask msk; - for (x = 0, found = 0, msk = 1; usable != 0; ++x, msk <<= 1) - if ((usable & msk) != 0) - { - usable ^= msk, ++found; - if (usable == 0 && found == 1) - {// this is the only register available - no need to choose the best - xbest = x; - break; - } - - size_t lgth = 0; - bool press = (instx->regpress[idx] & msk) != 0; - - for (ptrx = instx-1; ptrx >= begx && (ptrx->regusage[idx] & msk) == 0; --ptrx) - { - ++lgth; - press |= (ptrx->regpress[idx] & msk) != 0; - } - - for (ptrx = instx+1; ptrx < endx && (ptrx->regusage[idx] & msk) == 0; ++ptrx) - { - ++lgth; - press |= (ptrx->regpress[idx] & msk) != 0; - } - - if (press) - { - if (xbest_press == INT_MAX || xlgth_press >= lgth) - xbest_press = x, - xlgth_press = lgth; - } - else - { - if (xbest_free == INT_MAX || xlgth_free >= lgth) - xbest_free = x, - xlgth_free = lgth; - } - } - - if (xbest == INT_MAX) - xbest = xbest_free != INT_MAX ? xbest_free : xbest_press; - - return xbest == INT_MAX ? - RegName_Null : - getRegName(static_cast<OpndKind>(c.getKind()), c.getSize(), xbest); + Constraint c = registers[idx]; + usable &= c.getMask(); // search only from available registers + + Instx* begx = &*instxs.begin(); ++begx; + Instx* endx = &*instxs.end(); + Instx* ptrx; + + size_t xbest = INT_MAX, + xbest_free = INT_MAX, + xlgth_free = 0, + xbest_press = INT_MAX, + xlgth_press = 0; + + size_t x, found; + RegMask msk; + for (x = 0, found = 0, msk = 1; usable != 0; ++x, msk <<= 1) + if ((usable & msk) != 0) + { + usable ^= msk, ++found; + if (usable == 0 && found == 1) + {// this is the only register available - no need to choose the best + xbest = x; + break; + } + + size_t lgth = 0; + bool press = (instx->regpress[idx] & msk) != 0; + + for (ptrx = instx-1; ptrx >= begx && (ptrx->regusage[idx] & msk) == 0; --ptrx) + { + ++lgth; + press |= (ptrx->regpress[idx] & msk) != 0; + } + + for (ptrx = instx+1; ptrx < endx && (ptrx->regusage[idx] & msk) == 0; ++ptrx) + { + ++lgth; + press |= (ptrx->regpress[idx] & msk) != 0; + } + + if (press) + { + if (xbest_press == INT_MAX || xlgth_press >= lgth) + xbest_press = x, + xlgth_press = lgth; + } + else + { + if (xbest_free == INT_MAX || xlgth_free >= lgth) + xbest_free = x, + xlgth_free = lgth; + } + } + + if (xbest == INT_MAX) + xbest = xbest_free != INT_MAX ? xbest_free : xbest_press; + + return xbest == INT_MAX ? + RegName_Null : + getRegName(static_cast<OpndKind>(c.getKind()), c.getSize(), xbest); } RegName SpillGen::findEvict (RegMask usable, int idx, Instx* begx, Instx*& endx) { - Constraint c = registers[idx]; - Inst* inst = begx->inst; - Opnd* opnd; - - RegMask used = 0; - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) - used |= getRegMaskConstr(inst->getOpnd(it), c); - - usable &= ~used; - if (usable == 0) - return RegName_Null; - - if (!evicts_known) - setupEvicts(); - - Evicts evicts(mm); - - for (Opnds::iterator it = begx->evicts->begin(); it != begx->evicts->end(); ++it) - if ((opnd = *it) != 0 && (usable & getRegMaskConstr(opnd, c)) != 0) - { - Evict tmp; - tmp.opnd = opnd; - tmp.begx = begx; - tmp.endx = begx; - evicts.push_back(tmp); - } - - if (evicts.empty()) - return RegName_Null; - - Evict* evict = pickEvict(evicts); - if (evict == 0) - return RegName_Null; - - if (evict->endx->inst->hasKind(Inst::Kind_BranchInst)) - if (--(evict->endx) < evict->begx) - return RegName_Null; - - if (endx > evict->endx) - endx = evict->endx; - -// now evict the operand found - - emitPushPop(true, evict->begx->inst, evict->opnd, true); - emitPushPop(false, evict->endx->inst, evict->opnd, false); - -// update the 'instxs' table - - RegName rn = evict->opnd->getRegName(); - RegMask mk = getRegMask(rn); - assert((usable & mk)); - - Instx* ptrx; - for (ptrx = evict->begx; ptrx <= evict->endx; ++ptrx) - { - // mark register assigned to the operand as free - ptrx->regusage[idx] &= ~mk; - - // clear the operand as a candidate to evict - killEvict(evict->opnd, ptrx); - } - - if (ptrx <= &instxs.back()) - ptrx->regusage[idx] |= mk; + Constraint c = registers[idx]; + Inst* inst = begx->inst; + Opnd* opnd; + + RegMask used = 0; + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) + used |= getRegMaskConstr(inst->getOpnd(it), c); + + usable &= ~used; + if (usable == 0) + return RegName_Null; + + if (!evicts_known) + setupEvicts(); + + Evicts evicts(mm); + + for (Opnds::iterator it = begx->evicts->begin(); it != begx->evicts->end(); ++it) + if ((opnd = *it) != 0 && (usable & getRegMaskConstr(opnd, c)) != 0) + { + Evict tmp; + tmp.opnd = opnd; + tmp.begx = begx; + tmp.endx = begx; + evicts.push_back(tmp); + } + + if (evicts.empty()) + return RegName_Null; + + Evict* evict = pickEvict(evicts); + if (evict == 0) + return RegName_Null; + + if (evict->endx->inst->hasKind(Inst::Kind_LocalControlTransferInst)) + if (--(evict->endx) < evict->begx) + return RegName_Null; + + if (endx > evict->endx) + endx = evict->endx; + +// now evict the operand found + + emitPushPop(true, evict->begx->inst, evict->opnd, true); + emitPushPop(false, evict->endx->inst, evict->opnd, false); + +// update the 'instxs' table + + RegName rn = evict->opnd->getRegName(); + RegMask mk = getRegMask(rn); + assert((usable & mk)); + + Instx* ptrx; +#ifdef _OLD_ + for (ptrx = evict->begx; ptrx <= evict->endx; ++ptrx) + { + // mark register assigned to the operand as free + ptrx->regusage[idx] &= ~mk; + + // clear the operand as a candidate to evict + killEvict(evict->opnd, ptrx); + } + if (ptrx <= &instxs.back()) + ptrx->regusage[idx] |= mk; +#else + for (ptrx = evict->begx; ptrx <= evict->endx; ++ptrx) + { + // mark register assigned to the operand as free + if (ptrx != evict->endx) + ptrx->regusage[idx] &= ~mk; + + // clear the operand as a candidate to evict + killEvict(evict->opnd, ptrx); + } +#endif - return rn; + return rn; } void SpillGen::setupEvicts () { - Opnd* opnd; - -// will be used to calculate all registers used in an instruction - Registers used(mm); - used = registers; - - Registers* catched = 0; - - LiveSet ls = *lives_exit; - ls.resize(irManager.getOpndCount()); - LiveSet lsnext = ls; - - const Insts& insts = bblock->getInsts(); - Instxs::iterator instxp = instxs.end() - 1; - for (Inst* inst = insts.getLast(); inst != 0; inst = insts.getPrev(inst)) - { - used.clearMasks(); // mask of all registers used in the current instruction - Inst::Opnds opnds(inst, Inst::OpndRole_All); - for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) - { - opnd = inst->getOpnd(it); - - RegMask msk; - int idx; - Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - if ((msk = loc.getMask()) != 0 && (idx = registers.getIndex(loc)) != -1) - {// this operand is already assigned to some location/register - if (inst->isLiveRangeEnd(it)) - lsnext.setBit(opnd->getId(), false); - else if (inst->isLiveRangeStart(it)) - lsnext.setBit(opnd->getId(), true); - - merge(used[idx], msk); - } - } - - if (inst->hasKind(Inst::Kind_CallInst) && lives_catch != 0) - { - if (catched == 0) - {// construct the catched operand list - once per block - catched = new (mm) Registers(mm); - *catched = registers; - catched->clearMasks(); - - LiveSet::IterB lives(*lives_catch); - for (int i = lives.getNext(); i != -1; i = lives.getNext()) - { - opnd = irManager.getOpnd(i); - RegMask msk; - int idx; - Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - if ((msk = loc.getMask()) != 0 && (idx = registers.getIndex(loc)) != -1) - { - merge((*catched)[idx], msk); - } - } - } - used.merge(*catched); - } - - if (inst == instxp->inst) - { - if (instxp->evicts == 0) - instxp->evicts = new (mm) Opnds(mm); - else - instxp->evicts->resize(0); - - LiveSet::IterB lives(ls); - for (int i = lives.getNext(); i != -1; i = lives.getNext()) - { - opnd = irManager.getOpnd(i); - Constraint loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); - if (loc.getMask() != 0 && registers.contains(loc) && !used.contains(loc)) - { - instxp->evicts->push_back(opnd); - } - } - - --instxp; - } - - ls = lsnext; - } - - evicts_known = true; + Opnd* opnd; + Constraint loc; + RegMask msk; + int idx; + +// will be used to calculate all registers used in an instruction + Registers used(mm); + used = registers; + + Registers* catched = 0; + + BitSet ls = *lives_exit; + ls.resize(irManager->getOpndCount()); + BitSet lsnext = ls; + + Instxs::iterator instxp = instxs.end() - 1; + for (Inst* inst = (Inst*)bblock->getLastInst(); inst != 0; inst = inst->getPrevInst()) + { + used.clearMasks(); // mask of all registers used in the current instruction + + Inst::Opnds opnds(inst, Inst::OpndRole_All); + for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)) + { + opnd = inst->getOpnd(it); + loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if ((msk = loc.getMask()) != 0 && (idx = registers.getIndex(loc)) != -1) + {// this operand is already assigned to some location/register + if (inst->isLiveRangeEnd(it)) + lsnext.setBit(opnd->getId(), false); + else if (inst->isLiveRangeStart(it)) + lsnext.setBit(opnd->getId(), true); + + merge(used[idx], msk); + } + } + + if (inst->hasKind(Inst::Kind_CallInst) && lives_catch != 0) + { + if (catched == 0) + {// construct the catched operand list - once per block + catched = new (mm) Registers(mm); + *catched = registers; + catched->clearMasks(); + + BitSet::IterB lives(*lives_catch); + for (int i = lives.getNext(); i != -1; i = lives.getNext()) + { + opnd = irManager->getOpnd(i); + loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if ((msk = loc.getMask()) != 0 && (idx = registers.getIndex(loc)) != -1) + merge((*catched)[idx], msk); + } + } + used.merge(*catched); + } + + if (inst == instxp->inst) + { + if (instxp->evicts == 0) + instxp->evicts = new (mm) Opnds(mm); + else + instxp->evicts->resize(0); + + BitSet::IterB lives(ls); + for (int i = lives.getNext(); i != -1; i = lives.getNext()) + { + opnd = irManager->getOpnd(i); + loc = opnd->getConstraint(Opnd::ConstraintKind_Location, OpndSize_Default); + if (loc.getMask() != 0 && registers.contains(loc) && !used.contains(loc)) + instxp->evicts->push_back(opnd); + } + + --instxp; + } + + ls = lsnext; + } + + evicts_known = true; } SpillGen::Evict* SpillGen::pickEvict (Evicts& evicts) { - Instx* begx = &*instxs.begin(); ++begx; - Instx* endx = &*instxs.end(); - Instx* ptrx; + Instx* begx = &*instxs.begin(); ++begx; + Instx* endx = &*instxs.end(); + Instx* ptrx; - DBGOUT("Evicts" << endl;) - for (Evicts::iterator it = evicts.begin(); it != evicts.end(); ++it) - { - Evict& evict = *it; + DBGOUT("Evicts" << endl;) + for (Evicts::iterator it = evicts.begin(); it != evicts.end(); ++it) + { + Evict& evict = *it; - for (ptrx = evict.begx-1; ptrx >= begx && isEvict(evict.opnd, ptrx); --ptrx) - evict.begx = ptrx; + for (ptrx = evict.begx-1; ptrx >= begx && isEvict(evict.opnd, ptrx); --ptrx) + evict.begx = ptrx; - for (ptrx = evict.endx+1; ptrx < endx && isEvict(evict.opnd, ptrx); ++ptrx) - evict.endx = ptrx; + for (ptrx = evict.endx+1; ptrx < endx && isEvict(evict.opnd, ptrx); ++ptrx) + evict.endx = ptrx; - evict.weight = evict.endx - evict.begx; + evict.weight = evict.endx - evict.begx; - DBGOUT(" evict " << *evict.opnd << " [" << *evict.begx->inst - << " - " << *evict.endx->inst << "] w:" << evict.weight << endl;) - } + DBGOUT(" evict " << *evict.opnd << " [" << *evict.begx->inst + << " - " << *evict.endx->inst << "] w:" << evict.weight << endl;) + } - return &*max_element(evicts.begin(), evicts.end()); + return &*max_element(evicts.begin(), evicts.end()); } bool SpillGen::isEvict (const Opnd* opnd, const Instx* ptrx) const { - Opnds::iterator endx = ptrx->evicts->end(); - return find(ptrx->evicts->begin(), endx, opnd) != endx; + Opnds::iterator endx = ptrx->evicts->end(); + return find(ptrx->evicts->begin(), endx, opnd) != endx; } void SpillGen:: killEvict (const Opnd* opnd, Instx* instx) const { - Opnds::iterator end = instx->evicts->end(); - Opnds::iterator it = find(instx->evicts->begin(), end, opnd); - if (it != end) - *it = 0; + Opnds::iterator end = instx->evicts->end(); + Opnds::iterator it = find(instx->evicts->begin(), end, opnd); + if (it != end) + *it = 0; } SpillGen::RegMask SpillGen::getRegMaskConstr (const Opnd* opnd, Constraint c) const { - return opnd->isPlacedIn(c.getAliasConstraint(OpndSize_Default)) ? - getRegMask(opnd->getRegName()) : 0; + return opnd->isPlacedIn(c.getAliasConstraint(OpndSize_Default)) ? + getRegMask(opnd->getRegName()) : 0; } +#ifdef _DEBUG_SPILLGEN +#include "Ia32SpillGenDbgTail.h" +#endif + + } //namespace Ia32 } //namespace Jitrino -#ifdef _DEBUG_SPILLGEN -#include "Ia32SpillGenDbgTail.h" -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.h vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.h deleted file mode 100644 index a59a850..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32SpillGen.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Sergey L. Ivashin - * @version $Revision: 1.14.20.3 $ - */ - -#if !defined(__IA32SPILLGEN_H_INCLUDED__) -#define __IA32SPILLGEN_H_INCLUDED__ - -#include "Ia32IRManager.h" -#include "Stl.h" - - -namespace Jitrino -{ - -namespace Ia32 -{ - -BEGIN_DECLARE_IRTRANSFORMER(SpillGen, "spillgen", "Spill code generator") - - SpillGen (IRManager&, const char * params); - ~SpillGen (); - - uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} - uint32 getSideEffects () const {return SideEffect_InvalidatesLivenessInfo;} - - void runImpl(); - bool verify(bool force=false); - -// Inter-blocks data -// ----------------- - - typedef uint32 RegMask; - typedef StlVector<Opnd*> Opnds; - - MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() - - // Table of all available registers sets. - // Each set (GPReg, FPReg, XMMReg and so on) is represented by the corresponding - // Constraint object. - struct Registers : public StlVector<Constraint> - { - Registers (MemoryManager& mm) :StlVector<Constraint>(mm) {} - - void parse (const char*); - - // clear mask fields in all elements of the table - void clearMasks (); - - void merge (const Registers&); - - // register the new constraint (register) in the table. - // if table doesn't contain constraint of the specified kind, it will be ignored - // (add = false) or new table entry for the constraint will be created (add = true). - int merge (const Constraint&, bool add = false); - - // returns table index of the constraint of the specified kind or -1 - int getIndex (const Constraint&) const; - - // returns pointer to the table element of the specified kind - Constraint* contains (const Constraint&); - - int indexes[IRMaxRegKinds]; - }; - Registers registers; - - size_t opndcount; // initial count of operands - size_t emitted; // extra instructions count - size_t fails; // if != 0, then SpillGen should be aborted - - // mapping operand -> its memory location - // every operand that was splitted to memory is registered in this table - typedef ::std::pair<const Opnd*, Opnd*> TwoOpnds; - typedef StlVector<TwoOpnds> MemOpnds; - MemOpnds memopnds; - - -// Block-specific data -// ------------------- - - - // extension of 'Inst' structure with some specific data - struct Instx; - typedef StlVector<Instx> Instxs; - Instxs instxs; - - // created for all problem (needed to be allocated) operands - struct Op; - struct Opline; - typedef StlVector<Opline> Oplines; - Oplines actives; - StlVector<Opline*> actsmap; - - struct Evict; - typedef StlVector<Evict> Evicts; - - // current context - BasicBlock* bblock; // the basic block being processed - LiveSet* lives_start, // liveness info for start and end of the block - * lives_exit; // - LiveSet* lives_catch; // 0 or mask of operands live at the corresponding dispatch node - - bool evicts_known; - - -// Methods -// ------- - - size_t pass0 (); - size_t pass1 (); - RegMask lookPreffered (Opline&); - bool tryRegister (Opline&, Constraint, RegMask); - bool tryMemory (Opline&, Constraint); - bool tryEvict (Opline&, Constraint); - bool tryRepair (Opline&, Constraint); - bool simplify (Inst*, Opnd*); - RegMask usedRegs (const Instx*, int idx, bool isuse) const; - RegMask callRegs (const Instx*, int idx) const; - int update (const Inst*, const Opnd*, Constraint&) const; - void assignReg (Opline&, Instx* begx, Instx* endx, RegName); - void assignMem (Opline&, Instx* begx, Instx* endx); - void saveOpnd (Opline&, Instx*, Opnd*); - void saveOpnd (Opline&, Instx*, Opnd*, RegMask, int, bool); - void loadOpnd (Opline&, Instx*, Opnd*); - void loadOpndMem (Opline&); - Opnd* opndMem (Opline&); - Opnd* opndMem (const Opnd*); - Opnd* opndReg (const Opnd*, RegName) const; - void emitPushPop (bool before, Inst*, Opnd* opnd, bool push); - Inst* emitMove (bool before, Inst*, Opnd* dst, Opnd* src); - RegName findFree (RegMask usable, int idx, Instx* begx); - RegName findEvict (RegMask usable, int idx, Instx* begx, Instx*& endx); - void setupEvicts (); - Evict* pickEvict (Evicts&); - bool isEvict (const Opnd*, const Instx*) const; - void killEvict (const Opnd*, Instx*) const; - RegMask getRegMaskConstr (const Opnd*, Constraint) const; - -END_DECLARE_IRTRANSFORMER(SpillGen) - - -} //namespace Ia32 -} //namespace Jitrino - -#endif diff --git vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.cpp vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.cpp index 79473af..5fcebaf 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.cpp @@ -18,66 +18,98 @@ * @version $Revision: 1.14.14.3.4.4 $ */ +#include "Ia32IRManager.h" #include "Stl.h" #include "Ia32StackInfo.h" #include "Ia32RuntimeInterface.h" #include "Ia32InternalTrace.h" #include <math.h> + namespace Jitrino { namespace Ia32 { +//======================================================================================== +// class StackInfoInstRegistrar +//======================================================================================== +/** + * class StackInfoInstRegistrar performs calling of StackInfo method which + * performes saving information about call instructions for stack unwinding + * + * This transformer ensures that it calls the proper method + * + * This transformer must inserted after Code Emitter, because it needs + * EIP value for instructions. + */ + +class StackInfoInstRegistrar : public SessionAction { + void runImpl() + { + StackInfo * stackInfo = (StackInfo*)irManager->getInfo("stackInfo"); + assert(stackInfo!=NULL); + stackInfo->registerInsts(*irManager); + stackInfo->setMethodExitString(*irManager); + } + uint32 getNeedInfo()const{ return 0; } + uint32 getSideEffects()const{ return 0; } + bool isIRDumpEnabled(){ return false; } +}; + + +static ActionFactory<StackInfoInstRegistrar> _si_insts("si_insts"); + #define CALL_MIN_SIZE 2 #define CALL_MAX_SIZE 6 -uint32 hashFunc(uint32 key, uint32 hashTableSize) { - return (key % hashTableSize); +POINTER_SIZE_INT hashFunc(POINTER_SIZE_INT key, uint32 hashTableSize) { + return (key % hashTableSize); } - StackDepthInfo hashGet(DepthEntry** entries, uint32 key, uint32 hashTableSize) { - DepthEntry * e = entries[hashFunc(key,hashTableSize)]; - assert(e); - for(;e !=NULL;) { - if(e->eip == key) - return e->info; - else - e = e->next; - assert(e); - } - return e->info; - } - - void hashSet(DepthEntry** entries, uint32 eip, uint32 hashTableSize,StackDepthInfo info, MemoryManager& mm) { - uint32 key = hashFunc(eip,hashTableSize); - DepthEntry * e = entries[key]; - if(!e) { - entries[key] = new(mm) DepthEntry(eip, info, NULL); - } else { - for(;e->next!=NULL;e = e->next) ; - e->next = new(mm) DepthEntry(eip, info, NULL); - } - } - -uint32 StackInfo::getByteSize() const { - return byteSize ? - byteSize : - (sizeof(StackInfo)+(stackDepthInfo?stackDepthInfo->size()*sizeof(DepthEntry):0))+hashTableSize*4; + StackDepthInfo hashGet(DepthEntry** entries, POINTER_SIZE_INT key, uint32 hashTableSize) { + DepthEntry * e = entries[hashFunc(key,hashTableSize)]; + assert(e); + for(;e !=NULL;) { + if(e->eip == key) + return e->info; + else + e = e->next; + assert(e); + } + return e->info; + } + + void hashSet(DepthEntry** entries, POINTER_SIZE_INT eip, uint32 hashTableSize,StackDepthInfo info, MemoryManager& mm) { + POINTER_SIZE_INT key = hashFunc(eip,hashTableSize); + DepthEntry * e = entries[key]; + if(!e) { + entries[key] = new(mm) DepthEntry(eip, info, NULL); + } else { + for(;e->next!=NULL;e = e->next) ; + e->next = new(mm) DepthEntry(eip, info, NULL); + } + } + +POINTER_SIZE_INT StackInfo::getByteSize() const { + return byteSize ? + byteSize : + (sizeof(StackInfo)+(stackDepthInfo?stackDepthInfo->size()*sizeof(DepthEntry):0))+hashTableSize*sizeof(POINTER_SIZE_INT); } -uint32 StackInfo::getByteSize(MethodDesc* md) { +POINTER_SIZE_INT StackInfo::getByteSize(MethodDesc* md) { Byte* data = md->getInfoBlock(); - return *(uint32*)data; + return *(POINTER_SIZE_INT*)data; } -uint32 StackInfo::readByteSize(const Byte* bytes) const{ - uint32* data = (uint32 *) bytes; - uint32 sizeInBytes = *data; +POINTER_SIZE_INT StackInfo::readByteSize(const Byte* bytes) const{ + POINTER_SIZE_INT* data = (POINTER_SIZE_INT *) bytes; + POINTER_SIZE_INT sizeInBytes = *data; return sizeInBytes; } typedef DepthEntry * EntryPtr; + void StackInfo::write(Byte* bytes) { Byte* data = bytes; StackInfo* serializedInfo = (StackInfo*)data; @@ -85,127 +117,183 @@ void StackInfo::write(Byte* bytes) { serializedInfo->byteSize = getByteSize(); data+=sizeof(StackInfo); MemoryManager mm(0x100, "DepthInfo"); - EntryPtr * entries = new(mm) EntryPtr[hashTableSize]; - for(uint32 i = 0; i< hashTableSize; i++) - entries[i] = NULL; - for(DepthMap::iterator dmit = stackDepthInfo->begin(); dmit != stackDepthInfo->end(); dmit++) { - hashSet(entries, dmit->first, hashTableSize, dmit->second, mm); - } - Byte* next = data + hashTableSize * 4; - for(uint32 i = 0; i< hashTableSize; i++) { - DepthEntry * e = entries[i]; - uint32 serializedEntryAddr = 0; - if(entries[i]) { - serializedEntryAddr = (uint32)next; + EntryPtr * entries = new(mm) EntryPtr[hashTableSize]; + for(uint32 i = 0; i< hashTableSize; i++) + entries[i] = NULL; + for(DepthMap::iterator dmit = stackDepthInfo->begin(); dmit != stackDepthInfo->end(); dmit++) { + hashSet(entries, dmit->first, hashTableSize, dmit->second, mm); + } + Byte* next = data + hashTableSize * sizeof(POINTER_SIZE_INT); + for(uint32 i = 0; i< hashTableSize; i++) { + DepthEntry * e = entries[i]; + POINTER_SIZE_INT serializedEntryAddr = 0; + if(entries[i]) { + serializedEntryAddr = (POINTER_SIZE_INT)next; for(; e != NULL; e = e->next) { DepthEntry* serialized = (DepthEntry*)next; *serialized = *e; next+=sizeof(DepthEntry); serialized->next = e->next ? (DepthEntry*)next : NULL; - } - } - *((uint32*)data)= serializedEntryAddr; - data+=4; - } - assert(getByteSize() == (uint32) (((Byte*) next) - bytes)); + } + } + *((POINTER_SIZE_INT*)data)= serializedEntryAddr; + data+=sizeof(POINTER_SIZE_INT); + } + assert(getByteSize() == (POINTER_SIZE_INT) (((Byte*) next) - bytes)); } -DepthEntry * getHashEntry(Byte * data, uint32 eip, uint32 size) +DepthEntry * getHashEntry(Byte * data, POINTER_SIZE_INT eip, uint32 size) { - if(!size) - return NULL; - uint32 key = hashFunc(eip,size); - data += sizeof(StackInfo) + key * sizeof(uint32); - DepthEntry * entry = (DepthEntry *)*(uint32*)data; - for(;entry && entry->eip != eip; entry = entry->next) { - assert(entry!=entry->next); - } - return entry; + if(!size) + return NULL; + POINTER_SIZE_INT key = hashFunc(eip,size); + data += sizeof(StackInfo) + key * sizeof(POINTER_SIZE_INT); + DepthEntry * entry = (DepthEntry *)*(POINTER_SIZE_INT*)data; + for(;entry && entry->eip != eip; entry = entry->next) { + assert(entry!=entry->next); + } + return entry; } -void StackInfo::read(MethodDesc* pMethodDesc, uint32 eip, bool isFirst) { +void StackInfo::read(MethodDesc* pMethodDesc, POINTER_SIZE_INT eip, bool isFirst) { Byte* data = pMethodDesc->getInfoBlock(); - byteSize = ((StackInfo *)data)->byteSize; - hashTableSize = ((StackInfo *)data)->hashTableSize; - frameSize = ((StackInfo *)data)->frameSize; - icalleeOffset = ((StackInfo *)data)->icalleeOffset; - icalleeMask = ((StackInfo *)data)->icalleeMask; - localOffset = ((StackInfo *)data)->localOffset; - offsetOfThis = ((StackInfo *)data)->offsetOfThis; - itraceMethodExitString = ((StackInfo *)data)->itraceMethodExitString; - - if (!isFirst){ - DepthEntry * entry = getHashEntry(data, eip, hashTableSize); - assert(entry); - if (!entry){ - if (Log::cat_rt()->isFailEnabled()) - Log::cat_rt()->out()<<"eip=0x"<<(void*)eip<<" not found during stack unwinding!"<<::std::endl; - ::std::cerr<<"eip=0x"<<(void*)eip<<" not found during stack unwinding!"<<::std::endl; - } - callerSaveRegsConstraint =entry->info.callerSaveRegs; - calleeSaveRegsMask = entry->info.calleeSaveRegs; - stackDepth = entry->info.stackDepth; - }else{ - DepthEntry * entry = NULL; - uint32 i = CALL_MIN_SIZE; - for (; i<= CALL_MAX_SIZE; i++) { - entry = getHashEntry(data, eip + i, hashTableSize); - if(entry) - break; - } - if (entry && (entry->info.callSize == i)) { - stackDepth = entry->info.stackDepth; - } else { - stackDepth = frameSize; - } - - if (Log::cat_rt()->isDebugEnabled()) - Log::cat_rt()->out()<<"Hardware exception from eip=0x"<<(void*)eip<<::std::endl; - } + byteSize = ((StackInfo *)data)->byteSize; + hashTableSize = ((StackInfo *)data)->hashTableSize; + frameSize = ((StackInfo *)data)->frameSize; + icalleeOffset = ((StackInfo *)data)->icalleeOffset; + icalleeMask = ((StackInfo *)data)->icalleeMask; + localOffset = ((StackInfo *)data)->localOffset; + offsetOfThis = ((StackInfo *)data)->offsetOfThis; + itraceMethodExitString = ((StackInfo *)data)->itraceMethodExitString; + + if (!isFirst){ + DepthEntry * entry = getHashEntry(data, eip, hashTableSize); + assert(entry); + if (!entry){ + if (Log::cat_rt()->isEnabled()) + Log::cat_rt()->out()<<"eip=0x"<<(void*)eip<<" not found during stack unwinding!"<<::std::endl; + ::std::cerr<<"eip=0x"<<(void*)eip<<" not found during stack unwinding!"<<::std::endl; + } + calleeSaveRegsMask = entry->info.calleeSaveRegs; + stackDepth = entry->info.stackDepth; + }else{ + DepthEntry * entry = NULL; + uint32 i = CALL_MIN_SIZE; + for (; i<= CALL_MAX_SIZE; i++) { + entry = getHashEntry(data, eip + i, hashTableSize); + if(entry) + break; + } + if (entry && (entry->info.callSize == i)) { + stackDepth = entry->info.stackDepth; + } else { + stackDepth = frameSize; + } + + if (Log::cat_rt()->isEnabled()) + Log::cat_rt()->out()<<"Hardware exception from eip=0x"<<(void*)eip<<::std::endl; + } } void StackInfo::unwind(MethodDesc* pMethodDesc, JitFrameContext* context, bool isFirst) const { - if (itraceMethodExitString!=NULL){ - Log::cat_rt()->out()<<"__UNWIND__:" - <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") - <<"; unwound from EIP="<<(void*)*context->p_eip - <<::std::endl; - } + + POINTER_SIZE_INT offset_step = sizeof(POINTER_SIZE_INT); +#ifdef _EM64T_ + if (itraceMethodExitString!=NULL){ + Log::cat_rt()->out()<<"__UNWIND__:" + <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") + <<"; unwound from EIP="<<(void*)*context->p_rip + <<::std::endl; + } + + assert(!(context->rsp & 15)); + context->rsp += stackDepth; + + POINTER_SIZE_INT offset = context->rsp; + context->p_rip = (POINTER_SIZE_INT *) (offset); + + offset += icalleeOffset; + if(getRegMask(RegName_R15) & icalleeMask) { + context->p_r15 = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_R14) & icalleeMask) { + context->p_r14 = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_R13) & icalleeMask) { + context->p_r13 = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_R12) & icalleeMask) { + context->p_r12 = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_RBP) & icalleeMask) { + context->p_rbp = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_RBX) & icalleeMask) { + context->p_rbx = (POINTER_SIZE_INT *) offset; + } + context->rsp += offset_step; //IP register size +#else + if (itraceMethodExitString!=NULL){ + Log::cat_rt()->out()<<"__UNWIND__:" + <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") + <<"; unwound from EIP="<<(void*)*context->p_eip + <<::std::endl; + } context->esp += stackDepth; - uint32 offset = context->esp; - context->p_eip = (uint32 *) offset; - - offset += icalleeOffset; - if(getRegMask(RegName_EDI) & icalleeMask) { - context->p_edi = (uint32 *) offset; - offset += 4; - } - if(getRegMask(RegName_ESI) & icalleeMask) { - context->p_esi = (uint32 *) offset; - offset += 4; - } - if(getRegMask(RegName_EBP) & icalleeMask) { - context->p_ebp = (uint32 *) offset; - offset += 4; - } - if(getRegMask(RegName_EBX) & icalleeMask) { - context->p_ebx = (uint32 *) offset; - } - context->esp += sizeof(POINTER_SIZE_INT);//EIP size == 4 + uint32 offset = context->esp; + context->p_eip = (POINTER_SIZE_INT *) offset; + + offset += icalleeOffset; + if(getRegMask(RegName_EDI) & icalleeMask) { + context->p_edi = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_ESI) & icalleeMask) { + context->p_esi = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_EBP) & icalleeMask) { + context->p_ebp = (POINTER_SIZE_INT *) offset; + offset += offset_step; + } + if(getRegMask(RegName_EBX) & icalleeMask) { + context->p_ebx = (POINTER_SIZE_INT *) offset; + } + context->esp += offset_step; //IP register size +#endif } -uint32 * StackInfo::getRegOffset(const JitFrameContext* context, RegName reg) const +POINTER_SIZE_INT* StackInfo::getRegOffset(const JitFrameContext* context, RegName reg) const { - assert(stackDepth >=0); - if(calleeSaveRegsMask & getRegMask(reg)) { //callee save regs + assert(stackDepth >=0); + if(calleeSaveRegsMask & getRegMask(reg)) { //callee save regs //regnames are hardcoded -> unwind() has hardcoded regs too. - //return register offset for previous stack frame. - //MUST be called before unwind() + //return register offset for previous stack frame. + //MUST be called before unwind() switch(reg) { +#ifdef _EM64T_ + case RegName_R15: + return context->p_r15; + case RegName_R14: + return context->p_r14; + case RegName_R13: + return context->p_r13; + case RegName_R12: + return context->p_r12; + case RegName_RBP: + return context->p_rbp; + case RegName_RBX: + return context->p_rbx; +#else case RegName_ESI: return context->p_esi; case RegName_EDI: @@ -214,60 +302,75 @@ uint32 * StackInfo::getRegOffset(const J return context->p_ebp; case RegName_EBX: return context->p_ebx; - default: - assert(0); - return NULL; +#endif + default: + assert(0); + return NULL; } } else { //caller save regs - assert(0); - VERIFY_OUT("Caller save register requested!"); - exit(1); - } + assert(0); + VERIFY_OUT("Caller save register requested!"); + exit(1); + } } void StackInfo::fixHandlerContext(JitFrameContext* context) { - if (itraceMethodExitString!=NULL){ - Log::cat_rt()->out()<<"__CATCH_HANDLER__:" - <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") - <<"; unwound from EIP="<<(void*)*context->p_eip - <<::std::endl; - } - context->esp -= frameSize - stackDepth; +#ifdef _EM64T_ + if (itraceMethodExitString!=NULL){ + Log::cat_rt()->out()<<"__CATCH_HANDLER__:" + <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") + <<"; unwound from EIP="<<(void*)*context->p_rip + <<::std::endl; + } + context->rsp -= frameSize - stackDepth; +#else + if (itraceMethodExitString!=NULL){ + Log::cat_rt()->out()<<"__CATCH_HANDLER__:" + <<(itraceMethodExitString!=(const char*)1?itraceMethodExitString:"") + <<"; unwound from EIP="<<(void*)*context->p_eip + <<::std::endl; + } + context->esp -= frameSize - stackDepth; +#endif } void StackInfo::registerInsts(IRManager& irm) { - if (!irm.getMethodDesc().isStatic()) { - EntryPointPseudoInst * entryPointInst = irm.getEntryPointInst(); - offsetOfThis = (uint32)entryPointInst->getOpnd(0)->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement)->getImmValue(); - } - for (CFG::NodeIterator it(irm); it!=NULL; ++it){ - if (((Node*)it)->hasKind(Node::Kind_BasicBlock)){ - BasicBlock * bb=(BasicBlock * )(Node*)it; - const Insts& insts=bb->getInsts(); - for (Inst * inst=insts.getFirst(); inst!=NULL; inst=insts.getNext(inst)){ - if(inst->getMnemonic() == Mnemonic_CALL) { - (*stackDepthInfo)[(uint32)inst->getCodeStartAddr()+inst->getCodeSize()]= - StackDepthInfo(Constraint(), - ((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg), - inst->getStackDepth(), - inst->getCodeSize()); - } - } - } - } - hashTableSize = stackDepthInfo->size(); + if (!irm.getMethodDesc().isStatic()) { +#ifdef _EM64T_ + EntryPointPseudoInst * entryPointInst = irm.getEntryPointInst(); + offsetOfThis = (uint32)entryPointInst->thisOpnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement)->getImmValue(); +#else + EntryPointPseudoInst * entryPointInst = irm.getEntryPointInst(); + offsetOfThis = (uint32)entryPointInst->getOpnd(0)->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement)->getImmValue(); +#endif + } + const Nodes& nodes = irm.getFlowGraph()->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + if (node->isBlockNode()){ + for (Inst * inst=(Inst*)node->getFirstInst(); inst!=NULL; inst=inst->getNextInst()){ + if(inst->getMnemonic() == Mnemonic_CALL) { + (*stackDepthInfo)[(POINTER_SIZE_INT)inst->getCodeStartAddr()+inst->getCodeSize()]= + StackDepthInfo(((CallInst *)inst)->getCallingConventionClient().getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(), + inst->getStackDepth(), + inst->getCodeSize()); + } + } + } + } + hashTableSize = stackDepthInfo->size(); } void StackInfo::setMethodExitString(IRManager& irm) { - ConstantAreaItem * cai=(ConstantAreaItem *)irm.getInfo("itraceMethodExitString"); - if (cai!=NULL){ - itraceMethodExitString=(const char*)cai->getAddress(); - if (itraceMethodExitString==NULL) - itraceMethodExitString=(const char*)1; - } + ConstantAreaItem * cai=(ConstantAreaItem *)irm.getInfo("itraceMethodExitString"); + if (cai!=NULL){ + itraceMethodExitString=(const char*)cai->getAddress(); + if (itraceMethodExitString==NULL) + itraceMethodExitString=(const char*)1; + } } diff --git vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.h vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.h index 36a14f0..2762717 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.h +++ vm/jitrino/src/codegenerator/ia32/Ia32StackInfo.h @@ -33,127 +33,124 @@ namespace Jitrino { namespace Ia32 { - /** - * struct StackDepthInfo performs access to information about call - * instruction. It contains caller-save and callee save registers masks - * and stack depth for this instruction - */ - - struct StackDepthInfo { - Constraint callerSaveRegs; - uint32 calleeSaveRegs; - uint32 stackDepth; - uint32 callSize; - - StackDepthInfo(uint32 sd=0) : callerSaveRegs(OpndKind_Imm), calleeSaveRegs(0), stackDepth(sd), callSize(0) {} - StackDepthInfo(Constraint r, uint32 e, uint32 sd=0, uint32 cz=0) : callerSaveRegs(r), calleeSaveRegs(e), stackDepth(sd), callSize(cz) {} - }; - - struct DepthEntry { - uint32 eip; - StackDepthInfo info; - DepthEntry * next; - - DepthEntry(uint32 ip, StackDepthInfo i, DepthEntry * n) : eip(ip), info(i), next(n) {} - }; - - /** - * map DepthMap contains StackDepthInfos indexed by EIP of corresponded call - * instruction - */ - typedef StlMap<uint32, StackDepthInfo> DepthMap; + /** + * struct StackDepthInfo performs access to information about call + * instruction. It contains callee save registers masks + * and stack depth for this instruction + */ + + struct StackDepthInfo { + uint32 calleeSaveRegs; + uint32 stackDepth; + uint32 callSize; + + StackDepthInfo(uint32 sd=0) : calleeSaveRegs(0), stackDepth(sd), callSize(0) {} + StackDepthInfo(uint32 e, uint32 sd=0, uint32 cz=0) : calleeSaveRegs(e), stackDepth(sd), callSize(cz) {} + }; + + struct DepthEntry { + POINTER_SIZE_INT eip; + StackDepthInfo info; + DepthEntry * next; + + DepthEntry(POINTER_SIZE_INT ip, StackDepthInfo i, DepthEntry * n) : eip(ip), info(i), next(n) {} + }; + + /** + * map DepthMap contains StackDepthInfos indexed by EIP of corresponded call + * instruction + */ + typedef StlMap<POINTER_SIZE_INT, StackDepthInfo> DepthMap; //======================================================================================== -// class StackInfo +// class StackInfo //======================================================================================== /** - * class StackInfo performs stack unwinding and fixing handler context. - * It can be saved and restored from memory block + * class StackInfo performs stack unwinding and fixing handler context. + * It can be saved and restored from memory block * - * This class ensures that + * This class ensures that * - * 1) All fields of a JitFrameContext object contain appropriate information + * 1) All fields of a JitFrameContext object contain appropriate information * - * 2) All useful information from StackInfo object saves and restores - * properly + * 2) All useful information from StackInfo object saves and restores + * properly * - * The principle of the filling fields of a JitFrameContext object is a - * hard-coded enumeration of registers. + * The principle of the filling fields of a JitFrameContext object is a + * hard-coded enumeration of registers. * - * The implementation of this class is located in file Ia32StackInfo.cpp + * The implementation of this class is located in file Ia32StackInfo.cpp * */ - + class StackInfo { public: - StackInfo(MemoryManager& mm) + StackInfo(MemoryManager& mm) : byteSize(0), hashTableSize(0), frameSize(0), - itraceMethodExitString(0), - eipOffset(0), - icalleeMask(0),icalleeOffset(0), - fcallee(0),foffset(0), - acallee(0),aoffset(0), - localOffset(0), - callerSaveRegsConstraint(OpndKind_Imm), - calleeSaveRegsMask(0), - stackDepth(-1), - offsetOfThis(0){ stackDepthInfo = new(mm) DepthMap(mm);} - - StackInfo() - : byteSize(0), hashTableSize(0), frameSize(0), - itraceMethodExitString(0), - eipOffset(0), - icalleeMask(0),icalleeOffset(0), - fcallee(0),foffset(0), - acallee(0),aoffset(0), - localOffset(0), - stackDepthInfo(NULL), - callerSaveRegsConstraint(OpndKind_Imm), - calleeSaveRegsMask(0), - stackDepth(-1),offsetOfThis(0) {} - - /** writes StackInfo data into memory - */ - void write(Byte* output); - - /** reads StackInfo data from MethodDesc - */ - void read(MethodDesc* pMethodDesc, uint32 eip, bool isFirst); - - /** Loads JitFrameContext with the next stack frame according to StackInfo - */ - void unwind(MethodDesc* pMethodDesc, JitFrameContext* context, bool isFirst) const; - - /** Changes ESP to point to the start of stack frame - */ - void fixHandlerContext(JitFrameContext* context); - - /** stores into StackInfo information about calls instructions such as - * eip, stack depth, caller-save and callee-save registers masks - * The algorithm takes one-pass over CFG. - */ - void registerInsts(IRManager& irm); - - /** sets method exit string which was created during itrace pass - and is alive during runtime - */ - void setMethodExitString(IRManager& irm); - - /** returns register offset for previos stack frame. - MUST be called before unwind() - */ - uint32 * getRegOffset(const JitFrameContext* context, RegName reg) const; - - /** returns stack depth - */ - uint32 getStackDepth() const { - assert(stackDepth>=0); - return stackDepth; + itraceMethodExitString(0), + eipOffset(0), + icalleeMask(0),icalleeOffset(0), + fcallee(0),foffset(0), + acallee(0),aoffset(0), + localOffset(0), + calleeSaveRegsMask(0), + stackDepth(-1), + offsetOfThis(0){ stackDepthInfo = new(mm) DepthMap(mm);} + + StackInfo() + : byteSize(0), hashTableSize(0), frameSize(0), + itraceMethodExitString(0), + eipOffset(0), + icalleeMask(0),icalleeOffset(0), + fcallee(0),foffset(0), + acallee(0),aoffset(0), + localOffset(0), + stackDepthInfo(NULL), + calleeSaveRegsMask(0), + stackDepth(-1),offsetOfThis(0) {} + + /** writes StackInfo data into memory + */ + void write(Byte* output); + + /** reads StackInfo data from MethodDesc + */ + void read(MethodDesc* pMethodDesc, POINTER_SIZE_INT eip, bool isFirst); + + /** Loads JitFrameContext with the next stack frame according to StackInfo + */ + void unwind(MethodDesc* pMethodDesc, JitFrameContext* context, bool isFirst) const; + + /** Changes ESP to point to the start of stack frame + */ + void fixHandlerContext(JitFrameContext* context); + + /** stores into StackInfo information about calls instructions such as + * eip, stack depth and callee-save registers masks + * The algorithm takes one-pass over CFG. + */ + void registerInsts(IRManager& irm); + + /** sets method exit string which was created during itrace pass + and is alive during runtime + */ + void setMethodExitString(IRManager& irm); + + /** returns register offset for previos stack frame. + MUST be called before unwind() + */ + POINTER_SIZE_INT * getRegOffset(const JitFrameContext* context, RegName reg) const; + + /** returns stack depth + */ + POINTER_SIZE_INT getStackDepth() const { + assert(stackDepth>=0); + return stackDepth; } uint32 getFrameSize() const {return frameSize;} - int getRetEIPOffset() const {return eipOffset;} + int getRetEIPOffset() const {return eipOffset;} uint32 getIntCalleeMask() const {return icalleeMask;} @@ -167,77 +164,49 @@ public: int getApplCalleeOffset() const {return aoffset;} - int getLocalOffset() const {return localOffset;} + int getLocalOffset() const {return localOffset;} uint32 getOffsetOfThis() const {return offsetOfThis;} - /** returns byte size of StackInfo data - */ - uint32 getByteSize() const; + /** returns byte size of StackInfo data + */ + POINTER_SIZE_INT getByteSize() const; - static uint32 getByteSize(MethodDesc* md); + static POINTER_SIZE_INT getByteSize(MethodDesc* md); /** read byte size from info block * */ - uint32 readByteSize(const Byte* input) const; + POINTER_SIZE_INT readByteSize(const Byte* input) const; private: - uint32 byteSize; - uint32 hashTableSize; - uint32 frameSize; - - const char * itraceMethodExitString; + POINTER_SIZE_INT byteSize; + uint32 hashTableSize; + uint32 frameSize; + + const char * itraceMethodExitString; - int eipOffset; + int eipOffset; - uint32 icalleeMask; - int icalleeOffset; + uint32 icalleeMask; + int icalleeOffset; - uint32 fcallee; - int foffset; + uint32 fcallee; + int foffset; - uint32 acallee; - int aoffset; + uint32 acallee; + int aoffset; - int localOffset; - - DepthMap * stackDepthInfo; + int localOffset; + + DepthMap * stackDepthInfo; - Constraint callerSaveRegsConstraint; - uint32 calleeSaveRegsMask; - int stackDepth; - uint32 offsetOfThis; + uint32 calleeSaveRegsMask; + int stackDepth; + uint32 offsetOfThis; - friend class StackLayouter; + friend class StackLayouter; }; -//======================================================================================== -// class StackInfoInstRegistrar -//======================================================================================== -/** - * class StackInfoInstRegistrar performs calling of StackInfo method which - * performes saving information about call instructions for stack unwinding - * - * This transformer ensures that it calls the proper method - * - * This transformer must inserted after Code Emitter, because it needs - * EIP value for instructions. - */ - -BEGIN_DECLARE_IRTRANSFORMER(StackInfoInstRegistrar, "si_insts", "StackInfo inst registrar") - IRTRANSFORMER_CONSTRUCTOR(StackInfoInstRegistrar) - void runImpl() - { - StackInfo * stackInfo = (StackInfo*)irManager.getInfo("stackInfo"); - assert(stackInfo!=NULL); - stackInfo->registerInsts(irManager); - stackInfo->setMethodExitString(irManager); - } - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - bool isIRDumpEnabled(){ return false; } -END_DECLARE_IRTRANSFORMER(StackInfoInstRegistrar) - }}//namespace #endif /* _IA32_STACK_INFO_H_ */ diff --git vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp index 6f1f93b..5b48336 100644 --- vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp +++ vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.cpp @@ -18,184 +18,379 @@ * @version $Revision: 1.10.14.1.4.4 $ */ -#include "Ia32StackLayout.h" +#include "Ia32IRManager.h" +#include "Ia32StackInfo.h" + namespace Jitrino { namespace Ia32 { -StackLayouter::StackLayouter (IRManager& irm, const char * params) - :IRTransformer(irm, params), - localBase(0), - localEnd(0), - fcalleeBase(0), - fcalleeEnd(0), - acalleeBase(0), - acalleeEnd(0), - icalleeBase(0), - icalleeEnd(0), - icallerBase(0), - icallerEnd(0), - retEIPBase(0), - retEIPEnd(0), +//======================================================================================== +// class StackLayouter +//======================================================================================== +/** + * Class StackLayouter performs forming of stack memory for a method, e.g. + * allocates memory for stack variables and input arguments, inserts + * saving/restoring callee-save registers. Also it fills StackInfo object + * for runtime access to information about stack layout + * + * This transformer ensures that + * + * 1) All input argument operands and stack memory operands have appropriate + * displacements from stack pointer + * + * 2) There are save/restore instructions for all callee-save registers + * + * 3) There are save/restore instructions for all caller-save registers for + * all calls in method + * + * 4) ESP has appropriate value throughout whole method + * + * Stack layout illustration: + * + * +-------------------------------+ inargEnd + * | | + * | | + * | | + * +-------------------------------+ inargBase, eipEnd + * | eip | + * +-------------------------------+ eipBase,icalleeEnd <--- "virtual" ESP + * | EBX | + * | EBP | + * | ESI | + * | EDI | + * +-------------------------------+ icalleeBase, fcalleeEnd + * | | + * | | + * | | + * +-------------------------------+ fcalleeBase, acalleeEnd + * | | + * | | + * | | + * +-------------------------------+ acalleeBase, localEnd + * | | + * | | + * | | + * +-------------------------------+ localBase <--- "real" ESP + * | EAX | + * | ECX | + * | EDX | + * +-------------------------------+ base of caller-save regs + * +*/ + +class StackLayouter : public SessionAction { +public: + StackLayouter (); + StackInfo * getStackInfo() { return stackInfo; } + void runImpl(); + + uint32 getNeedInfo()const{ return 0; } + uint32 getSideEffects()const{ return 0; } + +protected: + void checkUnassignedOpnds(); + + /** Computes all offsets for stack areas and stack operands, + inserts pushs for callee-save registers + */ + void createProlog(); + + /** Restores stack pointer if needed, + inserts pops for callee-save registers + */ + void createEpilog(); + + int getLocalBase(){ return localBase; } + int getLocalEnd(){ return localEnd; } + int getApplCalleeBase(){ return acalleeBase; } + int getApplCalleeEnd(){ return acalleeEnd; } + int getFloatCalleeBase(){ return fcalleeBase; } + int getFloatCalleeEnd(){ return fcalleeEnd; } + int getIntCalleeBase(){ return icalleeBase; } + int getIntCalleeEnd(){ return icalleeEnd; } + int getRetEIPBase(){ return retEIPBase; } + int getRetEIPEnd(){ return retEIPEnd; } + int getInArgBase(){ return inargBase; } + int getInArgEnd(){ return inargEnd; } + uint32 getFrameSize(){ return frameSize; } + uint32 getOutArgSize(){ return outArgSize; } + + int localBase; + int localEnd; + int fcalleeBase; + int fcalleeEnd; + int acalleeBase; + int acalleeEnd; + int icalleeBase; + int icalleeEnd; + + int retEIPBase; + int retEIPEnd; + int inargBase; + int inargEnd; + uint32 frameSize; + uint32 outArgSize; +#ifdef _EM64T_ + bool stackCorrection; +#endif + StackInfo * stackInfo; + + MemoryManager memoryManager; + +}; + +static ActionFactory<StackLayouter> _stack("stack"); + + +StackLayouter::StackLayouter () + :localBase(0), + localEnd(0), + fcalleeBase(0), + fcalleeEnd(0), + acalleeBase(0), + acalleeEnd(0), + icalleeBase(0), + icalleeEnd(0), + retEIPBase(0), + retEIPEnd(0), inargBase(0), - inargEnd(0), - frameSize(0), - outArgSize(0), - stackInfo(new(irm.getMemoryManager()) StackInfo(irm.getMemoryManager())), - memoryManager(0x100, "StackLayouter") + inargEnd(0), + frameSize(0), + outArgSize(0), +#ifdef _EM64T_ + stackCorrection(0), +#endif + memoryManager(0x100, "StackLayouter") { - irm.setInfo("stackInfo", stackInfo); }; void StackLayouter::runImpl() { - IRManager & irm=getIRManager(); - irm.calculateOpndStatistics(); + IRManager & irm=getIRManager(); + + stackInfo = new(irm.getMemoryManager()) StackInfo(irm.getMemoryManager()); + irm.setInfo("stackInfo", stackInfo); + + irm.calculateOpndStatistics(); #ifdef _DEBUG - checkUnassignedOpnds(); + checkUnassignedOpnds(); #endif - irm.calculateTotalRegUsage(OpndKind_GPReg); - createProlog(); - createEpilog(); - irm.calculateStackDepth(); - irm.layoutAliasOpnds(); - - //fill StackInfo object - stackInfo->frameSize = getFrameSize(); - - stackInfo->icalleeMask = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg) & irm.getTotalRegUsage(OpndKind_GPReg); - stackInfo->icalleeOffset = getIntCalleeBase(); - stackInfo->fcallee = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_FPReg); - stackInfo->foffset = getFloatCalleeBase(); - stackInfo->acallee = 0; //VSH: TODO - get rid off appl regs irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_ApplicationReg); - stackInfo->aoffset = getApplCalleeBase(); - stackInfo->localOffset = getLocalBase(); - stackInfo->eipOffset = getRetEIPBase(); + irm.calculateTotalRegUsage(OpndKind_GPReg); + createProlog(); + createEpilog(); + irm.calculateStackDepth(); + irm.layoutAliasOpnds(); + + //fill StackInfo object + stackInfo->frameSize = getFrameSize(); + + stackInfo->icalleeMask = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask() & irm.getTotalRegUsage(OpndKind_GPReg); + stackInfo->icalleeOffset = getIntCalleeBase(); + stackInfo->fcallee = irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_FPReg).getMask(); + stackInfo->foffset = getFloatCalleeBase(); + stackInfo->acallee = 0; //VSH: TODO - get rid off appl regs irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_ApplicationReg); + stackInfo->aoffset = getApplCalleeBase(); + stackInfo->localOffset = getLocalBase(); + stackInfo->eipOffset = getRetEIPBase(); } void StackLayouter::checkUnassignedOpnds() { - for (uint32 i=0, n=irManager.getOpndCount(); i<n; i++) - assert(irManager.getOpnd(i)->hasAssignedPhysicalLocation()); + for (uint32 i=0, n=irManager->getOpndCount(); i<n; i++) { +#ifdef _DEBUG + Opnd * opnd = irManager->getOpnd(i); + assert(!opnd->getRefCount() || opnd->hasAssignedPhysicalLocation()); +#endif + } } void StackLayouter::createProlog() { - IRManager & irm=getIRManager(); - - for (uint32 i = 0; i<irm.getOpndCount(); i++)//create or reset displacements for stack memory operands - { - if(irm.getOpnd(i)->getMemOpndKind() == MemOpndKind_StackAutoLayout) { - Opnd * dispOpnd=irm.getOpnd(i)->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - if (dispOpnd==NULL){ - dispOpnd=irm.newImmOpnd(irm.getTypeManager().getInt32Type(), 0); - irm.getOpnd(i)->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, dispOpnd); - } - dispOpnd->assignImmValue(0); - } - }//end for - - int offset = 0; - - //return EIP area - retEIPBase = offset; - offset += 4; - - retEIPEnd = inargBase = offset; - - BasicBlock * bb = irm.getPrologNode(); - - uint32 slotSize=4; - - EntryPointPseudoInst * entryPointInst = irManager.getEntryPointInst(); - assert(entryPointInst->getBasicBlock()==irManager.getPrologNode()); - if (entryPointInst) {//process entry-point instruction - const StlVector<CallingConventionClient::StackOpndInfo>& stackOpndInfos = - ((const EntryPointPseudoInst*)entryPointInst)->getCallingConventionClient().getStackOpndInfos(Inst::OpndRole_Def); - - for (uint32 i=0, n=stackOpndInfos.size(); i<n; i++) {//assign displacements for input operands - Opnd * opnd=entryPointInst->getOpnd(stackOpndInfos[i].opndIndex); - Opnd * disp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - disp->assignImmValue(offset+stackOpndInfos[i].offset); - } - } + IRManager & irm=getIRManager(); + for (uint32 i = 0; i<irm.getOpndCount(); i++)//create or reset displacements for stack memory operands + { + Opnd * opnd = irm.getOpnd(i); + if(opnd->getRefCount() && opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { + Opnd * dispOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + if (dispOpnd==NULL){ + dispOpnd=irm.newImmOpnd(irm.getTypeManager().getInt32Type(), 0); + opnd->setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, dispOpnd); + } + dispOpnd->assignImmValue(0); + } + }//end for - inargEnd = offset; + int offset = 0; - icalleeEnd = offset = 0; + //return EIP area + retEIPBase = offset; + offset += sizeof(POINTER_SIZE_INT); - uint32 calleeSavedRegs=irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg); + retEIPEnd = inargBase = offset; - uint32 usageRegMask = irManager.getTotalRegUsage(OpndKind_GPReg); + uint32 slotSize=sizeof(POINTER_SIZE_INT); - Inst * lastPush = NULL; + EntryPointPseudoInst * entryPointInst = irManager->getEntryPointInst(); + assert(entryPointInst->getNode()==irManager->getFlowGraph()->getEntryNode()); + if (entryPointInst) {//process entry-point instruction + const StlVector<CallingConventionClient::StackOpndInfo>& stackOpndInfos = + ((const EntryPointPseudoInst*)entryPointInst)->getCallingConventionClient().getStackOpndInfos(Inst::OpndRole_Def); - for (uint32 reg = RegName_EDI; reg>=RegName_EAX; reg--) {//push callee-save registers onto stack - uint32 mask = getRegMask((RegName)reg); - if((mask & calleeSavedRegs) && (usageRegMask & mask)) { - Inst * inst = irm.newInst(Mnemonic_PUSH, irm.getRegOpnd((RegName)reg)); - if (!lastPush) - lastPush = inst; - bb->appendInsts(inst, entryPointInst); - offset -= 4; - } - } + for (uint32 i=0, n=stackOpndInfos.size(); i<n; i++) {//assign displacements for input operands - icalleeBase = fcalleeEnd = fcalleeBase = acalleeEnd = acalleeBase = localEnd = offset; - - IRManager::AliasRelation * relations = new(irm.getMemoryManager()) IRManager::AliasRelation[irm.getOpndCount()]; - irm.getAliasRelations(relations);// retrieve relations no earlier than all memory locations are assigned - - for (uint32 i = 0; i<irm.getOpndCount(); i++)//assign displacements for local variable operands - { - Opnd * opnd = irm.getOpnd(i); - if (opnd->getRefCount() == 0) - continue; - if(opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { - Opnd * dispOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); - if (dispOpnd->getImmValue()==0) { - if (relations[opnd->getId()].outerOpnd == NULL) { - uint32 cb=getByteSize(opnd->getSize()); - cb=(cb+slotSize-1)&~(slotSize-1); - offset -= cb; - dispOpnd->assignImmValue(offset); - } - } - } - } + uint64 argOffset = +#ifdef _EM64T_ + !entryPointInst->getCallingConventionClient().getCallingConvention()->pushLastToFirst() ? + ((n-1)*slotSize-stackOpndInfos[i].offset): +#endif + stackOpndInfos[i].offset; + + Opnd * opnd=entryPointInst->getOpnd(stackOpndInfos[i].opndIndex); + Opnd * disp = opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + disp->assignImmValue(offset+argOffset); + } + } + + + inargEnd = offset; + + icalleeEnd = offset = 0; + + uint32 calleeSavedRegs=irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(); + + uint32 usageRegMask = irManager->getTotalRegUsage(OpndKind_GPReg); + + Inst * lastPush = NULL; + +#ifdef _EM64T_ + //-------------------------------- + unsigned counter = 0; + for (uint32 reg = RegName_R15; reg >= RegName_RAX ; reg--) { + uint32 mask = getRegMask((RegName)reg); + if((mask & calleeSavedRegs) && (usageRegMask & mask)) counter++; + } + //-------------------------------- + for (uint32 reg = RegName_R15; reg >= RegName_RAX ; reg--) { +#else + for (uint32 reg = RegName_EDI; reg>=RegName_EAX; reg--) {//push callee-save registers onto stack +#endif + uint32 mask = getRegMask((RegName)reg); + if((mask & calleeSavedRegs) && (usageRegMask & mask)) { + Inst * inst = irm.newInst(Mnemonic_PUSH, irm.getRegOpnd((RegName)reg)); + if (!lastPush) + lastPush = inst; + inst->insertAfter(entryPointInst); + offset -= slotSize; + } + } +#ifdef _EM64T_ + if(!(counter & 1)) { + Opnd * rsp = irManager->getRegOpnd(STACK_REG); + Type* uint64_type = irManager->getTypeFromTag(Type::UInt64); + Inst* newIns = irManager->newInst(Mnemonic_SUB,rsp,irManager->newImmOpnd(uint64_type, slotSize)); + newIns->insertAfter(entryPointInst); + offset -= slotSize; + stackCorrection = 1; + } +#endif - localBase = icallerEnd = offset; + icalleeBase = fcalleeEnd = fcalleeBase = acalleeEnd = acalleeBase = localEnd = offset; - icallerBase = offset; - if (localEnd>localBase) - bb->appendInsts(irm.newInst(Mnemonic_SUB, irm.getRegOpnd(RegName_ESP), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd-localBase)),lastPush ? lastPush : entryPointInst); //set "real" ESP - frameSize = icalleeEnd -localBase; + IRManager::AliasRelation * relations = new(irm.getMemoryManager()) IRManager::AliasRelation[irm.getOpndCount()]; + irm.getAliasRelations(relations);// retrieve relations no earlier than all memory locations are assigned -} +#ifdef _EM64T_ + //-------------------------------- + counter = 0; + for (uint32 i = 0; i<irm.getOpndCount(); i++)//assign displacements for local variable operands + { + Opnd * opnd = irm.getOpnd(i); + if (opnd->getRefCount() == 0) + continue; + if(opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { + Opnd * dispOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + if (dispOpnd->getImmValue()==0) { + uint32 cb=getByteSize(opnd->getSize()); + cb=(cb+slotSize-1)&~(slotSize-1); + counter+=cb; + } + } + } + if (counter & 15) { + offset -= 16-(counter&15); + } + //-------------------------------- +#endif + + for (uint32 i = 0; i<irm.getOpndCount(); i++)//assign displacements for local variable operands + { + Opnd * opnd = irm.getOpnd(i); + if (opnd->getRefCount() == 0) + continue; + if(opnd->getMemOpndKind() == MemOpndKind_StackAutoLayout) { + Opnd * dispOpnd=opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); + if (dispOpnd->getImmValue()==0) { + if (relations[opnd->getId()].outerOpnd == NULL) { + uint32 cb=getByteSize(opnd->getSize()); + cb=(cb+slotSize-1)&~(slotSize-1); + offset -= cb; + dispOpnd->assignImmValue(offset); + } + } + } + } + + localBase = offset; + + if (localEnd>localBase) { + Inst* newIns = irm.newInst(Mnemonic_SUB, irm.getRegOpnd(STACK_REG), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd-localBase)); + newIns->insertAfter(lastPush ? lastPush : entryPointInst); + } + + frameSize = icalleeEnd -localBase; + +} void StackLayouter::createEpilog() { // Predeccessors of en and irm.isEpilog(en->pred) IRManager & irm=getIRManager(); - uint32 calleeSavedRegs=irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg); - const Edges& inEdges = irm.getExitNode()->getEdges(Direction_In); - uint32 usageRegMask = irManager.getTotalRegUsage(OpndKind_GPReg); - for (Edge * edge = inEdges.getFirst(); edge != NULL; edge = inEdges.getNext(edge)) {//check predecessors for epilog(s) - if (irm.isEpilog(edge->getNode(Direction_Tail))) { - BasicBlock * epilog = (BasicBlock*)edge->getNode(Direction_Tail); - Inst * retInst=epilog->getInsts().getLast(); - assert(retInst->hasKind(Inst::Kind_RetInst)); - if (localEnd>localBase) - epilog->prependInsts(irm.newInst(Mnemonic_ADD, irm.getRegOpnd(RegName_ESP), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd-localBase)), retInst);//restore stack pointer - for (uint32 reg = RegName_EDI; reg >= RegName_EAX ; reg--) {//pop callee-save registers - uint32 mask = getRegMask((RegName)reg); - if ((mask & calleeSavedRegs) && (usageRegMask & mask)) { - epilog->prependInsts(irm.newInst(Mnemonic_POP, irm.getRegOpnd((RegName)reg)), retInst); - } - } + uint32 calleeSavedRegs=irm.getCallingConvention()->getCalleeSavedRegs(OpndKind_GPReg).getMask(); + const Edges& inEdges = irm.getFlowGraph()->getExitNode()->getInEdges(); + uint32 usageRegMask = irManager->getTotalRegUsage(OpndKind_GPReg); + for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (irm.isEpilog(edge->getSourceNode())) { + Node * epilog = edge->getSourceNode(); + Inst * retInst=(Inst*)epilog->getLastInst(); + assert(retInst->hasKind(Inst::Kind_RetInst)); + if (localEnd>localBase) { + //restore stack pointer + Inst* newIns = irm.newInst(Mnemonic_ADD, irm.getRegOpnd(STACK_REG), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), localEnd-localBase)); + newIns->insertBefore(retInst); + } +#ifdef _EM64T_ + for (uint32 reg = RegName_R15; reg >= RegName_RAX ; reg--) {//pop callee-save registers +#else + for (uint32 reg = RegName_EDI; reg >= RegName_EAX ; reg--) {//pop callee-save registers +#endif + uint32 mask = getRegMask((RegName)reg); + if ((mask & calleeSavedRegs) && (usageRegMask & mask)) { + Inst* newIns = irm.newInst(Mnemonic_POP, irm.getRegOpnd((RegName)reg)); + newIns->insertBefore(retInst); + } + } +#ifdef _EM64T_ + if (stackCorrection) {//restore stack pointer + Inst* newIns = irm.newInst(Mnemonic_ADD, irm.getRegOpnd(STACK_REG), irm.newImmOpnd(irm.getTypeManager().getInt32Type(), sizeof(POINTER_SIZE_INT))); + newIns->insertBefore(retInst); + } +#endif } } } }} //namespace Ia32 + diff --git vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.h vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.h deleted file mode 100644 index d36d55e..0000000 --- vm/jitrino/src/codegenerator/ia32/Ia32StackLayout.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Nikolay A. Sidelnikov - * @version $Revision: 1.8.22.4 $ - */ - -#ifndef _IA32_STACK_LAYOUT_H_ -#define _IA32_STACK_LAYOUT_H_ - -#include "Ia32IRManager.h" -#include "Ia32StackInfo.h" -namespace Jitrino -{ -namespace Ia32{ - -//======================================================================================== -// class StackLayouter -//======================================================================================== -/** - * Class StackLayouter performs forming of stack memory for a method, e.g. - * allocates memory for stack variables and input arguments, inserts - * saving/restoring callee-save registers. Also it fills StackInfo object - * for runtime access to information about stack layout - * - * This transformer ensures that - * - * 1) All input argument operands and stack memory operands have appropriate - * displacements from stack pointer - * - * 2) There are save/restore instructions for all callee-save registers - * - * 3) There are save/restore instructions for all caller-save registers for - * all calls in method - * - * 4) ESP has appropriate value throughout whole method - * - * Stack layout illustration: - * - * +-------------------------------+ inargEnd - * | | - * | | - * | | - * +-------------------------------+ inargBase, eipEnd - * | eip | - * +-------------------------------+ eipBase,icalleeEnd <--- "virtual" ESP - * | EBX | - * | EBP | - * | ESI | - * | EDI | - * +-------------------------------+ icalleeBase, fcalleeEnd - * | | - * | | - * | | - * +-------------------------------+ fcalleeBase, acalleeEnd - * | | - * | | - * | | - * +-------------------------------+ acalleeBase, localEnd - * | | - * | | - * | | - * +-------------------------------+ localBase <--- "real" ESP - * | EAX | - * | ECX | - * | EDX | - * +-------------------------------+ base of caller-save regs - * -*/ - -BEGIN_DECLARE_IRTRANSFORMER(StackLayouter, "stack", "Stack Layout") - StackLayouter (IRManager& irm, const char * params); - StackInfo * getStackInfo() { return stackInfo; } - void runImpl(); - - uint32 getNeedInfo()const{ return 0; } - uint32 getSideEffects()const{ return 0; } - -protected: - void checkUnassignedOpnds(); - - /** Computes all offsets for stack areas and stack operands, - inserts pushs for callee-save registers - */ - void createProlog(); - - /** Restores stack pointer if needed, - inserts pops for callee-save registers - */ - void createEpilog(); - - int getLocalBase(){ return localBase; } - int getLocalEnd(){ return localEnd; } - int getApplCalleeBase(){ return acalleeBase; } - int getApplCalleeEnd(){ return acalleeEnd; } - int getFloatCalleeBase(){ return fcalleeBase; } - int getFloatCalleeEnd(){ return fcalleeEnd; } - int getIntCalleeBase(){ return icalleeBase; } - int getIntCalleeEnd(){ return icalleeEnd; } - int getRetEIPBase(){ return retEIPBase; } - int getRetEIPEnd(){ return retEIPEnd; } - int getInArgBase(){ return inargBase; } - int getInArgEnd(){ return inargEnd; } - uint32 getFrameSize(){ return frameSize; } - uint32 getOutArgSize(){ return outArgSize; } - - int localBase; - int localEnd; - int fcalleeBase; - int fcalleeEnd; - int acalleeBase; - int acalleeEnd; - int icalleeBase; - int icalleeEnd; - int icallerBase; - int icallerEnd; - - int retEIPBase; - int retEIPEnd; - int inargBase; - int inargEnd; - uint32 frameSize; - uint32 outArgSize; - - StackInfo * stackInfo; - - MemoryManager memoryManager; - -END_DECLARE_IRTRANSFORMER(StackLayouter) - -}}; //namespace Ia32 -#endif //_IA32_STACK_LAYOUT_H_ diff --git vm/jitrino/src/codegenerator/ia32/Ia32WebMaker.cpp vm/jitrino/src/codegenerator/ia32/Ia32WebMaker.cpp new file mode 100644 index 0000000..dc93029 --- /dev/null +++ vm/jitrino/src/codegenerator/ia32/Ia32WebMaker.cpp @@ -0,0 +1,691 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + +#include "Ia32IRManager.h" +#include "XTimer.h" +#include "Counter.h" +#include "Stl.h" + +#ifdef _DEBUG__WEBMAKER +#include <iostream> +#include <iomanip> +#include "Ia32IRXMLDump.h" +#ifdef _MSC_VER +#pragma warning(disable : 4505) //unreferenced local function has been removed +#endif //#ifdef _MSC_VER +#endif //#ifdef _DEBUG__WEBMAKER + + +using namespace std; + +namespace Jitrino +{ + +namespace Ia32 +{ + + +struct WebMaker : public SessionAction +{ + MemoryManager mm; // this is private MemoryManager, not irm.getMemoryManager() + + struct OpDef + { + int globid; // -1 for local definition or uniquue id (starting from 0) + Inst* defp; // defining instruction + size_t linkx; + bool visited; + + typedef StlVector<Inst*> Instps; + Instps* useps; // for local operands always 0 + }; + + struct Opndx + { + Opndx (MemoryManager& mm) :opdefs(mm), globdefsp(0), cbbp(0), webscount(0) {} + + typedef StlVector<OpDef> OpDefs; + OpDefs opdefs; // array of all definitions + + BitSet* globdefsp; // bitmask of all global definitions or 0 + + const Node* cbbp; + OpDef* copdefp; + int webscount; + Opnd* newopndp; + }; + + typedef StlVector <Opndx*> Opndxs; + Opndxs opndxs; + + + struct Nodex + { + Nodex (MemoryManager& mm, size_t s) :globentrys(mm,s), + globdefsp (0), + globkillsp(0), + globexitsp(0) {} + + BitSet globentrys; // all global definitions available at the block entry + BitSet* globdefsp, // can be 0 + * globkillsp, // can be 0 + * globexitsp; // 0 if globdefsp = globkillsp = 0 (globentrys must be used instead) + }; + + typedef StlVector <Nodex*> Nodexs; + Nodexs nodexs; + + /*const*/ size_t opandcount; + /*const*/ size_t nodecount; + size_t splitcount; + size_t globcount; + + + WebMaker () :mm(1000, "WebMaker"), opndxs(mm), nodexs(mm) {} + + uint32 getNeedInfo () const {return NeedInfo_LivenessInfo;} + uint32 getSideEffects () const {return splitcount == 0 ? 0 : SideEffect_InvalidatesLivenessInfo;} + + void runImpl(); + + void phase1(); + void phase2(); + void phase3(); + void phase4(); + void linkDef(Opndx::OpDefs&, OpDef*, OpDef*); + BitSet* bitsetp (BitSet*&); + Opnd* splitOpnd (const Opnd*); +}; + + +static ActionFactory<WebMaker> _webmaker("webmaker"); + +static Counter<size_t> count_splitted("ia32:webmaker:splitted", 0); + + +//======================================================================================== +// Internal debug helpers +//======================================================================================== + + +#ifdef _DEBUG__WEBMAKER + +using std::endl; +using std::ostream; + +static void onConstruct (const IRManager&); +static void onDestruct (); + +struct Sep +{ + Sep () :first(true) {} + + bool first; +}; + +static ostream& operator << (ostream&, Sep&); + +static ostream& operator << (ostream&, const Inst&); + +static ostream& operator << (ostream&, const Opnd&); + +static ostream& operator << (ostream&, /*const*/ BitSet*); + +struct Dbgout : public ::std::ofstream +{ + Dbgout (const char* s) {open(s);} + ~Dbgout () {close();} +}; + +static Dbgout dbgout("WebMaker.txt"); + +#define DBGOUT(s) dbgout << s +//#define DBGOUT(s) std::cerr << s + +#else + +#define DBGOUT(s) + +#endif + + +//======================================================================================== +// WebMaker implementation +//======================================================================================== + + +void WebMaker::runImpl() +{ +#ifdef _DEBUG__WEBMAKER + onConstruct(irm); +#endif + + opandcount = irManager->getOpndCount(); + nodecount = irManager->getFlowGraph()->getMaxNodeId(); + + splitcount = 0; + + phase1(); + +//TBD Local definitions also can be splitted! + + if (globcount != 0) + { + phase2(); + phase3(); + phase4(); + } + + count_splitted += splitcount; + DBGOUT("***splitcount=" << splitcount << "/" << count_splitted << endl;) + +#ifdef _DEBUG__WEBMAKER + onDestruct(); +#endif +} + + +void WebMaker::phase1() +{ + static CountTime phase1Timer("timer:ia32::webmaker:phase1"); + AutoTimer tm(phase1Timer); + + opndxs.resize(opandcount); + for (size_t i = 0; i != opandcount; ++i) + { + Opndx* opndxp = 0; + if (!irManager->getOpnd(i)->hasAssignedPhysicalLocation()) + opndxp = new Opndx(mm); + opndxs[i] = opndxp; + } + + BitSet lives(mm, opandcount); + globcount = 0; + + const Nodes& postOrder = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = postOrder.begin(), end = postOrder.end(); it!=end; ++it) { + Node* nodep = *it; + + if (nodep->isBlockNode()) + { + for (Inst* instp = (Inst*)nodep->getFirstInst(); instp!=NULL; instp = instp->getNextInst()) { + const uint32 iprops = instp->getProperties(); + Inst::Opnds defs(instp, Inst::OpndRole_AllDefs); + size_t itx = 0; + for (Inst::Opnds::iterator it = defs.begin(); it != defs.end(); it = defs.next(it), ++itx) + { + Opnd* opndp = instp->getOpnd(it); + Opndx* opndxp = opndxs.at(opndp->getId()); + if (opndxp != 0) + { + const uint32 oprole = const_cast<const Inst*>(instp)->getOpndRoles(itx); + const bool isdef = ((oprole & Inst::OpndRole_UseDef) == Inst::OpndRole_Def) + && ((iprops & Inst::Properties_Conditional) == 0 ); + if (isdef) + {// register the new definition + opndxp->opdefs.push_back(OpDef()); + OpDef& opdef = opndxp->opdefs.back(); + opdef.visited = false; + opdef.linkx = &opdef - &opndxp->opdefs.front(); + opdef.globid = -1; + opdef.defp = instp; + opdef.useps = 0; + } + } + } + } + + irManager->getLiveAtExit(nodep, lives); + BitSet::IterB bsk(lives); + for (int i = bsk.getNext(); i != -1; i = bsk.getNext()) + { + Opnd* opndp = irManager->getOpnd(i); + Opndx*& opndxp = opndxs.at(opndp->getId()); + if (opndxp != 0 && !opndxp->opdefs.empty()) + { + OpDef& opdef = opndxp->opdefs.back(); + if (opdef.defp->getNode() == nodep) + { + opdef.globid = globcount++; + bitsetp(opndxp->globdefsp)->setBit(opdef.globid, true); + } + } + } + } + } + +#ifdef _DEBUG__WEBMAKER +/* + dbgout << "--- phase1 ---" << endl; + for (size_t i = 0; i != opandcount; ++i) + if (opndxs[i] != 0) + { + dbgout << " O#" << irManager->getOpnd(i)->getFirstId() << " (#" << i << ")" << endl; + Opndx::OpDefs opdefs = opndxs[i]->opdefs; + for (Opndx::OpDefs::iterator it = opdefs.begin(); it != opdefs.end(); ++it) + { + OpDef& opdef = *it; + dbgout << " linkx#" << opdef.linkx << " globid#" << opdef.globid + << " opdef B#" << opdef.defp->getBasicBlock()->getId() << " " << *opdef.defp << endl; + } + } + dbgout << "--- opandcount:" << opandcount << " globcount:" << globcount << endl; +*/ +#endif +} + + +void WebMaker::phase2() +{ + static CountTime phase2Timer("timer:ia32::webmaker:phase2"); + AutoTimer tm(phase2Timer); + + nodexs.resize(nodecount); + for (size_t n = 0; n != nodecount; ++n) + nodexs[n] = new Nodex(mm, globcount); + + Opndx* opndxp; + for (size_t i = 0; i != opandcount; ++i) + if ((opndxp = opndxs[i]) != 0 && !opndxp->opdefs.empty()) + { + Opndx::OpDefs::iterator it = opndxp->opdefs.begin(), + end = opndxp->opdefs.end(); + for (; it != end; ++it) + { + OpDef& opdef = *it; + Nodex* nodexp = nodexs.at(opdef.defp->getNode()->getId()); + + if (opdef.globid != -1) + bitsetp(nodexp->globdefsp)->setBit(opdef.globid, true); + + if (opndxp->globdefsp != 0) + bitsetp(nodexp->globkillsp)->unionWith(*bitsetp(opndxp->globdefsp)); + } + + // prepare for pass3 + opndxp->cbbp = 0; + opndxp->copdefp = 0; + } + + + + BitSet wrkbs(mm, globcount); + bool wrkbsvalid; + size_t passnb = 0; + const Nodes& postOrder = irManager->getFlowGraph()->getNodesPostOrder(); + for (bool changes = true; changes; ++passnb) + { + changes = false; + + for (Nodes::const_reverse_iterator it = postOrder.rbegin(),end = postOrder.rend(); it!=end; ++it) + { + Node* nodep = *it; + Nodex* nodexp = nodexs[nodep->getId()]; + + wrkbsvalid = false; + + const Edges& edges = nodep->getInEdges(); + size_t edgecount = 0; + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite, ++edgecount) { + Edge* edgep = *ite; + Node* predp = edgep->getSourceNode(); + Nodex* predxp = nodexs[predp->getId()]; + + BitSet* predbsp = predxp->globexitsp; + if (predbsp == 0) + predbsp = &predxp->globentrys; + + if (edgecount == 0) + { + wrkbs.copyFrom(*predbsp); + wrkbsvalid = true; + } + else + wrkbs.unionWith(*predbsp); + } + + if (passnb > 0 && (!wrkbsvalid || nodexp->globentrys.isEqual(wrkbs))) + continue; + + if (!wrkbsvalid) + wrkbs.clear(); + + if (!nodexp->globentrys.isEqual(wrkbs)) + { + nodexp->globentrys.copyFrom(wrkbs); + changes = true; + } + + if (nodexp->globkillsp != 0 && nodexp->globdefsp != 0) + { + if (nodexp->globkillsp != 0) + wrkbs.subtract(*nodexp->globkillsp); + + if (nodexp->globdefsp != 0) + wrkbs.unionWith(*nodexp->globdefsp); + + if (!bitsetp(nodexp->globexitsp)->isEqual(wrkbs)) + { + nodexp->globexitsp->copyFrom(wrkbs); + changes = true; + } + } + } + } + +#ifdef _DEBUG__WEBMAKER +/* + dbgout << "--- total passes:" << passnb << endl; + for (size_t n = 0; n != nodecount; ++n) + { + Nodex* nodexp = nodexs[n]; + dbgout <<" node#" << n << endl; + dbgout <<" entry " << &nodexp->globentrys << endl; + if (nodexp->globexitsp != 0) + dbgout <<" exit " << nodexp->globexitsp << endl; + } +*/ +#endif +} + + +void WebMaker::phase3() +{ + static CountTime phase3Timer("timer:ia32::webmaker:phase3"); + AutoTimer tm(phase3Timer); + + DBGOUT("--- phase3 ---" << endl;) + + const Nodes& postOrder = irManager->getFlowGraph()->getNodesPostOrder(); + for (Nodes::const_iterator it = postOrder.begin(), end = postOrder.end(); it!=end; ++it) { + Node* nodep = *it; + if (nodep->isBlockNode()) + { + const BitSet* globentryp = &nodexs.at(nodep->getId())->globentrys; + + for (Inst* instp = (Inst*)nodep->getFirstInst(); instp!=NULL; instp = instp->getNextInst()) { + { + const uint32 iprops = instp->getProperties(); + Inst::Opnds all(instp, Inst::OpndRole_All); + size_t itx = 0; + for (Inst::Opnds::iterator it = all.begin(); it != all.end(); it = all.next(it), ++itx) + { + Opnd* opndp = instp->getOpnd(it); + Opndx* opndxp = opndxs.at(opndp->getId()); + if (opndxp != 0) + { + OpDef* opdefp = 0; + const uint32 oprole = const_cast<const Inst*>(instp)->getOpndRoles(itx); + const bool isdef = ((oprole & Inst::OpndRole_UseDef) == Inst::OpndRole_Def) + && ((iprops & Inst::Properties_Conditional) == 0 ); + DBGOUT(" O#" << opndp->getFirstId() << "(#" << opndp->getId() << ") def:" << isdef;) + DBGOUT(" B#" << instp->getBasicBlock()->getId() << " " << *instp;) + + if (isdef) + {// opand definition here + Opndx::OpDefs::iterator it = opndxp->opdefs.begin(), + end = opndxp->opdefs.end(); + //if (opndxp->copdefp != 0) + // it = opndxp->copdefp; + for (; it != end && it->defp != instp; ++it) + ; + + assert(it != end); + opdefp = &*it; + opndxp->copdefp = opdefp; + opndxp->cbbp = nodep; + DBGOUT(" found1 globid#" << opdefp->globid << " def B#" << opdefp->defp->getBasicBlock()->getId() << " " << *opdefp->defp << endl;) + } + else + {// opand usage here + if (opndxp->cbbp != nodep) + {// it must be usage of global definition + OpDef* lastdefp = 0; + Opndx::OpDefs::iterator it = opndxp->opdefs.begin(), + end = opndxp->opdefs.end(); + for (; it != end; ++it) + if (it->globid != -1 && globentryp->getBit(it->globid)) + { + opdefp = &*it; + opndxp->copdefp = opdefp; + opndxp->cbbp = nodep; + + if (lastdefp != 0) + linkDef(opndxp->opdefs, lastdefp, opdefp); + lastdefp = opdefp; + } + assert(lastdefp != 0); + DBGOUT(" found2 globid#" << opdefp->globid << " def B#" << opdefp->defp->getBasicBlock()->getId() << " " << *opdefp->defp << endl;) + } + else + {// it can be usage of global or local definition + opdefp = opndxp->copdefp; + DBGOUT(" found3 globid#" << opdefp->globid << " def B#" << opdefp->defp->getBasicBlock()->getId() << " " << *opdefp->defp << endl;) + } + } + assert(opdefp != 0); + + if (opdefp->globid == -1) + { + if (isdef) + { + ++opndxp->webscount; + if (opndxp->webscount > 1) + { + opndxp->newopndp = splitOpnd(opndp); + DBGOUT("**new local web found O#" << opndxp->newopndp->getFirstId() << "(#" << opndxp->newopndp->getId() << ")" << endl;) + } + } + + if (opndxp->webscount > 1 && opdefp->defp->getNode() == nodep) + { + instp->replaceOpnd(opndp, opndxp->newopndp); + DBGOUT(" opand replaced by O#" << opndxp->newopndp->getFirstId() << "(#" << opndxp->newopndp->getId() << ")" << endl;) + } + } + else + { + if (opdefp->useps == 0) + opdefp->useps = new OpDef::Instps(mm); + opdefp->useps->push_back(instp); + } + } + } + } + } + } + } +} + + +void WebMaker::phase4() +{ + static CountTime phase4Timer("timer:ia32::webmaker:phase4"); + AutoTimer tm(phase4Timer); + + DBGOUT("--- phase4 ---" << endl;) + + Opndx* opndxp; + for (size_t i = 0; i != opandcount; ++i) + if ((opndxp = opndxs[i]) != 0 && !opndxp->opdefs.empty()) + { + Opnd* opndp = irManager->getOpnd(i); + Opndx::OpDefs& opdefs = opndxp->opdefs; + DBGOUT(" O#" << opndp->getFirstId() << "(#" << i << ")" << endl;) + + for (size_t itx = 0; itx != opdefs.size(); ++itx) + { + OpDef* opdefp = &opdefs[itx]; + DBGOUT(" " << itx << "->" << opdefp->linkx << " globid#" << opdefp->globid << endl;) + if (opdefp->globid != -1 && !opdefp->visited) + { + Opnd* newopndp = 0; + ++opndxp->webscount; + if (opndxp->webscount > 1) + { + newopndp = splitOpnd(opndp); + DBGOUT("**new global web found O#" << newopndp->getFirstId() << "(#" << newopndp->getId() << ")" << endl;) + } + + while (!opdefp->visited) + { + DBGOUT(" -visited globid#" << opdefp->globid << endl;) + + if (newopndp != 0 && opdefp->useps != 0) + { + OpDef::Instps::iterator it = opdefp->useps->begin(), + end = opdefp->useps->end(); + for (; it != end; ++it) + { + (*it)->replaceOpnd(opndp, newopndp); + DBGOUT(" replace B#" << (*it)->getBasicBlock()->getId() << " " << *(*it);) + DBGOUT(" O#" << opndp->getFirstId() << "(#" << opndp->getId() << ")" << endl;) + } + } + + opdefp->visited = true; + opdefp = &opdefs.at(opdefp->linkx); + assert(opdefp->globid != -1); + } + } + } + } +} + + +void WebMaker::linkDef(Opndx::OpDefs& opdefs, OpDef* lastdefp, OpDef* opdefp) +{ + for (OpDef* p = lastdefp;;) + { + if (p == opdefp) + return; + if ((p = &opdefs.at(p->linkx)) == lastdefp) + break; + } + + size_t wx = lastdefp->linkx; + lastdefp->linkx = opdefp->linkx; + opdefp->linkx = wx; + DBGOUT("** glob def linked " << opdefp->globid << " + " << lastdefp->globid << endl;) +} + + +BitSet* WebMaker::bitsetp (BitSet*& bsp) +{ + if (bsp == 0) + bsp = new BitSet(mm, globcount); + else + bsp->resize(globcount); + return bsp; +} + + +Opnd* WebMaker::splitOpnd (const Opnd* op) +{ + Opnd* np = irManager->newOpnd(op->getType(), op->getConstraint(Opnd::ConstraintKind_Initial)); + np->setCalculatedConstraint( op->getConstraint(Opnd::ConstraintKind_Calculated)); + ++splitcount; + return np; +} + + +//======================================================================================== +// Internal debug helpers +//======================================================================================== + + +#ifdef _DEBUG__WEBMAKER + +static void onConstruct (const IRManager& irm) +{ + MethodDesc& md = irm.getMethodDesc(); + const char * methodName = md.getName(); + const char * methodTypeName = md.getParentType()->getName(); + DBGOUT(endl << "Constructed " << methodTypeName << "." << methodName + << "(" << md.getSignatureString() << ")" << endl;) + +// sos = strcmp(methodTypeName, "spec/benchmarks/_213_javac/BatchEnvironment") == 0 && +// strcmp(methodName, "flushErrors") == 0; +} + + +static void onDestruct () +{ + DBGOUT(endl << "Destructed" << endl;) +} + +#endif //#ifdef _DEBUG__WEBMAKER + + +//======================================================================================== +// Output formatters +//======================================================================================== + + +#ifdef _DEBUG__WEBMAKER + +static ostream& operator << (ostream& os, Sep& x) +{ + if (x.first) + x.first = false; + else + os << ","; + return os; +} + +static ostream& operator << (ostream& os, const Inst& x) +{ + return os << "I#" << x.getId(); +} + + +static ostream& operator << (ostream& os, const Opnd& x) +{ + os << "O#" << x.getFirstId(); + RegName rn = x.getRegName(); + if (rn != RegName_Null) + os << "<" << getRegNameString(rn) << ">"; + if (x.isPlacedIn(OpndKind_Memory)) + os << "<mem>"; + return os; +} + + +static ostream& operator << (ostream& os, /*const*/ BitSet* bs) +{ + if (bs != 0) + { + os << "{"; + Sep s; + BitSet::IterB bsk(*bs); + for (int i = bsk.getNext(); i != -1; i = bsk.getNext()) + os << s << i; + os << "}"; + } + else + os << "null"; + + return os; +} + +#endif //#ifdef _DEBUG__WEBMAKER + +} //namespace Ia32 +} //namespace Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfCfg.cpp vm/jitrino/src/codegenerator/ipf/IpfCfg.cpp new file mode 100644 index 0000000..f02d84d --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfCfg.cpp @@ -0,0 +1,343 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Edge +//========================================================================================// + +Edge::Edge(Node *source_, Node *target_, double prob_) : + edgeKind(EDGE_THROUGH), + source(source_), + target(target_), + prob(prob_) { +} + +//----------------------------------------------------------------------------------------// + +Edge::Edge(Node *source_, Node *target_, double prob_, EdgeKind edgeKind_) : + edgeKind(edgeKind_), + source(source_), + target(target_), + prob(prob_) { +} + +//----------------------------------------------------------------------------------------// + +bool Edge::isBackEdge() { + + if(source->getLoopHeader() == target) return true; + return false; +} + +//---------------------------------------------------------------------------// +void Edge::connect(Node *target_) { + if (target!=NULL) { +// target->removeEdge(this); + target->removeInEdge(this); + } + target=target_; +// target_->addEdge(this); + target_->addInEdge(this); +} + +//----------------------------------------------------------------------------// +void Edge::disconnect() { + if (target!=NULL) { +// target->removeEdge(this); + target->removeInEdge(this); + target=NULL; + } +} + +//========================================================================================// +// ExceptionEdge +//========================================================================================// + +ExceptionEdge::ExceptionEdge(Node *source_, + Node *target_, + double prob_, + Type *exceptionType_, + uint32 priority_) : + Edge(source_, target_, prob_), + exceptionType(exceptionType_), + priority(priority_) { + setEdgeKind(EDGE_EXCEPTION); +} + +//========================================================================================// +// Node +//========================================================================================// + +Node::Node(uint32 id_, NodeKind kind_) { + id = id_; + nodeKind = kind_; + loopHeader = NULL; +} + +//----------------------------------------------------------------------------------------// + +void Node::addEdge(Edge *edge) { + + if(edge->getSource() == this) outEdges.push_back(edge); + if(edge->getTarget() == this) inEdges.push_back(edge); +} + +//----------------------------------------------------------------------------------------// + +void Node::removeEdge(Edge *edge) { + if(edge->getSource() == this) remove(outEdges.begin(), outEdges.end(), edge); + if(edge->getTarget() == this) remove(inEdges.begin(), inEdges.end(), edge); +} + +//----------------------------------------------------------------------------------------// + +Edge *Node::getOutEdge(EdgeKind edgeKind) { + + Edge *edge = NULL; + for(uint16 i=0; i<outEdges.size(); i++) { + if(outEdges[i]->getEdgeKind() == edgeKind) { + if(edge != NULL) assert(0); + edge = outEdges[i]; + } + } + return edge; +} + +//----------------------------------------------------------------------------------------// + +Edge *Node::getOutEdge(Node *targetNode) { + for(uint16 i=0; i<outEdges.size(); i++) + if(outEdges[i]->getTarget() == targetNode) return outEdges[i]; + return NULL; +} + +//----------------------------------------------------------------------------------------// + +Edge *Node::getInEdge(EdgeKind edgeKind) { + + Edge *edge = NULL; + for(uint16 i=0; i<inEdges.size(); i++) { + if(inEdges[i]->getEdgeKind() == edgeKind) { + if(edge != NULL) assert(0); + edge = inEdges[i]; + } + } + return edge; +} + +//----------------------------------------------------------------------------------------// + +Edge *Node::getInEdge(Node *sourceNode) { + for(uint16 i=0; i<inEdges.size(); i++) + if(inEdges[i]->getSource() == sourceNode) return inEdges[i]; + return NULL; +} + +//----------------------------------------------------------------------------------------// + +Node *Node::getDispatchNode() { + + Edge *dispatchEdge = getOutEdge(EDGE_DISPATCH); + if(dispatchEdge == NULL) return NULL; + return dispatchEdge->getTarget(); +} + +//----------------------------------------------------------------------------------------// + +void Node::mergeOutLiveSets(RegOpndSet &resultSet) { + + for(uint16 i=0; i<outEdges.size(); i++) { + RegOpndSet &outLiveSet = outEdges[i]->getTarget()->getLiveSet(); + resultSet.insert(outLiveSet.begin(), outLiveSet.end()); + } +} + +//----------------------------------------------------------------------------------------// + +void Node::removeInEdge(Edge *edge) { +// remove(inEdges.begin(), inEdges.end(), edge); + EdgeVector::iterator last=inEdges.end(); + EdgeVector::iterator pos=find(inEdges.begin(), last, edge); + if (pos==last) return; // not found + inEdges.erase(pos); +} + +void Node::addInEdge(Edge *edge) { + inEdges.push_back(edge); +} + +void Node::printEdges(ostream& out, EdgeVector& edges, bool head) { + for (uint i=0; i<edges.size(); i++) { + Edge *edge=edges[i]; + if (edge==NULL) { + out << " <edge[" << i << "]=null>"; + continue; + } + Node *sibling=head? edge->getTarget(): edge->getSource(); + if (sibling==NULL) { + out << " null"; + continue; + } + out << " " << sibling->getId(); + } +} + +void Node::printEdges(ostream& out) { + out << " ins:"; + printEdges(out, getInEdges(), false); + out << " outs:"; + printEdges(out, getOutEdges(), true); +} + +//========================================================================================// +// BbNode +//========================================================================================// + +BbNode::BbNode(uint32 id_, uint32 execCounter_) : + Node(id_, NODE_BB), + layoutSucc(NULL), + address(0), + execCounter(execCounter_) { +} + +//----------------------------------------------------------------------------------------// + +void BbNode::addInst(Inst *inst) { + + IPF_LOG << " " << IrPrinter::toString(inst) << endl; + insts.push_back(inst); +} + +//========================================================================================// +// Cfg +//========================================================================================// + +Cfg::Cfg(MemoryManager &mm, CompilationInterface &compilationInterface): + mm(mm), + compilationInterface(compilationInterface), + enterNode(NULL), + lastSearchKind(SEARCH_UNDEF_ORDER), + maxNodeId(0) { + + opndManager = new(mm) OpndManager(mm, compilationInterface); +} + +//----------------------------------------------------------------------------------------// + +void Cfg::addEdge(Edge *edge) { + + edge->getSource()->addEdge(edge); + edge->getTarget()->addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void Cfg::removeEdge(Edge *edge) { + + edge->getSource()->removeEdge(edge); + edge->getTarget()->removeEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void Cfg::removeNode(Node *node) { + + EdgeVector &inEdges = node->getInEdges(); + EdgeVector &outEdges = node->getOutEdges(); + + for(uint16 i=0; i<inEdges.size(); i++) inEdges[i]->getSource()->removeEdge(inEdges[i]); + for(uint16 i=0; i<outEdges.size(); i++) outEdges[i]->getSource()->removeEdge(outEdges[i]); +} + +//----------------------------------------------------------------------------------------// + +NodeVector& Cfg::search(SearchKind searchKind) { + + if(lastSearchKind == searchKind) return searchResult; + lastSearchKind = searchKind; + + NodeSet visitedNodes; + searchResult.clear(); + + switch(searchKind) { + case SEARCH_DIRECT_ORDER : makeDirectOrdered(exitNode, visitedNodes); break; + case SEARCH_POST_ORDER : makePostOrdered(enterNode, visitedNodes); break; + case SEARCH_LAYOUT_ORDER : makeLayoutOrdered(); break; + case SEARCH_UNDEF_ORDER : break; + default : IPF_LOG << IPF_ERROR << endl; break; + } + + return searchResult; +} + +//----------------------------------------------------------------------------------------// +// All predecessors of current node have already been visited + +void Cfg::makeDirectOrdered(Node *node, NodeSet &visitedNodes) { + + visitedNodes.insert(node); // mark node visited + + EdgeVector& inEdges = node->getInEdges(); // get inEdges + for(uint32 i=0; i<inEdges.size(); i++) { // iterate through inEdges + Node *pred = inEdges[i]->getSource(); // get pred node + if(visitedNodes.count(pred) == 1) continue; // if it is already visited - ignore + makeDirectOrdered(pred, visitedNodes); // we have found unvisited pred - reenter + } + searchResult.push_back(node); // all succs have been visited - place node in searchResult vector +} + +//----------------------------------------------------------------------------------------// +// All successors of current node have already been visited + +void Cfg::makePostOrdered(Node *node, NodeSet &visitedNodes) { + + visitedNodes.insert(node); // mark node visited + + EdgeVector& outEdges = node->getOutEdges(); // get outEdges + for(uint32 i=0; i<outEdges.size(); i++) { // iterate through outEdges + Node *succ = outEdges[i]->getTarget(); // get succ node + if(visitedNodes.count(succ) == 1) continue; // if it is already visited - ignore + makePostOrdered(succ, visitedNodes); // we have found unvisited succ - reenter + } + searchResult.push_back(node); // all succs have been visited - place node in searchResult vector +} + +//----------------------------------------------------------------------------------------// + +void Cfg::makeLayoutOrdered() { + + BbNode *node = (BbNode *)getEnterNode(); + while(node != NULL) { + searchResult.push_back(node); + node = node->getLayoutSucc(); + } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfCfgVerifier.cpp vm/jitrino/src/codegenerator/ipf/IpfCfgVerifier.cpp new file mode 100644 index 0000000..f9097ef --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfCfgVerifier.cpp @@ -0,0 +1,768 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "BitSet.h" +#include "IpfCfgVerifier.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// OrderededNodeVector +//========================================================================================// +class OrderededNodeVector:public NodeVector { + friend class CfgView; +public: + OrderededNodeVector(Cfg& cfg_, const char* orderName, bool fromEnter=true): + cfg(cfg_), + orderName(orderName), + valid(false), + fromEnter(fromEnter), + nodes(*this), + visitedNodes(cfg_.getMM(), cfg_.getMaxNodeId()) + {} + + void collect(); + void printContent(ostream& out); + +protected: + + virtual void makeOrdered(Node* node)=0; + virtual ~OrderededNodeVector(){}; // for gcc + + Cfg& cfg; + const char* orderName; + bool valid; + bool fromEnter; + NodeVector& nodes; + BitSet visitedNodes; + +}; + +//---------------------------------------------------------------------------// +void OrderededNodeVector::collect() { + if (valid) return; + nodes.clear(); + uint32 numNodes=cfg.getMaxNodeId(); + visitedNodes.resizeClear(numNodes); + makeOrdered(fromEnter?cfg.getEnterNode():cfg.getExitNode()); + valid=true; +} + +//---------------------------------------------------------------------------// +void OrderededNodeVector::printContent(ostream& out) { + out << "CFG ordered: " << orderName << " size:" << size() << endl; + for(uint k=0; k<nodes.size(); k++) { + Node* node=nodes[k]; + out << "node " << node->getId() << ": "; + node->printEdges(out); + out << endl; + } +} + +//---------------------------------------------------------------------------// +class DirectOrderedNodeVector: public OrderededNodeVector { +public: + DirectOrderedNodeVector(Cfg& cfg_): + OrderededNodeVector(cfg_, "Direct", false) + {} +protected: + virtual void makeOrdered(Node* node); + +}; + +void DirectOrderedNodeVector::makeOrdered(Node* node) { + visitedNodes.setBit(node->getId()); // mark node visited + EdgeVector& inEdges = node->getInEdges(); // get inEdges + for (uint i=0; i<inEdges.size(); i++) { // iterate through inEdges + Edge* edge=inEdges[i]; + if (edge==NULL) { + assert(edge); + continue; + } + Node* pred = edge->getSource(); // get pred node + if (pred==NULL) { + assert(pred); + continue; + } + if (visitedNodes.getBit(pred->getId())) continue; // if it is already visited - ignore + makeOrdered(pred); // we have found unvisited pred - reenter + } + nodes.push_back(node); // all succs have been visited - place node in searchResult vector +} + +//----------------------------------------------------------------------------------------// +class PostOrderededNodeVector: public OrderededNodeVector { +public: + PostOrderededNodeVector(Cfg& cfg_): + OrderededNodeVector(cfg_, "Post") + {} +protected: + virtual void makeOrdered(Node* node); + +}; + +void PostOrderededNodeVector::makeOrdered(Node* node) { + visitedNodes.setBit(node->getId()); // mark node visited + EdgeVector& outEdges = node->getOutEdges(); // get outEdges + for (uint i=0; i<outEdges.size(); i++) { // iterate through outEdges + Edge* edge=outEdges[i]; + if (edge==NULL) { + assert(edge); + continue; + } + Node* succ = edge->getTarget(); // get succ node + if (succ==NULL) { + assert(succ); + continue; + } + if (visitedNodes.getBit(succ->getId())) continue; // if it is already visited - ignore + makeOrdered(succ); // we have found unvisited succ - reenter + } + nodes.push_back(node); // all succs have been visited - place node in searchResult vector +} + +//----------------------------------------------------------------------------------------// + +class LayoutOrderedNodeVector: public OrderededNodeVector { +public: + LayoutOrderedNodeVector(Cfg& cfg_): + OrderededNodeVector(cfg_, "Layout") + {} +protected: + virtual void makeOrdered(Node* node); + +}; + +void LayoutOrderedNodeVector::makeOrdered(Node* node_) { + BbNode* node = (BbNode*)node_; + while (node != NULL) { + visitedNodes.setBit(node->getId()); // mark node visited + nodes.push_back(node); + node = node->getLayoutSucc(); + } +} + +//========================================================================================// +class CfgView { +public: + CfgView(Cfg& cfg_): + directOrderedNodes(cfg_), + postOrderedNodes(cfg_), + layoutOrderedNodes(cfg_) + {} + + OrderededNodeVector& sortNodes(SearchKind searchKind); + void changed(); + bool verifyNodes(ostream& cout); + +private: + DirectOrderedNodeVector directOrderedNodes; + PostOrderededNodeVector postOrderedNodes; + LayoutOrderedNodeVector layoutOrderedNodes; +}; + +//---------------------------------------------------------------------------// +OrderededNodeVector& CfgView::sortNodes(SearchKind searchKind) { + switch (searchKind) { + case SEARCH_DIRECT_ORDER : + directOrderedNodes.collect(); + return directOrderedNodes; + case SEARCH_POST_ORDER : + postOrderedNodes.collect(); + return postOrderedNodes; + case SEARCH_LAYOUT_ORDER : + layoutOrderedNodes.collect(); + return layoutOrderedNodes; + case SEARCH_UNDEF_ORDER : + if (directOrderedNodes.valid) return directOrderedNodes; + if (postOrderedNodes.valid) return postOrderedNodes; + layoutOrderedNodes.collect(); + return layoutOrderedNodes; + default: + IPF_LOG << IPF_ERROR << endl; + assert(0); + layoutOrderedNodes.collect(); + return layoutOrderedNodes; + } +} + +bool CfgView::verifyNodes(ostream& cout) { + OrderededNodeVector& dir=sortNodes(SEARCH_DIRECT_ORDER); + OrderededNodeVector& post=sortNodes(SEARCH_POST_ORDER); + if (dir.visitedNodes.isEqual(post.visitedNodes)) return true; + cout << "verifyNodes: DIRECT_ORDER and POST_ORDER differs:" << endl; + BitSet collectedNodes(dir.visitedNodes); + collectedNodes.subtract(post.visitedNodes); + if (!collectedNodes.isEmpty()) { + cout << " DIRECT-POST = "; + collectedNodes.print(cout); + } + collectedNodes.copyFrom(post.visitedNodes); + collectedNodes.subtract(dir.visitedNodes); + if (!collectedNodes.isEmpty()) { + cout << " POST-DIRECT = "; + collectedNodes.print(cout); + } +// IPF_EXIT("CfgView::verifyNodes"); + return false; +} + +void CfgView::changed() { + directOrderedNodes.valid=false; + postOrderedNodes.valid=false; + layoutOrderedNodes.valid=false; +} + +//===========================================================================// +class IpfCfgVerifier: public CfgView { + friend class Vertex; + friend class VertexBB; +protected: + MemoryManager& mm; + Cfg& cfg; + uint numAllNodes; + uint numNodes; + uint numOpnds; + NodeVector& nodes; + Vertex** verticesById; // by node ids + Vertex** vertices; // post-ordered + BitSet tmpSet; + BitSet tmpSet2; + BitSet ignoredOpnds; + RegOpnd** opndsById; + uint p0Id; + + Vertex* getVertex(Node* node) { + return verticesById[node->getId()]; + } + VertexBB* getVertexBB(BbNode* node) { + return (VertexBB*)(verticesById[node->getId()]); + } + Vertex* getSourceVertex(Edge* edge) { + return getVertex(edge->getSource()); + } + Vertex* getTargetVertex(Edge* edge) { + return getVertex(edge->getTarget()); + } + + void registerOpnds(OpndVector& opnds); + void printOpndSet(ostream& os, const char* str, BitSet& set); +public: + + IpfCfgVerifier(MemoryManager& mm, Cfg& cfg); + void setDefUse(); + bool collectLiveSets(); + virtual bool checkLiveSets(); + + void setDefs(); + bool collectDefs(); + virtual bool checkDefs(); + + virtual ~IpfCfgVerifier() {} +}; // end class IpfCfgVerifier + +struct Vertex { +// friend class IpfCfgVerifier; + IpfCfgVerifier& fSolver; + Node* node; + BitSet* in; + BitSet* out; + + Vertex(MemoryManager& mm, IpfCfgVerifier& fSolver, Node* node, int width): + fSolver(fSolver), + node(node), + in(new(mm) BitSet(mm, width)), + out(in) + {} + + EdgeVector& getInEdges() { + return node->getInEdges(); + } + EdgeVector& getOutEdges() { + return node->getOutEdges(); + } + + virtual void computeIn(); +// virtual bool checkLiveSet() {return true; } + bool checkLiveSet(); + + virtual void computeOut(); + virtual bool checkDefs() {return true; } + +}; + +struct VertexBB:Vertex { +// friend class IpfCfgVerifier; + BbNode* node; + BitSet* use; + BitSet* def; + + VertexBB(MemoryManager& mm, IpfCfgVerifier& fSolver, BbNode* node, int width): + Vertex(mm, fSolver, node, width), + node(node), + use(new(mm) BitSet(mm, width)), + def(new(mm) BitSet(mm, width)) // TODO: def and use may be null + { + in=new(mm) BitSet(mm, width); + } + + void setDefUse(); + virtual void computeIn(); +// virtual bool checkLiveSet(); + + void setDef(Inst* inst); + void setDef(); + virtual void computeOut(); + bool checkOpndIsDef(Opnd* opnd, uint instId); + virtual bool checkDefs(); + +}; + +//---------------------------------------------------------------------------// +IpfCfgVerifier::IpfCfgVerifier(MemoryManager& mm, Cfg& cfg): + CfgView(cfg), + mm(mm), + cfg(cfg), + numAllNodes(cfg.getMaxNodeId()), + numOpnds(cfg.getOpndManager()->getNumOpnds()), + nodes(sortNodes(SEARCH_DIRECT_ORDER)), + verticesById(new(mm) (Vertex*)[numAllNodes]), + vertices(NULL), + tmpSet(mm, numOpnds), + tmpSet2(mm, numOpnds), + ignoredOpnds(mm, numOpnds), + opndsById(new(mm) (RegOpnd*)[numOpnds]), + p0Id(cfg.getOpndManager()->getP0()->getId()) +{ + for (uint k=0; k<numAllNodes; k++) { + verticesById[k]=NULL; + } + for (uint k=0; k<numOpnds; k++) { + opndsById[k]=NULL; + } + + numNodes=nodes.size(); + vertices=new(mm) (Vertex*)[numNodes]; + for (uint k=0; k<numNodes; k++) { + Node* node=nodes[k]; + Vertex* vertex; + if (node->getNodeKind()==NODE_BB) { + vertex=new(mm) VertexBB(mm, *this, (BbNode*)node, numOpnds); + } else { + vertex=new(mm) Vertex(mm, *this, node, numOpnds); + } + verticesById[node->getId()]=vertex; + vertices[k]=vertex; + } +} + +//---------------------------------------------------------------------------// +void IpfCfgVerifier::printOpndSet(ostream& os, const char* str, BitSet& set) { + RegOpndSet opndSet; + os << str; + for (uint k=0; k<numOpnds; k++) { + if (set.getBit(k)) { + RegOpnd* opnd=opndsById[k]; + if (opnd==NULL) { + os << "opnd[" << k << "] "; + continue; + } + opndSet.insert(opnd); + } + } + os << IrPrinter::toString(opndSet) << endl; +} + +//---------------------------------------------------------------------------// +// register ALL opnds in 'opndsById' +void IpfCfgVerifier::registerOpnds(OpndVector& opnds) { + for (uint k=0; k<opnds.size(); k++) { + Opnd* opnd = opnds[k]; + if (!opnd->isReg()) continue; + RegOpnd* reg = (RegOpnd*)opnd; + uint id=opnd->getId(); + if (opndsById[id]==reg) { + continue; // registered already + } + opndsById[id]=reg; + + int num=reg->getValue(); + switch(reg->getOpndKind()) { + case OPND_G_REG: + // ignore r0 r8 + if ((num == 0)|| (num == 8)) { + // r8 - returned value; TODO: more accurate + ignoredOpnds.setBit(id); + } + break; + case OPND_F_REG: + // ignore f0 f1 f8 + if ((num == 0) || (num == 1) || (num == 8)) { + // f8 - returned value; TODO: more accurate + ignoredOpnds.setBit(id); + } + break; + case OPND_P_REG: + // ignore p0 + if (num == 0) { + ignoredOpnds.setBit(id); + } + break; + case OPND_B_REG: + // ignore all br: + ignoredOpnds.setBit(id); + break; + default: ; + } + } +} + +//---------------------------------------------------------------------------// +// check live sets +//---------------------------------------------------------------------------// + +void VertexBB::setDefUse() { + // iterate through instructions postorder and calculate liveSet for begining of the node + InstVector& insts = node->getInsts(); + for (int j=insts.size()-1; j>=0; j--) { + Inst* inst=insts[j]; + uint numDst=inst->getNumDst(); + OpndVector& opnds = inst->getOpnds(); // get inst opnds + + if (((RegOpnd*) opnds[0])->getValue() == 0) { // qp==p0 + for (uint k=1; k<numDst+1; k++) { + Opnd* opnd = opnds[k]; + if (!opnd->isReg()) continue; // ignore non register opnd + uint id=opnd->getId(); + def->setBit(id); + use->setBit(id, false); + } + // TODO: If no one opnd was in Live Set - inst is dead + } else { + // add qp opnd in Use Set + use->setBit(opnds[0]->getId()); + } + // add src opnds in Use Set + for (uint k=numDst+1; k<opnds.size(); k++) { + Opnd* opnd = opnds[k]; + if (!opnd->isReg()) continue; // ignore non register opnd + use->setBit(opnd->getId()); + } + fSolver.registerOpnds(opnds); + } +} + +void IpfCfgVerifier::setDefUse() { + for (int k=numNodes-1; k>=0; k--) { + Node* node=nodes[k]; + if (node->getNodeKind()==NODE_BB) { + VertexBB* vertex=getVertexBB((BbNode*)node); + vertex->setDefUse(); + } + } +} + +void Vertex::computeIn() { + // out[B] := U in[S] + EdgeVector& outEdges=getOutEdges(); + uint size=outEdges.size(); + if (size==0) return; + Vertex* succ=fSolver.getTargetVertex(outEdges[0]); + out->copyFrom(*(succ->in)); + for (uint k=1; k<outEdges.size(); k++) { + succ=fSolver.getTargetVertex(outEdges[k]); + out->unionWith(*(succ->in)); + } + // in[B] == out[B] +} + +void VertexBB::computeIn() { + // out[B] := U in[S] + Vertex::computeIn(); + // in[B] := use[B} U (out[B] - def[B]) + in->copyFrom(*out); + in->subtract(*def); + in->unionWith(*use); +} + +//---------------------------------------------------------------------------// +//bool VertexBB::checkLiveSet() { +bool Vertex::checkLiveSet() { + + RegOpndSet& liveSet = node->getLiveSet(); + BitSet& dceIn=fSolver.tmpSet; + BitSet& tmpSet=fSolver.tmpSet2; + dceIn.clear(); + + for (RegOpndSetIterator i=liveSet.begin(); i!=liveSet.end(); i++) { + Opnd* opnd = (Opnd*)(*i); + IPF_ASSERT(opnd!=NULL); + uint id = opnd->getId(); + dceIn.setBit(id); + } + dceIn.subtract(fSolver.ignoredOpnds); // ignore p0, r0, f0 etc + in->subtract(fSolver.ignoredOpnds); + if (in->isEqual(dceIn)) return true; + + IPF_LOG << "checkLiveSets: DCE and IpfCfgVerifier results differs for node" << node->getId() << endl; + bool res=true; + tmpSet.copyFrom(dceIn); + tmpSet.subtract(*in); + if (!tmpSet.isEmpty()) { + if (LOG_ON) { + fSolver.printOpndSet(LOG_OUT, " DCE has ", tmpSet); + } +// res=false; commented out while too many failures to concide + } + + tmpSet.copyFrom(*in); + tmpSet.subtract(dceIn); + if (!tmpSet.isEmpty()) { + if (LOG_ON) { + fSolver.printOpndSet(LOG_OUT, " IpfCfgVerifier has ", tmpSet); + } + res=false; + } + + return res; +} + +//---------------------------------------------------------------------------// + +bool IpfCfgVerifier::collectLiveSets() { + bool changed = false; + for (int k=numNodes-1; k>=0; k--) { + Vertex* vertex=vertices[k]; + tmpSet.copyFrom(*vertex->in); // save to compare + vertex->computeIn(); +//printf(" %s%d", vertex->in->getBit(9)?"*":" ", vertex->node->getId()); + if (!changed) { + changed = !vertex->in->isEqual(tmpSet); // compare + } + } +//printf("\n"); + return changed; +} + +//---------------------------------------------------------------------------// +bool IpfCfgVerifier::checkLiveSets() { + setDefUse(); +//printf("IpfCfgVerifier::checkLiveSets():\n"); + // solve the flow equation set + while (collectLiveSets()) {}; + + // compare our results with DCE results + bool res = true; + for (uint k=0; k<numNodes; k++) { + Vertex* vertex=vertices[k]; + res=vertex->checkLiveSet() & res; + } + if (res) { + if (LOG_ON) { + IPF_LOG << "ignoredOpnds="; + ignoredOpnds.print(LOG_OUT); + } + } + return res; +} + +//---------------------------------------------------------------------------// +// check defs +//---------------------------------------------------------------------------// + +void VertexBB::setDef(Inst* inst) { + uint numDst=inst->getNumDst(); + OpndVector& opnds = inst->getOpnds(); // get inst opnds + +// if (((RegOpnd*) opnds[0])->getLocation() == 0) { // qp==p0 +// TODO: handle conditional instructions more accurate + for (uint k=1; k<numDst+1; k++) { + Opnd* opnd = opnds[k]; + if (!opnd->isReg()) continue; // ignore non register opnd + uint id=opnd->getId(); + def->setBit(id); + } +} + +void VertexBB::setDef() { + // iterate through instructions in direct order + InstVector& insts = node->getInsts(); + for (uint j=0; j<insts.size(); j++) { + Inst* inst=insts[j]; + setDef(inst); + OpndVector& opnds = inst->getOpnds(); // get inst opnds + fSolver.registerOpnds(opnds); + } +} + +//---------------------------------------------------------------------------// +void IpfCfgVerifier::setDefs() { + OpndVector& args = cfg.getArgs(); + BitSet* enterIn=getVertex(cfg.getEnterNode())->in; + for (uint k=0; k<args.size(); k++) { + enterIn->setBit(args[k]->getId()); + } + + for (uint k=0; k<numNodes; k++) { + Node* node=nodes[k]; + if (node->getNodeKind()==NODE_BB) { + VertexBB* vertex=getVertexBB((BbNode*)node); + vertex->setDef(); + } + } + + // after opnds registered and ignoredOpnds collected + enterIn->unionWith(ignoredOpnds); + for (uint k=0; k<numNodes; k++) { + Node* node=nodes[k]; + Vertex* vertex=getVertex(node); + vertex->out->setAll(); + if (node->getNodeKind()==NODE_BB) { + ((VertexBB*)vertex)->def->unionWith(ignoredOpnds); + } + } +} + +void Vertex::computeOut() { + // in[B] := & out[Preds] + EdgeVector& inEdges=getInEdges(); + uint size=inEdges.size(); + if (size==0) return; + Vertex* pred=fSolver.getSourceVertex(inEdges[0]); + in->copyFrom(*(pred->out)); + for (uint k=1; k<inEdges.size(); k++) { + pred=fSolver.getSourceVertex(inEdges[k]); + in->intersectWith(*(pred->out)); + } + // out[B] := in[B] +} + +void VertexBB::computeOut() { + Vertex::computeOut(); + // out[B] := in[B] U def[B] + out->copyFrom(*in); + out->unionWith(*def); +} + +//---------------------------------------------------------------------------// + +bool IpfCfgVerifier::collectDefs() { + bool changed = false; + for (uint k=0; k<numNodes; k++) { + Vertex* vertex=vertices[k]; + tmpSet.copyFrom(*vertex->out); // save to compare + vertex->computeOut(); + +// bool vchanged = !vertex->out->isEqual(tmpSet); // compare + if (!changed) { + changed = !vertex->out->isEqual(tmpSet); // compare + } + } + return changed; +} + +bool VertexBB::checkOpndIsDef(Opnd* opnd, uint instId) { + uint id=opnd->getId(); + if (def->getBit(id)) return true; + IPF_LOG << "UNDEF Opnd: " << IrPrinter::toString(opnd) << " in " + << node->getId() << ":" << instId << " " + << IrPrinter::toString((node->getInsts())[instId]) << endl; + return false; +} + +bool VertexBB::checkDefs() { + bool res=true; + // iterate through instructions in direct order + InstVector& insts = ((BbNode*)node)->getInsts(); + def->copyFrom(*in); + for (uint j=0; j<insts.size(); j++) { + Inst* inst=insts[j]; + uint numDst=inst->getNumDst(); + OpndVector& opnds = inst->getOpnds(); // get inst opnds + + // check src opnds + RegOpnd* qp = (RegOpnd*)opnds[0]; + if (qp->getValue() != 0) { // qp != p0, check qp opnd + res = checkOpndIsDef(qp, j) & res; + } + for (uint k=numDst+1; k<opnds.size(); k++) { + Opnd* opnd = opnds[k]; + if (!opnd->isReg()) continue; // ignore non register opnd + res = checkOpndIsDef(opnd, j) & res; + } + + // handle dst opnds + setDef(inst); + } + return res; +} + +//---------------------------------------------------------------------------// +bool IpfCfgVerifier::checkDefs() { + setDefs(); + + // solve the flow equation set + while (collectDefs()) {}; + + bool res = true; + for (uint k=0; k<numNodes; k++) { + Vertex* vertex=vertices[k]; + res=vertex->checkDefs() & res; + } + return res; +} + +//---------------------------------------------------------------------------// +void ipfCfgVerifier(Cfg& cfg) { + MemoryManager mm(1024, "IpfCfgVerifier"); + IpfCfgVerifier verifier(mm, cfg); + MethodDesc* method = cfg.getMethodDesc(); + const char* methodName = method->getName(); + const char* methodTypeName = (method->getParentType()!=NULL + ? method->getParentType()->getName() + : ""); + const char * methodSignature = method->getSignatureString(); + + if (!verifier.verifyNodes(LOG_OUT)) { + cout << "CFG check failed for " << methodTypeName << "." << methodName << methodSignature << endl; + } + // print + if (LOG_ON) { + verifier.sortNodes(SEARCH_DIRECT_ORDER).printContent(LOG_OUT); + } + + if (!verifier.checkLiveSets()) { + cout << "liveset check failed for [" << cfg.getMaxNodeId() << "] " << methodTypeName << "." << methodName << methodSignature << endl; + } + if (!verifier.checkDefs()) { + cout << "def check failed for [" << cfg.getMaxNodeId() << "] " << methodTypeName << "." << methodName << methodSignature << endl; + } + +} + +} // IPF +} // Jitrino +// TODO: +// debug this file saved in ~/saved diff --git vm/jitrino/src/codegenerator/ipf/IpfCodeGenerator.cpp vm/jitrino/src/codegenerator/ipf/IpfCodeGenerator.cpp new file mode 100755 index 0000000..3e973a0 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfCodeGenerator.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "Jitrino.h" +#include "IpfCodeGenerator.h" +#include "IpfCodeSelector.h" +#include "IpfCodeLayouter.h" +#include "IpfLiveAnalyzer.h" +#include "IpfDce.h" +#include "IpfRegisterAllocator.h" +#include "IpfSpillGen.h" +#include "IpfIrPrinter.h" +#include "IpfEmitter.h" +#include "IpfPrologEpilogGenerator.h" +#include "IpfRuntimeSupport.h" +#include "IpfCfgVerifier.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// IpfCodeGenerator +//========================================================================================// + +CodeGenerator::CodeGenerator(MemoryManager &memoryManager_, + CompilationInterface &compilationInterface_) + : memoryManager(memoryManager_), compilationInterface(compilationInterface_) { + + cfg = NULL; + methodDesc = NULL; +} + +//----------------------------------------------------------------------------------------// + +bool CodeGenerator::genCode(MethodCodeSelector &methodCodeSelector) { + + MemoryManager mm(0x1000, "IpfCodeGenerator"); + cfg = new(mm) Cfg(mm, compilationInterface); + char logDirName[] = "tmp_dir_name"; + IrPrinter irPrinter(*cfg, logDirName); + methodDesc = compilationInterface.getMethodToCompile(); + +// bool ipfLogIsOnSaved = ipfLogIsOn; +// if (isIpfLogoutMethod(methodDesc)) { +// ipfLogIsOn = true; +// } + if(LOG_ON) { + const char *methodName = methodDesc->getName(); + const char *methodTypeName = (methodDesc->getParentType()!=NULL + ? methodDesc->getParentType()->getName() + : ""); + const char * methodSignature = methodDesc->getSignatureString(); + + IPF_LOG << endl << methodTypeName << "." << methodName << methodSignature << endl; + } + + IPF_LOG << endl << "=========== Stage: Code Selector =============================" << endl; + IpfMethodCodeSelector ipfMethodCodeSelector(*cfg, compilationInterface); + methodCodeSelector.selectCode(ipfMethodCodeSelector); + + methodDesc = ipfMethodCodeSelector.getMethodDesc(); + cfg->getOpndManager()->initCompBases((BbNode *)cfg->getEnterNode()); + cfg->getOpndManager()->saveThisArg(); + if(LOG_ON) irPrinter.printCfgDot("/cfg_cs.dot"); + + IPF_LOG << endl << "=========== Stage: Code Layouter =============================" << endl; + CodeLayouter codeLayouter(*cfg); + codeLayouter.layout(); + if(LOG_ON) { + irPrinter.printCfgDot("/cfg_cl.dot"); + irPrinter.printLayoutDot("/lot.dot"); + } + + IPF_LOG << endl << "=========== Stage: Liveness analyzis =========================" << endl; + LiveAnalyzer liveAnalyzer(*cfg); + liveAnalyzer.makeLiveSets(false); + + IPF_LOG << endl << "=========== Stage: Dead Code Eliminator ======================" << endl; + Dce dce(*cfg); + dce.eliminate(); + + liveAnalyzer.makeLiveSets(false); + IPF_LOG << endl << "=========== Stage: Build GC Root Set =========================" << endl; + RuntimeSupport runtimeSupport(*cfg, compilationInterface); + runtimeSupport.buildRootSet(); + + IPF_LOG << endl << "=========== Stage: Register Allocator ========================" << endl; + RegisterAllocator registerAllocator(*cfg); + registerAllocator.allocate(); + if(LOG_ON) irPrinter.printAsm(LOG_OUT); + + IPF_LOG << endl << "=========== Stage: Prolog and Epilog Generator ===============" << endl; + PrologEpilogGenerator prologEpilogGenerator(*cfg); + prologEpilogGenerator.genPrologEpilog(); + + IPF_LOG << endl << "=========== Stage: Spill Generator ===========================" << endl; + SpillGen spillGen(*cfg); + spillGen.genSpillCode(); + if(LOG_ON) irPrinter.printAsm(LOG_OUT); + + IPF_LOG << endl << "=========== Stage: Code Emitter ==============================" << endl; + Emitter emitter(*cfg, compilationInterface); + bool ret = emitter.emit(); + + IPF_LOG << endl << "=========== Stage: Make Runtime Info =========================" << endl; + runtimeSupport.makeRuntimeInfo(); + + if(ret) IPF_LOG << endl << "=========== Compilation Successful ===========================" << endl; + else IPF_LOG << endl << "=========== Compilation Failed ===============================" << endl; + +// ipfLogIsOn = ipfLogIsOnSaved; + return ret; +} + +} // IPF +} // Jitrino + diff --git vm/jitrino/src/codegenerator/ipf/IpfCodeLayouter.cpp vm/jitrino/src/codegenerator/ipf/IpfCodeLayouter.cpp new file mode 100644 index 0000000..44cfcda --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfCodeLayouter.cpp @@ -0,0 +1,384 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "BitSet.h" +#include "IpfCodeLayouter.h" +#include "IpfIrPrinter.h" +#include "IpfOpndManager.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Compare two edges by prob value +//========================================================================================// + +bool greaterEdge (Edge *e1, Edge *e2) { return e1->getProb() > e2->getProb(); } + +//========================================================================================// +// CodeLayouter +//========================================================================================// + +CodeLayouter::CodeLayouter(Cfg &cfg_) : + mm(cfg_.getMM()), + cfg(cfg_) { +} + +//----------------------------------------------------------------------------------------// + +void CodeLayouter::layout() { + + IPF_LOG << endl << " Merge Nodes" << endl; + mergeNodes(); + + IPF_LOG << endl << " Make Chains" << endl; + makeChains(); + + IPF_LOG << endl << " Fix Branches" << endl; + fixBranches(); + + IPF_STAT << endl << "STAT_NUM_NODES " << cfg.search(SEARCH_POST_ORDER).size() << endl; +} + +//----------------------------------------------------------------------------------------// + +void CodeLayouter::mergeNodes() { + + NodeVector& nodes = cfg.search(SEARCH_DIRECT_ORDER); + bool cfgChanged = false; + + for (uint i=0; i<nodes.size(); i++) { // iterate through nodes + Node* node = nodes[i]; + + if (LOG_ON) { + IPF_LOG << " node" << setw(2) << left << node->getId() << flush; + node->printEdges(LOG_OUT); + } + + // don't merge with enter node + if (cfg.getEnterNode() == nodes[i]) { + IPF_LOG << " - ignore (don't merge with enter node)" << endl; + continue; + } + + // check node has only one successor (not taking in account unwind node) + EdgeVector& outEdges = node->getOutEdges(); + if (outEdges.size() != 1) { + IPF_LOG << " - ignore (has more than one successor)" << endl; + continue; + } + + // check if node is basic block + if (node->getNodeKind() != NODE_BB) { + IPF_LOG << " - ignore (is not basic block)" << endl; + continue; + } + + // don't merge with enter node + if (cfg.getEnterNode() == outEdges[0]->getTarget()) { + IPF_LOG << " - ignore (don't merge with enter node)" << endl; + continue; + } + + // don't merge with enter node + if (outEdges[0]->getTarget()->getNodeKind() != NODE_BB) { + IPF_LOG << " - ignore (target is not basic block)" << endl; + continue; + } + + cfgChanged |= mergeNode((BbNode*)node, outEdges[0]); + } + + if (cfgChanged) { + cfg.search(SEARCH_UNDEF_ORDER); // we have removed some nodes - old search is broken + } +} + +//----------------------------------------------------------------------------------------// + +bool CodeLayouter::mergeNode(BbNode *pred, Edge* pred2succ) { + BbNode* succ = (BbNode*)pred2succ->getTarget(); + IPF_LOG << " - try to merge with node" << setw(2) << left; + IPF_LOG << succ->getId() << flush; + if (succ->getNodeKind() != NODE_BB) { // if succ is NODE_DISPATCH - ignore + IPF_LOG << " - succ is not NODE_BB - ignore" << endl; + return false; + } + + InstVector &predInsts = pred->getInsts(); + if (predInsts.size() != 0) { // checks applicaple to non-empty blocks: + // do not merge non-empty node with exit node + if (succ == cfg.getExitNode()) { + IPF_LOG << " - merge canceled (succ is Exit Node)" << endl; + return false; + } + // if Succ has predecessors other than pred - return + if (succ->getInEdges().size()!=1) { + IPF_LOG << " - succInEdges.size()!=1" << endl; + return false; + } + // insert Succ instructions after Pred instructions + InstVector &succInsts = succ->getInsts(); + for (uint i=0, succsize = succInsts.size(); i<succsize; i++) { + predInsts.push_back(succInsts[i]); + } + // move combined instruction set to Succ + succInsts.swap(predInsts); + } // end if non-empty block + + // remove Pred's out-edge + pred2succ->disconnect(); + // reconnect Pred's in-edges to Succ + EdgeVector &predInEdges = pred->getInEdges(); + while (predInEdges.size()>0) { + predInEdges[predInEdges.size()-1]->connect(succ); + } + // if Pred is enter node - set Succ as new enter node + if (pred == cfg.getEnterNode()) { + cfg.setEnterNode(succ); + IPF_LOG << " - new enter"; + } + + IPF_LOG << " - merge successful" << endl; + return true; +} + +//----------------------------------------------------------------------------------------// + +void CodeLayouter::makeChains() { + + uint maxNodeId=cfg.getMaxNodeId(); + BbNode **availNodes=new(mm) BbNode*[maxNodeId]; + for(uint i=0; i<maxNodeId; i++) { + availNodes[i] = NULL; + } + + NodeVector& nodes = cfg.search(SEARCH_DIRECT_ORDER); // actually, order does not matter + for(uint i=0; i<nodes.size(); i++) { + Node* node=nodes[i]; + if (node->getNodeKind() != NODE_BB) continue; // ignore not BB nodes + availNodes[node->getId()] = (BbNode*)node; + } + + BbNode *currNode = (BbNode*) cfg.getEnterNode(); // start from the Enter Node + uint availPos=0; // where to look for next available node + IPF_LOG << " new chain:"; + for (;;) { + availNodes[currNode->getId()] = NULL; // mark curr node consumed + IPF_LOG << " node" << currNode->getId() << "->"; + + BbNode* nextNode=NULL; + + // find out edge with max prob + double currProb = -10.0; + EdgeVector& outEdges = currNode->getOutEdges(); + for(uint32 j=0; j<outEdges.size(); j++) { + BbNode* candidate = (BbNode*) outEdges[j]->getTarget(); + if (availNodes[candidate->getId()] == NULL) continue; // ignore consumed nodes + if (currProb < outEdges[j]->getProb()) { // we have found edge with prob greater then curr + currProb = outEdges[j]->getProb(); // reset curr max prob + nextNode = candidate; // curr cand to be placed in chain + } + } + if (nextNode==NULL) { + IPF_LOG << endl; // current chain finished + // try to start next chain + for (; availPos<maxNodeId; availPos++) { + nextNode = availNodes[availPos]; + if (nextNode!=NULL) { + break; + } + } + if (nextNode==NULL) { + return; // no more nodes available + } + IPF_LOG << " new chain:"; + } + currNode->setLayoutSucc(nextNode); + currNode=nextNode; + } +} +//----------------------------------------------------------------------------------------// + +void CodeLayouter::fixBranches() { + + BbNode *node = (BbNode*) cfg.getEnterNode(); + + for(; node != NULL; node = node->getLayoutSucc()) { + + IPF_LOG << " node" << setw(2) << left << node->getId(); + InstVector& insts = node->getInsts(); + + // check if last inst is conditional branch + if(insts.size() != 0) { + CompVector& compList = insts.back()->getComps(); + if(compList.size()>0 && compList[0] == CMPLT_BTYPE_COND) { + IPF_LOG << " fix conditional branch" << endl; + fixConditionalBranch(node); + continue; + } + } + + // check if last inst is ret + if(insts.size() != 0) { + CompVector& compList = insts.back()->getComps(); + if(compList.size()>0 && compList[0] == CMPLT_BTYPE_RET) { + IPF_LOG << " last inst is \"ret\"" << endl; + continue; + } + } + + // check if last inst is switch + if(insts.size() !=0) { + if(insts.back()->getInstCode() == INST_SWITCH) { + IPF_LOG << " fix switch" << endl; + fixSwitch(node); + continue; + } + } + + // thus, it is unconditional branch + IPF_LOG << " fix unconditional branch" << endl; + fixUnconditionalBranch(node); + } + cfg.search(SEARCH_UNDEF_ORDER); // it is possible that we have removed some nodes - old search is broken +} + + +//----------------------------------------------------------------------------------------// +// (p0) cmp4.ge p8, p0 = r32, r2 +// (p8) br unknown target +// +// Sets branch target accordingly + +void CodeLayouter::fixConditionalBranch(BbNode *node) { + + InstVector& insts = node->getInsts(); + Inst* branchInst = insts.back(); + + Edge *branchEdge = node->getOutEdge(EDGE_BRANCH); + Edge *throughEdge = node->getOutEdge(EDGE_THROUGH); + + IPF_LOG << " old branch target is node" << branchEdge->getTarget()->getId() << endl; + + // check if branch edge target coinsides with layout successor + if (branchEdge->getTarget() == node->getLayoutSucc()) { + // swap fall through and branch edges + throughEdge->setEdgeKind(EDGE_BRANCH); + branchEdge->setEdgeKind(EDGE_THROUGH); + Edge *tmpEdge=throughEdge; + throughEdge=branchEdge; branchEdge=tmpEdge; + + // swap predicate registers of the "cmp" instruction + Inst* cmpInst = *(insts.end() - 2); // get "cmp" inst + Opnd* p1 = cmpInst->getOpnd(POS_CMP_P1); // get p1 opnd + Opnd* p2 = cmpInst->getOpnd(POS_CMP_P2); // get p2 opnd + cmpInst->setOpnd(POS_CMP_P1, p2); // set p2 on p1's position + cmpInst->setOpnd(POS_CMP_P2, p1); // set p1 on p2's position + } + + // Set target for branch instruction + NodeRef *targetOpnd = (NodeRef*)branchInst->getOpnd(POS_BR_TARGET); + targetOpnd->setNode((BbNode*)branchEdge->getTarget()); + + IPF_LOG << " new branch target is node" << branchEdge->getTarget()->getId() << endl; + + // If through edge target coinsides with layout successor - do nothing + BbNode* target=(BbNode*) throughEdge->getTarget(); + if (target == node->getLayoutSucc()) { + IPF_LOG << " through edge coinsides with layout successor" << endl; + return; + } + IPF_LOG << " through edge points to" << target->getId() << endl; + + // add intermediate basic block for unconditional branch + BbNode *intNode = new(mm) BbNode(cfg.getNextNodeId(), 0xFFFF); //-1?TBD + IPF_LOG << " generate intermediate node" << intNode->getId() << endl; + intNode->setLayoutSucc(node->getLayoutSucc()); + node->setLayoutSucc(intNode); +// nodes.push_back(intNode); + throughEdge->connect(intNode); + Edge *intEdge = new(mm) Edge(intNode, target, throughEdge->getProb(), EDGE_BRANCH); + cfg.addEdge(intEdge); + cfg.search(SEARCH_UNDEF_ORDER); // old search is broken + + // Add branch instruction + OpndManager* opndManager = cfg.getOpndManager(); + Opnd* p0 = opndManager->getP0(); + NodeRef* targetNodeRef = opndManager->newNodeRef(target); + intNode->addInst(new(mm) Inst(INST_BR, p0, targetNodeRef)); +} + +//----------------------------------------------------------------------------------------// + +void CodeLayouter::fixSwitch(BbNode* node) { + + Inst* lastInst = node->getInsts().back(); + + // Find edge corresponding to layout successor and mark it fall through + Edge *throughEdge = node->getOutEdge((Node*) node->getLayoutSucc()); + throughEdge->setEdgeKind(EDGE_THROUGH); + + Opnd *troughTargetImm = lastInst->getOpnd(POS_SWITCH_THROUGH); + ConstantRef *constantRef = (ConstantRef*) lastInst->getOpnd(POS_SWITCH_TABLE); + SwitchConstant *switchConstant = (SwitchConstant*) constantRef->getConstant(); + + // Find out which switch choice corresponds to fall through edge + uint16 throughChoice = switchConstant->getChoice(throughEdge); + + // Set imm representing fall through choice + troughTargetImm->setValue(throughChoice); + + // We do not need switch opnds in switch instruction any more. Remove them + lastInst->removeLastOpnd(); + lastInst->removeLastOpnd(); + lastInst->removeLastOpnd(); + lastInst->setInstCode(INST_BR); +} + +//----------------------------------------------------------------------------------------// + +void CodeLayouter::fixUnconditionalBranch(BbNode *node) { + + Edge* throughEdge = node->getOutEdge(EDGE_THROUGH); + if(throughEdge == NULL) { // there is no through edge - nothing to do + IPF_LOG << " there is no through edge" << endl; + return; + } + + // If through edge target coinsides with layout successor - do nothing + BbNode* target=(BbNode*) throughEdge->getTarget(); + if (target == (Node*) node->getLayoutSucc()) { + IPF_LOG << " through edge coinsides with layout successor" << endl; + return; + } + + // Add branch to through edge target + Opnd* p0 = cfg.getOpndManager()->getP0(); + NodeRef* targetNode = cfg.getOpndManager()->newNodeRef(target); + node->addInst(new(mm) Inst(INST_BR, p0, targetNode)); + + throughEdge->setEdgeKind(EDGE_BRANCH); +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfCodeSelector.cpp vm/jitrino/src/codegenerator/ipf/IpfCodeSelector.cpp new file mode 100755 index 0000000..7d7976a --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfCodeSelector.cpp @@ -0,0 +1,341 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfCodeSelector.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// IpfMethodCodeSelector +//========================================================================================// + +IpfMethodCodeSelector::IpfMethodCodeSelector(Cfg &cfg_, + CompilationInterface &compilationInterface_) : + mm(cfg_.getMM()), + cfg(cfg_), + compilationInterface(compilationInterface_) { + + methodDesc = NULL; +// codeProfiler = NULL; +} + +//----------------------------------------------------------------------------------------// + +void IpfMethodCodeSelector::genVars(uint32 numVars, VarCodeSelector &varCodeSelector) { + + IPF_LOG << endl << " Select variables" << endl; + IpfVarCodeSelector ipfVarCodeSelector(cfg, opnds); + varCodeSelector.genCode(ipfVarCodeSelector); +} + +//----------------------------------------------------------------------------------------// + +void IpfMethodCodeSelector::setMethodDesc(MethodDesc *methodDesc_) { + methodDesc = methodDesc_; +} + +//----------------------------------------------------------------------------------------// + +void IpfMethodCodeSelector::genCFG(uint32 numNodes, + CFGCodeSelector &codeSelector, + bool useProfile) { + + IPF_LOG << endl << " Select CFG" << endl; + IpfCfgCodeSelector cfgCodeSelector(cfg, nodes, opnds, compilationInterface); + codeSelector.genCode(cfgCodeSelector); +} + +//----------------------------------------------------------------------------------------// + +//void IpfMethodCodeSelector::setProfileInfo(CodeProfiler *codeProfiler_) { +// codeProfiler = codeProfiler_; +//} + +//----------------------------------------------------------------------------------------// + +MethodDesc *IpfMethodCodeSelector::getMethodDesc() { return methodDesc; } + +//========================================================================================// +// IpfVarCodeSelector +//========================================================================================// + +IpfVarCodeSelector::IpfVarCodeSelector(Cfg &cfg_, OpndVector &opnds_) : + mm(cfg_.getMM()), + cfg(cfg_), + opnds(opnds_) { + + opndManager = cfg.getOpndManager(); +} + +//----------------------------------------------------------------------------------------// + +uint32 IpfVarCodeSelector::defVar(Type *varType, bool isAddressTaken, bool isPinned) { + + OpndKind opndKind = IpfInstCodeSelector::toOpndKind(varType->tag); + DataKind dataKind = IpfInstCodeSelector::toDataKind(varType->tag); + RegOpnd *var = NULL; + + if (Type::isTau(varType->tag)) var = opndManager->getTau(); + else var = opndManager->newRegOpnd(opndKind, dataKind); + + opnds.push_back(var); + + IPF_LOG << " Define local variable" + << "; varType=" << Type::tag2str(varType->tag) + << ", isPinned=" << isPinned + << "; var='" << IrPrinter::toString(var) << "'" << endl; + + return opnds.size()-1; // It is going to be varId +} + +//----------------------------------------------------------------------------------------// + +void IpfVarCodeSelector::setManagedPointerBase(uint32 managedPtrVarNum, uint32 baseVarNum) {} + +//========================================================================================// +// IpfCfgCodeSelector +//========================================================================================// + +IpfCfgCodeSelector::IpfCfgCodeSelector(Cfg &cfg_, + NodeVector &nodes_, + OpndVector &opnds_, + CompilationInterface &compilationInterface_) : + mm(cfg_.getMM()), + cfg(cfg_), + nodes(nodes_), + opnds(opnds_), + compilationInterface(compilationInterface_) { +} + +//----------------------------------------------------------------------------------------// + +uint32 IpfCfgCodeSelector::genDispatchNode(uint32 numInEdges, + uint32 numOutEdges, + double cnt) { + + Node *node = new(mm) Node(cfg.getNextNodeId(), NODE_DISPATCH); + nodes.push_back(node); + + IPF_LOG << endl << " Generate Dispatch node" << node->getId() << endl; + return nodes.size()-1; +} + +//----------------------------------------------------------------------------------------// + +uint32 IpfCfgCodeSelector::genBlock(uint32 numInEdges, + uint32 numOutEdges, + BlockKind blockKind, + BlockCodeSelector& codeSelector, + double cnt) { + + BbNode *node = new(mm) BbNode(cfg.getNextNodeId(), (uint32)cnt); + + nodes.push_back(node); + if(blockKind == Prolog) cfg.setEnterNode(node); + + IPF_LOG << endl << " Generate BB node" << node->getId() << endl; + IpfInstCodeSelector ipfInstCodeSelector(cfg, *node, opnds, compilationInterface); + codeSelector.genCode(ipfInstCodeSelector); + + return nodes.size()-1; +} + +//----------------------------------------------------------------------------------------// + +uint32 IpfCfgCodeSelector::genUnwindNode(uint32 numInEdges, + uint32 numOutEdges, + double cnt) { + + Node *node = new(mm) Node(cfg.getNextNodeId(), NODE_UNWIND); + nodes.push_back(node); + + IPF_LOG << endl << " Generate Unwind node" << node->getId() << endl; + return nodes.size()-1; +} + +//----------------------------------------------------------------------------------------// + +uint32 IpfCfgCodeSelector::genExitNode(uint32 numInEdges, double cnt) { + + BbNode *node = new(mm) BbNode(cfg.getNextNodeId(), (uint32) cnt); + nodes.push_back(node); + cfg.setExitNode(node); + + IPF_LOG << endl << " Generate Exit node" << node->getId() << endl << endl; + return nodes.size()-1; +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genUnconditionalEdge(uint32 tailNodeId, + uint32 headNodeId, + double prob) { + + IPF_LOG << " Generate Unconditional edge node" << nodes[tailNodeId]->getId(); + IPF_LOG << " -> node" << nodes[headNodeId]->getId() << endl; + + Edge *edge = new(mm) Edge(nodes[tailNodeId], nodes[headNodeId], prob, EDGE_THROUGH); + cfg.addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genTrueEdge(uint32 tailNodeId, uint32 headNodeId, double prob) { + + IPF_LOG << " Generate True edge node" << nodes[tailNodeId]->getId(); + IPF_LOG << " -> node" << nodes[headNodeId]->getId() << endl; + + Edge *edge = new(mm) Edge(nodes[tailNodeId], nodes[headNodeId], prob, EDGE_BRANCH); + cfg.addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genFalseEdge(uint32 tailNodeId, uint32 headNodeId, double prob) { + + IPF_LOG << " Generate False edge node" << nodes[tailNodeId]->getId(); + IPF_LOG << " -> node" << nodes[headNodeId]->getId() << endl; + + Edge *edge = new(mm) Edge(nodes[tailNodeId], nodes[headNodeId], prob, EDGE_THROUGH); + cfg.addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genSwitchEdges(uint32 tailNodeId, + uint32 numTargets, + uint32 *targets, + double *probs, + uint32 defaultTarget) { + + BbNode *tailNode = (BbNode *)nodes[tailNodeId]; + InstVector &insts = tailNode->getInsts(); + Inst *switchInst = insts.back(); + Opnd *defTargetImm = switchInst->getOpnd(POS_SWITCH_DEFAULT); + ConstantRef *constantRef = (ConstantRef *) switchInst->getOpnd(POS_SWITCH_TABLE); + SwitchConstant *switchConstant = (SwitchConstant *)constantRef->getConstant(); + Edge *defedge = NULL; + Edge *edge = NULL; + + bool defadded = false; + uint32 i = 0; + + IPF_LOG << " Generate Switch tailNodeId=" << tailNodeId + << "; defaultTarget=" << defaultTarget << endl; + + defedge = new(mm) Edge(nodes[tailNodeId], nodes[defaultTarget], probs[defaultTarget], EDGE_BRANCH); + cfg.addEdge(defedge); + + for(i=0; i<numTargets; i++) { + if(targets[i] == defaultTarget) { + defTargetImm->setValue(i); + switchConstant->addEdge(defedge); + defadded = true; + IPF_LOG << " default: " << i << endl; + continue; + } + IPF_LOG << " case " << i << ": " << targets[i] << endl; + edge = new(mm) Edge(nodes[tailNodeId], nodes[targets[i]], probs[i], EDGE_BRANCH); + switchConstant->addEdge(edge); + cfg.addEdge(edge); + } + + if (!defadded) { + defTargetImm->setValue(i); + switchConstant->addEdge(defedge); + defadded = true; + IPF_LOG << " default: " << i << endl; + } +} + +//--------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genExceptionEdge(uint32 tailNodeId, + uint32 headNodeId, + double prob) { + + Node *tailNode = nodes[tailNodeId]; + Node *headNode = nodes[headNodeId]; + + IPF_LOG << " Generate Exception edge node" << tailNodeId; + IPF_LOG << " -> node" << headNodeId << endl; + cfg.addEdge(new(mm) Edge(tailNode, headNode, prob, EDGE_DISPATCH)); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genCatchEdge(uint32 tailNodeId, + uint32 headNodeId, + uint32 priority, + Type *exceptionType, + double prob) { + + Node *tailNode = nodes[tailNodeId]; + Node *headNode = nodes[headNodeId]; + + IPF_LOG << " Generate Catch edge node" << tailNode->getId(); + IPF_LOG << " -> node" << headNode->getId() << endl; + + ExceptionEdge *edge = new(mm) ExceptionEdge(tailNode, headNode, prob, exceptionType, priority); + cfg.addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::genExitEdge(uint32 tailNodeId, + uint32 headNodeId, + double prob) { + + Node *tailNode=nodes[tailNodeId]; + Node *headNode=nodes[headNodeId]; + + IPF_LOG << " Generate Exit edge node" << tailNode->getId(); + IPF_LOG << " -> node" << headNode->getId() << endl; + + Edge *edge = new(mm) Edge(tailNode, headNode, prob, EDGE_THROUGH); + cfg.addEdge(edge); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::setLoopInfo(uint32 nodeId, + bool isLoopHeader, + bool hasContainingLoopHeader, + uint32 headerId) { + + if (hasContainingLoopHeader == false) return; + + Node *node = nodes[nodeId]; + Node *header = nodes[headerId]; + + node->setLoopHeader(header); +} + +//----------------------------------------------------------------------------------------// + +void IpfCfgCodeSelector::setPersistentId(uint32 nodeId, uint32 persistentId) {} + +} //namespace IPF +} //namespace Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfDce.cpp vm/jitrino/src/codegenerator/ipf/IpfDce.cpp new file mode 100644 index 0000000..ad1c157 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfDce.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfDce.h" +#include "IpfIrPrinter.h" +#include "IpfOpndManager.h" +#include "IpfLiveAnalyzer.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Dce +//========================================================================================// + +void Dce::eliminate() { + + IPF_LOG << endl; + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); // get postordered node list + + for(uint16 i=0; i<nodes.size(); i++) { // iterate through nodes postorder + + currLiveSet.clear(); // clear live set + nodes[i]->mergeOutLiveSets(currLiveSet); // put in the live set merged live sets of successors + + IPF_LOG << " node" << nodes[i]->getId() << endl; +// IPF_LOG << " exit live set: " << IrPrinter::toString(currLiveSet) << endl; + + if(nodes[i]->getNodeKind() != NODE_BB) continue; // node does not contain insts - ignore + + InstVector &insts = ((BbNode *)nodes[i])->getInsts(); + InstIterator currInst = insts.end()-1; + InstIterator firstInst = insts.begin()-1; + + for(; currInst>firstInst;) { + + if (isInstDead(*currInst)) { + InstIterator inst = currInst--; + removeInst(insts, inst); + continue; + } + + LiveAnalyzer::updateLiveSet(currLiveSet, *currInst); + +// IPF_LOG << " " << left << setw(46) << IrPrinter::toString(*currInst) << endl; +// IPF_LOG << " live set : " << IrPrinter::toString(currLiveSet) << endl; + + currInst--; + } + } +} + +//----------------------------------------------------------------------------------------// +// Check if instruction can be removed from inst vector. +// Do not remove instruction having "side effects" (like "call") + +bool Dce::isInstDead(Inst *inst) { + + if (Encoder::isBranchCallInst(inst)) return false; // "call" inst is never dead + if (inst->getInstCode() == INST_ALLOC) return false; // "alloc" inst is never dead + + uint16 numDst = inst->getNumDst(); + if (numDst == 0) return false; // if there is no dst opnds - ignore + + OpndVector& opnds = inst->getOpnds(); // get inst opnds + + // If no one dst opnd is in Live Set - inst is dead + for (uint16 i=1; i<numDst+1; i++) { + RegOpnd *opnd = (RegOpnd *)opnds[i]; + if (currLiveSet.count(opnd) > 0) return false; + } + + return true; +} + +//----------------------------------------------------------------------------------------// +// Remove instruction from inst vector + +void Dce::removeInst(InstVector &insts, InstIterator inst) { + + IPF_LOG << " dead code - " << IrPrinter::toString(*inst) << endl; + insts.erase(inst); // remove instruction +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfEmitter.cpp vm/jitrino/src/codegenerator/ipf/IpfEmitter.cpp new file mode 100644 index 0000000..813d549 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfEmitter.cpp @@ -0,0 +1,1277 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "CodeGenIntfc.h" +#include "IpfEmitter.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" +#include "IpfVerifier.h" +#include <iomanip> + +#define SIGILL_BREAK_ACTION_HANDLER + +#ifdef SIGILL_BREAK_ACTION_HANDLER +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _REENTRANT +#include <signal.h> +#include <errno.h> +#include <ucontext.h> + +void __stdcall sighandler(int sn, siginfo_t *si, void *_sc) { + struct sigaction signal_action; + struct ucontext * signal_ucontext; + int saved_errno = errno; + + if (sn==SIGILL && si->si_code==ILL_BREAK && si->si_imm==INST_BREAKPOINT_IMM_VALUE) { + signal_ucontext = (struct ucontext *)_sc; + + if ( (signal_ucontext->_u._mc.sc_ip & 0x03)==2 ) { + signal_ucontext->_u._mc.sc_ip = (signal_ucontext->_u._mc.sc_ip & ~0x03) + 0x10; + } else { + signal_ucontext->_u._mc.sc_ip++; + } + //printf("-- sighandler() for signal %d, si_code %d, si_imm %x\n", sn, si->si_code, si->si_imm); + + signal_action.sa_flags = SA_SIGINFO; + signal_action.sa_sigaction = sighandler; + if (sigaction(SIGILL, &signal_action, NULL)) { + printf("Sigaction returned error = %d\n", errno); + } + } + + errno = saved_errno; + return; +} + +#endif + +namespace Jitrino { +namespace IPF { + +vector<char *> ipfCompileMethodList; +vector<char *> ipfNotCompileMethodList; +vector<char *> ipfBreakMethodList; +vector<int> ipfBreakBbList; +vector<char *> ipfLogoutMethodList; +bool ipfEnableSigillBreakActionHandler = false; +bool ipfEnableAutoSigillBreak = false; +bool ipfSigillBreakAllBB = false; +bool ipfNotifyWhenMethodIsRecompiled = true; +bool ipfCompileAllMethods = true; +int ipfSigillBreakCount = 0; +bool ipfLogoutAllMethods = false; +bool __IPF_ONLY__ = false; + +bool isIpfCompiled(MethodDesc* method) { return false; } +bool isIpfMethod(MethodDesc* method) { return false; } +bool isIpfBreakBb(unsigned int nodeid) { return false; } +bool isIpfBreakMethod(MethodDesc* method, bool recompile) { return false; } +bool isIpfLogoutMethod(MethodDesc* method) { return false; } + +//============================================================================// + +Bundle::Bundle(Cfg& cfg, uint32 itmp, Inst *i0, Inst *i1, Inst *i2) { + indxtmpl = itmp; // !!! THis is not template, but index in Emitter::BundleDesc[] !!! + + MemoryManager& mm = cfg.getMM(); + OpndManager* opndManager = cfg.getOpndManager(); + + // slot 0 + if( i0==NULL ) { + slot[0] = new(mm) Inst(INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE)); + } else { + slot[0] = i0; + } + + // slot 1 + if( i1==NULL ) { + slot[1] = new(mm) Inst(INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE)); + } else { + slot[1] = i1; + } + + // slot 2 + if( i2==NULL ) { + slot[2] = new(mm) Inst(INST_NOP, PR(0), IMM(INST_BREAKPOINT_IMM_VALUE)); + } else { + slot[2] = i2; + } +} + +uint32 Bundle::getTmpl() { return Emitter::BundleDesc[indxtmpl].tmpl; }; + +//============================================================================// +void Bundle::emitBundleGeneral(void *whereToEmit) { + uint64 * p = (uint64 *)whereToEmit; + uint64 s; + + p[0] = 0; + p[1] = 0; + + p[0] = getTmpl(); + + s = getSlotBits(0); + p[0] |= s << 5; + + s = getSlotBits(1); + p[0] |= s << 46; + p[1] = s >> 18; + + s = getSlotBits(2); + p[1] |= s << 23; +} + +void Bundle::emitBundleBranch(void *whereToEmit, int * bundletarget) { + uint64 * p = (uint64 *)whereToEmit; + uint64 s; + uint32 itmp = getTmpl(); + + p[0] = 0; + p[1] = 0; + + p[0] = itmp; + + if (itmp==0x16 || itmp==0x17) { + s = getSlotBitsBranch(0, bundletarget[0]); + } else { + s = getSlotBits(0); + } + p[0] |= s << 5; + + if (itmp>=0x12 && itmp<=0x17) { + s = getSlotBitsBranch(1, bundletarget[1]); + } else { + s = getSlotBits(1); + } + p[0] |= s << 46; + p[1] = s >> 18; + + if (itmp>=0x10) { + s = getSlotBitsBranch(2, bundletarget[2]); + } else { + s = getSlotBits(2); + } + p[1] |= s << 23; +} + +void Bundle::emitBundleExtended(void *whereToEmit) { + uint64 * p = (uint64 *)whereToEmit; + uint64 s; + uint64 s12[2]; + + p[0] = 0; + p[1] = 0; + + p[0] = getTmpl(); + + s = getSlotBits(0); + p[0] |= s << 5; + + getSlotBitsExtended(s12, whereToEmit); + p[0] |= s12[0] << 46; + p[1] = s12[0] >> 18; + p[1] |= s12[1] << 23; +} + +uint64 Bundle::getSlotBits(int slotindex) { + return Encoder::getInstBits(Emitter::getExecUnitType(indxtmpl, slotindex) + , slot[slotindex]); +} +uint64 Bundle::getSlotBitsBranch(int slotindex, int target) { + return Encoder::getInstBitsBranch(Emitter::getExecUnitType(indxtmpl, slotindex) + , slot[slotindex], target); +} +uint64 * Bundle::getSlotBitsExtended(uint64 *slots12, void *whereToEmit) { + return Encoder::getInstBitsExtended(slot[1], slots12, whereToEmit); +} + +//============================================================================// +void Bundle::print() { + Inst * inst = getSlot(0); + uint32 tmpl = getTmpl(); + + IPF_LOG << "(" << tmpl << ")\n"; + IPF_LOG << IrPrinter::toString(inst); + IPF_LOG << ( tmpl==0x0A || tmpl==0x0B ? " ;;" : "") + << "\n"; + inst = getSlot(1); + IPF_LOG << IrPrinter::toString(inst); + IPF_LOG << ( tmpl==0x02 || tmpl==0x03 ? " ;;" : "") + << "\n"; + inst = getSlot(2); + IPF_LOG << IrPrinter::toString(inst); + IPF_LOG << ( tmpl%2==1 ? " ;;" : "") + << "\n"; +} + +//============================================================================// +const BundleDescription Emitter::BundleDesc[TEMPLATES_COUNT] = { + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x0, 0x00 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x4, 0x01 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x2, 0x02 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_I), 0x6, 0x03 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_L) | IT_SLOT2(IT_X), 0x0, 0x04 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_L) | IT_SLOT2(IT_X), 0x4, 0x05 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x0, 0x08 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x4, 0x09 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x1, 0x0a }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_I), 0x5, 0x0b }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_I), 0x0, 0x0c }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_I), 0x4, 0x0d }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_F), 0x0, 0x0e }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_F), 0x4, 0x0f }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_B), 0x0, 0x10 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_I) | IT_SLOT2(IT_B), 0x4, 0x11 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x0, 0x12 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x4, 0x13 }, + { IT_SLOT0(IT_B) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x0, 0x16 }, + { IT_SLOT0(IT_B) | IT_SLOT1(IT_B) | IT_SLOT2(IT_B), 0x4, 0x17 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_B), 0x0, 0x18 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_M) | IT_SLOT2(IT_B), 0x4, 0x19 }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_B), 0x0, 0x1c }, + { IT_SLOT0(IT_M) | IT_SLOT1(IT_F) | IT_SLOT2(IT_B), 0x4, 0x1d } +}; + +//============================================================================// +EmitterBb::EmitterBb(Cfg & cfg, CompilationInterface & compilationinterface + , BbNode * node_, bool _setbreak) : + node(node_), + insts(node->getInsts()) +{ + MemoryManager& mm=cfg.getMM(); + OpndManager * opndManager = cfg.getOpndManager(); + Opnd * p0 = opndManager->getP0(); + + isize=insts.size(); + stops=new(mm) vectorbool(isize); + wregs=new(mm) vectorregs(isize); + rregs=new(mm) vectorregs(isize); + bundles=new(mm) BundleVector(cfg); + consts=new(mm) vectorconst; + bsize=0; + +// if (__IPF_ONLY__) return; TODO + if (!_setbreak) { + bundles->addBundle(0x01 + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))); + return; + } else { +#ifdef SIGILL_BREAK_ACTION_HANDLER + if (ipfEnableSigillBreakActionHandler) { + struct sigaction signal_action; + + signal_action.sa_flags = SA_SIGINFO; + signal_action.sa_sigaction = sighandler; + if (sigaction(SIGILL, &signal_action, NULL)) { + printf("Sigaction returned error = %d\n", errno); + } + + bundles->addBundle(0x01 + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_BREAK, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))); + } else { + bundles->addBundle(0x01 + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))); + } +#else + bundles->addBundle(0x01 + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE)) + , new(mm) Inst(INST_NOP, p0, IMM(INST_BREAKPOINT_IMM_VALUE))); +#endif + } + +}; + +//============================================================================// +int Emitter::removeUselessInst(Cfg & cfg, CompilationInterface & compilationinterface) { + BbNode * node = (BbNode *)cfg.getEnterNode(); + int methoduseless = 0; + int methodafter = 0; + + do { + InstVector &insts = node->getInsts(); + int i; + + for( i=0 ; i < (int)insts.size() ; i++ ) { + Inst *inst = insts[i]; + InstCode icode = inst->getInstCode(); + + if (icode==INST_MOV) { + if (inst->getNumOpnd()==3) { + OpndVector &opnds = inst->getOpnds(); + if (opnds[1]->isReg() && opnds[2]->isReg() + && opnds[1]->getValue()==opnds[2]->getValue()) { + LOG_OUT << "USELESS: " << IrPrinter::toString(inst) << "\n"; + insts.erase(insts.begin() + i); + methoduseless++; + continue; + } + } + } + + if (icode==INST_ADD || icode==INST_ADDS || icode==INST_ADDL) { + if (inst->getNumOpnd()==4) { + OpndVector &opnds = inst->getOpnds(); + if (opnds[2]->getValue()==0 + && opnds[1]->getValue()==opnds[3]->getValue()) { + LOG_OUT << "USELESS: " << IrPrinter::toString(inst) << "\n"; + insts.erase(insts.begin() + i); + methoduseless++; + continue; + } + } + } + } + methodafter += i; + } while( (node = node->getLayoutSucc()) != NULL ); + + /* statistical data */ + if (0 && (methoduseless > 0)) { + static int alluseless = 0; + static int allafter = 0; + alluseless += methoduseless; + clog << "USELESS: method: " << methoduseless + << "(" << (((float)methoduseless)/(methoduseless + methodafter)) << "%) instructions\n"; + clog << "USELESS: all: " << alluseless + << "(" << (((float)alluseless)/(alluseless + allafter)) << "%) instructions\n"; + } + + if (methoduseless > 0) { + LOG_OUT << "USELESS: removed " << methoduseless + << "(" << (((float)methoduseless)/(methoduseless + methodafter)) << "%) instructions\n"; + } + return methoduseless; +} + +//============================================================================// +Emitter::Emitter(Cfg & cfg_, CompilationInterface & compilationinterface_ + , bool break4cafe_) : + mm(cfg_.getMM()), + cfg(cfg_), + compilationinterface(compilationinterface_), + break4cafe(break4cafe_) { + + removeUselessInst(cfg, compilationinterface); + + (new(mm) IpfVerifier(cfg, compilationinterface))->verifyMethod(); + + bbs = new(mm) vectorbb; + BbNode * node = (BbNode *)cfg.getEnterNode(); + EmitterBb * bbdesc; + bool setbreak = ipfEnableAutoSigillBreak + || isIpfBreakMethod(compilationinterface.getMethodToCompile()); + + if (break4cafe_) setbreak = true; + + do { + // for debugging + // tricking(node->getInsts(), mm, cfg); + + if (isIpfBreakBb(node->getId())) { + bbdesc = new(mm) EmitterBb(cfg, compilationinterface, node, true); + } else { + bbdesc = new(mm) EmitterBb(cfg, compilationinterface, node, setbreak); + } + bbs->push_back(bbdesc); + if (!ipfSigillBreakAllBB) setbreak = false; + } while( (node = node->getLayoutSucc()) != NULL ); + +}; + +//============================================================================// +InstructionType Emitter::getExecUnitType(int templateindex, int slotindex) { + return (InstructionType)((Emitter::BundleDesc[templateindex].slots >> (slotindex * 8)) & 0xFF); +} + +//============================================================================// +void Emitter::getTmpl(int bbindex, BundleDescription & tmp, Inst *i0, Inst *i1, Inst *i2, bool s0, bool s1, bool s2) { + if(i0!=NULL) { + tmp.slots = IT_SLOT0(Encoder::getInstType(i0)); + } else { + tmp.slots = IT_SLOT0(IT_ANY); + } + tmp.stops = (s0 ? 1 : 0); + + if(i1!=NULL) { + tmp.slots |= IT_SLOT1(Encoder::getInstType(i1)); + } else { + tmp.slots |= IT_SLOT1(IT_ANY); + } + tmp.stops |= (s1 ? 2 : 0); + + if( i2!=NULL ) { + tmp.slots |= IT_SLOT2(Encoder::getInstType(i2)); + } else { + tmp.slots |= IT_SLOT2(IT_ANY); + } + tmp.stops |= (s2 ? 4 : 0); +} + +int Emitter::findTmpl(const BundleDescription & tmp) { + for( int j=0 ; j<TEMPLATES_COUNT ; j++ ) { + if( (BundleDesc[j].slots & tmp.slots)==BundleDesc[j].slots + && (BundleDesc[j].stops & tmp.stops)==tmp.stops ) { + return j; + } + } + return -1; +} + +//============================================================================// +void Emitter::getWriteDpndBitset(Inst * inst, RegistersBitset * regs) +{ + OpndVector & opnds = inst->getOpnds(); + if(opnds.size() <= 1) return; + + uint32 dstcount=inst->getNumDst(); + Opnd *opnd; + + for( uint32 i=0 ; i<dstcount ; i++ ) { + opnd = opnds[i+1]; + switch (opnd->getOpndKind()) { + case OPND_G_REG: + regs->GR.set(opnd->getValue()); + break; + case OPND_F_REG: + regs->FR.set(opnd->getValue()); + break; + case OPND_P_REG: + regs->PR.set(opnd->getValue()); + break; + case OPND_B_REG: + regs->BR.set(opnd->getValue()); + break; + default: + break; + } + } +} + +//============================================================================// +void Emitter::getReadDpndBitset(Inst * inst, RegistersBitset * regs) +{ + OpndVector & opnds = inst->getOpnds(); + if(opnds.size() <= 1) return; + + uint32 dstcount=inst->getNumDst(); + uint32 opndcount=inst->getNumOpnd(); + Opnd *opnd; + + for( uint32 i=1+dstcount ; i<opndcount ; i++ ) { + opnd = opnds[i]; + switch (opnd->getOpndKind()) { + case OPND_G_REG: + regs->GR.set(opnd->getValue()); + break; + case OPND_F_REG: + regs->FR.set(opnd->getValue()); + break; + case OPND_P_REG: + regs->PR.set(opnd->getValue()); + break; + case OPND_B_REG: + regs->BR.set(opnd->getValue()); + break; + default: + break; + } + } + int p=opnds[0]->getValue(); + if( p ) { + regs->PR.set(p); + } +} + +//============================================================================// +bool Emitter::tricking(InstVector & insts, MemoryManager& mm, Cfg& cfg) { + RegistersBitset * regs; + Inst *inst; + + for( int i=0 ; i < (int)insts.size() ; i++ ) { + inst = insts[i]; + // regs masks + regs = new(mm) RegistersBitset(); + getWriteDpndBitset(inst, regs); + if (regs->GR.test(33)) { + OpndManager * opndManager = cfg.getOpndManager(); + insts.insert(insts.begin() + i + , new(mm) Inst(INST_BREAK, opndManager->getP0(), opndManager->newImm(INST_BREAKPOINT_IMM_VALUE))); + i++; + } + } + return true; +} + +//============================================================================// +bool Emitter::parsing() { + bool ret = true; + + datasize = 0; + for (int bbindex=0, bbssize=(int)bbs->size() ; bbindex<bbssize ; bbindex++) { + ret &= parsing(bbindex); + } + + return ret; +} + +bool Emitter::parsing(int bbindex) { + EmitterBb * bb = bbs->at(bbindex); + InstVector & insts = bb->insts; + vectorregs * wr = bb->wregs; + vectorregs * rr = bb->rregs; + Inst *inst; + RegistersBitset * regs; + uint32 dstcount; + uint32 opndcount; + Opnd * opnd; + vectorconst * consts = bb->consts; + Constant * constant; + + for( int i=0 ; i < (int)insts.size() ; i++ ) { + inst = insts[i]; + InstCode instCode = inst->getInstCode(); + OpndVector & opnds = inst->getOpnds(); + + if (instCode==INST_BR13 || instCode==INST_BRL13) { + instCode = (instCode == INST_BR13 ? INST_BR : INST_BRL); + } + + // regs masks + regs = new(mm) RegistersBitset(); + getWriteDpndBitset(inst, regs); + wr->at(i) = regs; + + regs = new(mm) RegistersBitset(); + getReadDpndBitset(inst, regs); + rr->at(i) = regs; + + // constants + dstcount=inst->getNumDst(); + opndcount=inst->getNumOpnd(); + + for( uint32 j=1 ; j<opndcount ; j++ ) { + opnd = opnds[j]; + if (opnd->isImm()) { + if ( opnd->getDataKind() == DATA_CONST_REF) { + constant = ((ConstantRef *)opnd)->getConstant(); + consts->push_back(opnd); + datasize += constant->getSize(); + } else if ( opnd->getDataKind() == DATA_SWITCH_REF) { + constant = ((ConstantRef *)opnd)->getConstant(); + consts->push_back(opnd); + datasize += ((SwitchConstant *)constant)->getSize(); + } + } + } + } + + return true; +} +//============================================================================// +bool Emitter::stopping() { + bool ret = true; + + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + ret &= stopping(bbindex); + } + + return ret; +} + +bool Emitter::stopping(int bbindex) { + EmitterBb * bb = bbs->at(bbindex); + InstVector & insts = bb->insts; + long sizebb = insts.size(); + if (sizebb==0) return true; + + vectorbool * stops = bb->stops; + vectorregs * wr = bb->wregs; + vectorregs * rr = bb->rregs; + Inst *inst1, *inst2; + InstCode icode1, icode2; + RegistersBitset * regs1w, * regs2w, * regs2r; + long start, stop, hardstop; + + for( start=0, stop=sizebb ; start < (sizebb - 1) ; ) { + hardstop = -1; + for (long i = start; i < (stop-1) ; i++) { + inst1 = insts[i]; + icode1 = inst1->getInstCode(); + if (icode1==INST_BRL || icode1==INST_BRL13) { + hardstop=i; + break; + } else if (icode1 == INST_ALLOC) { + if (i>0) stops->at(i-1) = true; + } + if (Encoder::isIgnoreInst(inst1)) continue; + if (icode1 >= INST_ST_FIRST && icode1 <= INST_ST_LAST) continue; + + regs1w = wr->at(i); + if(!regs1w->any()) continue; + + for (long j = i + 1; j < stop; j++) { + inst2 = insts[j]; + icode2 = inst2->getInstCode(); + if (icode2 == INST_ALLOC) { + if (j>0) stops->at(j-1) = true; + } + if (Encoder::isIgnoreInst(inst2)) continue; + + regs2w = wr->at(j); + regs2r = rr->at(j); + if(!regs2w->any() && !regs2r->any()) continue; + + if( (regs1w->GR & (regs2w->GR | regs2r->GR)).any() + || (regs1w->FR & (regs2w->FR | regs2r->FR)).any() + || (regs1w->PR & (regs2w->PR | regs2r->PR)).any() + || (regs1w->BR & (regs2w->BR | regs2r->BR)).any() ) { + stop=j; + break; + } + } + } + if (hardstop>=0) { + stops->at(hardstop) = true; + start=hardstop+1; + stop=sizebb; + } else if( stop==sizebb ) { + start++; + } else { + stops->at(stop-1) = true; + start=stop; + stop=sizebb; + } + } + stops->at(stops->size()-1) = true; + + return true; +} + +//============================================================================// +bool Emitter::bundling() { + EmitterBb * bb; + char * off=0; + bool ret = true; + + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + ret &= bundling(bbindex); + bb = bbs->at(bbindex); + bb->bsize = bb->bundles->size(); + bb->codeoff = off; + bb->codesize = bb->bsize * IPF_BUNDLE_SIZE; + off = (char *)off + bb->codesize; + } + codesize = (long)((char *)off); + + return ret; +} +bool Emitter::bundling(int bbindex) { + EmitterBb * bb = bbs->at(bbindex); + InstVector & insts = bb->insts; + long sizebb = insts.size(); + if (sizebb==0) return true; + + vectorbool * stops = bb->stops; + BundleVector * bundles = bb->bundles; + BundleDescription tmp = {0,0,0}; + int iTmpl=-1; + Inst * inst0=NULL, * inst1=NULL, * inst2=NULL; + bool stop0=false, stop1=false, stop2=false; + bool stop0_f=false, stop1_f=false, stop2_f=false; // inst is first in group + bool stop0_l=false, stop1_l=false, stop2_l=false; // inst is last in group + int it0=0, it1=0, it2=0; // insts type + long i0, i1, i2; + + for ( i0=0 ; i0 < sizebb ; ) { + inst0=Encoder::resolvePseudo(cfg, insts[i0]); + if (Encoder::isIgnoreInst(inst0)) { i0++; continue; } + stop0=stops->at(i0); + + for ( i1=i0+1 ; i1<sizebb ; ) { + inst1=Encoder::resolvePseudo(cfg, insts[i1]); + if (Encoder::isIgnoreInst(inst1)) { i1++; continue; } + stop1=stops->at(i1); + break; + } + if ( i1 >= sizebb ) { inst1=NULL; } + + for ( i2=i1+1 ; i2<sizebb ; ) { + inst2=Encoder::resolvePseudo(cfg, insts[i2]); + if (Encoder::isIgnoreInst(inst2)) { i2++; continue; } + stop2=stops->at(i2); + break; + } + if ( i2 >= sizebb ) { inst2=NULL; } + + it0 = Encoder::getInstType(inst0); + it1 = Encoder::getInstType(inst1); + it2 = Encoder::getInstType(inst2); + + stop0_l = (it0 & IT_GL)==IT_GL; + stop1_l = (it1 & IT_GL)==IT_GL; + stop2_l = (it2 & IT_GL)==IT_GL; + stop0_f = (it0 & IT_GF)==IT_GF; + stop1_f = (it1 & IT_GF)==IT_GF; + stop2_f = (it2 & IT_GF)==IT_GF; + + // Special case for br.call + // br.ret will return to next bundle, so + // all instructions after br.call must be nop + if (inst0->getInstCode()==INST_BR || inst0->getInstCode()==INST_BR13) { + CompVector & cmpls0 = inst0->getComps(); + if (cmpls0.size()>0 && cmpls0[0]==CMPLT_BTYPE_CALL) { + inst1=NULL; + inst2=NULL; + } + } else if (inst1!=NULL && (inst1->getInstCode()==INST_BR || inst1->getInstCode()==INST_BR13)) { + CompVector & cmpls1 = inst1->getComps(); + if (cmpls1.size()>0 && cmpls1[0]==CMPLT_BTYPE_CALL) { + inst2=NULL; + } + } + + if (inst1!=NULL && inst2!=NULL) { + getTmpl(bbindex, tmp, inst0, inst1, inst2 + , stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f, stop2 || stop2_l); + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, inst0, inst1, inst2); + i0 = i2 + 1; + continue; + } + } + + if (inst1!=NULL) { + getTmpl(bbindex, tmp, inst0, NULL, inst1 + , stop0 || stop0_l, stop1_f, stop1 || stop1_l || stop2_f); + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, inst0, NULL, inst1); + i0 = i1 + 1; + continue; + } + + if ( inst1!=NULL && Encoder::getInstType(inst1->getInstCode()) & IT_L ) { + getTmpl(bbindex, tmp, inst0, inst1, NULL + , stop0 || stop0_l || stop1_f, false, stop1 || stop1_l || stop2_f); + } else { + getTmpl(bbindex, tmp, inst0, inst1, NULL + , stop0 || stop0_l || stop1_f, stop1 || stop1_l, stop2_f); + } + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, inst0, inst1, NULL); + i0 = i1 + 1; + continue; + } + + getTmpl(bbindex, tmp, NULL, inst0, inst1 + , stop0_f, stop0 || stop0_l || stop1_f, stop1 || stop1_l || stop2_f); + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, NULL,inst0, inst1); + i0 = i1 + 1; + continue; + } + } + + getTmpl(bbindex, tmp, inst0, NULL, NULL + , stop0 || stop0_l, false, stop1_f); + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, inst0, NULL, NULL); + i0 += 1; + continue; + } + + if ( Encoder::getInstType(inst0->getInstCode()) & IT_L ) { + getTmpl(bbindex, tmp, NULL, inst0, NULL + , false, false, stop0 || stop0_l || stop1_f); + } else { + getTmpl(bbindex, tmp, NULL, inst0, NULL + , stop0_f, stop0 || stop0_l, stop1_f); + } + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, NULL, inst0, NULL); + i0 += 1; + continue; + } + + getTmpl(bbindex, tmp, NULL, NULL, inst0 + , false, stop0_f, stop0 || stop0_l || stop1_f); + iTmpl=findTmpl(tmp); + if( iTmpl>=0 ) { + bundles->addBundle(iTmpl, NULL, NULL, inst0); + i0 += 1; + continue; + } + + IPF_ERR << "ERROR: CAN'T FIND TEMPLATE !!!\n"; + IPF_ASSERT(0); + + i0++; + } + + return true; +} + +//============================================================================// +bool Emitter::emitData() { + if (datasize==0) return true; + + bool ret = true; + EmitterBb * bb; + char * p; + Opnd * opnd; + + dataoff = (char *)compilationinterface.allocateDataBlock(datasize + , L2_CACHE_BANK_SIZE); + assert(dataoff != NULL); + if ( dataoff == NULL ) return false; + + p = dataoff; + + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + bb = bbs->at(bbindex); + for ( int i=0, ii=bb->consts->size() ; i < ii ; i++ ) { + opnd = bb->consts->at(i); + if (opnd->isImm()) { + if ( opnd->getDataKind() == DATA_CONST_REF) { + Constant * c; + + c = ((ConstantRef *)opnd)->getConstant(); + switch (c->getDataKind()) { + case DATA_I64: + *((int64 *)p) = ((Int64Constant *)c)->getValue(); + c->setAddress(p); + p = (char *)(++((int64 *)p)); + break; + case DATA_S: + *((float *)p) = ((FloatConstant *)c)->getValue(); + c->setAddress(p); + p = (char *)(++((float *)p)); + break; + case DATA_D: + *((double *)p) = ((DoubleConstant *)c)->getValue(); + c->setAddress(p); + p = (char *)(++((double *)p)); + break; + default: + IPF_ERR << "DATA UNKNOWN\n"; + break; + } + } else if ( opnd->getDataKind() == DATA_SWITCH_REF) { + SwitchConstant * c; + + c = (SwitchConstant *)((ConstantRef *)opnd)->getConstant(); + *((uint64 *)p) = (uint64)opnd; // need to fill with actual + // values of node's addresses + // after code emitting! + c->setAddress(p); + p += c->getSize(); + } + } else { + IPF_LOG << "DATA UNKNOWN\n"; + assert(0); + } + } + } + + return ret; +} + +//============================================================================// +bool Emitter::fixSwitchTables() { + if ( datasize==0 ) return true; + if ( dataoff == NULL ) return true; + + bool ret = true; + EmitterBb * bb; + void * p; + Opnd * opnd; + SwitchConstant * c; + Node * node; + Edge * edge; + + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + bb = bbs->at(bbindex); + for ( int i=0, ii=bb->consts->size() ; i < ii ; i++ ) { + opnd = bb->consts->at(i); + if (opnd->isImm() && opnd->getDataKind()==DATA_SWITCH_REF) { + c = (SwitchConstant *)((ConstantRef *)opnd)->getConstant(); + p = c->getAddress(); + for (int j=0, jj=c->getChoiceCount() ; j<jj ; j++) { + edge = c->getEdge(j); + node = edge->getTarget(); + *((uint64 *)p) = (uint64)(codeoff + (int64)getBbNodeOff((BbNode *)node)); + p = (uint64 *)p +1; + } + } + } + } + + return ret; +} + +//============================================================================// +bool Emitter::emitCode() { + EmitterBb *bb; + BundleVector * bundles; + Bundle * bundle; + int target[3]; + char *bboff = 0; + char *off = 0; + Inst *inst; + + codeoff = (char *)compilationinterface.allocateCodeBlock( + codesize, IPF_CODE_ALIGNMENT, CompilationInterface::CodeBlockHeatDefault, 0, false); + assert(codeoff != NULL); + IPF_LOG << endl; + if ( codeoff ) { + off=codeoff; + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + bb = bbs->at(bbindex); + // sa + bb->node->setAddress((uint64)off); + bboff = off; + bundles = bb->bundles; + for(int i=0, ii=(int)bundles->size() ; i<ii ; i++ ) { + bundle = bundles->at(i); + for (uint32 si=0 ; si < IPF_SLOTS_COUNT ; si++) { + inst = bundle->getSlot(si); + inst->setAddr((uint32)(off - bboff) + si); + } + + if ( isBranchBundle(bundle, codeoff, off, target) ) { + // bundle contains B type inst + bundle->emitBundleBranch(off, target); + } else if ( isExtendedBundle(bundle) ) { + // bundle contains L+X type inst + bundle->emitBundleExtended(off); + + inst = bundle->getSlot(1); + InstCode icode = inst->getInstCode(); + unsigned int is13 = (icode==INST_BRL13 ? 1 : 0); // must be 1 or 0 + if ((icode==INST_BRL || icode==INST_BRL13) + && (inst->getComps())[0]==CMPLT_BTYPE_CALL + && (inst->getOpnds()[is13 + 2])->getDataKind()==DATA_METHOD_REF) { + if (((((uint64)off) | (((uint64)0x4cafe) << 32)) & ~((uint64)0x4cafe << 32))==(uint64)off) { + registerDirectCall(inst, ((uint64)off) | (((uint64)0x4cafe) << 32)); + } else { + IPF_ERR << "\n"; + assert(0); + } + } + } else { + bundle->emitBundleGeneral(off); + } + off = off + IPF_BUNDLE_SIZE; + } + } + IPF_LOG << "END code emitting: " + << compilationinterface.getMethodToCompile()->getParentType()->getName() + << "." << compilationinterface.getMethodToCompile()->getName() + << compilationinterface.getMethodToCompile()->getSignatureString() + << endl; + + return true; + } + return false; +} + +bool Emitter::isBranchBundle(Bundle * bundle, char * baseoff, char * bundleoff, int * branchtargets) { + bool ret = false; + + if ( bundle->getTmpl() > 15 ) { + Inst * inst; + Opnd * opnd; + InstCode icode; + unsigned int is13; // must be 1 or 0 + + for (int i=0 ; i<3 ; i++ ) { + branchtargets[i] = 0; + inst = bundle->getSlot(i); + if(Encoder::isBranchInst(inst)) { + icode = inst->getInstCode(); + is13 = (icode==INST_BRL13 || icode==INST_BR13 ? 1 : 0); // must be 1 or 0 + ret = true; + opnd = inst->getOpnd(is13 + 1); + if (opnd->getDataKind() == DATA_NODE_REF) { + branchtargets[i] = (long)getBbNodeOff(((NodeRef*) opnd)->getNode()) - (long)(bundleoff - baseoff); + } + } + } + } + return ret; +} + +char * Emitter::getBbNodeOff(BbNode * node) { + for (int i=0 ; i<(int)bbs->size() ; i++) { + if (bbs->at(i)->node == node) { + return bbs->at(i)->codeoff; + } + } + return (char *)-1; +} + +bool Emitter::emit() { + bool ret = true; + + // 0 pass: parsing insts + // - clear ignored insts + // - define registers read/write masks + // - create vector of constants + // - create vector of brunches + ret &= parsing(); + if (!ret) { IPF_ERR << "Bad results for parsing\n"; return ret; } + + // 1 pass: emit data + ret &= emitData(); + if (!ret) { IPF_ERR << "Bad results for emitData\n"; return ret; } + + // 2 pass: define stops + ret &= stopping(); + if (!ret) { IPF_ERR << "Bad results for stopping\n"; return ret; } + + // 3 pass: bundling instructions (also saving indexes of bundles with branch insts) + ret &= bundling(); + if (!ret) { IPF_ERR << "Bad results for bundling\n"; return ret; } + + // 4 pass: emits bundles + ret &= emitCode(); + if (!ret) { IPF_ERR << "Bad results for emitCode\n"; return ret; } + + // 5 pass: fix switch tables + ret = fixSwitchTables(); + if (!ret) { IPF_ERR << "Bad results for fixSwitchTables\n"; return ret; } + + if (LOG_ON) { +// printInsts(" Result of stopping() "); +// printBundles(" Result of bundling() "); + //printCodeBlock(" Result of emitting() "); + printDisasm(" Result of emitting(disasm) "); + } + + return ret; +} + +void Emitter::printBundles(char * cap) { + if (LOG_ON) { + IPF_LOG << "-----------" << cap << "-----------------------------\n"; + for (int i=0 ; i<(int)bbs->size() ; i++) { + printBundles(i); + } + IPF_LOG << "\n"; + } +} + +void Emitter::printBundles(int bbindex) { + BundleVector * bundles = bbs->at(bbindex)->bundles; + Bundle * bndl; + + IPF_LOG << ".L" << bbs->at(bbindex)->node->getId() + << " (0x" << hex << bbs->at(bbindex)->node->getAddress() << dec << ")\n"; + for (long i = 0, ii=bundles->size() ; i < ii ; i++) { + bndl = bundles->at(i); + if( bndl==NULL ) { + IPF_LOG << i; + IPF_LOG << " \tNULL\n" + << " \tNULL\n" + << " \tNULL\n"; + IPF_LOG << "\n"; + } else { + IPF_LOG << i; + bndl->print(); + IPF_LOG << "\n"; + } + } +} + +void Emitter::printInsts(char *cap) { + IPF_LOG << "\n-----------" << cap << "-----------------------------\n"; + for (int i=0 ; i<(int)bbs->size() ; i++) { + printInsts(i); + } + IPF_LOG << "\n"; +} + +void Emitter::printInsts(int bbindex) { + InstVector & insts = bbs->at(bbindex)->insts; + vectorbool * stops = bbs->at(bbindex)->stops; + Inst *inst; + + IPF_LOG << ".L" << bbs->at(bbindex)->node->getId() << "\n"; + for (uint32 i = 0, ii=insts.size() ; i < ii ; i++) { + inst = insts[i]; + if( inst==NULL ) { + IPF_LOG << IrPrinter::toString(inst); + } else { + IPF_LOG << IrPrinter::toString(inst); + IPF_LOG << (stops->at(i) ? " ;;" : ""); + } + IPF_LOG << "\n"; + } +} + +void Emitter::printCodeBlock(char * cap) { + char printbuf[256]; + char * off = codeoff; + uint64 * p, tmpl, i0, i1, i2; + + IPF_LOG << "\n-----------" << cap << "-----------------------------\n"; + sprintf(printbuf, "%-11.11s %-11.11s %-11.11s %-8.8s\n", "slot2", "slot1", "slot0", "template"); + IPF_LOG << printbuf; + for(int i=0 ; i<codesize; i += IPF_BUNDLE_SIZE) { + p = (uint64 *)off; + + tmpl = p[0] & 0x1F; + i0 = (p[0] & 0x3FFFFFFFFFE0) >> 5; + i1 = (((p[0] & ~0x1F) & ~0x3FFFFFFFFFE0) >> 46) | ((p[1] & 0x7FFFFF) << 18); + i2 = (p[1] & ~0x7FFFFF) >> 23; + + sprintf(printbuf, "%11.11llx %11.11llx %11.11llx %2.2x \n", i2, i1, i0, (unsigned)tmpl); + IPF_LOG << printbuf; + off += IPF_BUNDLE_SIZE; + } + IPF_LOG << "---------------------------------------------------\n"; +} + +void Emitter::registerDirectCall(Inst * inst, uint64 data) +{ + if (!ipfNotifyWhenMethodIsRecompiled) return; + + InstCode icode = inst->getInstCode(); + unsigned int is13 = (icode==INST_BRL13 ? 1 : 0); // must be 1 or 0 + + assert((icode==INST_BRL || icode==INST_BRL13) + && (inst->getComps())[0]==CMPLT_BTYPE_CALL); + Opnd * target = (inst->getOpnds())[is13 + 2]; + assert(target->isImm() && target->getDataKind()==DATA_METHOD_REF); + MethodDesc * method = ((MethodRef *)target)->getMethod(); + + compilationinterface.setNotifyWhenMethodIsRecompiled(method, (void *)data); + if (LOG_ON) { + IPF_LOG << "Registered call to " << method->getParentType()->getName() + << "." << method->getName() + << " : data=0x" << hex << data << dec + << " for recompiled method event" << endl; + } +} + +#include <dlfcn.h> +#include <libgen.h> + +void Emitter::printDisasm(char * cap) { + static bool load_done = false; + static unsigned (*disasm)(const char *, char *, unsigned) = NULL; + + if (!load_done) { + char buf[PATH_MAX+1]; + + // Resolve full path to module + string sz(""); + int len = 0; + + len = readlink("/proc/self/exe", buf, sizeof(buf)); + if (len < 0) { + buf[0]='.'; + buf[1]='/'; + buf[2]='\0'; + } else { + buf[len] = 0; + } + char * slash = strrchr(buf, '/'); + if (slash) { + *(slash) = '\0'; + } + + sz.append(buf); + sz.append("/libdisasm.so"); + std::cout << "Loading `" << sz << "'..."; + + char * path = strdup(sz.c_str()); + void * handle = dlopen(path, RTLD_NOW); + free(path); + disasm = (unsigned (*)(const char *, char *, unsigned)) + (handle == NULL ? NULL : dlsym(handle, "disasm")); + load_done = true; + + if (disasm==NULL) { + std::cout << "CAN'T LOAD" << std::endl; + return; + } else { + std::cout << "OK" << std::endl; + } + } + if (disasm==NULL) { + return; + } + + string str(""); + char buf[100]; + char * off = codeoff; + + for (unsigned i=0 ; i<codesize ; off=codeoff+i) { + unsigned l = disasm((const char*)off, buf, sizeof(buf)-1); + + for (int bbindex=0 ; bbindex<(int)bbs->size() ; bbindex++) { + EmitterBb *bb = bbs->at(bbindex); + char * bboff = (char *)bb->node->getAddress(); + + if (bboff==off) { + char bbid[64]; + + sprintf(bbid, "%i (%p)", (int)bb->node->getId(), bboff); + str.append("\n.L"); + str.append(bbid); + break; + } + } + if (buf[0]=='[') { + str.append("\n"); + buf[5] = '\0'; + str.append(buf); + str.append("\n "); + str.append(buf + 6); + str.append("\n"); + } else { + str.append(buf); + str.append("\n"); + } + i += l; + } + + IPF_LOG << endl << "-----------" << cap << "-----------------------" << endl; + IPF_LOG << str; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfEncoder.cpp vm/jitrino/src/codegenerator/ipf/IpfEncoder.cpp new file mode 100644 index 0000000..be4afa7 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfEncoder.cpp @@ -0,0 +1,1702 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfEncoder.h" +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// InstDescription initialization +//========================================================================================// + +const InstDescription Encoder::instDesc[] = { + {"add" , INST_ADD , 1, 4, IT_A}, + {"adds" , INST_ADDS , 1, 4, IT_A}, + {"addl" , INST_ADDL , 1, 4, IT_A}, + {"addp4" , INST_ADDP4 , 1, 4, IT_A}, + {"alloc" , INST_ALLOC , 1, 6, IT_M | IT_GF}, + {"and" , INST_AND , 1, 4, IT_A}, + {"andcm" , INST_ANDCM , 1, 4, IT_A}, + {"br" , INST_BR , 0, 2, IT_B}, + {"brl" , INST_BRL , 0, 2, IT_L | IT_GL}, + {"brp" , INST_BRP , 0, 3, IT_B}, + {"brp.ret" , INST_BRP_RET , 0, 3, IT_B}, + {"break" , INST_BREAK , 0, 2, IT_ANY | IT_EXPLICIT_IMBFX }, + {"bsw.0" , INST_BSW_0 , 0, 1, IT_B}, + {"bsw.1" , INST_BSW_1 , 0, 1, IT_B}, + {"chk.s" , INST_CHK_S , 0, 3, IT_EXPLICIT_IM }, + {"chk.s.i" , INST_CHK_S_I , 0, 3, IT_I }, + {"chk.s.m" , INST_CHK_S_M , 0, 3, IT_M }, + {"chk.a" , INST_CHK_A , 0, 3, IT_M}, + {"clrrrb" , INST_CLRRRB , 0, 1, IT_B}, + {"clrrrb.pr" , INST_CLRRRB_PR , 0, 1, IT_B}, + {"cmp" , INST_CMP , 2, 5, IT_A}, + {"cmp4" , INST_CMP4 , 2, 5, IT_A}, + {"cmpxchg" , INST_CMPXCHG , 1, 4, IT_M}, + {"cmp8xchg16" , INST_CMP8XCHG16 , 1, 4, IT_M}, + {"cover" , INST_COVER , 0, 1, IT_B}, + {"czx1.l" , INST_CZX1_L , 1, 3, IT_I}, + {"czx1.r" , INST_CZX1_R , 1, 3, IT_I}, + {"czx2.l" , INST_CZX2_L , 1, 3, IT_I}, + {"czx2.r" , INST_CZX2_R , 1, 3, IT_I}, + {"dep" , INST_DEP , 1, 6, IT_I}, + {"dep.z" , INST_DEP_Z , 1, 5, IT_I}, + {"epc" , INST_EPC , 0, 1, IT_B}, + {"extr" , INST_EXTR , 1, 5, IT_I}, + {"extr.u" , INST_EXTR_U , 1, 5, IT_I}, + {"fabs" , INST_FABS , 1, 3, IT_F}, + {"fadd" , INST_FADD , 1, 4, IT_F}, + {"famax" , INST_FAMAX , 1, 4, IT_F}, + {"famin" , INST_FAMIN , 1, 4, IT_F}, + {"fand" , INST_FAND , 1, 4, IT_F}, + {"fandcm" , INST_FANDCM , 1, 4, IT_F}, + {"fc" , INST_FC , 0, 2, IT_M}, + {"fc.i" , INST_FC_I , 0, 2, IT_M}, + {"fchkf" , INST_FCHKF , 0, 2, IT_F}, + {"fclass" , INST_FCLASS , 2, 5, IT_F}, + {"fclrf" , INST_FCLRF , 0, 1, IT_F}, + {"fcmp" , INST_FCMP , 2, 5, IT_F}, + {"fcvt.fx" , INST_FCVT_FX , 1, 3, IT_F}, + {"fcvt.fx.trunc" , INST_FCVT_FX_TRUNC , 1, 3, IT_F}, + {"fcvt.fxu" , INST_FCVT_FXU , 1, 3, IT_F}, + {"fcvt.fxu.trunc" , INST_FCVT_FXU_TRUNC , 1, 3, IT_F}, + {"fcvt.xf" , INST_FCVT_XF , 1, 3, IT_F}, + {"fcvt.xuf" , INST_FCVT_XUF , 1, 3, IT_F}, + {"fetchadd4" , INST_FETCHADD4 , 1, 4, IT_M}, + {"fetchadd8" , INST_FETCHADD8 , 1, 4, IT_M}, + {"flushrs" , INST_FLUSHRS , 0, 1, IT_M}, + {"fma" , INST_FMA , 1, 5, IT_F}, + {"fmax" , INST_FMAX , 1, 4, IT_F}, + {"fmerge.ns" , INST_FMERGE_NS , 1, 4, IT_F}, + {"fmerge.s" , INST_FMERGE_S , 1, 4, IT_F}, + {"fmerge.se" , INST_FMERGE_SE , 1, 4, IT_F}, + {"fmin" , INST_FMIN , 1, 4, IT_F}, + {"fmix.l" , INST_FMIX_L , 1, 4, IT_F}, + {"fmix.r" , INST_FMIX_R , 1, 4, IT_F}, + {"fmix.lr" , INST_FMIX_LR , 1, 4, IT_F}, + {"fmpy" , INST_FMPY , 1, 4, IT_F}, + {"fms" , INST_FMS , 1, 5, IT_F}, + {"fneg" , INST_FNEG , 1, 3, IT_F}, + {"fnegabs" , INST_FNEGABS , 1, 3, IT_F}, + {"fnma" , INST_FNMA , 1, 5, IT_F}, + {"fnmpy" , INST_FNMPY , 1, 4, IT_F}, + {"fnorm" , INST_FNORM , 1, 3, IT_F}, + {"for" , INST_FOR , 1, 4, IT_F}, + {"fpabs" , INST_FPABS , 1, 3, IT_F}, + {"fpack" , INST_FPACK , 1, 4, IT_F}, + {"fpamax" , INST_FPAMAX , 1, 4, IT_F}, + {"fpamin" , INST_FPAMIN , 1, 4, IT_F}, + {"fpcmp" , INST_FPCMP , 1, 4, IT_F}, + {"fpcvt.fx" , INST_FPCVT_FX , 1, 3, IT_F}, + {"fpcvt.fx.trunc" , INST_FPCVT_FX_TRUNC , 1, 3, IT_F}, + {"fpcvt.fxu" , INST_FPCVT_FXU , 1, 3, IT_F}, + {"fpcvt.fxu.trunc" , INST_FPCVT_FXU_TRUNC , 1, 3, IT_F}, + {"fpma" , INST_FPMA , 1, 5, IT_F}, + {"fpmax" , INST_FPMAX , 1, 4, IT_F}, + {"fpmerge.ns" , INST_FPMERGE_NS , 1, 4, IT_F}, + {"fpmerge.s" , INST_FPMERGE_S , 1, 4, IT_F}, + {"fpmerge.se" , INST_FPMERGE_SE , 1, 4, IT_F}, + {"fpmin" , INST_FPMIN , 1, 4, IT_F}, + {"fpmpy" , INST_FPMPY , 1, 4, IT_F}, + {"fpms" , INST_FPMS , 1, 5, IT_F}, + {"fpneg" , INST_FPNEG , 1, 3, IT_F}, + {"fpnegabs" , INST_FPNEGABS , 1, 3, IT_F}, + {"fpnma" , INST_FPNMA , 1, 5, IT_F}, + {"fpnmpy" , INST_FPNMPY , 1, 4, IT_F}, + {"fprcpa" , INST_FPRCPA , 2, 5, IT_F}, + {"fprsqrta" , INST_FPRSQRTA , 2, 4, IT_F}, + {"frcpa" , INST_FRCPA , 2, 5, IT_F}, + {"frsqrta" , INST_FRSQRTA , 2, 4, IT_F}, + {"fselect" , INST_FSELECT , 1, 5, IT_F}, + {"fsetc" , INST_FSETC , 0, 3, IT_F}, + {"fsub" , INST_FSUB , 1, 4, IT_F}, + {"fswap" , INST_FSWAP , 1, 4, IT_F}, + {"fswap.nl" , INST_FSWAP_NL , 1, 4, IT_F}, + {"fswap.nr" , INST_FSWAP_NR , 1, 4, IT_F}, + {"fsxt.l" , INST_FSXT_L , 1, 4, IT_F}, + {"fsxt.r" , INST_FSXT_R , 1, 4, IT_F}, + {"fwb" , INST_FWB , 0, 1, IT_M}, + {"fxor" , INST_FXOR , 1, 4, IT_F}, + {"getf.s" , INST_GETF_S , 1, 3, IT_M}, + {"getf.d" , INST_GETF_D , 1, 3, IT_M}, + {"getf.exp" , INST_GETF_EXP , 1, 3, IT_M}, + {"getf.sig" , INST_GETF_SIG , 1, 3, IT_M}, + {"hint" , INST_HINT , 0, 2, IT_ANY | IT_EXPLICIT_IMBFX }, + {"invala" , INST_INVALA , 0, 1, IT_M}, + {"invala.e" , INST_INVALA_E , 0, 2, IT_M}, + {"itc.i" , INST_ITC_I , 0, 2, IT_M}, + {"itc.d" , INST_ITC_D , 0, 2, IT_M}, + {"itr.i" , INST_ITR_I , 1, 3, IT_M}, + {"itr.d" , INST_ITR_D , 1, 3, IT_M}, + {"ld" , INST_LD , 1, 3, IT_M}, + {"ld16" , INST_LD16 , 1, 3, IT_M}, + {"ld16.acq" , INST_LD16_ACQ , 1, 3, IT_M}, + {"ld8.fill" , INST_LD8_FILL , 1, 3, IT_M}, + {"ldf" , INST_LDF , 1, 3, IT_M}, + {"ldf8" , INST_LDF8 , 1, 3, IT_M}, + {"ldf.fill" , INST_LDF_FILL , 1, 3, IT_M}, + {"ldfps" , INST_LDFPS , 2, 4, IT_M}, + {"ldfpd" , INST_LDFPD , 2, 4, IT_M}, + {"ldfp8" , INST_LDFP8 , 2, 4, IT_M}, + {"lfetch" , INST_LFETCH , 0, 3, IT_M}, + {"lfetch" , INST_LFETCH_EXCL , 0, 3, IT_M}, + {"loadrs" , INST_LOADRS , 0, 1, IT_M}, + {"mf" , INST_MF , 0, 1, IT_M}, + {"mf.a" , INST_MF_A , 0, 1 ,IT_M}, + {"mix1.l" , INST_MIX1_L , 1, 4, IT_I}, + {"mix2.l" , INST_MIX2_L , 1, 4, IT_I}, + {"mix4.l" , INST_MIX4_L , 1, 4, IT_I}, + {"mix1.r" , INST_MIX1_R , 1, 4, IT_I}, + {"mix2.r" , INST_MIX2_R , 1, 4, IT_I}, + {"mix4.r" , INST_MIX4_R , 1, 4, IT_I}, + {"mov" , INST_MOV , 1, 3, IT_PSEUDO_OP }, + {"mov.i" , INST_MOV_I , 1, 3, IT_I }, + {"mov.m" , INST_MOV_M , 1, 3, IT_M }, + {"mov.ret" , INST_MOV_RET , 1, 3, IT_I }, + {"movl" , INST_MOVL , 1, 3, IT_L}, + {"mux1" , INST_MUX1 , 1, 4, IT_I}, + {"mux2" , INST_MUX2 , 1, 4, IT_I}, + {"nop" , INST_NOP , 0, 1, IT_ANY | IT_EXPLICIT_IMBFX }, + {"or" , INST_OR , 1, 4, IT_A}, + {"pack2.sss" , INST_PACK2_SSS , 1, 4, IT_I}, + {"pack2.uss" , INST_PACK2_USS , 1, 4, IT_I}, + {"pack4.sss" , INST_PACK4_SSS , 1, 4, IT_I}, + {"padd1" , INST_PADD1 , 1, 4, IT_A}, + {"padd1.sss" , INST_PADD1_SSS , 1, 4, IT_A}, + {"padd1.uus" , INST_PADD1_UUS , 1, 4, IT_A}, + {"padd1.uuu" , INST_PADD1_UUU , 1, 4, IT_A}, + {"padd2" , INST_PADD2 , 1, 4, IT_A}, + {"padd2.sss" , INST_PADD2_SSS , 1, 4, IT_A}, + {"padd2.uus" , INST_PADD2_UUS , 1, 4, IT_A}, + {"padd2.uuu" , INST_PADD2_UUU , 1, 4, IT_A}, + {"padd4" , INST_PADD4 , 1, 4, IT_A}, + {"pavg1" , INST_PAVG1 , 1, 4, IT_A}, + {"pavg1.raz" , INST_PAVG1_RAZ , 1, 4, IT_A}, + {"pavg2" , INST_PAVG2 , 1, 4, IT_A}, + {"pavg2.raz" , INST_PAVG2_RAZ , 1, 4, IT_A}, + {"pavgsub1" , INST_PAVGSUB1 , 1, 4, IT_A}, + {"pavgsub2" , INST_PAVGSUB2 , 1, 4, IT_A}, + {"pcmp1" , INST_PCMP1 , 1, 4, IT_A}, + {"pcmp2" , INST_PCMP2 , 1, 4, IT_A}, + {"pcmp4" , INST_PCMP4 , 1, 4, IT_A}, + {"pmax1.u" , INST_PMAX1_U , 1, 4, IT_I}, + {"pmax2" , INST_PMAX2 , 1, 4, IT_I}, + {"pmin1.u" , INST_PMIN1_U , 1, 4, IT_I}, + {"pmin2" , INST_PMIN2 , 1, 4, IT_I}, + {"pmpy2.r" , INST_PMPY2_R , 1, 4, IT_I}, + {"pmpy2.l" , INST_PMPY2_L , 1, 4, IT_I}, + {"pmpyshr2" , INST_PMPYSHR2 , 1, 5, IT_I}, + {"pmpyshr2.u" , INST_PMPYSHR2_U , 1, 5, IT_I}, + {"popcnt" , INST_POPCNT , 1, 3, IT_I}, + {"probe.r" , INST_PROBE_R , 1, 4, IT_M}, + {"probe.w" , INST_PROBE_W , 1, 4, IT_M}, + {"probe.r.fault" , INST_PROBE_R_FAULT , 1, 3, IT_M}, + {"probe.w.fault" , INST_PROBE_W_FAULT , 1, 3, IT_M}, + {"probe.rw.fault" , INST_PROBE_RW_FAULT , 1, 3, IT_M}, + {"psad1" , INST_PSAD1 , 1, 4, IT_I}, + {"pshl2" , INST_PSHL2 , 1, 4, IT_I}, + {"pshl4" , INST_PSHL4 , 1, 4, IT_I}, + {"pshladd2" , INST_PSHLADD2 , 1, 5, IT_A}, + {"pshr2" , INST_PSHR2 , 1, 4, IT_I}, + {"pshr2.u" , INST_PSHR2_U , 1, 4, IT_I}, + {"pshr4" , INST_PSHR4 , 1, 4, IT_I}, + {"pshr4.u" , INST_PSHR4_U , 1, 4, IT_I}, + {"pshradd2" , INST_PSHRADD2 , 1, 5, IT_A}, + {"psub1" , INST_PSUB1 , 1, 4, IT_A}, + {"psub1.sss" , INST_PSUB1_SSS , 1, 4, IT_A}, + {"psub1.uus" , INST_PSUB1_UUS , 1, 4, IT_A}, + {"psub1.uuu" , INST_PSUB1_UUU , 1, 4, IT_A}, + {"psub2" , INST_PSUB2 , 1, 4, IT_A}, + {"psub2.sss" , INST_PSUB2_SSS , 1, 4, IT_A}, + {"psub2.uus" , INST_PSUB2_UUS , 1, 4, IT_A}, + {"psub2.uuu" , INST_PSUB2_UUU , 1, 4, IT_A}, + {"psub4" , INST_PSUB4 , 1, 4, IT_A}, + {"ptc.e" , INST_PTC_E , 0, 2, IT_M}, + {"ptc.g" , INST_PTC_G , 0, 3, IT_M}, + {"ptc.ga" , INST_PTC_GA , 0, 3, IT_M}, + {"ptc.l" , INST_PTC_L , 0, 3, IT_M}, + {"ptr.d" , INST_PTR_D , 0, 3, IT_M}, + {"ptr.i" , INST_PTR_I , 0, 3, IT_M}, + {"rfi" , INST_RFI , 0, 1, IT_B}, + {"rsm" , INST_RSM , 0, 2, IT_M}, + {"rum" , INST_RUM , 0, 2, IT_M}, + {"setf.s" , INST_SETF_S , 1, 3, IT_M}, + {"setf.d" , INST_SETF_D , 1, 3, IT_M}, + {"setf.exp" , INST_SETF_EXP , 1, 3, IT_M}, + {"setf.sig" , INST_SETF_SIG , 1, 3, IT_M}, + {"shl" , INST_SHL , 1, 4, IT_I}, + {"shladd" , INST_SHLADD , 1, 5, IT_A}, + {"shladdp4" , INST_SHLADDP4 , 1, 5, IT_A}, + {"shr" , INST_SHR , 1, 4, IT_I}, + {"shr.u" , INST_SHR_U , 1, 4, IT_I}, + {"shrp" , INST_SHRP , 1, 5, IT_I}, + {"srlz.i" , INST_SRLZ_I , 0, 1, IT_M}, + {"srlz.d" , INST_SRLZ_D , 0, 1, IT_M}, + {"ssm" , INST_SSM , 1, 2, IT_M}, + {"st" , INST_ST , 0, 3, IT_M}, + {"st16" , INST_ST16 , 0, 3, IT_M}, + {"st8.spill" , INST_ST8_SPILL , 0, 3, IT_M}, + {"stf" , INST_STF , 0, 3, IT_M}, + {"stf8" , INST_STF8 , 0, 3, IT_M}, + {"stf.spill" , INST_STF_SPILL , 0, 3, IT_M}, + {"sub" , INST_SUB , 1, 4, IT_A}, + {"sum" , INST_SUM , 0, 2, IT_M}, + {"sxt" , INST_SXT , 1, 3, IT_I}, + {"sync.i" , INST_SYNC_I , 0, 1, IT_M}, + {"tak" , INST_TAK , 1, 3, IT_M}, + {"tbit" , INST_TBIT , 2, 5, IT_I}, + {"thash" , INST_THASH , 1, 3, IT_M}, + {"tnat" , INST_TNAT , 2, 4, IT_I}, + {"tpa" , INST_TPA , 1, 3, IT_M}, + {"ttag" , INST_TTAG , 1, 3, IT_M}, + {"unpack1.h" , INST_UNPACK1_H , 1, 4, IT_I}, + {"unpack2.h" , INST_UNPACK2_H , 1, 4, IT_I}, + {"unpack4.h" , INST_UNPACK4_H , 1, 4, IT_I}, + {"unpack1.l" , INST_UNPACK1_L , 1, 4, IT_I}, + {"unpack2.l" , INST_UNPACK2_L , 1, 4, IT_I}, + {"unpack4.l" , INST_UNPACK4_L , 1, 4, IT_I}, + {"xchg" , INST_XCHG , 1, 4, IT_M}, + {"xma.l" , INST_XMA_L , 1, 5, IT_F}, + {"xma.lu" , INST_XMA_LU , 1, 5, IT_F}, + {"xma.h" , INST_XMA_H , 1, 5, IT_F}, + {"xma.hu" , INST_XMA_HU , 1, 5, IT_F}, + {"xmpy.l" , INST_XMPY_L , 1, 5, IT_F}, + {"xmpy.lu" , INST_XMPY_LU , 1, 5, IT_F}, + {"xmpy.h" , INST_XMPY_H , 1, 5, IT_F}, + {"xmpy.hu" , INST_XMPY_HU , 1, 5, IT_F}, + {"xor" , INST_XOR , 1, 4, IT_A}, + {"zxt" , INST_ZXT , 1, 3, IT_I}, + // following are pseudo-op + {"switch" , INST_SWITCH , 0, 0, IT_PSEUDO_OP | IT_IGNORE_OP}, + {"break.i" , INST_BREAKPOINT , 0, 1, IT_I}, + {"use" , INST_USE , 0, 2, IT_PSEUDO_OP | IT_IGNORE_OP}, + {"def" , INST_DEF , 1, 2, IT_PSEUDO_OP | IT_IGNORE_OP}, + {"brl-13" , INST_BRL13 , 1, 4, IT_L | IT_GL}, + {"br-13" , INST_BR13 , 1, 4, IT_B} +}; + +const CmpltDescription Encoder::cmpltDesc[] = { + // Branch_Types (br) + {".cond", CMPLT_BTYPE_COND}, // br, brl + {".ia", CMPLT_BTYPE_IA}, + {".wexit", CMPLT_BTYPE_WEXIT}, + {".wtop", CMPLT_BTYPE_WTOP}, + {".ret", CMPLT_BTYPE_RET}, + {".cloop", CMPLT_BTYPE_CLOOP}, + {".cexit", CMPLT_BTYPE_CEXIT}, + {".ctop", CMPLT_BTYPE_CTOP}, + {".call", CMPLT_BTYPE_CALL}, // br, brl + //---------------------------- + // Branch_Whether_Hint, NOT for all branch instructions! + {"", CMPLT_WH_IGNORE}, // Ignore all hints. + {".sptk", CMPLT_WH_SPTK}, // Presaged branch should be predicted Static Taken + {".spnt", CMPLT_WH_SPNT}, + {".loop", CMPLT_WH_LOOP}, // Presaged branch will be br.cloop, br.ctop, or br.wtop + {".exit", CMPLT_WH_EXIT}, // Presaged branch will be br.cexit or br.wexit + {".dptk", CMPLT_WH_DPTK}, // Presaged branch should be predicted Dynamically + {".dpnt", CMPLT_WH_DPNT}, + //---------------------------- + // Branch_Sequential_Prefetch_Hint (br, brl) + {".few", CMPLT_PH_FEW}, + {".many", CMPLT_PH_MANY}, + //---------------------------- + // Branch_Cache_Deallocation_Hint (br, brl) + {"", CMPLT_DH_NOT_CLR}, + {".clr", CMPLT_DH_CLR}, + //---------------------------- + // Branch_Predict_Importance_Hint (brp) + {"", CMPLT_IH_NOT_IMP}, + {".imp", CMPLT_IH_IMP}, + //---------------------------- + // Speculation_Check_ALAT_Clear_Completer (chk.s, chk.a) + {".clr", CMPLT_CHK_A_CLR}, // Invalidate matching ALAT entry + {".nc", CMPLT_CHK_A_NC}, // Dont invalidate + //---------------------------- + // Comparison_Types + {"", CMPLT_CMP_CTYPE_NONE}, + {".unc", CMPLT_CMP_CTYPE_UNC}, + {".or", CMPLT_CMP_CTYPE_OR}, + {".and", CMPLT_CMP_CTYPE_AND}, + {".or.andcm", CMPLT_CMP_CTYPE_OR_ANDCM}, + //---------------------------- + // Comparison_Relations + {".eq", CMPLT_CMP_CREL_EQ}, + {".ne", CMPLT_CMP_CREL_NE}, + {".lt", CMPLT_CMP_CREL_LT}, + {".le", CMPLT_CMP_CREL_LE}, + {".gt", CMPLT_CMP_CREL_GT}, + {".ge", CMPLT_CMP_CREL_GE}, + {".ltu", CMPLT_CMP_CREL_LTU}, // unsigned + {".leu", CMPLT_CMP_CREL_LEU}, // unsigned + {".gtu", CMPLT_CMP_CREL_GTU}, // unsigned + {".geu", CMPLT_CMP_CREL_GEU}, // unsigned + //---------------------------- + // Floating_Point_Comparison_Relations + {".unord", CMPLT_FCMP_FREL_UNORD}, // unordered f2 ? f3 + {".nlt", CMPLT_FCMP_FREL_NLT}, // not less than !(f2 < f3) + {".nle", CMPLT_FCMP_FREL_NLE}, // not less than or equal !(f2 <= f3) + {".ngt", CMPLT_FCMP_FREL_NGT}, // not greater than !(f2 > f3) + {".nge", CMPLT_FCMP_FREL_NGE}, // not greater than or equal !(f2 >= f3) + {".ord", CMPLT_FCMP_FREL_ORD}, // ordered !(f2 ? f3) + //---------------------------- + // Semaphore_Types + {".acq", CMPLT_SEM_ACQ}, // Acquire The memory read/write is made + // visible prior to all subsequent data + // memory accesses. + {".rel", CMPLT_SEM_REL}, // Release The memory read/write is made + // visible after all previous data memory + // accesses. + //---------------------------- + // Floating_Point_pc_Mnemonic_Values + {".s", CMPLT_PC_SINGLE}, + {".d", CMPLT_PC_DOUBLE}, + {"", CMPLT_PC_DYNAMIC}, + //---------------------------- + // Floating_Point_sf_Mnemonic_Values + {".s0", CMPLT_SF0}, + {".s1", CMPLT_SF1}, + {".s2", CMPLT_SF2}, + {".s3", CMPLT_SF3}, + //---------------------------- + // Floating_Point_Class_Relations + {".m", CMPLT_FCREL_M}, // FR f2 agrees with the pattern specified + // by fclass9 (is a member) + {".nm", CMPLT_FCREL_NM}, // FR f2 does not agree with the pattern + // specified by fclass9 (is not a member) + //---------------------------- + // Floating_Point_Classes fclass9 in fclass instruction + {"NaTVal", CMPLT_FCLASS_NAT}, // NaTVal + {"Quiet NaN", CMPLT_FCLASS_QNAN}, // Quiet NaN + {"Signaling NaN", CMPLT_FCLASS_SNAN}, // Signaling NaN + {"Positive", CMPLT_FCLASS_POS}, // Positive + {"Negative", CMPLT_FCLASS_NEG}, // Negative + {"Zero", CMPLT_FCLASS_ZERO}, // Zero + {"Unnormalized", CMPLT_FCLASS_UNORM}, // Unnormalized + {"Normalized", CMPLT_FCLASS_NORM}, // Normalized + {"Infinity", CMPLT_FCLASS_INF}, // Infinity + //---------------------------- + // fsz completer for ldf instruction + {"s", CMPLT_FSZ_S}, + {"d", CMPLT_FSZ_D}, + {"e", CMPLT_FSZ_E}, + //---------------------------- + // sz completer for ld/st instructions + {"1", CMPLT_SZ_1}, + {"2", CMPLT_SZ_2}, + {"4", CMPLT_SZ_4}, + {"8", CMPLT_SZ_8}, + //---------------------------- + // Load_Types + {"", CMPLT_LDTYPE_NORMAL}, // Normal load + {".s", CMPLT_LDTYPE_S}, // Speculative load + {".a", CMPLT_LDTYPE_A}, // Advanced load + {".sa", CMPLT_LDTYPE_SA}, // Speculative Advanced load + {".c.nc", CMPLT_LDTYPE_C_NC}, // Check load - no clear + {".c.clr", CMPLT_LDTYPE_C_CLR}, // Check load - clear + {".c.clr.acq", CMPLT_LDTYPE_C_CLR_ACQ}, // Ordered check load clear + {".acq", CMPLT_LDTYPE_ACQ}, // Ordered load + {".bias", CMPLT_LDTYPE_BIAS}, // Biased load + //---------------------------- + // Line_Prefetch_Hints + // Some of Line_Prefetch_Hints are valid for lfetch, store, etc. + {"", CMPLT_HINT_NONE}, // Temporal locality, level 1 + {".nt1", CMPLT_HINT_NT1}, // No temporal locality, level 1 + {".nt2", CMPLT_HINT_NT2}, // No temporal locality, level 2 + {".nta", CMPLT_HINT_NTA}, // No temporal locality, all levels + //---------------------------- + // Saturation + {"", CMPLT_SAT_NONE}, // modulo_form + {".sss", CMPLT_SAT_SSS}, + {".uss", CMPLT_SAT_USS}, + {".uus", CMPLT_SAT_UUS}, + {".uuu", CMPLT_SAT_UUU}, + //---------------------------- + // Store_Types + {"", CMPLT_ST_TYPE_NORMAL}, + {".rel", CMPLT_ST_TYPE_REL}, + //---------------------------- + // compliters + {".s", CMPLT_FP_S}, // single_form, M18/M19 + {".d", CMPLT_FP_D}, // double_form, M18/M19 + {".exp", CMPLT_FP_EXP}, // exponent_form, M18/M19 + {".sig", CMPLT_FP_SIG}, // significand_form, M18/M19 + //---------------------------- + {"cpuid", CMPLT_IREG_CPUID}, // Processor Identification Register + {"dbr", CMPLT_IREG_DBR}, // Data Breakpoint Register + {"ibr", CMPLT_IREG_IBR}, // Instruction Breakpoint Register + {"pkr", CMPLT_IREG_PKR}, // Protection Key Register + {"pmc", CMPLT_IREG_PMC}, // Performance Monitor Configuration Register + {"pmd", CMPLT_IREG_PMD}, // Performance Monitor Data Register + {"rr", CMPLT_IREG_RR} // Region Register +}; + +bool Encoder::isBranchInst(Inst * inst) { + + if (inst == NULL) return false; + + InstCode instCode = inst->getInstCode(); + if (instCode>=INST_BR_FIRST && instCode<=INST_BR_LAST) return true; + if (instCode == INST_BR13) return true; + if (instCode == INST_BRL13) return true; + + return false; +} + +bool Encoder::isBranchCallInst(Inst * inst) { + if (isBranchInst(inst)) { + CompVector &cmpls = inst->getComps(); + if ( cmpls.size()>0 && cmpls[0]==CMPLT_BTYPE_CALL) return true; + } + return false; +} + +bool Encoder::isIgnoreInst(Inst * inst ) { + InstCode icode = inst->getInstCode(); + + if ((getInstType(icode) & IT_IGNORE_OP)==IT_IGNORE_OP) { + return true; + } + + return false; +} + +bool Encoder::isPseudoInst(Inst * inst ) { + return (getInstType(inst->getInstCode()) & IT_PSEUDO_OP)==IT_PSEUDO_OP; +} + +int Encoder::getInstType(Inst *inst) { + if (inst==NULL) return 0; + + InstCode icode = inst->getInstCode(); + + if (icode==INST_MOV) { + OpndVector & opnds = inst->getOpnds(); + int opndsize=opnds.size(); + + if (opndsize>=3) { + CompVector & cmpls = inst->getComps(); + OpndKind okind1 = opnds[1]->getOpndKind(); + OpndKind okind2 = opnds[2]->getOpndKind(); + + if (okind1==OPND_A_REG || okind2==OPND_A_REG) return IT_I | IT_M; + if (okind1==OPND_B_REG || okind2==OPND_B_REG) return IT_I; + if (okind1==OPND_F_REG && okind2==OPND_F_REG) return IT_F; + if (okind1==OPND_G_REG && okind2==OPND_IP_REG) return IT_I; + if (okind1==OPND_G_REG && okind2==OPND_P_REG) return IT_I; + if (okind1==OPND_P_REG && okind2==OPND_G_REG) return IT_I; + if (okind1==OPND_P_REG && opnds[2]->isImm(44)) return IT_I; + if (okind1==OPND_UM_REG && okind2==OPND_UM_REG) return IT_M; + if (okind1==OPND_G_REG && okind2==OPND_G_REG && cmpls.size()==0) + return IT_A; + if (okind1==OPND_G_REG && okind2==OPND_G_REG && cmpls.size()==1 + && cmpls[0]>=CMPLT_IREG_FIRST && cmpls[0]<=CMPLT_IREG_LAST) + return IT_M; + } + } + return Encoder::getInstType(icode); +} + +Inst * Encoder::resolvePseudo(Cfg & cfg, Inst * inst) { + if (getInstType(inst->getInstCode()) & IT_PSEUDO_OP) { + MemoryManager& mm=cfg.getMM(); + OpndManager* opndManager = cfg.getOpndManager(); + + Inst * newinst = NULL; + OpndVector & opnds = inst->getOpnds(); + CompVector & cmpls = inst->getComps(); + OpndKind okind1 = OPND_INVALID; + OpndKind okind2 = OPND_INVALID; + int opndsize=opnds.size(); + + switch(inst->getInstCode()) { + case INST_MOV: + okind1 = opnds[1]->getOpndKind(); + okind2 = opnds[2]->getOpndKind(); + + if (opndsize == 3) { + if (okind1 == OPND_G_REG && opnds[2]->isImm(22)) { + newinst = new(mm) Inst(INST_ADDL, opnds[0], opnds[1], opnds[2] + , cfg.getOpndManager()->getR0()); + } else if (okind1 == OPND_G_REG && opnds[2]->isImm(64)) { + newinst = new(mm) Inst(INST_MOVL, opnds[0], opnds[1], opnds[2]); + } else if (okind1 == OPND_G_REG && okind2 == OPND_G_REG + && cmpls.size()==0) { + newinst = new(mm) Inst(INST_ADDS, opnds[0], opnds[1] + , opndManager->newImm(0), opnds[2]); + } else if (okind1 == OPND_F_REG && okind2 == OPND_F_REG) { + newinst = new(mm) Inst(INST_FMERGE_S, opnds[0], opnds[1], opnds[2], opnds[2]); + } else if (okind1 == OPND_B_REG && okind2 == OPND_G_REG) { + newinst = new(mm) Inst(INST_MOV, opnds[0], opnds[1], opnds[2] + , opndManager->newImm(0)); + } else if (okind1 == OPND_G_REG && okind2 == OPND_A_REG) { + newinst = new(mm) Inst(INST_MOV_M, opnds[0], opnds[1], opnds[2]); + } else if (okind1 == OPND_G_REG && okind2 == OPND_B_REG) { + break; + } else if (okind1 == OPND_A_REG + && (okind2 == OPND_G_REG || opnds[2]->isImm(8))) { + break; + } else { + IPF_ERR << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(INST_MOV) << "\n"; + assert(0); + } + } else { + IPF_ERR << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(INST_MOV) << "\n"; + assert(0); + } + break; + default: + break; + } + if (newinst!=NULL ) { + return newinst; + } + } + return inst; +} + + +// nop: I18, B9, M48, F16, X5 +uint64 Encoder::getNopBits(InstructionType unit, unsigned qp, uint64 imm21) { + if( unit==IT_B) { + return 0x4000000000 + | ((imm21 & 0x100000) << 16) + | ((imm21 & 0x0FFFFF) << 6) + | qp; + } + return 0x8000000 + | ((imm21 & 0x100000) << 16) + | ((imm21 & 0x0FFFFF) << 6) + | qp; +} + +// nop: I18, B9, M48, F16, X5 +uint64 Encoder::getHintBits(InstructionType unit, unsigned qp, uint64 imm) { + if( unit==IT_B) return 0x4008000000 | qp; + return 0xC000000 | qp; +} + +// break: I19, B9, M37, F15, X1 +uint64 Encoder::getBreakBits(InstructionType unit, unsigned qp, uint64 imm21) { + return (uint64)0x0 + | ((imm21 & 0x100000) << 16) + | ((imm21 & 0x0FFFFF) << 6) + | qp; +} + +uint64 Encoder::getInstBits(InstructionType unit, Inst * inst) { + InstCode icode = inst->getInstCode(); + OpndVector & opnds = inst->getOpnds(); + CompVector & cmpls = inst->getComps(); + int opndcount = opnds.size(); + int cmplcount = cmpls.size(); + uint64 qp = opnds[0]->getValue(); + uint64 instbits = 0; + + switch (icode) { + // special cases + case INST_NOP: + return getNopBits(unit, qp, opnds[1]->getValue()); + case INST_HINT: + return getHintBits(unit, qp, opnds[1]->getValue()); + case INST_BREAK: + return getBreakBits(unit, qp, opnds[1]->getValue()); + case INST_BREAKPOINT: + return getBreakBits(unit, qp, INST_BREAKPOINT_IMM_VALUE); + + // start insts processing + case INST_ADD: + if( opndcount == 5 ) { // add r1 = r2, r3, 1 + return A1(0, 1, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } else { // add r1 = r2, r3 + return A1(0, 0, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + case INST_ADDS: // opnds[2]->getOpndKind() == OPND_IMM14 + return A4(2, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_ADDL: // opnds[2]->getOpndKind() == OPND_IMM22 + return A5(opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_ADDP4: + if (opnds[2]->getOpndKind() == OPND_G_REG) { + return A1(2, 0, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } else { + return A4(3, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + case INST_ALLOC: + { + uint64 i, l, o, r, sof, sol, sor, r1; + + r1 = opnds[1]->getValue(); + i = opnds[2]->getValue(); + l = opnds[3]->getValue(); + o = opnds[4]->getValue(); + r = opnds[5]->getValue(); + sof = i + l + o; + sol = i +l; + sor = r >> 3; + + return M34(sor, sol, sof, r1, qp); + } + case INST_AND: + case INST_ANDCM: + case INST_OR: + case INST_XOR: + case INST_SUB: + { + uint64 x4=3, x2b=0; + + switch (icode) { + case INST_AND: x4=3; x2b=0; break; + case INST_ANDCM: x4=3; x2b=1; break; + case INST_OR: x4=3; x2b=2; break; + case INST_XOR: x4=3; x2b=3; break; + case INST_SUB: x4=1; if (opndcount == 5) x2b=0; else x2b=1; break; + default: assert(0); break; + } + + if (opnds[2]->isImm(14)) { + x4 += 0x8; + return A1(x4, x2b, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } else { + return A3(x4, x2b, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + } + case INST_CMP: + return cmp_cmp4(icode, inst, cmpls, opnds, qp); + case INST_CMP4: + return cmp_cmp4(icode, inst, cmpls, opnds, qp); + + case INST_FABS: + return F9(0, 0x10, opnds[2]->getValue(), 0, opnds[1]->getValue(), qp); + case INST_FADD: + // pseudo-op of: (qp) fma.pc.sf f1 = f3, f1, f2 + { + uint64 opcode=8, x=0, sf=0; + + for (int i=0 ; i<cmplcount ; i++ ) { + switch (cmpls[i]) { + case CMPLT_PC_DYNAMIC: x=0; opcode=8; break; + case CMPLT_PC_SINGLE: x=1; opcode=8; break; + case CMPLT_PC_DOUBLE: x=0; opcode=9; break; + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: assert(0); break; + } + } + return F1(opcode, x, sf, 1, opnds[2]->getValue(), opnds[3]->getValue(), opnds[1]->getValue(), qp); + } + case INST_FNORM: + // (qp) fnorm.pc.sf f1 = f3 pseudo-op of: (qp) fma.pc.sf f1 = f3, f1, f0 + { + uint64 opcode=8, x=0, sf=0; + + for (int i=0 ; i<cmplcount ; i++ ) { + switch (cmpls[i]) { + case CMPLT_PC_DYNAMIC: x=0; opcode=8; break; + case CMPLT_PC_SINGLE: x=1; opcode=8; break; + case CMPLT_PC_DOUBLE: x=0; opcode=9; break; + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: assert(0); break; + } + } + return F1(opcode, x, sf, 1, opnds[2]->getValue(), 0, opnds[1]->getValue(), qp); + } + case INST_FAND: + return F9(0, 0x2C, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_FANDCM: + return F9(0, 0x2D, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_FC: + return M28(0, opnds[1]->getValue(), qp); + case INST_FC_I: + return M28(1, opnds[1]->getValue(), qp); + case INST_FCMP: + return fcmp(icode, inst, cmpls, opnds, qp); + case INST_FCLASS: + { + uint64 px, p1=opnds[1]->getValue(), p2=opnds[2]->getValue(), ta=0; + + for (int i=0; i<cmplcount; ++i) { + if (cmpls[i]==CMPLT_FCMP_FCTYPE_UNC) { ta=1; } + else if (cmpls[i]==CMPLT_FCREL_NM) { px=p1; p1=p2; p2=px; } + } + return F5(opnds[4]->getValue(), p2, opnds[3]->getValue(), ta, p1, qp); + } + case INST_FCVT_FX: + case INST_FCVT_FXU: + case INST_FCVT_FX_TRUNC: + case INST_FCVT_FXU_TRUNC: + case INST_FPCVT_FX: + case INST_FPCVT_FXU: + case INST_FPCVT_FX_TRUNC: + case INST_FPCVT_FXU_TRUNC: + { + uint64 opcode=0, x6=0x18, sf=0; + + if ( cmplcount==1 ) { + switch(cmpls[0]) { + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: assert(0); break; + } + } + switch (icode) { + case INST_FCVT_FX: opcode=0; x6=0x18; break; + case INST_FCVT_FXU: opcode=0; x6=0x19; break; + case INST_FCVT_FX_TRUNC: opcode=0; x6=0x1A; break; + case INST_FCVT_FXU_TRUNC: opcode=0; x6=0x1B; break; + case INST_FPCVT_FX: opcode=1; x6=0x18; break; + case INST_FPCVT_FXU: opcode=1; x6=0x19; break; + case INST_FPCVT_FX_TRUNC: opcode=1; x6=0x1A; break; + case INST_FPCVT_FXU_TRUNC: opcode=1; x6=0x1B; break; + default: assert(0); break; + } + return F10(opcode, sf, x6, opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + case INST_FCVT_XF: + return F11(opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_FCVT_XUF: + case INST_FMA: { + uint64 opcode=0, x=0, pc=CMPLT_PC_DYNAMIC, sf=CMPLT_SF0; + + if ( cmpls.size()==2 ) { + pc=cmpls[0]; + sf=cmpls[1]; + } else if ( cmpls.size()==1 ) { + switch ( cmpls[0] ) { + case CMPLT_PC_SINGLE: + case CMPLT_PC_DOUBLE: + case CMPLT_PC_DYNAMIC: pc=cmpls[0]; break; + default: sf=cmpls[0]; break; + } + } + switch (pc) { + case CMPLT_PC_DYNAMIC: opcode=8; x=0; break; + case CMPLT_PC_SINGLE: opcode=8; x=1; break; + case CMPLT_PC_DOUBLE: opcode=9; x=0; break; + } + switch ( sf ) { + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + } + + if (icode==INST_FMA) { + return F1(opcode, x, sf + , opnds[3]->getValue(), opnds[2]->getValue() + , opnds[4]->getValue(), opnds[1]->getValue(), qp); + } else { + return F1(opcode, x, sf + , 1, opnds[2]->getValue() + , 0, opnds[1]->getValue(), qp); + } + } + case INST_FMIN: + case INST_FMAX: + case INST_FAMIN: + case INST_FAMAX: + case INST_FPMIN: + case INST_FPMAX: + case INST_FPAMIN: + case INST_FPAMAX: + case INST_FPCMP: + { + uint64 opcode=0, x6=0xFF, sf=0; + uint64 fx, f1=opnds[1]->getValue(), f2=opnds[2]->getValue(), f3=opnds[3]->getValue(); + + for (int i=0 ; i<cmplcount ; i++ ) { + switch (cmpls[i]) { + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + case CMPLT_FCMP_FREL_EQ: x6=0x30; break; + case CMPLT_FCMP_FREL_GT: fx=f2; f2=f3; f3=fx; + case CMPLT_FCMP_FREL_LT: x6=0x31; break; + case CMPLT_FCMP_FREL_GE: fx=f2; f2=f3; f3=fx; + case CMPLT_FCMP_FREL_LE: x6=0x32; break; + case CMPLT_FCMP_FREL_UNORD: x6=0x33; break; + case CMPLT_FCMP_FREL_NEQ: x6=0x34; break; + case CMPLT_FCMP_FREL_NGT: fx=f2; f2=f3; f3=fx; + case CMPLT_FCMP_FREL_NLT: x6=0x35; break; + case CMPLT_FCMP_FREL_NGE: fx=f2; f2=f3; f3=fx; + case CMPLT_FCMP_FREL_NLE: x6=0x36; break; + case CMPLT_FCMP_FREL_ORD: x6=0x37; break; + default: assert(0); break; + } + } + switch (icode) { + case INST_FMIN: opcode=0; x6=0x14; break; + case INST_FMAX: opcode=0; x6=0x15; break; + case INST_FAMIN: opcode=0; x6=0x16; break; + case INST_FAMAX: opcode=0; x6=0x17; break; + case INST_FPMIN: opcode=1; x6=0x14; break; + case INST_FPMAX: opcode=1; x6=0x15; break; + case INST_FPAMIN: opcode=1; x6=0x16; break; + case INST_FPAMAX: opcode=1; x6=0x17; break; + case INST_FPCMP: opcode=1; break; + default: assert(0); break; + } + + return F8(opcode, sf, x6, f3, f2, f1, qp); + } + case INST_FMERGE_S: + return F9(0, 0x10, opnds[3]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_FNEG: + return F9(0, 0x11, opnds[2]->getValue(), opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_FNMA: { + uint64 opcode=0xC, x=0, sf=0; + + for ( int ci=0 ; ci<cmplcount ; ci++ ) { + switch(cmpls[ci]) { + case CMPLT_PC_SINGLE: x=1; break; + case CMPLT_PC_DOUBLE: opcode=0xD; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: break; + } + } + + return F1(opcode, x, sf, opnds[3]->getValue(), opnds[2]->getValue(), + opnds[4]->getValue(), opnds[1]->getValue(), qp); + } + case INST_FRCPA: { + uint64 sf=0; + + if ( cmplcount==1 ) { + switch(cmpls[0]) { + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: break; + } + } + return F6(0, sf, opnds[2]->getValue(), opnds[4]->getValue(), + opnds[3]->getValue(), opnds[1]->getValue(), qp); + } + case INST_FSUB: { // qp) fsub.pc.sf f1 = f3, f2 pseudo-op of: (qp) fms.pc.sf f1 = f3, f4==1, f2 + uint64 opcode=0xA, x=0, sf=0; + + for ( int ci=0 ; ci<cmplcount ; ci++ ) { + switch(cmpls[ci]) { + case CMPLT_PC_SINGLE: opcode=0xA; x=1; break; + case CMPLT_PC_DOUBLE: opcode=0xB; x=0; break; + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: + assert(0); + break; + } + } + return F1(opcode, x, sf, 1, opnds[2]->getValue() + , opnds[3]->getValue(), opnds[1]->getValue(), qp); + } + case INST_GETF_S: + return M19(0x1e, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_GETF_D: + return M19(0x1f, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_GETF_EXP: + return M19(0x1d, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_GETF_SIG: + return M19(0x1c, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_LD: + case INST_LD16: + case INST_LD16_ACQ: + case INST_LD8_FILL: + { + uint64 x=0, x6=0x0, hint=0; + + for (int i=0 ; i<cmplcount ; i++ ) { + switch (cmpls[i]) { + case CMPLT_SZ_1: x6 = (x6 & 0x3C) | 0x00; break; + case CMPLT_SZ_2: x6 = (x6 & 0x3C) | 0x01; break; + case CMPLT_SZ_4: x6 = (x6 & 0x3C) | 0x02; break; + case CMPLT_SZ_8: x6 = (x6 & 0x3C) | 0x03; break; + case CMPLT_LDTYPE_NORMAL: x6 = (x6 & 0x3) | (0x00 << 2); break; + case CMPLT_LDTYPE_S: x6 = (x6 & 0x3) | (0x01 << 2); break; + case CMPLT_LDTYPE_A: x6 = (x6 & 0x3) | (0x02 << 2); break; + case CMPLT_LDTYPE_SA: x6 = (x6 & 0x3) | (0x03 << 2); break; + case CMPLT_LDTYPE_BIAS: x6 = (x6 & 0x3) | (0x04 << 2); break; + case CMPLT_LDTYPE_ACQ: x6 = (x6 & 0x3) | (0x05 << 2); break; + case CMPLT_LDTYPE_C_CLR: x6 = (x6 & 0x3) | (0x08 << 2); break; + case CMPLT_LDTYPE_C_NC: x6 = (x6 & 0x3) | (0x09 << 2); break; + case CMPLT_LDTYPE_C_CLR_ACQ: x6 = (x6 & 0x3) | (0x0A << 2); break; + case CMPLT_HINT_NONE: hint=0; break; + case CMPLT_HINT_NT1: hint=1; break; + case CMPLT_HINT_NTA: hint=3; break; + default: assert(0); break; + } + } + if (icode==INST_LD16 ) { + x6 = 0x28; + x = 1; + } else if (icode==INST_LD16_ACQ ) { + x6 = 0x2C; + x = 1; + } else if (icode==INST_LD8_FILL ) { + x6 = 0x1B; + x = 0; + } + if (opndcount>=4 && opnds[3]->isImm(9)) { + return M3(x6, hint, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else if (opndcount>=4 && opnds[3]->getOpndKind()==OPND_G_REG) { + return M2(x6, hint, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else { + return M1(x6, hint, x, opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + } + + case INST_LDF: + case INST_LDF8: + case INST_LDF_FILL: + return ldfx(icode, inst, cmpls, opnds, qp); + + case INST_MOV: + case INST_MOV_I: + case INST_MOV_M: + case INST_MOV_RET: + return mov(unit, icode, inst, cmpls, opnds, qp); + + case INST_SETF_S: + return M18(0x1e, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_SETF_D: + return M18(0x1f, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_SETF_EXP: + return M18(0x1d, opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_SETF_SIG: + return M18(0x1c, opnds[2]->getValue(), opnds[1]->getValue(), qp); + + case INST_SHL: + assert(opndcount>=4); + if (opnds[3]->getOpndKind()==OPND_G_REG) { + return I7(1, 1, opnds[3]->getValue(), opnds[2]->getValue() + , opnds[1]->getValue(), qp); + } else { + // pos6 = count6; len6 = 64-pos6; len6 = len6d + 1; pos6 = 63 - cpos6c + return I12(63-(uint64)opnds[3]->getValue(), 63-(uint64)opnds[3]->getValue() + , opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + case INST_SHLADD: + return A2(4, opnds[3]->getValue() & 0x3, opnds[4]->getValue() + , opnds[2]->getValue(), opnds[1]->getValue(), qp); + case INST_SHR: + assert(opndcount>=4); + if (opnds[3]->getOpndKind()==OPND_G_REG) { + return I5(1, 1, 2, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else { + return I11(64-opnds[3]->getValue(), opnds[2]->getValue() + , opnds[3]->getValue(), 1, opnds[1]->getValue(), qp); + } + case INST_SHR_U: + assert(opndcount>=4); + if (opnds[3]->getOpndKind()==OPND_G_REG) { + return I5(1, 1, 0, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else { + return I11(64-opnds[3]->getValue(), opnds[2]->getValue() + , opnds[3]->getValue(), 0, opnds[1]->getValue(), qp); + } + + case INST_ST: + { + uint64 x6=0x30, hint=0; + + for (int i=0, ii=cmplcount ; i<ii ; i++) { + switch (cmpls[i]) { + case CMPLT_SZ_1: x6 = (x6 & 0x3C) | 0x00; break; + case CMPLT_SZ_2: x6 = (x6 & 0x3C) | 0x01; break; + case CMPLT_SZ_4: x6 = (x6 & 0x3C) | 0x02; break; + case CMPLT_SZ_8: x6 = (x6 & 0x3C) | 0x03; break; + case CMPLT_ST_TYPE_NORMAL: x6 = (x6 & 0x3) | (0x0C << 2);break; + case CMPLT_ST_TYPE_REL: x6 = (x6 & 0x3) | (0x0D << 2); break; + case CMPLT_HINT_NONE: hint=0; break; + case CMPLT_HINT_NTA: hint=3; break; + default: assert(0); break; + } + } + if (opndcount==4 && opnds[3]->isImm(9)) { + return M5(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp); + } else { + return M4(x6, hint, 0, opnds[1]->getValue(), opnds[2]->getValue(), qp); + } + } + case INST_ST8_SPILL: + if ( opndcount==3 ) { + return M4(0x3B, (cmplcount>0 && cmpls[0]==CMPLT_HINT_NTA?3:0) + , 0, opnds[1]->getValue(), opnds[2]->getValue(), qp); + } else { + return M5(0x3B, (cmplcount>0 && cmpls[0]==CMPLT_HINT_NTA?3:0) + , opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp); + } + case INST_ST16: + { + uint64 x6=0x30, hint=0; + + for (int i=0, ii=cmpls.size() ; i<ii ; i++) { + switch (cmpls[i]) { + case CMPLT_ST_TYPE_NORMAL: x6 = 0x30;break; + case CMPLT_ST_TYPE_REL: x6 = 0x34; break; + case CMPLT_HINT_NONE: hint=0; break; + case CMPLT_HINT_NTA: hint=3; break; + default: assert(0); break; + } + } + return M4(x6, hint, 1, opnds[1]->getValue(), opnds[2]->getValue(), qp); + } + case INST_STF: + case INST_STF8: + case INST_STF_SPILL: + { + uint64 x6=0x32, hint=0; + + if (icode==INST_STF_SPILL) { + x6=0x3B; + } else if (icode==INST_STF8) { + x6=0x31; + } else { + switch (cmpls[0]) { + case CMPLT_FSZ_S: x6=0x32; break; + case CMPLT_FSZ_D: x6=0x33; break; + case CMPLT_FSZ_E: x6=0x30; break; + default: assert(0); break; + } + } + if (cmplcount>=1 && cmpls[0]==CMPLT_HINT_NTA ) hint=3; + else if (cmplcount>=2 && cmpls[1]==CMPLT_HINT_NTA ) hint=3; + + if (opnds.size()>=4 ) { + return M10(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), opnds[3]->getValue(), qp); + } else { + return M9(x6, hint, opnds[1]->getValue(), opnds[2]->getValue(), qp); + } + } + + case INST_SXT: + case INST_ZXT: + { + uint64 x6 = 0xFF; + + switch (cmpls[0]) { + case CMPLT_XSZ_1: x6 = 0x14; break; + case CMPLT_XSZ_2: x6 = 0x15; break; + case CMPLT_XSZ_4: x6 = 0x16; break; + default: assert(0); break; + } + if (icode==INST_ZXT) x6 = x6 - 4; + return I29(x6, opnds[2]->getValue(), opnds[1]->getValue(), qp); + } + + case INST_XMA_L: + case INST_XMA_LU: + return F2(0, opnds[3]->getValue(), opnds[2]->getValue() + , opnds[4]->getValue(), opnds[1]->getValue(), qp); + case INST_XMA_H: + return F2(3, opnds[3]->getValue(), opnds[2]->getValue() + , opnds[4]->getValue(), opnds[1]->getValue(), qp); + case INST_XMA_HU: + return F2(2, opnds[3]->getValue(), opnds[2]->getValue() + , opnds[4]->getValue(), opnds[1]->getValue(), qp); + + default: + IPF_ERR << __FILE__ << ": " << __LINE__ + << " IpfEncoder ERROR: NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(icode) << "\n"; + break; + } + + return instbits; +} + +uint64 Encoder::getInstBitsBranch(InstructionType unit, Inst * inst, int target) { + InstCode icode = inst->getInstCode(); + OpndVector & opnds = inst->getOpnds(); + uint64 qp = opnds[0]->getValue(); + + if( icode==INST_NOP ) return getNopBits(unit, qp, opnds[1]->getValue()); + if( icode==INST_HINT ) return getHintBits(unit, qp, opnds[1]->getValue()); + + uint64 instbits = 0; + + switch (icode) { + case INST_BR13: + case INST_BR: + { + unsigned int is13 = (icode==INST_BR13 ? 1 : 0); // must be 1 or 0 + CompVector & cmpls = inst->getComps(); + OpndKind okind1 = opnds[is13 + 1]->getOpndKind(); + uint64 o1 = opnds[is13 + 1]->getValue(); + uint64 cmplt_btype=CMPLT_BTYPE_COND, btype=0, ph=0, bwh=1, dh=0; + + for (int i=0, ii=cmpls.size() ; i<ii ; i++) { + switch (cmpls[i]) { + case CMPLT_BTYPE_COND: btype=0; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_IA: btype=1; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_RET: btype=4; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_CLOOP: btype=5; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_CEXIT: btype=6; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_CTOP: btype=7; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_WEXIT: btype=2; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_WTOP: btype=3; cmplt_btype=cmpls[i]; break; + case CMPLT_BTYPE_CALL: btype=(uint64)-1; cmplt_btype=cmpls[i]; break; + //---------------------------- + // Branch_Whether_Hint, NOT for all branch instructions! + case CMPLT_WH_SPTK: bwh=0; break; + case CMPLT_WH_SPNT: bwh=1; break; + case CMPLT_WH_DPTK: bwh=2; break; + case CMPLT_WH_DPNT: bwh=3; break; + //---------------------------- + // Branch_Sequential_Prefetch_Hint (br, brl) + case CMPLT_PH_FEW: ph=0; break; + case CMPLT_PH_MANY: ph=1; break; + //---------------------------- + // Branch_Cache_Deallocation_Hint (br, brl) + case CMPLT_DH_NOT_CLR: dh=0; break; + case CMPLT_DH_CLR: dh=1; break; + default: assert(0); + } + } + + if (cmplt_btype==CMPLT_BTYPE_CALL) { + assert(opnds.size()>=(is13 + 3)); + OpndKind okind2 = opnds[is13 + 2]->getOpndKind(); + uint64 o2 = opnds[is13 + 2]->getValue(); + + if (okind2==OPND_B_REG) { + return B5(ph, ((bwh%2)==0 ? 1 : bwh), dh, o2, o1, qp); + } else if ( (opnds[is13 + 2])->getDataKind() == DATA_NODE_REF ) { + assert(target != 0); + return B3(ph, bwh, dh, target>>4, o1, qp); + } else { + return B3(ph, bwh, dh, o2, o1, qp); + } + } else if (cmplt_btype==CMPLT_BTYPE_RET) { + return B4(0, 0, 0x21, o1, 0, 4, qp); + } else if (cmplt_btype==CMPLT_BTYPE_CLOOP + || cmplt_btype==CMPLT_BTYPE_CEXIT + || cmplt_btype==CMPLT_BTYPE_CTOP) { + if ( (opnds[is13 + 1])->getDataKind() == DATA_NODE_REF ) { + assert(target != 0); + return B1_B2(dh, bwh, ph, btype, target >> 4, qp); + } else { + return B1_B2(dh, bwh, ph, btype, o1, qp); + } + } else if (okind1==OPND_B_REG) { + return B4(dh, bwh, 0x20, o1, ph, btype, qp); + } else { + if ( (inst->getOpnd(is13 + 1))->getDataKind() == DATA_NODE_REF ) { + assert(target!=0); + return B1_B2(dh, bwh, ph, btype, target>>4, qp); + } else { + return B1_B2(dh, bwh, ph, btype, o1, qp); + } + } + } + // fall to assert(0) + default: + IPF_ERR << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(icode) << "\n"; + assert(0); + break; + } + + return instbits; +} + +uint64 * Encoder::getInstBitsExtended(Inst * inst, uint64 * slots12, void *whereToEmit) { + InstCode icode = inst->getInstCode(); + OpndVector & opnds = inst->getOpnds(); + CompVector & cmpls = inst->getComps(); + uint64 qp = opnds[0]->getValue(); + + switch (icode) { + case INST_MOVL: + assert(opnds.size()==3); + return X2(0, opnds[1]->getValue(), opnds[2]->getValue(), qp, slots12); + case INST_NOP: + return X5(0, 0, qp, slots12); + + case INST_BRL13: + case INST_BRL: + { + unsigned int is13 = (icode==INST_BRL13 ? 1 : 0); // must be 1 or 0 + if (cmpls[0]==CMPLT_BTYPE_CALL) assert(opnds.size()>=(is13 + 3)); + else assert(opnds.size()>=(is13 + 2)); + + // (qp) brl.btype.bwh.ph.dh b1 = target64 + // target64 = IP + ((i << 59 | imm39 << 20 | imm20b) << 4) + uint64 d=0, wh=0, p=0; + uint64 imm60 = 0; + uint64 imm64 = 0; + CompVector & cmpls = inst->getComps(); + + if (opnds[is13 + 2]->isImm(64)) { + imm64 = opnds[is13 + 2]->getValue(); + imm60 = (imm64 - (uint64)whereToEmit) >> 4; + } + for ( int i=0, ii=cmpls.size() ; i<ii ; i++ ) { + switch (cmpls[i]) { + case CMPLT_DH_CLR: d=1; break; + case CMPLT_WH_SPTK: wh=0; break; + case CMPLT_WH_SPNT: wh=1; break; + case CMPLT_WH_DPTK: wh=2; break; + case CMPLT_WH_DPNT: wh=3; break; + case CMPLT_PH_FEW: p=0; break; + case CMPLT_PH_MANY: p=1; break; + default: break; + } + } + + if (cmpls[0]==CMPLT_BTYPE_CALL) + return X4(imm60, d, wh, p, opnds[is13 + 1]->getValue(), qp, slots12); + else + return X3(imm60, d, wh, p, qp, slots12); + } + break; + default: + break; + } + + IPF_ERR << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(icode) << "\n"; + assert(0); + return slots12; +} + +//----------------------------------------------------------------------------// +uint64 Encoder::fcmp(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp) { + assert(opnds.size()==5); + int64 p1=opnds[1]->getValue(), p2=opnds[2]->getValue(); + int64 f2=opnds[3]->getValue(), f3=opnds[4]->getValue(), tmp; + Completer frel = cmpls[0]; + Completer fctype = CMPLT_FCMP_FCTYPE_NONE; + uint64 ra=0, rb=0, ta=0, sf = 0; + + switch (frel) { + case CMPLT_FCMP_FREL_EQ: ra=0; rb=0; break; + case CMPLT_FCMP_FREL_LT: ra=0; rb=1; break; + case CMPLT_FCMP_FREL_LE: ra=1; rb=0; break; + case CMPLT_FCMP_FREL_GT: + ra=0; rb=1; frel=CMPLT_FCMP_FREL_LT; + tmp=f2; f2=f3; f3=tmp; + break; + case CMPLT_FCMP_FREL_GE: + ra=1; rb=0; frel=CMPLT_FCMP_FREL_LE; + tmp=f2; f2=f3; f3=tmp; + break; + case CMPLT_FCMP_FREL_UNORD: + ra=1; rb=1; + break; + case CMPLT_FCMP_FREL_NEQ: + ra=0; rb=0; frel=CMPLT_FCMP_FREL_EQ; + tmp=p1; p1=p2; p2=tmp; + break; + case CMPLT_FCMP_FREL_NLT: + ra=0; rb=1; frel=CMPLT_FCMP_FREL_LT; + tmp=p1; p1=p2; p2=tmp; + break; + case CMPLT_FCMP_FREL_NLE: + ra=1; rb=0; frel=CMPLT_FCMP_FREL_LE; + tmp=p1; p1=p2; p2=tmp; + break; + case CMPLT_FCMP_FREL_NGT: + ra=0; rb=1; frel=CMPLT_FCMP_FREL_LT; + tmp=f2; f2=f3; f3=tmp; + tmp=p1; p1=p2; p2=tmp; + break; + case CMPLT_FCMP_FREL_NGE: + ra=1; rb=0; frel=CMPLT_FCMP_FREL_LE; + tmp=f2; f2=f3; f3=tmp; + tmp=p1; p1=p2; p2=tmp; + break; + case CMPLT_FCMP_FREL_ORD: + ra=1; rb=1; frel=CMPLT_FCMP_FREL_UNORD; + tmp=p1; p1=p2; p2=tmp; + break; + default: + assert(0); + break; + } + if (cmpls.size()>2) { + switch (cmpls[1]) { + case CMPLT_FCMP_FCTYPE_NONE: ta=0; fctype = CMPLT_FCMP_FCTYPE_NONE; break; + case CMPLT_FCMP_FCTYPE_UNC: ta=1; fctype = CMPLT_FCMP_FCTYPE_UNC; break; + default: + assert(0); break; + } + switch (cmpls[2]) { + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: + assert(0); break; + } + } else if (cmpls.size()>1) { + switch (cmpls[1]) { + case CMPLT_FCMP_FCTYPE_NONE: ta=0; fctype = CMPLT_FCMP_FCTYPE_NONE; break; + case CMPLT_FCMP_FCTYPE_UNC: ta=1; fctype = CMPLT_FCMP_FCTYPE_UNC; break; + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: + assert(0); break; + } + } + return F4(rb, sf, ra, p2, f3, f2, ta, p1, qp); +} + +//----------------------------------------------------------------------------// +uint64 Encoder::cmp_cmp4(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp) { + assert(opnds.size()>=5); + + int64 p1=opnds[1]->getValue(), p2=opnds[2]->getValue(); + int64 r2=opnds[3]->getValue(), r3=opnds[4]->getValue(); + OpndKind okind3=opnds[3]->getOpndKind(); + Completer crel = cmpls[0]; + Completer ctype = ( cmpls.size()>1 ? cmpls[1] : CMPLT_INVALID ); + uint64 opcode=0, ta=0, c=0, x2; + int64 tmp, & imm8 = r2; + + // parse pseudo-op + if ( cmpls.size() == 1 || ctype==CMPLT_CMP_CTYPE_UNC ) { + if (opnds[3]->isImm(8)) { + switch (crel) { + case CMPLT_CMP_CREL_NE: + crel=CMPLT_CMP_CREL_EQ; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LE: + crel=CMPLT_CMP_CREL_LT; + r2--; + break; + case CMPLT_CMP_CREL_GT: + crel=CMPLT_CMP_CREL_LT; + r2--; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GE: + crel=CMPLT_CMP_CREL_LT; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LEU: + crel=CMPLT_CMP_CREL_LTU; + r2--; + break; + case CMPLT_CMP_CREL_GTU: + crel=CMPLT_CMP_CREL_LTU; + r2--; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = p1; p1 = p2; p2 = tmp; + break; + default: + break; + } + } else { + switch (crel) { + case CMPLT_CMP_CREL_NE: + crel=CMPLT_CMP_CREL_EQ; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LE: + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GT: + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + break; + case CMPLT_CMP_CREL_GE: + crel=CMPLT_CMP_CREL_LT; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = r3; r3 = r2; r2 = tmp; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GTU: + crel=CMPLT_CMP_CREL_LTU; + tmp = r3; r3 = r2; r2 = tmp; + break; + case CMPLT_CMP_CREL_GEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = p1; p1 = p2; p2 = tmp; + break; + default: + break; + } + } + } else if ( crel!=CMPLT_CMP_CREL_EQ && crel!=CMPLT_CMP_CREL_NE ) { + if ( crel==CMPLT_CMP_CREL_LT && r2>0 ) { + crel=CMPLT_CMP_CREL_GT; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_LE && r2>0 ) { + crel=CMPLT_CMP_CREL_GE; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_GT && r2>0 ) { + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_GE && r2>0 ) { + crel=CMPLT_CMP_CREL_LE; + tmp = r3; r3 = r2; r2 = tmp; + } + } + + switch (ctype) { + case CMPLT_CMP_CTYPE_AND: opcode=0xC; break; + case CMPLT_CMP_CTYPE_OR: opcode=0xD; break; + case CMPLT_CMP_CTYPE_OR_ANDCM: opcode=0xE; break; + default: + switch (crel) { + case CMPLT_CMP_CREL_LT: opcode=0xC; break; + case CMPLT_CMP_CREL_LTU: opcode=0xD; break; + case CMPLT_CMP_CREL_EQ: opcode=0xE; break; + default: + IPF_ERR << __FILE__ << ": " << __LINE__ << ": BAD ctype/crel\n"; + assert(0); + break; + } + } + + switch (crel) { + case CMPLT_CMP_CREL_NE: ta=1; c=1; break; + case CMPLT_CMP_CREL_GE: ta=1; c=0; break; + case CMPLT_CMP_CREL_LE: ta=0; c=1; break; + case CMPLT_CMP_CREL_GT: ta=0; c=0; break; + case CMPLT_CMP_CREL_LTU: ta=0; c=(ctype==CMPLT_CMP_CTYPE_UNC ? 1 : 0); break; + case CMPLT_CMP_CREL_EQ: + if ( cmpls.size()==1 ) { ta=0; c=0; } + else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; } + else { ta=1; c=0; } + break; + case CMPLT_CMP_CREL_LT: + if ( cmpls.size()==1 ) { ta=0; c=0; } + else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; } + else { ta=1; c=1; } + break; + default: + IPF_ERR << __FILE__ << ": " << __LINE__ << ": BAD ctype/crel\n"; + assert(0); + break; + } + + if ( (ctype==CMPLT_CMP_CTYPE_NORMAL || ctype==CMPLT_CMP_CTYPE_UNC + || crel==CMPLT_CMP_CREL_NE || crel==CMPLT_CMP_CREL_EQ || cmpls.size()==1) + && okind3==OPND_G_REG ) { + x2 = icode==INST_CMP ? 0 : 1; + return A6(opcode, x2, ta, c, p1, p2, r2, r3, qp); + } else if (opnds[3]->isImm(8)) { + x2 = icode==INST_CMP ? 2 : 3; + return A8(opcode, x2, ta, c, p1, p2, imm8, r3, qp); + } else { + assert(r2==0); + x2 = icode==INST_CMP ? 0 : 1; + return A7(opcode, x2, ta, c, p1, p2, r3, qp); + } + +} + +//----------------------------------------------------------------------------// +uint64 Encoder::ldfx(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp) { + uint64 x6=0x02, hint=0; + int opndcount = opnds.size(); + int cmplcount = cmpls.size(); + + for (int i=0 ; i<cmplcount ; i++ ) { + switch (cmpls[i]) { + case CMPLT_FSZ_E: x6 = (x6 & 0x3C) | 0x00; break; + case CMPLT_FSZ_S: x6 = (x6 & 0x3C) | 0x02; break; + case CMPLT_FSZ_D: x6 = (x6 & 0x3C) | 0x03; break; + case CMPLT_LDTYPE_NORMAL: x6 = (x6 & 0x3) | (0x00 << 2); break; + case CMPLT_LDTYPE_S: x6 = (x6 & 0x3) | (0x01 << 2); break; + case CMPLT_LDTYPE_A: x6 = (x6 & 0x3) | (0x02 << 2); break; + case CMPLT_LDTYPE_SA: x6 = (x6 & 0x3) | (0x03 << 2); break; + case CMPLT_LDTYPE_C_CLR: x6 = (x6 & 0x3) | (0x08 << 2); break; + case CMPLT_LDTYPE_C_NC: x6 = (x6 & 0x3) | (0x09 << 2); break; + case CMPLT_HINT_NONE: hint=0; break; + case CMPLT_HINT_NT1: hint=1; break; + case CMPLT_HINT_NTA: hint=3; break; + default: assert(0); break; + } + } + + if (icode==INST_LDF_FILL ) { + x6 = 0x1B; + } else if (icode==INST_LDF8 ) { + x6 = (x6 & 0x3C) | 0x01; + } + if (opndcount>=4 && opnds[3]->isImm(9)) { + return M8(x6, hint, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else if (opndcount>=4 && opnds[3]->getOpndKind()==OPND_G_REG) { + return M7(x6, hint, opnds[2]->getValue(), opnds[3]->getValue() + , opnds[1]->getValue(), qp); + } else { + return M6(x6, hint, opnds[2]->getValue(), opnds[1]->getValue(), qp); + } +} + +//----------------------------------------------------------------------------// +uint64 Encoder::mov(InstructionType unit, InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp) { + OpndKind okind1 = opnds[1]->getOpndKind(); + OpndKind okind2 = opnds[2]->getOpndKind(); + uint64 o1 = opnds[1]->getValue(); + uint64 o2 = opnds[2]->getValue(); + + if (okind1 == OPND_A_REG && (okind2 == OPND_G_REG || opnds[2]->isImm(8))) { + if (unit==IT_I || o1==64) icode=INST_MOV_I; + else if (unit==IT_M) icode=INST_MOV_M; + else assert(0); + } + if (icode==INST_MOV_I) { + if (okind1==OPND_G_REG) return I28(o2, o1, qp); + else if (okind2==OPND_G_REG) return I26(o1, o2, qp); + else return I27(o1, o2, qp); + } else if (icode==INST_MOV_M) { + if (okind1==OPND_G_REG) return M31(o2, o1, qp); + else if (okind2==OPND_G_REG) return M29(o1, o2, qp); + else return M30(o1, o2, qp); + } else if (icode==INST_MOV) { + if (opnds.size()>=3) { + if (okind1==OPND_B_REG) { + uint64 timm9c=0, ih=0, wh=1; + + if (opnds.size()>3) + timm9c = opnds[3]->getValue(); + for (int i=0, ii=cmpls.size() ; i<ii ; i++){ + switch (cmpls[i]) { + case CMPLT_IH_IMP: ih=1; break; + case CMPLT_WH_DPTK: wh=2; break; + case CMPLT_WH_SPTK: wh=0; break; + default: break; + } + } + return I21(timm9c, ih, 0, wh, o2, o1, qp); + } else if (okind2==OPND_B_REG) { + return I22(o2, o1, qp); + } + /* + if (okind1==OPND_F_REG && okind2==OPND_F_REG) return IT_F; + if (okind1==OPND_G_REG && okind2==OPND_IP_REG) return IT_I; + if (okind1==OPND_G_REG && okind2==OPND_P_REG) return IT_I; + if (okind1==OPND_P_REG && okind2==OPND_G_REG) return IT_I; + if (okind1==OPND_P_REG && okind2==OPND_IMM44) return IT_I; + if (okind1==OPND_UM_REG && okind2==OPND_UM_REG) return IT_M; + if (okind1==OPND_G_REG && okind2==OPND_G_REG && cmpls.size()==0) + return IT_A; + if (okind1==OPND_G_REG && okind2==OPND_G_REG && cmpls.size()==1 + && cmpls[0]>=CMPLT_IREG_FIRST && cmpls[0]<=CMPLT_IREG_LAST) + return IT_M; + */ + } + } + IPF_ERR << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED INSTRUCTION: " + << Encoder::getMnemonic(icode) << "\n"; + assert(0); + + return 0x0123456789ABCDEF; +} + +//----------------------------------------------------------------------------// +void Encoder::readBundle(uint64 *code, uint64 * tmplt, uint64 * slots) +{ + *tmplt = code[0] & 0x01F; + slots[0] = (code[0] >> 5) & 0x1FFFFFFFFFF; + slots[1] = (code[0] >> 46) | ((code[1] & 0x7FFFFF) << 18); + slots[2] = (code[1] >> 23); +} + +//----------------------------------------------------------------------------// +bool Encoder::patchCallAddr(BinaryRewritingInterface & binaryRewritingInterface + , char * callAddr, char * methodAddr) +{ + uint64 p[2]; + uint64 s[3]; + uint64 t; + + // init + p[0] = ((uint64 *)callAddr)[0]; + p[1] = ((uint64 *)callAddr)[1]; + readBundle(p, &t, s); + + // target64 = IP + ((i << 59 | imm39 << 20 | imm20b) << 4) + uint64 i, imm39, imm20b, imm60; + + imm60 = ((methodAddr - callAddr) >> 4) & 0xFFFFFFFFFFFFFFF; + i = imm60 >> 59; + imm39 = (imm60 >> 20) & 0x7FFFFFFFFF; + imm20b = imm60 & 0xFFFFF; + + s[2] = s[2] & ~((uint64)0x1 << 36); + s[2] |= i << 36; + + s[1] = imm39 << 2; + + s[2] = s[2] & ~((uint64)0xFFFFF << 13); + s[2] |= imm20b << 13; + + // write to buffer + p[0] = t | (s[0] << 5); + p[0] |= s[1] << 46; + p[1] = s[1] >> 18; + p[1] |= s[2] << 23; + + // write to callAddr + binaryRewritingInterface.rewriteCodeBlock((Byte *)callAddr, + (Byte *)p, + IPF_BUNDLE_SIZE); + +// IPF_LOG << "Patch brl.call to 0x" << hex +// << (uint64)methodAddr << " at 0x" << (uint64)callAddr << "\n" +// << dec << "\n"; + return true; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfInst.cpp vm/jitrino/src/codegenerator/ipf/IpfInst.cpp new file mode 100755 index 0000000..52589d4 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfInst.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Inst +//========================================================================================// + +Inst::Inst(InstCode instCode_, Opnd *op1, Opnd *op2, Opnd *op3, Opnd *op4, Opnd *op5, Opnd *op6) { + + instCode = instCode_; + if(op1 != NULL) opndList.push_back(op1); + if(op2 != NULL) opndList.push_back(op2); + if(op3 != NULL) opndList.push_back(op3); + if(op4 != NULL) opndList.push_back(op4); + if(op5 != NULL) opndList.push_back(op5); + if(op6 != NULL) opndList.push_back(op6); +} + +//----------------------------------------------------------------------------------------// + +Inst::Inst(InstCode instCode_, Completer comp1, + Opnd *op1, Opnd *op2, Opnd *op3, Opnd *op4, Opnd *op5, Opnd *op6) { + + instCode = instCode_; + compList.push_back(comp1); + if(op1 != NULL) opndList.push_back(op1); + if(op2 != NULL) opndList.push_back(op2); + if(op3 != NULL) opndList.push_back(op3); + if(op4 != NULL) opndList.push_back(op4); + if(op5 != NULL) opndList.push_back(op5); + if(op6 != NULL) opndList.push_back(op6); +} + +//----------------------------------------------------------------------------------------// + +Inst::Inst(InstCode instCode_, Completer comp1, Completer comp2, + Opnd *op1, Opnd *op2, Opnd *op3, Opnd *op4, Opnd *op5, Opnd *op6) { + + instCode = instCode_; + compList.push_back(comp1); + compList.push_back(comp2); + if(op1 != NULL) opndList.push_back(op1); + if(op2 != NULL) opndList.push_back(op2); + if(op3 != NULL) opndList.push_back(op3); + if(op4 != NULL) opndList.push_back(op4); + if(op5 != NULL) opndList.push_back(op5); + if(op6 != NULL) opndList.push_back(op6); +} + +//----------------------------------------------------------------------------------------// + +Inst::Inst(InstCode instCode_, Completer comp1, Completer comp2, Completer comp3, + Opnd *op1, Opnd *op2, Opnd *op3, Opnd *op4, Opnd *op5, Opnd *op6) { + + instCode = instCode_; + compList.push_back(comp1); + compList.push_back(comp2); + compList.push_back(comp3); + if(op1 != NULL) opndList.push_back(op1); + if(op2 != NULL) opndList.push_back(op2); + if(op3 != NULL) opndList.push_back(op3); + if(op4 != NULL) opndList.push_back(op4); + if(op5 != NULL) opndList.push_back(op5); + if(op6 != NULL) opndList.push_back(op6); +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfInstCodeSelector.cpp vm/jitrino/src/codegenerator/ipf/IpfInstCodeSelector.cpp new file mode 100755 index 0000000..1acabc8 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfInstCodeSelector.cpp @@ -0,0 +1,2999 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "DrlVMInterface.h" +#include "MemoryAttribute.h" +#include "IpfCodeSelector.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +#define HEAPBASE (opndManager->getHeapBase()) +#define VTABLEBASE (opndManager->getVtableBase()) + +//===========================================================================// +// IpfInstCodeSelector +//===========================================================================// + +IpfInstCodeSelector::IpfInstCodeSelector(Cfg &cfg_, + BbNode &node_, + OpndVector &opnds_, + CompilationInterface &compilationInterface_) : + mm(cfg_.getMM()), + cfg(cfg_), + node(node_), + opnds(opnds_), + compilationInterface(compilationInterface_) { + + opndManager = cfg.getOpndManager(); + numFpInArgs = 0; + p0 = opndManager->getP0(); +} + +//----------------------------------------------------------------------------// +// InstructionCallback implementation +//----------------------------------------------------------------------------// + +//----------------------------------------------------------------------------// +// Add numeric values + +CG_OpndHandle *IpfInstCodeSelector::add(ArithmeticOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " add; opType=" << opType << endl; + + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + add(dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Subtract numeric values + +CG_OpndHandle *IpfInstCodeSelector::sub(ArithmeticOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " sub" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + sub(dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Multiply numeric values + +CG_OpndHandle *IpfInstCodeSelector::mul(ArithmeticOp::Types opType, + CG_OpndHandle *src1_, + CG_OpndHandle *src2_) { + + IPF_LOG << " mul" << endl; + + RegOpnd *src1 = toRegOpnd(src1_); + RegOpnd *src2 = toRegOpnd(src2_); + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType));; + RegOpnd *f0 = opndManager->getF0(); + + if (dst->isFloating()) { + Completer cmplt = CMPLT_PC_DYNAMIC; + + switch (dst->getDataKind()) { + case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; + case DATA_S: cmplt = CMPLT_PC_SINGLE; break; + default: IPF_ERR << "bad data kind for float mul\n"; break; + } + addNewInst(INST_FMA, cmplt, p0, dst, src1, src2, f0); + } else { + xma(INST_XMA_L, dst, src1, src2); + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Add integer to a reference + +CG_OpndHandle *IpfInstCodeSelector::addRef(RefArithmeticOp::Types opType, + CG_OpndHandle *refSrc, + CG_OpndHandle *intSrc) { + + IPF_LOG << " addRef" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + add(dst, refSrc, intSrc); + return dst; +} + +//----------------------------------------------------------------------------// +// Subtract integer from a reference + +CG_OpndHandle *IpfInstCodeSelector::subRef(RefArithmeticOp::Types opType, + CG_OpndHandle *refSrc, + CG_OpndHandle *intSrc) { + + IPF_LOG << " subRef" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + sub(dst, refSrc, intSrc); + return dst; +} + +//----------------------------------------------------------------------------// +// Subtract reference from reference + +CG_OpndHandle *IpfInstCodeSelector::diffRef(bool ovf, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " diffRef" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + sub(dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Subtract reference from reference and scale down by element type. + +CG_OpndHandle *IpfInstCodeSelector::scaledDiffRef(CG_OpndHandle *src1_, + CG_OpndHandle *src2_, + Type *type1, + Type *type2) { + + IPF_LOG << " scaledDiffRef" << endl; + IPF_ASSERT(type1->isManagedPtr() && type1==type2); + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + Type *elemType = ((PtrType *)type1)->getPointedToType(); + uint32 size = IpfType::getSize(toDataKind(elemType->tag)); + uint32 shift = 0; + + switch(size) { + case 1 : shift = 0; break; + case 2 : shift = 1; break; + case 4 : shift = 2; break; + case 8 : shift = 3; break; + default: IPF_ASSERT(0); return NULL; + } + + addNewInst(INST_SUB, p0, dst, src1, src2); + if(shift == 0) return dst; + + RegOpnd *scaledDst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + addNewInst(INST_SHR, p0, scaledDst, dst, opndManager->newImm(shift)); + return scaledDst; +} + +//----------------------------------------------------------------------------// +// Divide two numeric values + +CG_OpndHandle *IpfInstCodeSelector::tau_div(DivOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2, + CG_OpndHandle *tau_src1NonZero) { + + IPF_LOG << " tau_div" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + + switch (opType) { + case DivOp::I4: divInt (dst, src1, src2); break; + case DivOp::I : + case DivOp::I8: divLong (dst, src1, src2); break; + case DivOp::F : + case DivOp::D : divDouble(dst, src1, src2); break; + case DivOp::S : divFloat (dst, src1, src2); break; + default : IPF_ERR << "unexpected type " << opType << endl; + } + return dst; +} + +//----------------------------------------------------------------------------// +// Get remainder from the division of two numeric values +// On IPF computing integer remainder from division by zero does not result in hardware exception + +CG_OpndHandle *IpfInstCodeSelector::tau_rem(DivOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2, + CG_OpndHandle *tau_src2NonZero) { + + IPF_LOG << " tau_rem; opType=" << opType << endl; + + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + + if (dst->isFloating()) { + if (dst->getDataKind()==DATA_D) { + divDouble(dst, src1, src2, true); + } else { + divFloat(dst, src1, src2, true); + } + } else { + if (dst->getSize() > 4) { + divLong(dst, src1, src2, true); + } else { + divInt (dst, src1, src2, true); + } + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Negate numeric value + +CG_OpndHandle *IpfInstCodeSelector::neg(NegOp::Types opType, + CG_OpndHandle *src_) { + + IPF_LOG << " neg" << endl; + + RegOpnd *src = toRegOpnd(src_); + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + RegOpnd *r0 = opndManager->getR0(); + + if (dst->isFloating()) addNewInst(INST_FNEG, p0, dst, src); + else addNewInst(INST_SUB, p0, dst, r0, src); + + return dst; +} + +//----------------------------------------------------------------------------// +// Min + +CG_OpndHandle *IpfInstCodeSelector::min_op(NegOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " min_op" << endl; + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + + minMax(dst, src1, src2, false); + return dst; +} + +//----------------------------------------------------------------------------// +// Max + +CG_OpndHandle *IpfInstCodeSelector::max_op(NegOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " max_op" << endl; + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + + minMax(dst, src1, src2, true); + return dst; +} + +//----------------------------------------------------------------------------// +// Abs + +CG_OpndHandle *IpfInstCodeSelector::abs_op(NegOp::Types opType, + CG_OpndHandle *src_) { + RegOpnd *src = toRegOpnd(src_); + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); + + if (dst->isFloating()) { + // TODO: check all the peculiarities of Math.min/max + addNewInst(INST_FABS, p0, dst, src); + } else { + // cmp.lt truePred, falsePred = src, 0 + // (truePred) dst = src + // (falsePred) dst = -src + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *r0 = opndManager->getR0(src); + + cmp(CMPLT_CMP_CREL_LT, truePred, falsePred, src, r0); + addNewInst(INST_MOV, truePred, dst, src); + addNewInst(INST_SUB, falsePred, dst, r0, src); + } + return dst; +} + +//----------------------------------------------------------------------------// +// Logical and + +CG_OpndHandle *IpfInstCodeSelector::and_(IntegerOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " and_ " << endl; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + + binOp(INST_AND, dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Logical or + +CG_OpndHandle *IpfInstCodeSelector::or_(IntegerOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " or_ " << endl; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + + binOp(INST_OR, dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Logical xor + +CG_OpndHandle *IpfInstCodeSelector::xor_(IntegerOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " xor_ " << endl; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + + binOp(INST_XOR, dst, src1, src2); + return dst; +} + +//----------------------------------------------------------------------------// +// Logical not + +CG_OpndHandle *IpfInstCodeSelector::not_(IntegerOp::Types opType, + CG_OpndHandle *src) { + + IPF_LOG << " not_ " << endl; + + uint64 val = 0; + if (opType == IntegerOp::I4) val = 0xFFFFFFFF; + else val = 0xFFFFFFFFFFFFFFFFL; + + Opnd *allOnes = opndManager->newImm(val); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + + binOp(INST_XOR, dst, src, allOnes); + return dst; +} + +//----------------------------------------------------------------------------// +// Shift left + +CG_OpndHandle *IpfInstCodeSelector::shl(IntegerOp::Types opType, + CG_OpndHandle *value, + CG_OpndHandle *shiftAmount) { + + IPF_LOG << " shl " << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + Opnd *shiftcount = (Opnd *)shiftAmount; + int bits = 5; + + switch (opType) { + case IntegerOp::I: + case IntegerOp::I4: bits = 5; break; + case IntegerOp::I8: bits = 6; break; + } + + shift(INST_SHL, dst, value, shiftcount, bits); + return dst; +} + +//----------------------------------------------------------------------------// +// Shift right + +CG_OpndHandle *IpfInstCodeSelector::shr(IntegerOp::Types opType, + CG_OpndHandle *value, + CG_OpndHandle *shiftAmount) { + + IPF_LOG << " shr " << endl; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + int bits = 5; + + switch (opType) { + case IntegerOp::I: + case IntegerOp::I4: bits = 5; break; + case IntegerOp::I8: bits = 6; break; + } + + if (opType == IntegerOp::I4 && ((Opnd *)value)->getDataKind()==DATA_I32) { + sxt(value, 32); + } + shift(INST_SHR, dst, value, shiftAmount, bits); + return dst; +} + +//----------------------------------------------------------------------------// +// Shift right unsigned + +CG_OpndHandle *IpfInstCodeSelector::shru(IntegerOp::Types opType, + CG_OpndHandle *value, + CG_OpndHandle *shiftAmount) { + + IPF_LOG << " shru " << endl; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + int bits = 5; + + switch (opType) { + case IntegerOp::I: + case IntegerOp::I4: bits = 5; break; + case IntegerOp::I8: bits = 6; break; + } + + if (opType == IntegerOp::I4 && ((Opnd *)value)->getDataKind()==DATA_I32) { + zxt(value, 32); + } + shift(INST_SHR_U, dst, value, shiftAmount, bits); + return dst; +} + +//----------------------------------------------------------------------------// +// Shift left and add + +CG_OpndHandle *IpfInstCodeSelector::shladd(IntegerOp::Types opType, + CG_OpndHandle *value_, + uint32 imm, + CG_OpndHandle *addto_) { + + IPF_LOG << " shladd " << endl; + IPF_ASSERT(imm>=1 && imm<=4); + + RegOpnd *value = toRegOpnd(value_); + RegOpnd *addto = toRegOpnd(addto_); + Opnd *count = opndManager->newImm(imm); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); + + sxt(value, dst->getSize()); + sxt(addto, dst->getSize()); + addNewInst(INST_SHLADD, p0, dst, value, count, addto); + return dst; +} + +//----------------------------------------------------------------------------// +// Convert to integer + +CG_OpndHandle *IpfInstCodeSelector::convToInt(ConvertToIntOp::Types opType, + bool isSigned, + ConvertToIntOp::OverflowMod ovfMod, + Type *dstType, + CG_OpndHandle *src_) { + + RegOpnd *src = toRegOpnd(src_); + IPF_LOG << " convToInt " << IrPrinter::toString(src); + IPF_LOG << " to " << Type::tag2str(dstType->tag) ; + IPF_LOG << "; opType=" << opType << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); + + if (src->isFloating()) { + // convert fp to int (signed saturating conversion) + if (dst->getSize() > 4) saturatingConv8(dst, src); + else saturatingConv4(dst, src); + } else { + // convert int to int + Completer cmplt = CMPLT_INVALID; + switch (opType) { + case ConvertToIntOp::I1: cmplt = CMPLT_XSZ_1; break; + case ConvertToIntOp::I2: cmplt = CMPLT_XSZ_2; break; + case ConvertToIntOp::I4: cmplt = CMPLT_XSZ_4; break; + default : break; + } + + InstCode instCode = dst->isSigned() ? INST_SXT : INST_ZXT; + if (cmplt == CMPLT_INVALID) addNewInst(INST_MOV, p0, dst, src); + else addNewInst(instCode, cmplt, p0, dst, src); + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Convert to floating-point + +CG_OpndHandle *IpfInstCodeSelector::convToFp(ConvertToFpOp::Types opType, + Type *dstType, + CG_OpndHandle *src_) { + + IPF_LOG << " convToFp" << endl; + + RegOpnd *src = toRegOpnd(src_); + DataKind srcDataKind = src->getDataKind(); + DataKind dstDataKind = toDataKind(dstType->tag); + + if (dstDataKind == srcDataKind) return src; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, dstDataKind); + + if (src->isFloating()) { + // convert from fp to fp + Completer cmplt = dstDataKind == DATA_D ? CMPLT_PC_DOUBLE : CMPLT_PC_SINGLE; + addNewInst(INST_FNORM, cmplt, p0, dst, src); + } else { + // convert from int to fp + bool isSigned = (opType != ConvertToFpOp::FloatFromUnsigned); + InstCode instCode = (isSigned ? INST_FCVT_XUF : INST_FCVT_XF); + sxt(src, 8); + addNewInst(INST_SETF_SIG, p0, dst, src); + addNewInst(instCode, p0, dst, dst); + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Load 32-bit integer constant + +CG_OpndHandle *IpfInstCodeSelector::ldc_i4(uint32 val) { + + IPF_LOG << " ldc_i4" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + ldc(dst, (int64)((int32)val)); + + return dst; +} + +//----------------------------------------------------------------------------// +// Load 64-bit integer constant + +CG_OpndHandle *IpfInstCodeSelector::ldc_i8(uint64 val) { + + IPF_LOG << " ldc_i8" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + ldc(dst, (int64)val); + + return dst; +} + +//----------------------------------------------------------------------------// +// Load single FP constant + +CG_OpndHandle *IpfInstCodeSelector::ldc_s(float val) { + + IPF_LOG << " ldc_s" << endl; + + FloatConstant *fc = new(mm) FloatConstant(val); + ConstantRef *constref = opndManager->newConstantRef(fc); + RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_S); + + addNewInst(INST_MOVL, p0, r3, constref); + addNewInst(INST_LDF, CMPLT_FSZ_S, p0, dst, r3); + + return dst; +} + +//----------------------------------------------------------------------------// +// Load double FP constant + +CG_OpndHandle *IpfInstCodeSelector::ldc_d(double val) { + + IPF_LOG << " ldc_d" << endl; + + DoubleConstant *fc = new(mm) DoubleConstant(val); + ConstantRef *constref = opndManager->newConstantRef(fc); + RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + + addNewInst(INST_MOVL, p0, r3, constref); + addNewInst(INST_LDF, CMPLT_FSZ_D, p0, dst, r3); + + return dst; +} + +//----------------------------------------------------------------------------// +// Load Null + +CG_OpndHandle *IpfInstCodeSelector::ldnull(bool compressed) { + + IPF_LOG << " ldnull; compressed = " << boolalpha << compressed << endl; + + if (opndManager->areRefsCompressed() == false) { + return opndManager->getR0(); + } + + if (compressed) { + return opndManager->getR0(); + } else { + return HEAPBASE; + } +} + +//----------------------------------------------------------------------------// +// Load variable + +CG_OpndHandle *IpfInstCodeSelector::ldVar(Type *dstType, uint32 varId) { + + IPF_LOG << " ldVar " << Type::tag2str(dstType->tag) << " " << varId << endl; + + if (opnds[varId] == opndManager->getTau()) { + IPF_LOG << " tau operation - ignore" << endl; + return opndManager->getTau(); + } + + RegOpnd *src = toRegOpnd(opnds[varId]); + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); + + sxt(src, dst->getSize()); + addNewInst(INST_MOV, p0, dst, src); + return dst; +} + +//----------------------------------------------------------------------------// +// Store variable + +void IpfInstCodeSelector::stVar(CG_OpndHandle *src, uint32 varId) { + + IPF_LOG << " stVar" << endl; + + if (src==opndManager->getTau() || opnds[varId]==opndManager->getTau()) { + IPF_LOG << " tau operation - ignore" << endl; + return; + } + + IPF_ASSERT(opnds[varId]->isReg()); + addNewInst(INST_MOV, p0, opnds[varId], src); +} + +//----------------------------------------------------------------------------// +// Define an argument + +CG_OpndHandle *IpfInstCodeSelector::defArg(uint32 inArgPosition, Type *type) { + + DataKind dataKind = toDataKind(type->tag); + OpndKind opndKind = toOpndKind(type->tag); + int32 location = LOCATION_INVALID; + bool isFp = type->isFloatingPoint(); + + if (inArgPosition < MAX_REG_ARG) { + if (isFp) location = F_INARG_BASE + numFpInArgs++; + else location = opndManager->newInReg(inArgPosition); + } else { + location = opndManager->newInSlot(inArgPosition); // location is area local offset + } + + RegOpnd *arg = opndManager->newRegOpnd(opndKind, dataKind, location); + IPF_LOG << " defArg " << IrPrinter::toString(arg) << " " << type->getName() << endl; + +// addNewInst(INST_DEF, p0, arg); // artificial def for in arg opnd + if (isFp) { + RegOpnd *newarg = opndManager->newRegOpnd(opndKind, dataKind); + addNewInst(INST_MOV, p0, newarg, arg); // if fp arg crosses call site + arg = newarg; // it will be moved on preserved reg + } + + return arg; +} + +//----------------------------------------------------------------------------// +// Compare two values. Result is an integer. + +CG_OpndHandle *IpfInstCodeSelector::cmp(CompareOp::Operators cmpOp, + CompareOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " cmp; opType=" << opType << endl; + + InstCode instCode = toInstCmp(opType); + bool isFloating = (instCode == INST_FCMP); + Completer crel = toCmpltCrel(cmpOp, isFloating); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *r0 = opndManager->getR0(); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + + cmp(instCode, crel, truePred, falsePred, src1, src2); +// addNewInst(INST_DEF, p0, dst); + addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); + addNewInst(INST_MOV, falsePred, dst, r0); + + return dst; +} + +//----------------------------------------------------------------------------// +// Check if operand is equal to zero. Result is integer. + +CG_OpndHandle *IpfInstCodeSelector::czero(CompareZeroOp::Types opType, + CG_OpndHandle *src) { + + IPF_LOG << " czero" << endl; + + InstCode instCode = toInstCmp(opType); + Completer crel = CMPLT_CMP_CREL_EQ; + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *r0 = opndManager->getR0(); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + + cmp(instCode, crel, truePred, falsePred, src, r0); +// addNewInst(INST_DEF, p0, dst); + addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); + addNewInst(INST_MOV, falsePred, dst, r0); + + return dst; +} + +//----------------------------------------------------------------------------// +// Check if operand is not equal to zero. Result is integer. + +CG_OpndHandle *IpfInstCodeSelector::cnzero(CompareZeroOp::Types opType, + CG_OpndHandle *src) { + + IPF_LOG << " cnzero" << endl; + + InstCode instCode = toInstCmp(opType); + Completer crel = CMPLT_CMP_CREL_NE; + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *r0 = opndManager->getR0(); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + + cmp(instCode, crel, truePred, falsePred, src, r0); +// addNewInst(INST_DEF, p0, dst); + addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); + addNewInst(INST_MOV, falsePred, dst, r0); + + return dst; +} + +//----------------------------------------------------------------------------// +// Copy operand + +CG_OpndHandle *IpfInstCodeSelector::copy(CG_OpndHandle *src_) { + + IPF_LOG << " copy" << endl; + + if ((Opnd *)src_ == opndManager->getTau()) { + IPF_LOG << " tau operation - ignore" << endl; + return src_; + } + + RegOpnd *src = toRegOpnd(src_); + RegOpnd *dst = opndManager->newRegOpnd(src->getOpndKind(), src->getDataKind()); + + addNewInst(INST_MOV, p0, dst, src); + return dst; +} + +//----------------------------------------------------------------------------// +// Statically cast object to type. +// This cast requires no runtime check. It's a compiler assertion. + +CG_OpndHandle *IpfInstCodeSelector::tau_staticCast(ObjectType *toType, + CG_OpndHandle *obj, + CG_OpndHandle *tauIsType) { + + IPF_LOG << " tau_staticCast" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(toType->tag)); + + addNewInst(INST_MOV, p0, dst, obj); + return dst; +} + +//----------------------------------------------------------------------------// +// Branch if result of cmp is true + +void IpfInstCodeSelector::branch(CompareOp::Operators cmpOp, + CompareOp::Types opType, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + IPF_LOG << " branch" << endl; + + InstCode instCode = toInstCmp(opType); + bool isFloating = (instCode == INST_FCMP); + Completer crel = toCmpltCrel(cmpOp, isFloating); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + NodeRef *target = opndManager->newNodeRef(); + + cmp(instCode, crel, truePred, p0, src1, src2); + addNewInst(INST_BR, CMPLT_BTYPE_COND, truePred, target); +} + +//----------------------------------------------------------------------------// +// Branch if src is zero + +void IpfInstCodeSelector::bzero(CompareZeroOp::Types opType, + CG_OpndHandle *src) { + + IPF_LOG << " bzero" << endl; + IPF_ASSERT(((Opnd *)src)->isReg()); + + InstCode instCode = toInstCmp(opType); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + NodeRef *target = opndManager->newNodeRef(); + RegOpnd *zero = NULL; + + if (opType==CompareZeroOp::Ref && opndManager->areRefsCompressed()) { + zero = HEAPBASE; // if refs are compressed - zero is HEAPBASE + } else { + zero = opndManager->getR0((RegOpnd *)src); // get "0" corresponding to src size/sign + } + + cmp(instCode, CMPLT_CMP_CREL_EQ, truePred, p0, src, zero); + addNewInst(INST_BR, CMPLT_BTYPE_COND, truePred, target); +} + +//----------------------------------------------------------------------------// +// Branch if src is not zero + +void IpfInstCodeSelector::bnzero(CompareZeroOp::Types opType, + CG_OpndHandle *src) { + + IPF_LOG << " bnzero" << endl; + IPF_ASSERT(((Opnd *)src)->isReg()); + + InstCode instCode = toInstCmp(opType); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + NodeRef *target = opndManager->newNodeRef(); + RegOpnd *zero = NULL; + + if (opType==CompareZeroOp::Ref && opndManager->areRefsCompressed()) { + zero = HEAPBASE; // if refs are compressed - zero is HEAPBASE + } else { + zero = opndManager->getR0((RegOpnd *)src); // get "0" corresponding to src size/sign + } + + cmp(instCode, CMPLT_CMP_CREL_NE, truePred, p0, src, zero); + addNewInst(INST_BR, CMPLT_BTYPE_COND, truePred, target); +} + +//----------------------------------------------------------------------------// +// Switch +// +// cmp.eq p8,p9 = r0, r0 // set p8 = true +// cmp.lt.unc p6,p7 = maxTgt, trg // if target is greater than +// // max target p6=true p7=false +// (p7) cmp.ne.and p8,p7 = fallThroughTgt, trg // if target is fall through target +// // p7=false p8=false +// (p6) mov tgt = defTgt // target is default target +// (p8) mov tgtAddr = switchTblAddr // load switch table address +// (p8) shladd r14 = trg, 3, tgtAddr // calculate switch table address +// // containing target address +// (p8) ld8 r14 = [r14] // load target address +// (p8) mov b1 = r14 // load target address to branch register +// (p8) br.cond.sptk b1 // branch to target +// // if p8 is false - fall through + +void IpfInstCodeSelector::tableSwitch(CG_OpndHandle *src, uint32 nTargets) { + + IPF_LOG << " tableSwitch" << endl; + + Constant *switchTable = new(mm) SwitchConstant(); + + Opnd *r0 = opndManager->getR0(); + Opnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // default target is taken + Opnd *p7 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // check fall through target + Opnd *p8 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // fall through is not taken + Opnd *switchTblAddr = opndManager->newConstantRef(switchTable, DATA_SWITCH_REF); // switch table address + Opnd *tgtValue = (Opnd *)src; + Opnd *maxTgtValue = opndManager->newImm(nTargets-1); // max target value + Opnd *defTgtValue = opndManager->newImm(0); // default target value + Opnd *fallThroughTgtValue = opndManager->newImm(0); // FT target value + Opnd *tgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // target + Opnd *maxTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // max target + Opnd *defTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // default target + Opnd *fallThroughTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // FT target + Opnd *shlCnt = opndManager->newImm(3); + Opnd *tgtAddr = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + Opnd *branchTgt = opndManager->newRegOpnd(OPND_B_REG, DATA_I64); + + // mov to maxTgtValue, defTgtValue, fallThroughTgtValue to GRs + addNewInst(INST_MOV, p0, tgt, tgtValue); + addNewInst(INST_MOV, p0, maxTgt, maxTgtValue); + addNewInst(INST_MOV, p0, defTgt, defTgtValue); + addNewInst(INST_MOV, p0, fallThroughTgt, fallThroughTgtValue); + // just make 1 in p8 + addNewInst(INST_CMP4, CMPLT_CMP_CREL_EQ, p0, p8, p0, r0, r0); + // compare with default + addNewInst(INST_CMP4, CMPLT_CMP_CREL_GT, CMPLT_CMP_CTYPE_UNC, p0, p6, p7, tgt, maxTgt); + + Inst *tmpinst = new(mm) Inst(INST_CMP4, CMPLT_CMP_CREL_LT, CMPLT_CMP_CTYPE_OR_ANDCM, p7, p6, p7, tgt, r0); + tmpinst->addOpnd(p6); + tmpinst->addOpnd(p7); + node.addInst(tmpinst); + + addNewInst(INST_MOV, p6, tgt, defTgt); + // compare if through target + addNewInst(INST_CMP4, CMPLT_CMP_CREL_NE, CMPLT_CMP_CTYPE_AND, p0, p8, p0, fallThroughTgt, tgt, p8); + // if not through target load tgt Address + addNewInst(INST_MOV, p8, tgtAddr, switchTblAddr); + addNewInst(INST_SHLADD, p8, tgtAddr, tgt, shlCnt, tgtAddr); + addNewInst(INST_LD, CMPLT_SZ_8, p8, tgtAddr, tgtAddr); + addNewInst(INST_MOV, p8, branchTgt, tgtAddr); + addNewInst(INST_SWITCH, p8, branchTgt, switchTblAddr, defTgtValue, fallThroughTgtValue); +} + +//----------------------------------------------------------------------------// +// Direct call to the method + +CG_OpndHandle *IpfInstCodeSelector::call(uint32 numArgs, + CG_OpndHandle **args, + Type *retType, + MethodDesc *desc, + InlineInfo *ii) { + + return tau_call(numArgs, args, retType, desc, NULL, NULL, ii); +} + +//----------------------------------------------------------------------------// +// Direct call to the method + +CG_OpndHandle *IpfInstCodeSelector::tau_call(uint32 numArgs, + CG_OpndHandle **args, + Type *retType, + MethodDesc *desc, + CG_OpndHandle *tauNullCheckedFirstArg, + CG_OpndHandle *tauTypesChecked, + InlineInfo *ii) { + + IPF_LOG << " tau_call; method=" << desc->getName() + << ", desc=" << desc << ", addr=0x" << hex << *((uint64 *)desc->getIndirectAddress()) + << dec << endl; + + MethodRef *methodRef = opndManager->newMethodRef(desc); + RegOpnd *retOpnd = NULL; + + if(retType != NULL) { + retOpnd = opndManager->newRegOpnd(toOpndKind(retType->tag), toDataKind(retType->tag)); + } + + directCall(numArgs, (Opnd **)args, retOpnd, methodRef, p0); + + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Indirect call + +CG_OpndHandle *IpfInstCodeSelector::tau_calli(uint32 numArgs, + CG_OpndHandle **args, + Type *retType, + CG_OpndHandle *methodPtr, + CG_OpndHandle *nonNullFirstArgTau, + CG_OpndHandle *tauTypesChecked, + InlineInfo *ii) { + + IPF_LOG << " tau_calli; numArgs=" << numArgs + << ", retType=" << (retType ? Type::tag2str(retType->tag) : "NULL") << endl; + IPF_ASSERT(((Opnd *)methodPtr)->isReg()); + + RegOpnd *retOpnd = NULL; + if(retType != NULL) { + retOpnd = opndManager->newRegOpnd(toOpndKind(retType->tag), toDataKind(retType->tag)); + } + + indirectCall(numArgs, (Opnd **)args, retOpnd, (RegOpnd *)methodPtr, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Intrinsic call + +CG_OpndHandle *IpfInstCodeSelector::tau_callintr(uint32 numArgs, + CG_OpndHandle **args, + Type *retType, + IntrinsicCallOp::Id callId, + CG_OpndHandle *tauNullsChecked, + CG_OpndHandle *tauTypesChecked) { + + IPF_LOG << " tau_callintr" << endl; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_CharArrayCopy; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + RegOpnd *retOpnd = NULL; + + if(retType != NULL) + retOpnd = opndManager->newRegOpnd(toOpndKind(retType->tag), toDataKind(retType->tag)); + + directCall(numArgs, (Opnd **) args, retOpnd, helperAddress, p0); + + return retOpnd; +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::ret() { + + IPF_LOG << " ret" << endl; + + RegOpnd *b0 = opndManager->getB0(); + addNewInst(INST_BR, CMPLT_BTYPE_RET, p0, b0); +} + +//----------------------------------------------------------------------------// +// Return with a value + +void IpfInstCodeSelector::ret(CG_OpndHandle *retValue_) { + + IPF_LOG << " ret" << endl; + + RegOpnd *retValue = toRegOpnd(retValue_); + RegOpnd *b0 = opndManager->getB0(); + RegOpnd *retOpnd = NULL; + if(retValue->isFloating()) retOpnd = opndManager->newRegOpnd(OPND_F_REG, DATA_F, RET_F_REG); + else retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_I64, RET_G_REG); + + addNewInst(INST_MOV, p0, retOpnd, retValue); + addNewInst(INST_BR, CMPLT_BTYPE_RET, p0, b0, retOpnd); +} + +//----------------------------------------------------------------------------// +// Throw an exception + +void IpfInstCodeSelector::throwException(CG_OpndHandle *exceptionObj, bool createStackTrace) { + + IPF_LOG << " throwException; createStackTrace=" << createStackTrace << endl; + + Opnd *helperArgs[] = { (Opnd *)exceptionObj }; + + CompilationInterface::RuntimeHelperId hId; + if (createStackTrace) hId = CompilationInterface::Helper_Throw_SetStackTrace; + else hId = CompilationInterface::Helper_Throw_KeepStackTrace; + + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Throw system exception + +void IpfInstCodeSelector::throwSystemException(CompilationInterface::SystemExceptionId id) { + + IPF_LOG << " throwSystemException" << endl; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_Null; + switch (id) { + case CompilationInterface::Exception_NullPointer: + hId = CompilationInterface::Helper_NullPtrException; break; + case CompilationInterface::Exception_ArrayIndexOutOfBounds: + hId = CompilationInterface::Helper_ArrayBoundsException; break; + case CompilationInterface::Exception_ArrayTypeMismatch: + hId = CompilationInterface::Helper_ElemTypeException; break; + case CompilationInterface::Exception_DivideByZero: + hId = CompilationInterface::Helper_DivideByZeroException; break; + default: + IPF_ERR << "unexpected id " << id << endl; + } + + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(0, NULL, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Throw linking exception + +void IpfInstCodeSelector::throwLinkingException(Class_Handle encClass, + uint32 cp_ndx, + uint32 opcode) +{ + + IPF_LOG << " throwLinkingException" << endl; + + Opnd *helperArgs[] = { + opndManager->newImm((int64) encClass), + opndManager->newImm(cp_ndx), + opndManager->newImm(opcode) + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_Throw_LinkingException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(3, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Copy exception object from r8 to new RegOpnd + +CG_OpndHandle *IpfInstCodeSelector::catchException(Type *exceptionType) { + + IPF_LOG << " catchException" << endl; + + RegOpnd *exceptionObj = opndManager->newRegOpnd(OPND_G_REG, DATA_U64, RET_G_REG); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + + addNewInst(INST_DEF, p0, exceptionObj); + addNewInst(INST_MOV, p0, dst, exceptionObj); + return dst; +} + +//----------------------------------------------------------------------------// +// Throw null pointer exception if base is NULL + +CG_OpndHandle *IpfInstCodeSelector::tau_checkNull(CG_OpndHandle *base, bool checksThisForInlinedMethod) { + + IPF_LOG << " tau_checkNull" << endl; + IPF_ASSERT(((Opnd *)base)->isReg()); + + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *zero = NULL; + + if (opndManager->areRefsCompressed()) { + zero = HEAPBASE; + } else { + zero = opndManager->getR0((RegOpnd *)base); + } + + // p0 cmp.eq p2, p0 = base, zero + cmp(CMPLT_CMP_CREL_EQ, truePred, p0, base, zero); + + // p2 brl.call b0 = helperAddress + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_NullPtrException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau) +} + +//----------------------------------------------------------------------------// +// Throw index out of range exception if index is larger than array length + +CG_OpndHandle *IpfInstCodeSelector::tau_checkBounds(CG_OpndHandle *arrayLen, + CG_OpndHandle *index) { + + IPF_LOG << " tau_checkBounds" << endl; + + // p0 cmp.ge p2, p0 = index, arrayLen + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + cmp(CMPLT_CMP_CREL_GE, truePred, p0, index, arrayLen); + + // p2 brl.call b0 = helperAddress + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_ArrayBoundsException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau); +} + +//----------------------------------------------------------------------------// +// Throw index out of range exception if (a > b) + +CG_OpndHandle *IpfInstCodeSelector::tau_checkLowerBound(CG_OpndHandle *a, + CG_OpndHandle *b) { + + IPF_LOG << " tau_checkLowerBound" << endl; + + // p0 cmp.gt p2, p0 = a, b + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + cmp(CMPLT_CMP_CREL_GT, truePred, p0, a, b); + + // p2 brl.call b0 = helperAddress + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_ArrayBoundsException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau); +} + +//----------------------------------------------------------------------------// +// Throw index out of range exception if (a >=u b) + +CG_OpndHandle *IpfInstCodeSelector::tau_checkUpperBound(CG_OpndHandle *a, + CG_OpndHandle *b) { + + IPF_LOG << " tau_checkUpperBound" << endl; + + // p0 cmp.ge p2, p0 = a, b + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + cmp(CMPLT_CMP_CREL_GEU, truePred, p0, a, b); + + // p2 brl.call b0 = helperAddress + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_ArrayBoundsException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau); +} + +//----------------------------------------------------------------------------// +// p0 brl.call b0, Helper_IsValidElemType +// p0 mov retOpnd, r8 +// p0 cmp p3, p0 = retOpnd, r0 +// p3 brl.call b0, Helper_ElemTypeException + +CG_OpndHandle *IpfInstCodeSelector::tau_checkElemType(CG_OpndHandle *array, + CG_OpndHandle *src, + CG_OpndHandle *tauNullChecked, + CG_OpndHandle *tauIsArray) { + + IPF_LOG << " tau_checkElemType" << endl; + + Opnd *helperArgs[] = { + (Opnd *)src, + (Opnd *)array + }; + + // p0 brl.call b0, Helper_IsValidElemType + // p0 mov retOpnd, r8 + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_IsValidElemType; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress1 = opndManager->newImm(address); + RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + directCall(2, helperArgs, retOpnd, helperAddress1, p0); + + // p0 cmp p3, p0 = retOpnd, r0 + RegOpnd *r0 = opndManager->getR0(retOpnd); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + cmp(CMPLT_CMP_CREL_EQ, truePred, p0, retOpnd, r0); + + // p3 brl.call b0, Helper_ElemTypeException + hId = CompilationInterface::Helper_ElemTypeException; + address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress2 = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress2, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau); +} + +//----------------------------------------------------------------------------// +// Throw DivideByZeroException if checkZero's argument is 0 + +CG_OpndHandle *IpfInstCodeSelector::tau_checkZero(CG_OpndHandle *src_) { + + IPF_LOG << " tau_checkZero" << endl; + + // p0 cmp.eq p2, p0 = base, r0 + RegOpnd *src = toRegOpnd(src_); + RegOpnd *r0 = opndManager->getR0(src); + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + cmp(CMPLT_CMP_CREL_EQ, truePred, p0, src, r0); + + // p2 brl.call b0 = helperAddress + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_DivideByZeroException; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(0, NULL, NULL, helperAddress, truePred); + + return opndManager->getTau(); // return fake value (we do not use tau) +} + +//----------------------------------------------------------------------------// +// Cast object to type and return the tau tied to this cast if casting is legal, +// otherwise throw an exception. +// checkCast is different from cast - checkCast returns the tau while cast returns +// the casted object (which is the same as the argument object) + +CG_OpndHandle *IpfInstCodeSelector::tau_checkCast(ObjectType *toType, + CG_OpndHandle *obj, + CG_OpndHandle *tauCheckedNull) { + + IPF_LOG << " tau_checkCast" << endl; + + Opnd *helperArgs[] = { + (Opnd *)obj, + (Opnd *)opndManager->newImm((uint64) toType->getRuntimeIdentifier()) + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_Cast; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + directCall(2, helperArgs, NULL, helperAddress, p0); + + return opndManager->getTau(); // return fake value (we do not use tau) +} + +//----------------------------------------------------------------------------// +// Store indirect + +void IpfInstCodeSelector::tau_stInd(CG_OpndHandle *src_, + CG_OpndHandle *ptr_, + Type::Tag memType, + bool autoCompressRef, + CG_OpndHandle *tauBaseNonNull, + CG_OpndHandle *tauAddressInRange, + CG_OpndHandle *tauElemTypeChecked) { + + IPF_LOG << " tau_stInd" << endl; + + DataKind dataKind = toDataKind(memType); + InstCode instCode = IpfType::isFloating(dataKind) ? INST_STF : INST_ST; + Completer cmplt = toCmpltSz(dataKind); + RegOpnd *src = toRegOpnd(src_); + RegOpnd *ptr = toRegOpnd(ptr_); + + if (autoCompressRef) { + IPF_ASSERT(opndManager->areRefsCompressed()); + dataKind = DATA_U32; + cmplt = toCmpltSz(dataKind); + RegOpnd *tmp = opndManager->newRegOpnd(OPND_G_REG, dataKind); + sub(tmp, src, HEAPBASE); + + addNewInst(instCode, cmplt, p0, ptr, tmp); + } else { + addNewInst(instCode, cmplt, p0, ptr, src); + } +} + +//----------------------------------------------------------------------------// +// Load indirect + +CG_OpndHandle *IpfInstCodeSelector::tau_ldInd(Type *dstType, + CG_OpndHandle *ptr_, + Type::Tag memType, + bool autoUncompressRef, + bool speculateLoad, + CG_OpndHandle *tauBaseNonNull, + CG_OpndHandle *tauAddressInRange) { + + IPF_LOG << " tau_ldInd;" + << " dstType=" << Type::tag2str(dstType->tag) + << ", memType=" << Type::tag2str(memType) + << ", autoUncompressRef=" << autoUncompressRef << endl; + + DataKind dataKind = toDataKind(memType); + InstCode instCode = IpfType::isFloating(dataKind) ? INST_LDF : INST_LD; + Completer cmplt = toCmpltSz(dataKind); + RegOpnd *ptr = toRegOpnd(ptr_); + RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); + + if (autoUncompressRef) { + IPF_ASSERT(opndManager->areRefsCompressed()); + cmplt = toCmpltSz(DATA_U32); + addNewInst(instCode, cmplt, p0, dst, ptr); + add(dst, dst, HEAPBASE); + } else { + addNewInst(instCode, cmplt, p0, dst, ptr); + sxt(dst, 8, cmplt); + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Load string + +CG_OpndHandle *IpfInstCodeSelector::ldString(MethodDesc *enclosingMethod, + uint32 stringToken, + bool uncompress) { + + IPF_LOG << " ldString" << endl; + + Opnd *helperArgs[] = { + opndManager->newImm(stringToken), + opndManager->newImm((int64) enclosingMethod->getParentType()->getRuntimeIdentifier()) + }; + + RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_LdString; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(2, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Load address of the object lock +// (aka lock owner field in the synchronization header) + +CG_OpndHandle *IpfInstCodeSelector::ldLockAddr(CG_OpndHandle *obj) { + + IPF_LOG << " ldLockAddr(" << IrPrinter::toString((Opnd *)obj) << ")" << endl; + + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); + Opnd *offset = opndManager->newImm(LOC_OFFSET); + + add(dst, offset, obj); + return dst; +} + +//----------------------------------------------------------------------------// +// Load address of the virtual/interface table slot that contains function address + +CG_OpndHandle *IpfInstCodeSelector::tau_ldVirtFunAddr(Type *dstType, + CG_OpndHandle *vtableAddr, + MethodDesc *methodDesc, + CG_OpndHandle *tauVtableHasDesc) { + + IPF_LOG << " tau_ldVirtFunAddr; dstType==" << Type::tag2str(dstType->tag) + << ", method=" << methodDesc->getName() << endl; + IPF_ASSERT(((Opnd *)vtableAddr)->isReg()); + + uint64 offsetVal = methodDesc->getOffset(); // get method offset in class VTable + Opnd *offset = opndManager->newImm(offsetVal); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + + add(dst, offset, vtableAddr); + addNewInst(INST_LD, CMPLT_SZ_8, p0, dst, dst); + return dst; +} + +//----------------------------------------------------------------------------// +// Load virtual table address + +CG_OpndHandle *IpfInstCodeSelector::tau_ldVTableAddr(Type *dstType, + CG_OpndHandle *base, + CG_OpndHandle *tauBaseNonNull) { + + IPF_LOG << " tau_ldVTableAddr; dstType==" << Type::tag2str(dstType->tag) << endl; + IPF_ASSERT(((Opnd *)base)->isReg()); + + Opnd *offset = opndManager->getVtableOffset(); + RegOpnd *vtable = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); + RegOpnd *addr = NULL; + + if(offset == NULL) { // if VTable has offset 0 - base represents VTable address + addr = (RegOpnd *)base; + } else { + addr = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); + add(addr, offset, base); + } + + Completer completer = CMPLT_INVALID; + if(opndManager->areVtablePtrsCompressed()) completer = CMPLT_SZ_4; + else completer = CMPLT_SZ_8; + + addNewInst(INST_LD, completer, p0, vtable, addr); + + if (dstType->tag==Type::VTablePtr && opndManager->areVtablePtrsCompressed()) { + add(vtable, vtable, VTABLEBASE); + } + + return vtable; +} + +//----------------------------------------------------------------------------// +// get vtable constant (a constant pointer) + +CG_OpndHandle *IpfInstCodeSelector::getVTableAddr(Type *dstType, + ObjectType *base) { + + IPF_LOG << " getVTableAddr; dstType==" << Type::tag2str(dstType->tag) << endl; + + uint64 value = (uint64) base->getVTable(); + + if (dstType->tag==Type::VTablePtr && opndManager->areVtablePtrsCompressed()) { + value += (uint64) compilationInterface.getVTableBase(); + } + + Opnd *addr = opndManager->newImm(value); + return addr; +} + +//----------------------------------------------------------------------------// +// Load interface table address + +CG_OpndHandle *IpfInstCodeSelector::tau_ldIntfTableAddr(Type *dstType, + CG_OpndHandle *base, + NamedType *vtableType) { + + IPF_LOG << " tau_ldIntfTableAddr; dstType==" << Type::tag2str(dstType->tag) + << "; vtableType=" << Type::tag2str(vtableType->tag) << endl; + + Opnd *helperArgs[] = { + (Opnd *)base, + (Opnd *)opndManager->newImm((uint64) vtableType->getRuntimeIdentifier()) + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_LdInterface; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + RegOpnd *retOpnd = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); + + directCall(2, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Load address of the field at "base + offset" + +CG_OpndHandle *IpfInstCodeSelector::ldFieldAddr(Type *fieldRefType, + CG_OpndHandle *base, + FieldDesc *fieldDesc) { + + IPF_LOG << " ldFieldAddr " << fieldDesc->getName() + << "(" << Type::tag2str(fieldRefType->tag) << ")" << endl; + + Opnd *fieldOffset = opndManager->newImm(fieldDesc->getOffset()); + RegOpnd *fieldAddress = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); + + add(fieldAddress, fieldOffset, base); + return fieldAddress; +} + +//----------------------------------------------------------------------------// +// Load static field address + +CG_OpndHandle *IpfInstCodeSelector::ldStaticAddr(Type *fieldRefType, FieldDesc *fieldDesc) { + + IPF_LOG << " ldStaticAddr " << fieldDesc->getName() + << "(" << Type::tag2str(fieldRefType->tag) << ")"; + + Opnd *dst = opndManager->newImm((uint64) fieldDesc->getAddress()); + IPF_LOG << " addr is " << IrPrinter::toString(dst) << endl; + return dst; +} + +//----------------------------------------------------------------------------// +// Check if an object has given type. +// If it is return 1 else return 0. + +CG_OpndHandle *IpfInstCodeSelector::tau_instanceOf(ObjectType *type, + CG_OpndHandle *obj, + CG_OpndHandle *tauCheckedNull) { + IPF_LOG << " tau_instanceOf" << endl; + + Opnd *helperArgs[] = { + (Opnd *)obj, + opndManager->newImm((uint64) type->getRuntimeIdentifier()) + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_IsInstanceOf; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); + + directCall(2, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Initialize type + +void IpfInstCodeSelector::initType(Type *type) { + + IPF_LOG << " initType" << endl; + IPF_ASSERT(type->isObject()); + + uint64 typeRuntimeId = (uint64) type->asNamedType()->getRuntimeIdentifier(); + Opnd *helperArgs[] = { opndManager->newImm(typeRuntimeId) }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_InitType; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Create new object + +CG_OpndHandle *IpfInstCodeSelector::newObj(ObjectType *objType) { + + IPF_LOG << " newObj" << endl; + + Opnd *helperArgs[] = { + opndManager->newImm((int64) objType->getObjectSize()), + opndManager->newImm((int64) objType->getAllocationHandle()) + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_NewObj_UsingVtable; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + OpndKind opndKind = toOpndKind(objType->tag); + DataKind dataKind = toDataKind(objType->tag); + RegOpnd *retOpnd = opndManager->newRegOpnd(opndKind, dataKind); + + directCall(2, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Create new array + +CG_OpndHandle *IpfInstCodeSelector::newArray(ArrayType *arrayType, + CG_OpndHandle *numElems) { + + IPF_LOG << " newArray of " << arrayType->getElementType()->getName() << endl; + + Opnd *helperArgs[] = { + opndManager->newImm((int64) arrayType->getAllocationHandle()), + (Opnd *)numElems + }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_NewVector_UsingVtable; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); + + directCall(2, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} + +//----------------------------------------------------------------------------// +// Create multi-dimensional new array + +CG_OpndHandle *IpfInstCodeSelector::newMultiArray(ArrayType *arrayType, + uint32 numDims, + CG_OpndHandle **dims) { + + Opnd *helperArgs[2 + numDims]; + + helperArgs[0] = opndManager->newImm((uint64)arrayType->getRuntimeIdentifier()); + helperArgs[1] = opndManager->newImm(numDims); + for (uint32 i = 0; i < numDims; i++) { + helperArgs[i + 2] = (Opnd *)dims[numDims - 1 - i]; + } + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_NewMultiArray; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); + + directCall(2 + numDims, helperArgs, retOpnd, helperAddress, p0); + return retOpnd; +} +//----------------------------------------------------------------------------// +// Compute address of the first array element + +CG_OpndHandle *IpfInstCodeSelector::ldElemBaseAddr(CG_OpndHandle *array) { + + IPF_LOG << " ldElemBaseAddr " << endl; + + Opnd *offset = opndManager->newImm(opndManager->getElemBaseOffset()); + RegOpnd *elemBase = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); + add(elemBase, offset, array); + + return elemBase; +} + +//----------------------------------------------------------------------------// +// Compute address of the array element given +// address of the first element and index + +CG_OpndHandle *IpfInstCodeSelector::addElemIndex(Type *elemType, + CG_OpndHandle *elemBase_, + CG_OpndHandle *index_) { + + IPF_LOG << " addElemIndex; type=" << Type::tag2str(elemType->tag) << endl; + + RegOpnd *elemBase = toRegOpnd(elemBase_); + RegOpnd *index = toRegOpnd(index_); + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + int16 elemSize = IpfType::getSize(toDataKind(elemType->tag)); + int16 countVal = 0; + + switch(elemSize) { + case 1 : countVal = -1; break; + case 2 : countVal = 1; break; + case 4 : countVal = 2; break; + case 8 : countVal = 3; break; + case 16 : countVal = 0; break; + default : IPF_ERR << "elemSize =" << elemSize << endl; + } + + if(countVal >= 0) { + Opnd *count = opndManager->newImm(countVal); + addNewInst(INST_SHLADD, p0, dst, index, count, elemBase); + } else { + addNewInst(INST_ADD, p0, dst, index, elemBase); + } + + return dst; +} + +//----------------------------------------------------------------------------// +// Load array length + +CG_OpndHandle *IpfInstCodeSelector::tau_arrayLen(Type *dstType, + ArrayType *arrayType, + Type *lenType, + CG_OpndHandle *base, + CG_OpndHandle *tauArrayNonNull, + CG_OpndHandle *tauIsArray) { + + IPF_LOG << " tau_arrayLen" << endl; + + uint64 offset = arrayType->getArrayLengthOffset(); + Opnd *offsetOpnd = opndManager->newImm(offset); + RegOpnd *addr = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); + add(addr, offsetOpnd, base); + + return tau_ldInd(dstType, addr, lenType->tag, false, false, NULL, NULL); +} + +//----------------------------------------------------------------------------// +// Acquire monitor for an object + +void IpfInstCodeSelector::tau_monitorEnter(CG_OpndHandle *obj, + CG_OpndHandle *tauIsNonNull) { + + IPF_LOG << " tau_monitorEnter" << endl; + + Opnd *helperArgs[] = { (Opnd *)obj }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_ObjMonitorEnter; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Release monitor for an object + +void IpfInstCodeSelector::tau_monitorExit(CG_OpndHandle *obj, + CG_OpndHandle *tauIsNonNull) { + + IPF_LOG << " tau_monitorExit" << endl; + + Opnd *helperArgs[] = { (Opnd *)obj }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_ObjMonitorExit; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Acquire monitor for a class + +void IpfInstCodeSelector::typeMonitorEnter(NamedType *type) { + + IPF_LOG << " typeMonitorEnter" << endl; + + uint64 typeRuntimeId = (uint64) type->getRuntimeIdentifier(); + Opnd *helperArgs[] = { opndManager->newImm(typeRuntimeId) }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_TypeMonitorEnter; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Release monitor for a class + +void IpfInstCodeSelector::typeMonitorExit(NamedType *type) { + + IPF_LOG << " typeMonitorExit" << endl; + + uint64 typeRuntimeId = (uint64) type->getRuntimeIdentifier(); + Opnd *helperArgs[] = { opndManager->newImm(typeRuntimeId) }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_TypeMonitorExit; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(1, helperArgs, NULL, helperAddress, p0); +} + +//----------------------------------------------------------------------------// +// Wrapper around balanced monitor enter. Set cmpxchg role to BalancedMonitorEnter + +CG_OpndHandle *IpfInstCodeSelector::tau_balancedMonitorEnter(CG_OpndHandle *obj, + CG_OpndHandle *lockAddr, + CG_OpndHandle *tauIsNonNull) { + IPF_LOG << " tau_balancedMonitorEnter" << endl; + + tau_monitorEnter(obj, tauIsNonNull); + return opndManager->getR0(); +} + +//----------------------------------------------------------------------------// +// Balanced monitor exit + +void IpfInstCodeSelector::balancedMonitorExit(CG_OpndHandle *obj, + CG_OpndHandle *lockAddr, + CG_OpndHandle *oldLock) { + IPF_LOG << " balancedMonitorExit" << endl; + + tau_monitorExit(obj, NULL); +} + +//----------------------------------------------------------------------------// +// CG helper protected methods +//----------------------------------------------------------------------------// + +//----------------------------------------------------------------------------// +// Create direct call to the method + +void IpfInstCodeSelector::directCall(uint32 numArgs, + Opnd **args, + RegOpnd *retOpnd, + Opnd *methodAddress, + RegOpnd *pred) { + + RegOpnd *b0 = opndManager->getB0(); + RegOpnd *convOpnd = makeConvOpnd(retOpnd); + Inst *callInst = new(mm) Inst(INST_BRL13, CMPLT_BTYPE_CALL, CMPLT_WH_SPTK, CMPLT_PH_MANY + , pred, convOpnd, b0, methodAddress); + + opndManager->setContainCall(true); // set flag OpndManager::containCall + makeCallArgs(numArgs, args, callInst, pred); // add instructions moving args in appropriate locations + + node.addInst(callInst); // add "call" inst + makeRetVal(retOpnd, convOpnd, pred); // add instruction moving ret value from r8/f8 +} + +//----------------------------------------------------------------------------// +// Create indirect call to the method + +void IpfInstCodeSelector::indirectCall(uint32 numArgs, + Opnd **args, + RegOpnd *retOpnd, + RegOpnd *methodPtr, + RegOpnd *pred) { + + RegOpnd *b0 = opndManager->getB0(); + RegOpnd *convOpnd = makeConvOpnd(retOpnd); + RegOpnd *callTgt = opndManager->newRegOpnd(OPND_B_REG, DATA_U64); + Inst *ldAddress = new(mm) Inst(INST_MOV, pred, callTgt, methodPtr); + Inst *callInst = new(mm) Inst(INST_BR13, CMPLT_BTYPE_CALL, pred, convOpnd, b0, callTgt); + + opndManager->setContainCall(true); // set flag OpndManager::containCall (method contains call) + makeCallArgs(numArgs, args, callInst, pred); // add instructions moving args in appropriate locations + + node.addInst(ldAddress); // add inst loading method address + node.addInst(callInst); // add "call" inst + makeRetVal(retOpnd, convOpnd, pred); // add instruction moving ret value from r8/f8 +} + +//----------------------------------------------------------------------------// +// Move out args in regs and stack positions according with IPF software convention + +void IpfInstCodeSelector::makeCallArgs(uint32 numArgs, Opnd **args, Inst *callInst, RegOpnd *pred) { + + int16 numFpOutArgs = 0; + for(uint32 argPosition=0; argPosition<numArgs; argPosition++) { + + Opnd *opnd = args[argPosition]; + OpndKind opndKind = OPND_INVALID; + DataKind dataKind = DATA_INVALID; + InstCode instCode = INST_INVALID; + int32 location = LOCATION_INVALID; + bool isFp = opnd->isFloating(); + + if (opnd->isReg() == true) { // opnd is register + opndKind = opnd->getOpndKind(); // outArg has the same opndKind + dataKind = opnd->getDataKind(); // outArg has the same dataKind + instCode = INST_MOV; + } else { // opnd is imm + opndKind = OPND_G_REG; + dataKind = DATA_U64; + instCode = opnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; + } + + if (argPosition < MAX_REG_ARG) { // arg is going on register + if (isFp) location = F_OUTARG_BASE + numFpOutArgs++; // real location + else location = opndManager->newOutReg(argPosition); // temporary location + } else { // arg is going on stack + location = opndManager->newOutSlot(argPosition); // location is area local offset + } + + Opnd *outArg = opndManager->newRegOpnd(opndKind, dataKind, location); + addNewInst(instCode, pred, outArg, opnd); + callInst->addOpnd(outArg); // add the opnd in call opnds list (for data flow analysis) + } +} + +//----------------------------------------------------------------------------// +// make opnd representing return value of method (r8/f8) + +RegOpnd *IpfInstCodeSelector::makeConvOpnd(RegOpnd *retOpnd) { + + if(retOpnd == NULL) return opndManager->getR0(); // method has return type "void" + + OpndKind opndKind = retOpnd->getOpndKind(); + DataKind dataKind = retOpnd->getDataKind(); + int32 location = LOCATION_INVALID; + + if (retOpnd->isFloating()) location = RET_F_REG; + else location = RET_G_REG; + + return opndManager->newRegOpnd(opndKind, dataKind, location); +} + +//----------------------------------------------------------------------------// +// create mov to free r8/f8 + +void IpfInstCodeSelector::makeRetVal(RegOpnd *retOpnd, RegOpnd *convOpnd, RegOpnd *pred) { + + if(retOpnd == NULL) return; // method has return type "void" + + addNewInst(INST_MOV, pred, retOpnd, convOpnd); +} + +//----------------------------------------------------------------------------// +// Generate "cmp" instruction for two opnds (int, float or imm). + +void IpfInstCodeSelector::cmp(InstCode instCode, + Completer cmpRelation, + RegOpnd *truePred, + RegOpnd *falsePred, + CG_OpndHandle *src1_, + CG_OpndHandle *src2_) { + + RegOpnd *src1 = toRegOpnd(src1_); + RegOpnd *src2 = toRegOpnd(src2_); + + if (instCode == INST_CMP) { sxt(src1, 8); sxt(src2, 8); } + if (instCode == INST_CMP4) { sxt(src1, 4); sxt(src2, 4); } + + addNewInst(instCode, cmpRelation, p0, truePred, falsePred, src1, src2); +} + +//----------------------------------------------------------------------------// +// Choose and generate appropriate "cmp" instruction for two opnds (int, float or imm). + +void IpfInstCodeSelector::cmp(Completer cmpRelation, + RegOpnd *truePred, + RegOpnd *falsePred, + CG_OpndHandle *src1_, + CG_OpndHandle *src2_) { + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + + // fcmp + if (src1->isFloating() || src2->isFloating()) { + cmp(INST_FCMP, cmpRelation, truePred, falsePred, src1, src2); + return; + } + + // cmp + if (src1->getSize()>4 || src1->getSize()>4) { + cmp(INST_CMP, cmpRelation, truePred, falsePred, src1, src2); + return; + } + + // cmp4 + cmp(INST_CMP4, cmpRelation, truePred, falsePred, src1, src2); +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::sxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize) { + + Opnd *src = (Opnd *)src_; + + if (src->isReg() == false) return; // ignore non reg opnd (imm) + if (src->isFloating() == true) return; // ignore fp opnd + if (src->isSigned() == false) return; // ignore unsigned opnd + + Completer cmplt = (srcSize==CMPLT_INVALID ? toCmpltSz(src->getDataKind()) : srcSize); + int16 srcbytes = (cmplt==CMPLT_SZ_1 ? 1 : (cmplt==CMPLT_SZ_2 ? 2 : (cmplt==CMPLT_SZ_4?4:8))); + if (srcbytes >= refSize) return; // nothing to do + + addNewInst(INST_SXT, cmplt, p0, src, src); +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::zxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize) { + + Opnd *src = (Opnd *)src_; + + if (src->isReg() == false) return; // ignore non reg opnd (imm) + if (src->isFloating() == true) return; // ignore fp opnd + + Completer cmplt = (srcSize==CMPLT_INVALID?toCmpltSz(src->getDataKind()):srcSize); + int16 srcbytes = (cmplt==CMPLT_SZ_1?1:(cmplt==CMPLT_SZ_2?2:(cmplt==CMPLT_SZ_4?4:8))); + if (srcbytes >= refSize) return; // nothing to do + + addNewInst(INST_ZXT, cmplt, p0, src, src); +} + +//----------------------------------------------------------------------------// +// If opnd is imm this method generates "mov" from imm to gr + +RegOpnd *IpfInstCodeSelector::toRegOpnd(CG_OpndHandle *opnd_) { + + if(((Opnd *)opnd_)->isReg()) return (RegOpnd *)opnd_; + IPF_ASSERT(((Opnd *)opnd_)->isImm()); + + Opnd *opnd = (Opnd *)opnd_; + RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + InstCode instCode = opnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; + + addNewInst(instCode, p0, dst, opnd); + return dst; +} + +//----------------------------------------------------------------------------// +// Add int or fp values + +void IpfInstCodeSelector::add(RegOpnd *dst, CG_OpndHandle *src1_, CG_OpndHandle *src2_) { + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + + // fadd fr, fr + if(dst->isFloating()) { + Completer cmplt = CMPLT_PC_DYNAMIC; + + switch (dst->getDataKind()) { + case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; + case DATA_S: cmplt = CMPLT_PC_SINGLE; break; + default: IPF_ERR << "bad data kind for float add\n"; break; + } + addNewInst(INST_FADD, cmplt, p0, dst, src1, src2); + return; + } + + sxt(src1, dst->getSize()); // sxt src1 if appropriate + sxt(src2, dst->getSize()); // sxt src2 if appropriate + + // imm opnd must be on first position + if(src2->isImm()) { + Opnd *buf = src1; + src1 = src2; + src2 = toRegOpnd(buf); + } + + // add imm, gr + if (src1->isImm()) { + // imm14 + if(src1->isFoldableImm(14)) { + addNewInst(INST_ADDS, p0, dst, src1, src2); + return; + } + // imm + RegOpnd *buf = toRegOpnd(src1); + addNewInst(INST_ADD, p0, dst, buf, src2); + return; + } + + // add gr, gr + addNewInst(INST_ADD, p0, dst, src1, src2); +} + +//----------------------------------------------------------------------------// +// Sub int or fp values + +void IpfInstCodeSelector::sub(RegOpnd *dst, CG_OpndHandle *src1_, CG_OpndHandle *src2_) { + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + + // sub fr, fr + if(dst->isFloating()) { + Completer cmplt = CMPLT_PC_DYNAMIC; + + switch (dst->getDataKind()) { + case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; + case DATA_S: cmplt = CMPLT_PC_SINGLE; break; + default: IPF_ERR << "bad data kind for float sub\n"; break; + } + addNewInst(INST_FSUB, cmplt, p0, dst, src1, src2); + return; + } + + sxt(src1, dst->getSize()); // sxt src1 if appropriate + sxt(src2, dst->getSize()); // sxt src2 if appropriate + + // imm opnd must be on first position + if(src2->isImm()) { + Opnd *buf = src1; + src1 = src2; + src2 = toRegOpnd(buf); + } + + // sub imm, gr + if (src1->isImm()) { + + // imm8 + if(src1->isFoldableImm(8)) { + addNewInst(INST_SUB, p0, dst, src1, src2); + return; + } + + // imm + RegOpnd *buf = toRegOpnd(src1); + addNewInst(INST_SUB, p0, dst, buf, src2); + return; + } + + // sub gr, gr + addNewInst(INST_SUB, p0, dst, src1, src2); +} + +//----------------------------------------------------------------------------// +// Only INST_AND, INST_OR, INST_XOR + +void IpfInstCodeSelector::binOp(InstCode instCode, + RegOpnd *dst, + CG_OpndHandle *src1_, + CG_OpndHandle *src2_) { + + IPF_ASSERT(instCode==INST_AND || instCode==INST_OR || instCode==INST_XOR); + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + + // imm opnd must be on first position + if(src2->isImm()) { + Opnd *buf = src1; + src1 = src2; + src2 = toRegOpnd(buf); + } + + sxt(src1, dst->getSize()); // sxt src1 if appropriate + sxt(src2, dst->getSize()); // sxt src2 if appropriate + + // sub imm, gr + if (src1->isImm()) { + + // imm8 + if(src1->isFoldableImm(8)) { + addNewInst(instCode, p0, dst, src1, src2); + return; + } + + // imm + RegOpnd *buf = toRegOpnd(src1); + addNewInst(instCode, p0, dst, buf, src2); + return; + } + + // sub gr, gr + addNewInst(instCode, p0, dst, src1, src2); +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::shift(InstCode instCode, + RegOpnd *dst, + CG_OpndHandle *value_, + CG_OpndHandle *count_, + int bits) { + + RegOpnd *value = toRegOpnd(value_); + Opnd *count = (Opnd *)count_; + + sxt(value, dst->getSize()); + + if (count->isImm()) { + if (!count->isFoldableImm(bits)) { +// RegOpnd *tmp = toRegOpnd(count); +// +// addNewInst(INST_AND, p0, tmp, opndManager->newImm(bits==5?0x1F:0x2F), tmp); + count = opndManager->newImm(count->getValue() & (bits==5?0x1F:0x3F)); + } + } else { + RegOpnd *tmp = (RegOpnd *)count; + + if (value_==count_) { + tmp = opndManager->newRegOpnd(OPND_G_REG, count->getDataKind()); + addNewInst(INST_MOV, p0, tmp, count); + } + + addNewInst(INST_AND, p0, tmp, opndManager->newImm(bits==5?0x1F:0x3F), tmp); + count = tmp; + } + + // shx gr = gr, imm + if (count->isImm()) { + + // imm6 + if(count->isFoldableImm(6)) { + addNewInst(instCode, p0, dst, value, count); + return; + } + + // imm + RegOpnd *buf = toRegOpnd(count); + addNewInst(instCode, p0, dst, value, buf); + return; + } + + // shx gr = gr, gr + addNewInst(instCode, p0, dst, value, count); +} + +//----------------------------------------------------------------------------// +// Load N-bit integer constant + +void IpfInstCodeSelector::ldc(RegOpnd *dst, int64 val) { + +// if (val == 0) { +// IPF_LOG << " opnd \"r0\"" << endl; +// return dst->setLocation(0); +// } + + Opnd *immOpnd = opndManager->newImm(val); + InstCode instCode = immOpnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; + + addNewInst(instCode, p0, dst, immOpnd); +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::minMax(RegOpnd *dst, + CG_OpndHandle *src1_, + CG_OpndHandle *src2_, + bool max) { + + Opnd *src1 = (Opnd *)src1_; + Opnd *src2 = (Opnd *)src2_; + + if (dst->isFloating()) { + // TODO: check all the peculiarities of Math.min/max + InstCode instCode = max ? INST_FMAX : INST_FMIN; + addNewInst(instCode, p0, dst, src1, src2); + } else { + Completer crel = max ? CMPLT_CMP_CREL_LT : CMPLT_CMP_CREL_GT; + RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + + cmp(crel, truePred, falsePred, src1, src2); + addNewInst(INST_MOV, truePred, dst, src1); + addNewInst(INST_MOV, falsePred, dst, src2); + } +} + +//----------------------------------------------------------------------------// +// Generate instruction sequence for integer multiplication + +void IpfInstCodeSelector::xma(InstCode instCode, + RegOpnd *dst, + CG_OpndHandle *src1, + CG_OpndHandle *src2) { + + RegOpnd *f0 = opndManager->getF0(); + RegOpnd *buf1 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *buf2 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *dstF = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + + sxt(src1, 8); // sxt src1 if appropriate + sxt(src2, 8); // sxt src2 if appropriate + + addNewInst(INST_SETF_SIG, p0, buf1, src1); + addNewInst(INST_SETF_SIG, p0, buf2, src2); + addNewInst(instCode, p0, dstF, buf1, buf2, f0); + addNewInst(INST_GETF_SIG, p0, dst, dstF); +} + +//----------------------------------------------------------------------------// +// Convert floating-point to 64-bit integer with saturation +// +// ldfd tf1 = ALMOST_MAXINT8 (see below for details) +// mov t1 = -1 +// fcvt.fx tf2 = src +// fcmp.gt p1 = src, tf1 +// fcmp.unord p2 = src, src +// getf.sig dst = tf2 +// (p1) shr.u dst = t1, 1 +// (p2) mov dst = 0 +// + +void IpfInstCodeSelector::saturatingConv8(RegOpnd *dst, CG_OpndHandle *src_) { + + IPF_LOG << " saturatingConv8" << endl; + + IPF_ASSERT(((Opnd *)src_)->isFloating()); + + RegOpnd *src = (RegOpnd *)src_; + RegOpnd *tf1 = NULL; + RegOpnd *tf2 = opndManager->newRegOpnd(OPND_F_REG, src->getDataKind()); + RegOpnd *p1 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *p2 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *t1 = opndManager->newRegOpnd(OPND_G_REG, dst->getDataKind()); + + if (src->getDataKind() == DATA_S) { + // maximal int64 that is exactly representable in single FP format + tf1 = (RegOpnd *)ldc_s((float)__INT64_C(0x7fffff0000000000)); + } else { + // maximal int64 that is exactly representable in double FP format + int64 max_int64 = __INT64_C(0x7ffffffffffff800); + tf1 = (RegOpnd *)ldc_d((double)max_int64); + } + + sxt(src, 8); // sxt src if appropriate + addNewInst(INST_MOV, p0, t1, opndManager->newImm(-1)); + addNewInst(INST_FCVT_FX_TRUNC, p0, tf2, src); + addNewInst(INST_FCMP, CMPLT_CMP_CREL_GT, CMPLT_FCMP_FCTYPE_NONE, p0, p1, p0, src, tf1); + addNewInst(INST_FCMP, CMPLT_FCMP_FREL_UNORD, CMPLT_FCMP_FCTYPE_NONE, p0, p2, p0, src, src); + addNewInst(INST_GETF_SIG, p0, dst, tf2); + addNewInst(INST_SHR_U, p1, dst, t1, opndManager->newImm(1)); + addNewInst(INST_MOV, p2, dst, opndManager->newImm(0)); +} + +//----------------------------------------------------------------------------// +// Convert floating-point to 32-bit integer with saturation. Then sign/zero +// extend based on dstType. +// +// ldfd tf1 = MAXINT4 +// ldfd tf2 = MININT4 +// mov t1 = -1 +// fcvt.fx tf3 = src +// fcmp.gt p1 = src, tf1 +// fcmp.lt p2 = src, tf2 +// getf.sig t2 = tf3 +// sxt4 dst = t2 +// (p1) shr.u dst = t1, 33 +// (p2) shl dst = t1, 31 + +void IpfInstCodeSelector::saturatingConv4(RegOpnd *dst, CG_OpndHandle *src_) { + + IPF_ASSERT(((Opnd *)src_)->isFloating()); + + RegOpnd *src = (RegOpnd *)src_; + RegOpnd *p1 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *p2 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *t1 = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + RegOpnd *t2 = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); + RegOpnd *tf1 = NULL; + RegOpnd *tf2 = NULL; + RegOpnd *tf3 = opndManager->newRegOpnd(OPND_F_REG, src->getDataKind()); + + if (src->getDataKind() == DATA_S) { + tf1 = (RegOpnd *)ldc_s((float)0x7fffffff); + tf2 = (RegOpnd *)ldc_s((float)((int) 0x80000000)); + } else { + tf1 = (RegOpnd *)ldc_d((double)0x7fffffff); + tf2 = (RegOpnd *)ldc_d((double)((int) 0x80000000)); + } + + sxt(src, 8); // sxt src if appropriate + addNewInst(INST_MOV, p0, t1, opndManager->newImm(-1)); + addNewInst(INST_FCVT_FX_TRUNC, p0, tf3, src); + addNewInst(INST_FCMP, CMPLT_CMP_CREL_GT, p0, p1, p0, src, tf1); + addNewInst(INST_FCMP, CMPLT_CMP_CREL_LT, p0, p2, p0, src, tf2); + addNewInst(INST_GETF_SIG, p0, t2, tf3); + addNewInst(INST_SXT, CMPLT_XSZ_4, p0, dst, t2); + addNewInst(INST_SHR_U, p1, dst, t1, opndManager->newImm(33)); + addNewInst(INST_SHL, p2, dst, t1, opndManager->newImm(31)); +} + +//----------------------------------------------------------------------------// +// Divide two integer values. + +void IpfInstCodeSelector::divInt(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { + + IPF_ASSERT(((Opnd *)src1)->isReg()); + IPF_ASSERT(((Opnd *)src2)->isReg()); + + RegOpnd *f0 = opndManager->getF0(); + RegOpnd *f1 = opndManager->getF1(); + RegOpnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *f6 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f7 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f8 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f9 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f10 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + + sxt(src1, 8); + sxt(src2, 8); + + addNewInst(INST_SETF_SIG, p0, f10, src1); + addNewInst(INST_SETF_SIG, p0, f9, src2); + addNewInst(INST_FCVT_XF, p0, f6, f10); + addNewInst(INST_FCVT_XF, p0, f7, f9); + addNewInst(INST_MOV, p0, dst, opndManager->newImm(0x0ffdd)); + addNewInst(INST_SETF_EXP, p0, f9, dst); + + addNewInst(INST_FRCPA, p0, f8, p6, f6, f7); + addNewInst(INST_FMA, p6, f6, f6, f8, f0); + addNewInst(INST_FNMA, p6, f7, f7, f8, f1); + addNewInst(INST_FMA, p6, f6, f7, f6, f6); + addNewInst(INST_FMA, p6, f7, f7, f7, f9); + addNewInst(INST_FMA, p6, f8, f7, f6, f6); + addNewInst(INST_FCVT_FX_TRUNC, p0, f8, f8); + + if (rem) { + RegOpnd *msrc2 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + addNewInst(INST_SUB, p0, msrc2, opndManager->getR0(), src2); + addNewInst(INST_SETF_SIG, p0, f9, msrc2); + addNewInst(INST_XMA_L, p0, f8, f9, f8, f10); + } + + // result is in the least significant 32 bits of r8 (if b != 0) + addNewInst(INST_GETF_SIG, p0, dst, f8); +} + +//----------------------------------------------------------------------------// +// Divide two long values. + +void IpfInstCodeSelector::divLong(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { + + IPF_ASSERT(((Opnd *)src1)->isReg()); + IPF_ASSERT(((Opnd *)src2)->isReg()); + + RegOpnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *f0 = opndManager->getF0(); + RegOpnd *f1 = opndManager->getF1(); + RegOpnd *f6 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f7 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f8 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f9 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + RegOpnd *f10 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); + + sxt(src1, 8); + sxt(src2, 8); + + addNewInst(INST_SETF_SIG, p0, f10, src1); + addNewInst(INST_SETF_SIG, p0, f9, src2); + + addNewInst(INST_FCVT_XF, p0, f6, f10); + addNewInst(INST_FCVT_XF, p0, f7, f9); + + addNewInst(INST_FRCPA, p0, f8, p6, f6, f7); + addNewInst(INST_FNMA, p6, f9, f7, f8, f1); + addNewInst(INST_FMA, p6, f8, f9, f8, f8); + addNewInst(INST_FMA, p6, f9, f9, f9, f0); + addNewInst(INST_FMA, p6, f8, f9, f8, f8); + addNewInst(INST_FMA, p6, f9, f8, f6, f0); + addNewInst(INST_FNMA, p6, f7, f7, f9, f6); + addNewInst(INST_FMA, p6, f8, f7, f8, f9); + addNewInst(INST_FCVT_FX_TRUNC, p0, f8, f8); + + if (rem) { + RegOpnd *msrc2 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + addNewInst(INST_SUB, p0, msrc2, opndManager->getR0(), src2); + addNewInst(INST_SETF_SIG, p0, f9, msrc2); + addNewInst(INST_XMA_L, p0, f8, f9, f8, f10); + } + + addNewInst(INST_GETF_SIG, p0, dst, f8); +} + +//----------------------------------------------------------------------------// +// Divide two double values. + +void IpfInstCodeSelector::divDouble(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { + + IPF_ASSERT(((Opnd *)src1)->isReg()); + IPF_ASSERT(((Opnd *)src2)->isReg()); + + if (!rem) { + RegOpnd *f0 = opndManager->getF0(); + RegOpnd *f1 = opndManager->getF1(); + + RegOpnd *fRes = dst, *fA = (RegOpnd *)src1, *fB = (RegOpnd *)src2; + RegOpnd *pX = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *fe = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq0 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fe2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fy1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fe4 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fy2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fy3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fr = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + + // + // Group 0 + // frcpa.s0 fRes,pX = fA,fB + // Group 1 + // (pX) fnma.s1 fe = fRes,fB,f1 + // (pX) fmpy.s1 fq0 = fA,fRes + // Group 2 + // (pX) fmpy.s1 fe2 = fe,fe + // (pX) fma.s1 fq1 = fq0,fe,fq0 + // (pX) fma.s1 fy1 = fRes,fe,fRes + // Group 3 + // (pX) fmpy.s1 fe4 = fe2,fe2 + // (pX) fma.s1 fq2 = fq1,fe2,fq1 + // (pX) fma.s1 fy2 = fy1,fe2,fy1 + // Group 4 + // (pX) fma.d.s1 fq3 = fq2,fe4,fq2 + // (pX) fma.s1 fy3 = fy2,fe4,fy2 + // Group 5 + // (pX) fnma.s1 fr = fB,fq3,fA + // Group 6 + // (pX) fma.d.s0 fRes = fr,fy3,fq3 + // + addNewInst(INST_FRCPA, CMPLT_SF0, p0, fRes, pX, fA, fB); + + addNewInst(INST_FNMA, CMPLT_SF1, pX, fe, fRes, fB, f1); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq0, fA, fRes, f0); + + addNewInst(INST_FMA, CMPLT_SF1, pX, fe2, fe, fe, f0); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq1, fq0, fe, fq0); + addNewInst(INST_FMA, CMPLT_SF1, pX, fy1, fRes, fe, fRes); + + addNewInst(INST_FMA, CMPLT_SF1, pX, fe4, fe2, fe2, f0); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq2, fq1, fe2, fq1); + addNewInst(INST_FMA, CMPLT_SF1, pX, fy2, fy1, fe2, fy1); + + addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF1, pX, fq3, fq2, fe4, fq2); + addNewInst(INST_FMA, CMPLT_SF1, pX, fy3, fy2, fe4, fy2); + + addNewInst(INST_FNMA, CMPLT_SF1, pX, fr, fB, fq3, fA); + + addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF0, pX, fRes, fr, fy3, fq3); + } else { + // Call runtime helper to do FP remainder. We only inline the integer + // remainder sequence + // + Opnd *helperArgs[] = { (Opnd *)src1, (Opnd *)src2 }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_RemDouble; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(2, helperArgs, dst, helperAddress, p0); + } +} + +//----------------------------------------------------------------------------// +// Divide two float values. + +void IpfInstCodeSelector::divFloat(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { + + IPF_ASSERT(((Opnd *)src1)->isReg()); + IPF_ASSERT(((Opnd *)src2)->isReg()); + + if (!rem) { + RegOpnd *f0 = opndManager->getF0(); + RegOpnd *f1 = opndManager->getF1(); + + RegOpnd *fRes = dst, *fA = (RegOpnd *)src1, *fB = (RegOpnd *)src2; + RegOpnd *pX = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *fe = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq0 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fe2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fe4 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + RegOpnd *fq3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); + + // + // Group 0 + // frcpa.s0 fRes,pX = fA,fB + // Group 1 + // (pX) fnma.s1 fe = fRes,fB,f1 + // (pX) fmpy.s1 fq0 = fA,fRes + // Group 2 + // (pX) fmpy.s1 fe2 = fe,fe + // (pX) fma.s1 fq1 = fq0,fe,fq0 + // Group 3 + // (pX) fmpy.s1 fe4 = fe2,fe2 + // (pX) fma.s1 fq2 = fq1,fe2,fq1 + // Group 4 + // (pX) fma.d.s1 fq3 = fq2,fe4,fq2 + // (pX) fnorm.s.s0 fRes = fq3 + // + // Group 0 + addNewInst(INST_FRCPA, CMPLT_SF0, p0, fRes, pX, fA, fB); + + addNewInst(INST_FNMA, CMPLT_SF1, pX, fe, fRes, fB, f1); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq0, fA, fRes, f0); + + addNewInst(INST_FMA, CMPLT_SF1, pX, fe2, fe, fe, f0); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq1, fq0, fe, fq0); + + addNewInst(INST_FMA, CMPLT_SF1, pX, fe4, fe2, fe2, f0); + addNewInst(INST_FMA, CMPLT_SF1, pX, fq2, fq1, fe2, fq1); + + addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF1, pX, fq3, fq2, fe4, fq2); + addNewInst(INST_FNORM, CMPLT_PC_SINGLE, CMPLT_SF0, pX, fRes, fq3); + } else { + // Call runtime helper to do FP remainder. We only inline the integer + // remainder sequence + // + Opnd *helperArgs[] = { (Opnd *)src1, (Opnd *)src2 }; + + CompilationInterface::RuntimeHelperId hId = CompilationInterface::Helper_RemSingle; + uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); + Opnd *helperAddress = opndManager->newImm(address); + + directCall(2, helperArgs, dst, helperAddress, p0); + } +} + +//----------------------------------------------------------------------------// +// create new inst and add it in current node +//----------------------------------------------------------------------------// + +Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, + CG_OpndHandle *op1, + CG_OpndHandle *op2, + CG_OpndHandle *op3, + CG_OpndHandle *op4, + CG_OpndHandle *op5, + CG_OpndHandle *op6) { + + Inst* inst = new(mm) Inst(instCode, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, + (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); + node.addInst(inst); + return *inst; +} + +//----------------------------------------------------------------------------// + +Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, + Completer comp1, + CG_OpndHandle *op1, + CG_OpndHandle *op2, + CG_OpndHandle *op3, + CG_OpndHandle *op4, + CG_OpndHandle *op5, + CG_OpndHandle *op6) { + + Inst* inst = new(mm) Inst(instCode, comp1, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, + (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); + node.addInst(inst); + return *inst; +} + +//----------------------------------------------------------------------------// + +Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, + Completer comp1, + Completer comp2, + CG_OpndHandle *op1, + CG_OpndHandle *op2, + CG_OpndHandle *op3, + CG_OpndHandle *op4, + CG_OpndHandle *op5, + CG_OpndHandle *op6) { + + Inst* inst = new(mm) Inst(instCode, comp1, comp2, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, + (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); + node.addInst(inst); + return *inst; +} + +//----------------------------------------------------------------------------// +// convertors from HLO to CG types +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(Type::Tag tag) { + + switch(tag) { + case Type::Boolean : return DATA_U8; + case Type::Char : return DATA_U16; + case Type::Int8 : return DATA_I8; + case Type::Int16 : return DATA_I16; + case Type::Int32 : return DATA_I32; + case Type::Int64 : return DATA_I64; + case Type::UInt8 : return DATA_U8; + case Type::UInt16 : return DATA_U16; + case Type::UInt32 : return DATA_U32; + case Type::UInt64 : return DATA_U64; + case Type::IntPtr : return DATA_U64; + case Type::VTablePtr : return DATA_U64; + case Type::Single : return DATA_S; + case Type::Double : return DATA_D; + case Type::Float : return DATA_F; + case Type::Array : return DATA_BASE; + case Type::Object : return DATA_BASE; + case Type::NullObject : return DATA_BASE; + case Type::SystemObject : return DATA_BASE; + case Type::SystemString : return DATA_BASE; + case Type::ManagedPtr : return DATA_MPTR; + case Type::Tau : return DATA_INVALID; + case Type::CompressedSystemString : + case Type::CompressedSystemObject : + case Type::CompressedObject : + case Type::CompressedArray : return DATA_U32; + default : IPF_ERR << "unexpected tag " << Type::tag2str(tag) << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +OpndKind IpfInstCodeSelector::toOpndKind(Type::Tag tag) { + + switch(tag) { + case Type::Array : return OPND_G_REG; + case Type::Object : return OPND_G_REG; + case Type::NullObject : return OPND_G_REG; + case Type::SystemObject : return OPND_G_REG; + case Type::Boolean : return OPND_G_REG; + case Type::Char : return OPND_G_REG; + case Type::Int8 : return OPND_G_REG; + case Type::Int16 : return OPND_G_REG; + case Type::Int32 : return OPND_G_REG; + case Type::Int64 : return OPND_G_REG; + case Type::UInt8 : return OPND_G_REG; + case Type::UInt16 : return OPND_G_REG; + case Type::UInt32 : return OPND_G_REG; + case Type::UInt64 : return OPND_G_REG; + case Type::Single : return OPND_F_REG; + case Type::Double : return OPND_F_REG; + case Type::Float : return OPND_F_REG; + case Type::IntPtr : return OPND_G_REG; + case Type::ManagedPtr : return OPND_G_REG; + case Type::VTablePtr : return OPND_G_REG; + case Type::SystemString : return OPND_G_REG; + case Type::Tau : return OPND_INVALID; + default : IPF_ERR << "unexpected tag " << Type::tag2str(tag) << endl; + } + return OPND_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(IntegerOp::Types type) { + + switch(type) { + case IntegerOp::I4 : return DATA_I32; + case IntegerOp::I8 : return DATA_I64; + case IntegerOp::I : return DATA_U64; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(NegOp::Types type) { + + switch (type) { + case NegOp::F : return DATA_F; + case NegOp::D : return DATA_D; + case NegOp::S : return DATA_S; + case NegOp::I4 : return DATA_I32; + case NegOp::I : + case NegOp::I8 : return DATA_I64; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +OpndKind IpfInstCodeSelector::toOpndKind(NegOp::Types type) { + + switch (type) { + case NegOp::F : + case NegOp::D : + case NegOp::S : return OPND_F_REG; + case NegOp::I4 : + case NegOp::I : + case NegOp::I8 : return OPND_G_REG; + default : IPF_ERR << "unexpected type " << type << endl; + } + return OPND_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(ArithmeticOp::Types type) { + + switch (type) { + case ArithmeticOp::F : return DATA_F; + case ArithmeticOp::D : return DATA_D; + case ArithmeticOp::S : return DATA_S; + case ArithmeticOp::I4 : return DATA_I32; + case ArithmeticOp::I8 : return DATA_I64; + case ArithmeticOp::I : return DATA_I64; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +OpndKind IpfInstCodeSelector::toOpndKind(ArithmeticOp::Types type) { + + switch(type) { + case ArithmeticOp::F : + case ArithmeticOp::D : + case ArithmeticOp::S : return OPND_F_REG; + case ArithmeticOp::I4 : + case ArithmeticOp::I8 : + case ArithmeticOp::I : return OPND_G_REG; + default : IPF_ERR << "unexpected type " << type << endl; + } + return OPND_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(RefArithmeticOp::Types type) { + + switch(type) { + case RefArithmeticOp::I4 : return DATA_I32; + case RefArithmeticOp::I : return DATA_I64; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(ConvertToIntOp::Types type, bool isSigned) { + + switch(type) { + case ConvertToIntOp::I1 : return isSigned ? DATA_I8 : DATA_U8; + case ConvertToIntOp::I2 : return isSigned ? DATA_I16 : DATA_U16; + case ConvertToIntOp::I : + case ConvertToIntOp::I4 : return isSigned ? DATA_I32 : DATA_U32; + case ConvertToIntOp::I8 : return isSigned ? DATA_I64 : DATA_U64; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +OpndKind IpfInstCodeSelector::toOpndKind(DivOp::Types type) { + + switch(type) { + case DivOp::I4 : + case DivOp::U4 : + case DivOp::I : + case DivOp::I8 : + case DivOp::U : + case DivOp::U8 : return OPND_G_REG; + case DivOp::F : + case DivOp::S : + case DivOp::D : return OPND_F_REG; + default : IPF_ERR << "unexpected type " << type << endl; + } + return OPND_INVALID; +} + +//----------------------------------------------------------------------------// + +DataKind IpfInstCodeSelector::toDataKind(DivOp::Types type) { + + switch(type) { + case DivOp::I4 : return DATA_I32; + case DivOp::U4 : return DATA_U32; + case DivOp::I : + case DivOp::I8 : return DATA_I64; + case DivOp::U : + case DivOp::U8 : return DATA_U64; + case DivOp::F : return DATA_F; + case DivOp::S : return DATA_S; + case DivOp::D : return DATA_D; + default : IPF_ERR << "unexpected type " << type << endl; + } + return DATA_INVALID; +} + +//----------------------------------------------------------------------------// + +InstCode IpfInstCodeSelector::toInstCmp(CompareOp::Types type) { + + switch(type) { + case CompareOp::I4 : return INST_CMP4; + case CompareOp::I8 : + case CompareOp::I : + case CompareOp::Ref : + case CompareOp::CompRef : return INST_CMP; + case CompareOp::F : + case CompareOp::S : + case CompareOp::D : return INST_FCMP; + default : IPF_ERR << "unexpected type " << type << endl; + } + return INST_INVALID; +} + +//----------------------------------------------------------------------------// + +InstCode IpfInstCodeSelector::toInstCmp(CompareZeroOp::Types type) { + + switch(type) { + case CompareZeroOp::I4 : return INST_CMP4; + case CompareZeroOp::I8 : + case CompareZeroOp::I : + case CompareZeroOp::Ref : return INST_CMP; + case CompareZeroOp::CompRef : return INST_CMP4; + default : IPF_ERR << "unexpected type " << type << endl; + } + return INST_INVALID; +} + +//----------------------------------------------------------------------------// + +Completer IpfInstCodeSelector::toCmpltCrel(CompareOp::Operators cmpOp, bool isFloating) { + + if (isFloating) { + switch (cmpOp) { + case CompareOp::Eq : return CMPLT_FCMP_FREL_EQ; + case CompareOp::Ne : return CMPLT_FCMP_FREL_NEQ; + case CompareOp::Gt : return CMPLT_FCMP_FREL_GT; + case CompareOp::Gtu : return CMPLT_FCMP_FREL_NLE; + case CompareOp::Ge : return CMPLT_FCMP_FREL_GE; + case CompareOp::Geu : return CMPLT_FCMP_FREL_NLT; + default : IPF_ERR << "unexpected type " << cmpOp << endl; + } + } else { + switch (cmpOp) { + case CompareOp::Eq : return CMPLT_CMP_CREL_EQ; + case CompareOp::Ne : return CMPLT_CMP_CREL_NE; + case CompareOp::Gt : return CMPLT_CMP_CREL_GT; + case CompareOp::Gtu : return CMPLT_CMP_CREL_GTU; + case CompareOp::Ge : return CMPLT_CMP_CREL_GE; + case CompareOp::Geu : return CMPLT_CMP_CREL_GEU; + default : IPF_ERR << "unexpected type " << cmpOp << endl; + } + } + + return CMPLT_INVALID; +} + +//----------------------------------------------------------------------------// + +Completer IpfInstCodeSelector::toCmpltSz(DataKind dataKind) { + + switch(dataKind) { + case DATA_I8 : + case DATA_U8 : return CMPLT_SZ_1; + case DATA_I16 : + case DATA_U16 : return CMPLT_SZ_2; + case DATA_I32 : + case DATA_U32 : return CMPLT_SZ_4; + case DATA_I64 : + case DATA_U64 : + case DATA_BASE : + case DATA_MPTR : return CMPLT_SZ_8; + case DATA_S : return CMPLT_FSZ_S; + case DATA_D : return CMPLT_FSZ_D; + case DATA_F : return CMPLT_FSZ_E; + default : IPF_ERR << "unexpected dataKind " << dataKind << endl; + } + return CMPLT_INVALID; +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::ipfBreakCounted(RegOpnd *truePred) { + addNewInst(INST_BREAK, truePred, opndManager->newImm(INST_BREAKPOINT_IMM_VALUE)); +} + +//----------------------------------------------------------------------------// + +void IpfInstCodeSelector::ipfBreakCounted(RegOpnd *r2, Completer cmp, int val) { + // cmp4.crel.ctype p1, p2 = r2, r3 + + RegOpnd *p1 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + + addNewInst(INST_MOVL, p0, r3, opndManager->newImm(val)); + addNewInst(INST_CMP, cmp, p0, p1, p0, r2, r3); + addNewInst(INST_BREAK, p1, opndManager->newImm(INST_BREAKPOINT_IMM_VALUE)); +} + +//----------------------------------------------------------------------------------------// + +void IpfInstCodeSelector::ipfBreakCounted(int cnt) { + if (cnt==-1) cnt = ipfSigillBreakCount; + + if (cnt==0) { + addNewInst(INST_BREAK, p0, opndManager->newImm(INST_BREAKPOINT_IMM_VALUE)); + } else { + RegOpnd *r0 = opndManager->getR0(); + Int64Constant *ic = new(mm) Int64Constant(0); + ConstantRef *constref = opndManager->newConstantRef(ic); + RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + RegOpnd *r1 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + RegOpnd *r2 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); + Completer cmplt = toCmpltSz(DATA_I64); + RegOpnd *p1 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); + + addNewInst(INST_MOVL, p0, r3, constref); + addNewInst(INST_LD, cmplt, p0, r1, r3); + addNewInst(INST_ADD, p0, r1, r1, r0, opndManager->newImm(1)); + addNewInst(INST_ST, cmplt, p0, r3, r1); + addNewInst(INST_MOVL, p0, r2, opndManager->newImm(cnt)); + addNewInst(INST_CMP, CMPLT_CMP_CREL_LE, p0, p1, p0, r2, r1); + addNewInst(INST_BREAK, p1, opndManager->newImm(INST_BREAKPOINT_IMM_VALUE)); + } +} + +} //namespace IPF +} //namespace Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfIrPrinter.cpp vm/jitrino/src/codegenerator/ipf/IpfIrPrinter.cpp new file mode 100644 index 0000000..86058e6 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfIrPrinter.cpp @@ -0,0 +1,479 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Compare two opnds by id value +//========================================================================================// + +bool greaterOpnd (Opnd *o1, Opnd *o2) { return o1->getId() > o2->getId(); } + +//========================================================================================// +// IrPrinter +//========================================================================================// + +IrPrinter::IrPrinter(Cfg &cfg_, char *logDirName_) : + mm(cfg_.getMM()), + cfg(cfg_), + logDirName(logDirName_), + ofs(NULL) { +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printLayoutDot(char *logFileName) { + + string logName(logDirName); + logName.append(logFileName); + ofs = new(mm) ofstream(logName.c_str()); + + BbNode *node = (BbNode *)cfg.getEnterNode(); + BbNode *succ = node->getLayoutSucc(); + + printHead(); + while(succ != NULL) { + printNodeDot(node); + *ofs << " " << node->getId(); + *ofs << " -> " << succ->getId() << endl; + node = succ; + succ = node->getLayoutSucc(); + } + + printNodeDot(node); + printTail(); + ofs->close(); +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printCfgDot(char *logFileName) { + + string logName(logDirName); + logName.append(logFileName); + ofs = new(mm) ofstream(logName.c_str()); + + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); + + printHead(); + for(uint32 i=0; i<nodes.size(); i++) { + printNodeDot(nodes[i]); + EdgeVector &edges = nodes[i]->getOutEdges(); + for(uint32 j=0; j<edges.size(); j++) { + printEdgeDot(edges[j]); + } + } + printTail(); + ofs->close(); +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printAsm(ostream &os_) { + + os = &os_; + + BbNode *node = (BbNode *)cfg.getEnterNode(); + + *os << endl; + *os << "----------- Code dump ----------------------------------------" << endl; + while(node != NULL) { + printNodeAsm(node); + node = node->getLayoutSucc(); + } +} + +//----------------------------------------------------------------------------------------// +// Dot file printing +//----------------------------------------------------------------------------------------// + +void IrPrinter::printEdgeDot(Edge *edge) { + + *ofs << " " << edge->getSource()->getId(); + *ofs << " -> " << edge->getTarget()->getId(); + switch(edge->getEdgeKind()) { + case EDGE_EXCEPTION : *ofs << "[color=red"; break; + case EDGE_DISPATCH : *ofs << "[color=green"; break; + case EDGE_BRANCH : *ofs << "[color=blue"; break; + case EDGE_THROUGH : *ofs << "[color=black"; break; + default : *ofs << "[color=yellow"; + } + + *ofs << ",label=\"" << edge->getProb() << "\"];" << ::std::endl; +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printNodeDot(Node *node) { + + *ofs << " " << node->getId(); + *ofs << " [label=\"{"; + + switch(node->getNodeKind()) { + case NODE_BB : *ofs << "BB" << node->getId(); break; + case NODE_DISPATCH : *ofs << "Dispatch" << node->getId(); break; + case NODE_UNWIND : *ofs << "Unwind" << node->getId(); break; + default : *ofs << "Invalid" << node->getId(); break;; + } + + Node *loopHeader = node->getLoopHeader(); + if (loopHeader != NULL) { + *ofs << "(" << loopHeader->getId() << ")"; + } + + if(node->getNodeKind() == NODE_BB) { + InstVector &insts = ((BbNode *)node)->getInsts(); + for(uint32 i=0; i<insts.size(); i++) { + *ofs << "\\n" << insts[i]->getInstMnemonic(); + CompVector &compList = insts[i]->getComps(); + for(uint16 j=0; j<compList.size(); j++) *ofs << insts[i]->getCompMnemonic(compList[j]); + } + } + + *ofs << "}\"];" << endl; +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printHead() { + + *ofs << "digraph dotgraph {" << ::std::endl; + *ofs << " center=TRUE;" << ::std::endl; + *ofs << " margin=\".2,.2\";" << ::std::endl; + *ofs << " ranksep=\".25\";" << ::std::endl; + *ofs << " nodesep=\".20\";" << ::std::endl; + *ofs << " page=\"20,20\";" << ::std::endl; + *ofs << " ratio=auto;" << ::std::endl; + *ofs << " fontpath=\"c:\\winnt\\fonts\";" << ::std::endl; + *ofs << " node [shape=record,fontname=\"Courier\",fontsize=9];" << ::std::endl; + *ofs << " edge [fontname=\"Courier\",fontsize=9];" << ::std::endl; + +} + +//----------------------------------------------------------------------------------------// + +void IrPrinter::printTail() { + *ofs << "}" << ::std::endl; +} + +//----------------------------------------------------------------------------------------// +// Asm file printing +//----------------------------------------------------------------------------------------// + +void IrPrinter::printNodeAsm(BbNode *node) { + + *os << ".L" << node->getId() << ":" << endl; + + InstVector &insts = ((BbNode *)node)->getInsts(); + for(uint32 i=0; i<insts.size(); i++) *os << " " << toString(insts[i]) << endl; +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); + uint16 numDst = inst->getNumDst(); + CompVector &compList = inst->getComps(); + RegOpnd *qp = (RegOpnd *)opnds[0]; + + ostringstream oss; + oss << "(" << toString(qp) << ")"; + + while(oss.tellp() < 9) oss << " "; + oss << inst->getInstMnemonic(); // print instruction mnemonic + for(uint16 i=0; i<compList.size(); i++) oss << inst->getCompMnemonic(compList[i]); + oss << " "; + while(oss.tellp() < 21) oss << " "; + + InstCode icode = inst->getInstCode(); + bool lddone = false; + if (icode>=INST_ST_FIRST && icode<=INST_ST_LAST) { + oss << "["; + } + uint16 i = 1; // The first opnd is qp. It has been printed already + while(i < numDst+1) { + oss << toString(opnds[i]); + if(++i >= numDst+1) break; + oss << ", "; + } + if (icode>=INST_ST_FIRST && icode<=INST_ST_LAST) { + oss << toString(opnds[i]); + i++; + oss << "]"; + } + + if(i>1 && i<opnds.size()) { // if we have printed dst opnd - align and print "=" + while(oss.tellp() < 24) oss << " "; + oss << " = "; + } + + while(i < opnds.size()) { + if (!lddone && icode>=INST_LD_FIRST && icode<=INST_LD_LAST) { + oss << "["; + } + oss << toString(opnds[i]); + if (!lddone && icode>=INST_LD_FIRST && icode<=INST_LD_LAST) { + oss << "]"; + lddone = true; + } + if(++i >= opnds.size()) break; + oss << ", "; + } + return oss.str(); // return string representation of ostringstream +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(Opnd *opnd) { + + ostringstream oss; + if(opnd->getOpndKind() == OPND_INVALID) { oss << "invalid" << opnd->getId(); return oss.str(); } + + // opnd is register + if(opnd->isReg()) { + RegOpnd *reg = (RegOpnd *)opnd; + int32 num = reg->getLocation(); + + if (num == LOCATION_INVALID) { + num = reg->getId(); + switch(reg->getOpndKind()) { + case OPND_A_REG: oss << "A" << num; break; + case OPND_G_REG: oss << "R" << num; break; + case OPND_F_REG: oss << "F" << num; break; + case OPND_P_REG: oss << "P" << num; break; + case OPND_B_REG: oss << "B" << num; break; + default: oss << "??"; + } + return oss.str(); + } + + if (reg->isMem() == true) { + switch(reg->getOpndKind()) { + case OPND_A_REG: oss << "stack_a" << num; break; + case OPND_G_REG: oss << "stack_r" << num; break; + case OPND_F_REG: oss << "stack_f" << num; break; + case OPND_P_REG: oss << "stack_p" << num; break; + case OPND_B_REG: oss << "stack_b" << num; break; + default: oss << "??"; + } + } else { + switch(reg->getOpndKind()) { + case OPND_A_REG: oss << "a" << num; break; + case OPND_G_REG: oss << "r" << num; break; + case OPND_F_REG: oss << "f" << num; break; + case OPND_P_REG: oss << "p" << num; break; + case OPND_B_REG: oss << "b" << num; break; + default: oss << "??"; + } + } + return oss.str(); + } + + // opnd is imm + DataKind dataKind = opnd->getDataKind(); + + if (dataKind == DATA_CONST_REF) { + oss << "const"; + return oss.str(); + } + + if (dataKind == DATA_SWITCH_REF) { + oss << "switch"; + return oss.str(); + } + + if (dataKind == DATA_NODE_REF) { + BbNode *targetNode = ((NodeRef*) opnd)->getNode(); + if (targetNode == NULL) oss << "unknown target"; + else oss << ".L" << targetNode->getId(); + return oss.str(); + } + + if (dataKind == DATA_METHOD_REF) { + MethodDesc *method = ((MethodRef *)opnd)->getMethod(); + if (method == NULL) oss << "unknown method"; + else oss << method->getParentType()->getName() << "." << method->getName(); + return oss.str(); + } + + if (dataKind == DATA_IMM) { + int64 val = opnd->getValue(); + if(val > 100000) oss << hex << "0x" << val << dec; + else oss << val; + return oss.str(); + } + + oss << "ERROR"; + return oss.str(); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(OpndSet &opndSet) { + + ostringstream oss; + OpndVector opndVector(opndSet.begin(), opndSet.end()); + sort(opndVector.begin(), opndVector.end(), ptr_fun(greaterOpnd)); + + return toString(opndVector); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(RegOpndSet &opndSet) { + + ostringstream oss; + OpndVector opndVector(opndSet.begin(), opndSet.end()); + sort(opndVector.begin(), opndVector.end(), ptr_fun(greaterOpnd)); + + return toString(opndVector); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(OpndVector &opndVector) { + + ostringstream oss; + if (opndVector.size() == 0) return oss.str(); + + oss << toString(opndVector[0]); + for(uint16 i=1; i<opndVector.size(); i++) { + oss << ", " << toString(opndVector[i]); + } + return oss.str(); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(InstVector &insts) { + + ostringstream oss; + for(uint16 i=0; i<insts.size(); i++) { + oss << " " << toString(insts[i]) << endl; + } + return oss.str(); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(InstList &instList) { + + ostringstream oss; + for(InstListIterator i=instList.begin(); i!=instList.end(); i++) { + oss << " " << toString(*i) << endl; + } + return oss.str(); +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(NodeKind nodeKind) { + + string s; + switch(nodeKind) { + case NODE_BB : s = "NODE_BB"; break; + case NODE_DISPATCH: s = "NODE_DISPATCH"; break; + case NODE_UNWIND : s = "NODE_UNWIND"; break; + case NODE_INVALID : s = "NODE_INVALID"; break; + } + + if (s.empty()) IPF_ERR << " unexpected nodeKind " << nodeKind << endl; + return s; +} + +//----------------------------------------------------------------------------------------// + +string IrPrinter::toString(EdgeKind edgeKind) { + + string s; + switch(edgeKind) { + case EDGE_BRANCH : s = "EDGE_BRANCH"; break; + case EDGE_THROUGH : s = "EDGE_THROUGH"; break; + case EDGE_DISPATCH : s = "EDGE_DISPATCH"; break; + case EDGE_EXCEPTION: s = "EDGE_EXCEPTION"; break; + case EDGE_INVALID : s = "EDGE_INVALID"; break; + } + + if (s.empty()) IPF_ERR << " unexpected edgeKind " << edgeKind << endl; + return s; +} + +//----------------------------------------------------------------------------// + +string IrPrinter::toString(OpndKind opndKind) { + + string s; + switch(opndKind) { + case OPND_G_REG : s = "OPND_G_REG"; break; + case OPND_F_REG : s = "OPND_F_REG"; break; + case OPND_P_REG : s = "OPND_P_REG"; break; + case OPND_B_REG : s = "OPND_B_REG"; break; + case OPND_A_REG : s = "OPND_A_REG"; break; + case OPND_IP_REG : s = "OPND_IP_REG"; break; + case OPND_UM_REG : s = "OPND_UM_REG"; break; + case OPND_IMM : s = "OPND_IMM"; break; + case OPND_INVALID: s = "OPND_INVALID"; break; + } + + if (s.empty()) IPF_ERR << " unexpected opndKind " << opndKind << endl; + return s; +} + +//----------------------------------------------------------------------------// + +string IrPrinter::toString(DataKind dataKind) { + + string s; + switch(dataKind) { + case DATA_I8 : s = "DATA_I8"; break; + case DATA_U8 : s = "DATA_U8"; break; + case DATA_I16 : s = "DATA_I16"; break; + case DATA_U16 : s = "DATA_U16"; break; + case DATA_I32 : s = "DATA_I32"; break; + case DATA_U32 : s = "DATA_U32"; break; + case DATA_I64 : s = "DATA_I64"; break; + case DATA_U64 : s = "DATA_U64"; break; + case DATA_S : s = "DATA_S"; break; + case DATA_D : s = "DATA_D"; break; + case DATA_F : s = "DATA_F"; break; + case DATA_P : s = "DATA_P"; break; + case DATA_B : s = "DATA_B"; break; + case DATA_IMM : s = "DATA_IMM"; break; + case DATA_BASE : s = "DATA_BASE"; break; + case DATA_MPTR : s = "DATA_MPTR"; break; + case DATA_CONST_REF : s = "DATA_CONST_REF"; break; + case DATA_NODE_REF : s = "DATA_NODE_REF"; break; + case DATA_METHOD_REF : s = "DATA_METHOD_REF"; break; + case DATA_SWITCH_REF : s = "DATA_SWITCH_REF"; break; + case DATA_INVALID : s = "DATA_INVALID"; break; + } + + if (s.empty()) IPF_ERR << " unexpected dataKind " << dataKind << endl; + return s; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfLiveAnalyzer.cpp vm/jitrino/src/codegenerator/ipf/IpfLiveAnalyzer.cpp new file mode 100755 index 0000000..78d0d43 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfLiveAnalyzer.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfLiveAnalyzer.h" +#include "IpfIrPrinter.h" +#include "IpfOpndManager.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// LiveAnalyzer +//========================================================================================// + +LiveAnalyzer::LiveAnalyzer(Cfg &cfg_) : cfg(cfg_) { } + +//----------------------------------------------------------------------------------------// + +void LiveAnalyzer::makeLiveSets(bool verify_) { + + IPF_LOG << endl; + verify = verify_; + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); // get postordered node list + + // clear live sets for all nodes + if (!verify) { + for(uint16 i=0; i<nodes.size(); i++) { + nodes[i]->clearLiveSet(); + } + } + + // make new live sets for all nodes + bool flag = true; + while (flag == true) { + flag = false; + for(uint16 i=0; i<nodes.size(); i++) { + if (analyzeNode(nodes[i]) == false) flag = true; + } + } +} + +//----------------------------------------------------------------------------------------// + +bool LiveAnalyzer::analyzeNode(Node *node) { + + // build live set for node + RegOpndSet currLiveSet; + RegOpndSet &oldLiveSet = node->getLiveSet(); + node->mergeOutLiveSets(currLiveSet); // put in the live set merged live sets of successors + + if (LOG_ON) { + IPF_LOG << " node" << node->getId() << " successors:"; + EdgeVector &edges = node->getOutEdges(); + for (uint16 i=0; i<edges.size(); i++) { + Node *succ = edges[i]->getTarget(); + Node *loopHeader = succ->getLoopHeader(); + IPF_LOG << " " << succ->getId(); + if (loopHeader != NULL) IPF_LOG << "(" << loopHeader->getId() << ")"; + } + IPF_LOG << " exit live set: " << IrPrinter::toString(currLiveSet) << endl; + } + + // If node is not BB - currLiveSet is not going to change + if(node->getNodeKind() != NODE_BB) { + IPF_LOG << " node is not BB - live set is not changed" << endl; + if (oldLiveSet == currLiveSet) return true; // if live set has not changed - nothing to do + + node->setLiveSet(currLiveSet); // Set currLiveSet for the current node + return false; // and continue + } + + InstVector &insts = ((BbNode *)node)->getInsts(); + InstIterator currInst = insts.end()-1; + InstIterator firstInst = insts.begin()-1; + + for(; currInst>firstInst; currInst--) { + + updateLiveSet(currLiveSet, *currInst); + + IPF_LOG << " " << left << setw(46) << IrPrinter::toString(*currInst); + IPF_LOG << " live set : " << IrPrinter::toString(currLiveSet) << endl; + } + + if (oldLiveSet == currLiveSet) return true; // if live set has not changed - nothing to do + if (verify) { + IPF_LOG << "ERROR node" << node->getId() << endl; + IPF_LOG << " old live set: " << IrPrinter::toString(oldLiveSet) << endl; + IPF_LOG << " new live set: " << IrPrinter::toString(currLiveSet) << endl; + } + node->setLiveSet(currLiveSet); // set currLiveSet for the current node + return false; +} + +//----------------------------------------------------------------------------------------// +// Remove dst and insert qp and src opnds in live set. +// If qp is not "p0" do not remove dst opnd from live set, +// because if the inst is not executed dst opnd will stay alive + +void LiveAnalyzer::updateLiveSet(RegOpndSet &liveSet, Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); // get instruction's opnds + uint16 numDst = inst->getNumDst(); // number of dst opnds (qp has index 0) + bool isP0 = (opnds[0]->getValue() == 0); // is instruction qp is p0 + + // remove dst opnds from live set + for(uint16 i=1; isP0 && i<=numDst; i++) { + if (opnds[i]->isWritable()) liveSet.erase((RegOpnd *)opnds[i]); + } + + // insert qp opnd in live set + if (opnds[0]->isWritable()) liveSet.insert((RegOpnd *)opnds[0]); + + // insert src opnds in live set + for(uint16 i=numDst+1; i<opnds.size(); i++) { + if (opnds[i]->isWritable()) liveSet.insert((RegOpnd *)opnds[i]); + } +} + +//----------------------------------------------------------------------------------------// +// Remove dst opnds from live set. +// If qp is not "p0" do not remove dst opnd from live set, +// because if the inst is not executed dst opnd will stay alive + +void LiveAnalyzer::defOpnds(RegOpndSet &liveSet, Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); // get instruction's opnds + uint16 numDst = inst->getNumDst(); // number of dst opnds (qp has index 0) + bool isP0 = (opnds[0]->getValue() == 0); // is instruction qp is p0 + + // remove dst opnds from live set + for(uint16 i=1; isP0 && i<=numDst; i++) { + if (opnds[i]->isWritable()) liveSet.erase((RegOpnd *)opnds[i]); + } +} + +//----------------------------------------------------------------------------------------// +// Insert qp and src opnds in live set. + +void LiveAnalyzer::useOpnds(RegOpndSet &liveSet, Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); // get instruction's opnds + uint16 numDst = inst->getNumDst(); // number of dst opnds (qp has index 0) + + // insert qp opnd in live set + if (opnds[0]->isWritable()) liveSet.insert((RegOpnd *)opnds[0]); + + // insert src opnds in live set + for(uint16 i=numDst+1; i<opnds.size(); i++) { + if (opnds[i]->isWritable()) liveSet.insert((RegOpnd *)opnds[i]); + } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfOpnd.cpp vm/jitrino/src/codegenerator/ipf/IpfOpnd.cpp new file mode 100755 index 0000000..e3678cb --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfOpnd.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//============================================================================// +// Constant +//============================================================================// + +Constant::Constant(DataKind dataKind_) { + offset = LOCATION_INVALID; + size = 0; + dataKind = dataKind_; +} + +//============================================================================// +// SwitchConstant +//============================================================================// + +SwitchConstant::SwitchConstant() : Constant(DATA_U64) { +} + +//----------------------------------------------------------------------------// + +void SwitchConstant::addEdge(Edge *edge) { + edgeList.push_back(edge); +} + +//----------------------------------------------------------------------------// + +int16 SwitchConstant::getSize() { + return edgeList.size() * sizeof(uint64); +} + +//----------------------------------------------------------------------------// + +void *SwitchConstant::getData(void *p) { + return NULL; +} + +//----------------------------------------------------------------------------// + +uint16 SwitchConstant::getChoice(Edge *edge) { + + for (uint16 i=0; i < edgeList.size(); i++) { + if (edgeList[i] == edge) { + return i; + } + } + + return (uint16)-1; +} + +//============================================================================// +// Float Constants +//============================================================================// + +FloatConstant::FloatConstant(float value_) : Constant(DATA_S) { + value = value_; + setSize(sizeof(float)); +} + +//----------------------------------------------------------------------------// + +void *FloatConstant::getData() { + return NULL; +} + +//============================================================================// +// Double Constants +//============================================================================// + +DoubleConstant::DoubleConstant(double value_) : Constant(DATA_D) { + value = value_; + setSize(sizeof(double)); +} + +//----------------------------------------------------------------------------// + +void *DoubleConstant::getData() { + return NULL; +} + +//============================================================================// +// Opnd +//============================================================================// + +Opnd::Opnd(uint32 id_, OpndKind opndKind_, DataKind dataKind_, int64 value_) : + id(id_), + opndKind(opndKind_), + dataKind(dataKind_), + value(value_) { +} + +//----------------------------------------------------------------------------// + +bool Opnd::isWritable() { + if (isReg() == false) return false; + if (isConstant() == true) return false; + return true; +} + +//----------------------------------------------------------------------------// +// true if opnd resides on memory stack + +bool Opnd::isMem() { + + if (isReg() == false) return false; + if (value < S_BASE) return false; + if (value >= LOCATION_INVALID) return false; + return true; + + return true; +} + +//----------------------------------------------------------------------------// + +bool Opnd::isConstant() { + + if (value==0 && opndKind==OPND_P_REG) return true; // p0 + if (value==0 && opndKind==OPND_G_REG) return true; // r0 + if (value==0 && opndKind==OPND_F_REG) return true; // f0 + if (value==1 && opndKind==OPND_F_REG) return true; // f1 + + return false; +} + +//----------------------------------------------------------------------------// + +bool Opnd::isImm(int size) { + + if (isImm() == false) return false; + + Opnd* imm = (Opnd*) this; + if (Opnd::isFoldableImm(imm->getValue(), size)) return true; + return false; +} + +//----------------------------------------------------------------------------// + +bool Opnd::isFoldableImm(int64 imm, int16 size) { + uint64 max = ((uint64)0x1 << (size - 1)) - 1; + uint64 min = ~max; + return (imm >= (int64)min) && (imm <= (int64)max); +} + +//============================================================================// +// RegOpnd +//============================================================================// + +RegOpnd::RegOpnd(uint32 id_, OpndKind opndKind_, DataKind dataKind_, int32 value_) : + Opnd(id_, opndKind_, dataKind_, value_) { + + spillCost = 0; + crossCallSite = false; +} + +//----------------------------------------------------------------------------// + +int64 RegOpnd::getValue() { + + if (isMem() == false) return value; + if (value >= S_OUTARG_BASE) return value; + return value - S_BASE; +} + +//----------------------------------------------------------------------------// + +void RegOpnd::insertDepOpnd(RegOpnd *depOpnd) { + + if (depOpnd->isMem() == true) return; + if (depOpnd->getOpndKind() != opndKind) return; + depOpnds.insert(depOpnd); +} + +//============================================================================// +// NodeRef +//============================================================================// + +int64 NodeRef::getValue() { return node->getAddress(); } + +//============================================================================// +// MethodRef +//============================================================================// + +int64 MethodRef::getValue() { + + int64 *indirectAddress = (int64 *)method->getIndirectAddress(); + return *indirectAddress; +} + +} //Jitrino +} // IPF diff --git vm/jitrino/src/codegenerator/ipf/IpfOpndManager.cpp vm/jitrino/src/codegenerator/ipf/IpfOpndManager.cpp new file mode 100644 index 0000000..5b3a9cf --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfOpndManager.cpp @@ -0,0 +1,483 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "DrlVMInterface.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// RegStack +//----------------------------------------------------------------------------------------// +// For all masks "1" means reg can be used +// Scratch registers r14-r16, f32-f34, p6-p8, b6 are reserved for spill/fill +// Preserved reg r4 is thread pointer, r5 and r6 are also busy, so we do not use preserved grs +//========================================================================================// + +RegStack::RegStack() : + scratchGrMask(string("1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111100000111100001100")), + preservGrMask(string("1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111100000000000000000000000010000000")), + spillGrMask (string("0000000000000000000000000000000000000000000000011000000000000000")), + scratchFrMask(string("1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111100000000000000000001111111111000000")), + preservFrMask(string("0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000011111111111111110000000000111100")), + spillFrMask (string("0000000000000000000000000000011100000000000000000000000000000000")), + scratchPrMask(string("0000000000000000000000000000000000000000000000001111111000000000")), + preservPrMask(string("1111111111111111111111111111111111111111111111110000000000111110")), + spillPrMask (string("0000000000000000000000000000000000000000000000000000000111000000")), + scratchBrMask(string("10000001")), + preservBrMask(string("00111110")), + spillBrMask (string("01000000")) { + + inRegSize = 0; + locRegSize = 0; + outRegSize = 0; +} + +//----------------------------------------------------------------------------------------// + +int32 RegStack::newInReg(int32 inArgPosition) { + + if (inRegSize < inArgPosition+1) inRegSize = inArgPosition+1; + return G_INARG_BASE + inArgPosition; +} + +//----------------------------------------------------------------------------------------// + +int32 RegStack::newOutReg(int32 outArgPosition) { + + if (outRegSize < outArgPosition+1) { + outRegSize = outArgPosition+1; + // out regs can not be used as preserved (but can be used as scratch) + for (uint16 i=NUM_G_REG-outRegSize; i<NUM_G_REG; i++) preservGrMask[i] = 0; + } + + return G_OUTARG_BASE - outArgPosition; +} + +//----------------------------------------------------------------------------------------// + +bool RegStack::isOutReg(RegOpnd* opnd) { + + if (opnd->getOpndKind() != OPND_G_REG) return false; // opnd is not gr - ignore + + int32 firstOutRegArg = G_OUTARG_BASE - outRegSize + 1; + int32 location = opnd->getLocation(); + if (location < firstOutRegArg) return false; // location is less then first outArg - ignore + if (location >= NUM_G_REG) return false; // location is greater then last outArg - ignore + return true; // it is out reg arg +} + +//========================================================================================// +// MemStack +//========================================================================================// + +MemStack::MemStack() { + + locMemSize = 0; + outMemSize = 0; + inBase = 0; + locBase = 0; + outBase = 0; +} + +//----------------------------------------------------------------------------------------// +// returns location (not offset!) for new in stack opnd + +int32 MemStack::newInSlot(int32 inArgPosition) { + + int32 offset = (inArgPosition - MAX_REG_ARG) * ARG_SLOT_SIZE; + return S_INARG_BASE + offset; +} + +//----------------------------------------------------------------------------------------// +// increments locMemSize and returns location (not offset!) for new local stack opnd + +int32 MemStack::newLocSlot(DataKind dataKind) { + + if (inBase > 0) IPF_ERR << endl; // new loc slot makes illegal in arg offsets + + int16 size = IpfType::getSize(dataKind); + int32 offset = align(locMemSize, size); // align memory address to natural boundary + locMemSize = offset + size; // increase current local area size + + return S_LOCAL_BASE + offset; +} + +//----------------------------------------------------------------------------------------// +// increments outMemSize and returns location (not offset!) for new out stack opnd + +int32 MemStack::newOutSlot(int32 outArgPosition) { + + if (locBase+inBase > 0) IPF_ERR << endl; // new out slot makes illegal in arg and local offsets + + int32 offset = (outArgPosition - MAX_REG_ARG) * ARG_SLOT_SIZE; + int32 newSize = offset + ARG_SLOT_SIZE; + if(outMemSize < newSize) outMemSize = newSize; + + return S_OUTARG_BASE + offset; +} + +//----------------------------------------------------------------------------------------// +// converts area local offset (location) in absolute offset + S_BASE + +void MemStack::calculateOffset(RegOpnd* opnd) { + + int32 location = opnd->getLocation(); + location = calculateOffset(location); + opnd->setLocation(location); +} + +//----------------------------------------------------------------------------------------// +// converts area local offset (location) in absolute offset + S_BASE + +int32 MemStack::calculateOffset(int32 location) { + + if(location < S_OUTARG_BASE) { // offset has been calculated + return location; + } + + outBase = outMemSize+locMemSize > 0 ? S_SCRATCH_SIZE : 0; + if(location < S_LOCAL_BASE) { // it is mem outArg location + return location - S_OUTARG_BASE + outBase + S_BASE; + } + + locBase = outBase + align(outMemSize, S_SCRATCH_SIZE); + if(location < S_INARG_BASE) { // it is local mem location + return location - S_LOCAL_BASE + locBase + S_BASE; + } + + // it is mem inArg location + inBase = locBase + align(locMemSize, S_SCRATCH_SIZE) + S_SCRATCH_SIZE; + return location - S_INARG_BASE + inBase + S_BASE; +} + +//----------------------------------------------------------------------------------------// +// return current location in local area + +int32 MemStack::getSavedBase() { + + outBase = outMemSize+locMemSize > 0 ? S_SCRATCH_SIZE : 0; + locBase = outBase + align(outMemSize, S_SCRATCH_SIZE); + return locBase + align(locMemSize, S_SCRATCH_SIZE); +} + +//----------------------------------------------------------------------------------------// + +int32 MemStack::getMemStackSize() { + + outBase = outMemSize+locMemSize > 0 ? S_SCRATCH_SIZE : 0; + locBase = outBase + align(outMemSize, S_SCRATCH_SIZE); + inBase = locBase + align(locMemSize, S_SCRATCH_SIZE) + S_SCRATCH_SIZE; + + return inBase - S_SCRATCH_SIZE; +} + +//----------------------------------------------------------------------------------------// + +int32 MemStack::align(int32 val, int32 size) { + + int32 mask = -size; + int32 buf = val & mask; + return buf<val ? buf+size : buf; +} + +//========================================================================================// +// StackInfo +//========================================================================================// + +StackInfo::StackInfo() { + + rpBak = LOCATION_INVALID; + prBak = LOCATION_INVALID; + pfsBak = LOCATION_INVALID; + unatBak = LOCATION_INVALID; + savedBase = 0; + savedGrMask = 0; + savedFrMask = 0; + savedBrMask = 0; + memStackSize = 0; +} + +//========================================================================================// +// OpndManager +//========================================================================================// + +OpndManager::OpndManager(MemoryManager &mm, CompilationInterface &compilationInterface) : + mm(mm), + compilationInterface(compilationInterface) { + + maxOpndId = 0; + + r0 = NULL; + f0 = NULL; + f1 = NULL; + p0 = NULL; + b0 = NULL; + r12 = NULL; + tau = NULL; + + containCall = false; + + refsCompressed = compilationInterface.areReferencesCompressed(); + vtablePtrsCompressed = compilationInterface.areVTablePtrsCompressed(); + heapBase = NULL; + vtableBase = NULL; + vtableOffset = NULL; +} + +//----------------------------------------------------------------------------------------// + +Opnd *OpndManager::newOpnd(OpndKind opndKind) { + return new(mm) Opnd(maxOpndId++, opndKind); +} + +//----------------------------------------------------------------------------------------// + +RegOpnd *OpndManager::newRegOpnd(OpndKind opndKind, DataKind dataKind, int32 location) { + return new(mm) RegOpnd(maxOpndId++, opndKind, dataKind, location); +} + +//----------------------------------------------------------------------------------------// + +Opnd *OpndManager::newImm(int64 immValue) { + return new(mm) Opnd(maxOpndId++, OPND_IMM, DATA_IMM, immValue); +} + +//----------------------------------------------------------------------------------------// + +ConstantRef *OpndManager::newConstantRef(Constant *constant, DataKind dataKind) { + return new(mm) ConstantRef(maxOpndId++, constant, dataKind); +} + +//----------------------------------------------------------------------------------------// + +NodeRef *OpndManager::newNodeRef(BbNode *node) { + return new(mm) NodeRef(maxOpndId++, node); +} + +//----------------------------------------------------------------------------------------// + +MethodRef *OpndManager::newMethodRef(MethodDesc *method) { + return new(mm) MethodRef(maxOpndId++, method); +} + +//----------------------------------------------------------------------------------------// + +RegOpnd *OpndManager::getR0() { if(r0 ==NULL) r0 =newRegOpnd(OPND_G_REG, DATA_I64, 0); return r0; } +RegOpnd *OpndManager::getF0() { if(f0 ==NULL) f0 =newRegOpnd(OPND_F_REG, DATA_F, 0); return f0; } +RegOpnd *OpndManager::getF1() { if(f1 ==NULL) f1 =newRegOpnd(OPND_F_REG, DATA_F, 1); return f1; } +RegOpnd *OpndManager::getP0() { if(p0 ==NULL) p0 =newRegOpnd(OPND_P_REG, DATA_P, 0); return p0; } +RegOpnd *OpndManager::getB0() { if(b0 ==NULL) b0 =newRegOpnd(OPND_B_REG, DATA_I64, 0); return b0; } +RegOpnd *OpndManager::getR12() { if(r12==NULL) r12=newRegOpnd(OPND_G_REG, DATA_I64, 12); return r12; } +RegOpnd *OpndManager::getTau() { if(tau==NULL) tau=newRegOpnd(OPND_INVALID, DATA_INVALID); return tau; } +RegOpnd *OpndManager::getR0(RegOpnd *ref) { return newRegOpnd(OPND_G_REG, ref->getDataKind(), 0); } + +//----------------------------------------------------------------------------------------// + +RegOpnd *OpndManager::getHeapBase() { + if (heapBase == NULL) heapBase = newRegOpnd(OPND_G_REG, DATA_U64); + return heapBase; +} + +//----------------------------------------------------------------------------------------// + +RegOpnd *OpndManager::getVtableBase() { + if (vtableBase == NULL) vtableBase = newRegOpnd(OPND_G_REG, DATA_U64); + return vtableBase; +} + +//----------------------------------------------------------------------------------------// + +Opnd *OpndManager::getVtableOffset() { + + if (vtableOffset == NULL) { + vtableOffset = newImm(compilationInterface.getVTableOffset()); + } + return vtableOffset; +} + +//----------------------------------------------------------------------------------------// + +void OpndManager::initCompBases(BbNode *enterNode) { + + uint64 baseValue = 0; + Opnd *baseImm = NULL; + RegOpnd *p0 = getP0(); + InstVector &insts = enterNode->getInsts(); + + if (heapBase != NULL) { + baseValue = (uint64) compilationInterface.getHeapBase(); + baseImm = newImm(baseValue); + Inst *inst = new(mm) Inst(INST_MOVL, p0, heapBase, baseImm); + insts.insert(insts.begin(), inst); + IPF_LOG << " HeapBase initialization code inserted" << endl; + } + + if (vtableBase != NULL) { + baseValue = (uint64) compilationInterface.getVTableBase(); + baseImm = newImm(baseValue); + Inst *inst = new(mm) Inst(INST_MOVL, p0, vtableBase, baseImm); + insts.insert(insts.begin(), inst); + IPF_LOG << " VtableBase initialization code inserted" << endl; + } +} + +//----------------------------------------------------------------------------------------// +// assign location for opnd + +void OpndManager::assignLocation(RegOpnd *opnd) { + + OpndKind opndKind = opnd->getOpndKind(); + DataKind dataKind = opnd->getDataKind(); + RegBitSet &usedMask = opnd->getBusyRegMask(); + bool isPreserved = opnd->getCrossCallSite(); + + int32 location = newLocation(opndKind, dataKind, usedMask, isPreserved); + opnd->setLocation(location); +} + +//----------------------------------------------------------------------------------------// +// tryes to find available location for the opndKind/dataKind taking in account mask of used regs + +int32 OpndManager::newLocation(OpndKind opndKind, + DataKind dataKind, + RegBitSet usedMask, + bool isPreserved) { + + RegBitSet &unusedMask = usedMask.flip(); + int32 location = LOCATION_INVALID; + + if (isPreserved == false) { // it is scratch location + location = newScratchReg(opndKind, unusedMask); // try to find scratch register + if (location != LOCATION_INVALID) return location; // if we succeed - return it + } + // it is preserved location or we failed to find scratch one + location = newPreservReg(opndKind, unusedMask); // try to find preserved register + if (location != LOCATION_INVALID) return location; // if we succeed - return it + // we failed to find available register + return newLocSlot(dataKind); // allocate new slot on memory stack +} + +//----------------------------------------------------------------------------------------// +// tryes to find available scratch register for the opndKind taking in account mask of unused regs + +int32 OpndManager::newScratchReg(OpndKind opndKind, RegBitSet &unusedMask) { + + RegBitSet mask; + int16 maskSize = 0; + + // initialise reg masks and mask size + switch(opndKind) { + case OPND_G_REG: mask = scratchGrMask & unusedMask; maskSize = NUM_G_REG; break; + case OPND_F_REG: mask = scratchFrMask & unusedMask; maskSize = NUM_F_REG; break; + case OPND_P_REG: mask = scratchPrMask & unusedMask; maskSize = NUM_P_REG; break; + case OPND_B_REG: mask = scratchBrMask & unusedMask; maskSize = NUM_B_REG; break; + default: IPF_ERR << " unexpected opnd kind: " << opndKind << endl; + } + + for(int16 i=0; i<maskSize; i++) if(mask[i] == true) return i; + return LOCATION_INVALID; +} + +//----------------------------------------------------------------------------------------// +// tryes to find available preserved register for the opndKind taking in account mask of unused regs + +int32 OpndManager::newPreservReg(OpndKind opndKind, RegBitSet &unusedMask) { + + RegBitSet mask; + int16 maskSize = 0; + + // initialise reg masks and mask size + switch(opndKind) { + case OPND_G_REG: mask = preservGrMask & unusedMask; maskSize = REG_STACK_BASE; break; + case OPND_F_REG: mask = preservFrMask & unusedMask; maskSize = NUM_F_REG; break; + case OPND_P_REG: mask = preservPrMask & unusedMask; maskSize = NUM_P_REG; break; + case OPND_B_REG: mask = preservBrMask & unusedMask; maskSize = NUM_B_REG; break; + default: IPF_ERR << " unexpected opnd kind: " << opndKind << endl; + } + + // general registers is special case - it is better to allocate preserved reg on dynamic subset of + // register stack and only if the attempt failes try to allocate it on static regs + if (opndKind == OPND_G_REG) { + for(int16 i=REG_STACK_BASE; i<NUM_G_REG; i++) if(mask[i] == true) return i; + } + + for(int16 i=0; i<maskSize; i++) if(mask[i] == true) return i; + return LOCATION_INVALID; +} + +//----------------------------------------------------------------------------------------// +// get offset of the first element in array object + +int64 OpndManager::getElemBaseOffset() { + + DrlVMTypeManager typeManager(mm); + typeManager.init(compilationInterface); + ArrayType *arrayType = typeManager.getArrayType(typeManager.getInt64Type()); + return arrayType->getArrayElemOffset(); +} + +//----------------------------------------------------------------------------------------// +// init savedBase with current location in local area + +void OpndManager::initSavedBase() { + savedBase = getSavedBase(); +} + +//----------------------------------------------------------------------------------------// +// init memStackSize + +void OpndManager::initMemStackSize() { + memStackSize = getMemStackSize(); +} + +//----------------------------------------------------------------------------------------// + +void OpndManager::printStackInfo() { + + IPF_LOG << " Stack info" << endl; + IPF_LOG << " Register: loc=" << locRegSize << " out=" << outRegSize << endl; + IPF_LOG << " Memory : loc=" << locMemSize << " out=" << outMemSize << endl; + IPF_LOG << " Method contains call = " << boolalpha << containCall << endl; +} + +//----------------------------------------------------------------------------------------// + +void OpndManager::saveThisArg() { + + MethodDesc *methodDesc = compilationInterface.getMethodToCompile(); + if (methodDesc->isStatic() == true) return; // there is no "this" arg in static method + + preservGrMask[32] = 0; // make r32 unavailable for reg allocator + scratchGrMask[32] = 0; // make r32 unavailable for reg allocator + IPF_LOG << endl << " \"this\" arg is saved" << endl; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfPrologEpilogGenerator.cpp vm/jitrino/src/codegenerator/ipf/IpfPrologEpilogGenerator.cpp new file mode 100644 index 0000000..50cc490 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfPrologEpilogGenerator.cpp @@ -0,0 +1,521 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfPrologEpilogGenerator.h" +#include "IpfIrPrinter.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// PrologEpilogGenerator +//========================================================================================// + +PrologEpilogGenerator::PrologEpilogGenerator(Cfg &cfg_) : + mm(cfg_.getMM()), + cfg(cfg_) { + + opndManager = cfg.getOpndManager(); + p0 = opndManager->getP0(); + sp = opndManager->getR12(); + stackAddr = opndManager->newRegOpnd(OPND_G_REG, DATA_I64, SPILL_REG1); +} + +//----------------------------------------------------------------------------------------// +// Generate prolog and epilog +// save/restore callee saved regs +// build mask of regs not used in method +// generate "alloc" +// calculate number of local grs +// save/restore PFS, Stack pointer and Return pointer +// calculate stack size +// reassign out reg args. Now they are located inverse order in the end of reg +// stack (first in 127, second in 126 ...) + +void PrologEpilogGenerator::genPrologEpilog() { + + IPF_LOG << endl << " Build Data Sets" << endl; + buildSets(); + + IPF_LOG << " Generate Code" << endl; + genCode(); + + IPF_LOG << " Reassign OutRegArgs" << endl; + reassignOutRegArgs(); + + IPF_LOG << endl; opndManager->printStackInfo(); + IPF_LOG << endl; printRegMasks(); IPF_LOG << endl; +} + +//----------------------------------------------------------------------------------------// +// Build free reg masks and outArgs vector + +void PrologEpilogGenerator::buildSets() { + + // Build set of RegOpnd used in method. Buld epilog nodes vector + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); // get nodes + for(uint16 i=0; i<nodes.size(); i++) { // iterate through CFG nodes + + if(nodes[i]->getNodeKind() != NODE_BB) continue; // ignore non BB node + InstVector &insts = ((BbNode *)nodes[i])->getInsts(); // get insts + + // check if node is epilog and insert it in epilogNodes list + if(insts.size() > 0) { // if there are insts in node + CompVector &comps = insts.back()->getComps(); // get last one completers + if(comps.size()>0 && comps[0]==CMPLT_BTYPE_RET) { // if the inst is br.ret - node is epilog + epilogNodes.push_back(nodes[i]); // put it in epilogNodes list + } + } + + // build mask of used registers and vector of outArgs + for(uint16 j=0; j<insts.size(); j++) { // iterate through instructions + OpndVector &opnds = insts[j]->getOpnds(); // get opnds + for(uint16 k=0; k<insts[j]->getNumOpnd(); k++) { // iterate through opnds + if(opnds[k]->isReg() == false) continue; // ignore non register opnd + RegOpnd *opnd = (RegOpnd *)opnds[k]; + + setRegUsage(opnd, true); // mark reg as used + if (opndManager->isOutReg(opnd)) { // if opnd is out arg + outRegArgs.push_back(opnd); // place it in ouRegArgs vector + } + } + } + } +} + +//----------------------------------------------------------------------------------------// +// At this point out reg args have temporary locations. First one assigned to gr127, second to 126 ... +// Now we know number of in args and locals. Thus we can assign real locations for out args. + +void PrologEpilogGenerator::reassignOutRegArgs() { + + // First out arg will have this location + int32 outArgBase = G_INARG_BASE + opndManager->getLocRegSize(); + + for(uint16 i=0; i<outRegArgs.size(); i++) { // iterate through out args list + setRegUsage(outRegArgs[i], false); // mark old reg as free + } + + for(uint16 i=0; i<outRegArgs.size(); i++) { // iterate through out args list + + IPF_LOG << " " << IrPrinter::toString(outRegArgs[i]) << " reassigned on "; + int32 outArgNum = G_OUTARG_BASE - outRegArgs[i]->getValue(); // calculate real out arg number + outRegArgs[i]->setLocation(outArgBase + outArgNum); // calculate and assign new location + setRegUsage(outRegArgs[i], true); // mark new reg as used + IPF_LOG << IrPrinter::toString(outRegArgs[i]) << endl; + } +} + +//----------------------------------------------------------------------------------------// +// Generate prolog and epilog code and place it in Enter and Epilog nodes +// Prolog: +// alloc pfsBak = 1, 93, 2, 0 # gen alloc (pfsBak can not be preserved gr) +// adds r12 = -stackSize, r12 # save SP +// adds stackAddr = offset, r12 # if pfsBak is stack opnd - spill pfs +// st8 [stackAddr] = pfsBak # +// mov scratch = unat # if we use preserved grs - spill unat +// adds stackAddr = offset, r12 # +// st8 [stackAddr] = scratch # +// adds stackAddr = offset, r12 # spill preserved grs +// st8.spill [stackAddr] = preservedGr # +// adds stackAddr = offset, r12 # spill preserved frs +// stf.spill [stackAddr] = preservedFr # +// mov brBak = preservedBr # save preserved brs +// mov prBak = pr # save preserved prs +// mov rpBak = b0 # save return poiner +// +// Epilog: +// mov b0 = prBak # restore return poiner +// mov pr = prBak # restore preserved prs +// mov preservedBr = brBak # restore preserved brs +// adds stackAddr = offset, r12 # fill preserved frs +// ldf.fill preservedFr = [stackAddr] # +// adds stackAddr = offset1, r12 # fill preserved grs +// ld8.fill preservedGr = [stackAddr] # +// adds stackAddr = offset, r12 # if we use preserved grs - fill unat +// ld8 scratch = [stackAddr] # +// mov unat = scratch # +// mov.i AR.PFS = pfsBak # restore AR.PFS (if pfsBak is stack opnd - fill pfs) +// adds r12 = stackSize, r12 # restore SP + +void PrologEpilogGenerator::genCode() { + + containCall = opndManager->getContainCall(); + + saveRestoreRp(); // affects: mem stack, reg stack use: + saveRestorePr(); // affects: mem stack, reg stack use: + genAlloc(); // affects: mem stack, reg stack use: reg stack + saveRestoreUnat(); // affects: mem stack use: + saveRestorePreservedGr(); // affects: mem stack use: + saveRestorePreservedFr(); // affects: mem stack use: + saveRestorePreservedBr(); // affects: mem stack use: + saveRestoreSp(); // affects: use: mem stack + + prologInsts.splice(prologInsts.end(), allocInsts); + prologInsts.splice(prologInsts.end(), saveSpInsts); + prologInsts.splice(prologInsts.end(), savePfsInsts); + prologInsts.splice(prologInsts.end(), saveUnatInsts); + prologInsts.splice(prologInsts.end(), saveGrsInsts); + prologInsts.splice(prologInsts.end(), saveFrsInsts); + prologInsts.splice(prologInsts.end(), saveBrsInsts); + prologInsts.splice(prologInsts.end(), savePrsInsts); + prologInsts.splice(prologInsts.end(), saveRpInsts); + + epilogInsts.splice(epilogInsts.end(), restRpInsts); + epilogInsts.splice(epilogInsts.end(), restPrsInsts); + epilogInsts.splice(epilogInsts.end(), restBrsInsts); + epilogInsts.splice(epilogInsts.end(), restFrsInsts); + epilogInsts.splice(epilogInsts.end(), restGrsInsts); + epilogInsts.splice(epilogInsts.end(), restUnatInsts); + epilogInsts.splice(epilogInsts.end(), restPfsInsts); + epilogInsts.splice(epilogInsts.end(), restSpInsts); + + // Print Prolog and Epilog insts + IPF_LOG << endl; + IPF_LOG << " Prolog:" << endl << IrPrinter::toString(prologInsts) << endl; + IPF_LOG << " Epilog:" << endl << IrPrinter::toString(epilogInsts) << endl; + + // Insert prolog instructions in begining of enter node + BbNode *enterNode = (BbNode *)cfg.getEnterNode(); + InstVector &enterInsts = enterNode->getInsts(); + enterInsts.insert(enterInsts.begin(), prologInsts.begin(), prologInsts.end()); + + // Insert epilog instructions in each epilog node (all nodes which end with "br.ret") + for(uint16 i=0; i<epilogNodes.size(); i++) { + InstVector &exitInsts = ((BbNode *)epilogNodes[i])->getInsts(); + exitInsts.insert(exitInsts.end()-1, epilogInsts.begin(), epilogInsts.end()); + } +} + +//----------------------------------------------------------------------------------------// +// Generate saving/restoring return pointer +// mov rpBak = b0 + +void PrologEpilogGenerator::saveRestoreRp() { + + if(containCall == false) return; // method does not contain "call" - nothing to do + + RegOpnd *b0 = opndManager->getB0(); // return pointer to be saved + RegOpnd *rpBak = newStorage(DATA_B, SITE_REG); // opnd to store return pointer + opndManager->rpBak = rpBak->getLocation(); // set rpBak as storage of return pointer + + if (rpBak->isMem()) { + Opnd *offset = opndManager->newImm(rpBak->getValue()); + Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_B, SPILL_REG2); + + saveRpInsts.push_back(new(mm) Inst(INST_MOV, p0, scratch, b0)); + saveRpInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + saveRpInsts.push_back(new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); + + restRpInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restRpInsts.push_back(new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); + restRpInsts.push_back(new(mm) Inst(INST_MOV, p0, b0, scratch)); + } else { + saveRpInsts.push_back(new(mm) Inst(INST_MOV, p0, rpBak, b0)); + restRpInsts.push_back(new(mm) Inst(INST_MOV, p0, b0, rpBak)); + } +} + +//----------------------------------------------------------------------------------------// +// If we use preserved prs - generate saving/restoring predicate registers + +void PrologEpilogGenerator::saveRestorePr() { + + RegBitSet regMask = usedPrMask & opndManager->preservPrMask; + if(regMask.any() == false) return; // method does not use preserved pr + + RegOpnd *prBak = newStorage(DATA_U64, SITE_REG); // opnd to store prs + opndManager->prBak = prBak->getLocation(); // set prBak as storage of prs + + if (prBak->isMem()) { + Opnd *offset = opndManager->newImm(prBak->getValue()); + Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_B, SPILL_REG2); + + savePrsInsts.push_back(new(mm) Inst(INST_MOV, p0, scratch, p0)); + savePrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + savePrsInsts.push_back(new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); + + restPrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restPrsInsts.push_back(new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); + restPrsInsts.push_back(new(mm) Inst(INST_MOV, p0, p0, scratch)); + } else { + savePrsInsts.push_back(new(mm) Inst(INST_MOV, p0, prBak, p0)); + restPrsInsts.push_back(new(mm) Inst(INST_MOV, p0, p0, prBak)); + } +} + +//----------------------------------------------------------------------------------------// +// Generate "alloc" and AR.PFS restoring instructions + +void PrologEpilogGenerator::genAlloc() { + + int32 locRegSize = calculateLocRegSize(); // actual reg usage in local area + int32 inRegSize = opndManager->getInRegSize(); // in regs number + int32 outRegSize = opndManager->getOutRegSize(); // out regs number + + if (containCall==false && locRegSize<=inRegSize) return; // method does not need "alloc" inst + + Opnd *pfsBak = saveRestorePfs(); // opnd to store AR.PFS + locRegSize = calculateLocRegSize(); // saveRestorePfs can allocate local gr + Opnd *iSize = opndManager->newImm(0); // always 0 + Opnd *lSize = opndManager->newImm(locRegSize); // number of in+local gr + Opnd *oSize = opndManager->newImm(outRegSize); // number of output gr + Opnd *rSize = opndManager->newImm(0); // number of rotate gr + + allocInsts.push_back(new(mm) Inst(INST_ALLOC, p0, pfsBak, iSize, lSize, oSize, rSize)); +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring AR.PFS + +Opnd* PrologEpilogGenerator::saveRestorePfs() { + + if (containCall == false) { // method does not contain "call" - do not save AR.PFS + return opndManager->newRegOpnd(OPND_G_REG, DATA_U64, SPILL_REG2); + } + + RegBitSet regMask = usedGrMask; + for(uint16 i=4; i<8; i++) regMask[i] = 1; // do not use preserved gr for saving AR.PFS + + Opnd *pfs = opndManager->newRegOpnd(OPND_A_REG, DATA_U64, AR_PFS_NUM); + RegOpnd *pfsBak = newStorage(DATA_U64, SITE_REG); + opndManager->pfsBak = pfsBak->getLocation(); // set the location as storage of AR.PFS + + if (pfsBak->isMem()) { + Opnd *offset = opndManager->newImm(pfsBak->getValue()); + Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_B, SPILL_REG2); + + savePfsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + savePfsInsts.push_back(new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); + + restPfsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restPfsInsts.push_back(new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); + restPfsInsts.push_back(new(mm) Inst(INST_MOV_I, p0, pfs, scratch)); + + return scratch; + } else { + restPfsInsts.push_back(new(mm) Inst(INST_MOV_I, p0, pfs, pfsBak)); + return pfsBak; + } +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring AR.UNAT + +void PrologEpilogGenerator::saveRestoreUnat() { + + RegBitSet preservGrMask(string("11110000")); // work with r4-r7 only (not with automatic regs r32-r127) + RegBitSet regMask = usedGrMask & preservGrMask; + if(regMask.any() == false) return; + + RegOpnd *storage = newStorage(DATA_U64, SITE_STACK); + Opnd *offset = opndManager->newImm(storage->getValue()); + Opnd *unat = opndManager->newRegOpnd(OPND_A_REG, DATA_U64, AR_UNAT_NUM); + Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_U64, SPILL_REG2); + + opndManager->unatBak = storage->getLocation(); + + saveUnatInsts.push_back(new(mm) Inst(INST_MOV_M, p0, scratch, unat)); + saveUnatInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + saveUnatInsts.push_back(new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); + + restUnatInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restUnatInsts.push_back(new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); + restUnatInsts.push_back(new(mm) Inst(INST_MOV_M, p0, unat, scratch)); +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring preserved grs +// adds r14 = offset, r12 +// st8.spill [r14] = preserved gr + +void PrologEpilogGenerator::saveRestorePreservedGr() { + + opndManager->initSavedBase(); // after this point mem local stack must contain preserved regs only + IPF_LOG << " Preserved register saved in memory stack with offset: " << opndManager->savedBase << endl; + + RegBitSet preservGrMask(string("11110000")); // work with r4-r7 only (not with automatic regs r32-r127) + RegBitSet regMask = usedGrMask & preservGrMask; + if(regMask.any() == false) return; + + IPF_LOG << " Preserved grs:"; + for(uint16 i=4; i<8; i++) { + if(regMask[i] == false) continue; + + Opnd *storage = newStorage(DATA_U64, SITE_STACK); + Opnd *offset = opndManager->newImm(storage->getValue()); + Opnd *preserv = opndManager->newRegOpnd(OPND_G_REG, DATA_U64, i); + + saveGrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + saveGrsInsts.push_back(new(mm) Inst(INST_ST8_SPILL, p0, stackAddr, preserv)); + restGrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restGrsInsts.push_back(new(mm) Inst(INST_LD8_FILL, p0, preserv, stackAddr)); + + IPF_LOG << " " << IrPrinter::toString(preserv); + } + IPF_LOG << endl; + opndManager->savedGrMask = regMask.to_ulong(); +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring preserved frs +// adds r14 = offset, r12 +// stf.spill [r14] = preserved fr + +void PrologEpilogGenerator::saveRestorePreservedFr() { + + RegBitSet regMask = usedFrMask & opndManager->preservFrMask; + if(regMask.any() == false) return; + + IPF_LOG << " Preserved frs:"; + for(uint16 i=2; i<32; i++) { + if(regMask[i] == false) continue; + + Opnd *storage = newStorage(DATA_F, SITE_STACK); + Opnd *offset = opndManager->newImm(storage->getValue()); + Opnd *preserv = opndManager->newRegOpnd(OPND_F_REG, DATA_F, i); + + saveFrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + saveFrsInsts.push_back(new(mm) Inst(INST_STF_SPILL, p0, stackAddr, preserv)); + restFrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restFrsInsts.push_back(new(mm) Inst(INST_LDF_FILL, p0, preserv, stackAddr)); + + IPF_LOG << " " << IrPrinter::toString(preserv); + } + IPF_LOG << endl; + opndManager->savedFrMask = regMask.to_ulong(); +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring preserved brs + +void PrologEpilogGenerator::saveRestorePreservedBr() { + + RegBitSet regMask = usedBrMask & opndManager->preservBrMask; + if(regMask.any() == false) return; + + IPF_LOG << " Preserved brs:"; + for(uint16 i=1; i<6; i++) { + if(regMask[i] == false) continue; + + Opnd *storage = newStorage(DATA_B, SITE_STACK); + Opnd *offset = opndManager->newImm(storage->getValue()); + Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_B, SPILL_REG2); + Opnd *preserv = opndManager->newRegOpnd(OPND_B_REG, DATA_B, i); + + saveBrsInsts.push_back(new(mm) Inst(INST_MOV, p0, scratch, preserv)); + saveBrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + saveBrsInsts.push_back(new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); + + restBrsInsts.push_back(new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp)); + restBrsInsts.push_back(new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); + restBrsInsts.push_back(new(mm) Inst(INST_MOV, p0, preserv, scratch)); + IPF_LOG << " " << IrPrinter::toString(preserv); + } + IPF_LOG << endl; + opndManager->savedBrMask = regMask.to_ulong(); +} + +//----------------------------------------------------------------------------------------// +// Generate instructions for saving/restoring stack pointer. Instructions are inserted after "alloc" + +void PrologEpilogGenerator::saveRestoreSp() { + + opndManager->initMemStackSize(); + int32 memStackSize = opndManager->memStackSize; + if (memStackSize <= S_SCRATCH_SIZE) return; // method does not need to save SP + + Opnd *memStackSizeOpndNeg = opndManager->newImm(-memStackSize); + Opnd *memStackSizeOpndPos = opndManager->newImm(memStackSize); + saveSpInsts.push_back(new(mm) Inst(INST_ADDS, p0, sp, memStackSizeOpndNeg, sp)); + restSpInsts.push_back(new(mm) Inst(INST_ADDS, p0, sp, memStackSizeOpndPos, sp)); +} + +//----------------------------------------------------------------------------------------// + +RegOpnd* PrologEpilogGenerator::newStorage(DataKind dataKind, uint16 site) { + + int32 location = LOCATION_INVALID; + if (site==SITE_REG) location = opndManager->newLocation(OPND_G_REG, dataKind, usedGrMask, containCall); + else location = opndManager->newLocSlot(dataKind); + + RegOpnd *storage = opndManager->newRegOpnd(OPND_G_REG, dataKind, location); // new storage + + if (storage->isMem()) opndManager->calculateOffset(storage); // calc real offset + else setRegUsage(storage, true); // mark reg as used + + return storage; +} + +//----------------------------------------------------------------------------------------// + +void PrologEpilogGenerator::setRegUsage(RegOpnd *opnd, bool flag) { + + if(opnd->isMem() == true) return; + uint16 regNum = opnd->getValue(); + + switch(opnd->getOpndKind()) { + case OPND_G_REG: usedGrMask[regNum] = flag; break; + case OPND_F_REG: usedFrMask[regNum] = flag; break; + case OPND_P_REG: usedPrMask[regNum] = flag; break; + case OPND_B_REG: usedBrMask[regNum] = flag; break; + default: IPF_ERR << " " << opnd->getOpndKind() << endl; + } +} + +//----------------------------------------------------------------------------------------// + +int32 PrologEpilogGenerator::calculateLocRegSize() { + + uint16 first = G_INARG_BASE; // first possible loc reg opnd location + uint16 last = NUM_G_REG - opndManager->getOutRegSize(); // last possible loc reg opnd location + int32 locRegSize = 0; + + // find last used gr in local area + for(uint16 i=first; i<last; i++) { + if (usedGrMask[i] == true) locRegSize = i; + } + + if (locRegSize > 0) locRegSize = locRegSize - first + 1; + opndManager->setLocRegSize(locRegSize); // set new local register area size + return locRegSize; +} + +//----------------------------------------------------------------------------------------// + +void PrologEpilogGenerator::printRegMasks() { + + IPF_LOG << noboolalpha << " Used grs: "; + for(uint16 i=0; i<NUM_G_REG; i++) { if(i%8==0) IPF_LOG << " " << i << " "; IPF_LOG << usedGrMask[i]; } + + IPF_LOG << endl << " Used frs: "; + for(uint16 i=0; i<NUM_F_REG; i++) { if(i%8==0) IPF_LOG << " " << i << " "; IPF_LOG << usedFrMask[i]; } + + IPF_LOG << endl << " Used prs: "; + for(uint16 i=0; i<NUM_P_REG; i++) { if(i%8==0) IPF_LOG << " " << i << " "; IPF_LOG << usedPrMask[i]; } + + IPF_LOG << endl << " Used brs: "; + for(uint16 i=0; i<NUM_B_REG; i++) { if(i%8==0) IPF_LOG << " " << i << " "; IPF_LOG << usedBrMask[i]; } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfRegisterAllocator.cpp vm/jitrino/src/codegenerator/ipf/IpfRegisterAllocator.cpp new file mode 100644 index 0000000..baedc82 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfRegisterAllocator.cpp @@ -0,0 +1,220 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfRegisterAllocator.h" +#include "IpfIrPrinter.h" +#include "IpfOpndManager.h" +#include "IpfLiveAnalyzer.h" + +namespace Jitrino { +namespace IPF { + +bool greaterSpillCost(RegOpnd *op1, RegOpnd *op2) { return op1->getSpillCost() > op2->getSpillCost(); } + +//========================================================================================// +// RegisterAllocator +//========================================================================================// + +RegisterAllocator::RegisterAllocator(Cfg &cfg_) : + mm(cfg_.getMM()), + cfg(cfg_) { + + opndManager = cfg.getOpndManager(); +} + +//----------------------------------------------------------------------------------------// + +void RegisterAllocator::allocate() { + + IPF_LOG << endl << " Build Interference Matrix" << endl << endl; + buildInterferenceMatrix(); + makeInterferenceMatrixSymmetric(); + + IPF_LOG << endl << " Remove Preassigned Opnds" << endl; + removePreassignedOpnds(); + + IPF_LOG << endl << " Assign Locations" << endl; + assignLocations(); +} + +//----------------------------------------------------------------------------------------// + +void RegisterAllocator::buildInterferenceMatrix() { + + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); + + for(uint16 i=0; i<nodes.size(); i++) { // iterate through CFG nodes + + IPF_LOG << " node" << nodes[i]->getId(); + if(nodes[i]->isBb() == false) { // ignore non BB nodes + IPF_LOG << " node is not BB - ignore" << endl; + continue; + } + + liveSet.clear(); // clear live set + nodes[i]->mergeOutLiveSets(liveSet); // put in the live set merged live sets of successors + IPF_LOG << " live set: " << IrPrinter::toString(liveSet) << endl; + + BbNode *node = (BbNode *)nodes[i]; + uint32 execCounter = node->getExecCounter(); + InstIterator currInst = node->getInsts().end()-1; + InstIterator firstInst = node->getInsts().begin()-1; + + for(; currInst>firstInst; currInst--) { + + Inst *inst = *currInst; + uint16 numDst = inst->getNumDst(); // number of dst opnds (qp has index 0) + OpndVector& opnds = inst->getOpnds(); // get inst's opnds + + LiveAnalyzer::defOpnds(liveSet, inst); // remove dst opnds from live set + checkCallSite(inst); // if currInst is "call" - all alive opnds cross call site + for(uint16 i=1; i<=numDst; i++) { // for each dst opnd + updateAllocSet(opnds[i], execCounter); // insert in allocSet and add live set in dep list + } + + LiveAnalyzer::useOpnds(liveSet, inst); // add src opnds in live set + updateAllocSet(opnds[0], execCounter); // insert in allocSet pq opnd and add alive qps in dep list + for(uint16 i=numDst+1; i<opnds.size(); i++) { // for each src opnd + updateAllocSet(opnds[i], execCounter); // insert in allocSet and add live set in dep list + } + + IPF_LOG << " " << left << setw(46) << IrPrinter::toString(inst); + IPF_LOG << " live set : " << IrPrinter::toString(liveSet) << endl; + } + } +} + +//----------------------------------------------------------------------------------------// +// 1. Remove opnd dependency on itself +// 2. Make dependency matrix symmetric + +void RegisterAllocator::makeInterferenceMatrixSymmetric() { + + for(RegOpndSetIterator it1=allocSet.begin(); it1!=allocSet.end(); it1++) { + RegOpnd *opnd = *it1; + opnd->getDepOpnds().erase(opnd); + RegOpndSet &depOpnds = opnd->getDepOpnds(); + for(RegOpndSetIterator it2=depOpnds.begin(); it2!=depOpnds.end(); it2++) { + (*it2)->insertDepOpnd(opnd); + } + } + + if(LOG_ON) { + IPF_LOG << endl << " Opnds dependensies: " << endl; + for(RegOpndSetIterator it=allocSet.begin(); it!=allocSet.end(); it++) { + RegOpnd *opnd = *it; + IPF_LOG << " " << setw(4) << left << IrPrinter::toString(opnd) << " depends on: "; + RegOpndSet &depOpnds = opnd->getDepOpnds(); + IPF_LOG << IrPrinter::toString(depOpnds) << endl; + } + } +} + +//----------------------------------------------------------------------------------------// +// 1. Creates out arg opngs list +// 2. Iterate through opnds having preassigned regs and notify their dep opnds that the reg +// has already been used +// 3. Remove opnds having preassigned regs from allocation cands list + +void RegisterAllocator::removePreassignedOpnds() { + + for(RegOpndSetIterator it1=allocSet.begin(); it1!=allocSet.end();) { + + RegOpnd *opnd = *it1; + int32 location = opnd->getLocation(); + + // if opnd does not have preassigned location - ignore + if(location == LOCATION_INVALID) { it1++; continue; } + + RegOpndSet& depOpnds = opnd->getDepOpnds(); // get opnds that depend on current one + for(RegOpndSetIterator it2=depOpnds.begin(); it2!=depOpnds.end(); it2++) { + (*it2)->markRegBusy(location); + } + + // remove opnd + IPF_LOG << " remove " << IrPrinter::toString(opnd) << endl; + it1++; + allocSet.erase(opnd); + } +} + +//----------------------------------------------------------------------------------------// +// 1. Sort opnd list by Spill Cost +// 2. Assign locations to all not allocated opnds + +void RegisterAllocator::assignLocations() { + + RegOpndVector opndVector(allocSet.begin(), allocSet.end()); // create vector of opns to be allocated + sort(opndVector.begin(), opndVector.end(), greaterSpillCost); // sort them by Spill Cost + + for (uint16 i=0; i<opndVector.size(); i++) { + RegOpnd *opnd = opndVector[i]; + IPF_LOG << " " << left << setw(5) << IrPrinter::toString(opnd); + opndManager->assignLocation(opnd); // assign location for current opnd + IPF_LOG << " after assignment " << IrPrinter::toString(opnd) << endl; + + if (opnd->isMem()) continue; // if opnd assigned on stack - nothing more to do + + RegOpndSet &depOpnds = opnd->getDepOpnds(); + int32 regNum = opnd->getLocation(); + for (RegOpndSetIterator it=depOpnds.begin(); it!=depOpnds.end(); it++) { + (*it)->markRegBusy(regNum); // notify all dep opnds that they can not use this reg + } + } +} + +//----------------------------------------------------------------------------------------// + +void RegisterAllocator::updateAllocSet(Opnd *opnd, uint32 execCounter) { + + if (opnd->isReg() == false) return; // imm - it does not need allocation + if (opnd->isMem() == true) return; // mem stack - it does not need allocation + if (opnd->isConstant() == true) return; // constant - it does not need allocation + + RegOpnd *regOpnd = (RegOpnd *)opnd; + + regOpnd->incSpillCost(execCounter); // increase opnd spill cost + allocSet.insert(regOpnd); // isert opnd in list for allocation + + // add current live set in opnd dep list (they must be placed on different regs) + for (RegOpndSetIterator it=liveSet.begin(); it!=liveSet.end(); it++) { + regOpnd->insertDepOpnd(*it); + } +} + +//----------------------------------------------------------------------------------------// +// Check if current inst is "call" and mark all opnds in liveSet as crossing call site + +void RegisterAllocator::checkCallSite(Inst *inst) { + + if(Encoder::isBranchCallInst(inst) == false) return; // opnd does not crass call site + + IPF_LOG << " these opnds cross call site: "; + IPF_LOG << IrPrinter::toString(liveSet) << endl; + + for(RegOpndSetIterator it=liveSet.begin(); it!=liveSet.end(); it++) { + (*it)->setCrossCallSite(true); + } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfRuntimeInterface.cpp vm/jitrino/src/codegenerator/ipf/IpfRuntimeInterface.cpp new file mode 100644 index 0000000..4fb7473 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfRuntimeInterface.cpp @@ -0,0 +1,322 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfRuntimeInterface.h" +#include "IpfEncoder.h" +#include "IpfType.h" +#include "IpfOpndManager.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// RuntimeInterface +//========================================================================================// + +void RuntimeInterface::unwindStack(MethodDesc *methodDesc, + JitFrameContext *jitFrameContext, + bool isFirst) { + +// cout << "IPF::RuntimeInterface::unwindStack "; +// cout << methodDesc->getName() << " " << methodDesc->getSignatureString() << endl; + + Byte *infoBlock = methodDesc->getInfoBlock(); // get method infoBlock + StackInfo stackInfo = *((StackInfo*) infoBlock); // read StackInfo structure + + uint64 sp = jitFrameContext->sp; // get current frame sp + uint64 addr = sp + stackInfo.savedBase; // mem stack offset of first saved gr + uint32 savedGrMask = stackInfo.savedGrMask; // mask of preserved grs saved on stack + uint32 savedFrMask = stackInfo.savedFrMask; // mask of preserved frs saved on stack + uint32 savedBrMask = stackInfo.savedBrMask; // mask of preserved frs saved on stack + + // Restore preserved general registers + if(savedGrMask != 0) { + for(uint32 i=0; i<32; i++) { + if((savedGrMask & 1) == 1) { + jitFrameContext->p_gr[i] = (uint64 *)addr; + addr += 8; + } + savedGrMask >>= 1; + } + } + + // Restore preserved floating registers + if(savedFrMask != 0) { + for(uint32 i=0; i<32; i++) { + if((savedFrMask & 1) == 1) { + jitFrameContext->p_fp[i] = (uint64 *)addr; + addr += 16; + } + savedFrMask >>= 1; + } + } + + // Restore preserved branch registers + if(savedBrMask != 0) { + for(uint32 i=0; i<8; i++) { + if((savedBrMask & 1) == 1) { + jitFrameContext->p_br[i] = (uint64 *)addr; + addr += 8; + } + savedBrMask >>= 1; + } + } + + // restore sp + jitFrameContext->sp += stackInfo.memStackSize; + + // Restore return pointer + int32 rpBak = stackInfo.rpBak; + if(rpBak != LOCATION_INVALID) { + if(rpBak >= S_BASE) jitFrameContext->p_eip = (uint64 *)(sp + rpBak - S_BASE); + else jitFrameContext->p_eip = jitFrameContext->p_gr[rpBak]; + } + + // Restore prs + int32 prBak = stackInfo.prBak; + if(prBak != LOCATION_INVALID) { + if(prBak >= S_BASE) jitFrameContext->preds = *((uint64 *)(sp + prBak - S_BASE)); + else jitFrameContext->preds = *(jitFrameContext->p_gr[prBak]); + } + + // Restore pfs + int32 pfsBak = stackInfo.pfsBak; + if(pfsBak != LOCATION_INVALID) { + if(pfsBak >= S_BASE) jitFrameContext->p_ar_pfs = (uint64 *)(sp + pfsBak - S_BASE); + else jitFrameContext->p_ar_pfs = jitFrameContext->p_gr[pfsBak]; + } + + // Restore unat + int32 unatBak = stackInfo.unatBak; + if(unatBak != LOCATION_INVALID) { + if(unatBak >= S_BASE) jitFrameContext->ar_unat = *((uint64 *)(sp + unatBak - S_BASE)); + else jitFrameContext->ar_unat = *(jitFrameContext->p_gr[unatBak]); + } + +// cout << " sp " << hex << jitFrameContext->sp << dec << " frame size " << stackInfo.memStackSize << endl; +// if(savedGrMask != 0) cout << " savedGrMask " << hex << savedGrMask << dec << endl; +// if(savedFrMask != 0) cout << " savedFrMask " << hex << savedFrMask << dec << endl; +// if(savedBrMask != 0) cout << " savedBrMask " << hex << savedBrMask << dec << endl; +// if(pfsBak != LOCATION_INVALID) cout << " pfsBak " << pfsBak << " " << hex << *(jitFrameContext->p_ar_pfs) << dec << endl; +// if(rpBak != LOCATION_INVALID) cout << " rpBak " << rpBak << " " << hex << *(jitFrameContext->p_eip) << dec << endl; +// if(prBak != LOCATION_INVALID) cout << " prBak " << prBak << " " << hex << jitFrameContext->preds << dec<< endl; +} + +//----------------------------------------------------------------------------------------// + +void RuntimeInterface::getGCRootSet(MethodDesc *methodDesc, + GCInterface *gcInterface_, + const JitFrameContext *context_, + bool isFirst) { + + gcInterface = gcInterface_; + context = context_; + Byte *infoBlock = methodDesc->getInfoBlock(); + Byte *gcInfo = infoBlock + sizeof(StackInfo); + uint64 currIp = *context->p_eip; + uint32 gcSize = *((uint32 *)gcInfo); + +// cout << "getGCRootSet for ip " << hex << currIp << dec << " method " << methodDesc->getName() << endl; + Byte* safePoint = findSafePoint(gcInfo, gcSize, currIp); + enumerateRootSet(gcInterface, context, safePoint); +} + +//----------------------------------------------------------------------------------------// + +uint32 RuntimeInterface::getInlineDepth(InlineInfoPtr ptr, uint32 offset) { + + cerr << "IPF::RuntimeInterface::getInlineDepth" << endl; + return 0; +} + +//----------------------------------------------------------------------------------------// + +Method_Handle RuntimeInterface::getInlinedMethod(InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth) { + + cerr << "IPF::RuntimeInterface::getInlinedMethod" << endl; + return NULL; +} + +//----------------------------------------------------------------------------------------// + +bool RuntimeInterface::canEnumerate(MethodDesc *methodDesc, NativeCodePtr eip) { + + cerr << "IPF::RuntimeInterface::canEnumerate" << endl; + return true; +} + +//----------------------------------------------------------------------------------------// + +void RuntimeInterface::fixHandlerContext(MethodDesc *methodDesc, JitFrameContext *context, bool isFirst) {} + +//----------------------------------------------------------------------------------------// + +void* RuntimeInterface::getAddressOfThis(MethodDesc *methodDesc, + const ::JitFrameContext *jitFrameContext, + bool isFirst) { + + assert(!methodDesc->isStatic()); + return jitFrameContext->p_gr[G_INARG_BASE]; +} + +//----------------------------------------------------------------------------------------// + +void* RuntimeInterface::getAddressOfSecurityObject(MethodDesc *methodDesc, + const ::JitFrameContext *jitFrameContext) { + + cerr << "IPF::RuntimeInterface::getAddressOfSecurityObject" << endl; + assert(0); + return NULL; +} + +//----------------------------------------------------------------------------------------// + +bool RuntimeInterface::recompiledMethodEvent(BinaryRewritingInterface &binaryRewritingInterface, + MethodDesc *methodDesc, + void *data) { + + char *callAddr = (char *)(~(((uint64)0x4cafe) << 32) & (uint64)data); + char **indirectAddr = (char **)methodDesc->getIndirectAddress(); + char *methodAddr = *indirectAddr; + + return Encoder::patchCallAddr(binaryRewritingInterface, callAddr, methodAddr); +} + +//----------------------------------------------------------------------------------------// + +bool RuntimeInterface::getBcLocationForNative(MethodDesc *method, uint64 native_pc, uint16 *bc_pc) { + + cerr << "IPF::RuntimeInterface::getBcLocationForNative" << endl; + assert(0); + return false; +} + +//----------------------------------------------------------------------------------------// + +bool RuntimeInterface::getNativeLocationForBc(MethodDesc *method, uint16 bc_pc, uint64 *native_pc) { + + cerr << "IPF::RuntimeInterface::getNativeLocationForBc" << endl; + assert(0); + return false; +} + +//----------------------------------------------------------------------------------------// +// GC Root Set +//----------------------------------------------------------------------------------------// + +Byte* RuntimeInterface::findSafePoint(Byte *info, uint32 size, uint64 currIp) { + + uint32 offset = ROOT_SET_HEADER_SIZE; + Byte *safePoint = NULL; + uint32 spSize = 0; + uint64 spAddress = 0; + + while (offset < size) { + safePoint = info + offset; + spSize = *((uint32 *)safePoint); + spAddress = *((uint64 *)(safePoint + sizeof(uint32))); + + if (spAddress == currIp) return safePoint; + offset += spSize; + } + + IPF_ERR << " No safe point found"; + return NULL; +} + +//----------------------------------------------------------------------------------------// +// + +void RuntimeInterface::enumerateRootSet(GCInterface *gcInterface, + const JitFrameContext *context, + Byte *safePoint) { + + uint32 size = *((uint32 *)(safePoint)); + int32* ptr = (int32 *)(safePoint + SAFE_POINT_HEADER_SIZE); + int32* maxPtr = (int32 *)(safePoint + size); + + while (ptr < maxPtr) { + if (isMptr(*ptr)) reportMptr(*(ptr++), *(ptr++)); + else reportBase(*(ptr++)); + } +} + +//----------------------------------------------------------------------------------------// + +void** RuntimeInterface::getContextValue(int32 location) { + + if (location < 0) { + location = - (location + 1); // if location refers mptr - restore it + } + + void** ptr = NULL; + if (location >= NUM_G_REG) { // this location points in memory stack + int32 offset = location - NUM_G_REG; // calc memory stack offset + ptr = (void **)(context->sp + offset); // get pointer on stack value + } else { // general register + ptr = (void **)(context->p_gr[location]); // get pointer on reg value + } + return ptr; // return value +} + +//----------------------------------------------------------------------------------------// + +void RuntimeInterface::reportMptr(int32 mptr, int32 base) { + + void **mptrPtr = getContextValue(mptr); + void **basePtr = getContextValue(base); + +// uint64 *u1 = (uint64 *)basePtr; +// uint64 *u2 = (uint64 *)mptrPtr; +// cout << " report mptr: " << - (mptr+1) << flush; +// cout << " " << u2 << flush; +// cout << " " << hex << *u2 << dec << flush; +// cout << " base: " << base << flush; +// cout << " " << u1 << flush; +// cout << " " << hex << *u1 << dec << endl; + + gcInterface->enumerateRootManagedReferenceWithBase(mptrPtr, basePtr); +} + +//----------------------------------------------------------------------------------------// + +void RuntimeInterface::reportBase(int32 base) { + + void** basePtr = getContextValue(base); +// uint64 *u1 = (uint64 *)basePtr; +// cout << " report base: " << base << flush; +// cout << " " << u1 << flush; +// cout << " " << hex << *u1 << dec << endl; + + gcInterface->enumerateRootReference(basePtr); +} + +//----------------------------------------------------------------------------------------// + +bool RuntimeInterface::isMptr(int32 ptr) { return ptr < 0; } + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfRuntimeSupport.cpp vm/jitrino/src/codegenerator/ipf/IpfRuntimeSupport.cpp new file mode 100644 index 0000000..ab843a8 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfRuntimeSupport.cpp @@ -0,0 +1,490 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfRuntimeSupport.h" +#include "IpfIrPrinter.h" +#include "IpfLiveAnalyzer.h" + +namespace Jitrino { +namespace IPF { + +//----------------------------------------------------------------------------------------// + +bool greaterPriority(Edge *edge1, Edge *edge2) { + + EdgeKind kind1 = edge1->getEdgeKind(); + EdgeKind kind2 = edge2->getEdgeKind(); + if (kind1 != EDGE_EXCEPTION || kind2 != EDGE_EXCEPTION) return false; + + return ((ExceptionEdge *)edge1)->getPriority() < ((ExceptionEdge *)edge2)->getPriority(); +} + +//========================================================================================// +// TryRegion +//========================================================================================// + +TryRegion::TryRegion(Byte *startAddr_, + Byte *endAddr_, + Byte *handlerAddr_, + ObjectType *exceptionType_, + bool isExceptionObjDead_) : + startAddr(startAddr_), + endAddr(endAddr_), + handlerAddr(handlerAddr_), + exceptionType(exceptionType_), + isExceptionObjDead(isExceptionObjDead_) { +} + +//========================================================================================// +// RuntimeSupport +//========================================================================================// + +RuntimeSupport::RuntimeSupport(Cfg &cfg_, CompilationInterface &compilationInterface_) : + mm(cfg_.getMM()), + cfg(cfg_), + compilationInterface(compilationInterface_) { + + opndManager = cfg.getOpndManager(); +} + +//----------------------------------------------------------------------------------------// +// Runtime info +// Stack info +// Root Set info +// +// Stack info structure +// see struct StackInfo in IpfRuntimeInterface.h +// +// Root set info structure +// +---------------+ +// header | 4 bytes | block size in bytes +// +---------------+ +// safe point n | 4 bytes | safe poin info size in bytes +// | 8 bytes | safe point address +// | 4 or 8 bytes | base or mptr+base +// +---------------+ + +void RuntimeSupport::makeRuntimeInfo() { + + IPF_LOG << endl << " Register Exception Handlers" << dec << endl; + registerExceptionHandlers(); + + IPF_LOG << endl << " Make Stack Info" << endl; + StackInfo *stackInfo = makeStackInfo(); + uint32 stackInfoSize = sizeof(StackInfo); + IPF_LOG << " stack info size (bytes): " << stackInfoSize << endl; + + IPF_LOG << endl << " Make Root Seet Info" << endl; + Uint32Vector rootSetInfo; + makeRootSetInfo(rootSetInfo); + uint32 rootSetInfoSize = ROOT_SET_HEADER_SIZE + rootSetInfo.size() * sizeof(uint32); + IPF_LOG << " GC root set info size (bytes): " << rootSetInfoSize << endl; + + // create info block + uint32 infoBlockSize = stackInfoSize + rootSetInfoSize; + Byte *infoBlock = compilationInterface.allocateInfoBlock(infoBlockSize); + + // write stack info + *((StackInfo *)infoBlock) = *stackInfo; + + // write root set info + uint32 *gcInfo = (uint32 *)(infoBlock + sizeof(StackInfo)); + uint32 j = ROOT_SET_HEADER_SIZE / sizeof(uint32); + gcInfo[0] = rootSetInfoSize; + for (uint32 i=0; i<rootSetInfo.size(); i++, j++) { + gcInfo[j] = rootSetInfo[i]; + } +} + +//----------------------------------------------------------------------------------------// +// Exception registration +//----------------------------------------------------------------------------------------// + +void RuntimeSupport::registerExceptionHandlers() { + + Node *dispatchNode = cfg.getEnterNode()->getDispatchNode(); + NodeVector &nodes = cfg.search(SEARCH_LAYOUT_ORDER); + Byte *startAddr = (Byte *)((BbNode *)cfg.getEnterNode())->getAddress(); + + for(uint16 i=1; i<nodes.size(); i++) { + if(nodes[i]->getNodeKind() != NODE_BB) continue; // ignore non BB node + + if(dispatchNode != nodes[i]->getDispatchNode()) { + Byte *endAddr = (Byte *)(((BbNode *)nodes[i])->getAddress()); + Node *lastNode = nodes[i-1]; + + IPF_LOG << " region detected, last node is BB" << lastNode->getId() << endl; + + makeRegion(startAddr, endAddr, dispatchNode); + startAddr = (Byte *)((BbNode *)nodes[i])->getAddress(); + dispatchNode = nodes[i]->getDispatchNode(); + } + } + compilationInterface.setNumExceptionHandler(tryRegions.size()); + + IPF_LOG << " region registration:" << endl; + if(tryRegions.size() == 0) { + IPF_LOG << " no catch handlers detected" << endl; + return; + } + + IPF_LOG << " start end handler exception objIsDead" << endl; + for(uint16 i=0; i<tryRegions.size(); i++) { + compilationInterface.setExceptionHandlerInfo(i, + tryRegions[i]->startAddr, + tryRegions[i]->endAddr, + tryRegions[i]->handlerAddr, + tryRegions[i]->exceptionType, + tryRegions[i]->isExceptionObjDead); + + IPF_LOG << " " << hex << (uint64)tryRegions[i]->startAddr; + IPF_LOG << " " << (uint64)tryRegions[i]->endAddr; + IPF_LOG << " " << (uint64)tryRegions[i]->handlerAddr; + IPF_LOG << " " << setw(35) << tryRegions[i]->exceptionType->getName(); + IPF_LOG << " " << boolalpha << tryRegions[i]->isExceptionObjDead << dec << endl; + } +} + +//----------------------------------------------------------------------------------------// + +void RuntimeSupport::makeRegion(Byte *startAddr, Byte *endAddr, Node *dispatchNode) { + + if(dispatchNode == NULL) { + IPF_LOG << " there is no dispatch node - region is not created" << endl; + return; + } + + if(dispatchNode->getNodeKind() != NODE_DISPATCH) return; + + IPF_LOG << " dispatch node is BB" << dispatchNode->getId() << endl; + EdgeVector& outEdges = dispatchNode->getOutEdges(); // get out edges + sort(outEdges.begin(), outEdges.end(), greaterPriority); // sort them by Priority + + for(uint16 i=0; i<outEdges.size(); i++) { + if(outEdges[i]->getEdgeKind() == EDGE_EXCEPTION) { + + Byte *handlerAddr = (Byte *)((BbNode *)outEdges[i]->getTarget())->getAddress(); + ObjectType *exceptionType = (ObjectType *)((ExceptionEdge *)outEdges[i])->getExceptionType(); + TryRegion *region = new(mm) TryRegion(startAddr, endAddr, handlerAddr, exceptionType, false); + + tryRegions.push_back(region); + IPF_LOG << " region created for handler BB" << outEdges[i]->getTarget()->getId(); + IPF_LOG << " priority: " << ((ExceptionEdge *)outEdges[i])->getPriority(); + IPF_LOG << " " << exceptionType->getName() << endl; + } + + if(outEdges[i]->getEdgeKind() == EDGE_DISPATCH) { + makeRegion(startAddr, endAddr, outEdges[i]->getTarget()); + } + } +} + +//----------------------------------------------------------------------------------------// +// Make info block which will be used in stack unwind routine +//----------------------------------------------------------------------------------------// + +StackInfo* RuntimeSupport::makeStackInfo() { + + int32 rpBak = opndManager->rpBak; + int32 prBak = opndManager->prBak; + int32 pfsBak = opndManager->pfsBak; + int32 unatBak = opndManager->unatBak; + uint32 savedGrMask = opndManager->savedGrMask; + uint32 savedFrMask = opndManager->savedFrMask; + uint32 savedBrMask = opndManager->savedBrMask; + uint32 memStackSize = opndManager->memStackSize; + int32 savedBase = opndManager->savedBase; + + if(LOG_ON) { + if (rpBak!=LOCATION_INVALID && rpBak>=S_OUTARG_BASE) { IPF_ERR << " rpBak = " << rpBak << endl; } + if (prBak!=LOCATION_INVALID && prBak >= S_OUTARG_BASE) { IPF_ERR << " prBak = " << prBak << endl; } + if (pfsBak!=LOCATION_INVALID && pfsBak >= S_OUTARG_BASE) { IPF_ERR << " pfsBak = " << pfsBak << endl; } + if (unatBak!=LOCATION_INVALID && unatBak >= S_OUTARG_BASE) { IPF_ERR << " unatBak = " << unatBak << endl; } + + if (rpBak==LOCATION_INVALID) { IPF_LOG << " return pointer is not saved" << endl; } + else if (rpBak >= S_BASE) { IPF_LOG << " return pointer saved on stack offset " << rpBak-S_BASE << endl; } + else { IPF_LOG << " return pointer saved on reg " << rpBak << endl; } + + if (prBak==LOCATION_INVALID) { IPF_LOG << " pred registers are not saved" << endl; } + else if (prBak >= S_BASE) { IPF_LOG << " pred registers saved on stack offset " << prBak-S_BASE << endl; } + else { IPF_LOG << " pred registers saved on reg " << prBak << endl; } + + if (pfsBak==LOCATION_INVALID) { IPF_LOG << " pfs register is not saved " << endl; } + else if (pfsBak >= S_BASE) { IPF_LOG << " pfs register saved on stack offset " << pfsBak-S_BASE << endl; } + else { IPF_LOG << " pfs register saved on reg " << pfsBak << endl; } + + if (unatBak==LOCATION_INVALID) { IPF_LOG << " unat register is not saved " << endl; } + else if (unatBak >= S_BASE) { IPF_LOG << " unat register saved on stack offset " << unatBak-S_BASE << endl; } + else { IPF_LOG << " unat register saved on reg " << unatBak << endl; } + + IPF_LOG << " memory stack offset for preserved regs " << savedBase << endl; + IPF_LOG << " saved general registers (hex mask) " << hex << savedGrMask << endl; + IPF_LOG << " saved floating registers (hex mask) " << hex << savedFrMask << endl; + IPF_LOG << " saved branch registers (hex mask) " << hex << savedBrMask << endl; + IPF_LOG << " stack size " << dec << memStackSize << endl; + } + + return (StackInfo *)opndManager; +} + +//----------------------------------------------------------------------------------------// +// Build GC Root Set +//----------------------------------------------------------------------------------------// +// - Build set of alive mptrs and bases for each safe point (call instruction) +// - Build mptr->base dependencies for all mptrs (mptr = base + const) +// - Extend base live ranges. For each mptr alive on safe point we must report base. Thus, the base +// must be alive on the safe point. + +void RuntimeSupport::buildRootSet() { + + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); + RegOpndSet liveSet; + + for (uint16 i=0; i<nodes.size(); i++) { // iterate through CFG nodes + + if (nodes[i]->isBb() == false) continue; // non BB node - ignore + + liveSet.clear(); // clear live set + nodes[i]->mergeOutLiveSets(liveSet); // put in the live set merged live sets of successors + + BbNode *node = (BbNode *)nodes[i]; + InstVector &insts = node->getInsts(); + InstIterator currInst = insts.end()-1; + InstIterator firstInst = insts.begin()-1; + + for (; currInst>firstInst; currInst--) { + + Inst *inst = *currInst; + LiveAnalyzer::defOpnds(liveSet, inst); // update liveSet for currInst + if (Encoder::isBranchCallInst(inst)) { // if currInst is "call" (only safe point we have) + newSafePoint(node, inst, liveSet); // insert (safe point->liveSet) pair in sp2LiveSet + } + LiveAnalyzer::useOpnds(liveSet, inst); // update liveSet for currInst + defMptr(node, inst); // build mptr->base dependency for currInst + } + } + + if (LOG_ON) { + IPF_LOG << endl << " Build mptr to base map:" << endl; + for (MptrDefMapIterator it=mptr2def.begin(); it!=mptr2def.end(); it++) { + IPF_LOG << " " << IrPrinter::toString(it->first) << "->"; + IPF_LOG << IrPrinter::toString(it->second.base) << endl; + } + } + + IPF_LOG << " Safe point list:" << endl; + // set mptr->base relations (vector SafePoint.alivePtrs will contain base after each mptr) + // and extend bases live ranges + for (uint16 i=0; i<safePoints.size(); i++) { + SafePoint& sp = safePoints[i]; + insertBases(sp.inst, sp.alivePtrs); + } +} + +//----------------------------------------------------------------------------------------// +// - Add new record in rootSet map (sp position -> alive mptrs&bases) +// - extend base live ranges + +void RuntimeSupport::newSafePoint(BbNode *node, Inst *spInst, RegOpndSet &liveSet) { + + safePoints.push_back(SafePoint(node, spInst)); // create record for current safe point + RegOpndVector &ptrs = safePoints.back().alivePtrs; // get vector for mptrs and bases alive on the safe point + + for (RegOpndSetIterator it=liveSet.begin(); it!=liveSet.end(); it++) { + RegOpnd *opnd = *it; + if (opnd->getDataKind() == DATA_MPTR) { + ptrs.push_back(opnd); + ptrs.push_back(NULL); + } + if (opnd->getDataKind() == DATA_BASE) { + ptrs.push_back(opnd); + } + } +} + +//----------------------------------------------------------------------------------------// +// If inst defs mptr and uses base - add new record in mptr2base map + +void RuntimeSupport::defMptr(BbNode *node, Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); + uint16 numDst = inst->getNumDst(); + uint16 numOpnd = inst->getNumOpnd(); + RegOpnd *mptr = NULL; + RegOpnd *base = NULL; + + // check if the inst defines mptr + for (uint16 i=1; i<=numDst; i++) { + if (opnds[i]->getDataKind() == DATA_MPTR) mptr = (RegOpnd *)opnds[i]; + } + if (mptr == NULL) return; // there is no mptr among dst opnds of the inst + + // check if the inst uses base + for (uint16 i=numDst+1; i<numOpnd; i++) { + if (opnds[i]->getDataKind() == DATA_BASE) base = (RegOpnd *)opnds[i]; + } + if (base == NULL) return; // there is no base among src opnds of the inst + + // add new record or merge with existing one in mptr2def map + if (mptr2def.count(mptr) > 0) { // if there is record for this mptr (mptr has been already defined) + MptrDef &md = mptr2def[mptr]; + if (md.inst != NULL) { // if record base has not been merged - merge it + RegOpnd *commonBase = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); // create common base for this mptr + mergeBase(md.node, md.inst, md.base, commonBase); // merge record base with new common base + md.base = commonBase; // record base is common base now + md.inst = NULL; + md.node = NULL; + } + mergeBase(node, inst, base, md.base); // merge current base with common base + } else { + mptr2def[mptr] = MptrDef(node, inst, base); // add new record (new mptr definition found) + } +} + +//----------------------------------------------------------------------------------------// +// From: +// add mptr = 5, oldBase +// To: +// mov commonBase = oldBase +// add mptr = 5, commonBase + +void RuntimeSupport::mergeBase(BbNode *node, Inst *inst, RegOpnd *oldBase, RegOpnd *commonBase) { + + if (oldBase == commonBase) return; // nothing to do + replaceBase(inst, oldBase, commonBase); // replace old base opnd with new one in the current instruction + insertMovInst(node, inst, oldBase, commonBase); // insert inst "mov commonBase, oldBase" before inst defining the mptr +} + +//----------------------------------------------------------------------------------------// +// - Find base opnd among inst srcs +// - Replace it with commonBase opnd +// - Return old base + +void RuntimeSupport::replaceBase(Inst *inst, Opnd *base, Opnd *commonBase) { + + OpndVector &opnds = inst->getOpnds(); + uint16 numDst = inst->getNumDst(); + uint16 numOpnd = inst->getNumOpnd(); + + for (uint16 i=numDst+1; i<numOpnd; i++) { + if (opnds[i] == base) { + opnds[i] = commonBase; + return; + } + } + IPF_ERR << endl; +} + +//----------------------------------------------------------------------------------------// + +void RuntimeSupport::insertMovInst(BbNode *node, Inst *inst, Opnd *oldBase, Opnd *commonBase) { + + InstVector &insts = node->getInsts(); + Inst *newInst = new(mm) Inst(INST_MOV, commonBase, oldBase); + InstIterator pos = find(insts.begin(), insts.end(), inst); + + if (LOG_ON) if (pos == insts.end()) IPF_ERR << endl; + + insts.insert(pos, newInst); +} + +//----------------------------------------------------------------------------------------// +// Find base corresponding to mptr and +// - insert it in vector of alive on safe point opnds +// - insert it in safe point instruction arg list (extend live range) + +void RuntimeSupport::insertBases(Inst *inst, RegOpndVector &ptrs) { + + IPF_LOG << " alive pointers:"; + for (uint16 i=0; i<ptrs.size(); i++) { + IPF_LOG << " " << IrPrinter::toString(ptrs[i]); + if (ptrs[i]->getDataKind() == DATA_MPTR) { + RegOpnd *mptr = (RegOpnd *)ptrs[i]; + if (LOG_ON && mptr2def.count(mptr) == 0) IPF_ERR << IrPrinter::toString(mptr) << endl; + RegOpnd *base = mptr2def[mptr].base; + if (find(ptrs.begin(), ptrs.end(), base) == ptrs.end()) { + ptrs.push_back(base); + } + ptrs[++i] = base; // next to mptr opnd is the mptr's base + inst->addOpnd(base); // extend base live range till the inst + base->setCrossCallSite(true); // base must live across call site + IPF_LOG << "->" << IrPrinter::toString(base); + } + } + IPF_LOG << " safe point: " << IrPrinter::toString(inst) << endl; +} + +//----------------------------------------------------------------------------------------// +// Write GC Root Set info block +//----------------------------------------------------------------------------------------// +// Create info block which is used in GC root set enumeration routine (RuntimeInterface::getGCRootSet) + +void RuntimeSupport::makeRootSetInfo(Uint32Vector &info) { + + IPF_LOG << " Safe points list:" << endl; + for (uint16 i=0; i<safePoints.size(); i++) { + + BbNode *node = safePoints[i].node; + Inst *inst = safePoints[i].inst; + uint64 spAddr = node->getInstAddr(inst); // get address of safe point instruction + spAddr = (spAddr & 0xfffffffffffffff0) + 0x10; // zero low part and increment + writeSpInfo(info, spAddr, safePoints[i].alivePtrs); + } +} + +//----------------------------------------------------------------------------------------// + +void RuntimeSupport::writeSpInfo(Uint32Vector &info, uint64 spAddr, RegOpndVector &ptrs) { + + uint32 spAddrHight = spAddr; // hight part of spAddr + uint32 spAddrLow = spAddr >> 32; // low part of spAddr + uint16 sizePos = info.size(); + + info.push_back(0); // push safe point info size (placeholder) + info.push_back(spAddrHight); // push safe point addr (hight) + info.push_back(spAddrLow); // push safe point addr (low) + + IPF_LOG << " address: " << hex << spAddr << dec << " alive pointers locations:"; + for (uint16 i=0; i<ptrs.size(); i++) { + int32 location = toInt32(ptrs[i]); // get mptr location + info.push_back(location); // push base location + IPF_LOG << " " << location; + } + + info[sizePos] = (info.size() - sizePos) * sizeof(uint32); + IPF_LOG << " size: " << info[sizePos] << endl; +} + +//----------------------------------------------------------------------------------------// +// returns opnd location in form to store in info block + +int32 RuntimeSupport::toInt32(RegOpnd *opnd) { + + int32 location = opnd->getValue(); + if (LOG_ON && location >= S_OUTARG_BASE) IPF_ERR << " location = " << location << endl; + if (opnd->isMem() == true) location += NUM_G_REG; + if (opnd->getDataKind() == DATA_MPTR) location = - (location + 1); + return location; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfSpillGen.cpp vm/jitrino/src/codegenerator/ipf/IpfSpillGen.cpp new file mode 100644 index 0000000..128a764 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfSpillGen.cpp @@ -0,0 +1,375 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfSpillGen.h" +#include "IpfIrPrinter.h" +#include "IpfOpndManager.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// SpillGen +//========================================================================================// + +SpillGen::SpillGen(Cfg &cfg_) : + mm(cfg_.getMM()), + cfg(cfg_) { + + opndManager = cfg.getOpndManager(); + p0 = opndManager->getP0(); + sp = opndManager->getR12(); + stackAddr = opndManager->newRegOpnd(OPND_G_REG, DATA_I64, SPILL_REG1); + + outOffset = 0; + locOffset = 0; + psfOffset = 0; + inOffset = 0; + maxOffset = 0; +} + +//----------------------------------------------------------------------------------------// + +void SpillGen::genSpillCode() { + + // Iterate through CFG nodes + NodeVector &nodes = cfg.search(SEARCH_POST_ORDER); + for(uint16 i=0; i<nodes.size(); i++) { + + if(nodes[i]->getNodeKind() != NODE_BB) continue; // ignore not BB node + InstVector &insts = ((BbNode *)nodes[i])->getInsts(); // get node's insts + for(uint16 j=0; j<insts.size(); j++) { // iterate through the insts + + if (LOG_ON && containsStackOpnd(insts[j])==true) { + IPF_LOG << endl << " instruction: " << endl; + IPF_LOG << " " << IrPrinter::toString(insts[j]) << endl; + } + + spillInst(insts[j]); // gen spill and fill code for the inst + + InstIterator it = insts.begin() + j; // get iterator on current inst + insts.insert(it, fillCode.begin(), fillCode.end()); // insert fill code before curr inst + j += fillCode.size(); // increment counter + + it = insts.begin() + j + 1; // get iterator on current inst + insts.insert(it, spillCode.begin(), spillCode.end()); // insert spill code after curr inst + j += spillCode.size(); // increment counter + + if (LOG_ON) printResult(insts, j); + } + } +} + +//----------------------------------------------------------------------------------------// + +void SpillGen::spillInst(Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); // get inst opnds + uint16 numDst = inst->getNumDst(); // get num of dst opnds + uint16 numOpnd = inst->getNumOpnd(); // get num of all opnds + + // Generate fill code. Result in fillCode vector. It goes before current instruction + fillCode.clear(); // clear fill code buffer + resetSpillRegMasks(); // make all spill regs available + for(uint16 i=numDst+1; i<numOpnd; i++) { + if(opnds[i]->isMem() == false) continue; // ignore non stack opnds + + IPF_LOG << " opnd to fill: " << IrPrinter::toString(opnds[i]) << endl; + opnds[i] = spillOpnd((RegOpnd *)opnds[i], false); // gen fill code + } + + // Generate spill code. Result in fillCode vector. It goes after current instruction + spillCode.clear(); // clear spill code buffer + resetSpillRegMasks(); // make all spill regs available + for(uint16 i=0; i<numDst+1; i++) { + if(opnds[i]->isMem() == false) continue; // ignore non stack opnds + + IPF_LOG << " opnd to spill: " << IrPrinter::toString(opnds[i]) << endl; + opnds[i] = spillOpnd((RegOpnd *)opnds[i], true); // gen spill code + } +} + +//----------------------------------------------------------------------------------------// + +RegOpnd *SpillGen::spillOpnd(RegOpnd *stackOpnd, bool spillFlag) { + + // Create scratchOpnd + OpndKind opndKind = stackOpnd->getOpndKind(); + DataKind dataKind = stackOpnd->getDataKind(); + int32 scratchReg = getAvailableSpillReg(opndKind); + RegOpnd *scratchOpnd = opndManager->newRegOpnd(opndKind, dataKind, scratchReg); + + // calculate absolute offset and set it as location on stack opnd + opndManager->calculateOffset(stackOpnd); + + // Create instruction calculating stack address to store to + Opnd *offset = opndManager->newImm(stackOpnd->getValue()); + Inst *adds = new(mm) Inst(INST_ADDS, p0, stackAddr, offset, sp); + spillFlag ? spillCode.push_back(adds) : fillCode.push_back(adds); + + // Create instruction storing value from scratchOpnd on stack + switch(scratchOpnd->getOpndKind()) { + case OPND_G_REG: spillFlag ? spillGr(scratchOpnd) : fillGr(scratchOpnd); break; + case OPND_F_REG: spillFlag ? spillFr(scratchOpnd) : fillFr(scratchOpnd); break; + case OPND_B_REG: spillFlag ? spillBr(scratchOpnd) : fillBr(scratchOpnd); break; + case OPND_P_REG: spillFlag ? spillPr(scratchOpnd) : fillPr(scratchOpnd); break; + default: IPF_ERR << "invalid OpndKind " << IrPrinter::toString(scratchOpnd) << endl; + } + + return scratchOpnd; +} + +//----------------------------------------------------------------------------------------// + +void SpillGen::resetSpillRegMasks() { + + spillGrMask = opndManager->spillGrMask; + spillFrMask = opndManager->spillFrMask; + spillPrMask = opndManager->spillPrMask; + spillBrMask = opndManager->spillBrMask; +} + +//----------------------------------------------------------------------------------------// + +int32 SpillGen::getAvailableSpillReg(OpndKind opndKind) { + + switch(opndKind) { + case OPND_G_REG: return getAvailableReg(spillGrMask, NUM_G_REG); + case OPND_F_REG: return getAvailableReg(spillFrMask, NUM_F_REG); + case OPND_P_REG: return getAvailableReg(spillPrMask, NUM_P_REG); + case OPND_B_REG: return getAvailableReg(spillBrMask, NUM_B_REG); + default : return LOCATION_INVALID; + } +} + +//----------------------------------------------------------------------------------------// + +int32 SpillGen::getAvailableReg(RegBitSet ®Mask, int16 maskSize) { + + for(int16 i=0; i<maskSize; i++) if(regMask[i] == 1) { regMask[i]=0; return i; } + IPF_ERR << " No available spill reg" << endl; + return LOCATION_INVALID; + +} + +//----------------------------------------------------------------------------------------// +// add stackOpnd = 1, r34 +// +// add scratchOpnd = 1, r34 +// adds stackAddr = offset, r12 +// st [stackAddr] = scratchOpnd + +void SpillGen::spillGr(RegOpnd *scratchOpnd) { + + Completer completer = CMPLT_INVALID; + switch(scratchOpnd->getSize()) { + case 1 : completer = CMPLT_SZ_1; break; + case 2 : completer = CMPLT_SZ_2; break; + case 4 : completer = CMPLT_SZ_4; break; + case 8 : completer = CMPLT_SZ_8; break; + default : IPF_ERR << "invalid size " << IrPrinter::toString(scratchOpnd) << endl; + } + + Inst *st = new(mm) Inst(INST_ST, completer, p0, stackAddr, scratchOpnd); + spillCode.push_back(st); +} + +//----------------------------------------------------------------------------------------// +// fadd stackOpnd = f30, f31 +// +// fadd scratchOpnd = r30, f31 +// adds stackAddr = offset, r12 +// stf [stackAddr] = scratchOpnd + +void SpillGen::spillFr(RegOpnd *scratchOpnd) { + + Completer completer = CMPLT_INVALID; + switch(scratchOpnd->getDataKind()) { + case DATA_S : completer = CMPLT_FSZ_S; break; + case DATA_D : completer = CMPLT_FSZ_D; break; + case DATA_F : completer = CMPLT_FSZ_E; break; + default: IPF_ERR << "invalid DataKind " << IrPrinter::toString(scratchOpnd) << endl; + } + + Inst *st = new(mm) Inst(INST_STF, completer, p0, stackAddr, scratchOpnd); + spillCode.push_back(st); +} + +//----------------------------------------------------------------------------------------// +// mov stackOpnd = r34 +// +// mov scratchOpnd = r34 +// adds stackAddr = offset, r12 +// mov bufOpnd = scratchOpnd +// st [stackAddr] = bufOpnd + +void SpillGen::spillBr(RegOpnd *scratchOpnd) { + + int32 bufReg = getAvailableSpillReg(OPND_G_REG); + Opnd *bufOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_B, bufReg); + Inst *mov = new(mm) Inst(INST_MOV, p0, bufOpnd, scratchOpnd); + Inst *st = new(mm) Inst(INST_ST, CMPLT_SZ_8, p0, stackAddr, bufOpnd); + + spillCode.push_back(mov); + spillCode.push_back(st); +} + +//----------------------------------------------------------------------------------------// +// cmp stackOpnd, p0 = r0, r0 +// +// cmp scratchOpnd, p0 = r0, r0 +// adds stackAddr = offset, r12 +// mov bufOpnd = r0 +// (scratchOpnd) mov bufOpnd = 1 +// st [stackAddr] = bufOpnd + +void SpillGen::spillPr(RegOpnd *scratchOpnd) { + + int32 bufReg = getAvailableSpillReg(OPND_G_REG); + Opnd *bufOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_P, bufReg); + Opnd *imm1 = opndManager->newImm(1); + Inst *mov1 = new(mm) Inst(INST_MOV, p0, bufOpnd, opndManager->getR0()); + Inst *mov2 = new(mm) Inst(INST_MOV, scratchOpnd, bufOpnd, imm1); + Inst *st = new(mm) Inst(INST_ST, CMPLT_SZ_1, p0, stackAddr, bufOpnd); + + spillCode.push_back(mov1); + spillCode.push_back(mov2); + spillCode.push_back(st); +} + +//----------------------------------------------------------------------------------------// +// add r34 = stackOpnd, 1 +// +// adds stackAddr = offset, r12 +// ld scratchOpnd = [stackAddr] +// add r34 = scratchOpnd, 1 + +void SpillGen::fillGr(RegOpnd *scratchOpnd) { + + Completer completer = CMPLT_INVALID; + switch(scratchOpnd->getSize()) { + case 1 : completer = CMPLT_SZ_1; break; + case 2 : completer = CMPLT_SZ_2; break; + case 4 : completer = CMPLT_SZ_4; break; + case 8 : completer = CMPLT_SZ_8; break; + default : IPF_ERR << "invalid size " << IrPrinter::toString(scratchOpnd) << endl; + } + + Inst *ld = new(mm) Inst(INST_LD, completer, p0, scratchOpnd, stackAddr); + fillCode.push_back(ld); + + // Create sxt instruction for int32 data type + if(scratchOpnd->getDataKind() == DATA_I32) { + Inst *sxt = new(mm) Inst(INST_SXT, CMPLT_XSZ_4, p0, scratchOpnd, scratchOpnd); + fillCode.push_back(sxt); + } +} + +//----------------------------------------------------------------------------------------// +// fadd f30 = stackOpnd, f0 +// +// adds stackAddr = offset, r12 +// ldf scratchOpnd = [stackAddr] +// add f30 = scratchOpnd, f0 + +void SpillGen::fillFr(RegOpnd *scratchOpnd) { + + Completer completer = CMPLT_INVALID; + switch(scratchOpnd->getDataKind()) { + case DATA_S : completer = CMPLT_FSZ_S; break; + case DATA_D : completer = CMPLT_FSZ_D; break; + case DATA_F : completer = CMPLT_FSZ_E; break; + default: IPF_ERR << "invalid DataKind " << IrPrinter::toString(scratchOpnd) << endl; + } + + Inst *ld = new(mm) Inst(INST_LDF, completer, p0, scratchOpnd, stackAddr); + fillCode.push_back(ld); +} + +//----------------------------------------------------------------------------------------// +// br stackOpnd +// +// adds stackAddr = offset, r12 +// ld bufOpnd = [stackAddr] +// mov scratchOpnd = bufOpnd +// br scratchOpnd + +void SpillGen::fillBr(RegOpnd *scratchOpnd) { + + int32 bufReg = getAvailableSpillReg(OPND_G_REG); + Opnd *bufOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_I64, bufReg); + Inst *ld = new(mm) Inst(INST_LD, CMPLT_SZ_8, p0, bufOpnd, stackAddr); + Inst *mov = new(mm) Inst(INST_MOV, p0, scratchOpnd, bufOpnd); + + fillCode.push_back(ld); + fillCode.push_back(mov); +} + +//----------------------------------------------------------------------------------------// +// (stackOpnd) mov r34 = r0 +// +// adds stackAddr = offset, r12 +// ld bufOpnd = [stackAddr] +// cmp.ne scratchOpnd, p0 = bufOpnd, r0 +// (scratchOpnd) mov r34 = r0 + +void SpillGen::fillPr(RegOpnd *scratchOpnd) { + + int32 bufReg = getAvailableSpillReg(OPND_G_REG); + Opnd *bufOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_P, bufReg); + Inst *ld = new(mm) Inst(INST_LD, CMPLT_SZ_1, p0, bufOpnd, stackAddr); + Inst *cmp = new(mm) Inst(INST_CMP, CMPLT_CMP_CREL_NE, p0, scratchOpnd, p0, bufOpnd); + cmp->addOpnd(opndManager->getR0()); + + fillCode.push_back(ld); + fillCode.push_back(cmp); +} + +//----------------------------------------------------------------------------------------// + +bool SpillGen::containsStackOpnd(Inst *inst) { + + OpndVector &opnds = inst->getOpnds(); + uint16 numOpnd = inst->getNumOpnd(); + + for(uint16 i=0; i<numOpnd; i++) { + if(opnds[i]->isMem() == false) continue; // ignore non stack opnds + return true; + } + return false; +} + +//----------------------------------------------------------------------------------------// +// print spill/fill code for current inst + +void SpillGen::printResult(InstVector &insts, uint16 last) { + + if (fillCode.size()+spillCode.size() == 0) return; + uint16 first = last - fillCode.size() - spillCode.size(); + + for (uint16 i=first; i<=last; i++) { + IPF_LOG << " " << IrPrinter::toString(insts[i]) << endl; + } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfType.cpp vm/jitrino/src/codegenerator/ipf/IpfType.cpp new file mode 100644 index 0000000..982d143 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfType.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfType.h" + +namespace Jitrino { +namespace IPF { + +bool ipfLogIsOn = false; +bool ipfVerifyIsOn = true; + +//============================================================================// +// IpfType +//============================================================================// + +int16 IpfType::getSize(DataKind dataKind) { + + switch(dataKind) { + case DATA_BASE : return 8; + case DATA_MPTR : return 8; + case DATA_I8 : return 1; + case DATA_U8 : return 1; + case DATA_I16 : return 2; + case DATA_U16 : return 2; + case DATA_I32 : return 4; + case DATA_U32 : return 4; + case DATA_I64 : return 8; + case DATA_U64 : return 8; + case DATA_S : return 4; + case DATA_D : return 8; + case DATA_F : return 16; + case DATA_P : return 1; + case DATA_B : return 8; + case DATA_IMM : return 8; + case DATA_CONST_REF : return 8; + case DATA_NODE_REF : return 8; + case DATA_METHOD_REF : return 8; + case DATA_SWITCH_REF : return 8; + case DATA_INVALID : break; + } + + IPF_ERR << " unexpected dataKind " << dataKind << endl; + return 0; +} + +//----------------------------------------------------------------------------------------// + +bool IpfType::isReg(OpndKind opndKind) { + + switch(opndKind) { + case OPND_G_REG : + case OPND_F_REG : + case OPND_P_REG : + case OPND_B_REG : + case OPND_A_REG : + case OPND_IP_REG : + case OPND_UM_REG : return true; + case OPND_IMM : return false; + case OPND_INVALID : break; + } + + IPF_ERR << " unexpected opndKind " << opndKind << endl; + return 0; +} + +//----------------------------------------------------------------------------------------// + +bool IpfType::isImm(OpndKind opndKind) { + + switch(opndKind) { + case OPND_G_REG : + case OPND_F_REG : + case OPND_P_REG : + case OPND_B_REG : + case OPND_A_REG : + case OPND_IP_REG : + case OPND_UM_REG : return false; + case OPND_IMM : return true; + case OPND_INVALID : break; + } + + IPF_ERR << " unexpected opndKind " << opndKind << endl; + return 0; +} + +//----------------------------------------------------------------------------------------// + +bool IpfType::isSigned(DataKind dataKind) { + + switch(dataKind) { + case DATA_I8 : + case DATA_I16 : + case DATA_I32 : + case DATA_I64 : + case DATA_S : + case DATA_D : + case DATA_F : return true; + default : return false;; + } +} + +//----------------------------------------------------------------------------------------// + +bool IpfType::isFloating(DataKind dataKind) { + + switch(dataKind) { + case DATA_S : + case DATA_D : + case DATA_F : return true; + default : return false;; + } +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/IpfVerifier.cpp vm/jitrino/src/codegenerator/ipf/IpfVerifier.cpp new file mode 100644 index 0000000..73ef54f --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/IpfVerifier.cpp @@ -0,0 +1,1158 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#include "IpfEncoder.h" +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "IpfVerifier.h" + +#define O(n) ((opnds)[n]) +#define K(n) ((opnds)[n]->getOpndKind()) +#define V(n) ((opnds)[n]->getValue()) +#define C(n) ((cmpls)[n]) +#define GR(n) ((RegOpnd *)O(n)) + +#define IS_O(n) ((opnds).size()>=(n+1)) +#define IS_C(n) ((cmpls).size()>=(n+1)) +#define IS_AR(n) (IS_O(n) && K(n)==OPND_A_REG) +#define IS_GR(n) (IS_O(n) && K(n)==OPND_G_REG) +#define IS_FR(n) (IS_O(n) && K(n)==OPND_F_REG) +#define IS_PR(n) (IS_O(n) && K(n)==OPND_P_REG) +#define IS_BR(n) (IS_O(n) && K(n)==OPND_B_REG) +#define IS_IMM(n) (IS_O(n) && O(n)->isImm()) +#define IS_IMM6(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 6)) +#define IS_IMM8(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 8)) +#define IS_IMM9(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 9)) +#define IS_IMM13(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 13)) +#define IS_IMM14(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 14)) +#define IS_IMM22(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 22)) +#define IS_IMM25(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 25)) +#define IS_IMM64(n) (IS_IMM(n) && Opnd::isFoldableImm(V(n), 64)) + +#define IS_CONST_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_CONST_REF)) +#define IS_NODE_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_NODE_REF)) +#define IS_SWITCH_REF(n) (IS_O(n) && O(n)->isImm() && (O(n)->getDataKind()==DATA_SWITCH_REF)) +#define IS_REF(n) (IS_CONST_REF(n) || IS_NODE_REF(n) || IS_SWITCH_REF(n)) + +namespace Jitrino { +namespace IPF { + +IpfVerifier::IpfVerifier(Cfg & cfg_, CompilationInterface & compilationinterface_) : + cfg(cfg_), compilationinterface(compilationinterface_), mm(cfg_.getMM()) +{ + methodDesc = compilationinterface.getMethodToCompile(); + methodString = new(mm) string(""); + if (methodDesc != NULL) { + methodString->append((methodDesc->getParentType()!=NULL + ? methodDesc->getParentType()->getName() + : "")); + methodString->append("."); + methodString->append(methodDesc->getName()); + methodString->append(methodDesc->getSignatureString()); + } +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyMethod(char * str) { + bool ret = true; + + ret = ret && verifyMethodInsts(); + ret = ret && verifyMethodNodes(); + ret = ret && verifyMethodEdges(); + + return ret; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyMethodInsts(char * str) { + BbNode * node = (BbNode *)cfg.getEnterNode(); + bool ret = true; + + do { + ret = ret && verifyNodeInsts(node); + } while( (node = node->getLayoutSucc()) != NULL ); + + return ret; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyMethodNodes(char * str) { + + uint16 size1 = cfg.search(SEARCH_DIRECT_ORDER).size(); + uint16 size2 = cfg.search(SEARCH_POST_ORDER).size(); + + if(size1 != size2) { + cerr << "VERIFY ERROR: " << *methodString << " SEARCH_DIRECT_ORDER gives size " << size1; + cerr << " SEARCH_POST_ORDER gives size " << size2 << endl; + return false; + } + + return true; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyMethodEdges(char * str) { + BbNode* node = (BbNode*) cfg.getEnterNode(); + bool ret = true; + + do { + ret = ret && verifyNodeEdges(node); + } while( (node = node->getLayoutSucc()) != NULL ); + + return ret; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyNodeInsts(BbNode * node) { + InstVector & insts = node->getInsts(); + Inst * inst; + bool ret = true; + string * res = new(mm) string(); + + for (int i=0, ii=insts.size() ; i<ii ; i++ ) { + inst = insts[i]; + res->erase(); + if( !verifyInst(res, inst) ) { + cerr << "VERIFY METHOD ERROR: " << *methodString; + cerr << "; node id: " << node->getId() + << ", inst index: " << i + << ", inst code: " << IrPrinter::toString(inst) + << (res->empty() ? "" : " : ") << *res + << "\n"; + ret = false; + } + } + + return ret; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyInst(string * res, Inst * inst) { + InstCode icode = inst->getInstCode(); + OpndVector & opnds = inst->getOpnds(); + CompVector & cmpls = inst->getComps(); + + if ( !IS_PR(0) ) return false; + + switch (icode) { + // special cases + case INST_NOP: + return true; + case INST_HINT: + return true; + case INST_BREAK: + return true; + case INST_BREAKPOINT: + return true; + + case INST_BR13: + case INST_BRL13: + case INST_BR: + case INST_BRL: + case INST_BRP: + case INST_BRP_RET: + return br(res, inst, icode, opnds, cmpls); + + case INST_ADD: + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true; + if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true; + if (IS_GR(1) && IS_IMM22(2) && IS_GR(3)) { + if (V(2)<=3 && V(2)>=0) return true; + } + break;; + case INST_ADDS: + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true; + break;; + case INST_ADDL: // opnds[2]->getOpndKind() == OPND_IMM22 + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_IMM22(2) && IS_GR(3)) { + if (opnds[2]->getValue()<=3 && opnds[2]->getValue()>=0) return true; + } + break;; + case INST_ADDP4: + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true; + if (IS_GR(1) && IS_IMM14(2) && IS_GR(3)) return true; + break; + case INST_ALLOC: + if (!IS_O(5)) return false; + if (IS_GR(1) && IS_IMM(2) && IS_IMM(3) && IS_IMM(4) && IS_IMM(5)) { + if (V(0)!=0) return false; + if ((V(2) + V(3) + V(4))>96) return false; + if (V(5)>(V(2) + V(3) + V(4))) return false; + if ((V(2) + V(3))>(V(2) + V(3) + V(4))) return false; + if (V(5)%8 != 0) return false; + return true; + } + break; + case INST_AND: + case INST_ANDCM: + case INST_OR: + case INST_XOR: + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true; + if (IS_GR(1) && IS_IMM8(2) && IS_GR(3)) return true; + break; + case INST_SUB: + if (!IS_O(3)) return false; + if (IS_GR(1) && IS_GR(2) && IS_GR(3) && IS_O(4)) { + if (IS_IMM(4) && V(4)==1) return true; + return false; + } + if (IS_GR(1) && IS_GR(2) && IS_GR(3)) return true; + if (IS_GR(1) && IS_IMM8(2) && IS_GR(3)) return true; + break; + case INST_CMP: + case INST_CMP4: + return cmp_cmp4(res, inst, icode, opnds, cmpls); + case INST_FABS: + if (!IS_O(2)) return false; + if (IS_FR(1) && IS_FR(2)) return true; + break; + case INST_FADD: + { + uint64 opcode=8, x=0, sf=0; + + if (!IS_O(3) || IS_O(4)) return false; + if (!(IS_FR(1) && IS_FR(2) && IS_FR(3))) return false; + for (uint64 i=0 ; IS_C(i) ; i++ ) { + switch (C(i)) { + case CMPLT_PC_DYNAMIC: x=0; opcode=8; break; + case CMPLT_PC_SINGLE: x=1; opcode=8; break; + case CMPLT_PC_DOUBLE: x=0; opcode=9; break; + case CMPLT_SF0: sf=0; break; + case CMPLT_SF1: sf=1; break; + case CMPLT_SF2: sf=2; break; + case CMPLT_SF3: sf=3; break; + default: return false; + } + } + return true; + } + case INST_FAND: + case INST_FANDCM: + if ( !IS_O(3) || IS_O(4)) return false; + if (IS_FR(1) && IS_FR(2) && IS_FR(3)) return true; + break; + case INST_FC: + case INST_FC_I: + if (IS_GR(1) && !IS_O(2)) return true; + break; + case INST_FCMP: + return fcmp(res, inst, icode, opnds, cmpls); + case INST_FCLASS: + if (!IS_O(4) || IS_O(5)) return false; + for (unsigned int i=0 ; IS_C(i) ; ++i) { + if ( !(C(i)==CMPLT_FCMP_FCTYPE_UNC + || C(i)==CMPLT_FCMP_FCTYPE_NONE + || C(i)==CMPLT_FCMP_FCTYPE_NORMAL + || C(i)==CMPLT_FCREL_NM + || C(i)==CMPLT_FCREL_M) ) { + return false; + } + } + if (IS_PR(1) && IS_PR(2) && IS_FR(3) && IS_IMM9(4)) return true; + + break; + case INST_FCVT_FX: + case INST_FCVT_FX_TRUNC: + case INST_FCVT_FXU: + case INST_FCVT_FXU_TRUNC: + if ( IS_C(0) ) { + switch(C(0)) { + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2)) return true; + break; + case INST_FCVT_XF: + if (IS_FR(1) && IS_FR(2)) return true; + break; + case INST_FCVT_XUF: + if (IS_C(2)) return false; + for (uint32 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_PC_SINGLE: + case CMPLT_PC_DOUBLE: + case CMPLT_PC_DYNAMIC: + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2)) return true; + break; + case INST_FMA: + for (uint32 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_PC_SINGLE: + case CMPLT_PC_DOUBLE: + case CMPLT_PC_DYNAMIC: + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4)) return true; + break; + case INST_FMIN: + case INST_FMAX: + case INST_FAMIN: + case INST_FAMAX: + case INST_FPMIN: + case INST_FPMAX: + case INST_FPAMIN: + case INST_FPAMAX: + for (uint32 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2) && IS_FR(3)) return true; + break; + case INST_FPCMP: + for (uint32 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + case CMPLT_FCMP_FREL_EQ: + case CMPLT_FCMP_FREL_GT: + case CMPLT_FCMP_FREL_LT: + case CMPLT_FCMP_FREL_GE: + case CMPLT_FCMP_FREL_LE: + case CMPLT_FCMP_FREL_UNORD: + case CMPLT_FCMP_FREL_NEQ: + case CMPLT_FCMP_FREL_NGT: + case CMPLT_FCMP_FREL_NLT: + case CMPLT_FCMP_FREL_NGE: + case CMPLT_FCMP_FREL_NLE: + case CMPLT_FCMP_FREL_ORD: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4)) return true; + break; + case INST_FMERGE_NS: + case INST_FMERGE_S: + case INST_FMERGE_SE: + if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4)) return true; + break; + case INST_FNEG: + if (IS_FR(1) && IS_FR(2) && !IS_O(3) && !IS_C(0)) return true; + break; + case INST_FNMA: + for ( uint32 i=0 ; IS_C(i) ; i++ ) { + switch(C(i)) { + case CMPLT_PC_SINGLE: + case CMPLT_PC_DOUBLE: + case CMPLT_PC_DYNAMIC: + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4) && !IS_O(5)) return true; + break; + case INST_FNORM: + for ( uint32 i=0 ; IS_C(i) ; i++ ) { + switch(C(i)) { + case CMPLT_PC_SINGLE: + case CMPLT_PC_DOUBLE: + case CMPLT_PC_DYNAMIC: + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_FR(2) && !IS_FR(3)) return true; + break; + case INST_FSUB: + if (IS_FR(1) && IS_FR(2) && IS_FR(3) && !IS_O(4) && !IS_C(2)) return true; + break; + case INST_FRCPA: + if ( IS_C(0) ) { + switch(C(0)) { + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: + break; + default: + return false; + } + } + if (IS_FR(1) && IS_PR(2) && IS_FR(3) && IS_FR(4) && !IS_O(5)) return true; + break; + case INST_GETF_S: + case INST_GETF_D: + case INST_GETF_EXP: + case INST_GETF_SIG: + if (IS_GR(1) && IS_FR(2) && !IS_O(3)) return true; + break; + case INST_LD: + case INST_LD16: + case INST_LD16_ACQ: + case INST_LD8_FILL: + return ldx(res, inst, icode, opnds, cmpls); + case INST_LDF: + case INST_LDF8: + case INST_LDF_FILL: + return ldfx(res, inst, icode, opnds, cmpls); + case INST_MOV: + case INST_MOV_I: + case INST_MOV_M: + case INST_MOV_RET: + return mov(res, inst, icode, opnds, cmpls); + case INST_MOVL: + if (IS_GR(1) && IS_IMM64(2)) return true; + break; + case INST_SETF_S: + case INST_SETF_D: + case INST_SETF_EXP: + case INST_SETF_SIG: + if (!IS_O(3) && !IS_C(0) && IS_FR(1) && IS_GR(2)) return true; + break; + case INST_SHL: + case INST_SHR: + case INST_SHR_U: + if (!IS_C(0) && !IS_O(4) && IS_GR(1) && IS_GR(2) + && (IS_GR(3) || (IS_IMM(3) && (V(3)&0x3F)==V(3)))) return true; + break; + case INST_SHLADD: + if (V(3)>4 || V(3)<1) { res->append("shift value must be 1...4"); return false; } + if (!IS_C(0) && !IS_O(5) && IS_GR(1) && IS_GR(2) && IS_GR(4)) return true; + break; + case INST_ST: + case INST_ST8_SPILL: + case INST_ST16: + return stx(res, inst, icode, opnds, cmpls); + case INST_STF: + case INST_STF8: + case INST_STF_SPILL: + for (uint64 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_FSZ_D: + case CMPLT_FSZ_E: + case CMPLT_FSZ_S: + if (icode==INST_STF && i!=0) return false; + break; + case CMPLT_HINT_NONE: + case CMPLT_HINT_NTA: + if (icode!=INST_STF && i!=0) return false; + break; + default: + return false; + } + } + if (!IS_C(2) && IS_GR(1) && IS_FR(2) && (!IS_O(3) || IS_IMM9(3))) return true; + break; + case INST_SXT: + case INST_ZXT: + if (!IS_C(0)) return false; + switch (C(0)) { + case CMPLT_XSZ_1: + case CMPLT_XSZ_2: + case CMPLT_XSZ_4: + break; + default: + return false; + } + if (!IS_C(1) && IS_GR(1) && IS_GR(2)) return true; + break; + case INST_DEF: + case INST_USE: + return true; + case INST_XMA_L: + case INST_XMA_LU: + case INST_XMA_H: + case INST_XMA_HU: + if (!IS_C(0) && IS_FR(1) && IS_FR(2) && IS_FR(3) && IS_FR(4)) return true; + break; + + default: + IPF_ERR << ": NOT YET IMPLEMENTED VERIFIER FOR INSTRUCTION: " + << IrPrinter::toString(inst) << "\n"; + return true;; + } + + return false; +} + +bool IpfVerifier::br(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + unsigned int is13 = (icode==INST_BR13 || icode==INST_BRL13 ? 1 : 0); // must be 1 or 0 + + switch (icode) { + case INST_BRL13: + case INST_BRL: + if (IS_C(0) && C(0)==CMPLT_BTYPE_CALL) { + if (!IS_O(is13 + 2)) return false; + if (!IS_IMM64(is13 + 2)) return false; + if (!IS_BR(is13 + 1)) return false; + } else { + if (!IS_O(is13 + 1)) return false; + if (!IS_IMM64(is13 + 1)) return false; + } + for (uint64 i=1 ; IS_C(i) ; i++ ) { + switch (C(i)) { + case CMPLT_DH_CLR: + case CMPLT_WH_SPTK: + case CMPLT_WH_SPNT: + case CMPLT_WH_DPTK: + case CMPLT_WH_DPNT: + case CMPLT_PH_FEW: + case CMPLT_PH_MANY: + break; + default: + return false; + } + } + return true; + + case INST_BR: + case INST_BR13: + if (!IS_O(is13 + 1)) return false; + { + OpndKind okind1 = K(is13 + 1); + uint64 cmplt_btype=CMPLT_BTYPE_COND, btype=0, ph=0, bwh=0, dh=0; + + for (uint64 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_BTYPE_COND: btype=0; cmplt_btype=C(i); break; + case CMPLT_BTYPE_IA: btype=1; cmplt_btype=C(i); break; + case CMPLT_BTYPE_RET: btype=4; cmplt_btype=C(i); break; + case CMPLT_BTYPE_CLOOP: btype=5; cmplt_btype=C(i); break; + case CMPLT_BTYPE_CEXIT: btype=6; cmplt_btype=C(i); break; + case CMPLT_BTYPE_CTOP: btype=7; cmplt_btype=C(i); break; + case CMPLT_BTYPE_WEXIT: btype=2; cmplt_btype=C(i); break; + case CMPLT_BTYPE_WTOP: btype=3; cmplt_btype=C(i); break; + case CMPLT_BTYPE_CALL: btype=(uint64)-1; cmplt_btype=C(i); break; + //---------------------------- + // Branch_Whether_Hint, NOT for all branch instructions! + case CMPLT_WH_SPTK: bwh=0; break; + case CMPLT_WH_SPNT: bwh=1; break; + case CMPLT_WH_DPTK: bwh=2; break; + case CMPLT_WH_DPNT: bwh=3; break; + //---------------------------- + // Branch_Sequential_Prefetch_Hint (br, brl) + case CMPLT_PH_FEW: ph=0; break; + case CMPLT_PH_MANY: ph=1; break; + //---------------------------- + // Branch_Cache_Deallocation_Hint (br, brl) + case CMPLT_DH_NOT_CLR: dh=0; break; + case CMPLT_DH_CLR: dh=1; break; + default: + return false; + } + } + + if (cmplt_btype==CMPLT_BTYPE_CALL) { + if (!IS_O(is13 + 2)) return false; + if (!IS_BR(is13 + 1)) return false; + + if (IS_BR(is13 + 2)) { + return true; + } else { + if (!IS_IMM25(is13 + 2)) return false; + if ( IS_NODE_REF(is13 + 2) ) { + return true; + } else { + return true; + } + } + } else if (cmplt_btype==CMPLT_BTYPE_RET) { + return true; + } else if (cmplt_btype==CMPLT_BTYPE_CLOOP + || cmplt_btype==CMPLT_BTYPE_CEXIT + || cmplt_btype==CMPLT_BTYPE_CTOP) { + if ( IS_NODE_REF(is13 + 1) ) { + //assert(target != 0); + return true; + } else { + return true; + } + } else if (okind1==OPND_B_REG) { + return true; + } else { + if (!IS_IMM25(is13 + 1)) return false; + if ( IS_NODE_REF(is13 + 1) ) { + //assert(target!=0); + return true; + } else { + return true; + } + } + } + // fall to assert(0) + default: + IPF_LOG << __FILE__ << ": " << __LINE__ + << ": NOT YET IMPLEMENTED VERIFIER FOR INSTRUCTION: " + << IrPrinter::toString(inst) << "\n"; + return false; + } + + return false; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::fcmp(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + if (!IS_O(4) || !IS_C(0) || IS_O(5)) return false; + if (!IS_PR(1) || !IS_PR(2) || !IS_FR(3) || !IS_FR(4)) return false; + + switch (C(0)) { + case CMPLT_FCMP_FREL_EQ: + case CMPLT_FCMP_FREL_LT: + case CMPLT_FCMP_FREL_LE: + case CMPLT_FCMP_FREL_GT: + case CMPLT_FCMP_FREL_GE: + case CMPLT_FCMP_FREL_UNORD: + case CMPLT_FCMP_FREL_NEQ: + case CMPLT_FCMP_FREL_NLT: + case CMPLT_FCMP_FREL_NLE: + case CMPLT_FCMP_FREL_NGT: + case CMPLT_FCMP_FREL_NGE: + case CMPLT_FCMP_FREL_ORD: + break; + default: + res->append("WRONG COMPLETER"); + return false; + } + if (IS_C(2)) { + switch (C(1)) { + case CMPLT_FCMP_FCTYPE_NONE: + case CMPLT_FCMP_FCTYPE_UNC: break; + default: + res->append("WRONG COMPLETER"); + return false; + } + switch (C(2)) { + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: break; + default: + res->append("WRONG COMPLETER"); + return false; + } + } else if (IS_C(1)) { + switch (C(1)) { + case CMPLT_FCMP_FCTYPE_NONE: + case CMPLT_FCMP_FCTYPE_UNC: + case CMPLT_SF0: + case CMPLT_SF1: + case CMPLT_SF2: + case CMPLT_SF3: break; + default: + res->append("WRONG COMPLETER"); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::cmp_cmp4(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + if (!IS_O(4) || !IS_C(0)) return false; + if (!IS_PR(1) || !IS_PR(2) || !(IS_GR(3) || IS_IMM(3)) || !IS_GR(4)) return false; + if (IS_GR(3) && IS_GR(4)) { +// if (GR(3)->getDataKind() != GR(4)->getDataKind()) { +// res->append(IrPrinter::toString(O(3)) +// + " and " +// + IrPrinter::toString(O(4)) +// + " have different DataKind: " +// + getDataKindStr(GR(3)->getDataKind()) +// + ", " +// + getDataKindStr(GR(4)->getDataKind())); +// return false; +// } + } + + int64 p1=V(1), p2=V(2); + int64 r2=V(3), r3=V(4); + OpndKind okind3=K(3); + Completer crel = C(0); + Completer ctype = ( IS_C(1) ? C(1) : CMPLT_INVALID ); + uint64 opcode=0, ta=0, c=0, x2; + int64 tmp; + + // parse pseudo-op + if ( !IS_C(1) || ctype==CMPLT_CMP_CTYPE_UNC ) { + if ( IS_IMM8(3) ) { + switch (crel) { + case CMPLT_CMP_CREL_NE: + crel=CMPLT_CMP_CREL_EQ; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LE: + crel=CMPLT_CMP_CREL_LT; + r2--; + break; + case CMPLT_CMP_CREL_GT: + crel=CMPLT_CMP_CREL_LT; + r2--; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GE: + crel=CMPLT_CMP_CREL_LT; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LEU: + crel=CMPLT_CMP_CREL_LTU; + r2--; + break; + case CMPLT_CMP_CREL_GTU: + crel=CMPLT_CMP_CREL_LTU; + r2--; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = p1; p1 = p2; p2 = tmp; + break; + default: + break; + } + } else { + switch (crel) { + case CMPLT_CMP_CREL_NE: + crel=CMPLT_CMP_CREL_EQ; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LE: + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GT: + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + break; + case CMPLT_CMP_CREL_GE: + crel=CMPLT_CMP_CREL_LT; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_LEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = r3; r3 = r2; r2 = tmp; + tmp = p1; p1 = p2; p2 = tmp; + break; + case CMPLT_CMP_CREL_GTU: + crel=CMPLT_CMP_CREL_LTU; + tmp = r3; r3 = r2; r2 = tmp; + break; + case CMPLT_CMP_CREL_GEU: + crel=CMPLT_CMP_CREL_LTU; + tmp = p1; p1 = p2; p2 = tmp; + break; + default: + break; + } + } + } else if ( crel!=CMPLT_CMP_CREL_EQ && crel!=CMPLT_CMP_CREL_NE ) { + if ( crel==CMPLT_CMP_CREL_LT && r2>0 ) { + crel=CMPLT_CMP_CREL_GT; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_LE && r2>0 ) { + crel=CMPLT_CMP_CREL_GE; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_GT && r2>0 ) { + crel=CMPLT_CMP_CREL_LT; + tmp = r3; r3 = r2; r2 = tmp; + } else if ( crel==CMPLT_CMP_CREL_GE && r2>0 ) { + crel=CMPLT_CMP_CREL_LE; + tmp = r3; r3 = r2; r2 = tmp; + } + } + + switch (ctype) { + case CMPLT_CMP_CTYPE_AND: opcode=0xC; break; + case CMPLT_CMP_CTYPE_OR: opcode=0xD; break; + case CMPLT_CMP_CTYPE_OR_ANDCM: opcode=0xE; break; + default: + switch (crel) { + case CMPLT_CMP_CREL_LT: opcode=0xC; break; + case CMPLT_CMP_CREL_LTU: opcode=0xD; break; + case CMPLT_CMP_CREL_EQ: opcode=0xE; break; + default: + return false; + } + } + + switch (crel) { + case CMPLT_CMP_CREL_NE: ta=1; c=1; break; + case CMPLT_CMP_CREL_GE: ta=1; c=0; break; + case CMPLT_CMP_CREL_LE: ta=0; c=1; break; + case CMPLT_CMP_CREL_GT: ta=0; c=0; break; + case CMPLT_CMP_CREL_LTU: ta=0; c=(ctype==CMPLT_CMP_CTYPE_UNC ? 1 : 0); break; + case CMPLT_CMP_CREL_EQ: + if ( cmpls.size()==1 ) { ta=0; c=0; } + else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; } + else { ta=1; c=0; } + break; + case CMPLT_CMP_CREL_LT: + if ( cmpls.size()==1 ) { ta=0; c=0; } + else if ( ctype==CMPLT_CMP_CTYPE_UNC ) { ta=0; c=1; } + else { ta=1; c=1; } + break; + default: + return false; + } + + if ( (ctype==CMPLT_CMP_CTYPE_NORMAL || ctype==CMPLT_CMP_CTYPE_UNC + || crel==CMPLT_CMP_CREL_NE || crel==CMPLT_CMP_CREL_EQ || cmpls.size()==1) + && okind3==OPND_G_REG ) { + x2 = icode==INST_CMP ? 0 : 1; + return true; + } else if ( IS_IMM8(3) ) { + x2 = icode==INST_CMP ? 2 : 3; + return true; + } else { + if (r2!=0) return false; + x2 = icode==INST_CMP ? 0 : 1; + return true; + } + return false; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::stx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + switch (icode) { + case INST_ST: + for (uint64 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_SZ_1: + case CMPLT_SZ_2: + case CMPLT_SZ_4: + case CMPLT_SZ_8: + case CMPLT_ST_TYPE_NORMAL: + case CMPLT_ST_TYPE_REL: + case CMPLT_HINT_NONE: + case CMPLT_HINT_NTA: + break; + default: + return false; + } + } + if (!IS_C(3) && IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_IMM9(3))) return true; + break; + case INST_ST8_SPILL: + if (!IS_C(1) + && (!IS_C(0) || (IS_C(0) && (C(0)==CMPLT_HINT_NONE || C(0)==CMPLT_HINT_NTA))) + && IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_IMM9(3))) return true; + break; + case INST_ST16: + for (uint64 i=0 ; IS_C(i) ; i++) { + switch (C(i)) { + case CMPLT_ST_TYPE_NORMAL: + case CMPLT_ST_TYPE_REL: + case CMPLT_HINT_NONE: + case CMPLT_HINT_NTA: + break; + default: + return false; + } + } + if (!IS_C(2) && IS_GR(1) && IS_GR(2)) return true; + break; + default: + return false; + } + return false; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::ldx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + for (uint32 i=0 ; IS_C(i) ; i++ ) { + switch (C(i)) { + case CMPLT_SZ_1: + case CMPLT_SZ_2: + case CMPLT_SZ_4: + case CMPLT_SZ_8: + case CMPLT_LDTYPE_NORMAL: + case CMPLT_LDTYPE_S: + case CMPLT_LDTYPE_A: + case CMPLT_LDTYPE_SA: + case CMPLT_LDTYPE_BIAS: + case CMPLT_LDTYPE_ACQ: + case CMPLT_LDTYPE_C_CLR: + case CMPLT_LDTYPE_C_NC: + case CMPLT_LDTYPE_C_CLR_ACQ: + case CMPLT_HINT_NONE: + case CMPLT_HINT_NT1: + case CMPLT_HINT_NTA: + break; + default: + return false; + } + } + switch (icode) { + case INST_LD: + if (IS_C(2)) return false; + if (IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true; + break; + case INST_LD16: + case INST_LD16_ACQ: + if (IS_C(1)) return false; + if (IS_GR(1) && IS_GR(2) && !IS_O(3)) return true; + break; + case INST_LD8_FILL: + if (IS_C(1)) return false; + if (IS_GR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true; + break; + default: + break; + } + return false; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::ldfx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + for (uint32 i=0 ; IS_C(i) ; i++ ) { + switch (C(i)) { + case CMPLT_FSZ_E: + case CMPLT_FSZ_S: + case CMPLT_FSZ_D: + case CMPLT_LDTYPE_NORMAL: + case CMPLT_LDTYPE_S: + case CMPLT_LDTYPE_A: + case CMPLT_LDTYPE_SA: + case CMPLT_LDTYPE_C_CLR: + case CMPLT_LDTYPE_C_NC: + case CMPLT_HINT_NONE: + case CMPLT_HINT_NT1: + case CMPLT_HINT_NTA: + break; + default: + return false; + } + } + switch (icode) { + case INST_LDF: + if (IS_C(3)) return false; + break; + case INST_LDF8: + if (IS_C(2)) return false; + break; + case INST_LDF_FILL: + if (IS_C(1)) return false; + break; + default: + break; + } + if (IS_FR(1) && IS_GR(2) && (!IS_O(3) || IS_GR(3) || IS_IMM9(3))) return true; + return false; +} + +//----------------------------------------------------------------------------// +bool IpfVerifier::mov(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls) { + if (icode!=INST_MOV_RET && IS_O(1) && IS_O(2) && !IS_O(3) + && ((IS_AR(1) && IS_GR(2)) || (IS_GR(1) && IS_AR(2)) || (IS_AR(1) && IS_IMM8(2)))) + return true; + if (icode==INST_MOV && !IS_O(3) && ((IS_GR(1) && IS_BR(2)) || (IS_BR(1) && IS_GR(2)))) + return true; + if ((icode==INST_MOV || icode==INST_MOV_RET) && IS_O(3) && IS_BR(1) && IS_GR(2) && IS_IMM13(3)) { + for (uint32 i=0 ; IS_C(i) ; i++){ + switch (C(i)) { + case CMPLT_IH_NOT_IMP: + case CMPLT_IH_IMP: + case CMPLT_WH_DPTK: + case CMPLT_WH_SPTK: + case CMPLT_WH_IGNORE: + break; + default: + return false; + } + } + return true; + } + if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_FR(1) && IS_FR(2)) return true; + if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_GR(1) && IS_GR(2)) return true; + if (icode==INST_MOV && !IS_O(3) && !IS_C(0) && IS_GR(1) && (IS_IMM22(2) || IS_REF(2))) return true; + + return false; +} + +//----------------------------------------------------------------------------// + +bool IpfVerifier::verifyNodeEdges(BbNode * node) { + string * res = new(mm) string(); + ostringstream oss; + + EdgeVector& outEdges = node->getOutEdges(); + + if(outEdges.size() == 0 && cfg.getExitNode() != node) { + oss << endl << " does not have out edges"; + } + + for(uint16 i=0; i<outEdges.size(); i++) { + switch(outEdges[i]->getEdgeKind()) { + case EDGE_BRANCH : edgeBranch(node, outEdges[i], oss); break; + case EDGE_THROUGH : edgeThrough(node, outEdges[i], oss); break; + case EDGE_DISPATCH : break; + case EDGE_EXCEPTION : break; + case EDGE_INVALID : edgeInvalid(node, oss); break; + } + } + + res->append(oss.str()); + if(!res->empty()) { + cerr << "VERIFY ERROR: " << *methodString << " " << *res << endl; + return false; + } + return true; +} + +//----------------------------------------------------------------------------// + +void IpfVerifier::edgeBranch(Node* node, Edge* edge, ostream& os) { + + if(node->getNodeKind() != NODE_BB) { + os << endl << " is not BB, but contains EDGE_BRANCH"; + return; + } + + InstVector& insts = ((BbNode*) node)->getInsts(); + if(insts.size() == 0) { + os << endl << " does not have insts, but contains EDGE_BRANCH"; + return; + } + + Inst* branchInst = insts.back(); + if(Encoder::isBranchInst(branchInst) == false) { + os << endl << " contains EDGE_BRANCH, but last inst is not \"br\""; + return; + } + + Opnd* targetOpnd = branchInst->getOpnd(1); + if(targetOpnd->getDataKind() != DATA_NODE_REF) return; // it must be switch + + NodeRef* targetNodeRef = (NodeRef*) targetOpnd; + Node* targetNode=targetNodeRef->getNode(); + Node* edgeTarget= edge->getTarget(); + if (targetNode!=edgeTarget) { + os << "node" << node->getId() << " branch edge target and \"br\" instruction target are different"; + return; + } +} + +//----------------------------------------------------------------------------// + +void IpfVerifier::edgeThrough(Node* node, Edge* edge, ostream& os) { + + if(node->getNodeKind() != NODE_BB) { + os << endl << " is not BB, but contains EDGE_THROUGH"; + return; + } + + Node* edgeTarget = edge->getTarget(); + Node* layoutSucc = ((BbNode*) node)->getLayoutSucc(); + if(edgeTarget != layoutSucc) { + + // check if last inst is br.ret + Inst* lastInst = NULL; + InstVector & insts = ((BbNode*) node)->getInsts(); + if (insts.size()>0) lastInst = insts.back(); + + if(lastInst!=NULL && lastInst->getComps().size()>0 && lastInst->getComp(0)==CMPLT_BTYPE_RET) + return; + + os << endl + << " through edge target (node" + << (edgeTarget ? edgeTarget->getId() : (uint64)-1) + << ") and layout successor (node" + << (layoutSucc ? layoutSucc->getId() : (uint64)-1) + << ") are different"; + return; + } +} + +//----------------------------------------------------------------------------// + +void IpfVerifier::edgeInvalid(Node* node, ostream& os) { + + os << endl << " contains EDGE_INVALID"; +} + +//----------------------------------------------------------------------------// + +char * IpfVerifier::getDataKindStr(DataKind datakind) { + switch ( datakind ) { + case DATA_BASE: return "DATA_BASE"; + case DATA_MPTR: return "DATA_MPTR"; + case DATA_I8: return "DATA_I8"; + case DATA_U8: return "DATA_U8"; + case DATA_I16: return "DATA_I16"; + case DATA_U16: return "DATA_U16"; + case DATA_I32: return "DATA_I32"; + case DATA_U32: return "DATA_U32"; + case DATA_I64: return "DATA_I64"; + case DATA_U64: return "DATA_U64"; + case DATA_S: return "DATA_S"; + case DATA_D: return "DATA_D"; + case DATA_F: return "DATA_F"; + case DATA_P: return "DATA_P"; + default: return "DATA_XXX"; + } + return "DATA_XXX"; +} + +} // IPF +} // Jitrino diff --git vm/jitrino/src/codegenerator/ipf/include/IpfCfg.h vm/jitrino/src/codegenerator/ipf/include/IpfCfg.h new file mode 100644 index 0000000..84fbc62 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfCfg.h @@ -0,0 +1,452 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFCFG_H_ +#define IPFCFG_H_ + +#include "Type.h" +#include "CodeGenIntfc.h" +#include "IpfType.h" +#include "IpfEncoder.h" +#include "MemoryManager.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Forward declarations +//========================================================================================// + +class Opnd; +class Inst; +class Node; +class BbNode; +class Edge; +class OpndManager; + +//========================================================================================// +// Constant +//========================================================================================// + +class Constant { +public: + Constant(DataKind dataKind_); + void setOffset(int32 offset_) { offset = offset_; } + int32 getOffset() { return offset; } + void setAddress(void *address_) { address = address_; } + void *getAddress() { return address; } + void setSize(int16 size_) { size = size_; } + int16 getSize() { return size; } + DataKind getDataKind() { return dataKind; } + virtual void *getData() { return NULL; } + +protected: + void *address; + int32 offset; + int16 size; + DataKind dataKind; +}; + +//========================================================================================// +// SwitchConstant +//========================================================================================// + +class SwitchConstant : public Constant { +public: + SwitchConstant(); + void addEdge(Edge*); + Edge *getEdge(int16 choice) { return edgeList[choice]; }; + uint16 getChoice(Edge*); + uint16 getChoiceCount() { return edgeList.size(); }; + void *getData(void*); + int16 getSize(); + virtual ~SwitchConstant() {} + +protected: + EdgeVector edgeList; +}; + +//========================================================================================// +// int64 Constants +//========================================================================================// + +class Int64Constant : public Constant { +public: + Int64Constant(int64 value_) : Constant(DATA_I64) { value = value_; setSize(sizeof(int64)); }; + void *getData() { return NULL; }; + int64 getValue() { return value; }; + +protected: + int64 value; +}; + +//========================================================================================// +// Float Constants +//========================================================================================// + +class FloatConstant : public Constant { +public: + FloatConstant(float value_); + void *getData(); + double getValue() { return value; }; + +protected: + float value; +}; + +//========================================================================================// +// Double Constants +//========================================================================================// + +class DoubleConstant : public Constant { +public: + DoubleConstant(double value_); + void *getData(); + double getValue() { return value; }; + +protected: + double value; +}; + +//========================================================================================// +// Opnd +//========================================================================================// + +class Opnd : public CG_OpndHandle { +public: + Opnd(uint32, OpndKind=OPND_INVALID, DataKind=DATA_INVALID, int64=0); + + uint32 getId() { return id; } + OpndKind getOpndKind() { return opndKind; } + DataKind getDataKind() { return dataKind; } + void setValue(int64 value_) { value = value_; } + virtual int64 getValue() { return value; } + + bool isReg() { return IpfType::isReg(opndKind); } + bool isImm() { return IpfType::isImm(opndKind); } + bool isFloating() { return IpfType::isFloating(dataKind); } + bool isSigned() { return IpfType::isSigned(dataKind); } + int16 getSize() { return IpfType::getSize(dataKind); } + bool isWritable(); + bool isConstant(); + bool isMem(); + + bool isFoldableImm(int16 size) { return isFoldableImm(value, size); } + bool isImm(int); + static bool isFoldableImm(int64 value, int16 size); + +protected: + uint32 id; + OpndKind opndKind; + DataKind dataKind; + int64 value; +}; + +//========================================================================================// +// RegOpnd +//========================================================================================// + +class RegOpnd : public Opnd { +public: + RegOpnd(uint32, OpndKind, DataKind, int32=LOCATION_INVALID); + int64 getValue(); + void setLocation(int32 value_) { value = value_; } + int32 getLocation() { return value; } + + void incSpillCost(uint32 spillCost_) { spillCost += spillCost_; } + uint32 getSpillCost() { return spillCost; } + RegOpndSet &getDepOpnds() { return depOpnds; } + void markRegBusy(uint16 regNum) { busyRegMask[regNum] = true; } + RegBitSet &getBusyRegMask() { return busyRegMask; } + void setCrossCallSite(bool crossCallSite_) { crossCallSite = crossCallSite_; } + bool getCrossCallSite() { return crossCallSite; } + void insertDepOpnd(RegOpnd *depOpnd); + + virtual ~RegOpnd() {} + +protected: + // These fields are for register allocation algorithm + uint32 spillCost; // number of opnd uses + RegOpndSet depOpnds; // opnds which can not be placed in the same reg with the opnd + RegBitSet busyRegMask; // registers that can not be used for allocation of this opnd + bool crossCallSite; // opnd live range crosses call site +}; + +//========================================================================================// +// ConstantRef +//========================================================================================// + +class ConstantRef : public Opnd { +public: + ConstantRef::ConstantRef(uint32 id_, Constant *constant_, DataKind dataKind_ = DATA_CONST_REF) + : Opnd(id_, OPND_IMM, dataKind_, LOCATION_INVALID) { + constant = constant_; + } + + int64 getValue() { return (int64)constant->getAddress(); } + Constant *getConstant() { return constant; } + +protected: + Constant *constant; +}; + +//========================================================================================// +// NodeRef +//========================================================================================// + +class NodeRef : public Opnd { +public: + NodeRef(uint32 id_, BbNode *node_ = NULL) + : Opnd(id_, OPND_IMM, DATA_NODE_REF, LOCATION_INVALID), node(node_) {} + + int64 getValue(); + void setNode(BbNode *node_) { node = node_; } + BbNode *getNode() { return node; } + +protected: + BbNode *node; +}; + + +//========================================================================================// +// MethodRef +//========================================================================================// + +class MethodRef : public Opnd { +public: + MethodRef(uint32 id_, MethodDesc *method_ = NULL) + : Opnd(id_, OPND_IMM, DATA_METHOD_REF, LOCATION_INVALID), method(method_) {} + + int64 getValue(); + void setMethod(MethodDesc *method_) { method = method_; } + MethodDesc *getMethod() { return method; } + +protected: + MethodDesc *method; +}; + +//========================================================================================// +// Inst +//========================================================================================// + +class Inst { +public: + Inst(InstCode instCode_, + Opnd *op1=NULL, Opnd *op2=NULL, Opnd *op3=NULL, Opnd *op4=NULL, Opnd *op5=NULL, Opnd *op6=NULL); + + Inst(InstCode instCode_, Completer comp1, + Opnd *op1=NULL, Opnd *op2=NULL, Opnd *op3=NULL, Opnd *op4=NULL, Opnd *op5=NULL, Opnd *op6=NULL); + + Inst(InstCode instCode_, Completer comp1, Completer comp2, + Opnd *op1=NULL, Opnd *op2=NULL, Opnd *op3=NULL, Opnd *op4=NULL, Opnd *op5=NULL, Opnd *op6=NULL); + + Inst(InstCode instCode_, Completer comp1, Completer comp2, Completer comp3, + Opnd *op1=NULL, Opnd *op2=NULL, Opnd *op3=NULL, Opnd *op4=NULL, Opnd *op5=NULL, Opnd *op6=NULL); + + InstCode getInstCode() { return instCode; } + void setInstCode(InstCode instCode_) { instCode = instCode_; } + + CompVector &getComps() { return compList; } + Completer getComp(uint16 num) { return compList[num]; } + void addComp(Completer comp_) { compList.push_back(comp_); } + void removeLastComp() { compList.pop_back(); } + void setComp(uint32 num, Completer comp_) { compList[num] = comp_; } + + void addOpnd(Opnd *opnd_) { opndList.push_back(opnd_); } + void removeLastOpnd() { opndList.pop_back(); } + OpndVector &getOpnds() { return opndList; } + void setOpnd(uint32 num, Opnd *opnd_) { opndList[num] = opnd_; } + Opnd *getOpnd(uint32 num) { return opndList[num]; } + char *getInstMnemonic() { return Encoder::getMnemonic(instCode); } + + char *getCompMnemonic(Completer comp) { return Encoder::getMnemonic(comp); } + uint16 getNumDst() { return Encoder::getNumDst(instCode); } + uint16 getNumOpnd() { return Encoder::getNumOpnd(instCode); } + Inst& set_qp(Opnd *p1) { setOpnd(0, p1); return *this; } + + uint32 getAddr() { return addr; } + void setAddr(uint32 addr_) { addr = addr_; } + +protected: + InstCode instCode; + CompVector compList; + OpndVector opndList; + uint32 addr; // addr == <bundle's offset in basic block> + <slot's index> +}; + +//========================================================================================// +// Edge +//========================================================================================// + +class Edge { +public: + Edge(Node *source_, Node *target_, double prob_); + Edge(Node *source_, Node *target_, double prob_, EdgeKind kind_); + void setSource(Node *source_) { source = source_; } + Node *getSource() { return source; } + void setTarget(Node *target_) { target = target_; } + Node *getTarget() { return target; } + double getProb() { return prob; } + void setProb(double prob_) { prob = prob_; } + EdgeKind getEdgeKind() { return edgeKind; } + void setEdgeKind(EdgeKind kind_) { edgeKind = kind_; } + bool isBackEdge(); + void connect(Node *target); + void disconnect(); + +protected: + EdgeKind edgeKind; + Node *source; + Node *target; + double prob; +}; + +//========================================================================================// +// ExceptionEdge +//========================================================================================// + +class ExceptionEdge : public Edge { +public: + ExceptionEdge(Node*, Node*, double, Type*, uint32); + Type *getExceptionType() { return exceptionType; } + uint32 getPriority() { return priority; } + +protected: + Type *exceptionType; + uint32 priority; +}; + +//========================================================================================// +// Node +//========================================================================================// + +class Node { +public: + Node(uint32 id_, NodeKind kind_ = NODE_INVALID); + + void addEdge(Edge *edge); + void removeEdge(Edge *edge); + Edge *getOutEdge(EdgeKind edgeKind); + Edge *getOutEdge(Node *targetNode); + Edge *getInEdge(EdgeKind edgeKind); + Edge *getInEdge(Node *targetNode); + Node *getDispatchNode(); + void mergeOutLiveSets(RegOpndSet &resultSet); + + EdgeVector &getInEdges() { return inEdges; } + EdgeVector &getOutEdges() { return outEdges; } + void setNodeKind(NodeKind kind_) { nodeKind = kind_; } + NodeKind getNodeKind() { return nodeKind; } + void setId(uint32 id_) { id = id_; } + uint32 getId() { return id; } + void setLiveSet(RegOpndSet& liveSet_) { liveSet = liveSet_; } + RegOpndSet &getLiveSet() { return liveSet; } + void clearLiveSet() { liveSet.clear(); } + void setLoopHeader(Node *loopHeader_) { loopHeader = loopHeader_; } + Node *getLoopHeader() { return loopHeader; } + bool isBb() { return nodeKind == NODE_BB; } + void addInEdge(Edge *edge); + void removeInEdge(Edge *edge); + void printEdges(ostream& out); + +protected: + uint32 id; // node unique Id + NodeKind nodeKind; // + EdgeVector inEdges; // in edges list + EdgeVector outEdges; // out edges list + Node *loopHeader; // header of loop containing this node, if NULL - node is not in loop + RegOpndSet liveSet; // set of opnds alive on node enter + void printEdges(ostream& out, EdgeVector& edges, bool head); +}; + +//========================================================================================// +// BbNode +//========================================================================================// + +class BbNode : public Node { +public: + BbNode(uint32 execCounter_); + BbNode(uint32 execCounter_, uint32 id_); + void addInst(Inst *inst); + void removeInst(Inst *inst) { insts.erase(find(insts.begin(),insts.end(),inst)); } + InstVector &getInsts() { return insts; } + void setAddress(uint64 address_) { address = address_; } + uint64 getAddress() { return address; } + void setLayoutSucc(BbNode *layoutSucc_) { layoutSucc = layoutSucc_; } + BbNode *getLayoutSucc() { return layoutSucc; } + void setExecCounter(uint32 execCounter_) { execCounter = execCounter_; } + uint32 getExecCounter() { return execCounter; } + uint64 getInstAddr(Inst *inst) { return ((uint64)address + inst->getAddr()); } + +protected: + InstVector insts; + BbNode *layoutSucc; + uint64 address; + uint32 execCounter; +}; + +//========================================================================================// +// Cfg +//========================================================================================// + +class Cfg { +public: + Cfg(MemoryManager &mm, CompilationInterface &compilationInterface); + void addEdge(Edge *edge); + void removeEdge(Edge *edge); + void removeNode(Node *node); + NodeVector &search(SearchKind searchKind); + + MemoryManager &getMM() { return mm; } + void setEnterNode(Node *enterNode_) { enterNode = enterNode_; } + Node *getEnterNode() { return enterNode; } + void setExitNode(Node *exitNode_) { exitNode = exitNode_; } + Node *getExitNode() { return exitNode; } + OpndManager *getOpndManager() { return opndManager; } + uint16 getNextNodeId() { return maxNodeId++; } + uint16 getMaxNodeId() { return maxNodeId; } + MethodDesc *getMethodDesc() { return compilationInterface.getMethodToCompile(); } + void addArg(Opnd *opnd_) { argList.push_back(opnd_); } + OpndVector &getArgs() { return argList; } +protected: + void makePostOrdered(Node *node, NodeSet &visitedNodes); + void makeDirectOrdered(Node *node, NodeSet &visitedNodesd); + void makeLayoutOrdered(); + + MemoryManager &mm; + CompilationInterface &compilationInterface; + + Node *enterNode; + Node *exitNode; + NodeVector searchResult; + SearchKind lastSearchKind; + OpndManager *opndManager; + uint16 maxNodeId; + OpndVector argList; +}; + +} // IPF +} // Jitrino + +#endif /*IPFCFG_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfCfgVerifier.h vm/jitrino/src/codegenerator/ipf/include/IpfCfgVerifier.h new file mode 100644 index 0000000..ca3f092 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfCfgVerifier.h @@ -0,0 +1,43 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFCFGVERIFIER_H_ +#define IPFCFGVERIFIER_H_ + +#include "IpfCfg.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// IpfCfgVerifier +//========================================================================================// + + extern void ipfCfgVerifier(Cfg& cfg_); + +} // IPF +} // Jitrino + + +#endif /*IPFCFGVERIFIER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfCodeGenerator.h vm/jitrino/src/codegenerator/ipf/include/IpfCodeGenerator.h new file mode 100644 index 0000000..c2a5acd --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfCodeGenerator.h @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFCODEGENERATOR_H_ +#define IPFCODEGENERATOR_H_ + +#include "MemoryManager.h" +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// CodeGenerator +//========================================================================================// + +class CodeGenerator : public ::Jitrino::CodeGenerator { +public: + CodeGenerator(MemoryManager&, CompilationInterface&); + bool genCode(MethodCodeSelector&); + void genCode(SessionAction* s, MethodCodeSelector& m) {} // TODO + virtual ~CodeGenerator() {} + +protected: + MemoryManager &memoryManager; + CompilationInterface &compilationInterface; + MethodDesc *methodDesc; + + Cfg *cfg; +}; + +} // IPF +} // Jitrino + +#endif /*IPFCODEGENERATOR_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfCodeLayouter.h vm/jitrino/src/codegenerator/ipf/include/IpfCodeLayouter.h new file mode 100644 index 0000000..711c107 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfCodeLayouter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFCODELAYOUTER_H_ +#define IPFCODELAYOUTER_H_ + +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Typedefs +//========================================================================================// + +typedef vector< NodeVector* > ChainVector; + +//========================================================================================// +// CodeLayouter +//========================================================================================// + +class CodeLayouter { +public: + CodeLayouter(Cfg &cfg_); + void layout(); + +protected: + void mergeNodes(); + bool mergeNode(BbNode *pred, Edge *pred2succ); + void makeChains(); + void fixBranches(); + void fixConditionalBranch(BbNode *node); + void fixSwitch(BbNode *node); + void fixUnconditionalBranch(BbNode *node); + + MemoryManager &mm; + Cfg &cfg; + ChainVector chains; +}; + +} // IPF +} // Jitrino +#endif /*IPFCODELAYOUTER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfCodeSelector.h vm/jitrino/src/codegenerator/ipf/include/IpfCodeSelector.h new file mode 100644 index 0000000..d1ec8a4 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfCodeSelector.h @@ -0,0 +1,384 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef _IPF_CODE_SELECTOR_H_ +#define _IPF_CODE_SELECTOR_H_ + +#include "CodeGenIntfc.h" +#include "VMInterface.h" +//#include "Profiler.h" +#include "IpfCfg.h" +#include "IpfOpndManager.h" + +namespace Jitrino { +namespace IPF { + +#define NOT_IMPLEMENTED_C(name) { IPF_ERR << name << " INSTRUCTION NOT IMPLEMENTED" << endl; return NULL; } +#define NOT_IMPLEMENTED_V(name) { IPF_ERR << name << " INSTRUCTION NOT IMPLEMENTED" << endl; } + +//========================================================================================// +// IpfMethodCodeSelector +//========================================================================================// + +class IpfMethodCodeSelector : public MethodCodeSelector::Callback { +public: + IpfMethodCodeSelector(Cfg&, CompilationInterface&); + MethodDesc *getMethodDesc(); + + void genVars(uint32, VarCodeSelector&); + void setMethodDesc(MethodDesc*); + void genCFG(uint32, CFGCodeSelector&, bool); +// void setProfileInfo(CodeProfiler*); + virtual ~IpfMethodCodeSelector() {} + +protected: + MemoryManager &mm; + Cfg &cfg; + CompilationInterface &compilationInterface; + MethodDesc *methodDesc; +// CodeProfiler *codeProfiler; + OpndVector opnds; + NodeVector nodes; +}; + +//========================================================================================// +// IpfVarCodeSelector +//========================================================================================// + +class IpfVarCodeSelector : public VarCodeSelector::Callback { +public: + IpfVarCodeSelector(Cfg&, OpndVector&); + uint32 defVar(Type*, bool, bool); + void setManagedPointerBase(uint32, uint32); + +protected: + MemoryManager &mm; + Cfg &cfg; + OpndVector &opnds; + OpndManager *opndManager; +}; + +//========================================================================================// +// IpfCfgCodeSelector +//========================================================================================// + +class IpfCfgCodeSelector : public CFGCodeSelector::Callback { +public: + IpfCfgCodeSelector(Cfg&, NodeVector&, OpndVector&, CompilationInterface&); + uint32 genDispatchNode(uint32, uint32, double); + uint32 genBlock(uint32, uint32, BlockKind, BlockCodeSelector&, double); + uint32 genUnwindNode(uint32, uint32, double); + uint32 genExitNode(uint32, double); + void genUnconditionalEdge(uint32, uint32, double); + void genTrueEdge(uint32, uint32, double); + void genFalseEdge(uint32, uint32, double); + void genSwitchEdges(uint32, uint32, uint32*, double*, uint32); + void genExceptionEdge(uint32, uint32, double); + void genCatchEdge(uint32, uint32, uint32, Type*, double); + void genExitEdge(uint32, uint32, double); + void setLoopInfo(uint32, bool, bool, uint32); + void setPersistentId(uint32, uint32); + virtual ~IpfCfgCodeSelector() {} + +protected: + MemoryManager &mm; + Cfg &cfg; + NodeVector &nodes; + OpndVector &opnds; + CompilationInterface &compilationInterface; +}; + +//========================================================================================// +// IpfInstCodeSelector +//========================================================================================// +//Jitrino::CG_OpndHandle* Jitrino::InstructionCallback::scaledDiffRef(Jitrino::CG_OpndHandle*, Jitrino::CG_OpndHandle*) +//virtual Jitrino::CG_OpndHandle* Jitrino::InstructionCallback::tau_ldIntfTableAddr(Jitrino::Type*, Jitrino::CG_OpndHandle*, Jitrino::NamedType*) +//virtual Jitrino::CG_OpndHandle* Jitrino::InstructionCallback::callvmhelper(unsigned int, Jitrino::CG_OpndHandle**, Jitrino::Type*, Jitrino::VMHelperCallOp::Id, Jitrino::InlineInfo*) + +class IpfInstCodeSelector : public InstructionCallback { + +public: + IpfInstCodeSelector(Cfg&, BbNode&, OpndVector&, CompilationInterface&); + + //---------------------------------------------------------------------------// + // Arithmetic + //---------------------------------------------------------------------------// + + CG_OpndHandle *add(ArithmeticOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *sub(ArithmeticOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *mul(ArithmeticOp::Types, CG_OpndHandle*, CG_OpndHandle*); + + CG_OpndHandle *addRef(RefArithmeticOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *subRef(RefArithmeticOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *diffRef(bool, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *scaledDiffRef(CG_OpndHandle*,CG_OpndHandle*, Type*, Type*); + + CG_OpndHandle *tau_div(DivOp::Types, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_rem(DivOp::Types, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + + CG_OpndHandle *neg (NegOp::Types, CG_OpndHandle*); + CG_OpndHandle *min_op (NegOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *max_op (NegOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *abs_op (NegOp::Types, CG_OpndHandle*); + + CG_OpndHandle *and_ (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *or_ (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *xor_ (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *not_ (IntegerOp::Types, CG_OpndHandle*); + CG_OpndHandle *shl (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *shr (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *shru (IntegerOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *shladd(IntegerOp::Types, CG_OpndHandle*, uint32, CG_OpndHandle*); + + CG_OpndHandle *convToInt(ConvertToIntOp::Types, bool, ConvertToIntOp::OverflowMod, Type*, CG_OpndHandle*); + CG_OpndHandle *convToFp(ConvertToFpOp::Types, Type*, CG_OpndHandle*); + + CG_OpndHandle *ldc_i4(uint32); + CG_OpndHandle *ldc_i8(uint64); + CG_OpndHandle *ldc_s(float); + CG_OpndHandle *ldc_d(double); + CG_OpndHandle *ldnull(bool); + CG_OpndHandle *ldVar(Type*, uint32); + void stVar(CG_OpndHandle*, uint32); + CG_OpndHandle *defArg(uint32, Type*); + + CG_OpndHandle *cmp (CompareOp::Operators, CompareOp::Types, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *czero (CompareZeroOp::Types, CG_OpndHandle*); + CG_OpndHandle *cnzero(CompareZeroOp::Types, CG_OpndHandle*); + + CG_OpndHandle *copy(CG_OpndHandle*); + CG_OpndHandle *tau_staticCast(ObjectType*, CG_OpndHandle*, CG_OpndHandle*); + + //---------------------------------------------------------------------------// + // Branch & Call + //---------------------------------------------------------------------------// + + void branch(CompareOp::Operators, CompareOp::Types, CG_OpndHandle*, CG_OpndHandle*); + void bzero (CompareZeroOp::Types, CG_OpndHandle*); + void bnzero(CompareZeroOp::Types, CG_OpndHandle*); + void tableSwitch(CG_OpndHandle*, uint32); + + CG_OpndHandle *call(uint32, CG_OpndHandle**, Type*, MethodDesc*, InlineInfo* ii = NULL); + CG_OpndHandle *tau_call(uint32, CG_OpndHandle**, Type*, MethodDesc*, CG_OpndHandle*, CG_OpndHandle*, InlineInfo* ii = NULL); + CG_OpndHandle *tau_calli(uint32,CG_OpndHandle**, Type*, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*, InlineInfo* ii = NULL); + CG_OpndHandle *tau_callintr(uint32, CG_OpndHandle**, Type*, IntrinsicCallOp::Id, CG_OpndHandle*, CG_OpndHandle*); + void ret(); + void ret(CG_OpndHandle*); + + //---------------------------------------------------------------------------// + // Exceptions & checks + //---------------------------------------------------------------------------// + + void throwException(CG_OpndHandle*, bool); + void throwSystemException(CompilationInterface::SystemExceptionId); + void throwLinkingException(Class_Handle, uint32, uint32); + CG_OpndHandle *catchException(Type*); + + CG_OpndHandle *tau_checkNull(CG_OpndHandle *, bool); + CG_OpndHandle *tau_checkBounds(CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_checkLowerBound(CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_checkUpperBound(CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_checkElemType(CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_checkZero(CG_OpndHandle*); + CG_OpndHandle *tau_checkCast(ObjectType*, CG_OpndHandle*, CG_OpndHandle*); + + //---------------------------------------------------------------------------// + // Memory operations + //---------------------------------------------------------------------------// + + void tau_stInd(CG_OpndHandle*, CG_OpndHandle*, Type::Tag, bool, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_ldInd(Type*, CG_OpndHandle*, Type::Tag, bool, bool, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *ldString(MethodDesc*, uint32, bool); + CG_OpndHandle *ldLockAddr(CG_OpndHandle*); + CG_OpndHandle *tau_ldVirtFunAddr(Type*, CG_OpndHandle*, MethodDesc*, CG_OpndHandle*); + CG_OpndHandle *tau_ldVTableAddr(Type*, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *getVTableAddr(Type*, ObjectType*); + CG_OpndHandle *tau_ldIntfTableAddr(Type*, CG_OpndHandle*, NamedType*); + CG_OpndHandle *ldFieldAddr(Type*, CG_OpndHandle*, FieldDesc*); + CG_OpndHandle *ldStaticAddr(Type*, FieldDesc*); + + CG_OpndHandle *tau_instanceOf(ObjectType*, CG_OpndHandle*, CG_OpndHandle*); + void initType(Type*); + CG_OpndHandle *newObj(ObjectType*); + CG_OpndHandle *newArray(ArrayType*, CG_OpndHandle*); + CG_OpndHandle *newMultiArray(ArrayType*, uint32, CG_OpndHandle**); + CG_OpndHandle *ldElemBaseAddr(CG_OpndHandle*); + CG_OpndHandle *addElemIndex(Type*, CG_OpndHandle*, CG_OpndHandle*); + CG_OpndHandle *tau_arrayLen(Type*, ArrayType*, Type*, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + + //---------------------------------------------------------------------------// + // Monitors + //---------------------------------------------------------------------------// + + void tau_monitorEnter(CG_OpndHandle*, CG_OpndHandle*); + void tau_monitorExit (CG_OpndHandle*, CG_OpndHandle*); + void typeMonitorEnter(NamedType*); + void typeMonitorExit (NamedType*); + CG_OpndHandle *tau_balancedMonitorEnter(CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + void balancedMonitorExit (CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*); + + //---------------------------------------------------------------------------// + // Methods that are not used (but implemented) + //---------------------------------------------------------------------------// + + CG_OpndHandle *tauPoint() { return opndManager->getTau(); } + CG_OpndHandle *tauEdge() { return opndManager->getTau(); } + CG_OpndHandle *tauUnsafe() { return opndManager->getTau(); } + CG_OpndHandle *tauSafe() { return opndManager->getTau(); } + CG_OpndHandle *tauAnd(uint32, CG_OpndHandle**) { return opndManager->getTau(); } + void opndMaybeGlobal(CG_OpndHandle* opnd) {} + void setCurrentPersistentId(PersistentInstructionId) {} + void clearCurrentPersistentId() {} + void setCurrentHIRHandler(uint64) {} + void setCurrentHIRInstrID(uint64) {} + + //---------------------------------------------------------------------------// + // Methods that are not going to be implemented + //---------------------------------------------------------------------------// + + CG_OpndHandle *mulhi(MulHiOp::Types, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("mulhi"); } + CG_OpndHandle *pred_czero (CompareZeroOp::Types, CG_OpndHandle*) { NOT_IMPLEMENTED_C("pred_czero") } + CG_OpndHandle *pred_cnzero(CompareZeroOp::Types, CG_OpndHandle*) { NOT_IMPLEMENTED_C("pred_cnzero") } + CG_OpndHandle *tau_checkDivOpnds(CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_checkDivOpnds") } + CG_OpndHandle *ldFunAddr(Type*, MethodDesc*) { NOT_IMPLEMENTED_C("ldFunAddr") } + CG_OpndHandle *uncompressRef(CG_OpndHandle *compref) { NOT_IMPLEMENTED_C("uncompressRef") } + CG_OpndHandle *compressRef(CG_OpndHandle *ref) { NOT_IMPLEMENTED_C("compressRef") } + CG_OpndHandle *ldFieldOffset(FieldDesc*) { NOT_IMPLEMENTED_C("ldFieldOffset") } + CG_OpndHandle *ldFieldOffsetPlusHeapbase(FieldDesc*) { NOT_IMPLEMENTED_C("ldFieldOffsetPlusHeapbase") } + CG_OpndHandle *ldArrayBaseOffset(Type*) { NOT_IMPLEMENTED_C("ldArrayBaseOffset") } + CG_OpndHandle *ldArrayLenOffset(Type*) { NOT_IMPLEMENTED_C("ldArrayLenOffset") } + CG_OpndHandle *ldArrayBaseOffsetPlusHeapbase(Type*) { NOT_IMPLEMENTED_C("ldArrayBaseOffsetPlusHeapbase") } + CG_OpndHandle *ldArrayLenOffsetPlusHeapbase(Type*) { NOT_IMPLEMENTED_C("ldArrayLenOffsetPlusHeapbase") } + CG_OpndHandle *addOffset(Type*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("addOffset") } + CG_OpndHandle *ldElemAddr(CG_OpndHandle*,CG_OpndHandle*) { NOT_IMPLEMENTED_C("ldElemAddr") } + CG_OpndHandle *ldStatic(Type*, FieldDesc*, Type::Tag, bool) { NOT_IMPLEMENTED_C("ldStatic") } + CG_OpndHandle *ldVarAddr(uint32) { NOT_IMPLEMENTED_C("ldVarAddr") } + CG_OpndHandle *ldToken(Type*, MethodDesc*, uint32) { NOT_IMPLEMENTED_C("ldToken") } + CG_OpndHandle *tau_cast(ObjectType*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_cast") } + CG_OpndHandle *tau_asType(ObjectType*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_asType") } + CG_OpndHandle *box(ObjectType*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("box") } + CG_OpndHandle *unbox(Type*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("unbox") } + CG_OpndHandle *ldValueObj(Type*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("ldValueObj") } + CG_OpndHandle *tau_ckfinite(CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_ckfinite") } + CG_OpndHandle *callhelper(uint32, CG_OpndHandle**, Type*, JitHelperCallOp::Id) { NOT_IMPLEMENTED_C("callhelper") } + CG_OpndHandle *tau_callvirt(uint32, CG_OpndHandle**, Type*, MethodDesc*, CG_OpndHandle*, CG_OpndHandle*, InlineInfo* ii = NULL) { NOT_IMPLEMENTED_C("tau_callvirt") } + CG_OpndHandle *select(CompareOp::Types, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("select") } + CG_OpndHandle *cmp3(CompareOp::Operators,CompareOp::Types, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("cmp3") } + CG_OpndHandle *pred_cmp(CompareOp::Operators,CompareOp::Types, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("pred_cmp") } + CG_OpndHandle *tau_optimisticBalancedMonitorEnter(CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_optimisticBalancedMonitorEnter") } + CG_OpndHandle *addOffsetPlusHeapbase(Type*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("addOffsetPlusHeapbase") } + CG_OpndHandle *tau_ldField(Type*, CG_OpndHandle*, Type::Tag, FieldDesc*, bool, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_ldField") } + CG_OpndHandle *tau_ldElem(Type*, CG_OpndHandle*, CG_OpndHandle*, bool, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_C("tau_ldElem") } + void incCounter(Type*, uint32) { NOT_IMPLEMENTED_V("incCounter") } + void incRecursionCount(CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("incRecursionCount") } + void monitorEnterFence(CG_OpndHandle*) { NOT_IMPLEMENTED_V("monitorEnterFence") } + void monitorExitFence(CG_OpndHandle*) { NOT_IMPLEMENTED_V("monitorExitFence") } + void stValueObj(CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("stValueObj") } + void initValueObj(Type*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("initValueObj") } + void copyValueObj(Type*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("copyValueObj") } + void prefetch(CG_OpndHandle*, uint32, int) { NOT_IMPLEMENTED_V("prefetch") } + void pred_btrue(CG_OpndHandle*) { NOT_IMPLEMENTED_V("pred_btrue") } + void jump() { NOT_IMPLEMENTED_V("jump") } + void throwLazyException(uint32, CG_OpndHandle**, MethodDesc*) { NOT_IMPLEMENTED_V("throwLazyException") } + void tau_stStatic(CG_OpndHandle*, FieldDesc*, Type::Tag, bool, CG_OpndHandle*) { NOT_IMPLEMENTED_V("tau_stStatic") } + void tau_stField(CG_OpndHandle*, CG_OpndHandle*, Type::Tag, FieldDesc*, bool, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("tau_stField") } + void tau_stElem(CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*, bool, CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("tau_stElem") } + void optimisticBalancedMonitorExit(CG_OpndHandle*, CG_OpndHandle*, CG_OpndHandle*) { NOT_IMPLEMENTED_V("optimisticBalancedMonitorExit") } + CG_OpndHandle *callvmhelper(uint32, CG_OpndHandle**, Type*, VMHelperCallOp::Id, InlineInfo* = NULL) { NOT_IMPLEMENTED_C("callvmhelper") } + + //---------------------------------------------------------------------------// + // convertors from HLO to IPF::CG types + //---------------------------------------------------------------------------// + + static DataKind toDataKind(IntegerOp::Types type); + static DataKind toDataKind(Type::Tag tag); + static OpndKind toOpndKind(Type::Tag tag); + static DataKind toDataKind(NegOp::Types type); + static OpndKind toOpndKind(NegOp::Types type); + static DataKind toDataKind(ArithmeticOp::Types type); + static OpndKind toOpndKind(ArithmeticOp::Types type); + static DataKind toDataKind(RefArithmeticOp::Types type); + static DataKind toDataKind(ConvertToIntOp::Types type, bool isSigned); + static OpndKind toOpndKind(DivOp::Types type); + static DataKind toDataKind(DivOp::Types type); + static InstCode toInstCmp(CompareOp::Types type); + static InstCode toInstCmp(CompareZeroOp::Types type); + static Completer toCmpltCrel(CompareOp::Operators cmpOp, bool isFloating); + static Completer toCmpltSz(DataKind dataKind); + +protected: + + // Create new inst and add it in current node + Inst& addNewInst(InstCode instCode_, + CG_OpndHandle *op1=NULL, CG_OpndHandle *op2=NULL, CG_OpndHandle *op3=NULL, + CG_OpndHandle *op4=NULL, CG_OpndHandle *op5=NULL, CG_OpndHandle *op6=NULL); + Inst& addNewInst(InstCode instCode_, Completer comp1, + CG_OpndHandle *op1=NULL, CG_OpndHandle *op2=NULL, CG_OpndHandle *op3=NULL, + CG_OpndHandle *op4=NULL, CG_OpndHandle *op5=NULL, CG_OpndHandle *op6=NULL); + Inst& addNewInst(InstCode instCode_, Completer comp1, Completer comp2, + CG_OpndHandle *op1=NULL, CG_OpndHandle *op2=NULL, CG_OpndHandle *op3=NULL, + CG_OpndHandle *op4=NULL, CG_OpndHandle *op5=NULL, CG_OpndHandle *op6=NULL); + + // CG helper methods + void directCall(uint32, Opnd**, RegOpnd*, Opnd*, RegOpnd*); + void indirectCall(uint32, Opnd**, RegOpnd*, RegOpnd*, RegOpnd*); + void makeCallArgs(uint32, Opnd**, Inst*, RegOpnd*); + RegOpnd *makeConvOpnd(RegOpnd*); + void makeRetVal(RegOpnd*, RegOpnd*, RegOpnd*); + + void add(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void sub(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void cmp(InstCode, Completer, RegOpnd*, RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void cmp(Completer, RegOpnd*, RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void binOp(InstCode, RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void shift(InstCode, RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, int); + void minMax(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, bool); + void xma(InstCode, RegOpnd*, CG_OpndHandle*, CG_OpndHandle*); + void saturatingConv4(RegOpnd*, CG_OpndHandle*); + void saturatingConv8(RegOpnd*, CG_OpndHandle*); + void divDouble(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, bool rem = false); + void divFloat(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, bool rem = false); + void divInt(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, bool rem = false); + void divLong(RegOpnd*, CG_OpndHandle*, CG_OpndHandle*, bool rem = false); + void ldc(RegOpnd*, int64 val); + void sxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize = CMPLT_INVALID); + void zxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize = CMPLT_INVALID); + RegOpnd *toRegOpnd(CG_OpndHandle*); + void ipfBreakCounted(int); + void ipfBreakCounted(RegOpnd*, Completer, int); + void ipfBreakCounted(RegOpnd*); + + MemoryManager &mm; + Cfg &cfg; + BbNode &node; + OpndVector &opnds; + CompilationInterface &compilationInterface; + OpndManager *opndManager; + int32 numFpInArgs; + + RegOpnd *p0; +}; + +} //namespace IPF +} //namespace Jitrino + +#endif // _IPF_CODE_SELECTOR_H_ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfDce.h vm/jitrino/src/codegenerator/ipf/include/IpfDce.h new file mode 100644 index 0000000..5a514ec --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfDce.h @@ -0,0 +1,53 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFDCE_H_ +#define IPFDCE_H_ + +#include "IpfCfg.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Dce +//========================================================================================// + +class Dce { +public: + Dce(Cfg &cfg_) : cfg(cfg_) {} + void eliminate(); + +protected: + bool isInstDead(Inst*); + void removeInst(InstVector&, InstIterator); + + Cfg &cfg; + RegOpndSet currLiveSet; +}; + +} // IPF +} // Jitrino + +#endif /*IPFDCE_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfEmitter.h vm/jitrino/src/codegenerator/ipf/include/IpfEmitter.h new file mode 100644 index 0000000..94322b3 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfEmitter.h @@ -0,0 +1,241 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFEMITTER_H_ +#define IPFEMITTER_H_ + +#include <vector> +#include <bitset> +#include "Type.h" +#include "IpfEncoder.h" +#include "IpfCfg.h" +#include "IpfCodeSelector.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// This file is based on following docs: +// Intel Itanium Architecture +// Software Developers Manual +// Volume 1: Application Architecture +// Volume 2: System Architecture +// Volume 3: Instruction Set Reference +// Revision 2.1 +// October 2002 +//========================================================================================// + +// +// Constants that describe cache on IPF +// + +// +// Level 1 cache +// +#define L1_CACHE_LINE_SIZE 64 + +// +// Level 2 cache +// +#define L2_CACHE_BANK_SIZE 16 +#define NUM_L2_CACHE_BANKS 16 + + +#define PR(n) (opndManager->newRegOpnd(OPND_P_REG, DATA_P, n)) +#define GR(n) (opndManager->newRegOpnd(OPND_G_REG, DATA_I64, n)) +#define FR(n) (opndManager->newRegOpnd(OPND_F_REG, DATA_F, n)) +#define BR(n) (opndManager->newRegOpnd(OPND_B_REG, DATA_I64, n)) +#define IMM(n) (opndManager->newImm(n)) + +#define IPF_SLOTS_COUNT 3 +#define IT_SLOT0(v) (0xFF & v) +#define IT_SLOT1(v) ((0xFF & v) << 8) +#define IT_SLOT2(v) ((0xFF & v) << 16) + +#define TEMPLATES_COUNT 24 // count of valid templates +#define IPF_CODE_ALIGNMENT 32 // 2-bundles alignment + +typedef vector<bool> vectorbool; +typedef bitset<128> bitset128; +typedef bitset<64> bitset64; +typedef bitset<8> bitset8; +typedef vector<Opnd *> vectorconst; + +//============================================================================// +/* + * Bundle description + * slots = slot_0_type | (slot_1_type << 8) | (slot_2_type << 16) + * type of slot is InstructionType enum, but IT_I...IT_X only + * stops = 1 in bit pos corresponds stop after those slot + * id est, 0x1 - stop after 0 slot, 0x6 - stops after 1 and 2 slots, ... + * tmpl = template field encoding + */ +struct BundleDescription { + uint32 slots; + uint32 stops; + uint32 tmpl; +}; + +//============================================================================// +class RegistersBitset { + public: + void reset() { + GR.reset(); + FR.reset(); + PR.reset(); + BR.reset(); + } + + bool any() { + return GR.any() || FR.any() || PR.any() || BR.any(); + } + + bitset128 GR; + bitset128 FR; + bitset64 PR; + bitset8 BR; +}; + +typedef vector<RegistersBitset *> vectorregs; + +//============================================================================// +// Bundle +//============================================================================// +class Bundle { + public: + Bundle(Cfg& cfg, uint32 tmpl, Inst *, Inst *, Inst *); + + Inst * getSlot(int si) { return slot[si]; }; + uint32 getTmplIndex() { return indxtmpl; }; + uint32 getTmpl(); + void emitBundleGeneral(void *); + void emitBundleExtended(void *); + void emitBundleBranch(void *, int *); + void print(); + uint64 getSlotBits(int); + uint64 getSlotBitsBranch(int, int); + uint64 * getSlotBitsExtended(uint64 *, void *); + + protected: + uint32 indxtmpl; + Inst *slot[IPF_SLOTS_COUNT]; +}; + +class BundleVector : public vector<Bundle*> { + MemoryManager& mm; + Cfg& cfg; + public: + BundleVector(Cfg& cfg): mm(cfg.getMM()), cfg(cfg) { + branches=new(mm) vector<int>; + }; + + void addBundle(uint32 itmpl, Inst *i0, Inst *i1, Inst *i2) { + push_back(new(mm) Bundle(cfg, itmpl, i0, i1, i2)); + if(Encoder::isBranchInst(i0) || Encoder::isBranchInst(i1) || Encoder::isBranchInst(i2)) { + branches->push_back(size() - 1); + } + } + + vector<int> * branches; // indexes of bundles which contain br, brl, ... + +}; + +class EmitterBb { + public: + EmitterBb(Cfg & cfg_, CompilationInterface & compilationinterface_ + , BbNode * node_, bool _setbreak=false); + + BbNode * node; + InstVector & insts; + long isize; + vectorbool * stops; + vectorregs * wregs; + vectorregs * rregs; + BundleVector * bundles; + vectorconst * consts; + + long bsize; + char * codeoff; // offset in full code block + long codesize; // size of this bb code block +}; + +typedef vector<EmitterBb *> vectorbb; + +//============================================================================// +// Encoder +//============================================================================// + +class Emitter { + public: + Emitter(Cfg & cfg_, CompilationInterface & compilationinterface_ + , bool break4cafe_=false); + + bool emit(); + void printInsts(char *); + void printInsts(int); + void printBundles(char *); + void printBundles(int); + void printCodeBlock(char *); + void printDisasm(char * cap); + void registerDirectCall(Inst *, uint64); + + static InstructionType getExecUnitType(int, int); + + static const BundleDescription BundleDesc[TEMPLATES_COUNT]; + + protected: + static void getTmpl(int, BundleDescription &, Inst *, Inst *, Inst *, bool, bool, bool); + static int findTmpl(const BundleDescription &); + static void getWriteDpndBitset(Inst *, RegistersBitset *); + static void getReadDpndBitset(Inst *, RegistersBitset *); + static bool tricking(InstVector & insts, MemoryManager& mm, Cfg& cfg); + static int removeUselessInst(Cfg &, CompilationInterface &); + bool parsing(); + bool parsing(int); + bool stopping(); + bool stopping(int); + bool bundling(); + bool bundling(int); + bool emitData(); + bool emitCode(); + bool fixSwitchTables(); + bool isBranchBundle(Bundle *, char *, char *, int *); + bool isExtendedBundle(Bundle *bundle) { if (bundle->getTmpl()>=0x4 && bundle->getTmpl()<=0x5) return true; return false; }; + char * getBbNodeOff(BbNode * node); + + MemoryManager& mm; + Cfg & cfg; + CompilationInterface & compilationinterface; + bool break4cafe; + vectorbb * bbs; + char * dataoff; + long datasize; // full size of data block + char * codeoff; + long codesize; // full size of code block (summ of all bb codesize) +}; + +} // IPF +} // Jitrino + +#endif /*IPFEMITTER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfEncoder.h vm/jitrino/src/codegenerator/ipf/include/IpfEncoder.h new file mode 100644 index 0000000..7e04e87 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfEncoder.h @@ -0,0 +1,1020 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFENCODER_H_ +#define IPFENCODER_H_ + +#include <vector> +#include <bitset> +#include "Type.h" +#include "IpfType.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +#define IPF_BUNDLE_SIZE 16 // 16 bytes + +//============================================================================// +// This file is based on following docs: +// Intel Itanium Architecture +// Software Developers Manual +// Volume 1: Application Architecture +// Volume 2: System Architecture +// Volume 3: Instruction Set Reference +// Revision 2.1 +// October 2002 +//============================================================================// + +// Type of instruction, Description Execution Unit Type +// IT_I...IT_X are used in bundle mask and occupies 1 byte +enum InstructionType { + IT_I = 0x01, // Non-ALU integer, I-unit slot type + IT_M = 0x02, // Memory, M-unit slot type + IT_A = IT_I | IT_M, // Integer ALU, I/M-unit slot type + IT_F = 0x04, // Floating-point, F-unit slot type + IT_B = 0x08, // Branch, B-unit slot type + IT_L = 0x10, // Extended, occupies 2 slots: 2nd ant 3d + // L+X Major Opcodes 0 - 7 execute on an I-unit. + // L+X Major Opcodes 8 - F execute on a B-unit. + IT_X = 0x20, // Continue of IT_L + IT_ANY = 0xFF, // ANY type above + + // pseudo-op + IT_PSEUDO_OP = 0x100, + IT_IGNORE_OP = 0x200, // the inst is ignored in all passes (stopping, bundling, etc.) + + // pseudo-op special: explicit set of unit, something else for chk.s + IT_EXPLICIT_IMBFX = 0x1000, // explicitly set compliter (I,M,B,F,X) due to slot type + IT_EXPLICIT_IM = 0x2000, // explicitly set compliter (I,M) due to slot type + + // positon in instruction group + IT_GF = 0x10000, // first in group + IT_GL = 0x20000 // last in group +}; + +// List of instructions +// - prefixed with INST_ +// - dots in names are replaced by underscores +// - there is a difference from "Volume 3: Instruction Set Reference": +// few instructions have variable operands count, but we havn't +// so there are additional instructions for those cases +enum InstCode { + INST_INVALID = -1, + INST_FIRST = 0, // MUST BE 0 + INST_ADD = INST_FIRST, + INST_ADDS, // imm-14 + INST_ADDL, // imm-22 + INST_ADDP4, + INST_ALLOC, + INST_AND, + INST_ANDCM, + INST_BR_FIRST, // start of continuous group of branch instructions + INST_BR=INST_BR_FIRST, + INST_BRL, + INST_BRP, // ip_relative_form, indirect_form + INST_BRP_RET, // return_form, indirect_form + INST_BR_LAST=INST_BRP_RET, // end of continuous group of branch instructions + INST_BREAK, + INST_BSW_0, + INST_BSW_1, + INST_CHK_S, + INST_CHK_S_I, + INST_CHK_S_M, + INST_CHK_A, + INST_CLRRRB, + INST_CLRRRB_PR, + INST_CMP, + INST_CMP4, + INST_CMPXCHG, + INST_CMP8XCHG16, + INST_COVER, + INST_CZX1_L, // one_byte_form, left_form + INST_CZX1_R, // one_byte_form, right_form + INST_CZX2_L, // two_byte_form, left_form + INST_CZX2_R, // two_byte_form, right_form + INST_DEP, + INST_DEP_Z, + INST_EPC, + INST_EXTR, + INST_EXTR_U, + INST_FABS, + INST_FADD, + INST_FAMAX, + INST_FAMIN, + INST_FAND, + INST_FANDCM, + INST_FC, // invalidate_line_form + INST_FC_I, // instruction_cache_coherent_form + INST_FCHKF, + INST_FCLASS, + INST_FCLRF, + INST_FCMP, + INST_FCVT_FX, // signed_form + INST_FCVT_FX_TRUNC, // signed_form, trunc_form + INST_FCVT_FXU, // unsigned_form + INST_FCVT_FXU_TRUNC, // unsigned_form, trunc_form + INST_FCVT_XF, + INST_FCVT_XUF, + INST_FETCHADD4, // four_byte_form + INST_FETCHADD8, // eight_byte_form + INST_FLUSHRS, + INST_FMA, + INST_FMAX, + INST_FMERGE_NS, // Floating-point Merge Negative Sign + INST_FMERGE_S, // Floating-point Merge Sign Operation + INST_FMERGE_SE, // Floating-point Merge Sign and Exponent + INST_FMIN, + INST_FMIX_L, // Floating-point Mix Left + INST_FMIX_R, // Floating-point Mix Right + INST_FMIX_LR, // Floating-point Mix Left-Right + INST_FMPY, + INST_FMS, + INST_FNEG, + INST_FNEGABS, + INST_FNMA, + INST_FNMPY, + INST_FNORM, + INST_FOR, + INST_FPABS, + INST_FPACK, + INST_FPAMAX, + INST_FPAMIN, + INST_FPCMP, + INST_FPCVT_FX, + INST_FPCVT_FX_TRUNC, + INST_FPCVT_FXU, + INST_FPCVT_FXU_TRUNC, + INST_FPMA, + INST_FPMAX, + INST_FPMERGE_NS, // Floating-point Parallel Merge Negative Sign + INST_FPMERGE_S, // Floating-point Parallel Merge Sign + INST_FPMERGE_SE, // Floating-point Parallel Merge Sign and Exponent Operation + INST_FPMIN, + INST_FPMPY, + INST_FPMS, + INST_FPNEG, + INST_FPNEGABS, + INST_FPNMA, + INST_FPNMPY, + INST_FPRCPA, + INST_FPRSQRTA, + INST_FRCPA, + INST_FRSQRTA, + INST_FSELECT, + INST_FSETC, + INST_FSUB, + INST_FSWAP, // Floating-point Swap + INST_FSWAP_NL, // Floating-point Swap Negate Left + INST_FSWAP_NR, // Floating-point Swap Negate Right + INST_FSXT_L, // Floating-point Sign Extend Left + INST_FSXT_R, // Floating-point Sign Extend Right + INST_FWB, + INST_FXOR, + INST_GETF_S, + INST_GETF_D, + INST_GETF_EXP, + INST_GETF_SIG, + INST_HINT, + INST_INVALA, // All entries in ALAT are invalidated + INST_INVALA_E, // One entry in ALAT is invalidated + INST_ITC_I, // itc.i instruction_form + INST_ITC_D, // itc.d data_form + INST_ITR_I, // instruction_form + INST_ITR_D, // data_form + INST_LD_FIRST, + INST_LD = INST_LD_FIRST, + INST_LD16, + INST_LD16_ACQ, + INST_LD8_FILL, + INST_LDF, // 4,8,10 bytes Single precision + INST_LDF8, // integer form + INST_LDF_FILL, // fill form + INST_LDFPS, + INST_LDFPD, + INST_LDFP8, + INST_LD_LAST = INST_LDFP8, + INST_LFETCH, + INST_LFETCH_EXCL, + INST_LOADRS, + INST_MF, + INST_MF_A, + INST_MIX1_L, // one_byte_form, left_form + INST_MIX2_L, // two_byte_form, left_form + INST_MIX4_L, // four_byte_form, left_form + INST_MIX1_R, // one_byte_form, right_form + INST_MIX2_R, // two_byte_form, right_form + INST_MIX4_R, // four_byte_form, right_form + INST_MOV, // there are many incarnations of mov, + // so parse it like pseudo-op + INST_MOV_I, + INST_MOV_M, + INST_MOV_RET, + INST_MOVL, + INST_MUX1, + INST_MUX2, + INST_NOP, + INST_OR, + INST_PACK2_SSS, + INST_PACK2_USS, + INST_PACK4_SSS, + INST_PADD1, + INST_PADD1_SSS, + INST_PADD1_UUS, + INST_PADD1_UUU, + INST_PADD2, + INST_PADD2_SSS, + INST_PADD2_UUS, + INST_PADD2_UUU, + INST_PADD4, + INST_PAVG1, + INST_PAVG1_RAZ, + INST_PAVG2, + INST_PAVG2_RAZ, + INST_PAVGSUB1, + INST_PAVGSUB2, + INST_PCMP1, + INST_PCMP2, + INST_PCMP4, + INST_PMAX1_U, + INST_PMAX2, + INST_PMIN1_U, + INST_PMIN2, + INST_PMPY2_R, + INST_PMPY2_L, + INST_PMPYSHR2, + INST_PMPYSHR2_U, + INST_POPCNT, + INST_PROBE_R, + INST_PROBE_W, + INST_PROBE_R_FAULT, + INST_PROBE_W_FAULT, + INST_PROBE_RW_FAULT, + INST_PSAD1, + INST_PSHL2, + INST_PSHL4, + INST_PSHLADD2, + INST_PSHR2, + INST_PSHR2_U, + INST_PSHR4, + INST_PSHR4_U, + INST_PSHRADD2, + INST_PSUB1, + INST_PSUB1_SSS, + INST_PSUB1_UUS, + INST_PSUB1_UUU, + INST_PSUB2, + INST_PSUB2_SSS, + INST_PSUB2_UUS, + INST_PSUB2_UUU, + INST_PSUB4, + INST_PTC_E, + INST_PTC_G, + INST_PTC_GA, + INST_PTC_L, + INST_PTR_D, + INST_PTR_I, + INST_RFI, + INST_RSM, + INST_RUM, + INST_SETF_S, + INST_SETF_D, + INST_SETF_EXP, + INST_SETF_SIG, + INST_SHL, + INST_SHLADD, + INST_SHLADDP4, + INST_SHR, + INST_SHR_U, + INST_SHRP, + INST_SRLZ_I, + INST_SRLZ_D, + INST_SSM, + INST_ST_FIRST, // start of continuous group of store instructions + INST_ST = INST_ST_FIRST, + INST_ST16, + INST_ST8_SPILL, + INST_STF, + INST_STF8, + INST_STF_SPILL, + INST_ST_LAST = INST_STF_SPILL, // end of continuous group of store instructions + INST_SUB, + INST_SUM, + INST_SXT, + INST_SYNC_I, + INST_TAK, + INST_TBIT, + INST_THASH, + INST_TNAT, + INST_TPA, + INST_TTAG, + INST_UNPACK1_H, + INST_UNPACK2_H, + INST_UNPACK4_H, + INST_UNPACK1_L, + INST_UNPACK2_L, + INST_UNPACK4_L, + INST_XCHG, + INST_XMA_L, + INST_XMA_LU, + INST_XMA_H, + INST_XMA_HU, + INST_XMPY_L, + INST_XMPY_LU, + INST_XMPY_H, + INST_XMPY_HU, + INST_XOR, + INST_ZXT, + INST_LAST = INST_ZXT, + // following are pseudo-op + INST_SWITCH, // switch, ignored + INST_BREAKPOINT, + INST_USE, + INST_DEF, + INST_BRL13, + INST_BR13 +}; + +enum Completer { + CMPLT_INVALID = -1, + CMPLT_FIRST = 0, // MUST BE 0 + //---------------------------- + // Branch_Types (br) + CMPLT_BTYPE_COND = CMPLT_FIRST, // br, brl + CMPLT_BTYPE_IA, + CMPLT_BTYPE_WEXIT, + CMPLT_BTYPE_WTOP, + CMPLT_BTYPE_RET, + CMPLT_BTYPE_CLOOP, + CMPLT_BTYPE_CEXIT, + CMPLT_BTYPE_CTOP, + CMPLT_BTYPE_CALL, // br, brl + //---------------------------- + // Branch_Whether_Hint, NOT for all branch instructions! + CMPLT_WH_IGNORE, // Ignore all hints. + CMPLT_WH_SPTK, // Presaged branch should be predicted Static Taken + CMPLT_WH_SPNT, + CMPLT_WH_LOOP, // Presaged branch will be br.cloop, br.ctop, or br.wtop + CMPLT_WH_EXIT, // Presaged branch will be br.cexit or br.wexit + CMPLT_WH_DPTK, // Presaged branch should be predicted Dynamically + CMPLT_WH_DPNT, + //---------------------------- + // Branch_Sequential_Prefetch_Hint (br, brl) + CMPLT_PH_FEW, + CMPLT_PH_MANY, + //---------------------------- + // Branch_Cache_Deallocation_Hint (br, brl) + CMPLT_DH_NOT_CLR, + CMPLT_DH_CLR, + //---------------------------- + // Branch_Predict_Importance_Hint (brp) + CMPLT_IH_NOT_IMP, + CMPLT_IH_IMP, + //---------------------------- + // Speculation_Check_ALAT_Clear_Completer (chk.s, chk.a) + CMPLT_CHK_A_CLR, // Invalidate matching ALAT entry + CMPLT_CHK_A_NC, // Dont invalidate + //---------------------------- + // Comparison_Types ( both int and float! ) + CMPLT_CMP_CTYPE_NONE, + CMPLT_CMP_CTYPE_NORMAL = CMPLT_CMP_CTYPE_NONE, + CMPLT_CMP_CTYPE_UNC, + CMPLT_CMP_CTYPE_OR, + CMPLT_CMP_CTYPE_AND, + CMPLT_CMP_CTYPE_OR_ANDCM, + //---------------------------- + // Comparison_Relations + CMPLT_CMP_CREL_EQ, + CMPLT_CMP_CREL_NE, + CMPLT_CMP_CREL_LT, + CMPLT_CMP_CREL_LE, + CMPLT_CMP_CREL_GT, + CMPLT_CMP_CREL_GE, + CMPLT_CMP_CREL_LTU, // unsigned + CMPLT_CMP_CREL_LEU, // unsigned + CMPLT_CMP_CREL_GTU, // unsigned + CMPLT_CMP_CREL_GEU, // unsigned + // Floating_Point_Comparison_Relations + CMPLT_FCMP_FREL_UNORD, // unordered f2 ? f3 + CMPLT_FCMP_FREL_NLT, // not less than !(f2 < f3) + CMPLT_FCMP_FREL_NLE, // not less than or equal !(f2 <= f3) + CMPLT_FCMP_FREL_NGT, // not greater than !(f2 > f3) + CMPLT_FCMP_FREL_NGE, // not greater than or equal !(f2 >= f3) + CMPLT_FCMP_FREL_ORD, // ordered !(f2 ? f3) + //---------------------------- + // Semaphore_Types + CMPLT_SEM_ACQ, // Acquire The memory read/write is made + // visible prior to all subsequent data + // memory accesses. + CMPLT_SEM_REL, // Release The memory read/write is made + // visible after all previous data memory + // accesses. + //---------------------------- + // Floating_Point_pc_Mnemonic_Values + CMPLT_PC_SINGLE, + CMPLT_PC_DOUBLE, + CMPLT_PC_DYNAMIC, + //---------------------------- + // Floating_Point_sf_Mnemonic_Values + CMPLT_SF0, + CMPLT_SF1, + CMPLT_SF2, + CMPLT_SF3, + //---------------------------- + // Floating_Point_Class_Relations + CMPLT_FCREL_M, // FR f2 agrees with the pattern specified + // by fclass9 (is a member) + CMPLT_FCREL_NM, // FR f2 does not agree with the pattern + // specified by fclass9 (is not a member) + //---------------------------- + // Floating_Point_Classes + CMPLT_FCLASS_NAT, // NaTVal + CMPLT_FCLASS_QNAN, // Quiet NaN + CMPLT_FCLASS_SNAN, // Signaling NaN + CMPLT_FCLASS_POS, // Positive + CMPLT_FCLASS_NEG, // Negative + CMPLT_FCLASS_ZERO, // Zero + CMPLT_FCLASS_UNORM, // Unnormalized + CMPLT_FCLASS_NORM, // Normalized + CMPLT_FCLASS_INF, // Infinity + //---------------------------- + // fsz completer for ldf instruction + CMPLT_FSZ_S, + CMPLT_FSZ_D, + CMPLT_FSZ_E, + //---------------------------- + // sz completer for ld, st, cmpxchg, ... + CMPLT_SZ_1, + CMPLT_SZ_2, + CMPLT_SZ_4, + CMPLT_SZ_8, + //---------------------------- + // Load_Types + CMPLT_LDTYPE_NORMAL, // Normal load + CMPLT_LDTYPE_S, // Speculative load + CMPLT_LDTYPE_A, // Advanced load + CMPLT_LDTYPE_SA, // Speculative Advanced load + CMPLT_LDTYPE_C_NC, // Check load - no clear + CMPLT_LDTYPE_C_CLR, // Check load - clear + CMPLT_LDTYPE_C_CLR_ACQ, // Ordered check load clear + CMPLT_LDTYPE_ACQ, // Ordered load + CMPLT_LDTYPE_BIAS, // Biased load + //---------------------------- + // Line_Prefetch_Hints + // Some of Line_Prefetch_Hints are valid for lfetch, store, etc. + CMPLT_HINT_NONE, // Temporal locality, level 1 + CMPLT_HINT_NT1, // No temporal locality, level 1 + CMPLT_HINT_NT2, // No temporal locality, level 2 + CMPLT_HINT_NTA, // No temporal locality, all levels + //---------------------------- + // Saturation + CMPLT_SAT_NONE, // modulo_form + CMPLT_SAT_SSS, + CMPLT_SAT_USS, + CMPLT_SAT_UUS, + CMPLT_SAT_UUU, + //---------------------------- + // Store_Types + CMPLT_ST_TYPE_NORMAL, + CMPLT_ST_TYPE_REL, + //---------------------------- + CMPLT_FP_S, // single_form, M18/M19 + CMPLT_FP_D, // double_form, M18/M19 + CMPLT_FP_EXP, // exponent_form, M18/M19 + CMPLT_FP_SIG, // significand_form, M18/M19 + //---------------------------- + CMPLT_IREG_FIRST, + CMPLT_IREG_CPUID = CMPLT_IREG_FIRST, // Processor Identification Register + CMPLT_IREG_DBR, // Data Breakpoint Register + CMPLT_IREG_IBR, // Instruction Breakpoint Register + CMPLT_IREG_PKR, // Protection Key Register + CMPLT_IREG_PMC, // Performance Monitor Configuration Register + CMPLT_IREG_PMD, // Performance Monitor Data Register + CMPLT_IREG_RR, // Region Register + CMPLT_IREG_LAST = CMPLT_IREG_RR, + //================================================== + CMPLT_LAST = CMPLT_FP_SIG, + //---------------------------- + // xsz completer for sxt/zxt instructions + CMPLT_XSZ_1 = CMPLT_SZ_1, + CMPLT_XSZ_2 = CMPLT_SZ_2, + CMPLT_XSZ_4 = CMPLT_SZ_4, + //---------------------------- + // Floating_Point_Comparison_Types + CMPLT_FCMP_FCTYPE_NORMAL = CMPLT_CMP_CTYPE_NORMAL, + CMPLT_FCMP_FCTYPE_NONE = CMPLT_FCMP_FCTYPE_NORMAL, + CMPLT_FCMP_FCTYPE_UNC = CMPLT_CMP_CTYPE_UNC, + // Floating_Point_Comparison_Relations + CMPLT_FCMP_FREL_EQ = CMPLT_CMP_CREL_EQ, // equal f2 == f3 + CMPLT_FCMP_FREL_NEQ = CMPLT_CMP_CREL_NE, // not equal !(f2 == f3) + CMPLT_FCMP_FREL_LT = CMPLT_CMP_CREL_LT, // less than f2 < f3 + CMPLT_FCMP_FREL_LE = CMPLT_CMP_CREL_LE, // less than or equal f2 <= f3 + CMPLT_FCMP_FREL_GT = CMPLT_CMP_CREL_GT, // greater than f2 > f3 + CMPLT_FCMP_FREL_GE = CMPLT_CMP_CREL_GE // greater than or equal f2 >= f3 +}; + +// ========================================================================================// +// Instruction Description +// ========================================================================================// + +struct InstDescription { + char * mnemonic; + InstCode inst; + uint16 numDst; + uint16 numOpnd; + int instType; +}; + +//============================================================================// +// Compliter Description +//============================================================================// + +struct CmpltDescription { + char *mnemonic; + Completer cmplt; +}; + + +//============================================================================// +#define INST_BREAKPOINT_IMM_VALUE ((uint64)0x4cafe) +#define CAFE ((uint64)0x4cafe) + +//============================================================================// +// Encoder +//============================================================================// + +// forward declaration of Inst class, declared in some other file +//class Inst; +//class Opnd; +//class Cfg; +//typedef vector<Opnd*> OpndVector; +//typedef vector<Inst*> InstVector; +//typedef vector<Completer> CompVector; +typedef vector<Completer> CompVector; + +class Encoder { + public: + static bool patchCallAddr(BinaryRewritingInterface &binaryRewritingInterface + , char * callAddr, char * methodAddr); + static void readBundle(uint64 *code, uint64 * tmplt, uint64 * slots); + + static char * getMnemonic(InstCode opcode) { return instDesc[opcode].mnemonic; }; + static uint16 getNumDst(InstCode opcode) { return instDesc[opcode].numDst; }; + static uint16 getNumOpnd(InstCode opcode) { return instDesc[opcode].numOpnd; }; + static int getInstType(InstCode opcode) { return instDesc[opcode].instType; }; + static int getInstType(Inst *inst); + static char * getMnemonic(Completer cmplt) { return cmpltDesc[cmplt].mnemonic; }; + + static bool isBranchInst(Inst *); + static bool isBranchCallInst(Inst *); + static bool isIgnoreInst(Inst *); + static bool isPseudoInst(Inst *); + static Inst * resolvePseudo(Cfg &, Inst *); + + static uint64 getNopBits(InstructionType, unsigned, uint64); + static uint64 getHintBits(InstructionType, unsigned, uint64); + static uint64 getBreakBits(InstructionType, unsigned, uint64); + + static uint64 getInstBits(InstructionType, Inst *); + static uint64 getInstBitsBranch(InstructionType, Inst *, int); + static uint64 * getInstBitsExtended(Inst *, uint64 *, void *); + + static uint64 ldfx(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp); + static uint64 fcmp(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp); + static uint64 cmp_cmp4(InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp); + static uint64 mov(InstructionType unit, InstCode icode, Inst * inst, CompVector & cmpls, OpndVector & opnds, uint64 qp); + + //----------------------------------------------------------------------------// + static uint64 A1(uint64 x4, uint64 ct2d, int64 r3, int64 r2, int64 r1, uint64 qp) { + return ((uint64)8 << 37) | ((x4 & 0xF) << 29) | (ct2d << 27) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 A2(uint64 x4, int64 count2, int64 r3, int64 r2, int64 r1, uint64 qp) { + // count2 = ct2d + 1 + return ((uint64)8 << 37) | ((x4 & 0xF) << 29) | (((count2-1) & 0x3) << 27) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 A3(uint64 x4, uint64 x2b, int64 r3, int64 imm8, int64 r1, uint64 qp) { + return ((uint64)8 << 37) | (x4 << 29) | (x2b << 27) + | (r3 << 20) | ( imm8<0 ? (uint64)1<<36 : 0 ) | ((0x7F & imm8) << 13) + | (r1 << 6) | qp; + } + + static uint64 A4(uint64 x2a, int64 r3, int64 imm14, int64 r1, uint64 qp) { + // imm14 = sign_ext(s << 13 | imm6d << 7 | imm7b, 14) + return ((uint64)8 << 37) | (x2a << 34) + | (r3 << 20) | (r1 << 6) | qp + | (imm14<0 ? (uint64)1<<36 : 0) + | ((imm14 & 0x1F80) << 20) | ((imm14 & 0x7F) << 13); + } + + static uint64 A5(int64 r3, int64 imm22, int64 r1, uint64 qp) { + // imm22 = sign_ext(s << 21 | imm5c << 16 | imm9d << 7 | imm7b, 22) + return ((uint64)9 << 37) + | ((r3 & 0x3) << 20) | (r1 << 6) | qp + | (imm22<0 ? (uint64)1<<36 : 0) + | ((imm22 & 0xFF80) << 20) | ((imm22 & 0x1F0000) << 6) | ((imm22 & 0x7F) << 13); + } + + static uint64 A6(uint64 opcode, uint64 x2, uint64 ta, uint64 c, int64 p1, int64 p2, int64 r2, int64 r3, uint64 qp) { + return (opcode << 37) | (x2 << 34) + | (ta << 33) | (p2 << 27) | (r3 << 20) + | (r2 << 13) | (c << 12) | (p1 << 6) | qp; + } + + static uint64 A7(uint64 opcode, uint64 x2, uint64 ta, uint64 c, int64 p1, int64 p2, int64 r3, uint64 qp) { + return (opcode << 37) | ((uint64)1 << 36) | (x2 << 34) + | (ta << 33) | (p2 << 27) | (r3 << 20) + | (c << 12) | (p1 << 6) | qp; + } + + + static uint64 A8(uint64 opcode, uint64 x2, uint64 ta, uint64 c, int64 p1, int64 p2, int64 imm8, int64 r3, uint64 qp) { + return (opcode << 37) | (x2 << 34) | (ta << 33) | (c << 12) + | (p1 << 6) | (p2 << 27) | (r3 << 20) + | (imm8<0 ? (uint64)1<<36 : 0) | ((imm8 & 0x7F) << 13) | qp; + } + + static uint64 A9(uint64 za, uint64 zb, uint64 x4, uint64 x2b, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)0x8 << 37) | (za << 36) | ((uint64)0x1 << 34) + | (zb << 33) | (x4 << 29) | (x2b << 27) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 A10(uint64 x4, uint64 ct2d, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)0x8 << 37) | ((uint64)0x1 << 34) + | ((uint64)0x1 << 33) | (x4 << 29) | (ct2d << 27) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I1(uint64 ct2d, uint64 x2b, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + // count2 = (ct2d == 0) ? 0 : (ct2d == 1) ? 7 : (ct2d == 2) ? 15 : 16 + return ((uint64)7 << 37) | ((uint64)1 << 33) | ((0x3 & ct2d) << 30) + | ((0x3 & x2b) << 28) | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I2(uint64 za, uint64 zb, uint64 x2c, uint64 x2b, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)2 << 34) | ((0x1 & za) << 36) + | ((0x1 & zb) << 33) | ((0x3 & x2c) << 30) | ((0x3 & x2b) << 28) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I3(uint64 mbt4c, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)3 << 34) | ((uint64)2 << 28) + | ((uint64)2 << 30) + | ((0xf & mbt4c) << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I4(uint64 mht8c, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)3 << 34) | ((uint64)2 << 28) + | ((uint64)2 << 30) | ((uint64)1 << 33) + | ((0xFF & mht8c) << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I5(uint64 za, uint64 zb, uint64 x2b, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) + | ((0x1 & za) << 36) | ((0x1 & zb) << 33) | ((0x3 & x2b) << 28) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I6(uint64 za, uint64 zb, uint64 x2b, uint64 r3, uint64 count5b, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)1 << 34) + | ((0x1 & za) << 36) | ((0x1 & zb) << 33) | ((0x3 & x2b) << 28) + | (r3 << 20) | ((0x1F & count5b) << 14) | (r1 << 6) | qp; + } + + static uint64 I7(uint64 za, uint64 zb, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)1 << 30) + | ((0x1 & za) << 36) | ((0x1 & zb) << 33) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I8(uint64 za, uint64 zb, uint64 count5c, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)3 << 34) | ((uint64)1 << 28) | ((uint64)1 << 30) + | ((0x1 & za) << 36) | ((0x1 & zb) << 33) + | (count5c << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I9(uint64 r3, uint64 r1, uint64 qp) { + return ((uint64)7 << 37) | ((uint64)1 << 33) | ((uint64)1 << 34) + | ((uint64)1 << 28) | ((uint64)2 << 30) + | (r3 << 20) | (r1 << 6) | qp; + } + + static uint64 I10(uint64 count6d, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)5 << 37) | ((uint64)3 << 34) + | (count6d << 27) | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I11(uint64 len6d, uint64 r3, uint64 pos6b, uint64 y, uint64 r1, uint64 qp) { + return ((uint64)5 << 37) | ((uint64)1 << 34) + | (len6d << 27) | (r3 << 20) | (pos6b << 14) | (y << 13) | (r1 << 6) | qp; + } + + static uint64 I12(uint64 len6d, uint64 cpos6c, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)5 << 37) | ((uint64)1 << 34) | ((uint64)1 << 33) + | ((0x3F & len6d) << 27) | ((0x3F & cpos6c) << 20) + | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I13(uint64 len6d, uint64 cpos6c, int64 imm8, uint64 r1, uint64 qp) { + return ((uint64)5 << 37) | ((uint64)1 << 34) | ((uint64)1 << 33) | ((uint64)1 << 26) + | ((uint64)(imm8<0?1:0) << 36) | ((0x7F & imm8) << 13) + | (len6d << 27) | (cpos6c << 20) | (r1 << 6) | qp; + } + + static uint64 I14(int64 imm1, uint64 len6d, uint64 r3, uint64 cpos6b, uint64 r1, uint64 qp) { + return ((uint64)5 << 37) | ((uint64)3 << 34) | ((uint64)1 << 33) + | ((0x1 & imm1) << 36) | (len6d << 27) | (r3 << 20) | (cpos6b << 14) | (r1 << 6) | qp; + } + + static uint64 I15(uint64 cpos6d, uint64 len4d, uint64 r3, uint64 r2, uint64 r1, uint64 qp) { + return ((uint64)4 << 37) + | (cpos6d << 36) | (len4d << 27) | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 I20(int64 imm21, uint64 r2, uint64 qp) { + return ((uint64)(imm21<0?1:0) << 36) | ((uint64)1 << 33) + | ((0xFFF80 & imm21) << 20) | (r2 << 13) | ((0x7F & imm21) << 6) | qp; + } + + static uint64 I21(uint64 timm9c, uint64 ih, uint64 x, uint64 wh, uint64 r2, uint64 b1, uint64 qp) { + return ((uint64)0x7 << 33) | (timm9c << 24) + | (ih << 23) | (x << 22) | (wh << 20) | (r2 << 13) | (b1 << 6) | qp; + } + + static uint64 I22(uint64 b2, uint64 r1, uint64 qp) { + return ((uint64)0x31 << 27) + | (b2 << 13) | (r1 << 6) | qp; + } + + static uint64 I23(uint64 mask16, uint64 r2, uint64 qp) { + return ((uint64)0x3 << 33) + | ((uint64)(mask16&0x8000 ? 1 : 0) << 36) | (((mask16 >> 7) & 0xFF) << 24) + | ((mask16 & 0x7F) << 6) | (r2 << 13) | qp; + } + + static uint64 I24(int64 imm28, uint64 qp) { + return ((uint64)0x2 << 33) + | ((uint64)(imm28<0 ? 1 : 0) << 36) | ((imm28 & 0x7FFFFFF) << 6) | qp; + } + + static uint64 I25(uint64 x6, uint64 r1, uint64 qp) { + return (x6 << 27) | (r1 << 6) | qp; + } + + static uint64 I26(uint64 ar3, uint64 r2, uint64 qp) { + return ((uint64)0x2A << 27) | (ar3 << 20) | (r2 << 13) | qp; + } + + static uint64 I27(uint64 ar3, int64 imm8, uint64 qp) { + return ((uint64)0x0A << 27) | (ar3 << 20) + | ((uint64)(imm8 < 0?1:0) << 36) | ((0x7F & imm8) << 13) | qp; + } + + static uint64 I28(uint64 ar3, uint64 r1, uint64 qp) { + return ((uint64)0x32 << 27) | (ar3 << 20) | (r1 << 6) | qp; + } + + static uint64 I29(uint64 x6, uint64 r3, uint64 r1, uint64 qp) { + return ((x6 & 0x3f) << 27) | ((r3 & 0x7f) << 20) | ((r1 & 0x7f) << 6) | qp; + } + + static uint64 M1(uint64 x6, uint64 hint, uint64 x, int64 r3, int64 r1, uint64 qp) { + return ((uint64)4 << 37) | (x6 << 30) | (hint << 28) | (x << 27) + | (r3 << 20) | (r1 << 6) | qp; + } + + static uint64 M2(uint64 x6, uint64 hint, int64 r3, int64 r2, int64 r1, uint64 qp) { + return ((uint64)4 << 37) | ((uint64)1 << 36) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (r2 << 13) | (r1 << 6) | qp; + } + + static uint64 M3(uint64 x6, uint64 hint, int64 r3, int64 imm9, int64 r1, uint64 qp) { + return ((uint64)5 << 37) | (x6 << 30) | (hint << 28) + | (r3 << 20) | ((uint64)(imm9<0?1:0) << 36) + | (((imm9 >> 7) & 0x1) << 27) | ((imm9 & 0x7F) <<13) + | (r1 << 6) | qp; + } + + static uint64 M4(uint64 x6, uint64 hint, uint64 x, int64 r3, int64 r2, uint64 qp) { + return ((uint64)4 << 37) | (x6 << 30) | (hint << 28) |(x << 27) + | (r3 << 20) | (r2 << 13) | qp; + } + + static uint64 M5(uint64 x6, uint64 hint, int64 r3, int64 r2, int64 imm9, uint64 qp) { + // imm9 = sign_ext(s << 8 | i << 7 | imm7a, 9) + return ((uint64)5 << 37) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (r2 << 13) + | (imm9<0 ? (uint64)1<<36 : 0) + | ((imm9 & 0x80) << 20) | ((imm9 & 0x7F) << 6) | qp; + } + + static uint64 M6(uint64 x6, uint64 hint, int64 r3, int64 f1, uint64 qp) { + return ((uint64)6 << 37) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (f1 << 6) | qp; + } + + static uint64 M7(uint64 x6, uint64 hint, int64 r3, int64 r2, int64 f1, uint64 qp) { + return ((uint64)6 << 37) | ((uint64)1 << 36) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (r2 << 13) | (f1 << 6) | qp; + } + + static uint64 M8(uint64 x6, uint64 hint, int64 r3, int64 imm9, int64 f1, uint64 qp) { + return ((uint64)7 << 37) | (x6 << 30) | (hint << 28) + | ((uint64)(imm9<0?1:0) << 36) | (((imm9 >> 7) & 0x1) << 27) + | ((imm9 & 0x7F) << 13) | (r3 << 20) | (f1 << 6) | qp; + } + + static uint64 M9(uint64 x6, uint64 hint, int64 r3, int64 f2, uint64 qp) { + // 6 m x6 hint x r3 f2 qp + return ((uint64)6 << 37) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (f2 << 13) | qp; + } + + static uint64 M10(uint64 x6, uint64 hint, int64 r3, int64 f2, int64 imm9, uint64 qp) { + // imm9 = sign_ext(s << 8 | i << 7 | imm7a, 9) + return ((uint64)7 << 37) | (x6 << 30) | (hint << 28) + | (r3 << 20) | (f2 << 13) | ((uint64)(imm9<0?1:0) << 36) + | ((uint64)(imm9 & 0x80) << 20) | ((uint64)(imm9 & 0x7F) << 6) | qp; + } + + static uint64 M18(uint64 x6, int64 r2, int64 f1, int64 qp) { + return ((uint64)6 << 37) | (x6 << 30) | ((uint64)1 << 27) + | (r2 << 13) | (f1 << 6) | qp; + } + + static uint64 M19(uint64 x6, int64 f2, int64 r1, int64 qp) { + return ((uint64)4 << 37) | (x6 << 30) | ((uint64)1 << 27) + | (f2 << 13) | (r1 << 6) | qp; + } + + static uint64 M28(uint64 x, int64 r3, int64 qp) { + return ((uint64)1 << 37) | ((uint64)0x30 << 27) + | (x << 36) | (r3 << 20) | qp; + } + + static uint64 M29(uint64 ar3, int64 r2, int64 qp) { + return ((uint64)1 << 37) | ((uint64)0x2A << 27) + | (ar3 << 20) | (r2 << 13) | qp; + } + + static uint64 M30(uint64 ar3, int64 imm8, int64 qp) { + return ((uint64)0 << 37) | ((uint64)0x2 << 31) | ((uint64)0x8 << 27) + | (ar3 << 20) | ((uint64)(imm8<0?1:0) << 36) | ((0x7F & imm8) << 13) + | qp; + } + + static uint64 M31(uint64 ar3, int64 r1, int64 qp) { + return ((uint64)1 << 37) | ((uint64)0x22 << 27) + | (ar3 << 20) | (r1 << 6) | qp; + } + + static uint64 M34(uint64 sor, uint64 sol, uint64 sof, int64 r1, int64 qp) { + return ((uint64)1 << 37) | ((uint64)0x6 << 33) + | (sor << 27) | (sol << 20) | (sof << 13) | (r1 << 6) | qp; + } + + + static uint64 B1_B2(uint64 dh, uint64 bwh, uint64 ph, uint64 btype, int64 imm21, uint64 qp) { + return ((uint64)4 << 37) + | (dh << 35) | (bwh << 33) | (ph << 12) | (btype << 6) | qp + | (imm21<0 ? (uint64)1<<36 : 0) + | ((imm21 & 0xFFFFF) << 13); + } + + static uint64 B3(uint64 p, uint64 wh, uint64 d, int64 imm21, uint64 b1, uint64 qp) { + // target25 = IP + (sign_ext(s << 20 | imm20b, 21) << 4) + return ((uint64)5 << 37) + | (d << 35) | (wh << 32) | (p << 12) + | ((uint64)(imm21<0?1:0) << 36) | ((imm21 & 0xFFFFF) << 13) | (b1 << 6) | qp; + } + + static uint64 B4(uint64 dh, uint64 bwh, uint64 x6, uint64 b2, uint64 ph, uint64 btype, uint64 qp) { + return ((uint64)0 << 37) + | (dh << 35) | (bwh << 33) | (x6 << 27) | (ph << 12) | (btype << 6) | qp + | (b2 << 13); + } + + static uint64 B5(uint64 p, uint64 wh, uint64 d, uint64 b2, uint64 b1, uint64 qp) { + return ((uint64)1 << 37) + | (d << 35) | (wh << 32) | (p << 12) | (b2 << 13) | (b1 << 6) | qp; + } + + static uint64 F1(uint64 opcode, uint64 x, uint64 sf, int64 f4, int64 f3, int64 f2, int64 f1, uint64 qp) { + return (opcode << 37) | (x << 36) | (sf << 34) + | (f4 << 27) | (f3 << 20) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F2(uint64 x2, int64 f4, int64 f3, int64 f2, int64 f1, uint64 qp) { + return ((uint64)0xE << 37) | ((uint64)1 << 36) | ((x2 & 0x3)<< 34) + | (f4 << 27) | (f3 << 20) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F4(uint64 rb, uint64 sf, uint64 ra, int64 p2, int64 f3, int64 f2, uint64 ta, int64 p1, uint64 qp) { + return ((uint64)0x4 << 37) | (rb << 36) | (sf << 34) | (ra << 33) + | (p2 << 27) | (f3 << 20) | (f2 << 13) | (ta << 12) | ( p1 << 6) | qp; + } + + static uint64 F5(uint64 fclass9, uint64 p2, uint64 f2, int64 ta, uint64 p1, uint64 qp) { + return ((uint64)0x5 << 37) | ((fclass9 >> 7) << 33) | ((fclass9 & 0x7F) << 20) + | (p2 << 27) | (f2 << 13) | (ta << 12) | ( p1 << 6) | qp; + } + + static uint64 F6(uint64 opcode, uint64 sf, int64 p2, int64 f3, int64 f2, uint64 f1, uint64 qp) { + return (opcode << 37) | (sf << 34) | ((uint64)1 << 33) + | (p2 << 27) | (f3 << 20) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F8(uint64 opcode, uint64 sf, uint64 x6, int64 f3, int64 f2, uint64 f1, uint64 qp) { + return (opcode << 37) | (sf <<34) | (x6 << 27) | (f3 << 20) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F9(uint64 opcode, uint64 x6, int64 f3, int64 f2, uint64 f1, uint64 qp) { + return (opcode << 37) | (x6 << 27) | (f3 << 20) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F10(uint64 opcode, uint64 sf, uint64 x6, int64 f2, uint64 f1, uint64 qp) { + return (opcode << 37) | (sf << 34) | (x6 << 27) | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 F11(int64 f2, int64 f1, int64 qp) { + return ((uint64)0x1C << 27) + | (f2 << 13) | (f1 << 6) | qp; + } + + static uint64 * X2(int vc, uint64 r1, int64 imm64, uint64 qp, uint64 * slots12) { + // imm64 = i << 63 | imm41 << 22 | ic << 21 | imm5c << 16 | imm9d << 7 | imm7b + // slot1: 6 i imm9d imm5c ic vc imm7b r1 qp; slot2: imm41 + slots12[1] = ((uint64)6 << 37); + slots12[1] |= r1 << 6 + | qp | ((vc & 0x01) << 20) + | ((int64)imm64<0 ? (uint64)1<<36 : 0) + | ((imm64 & 0x7F) << 13) + | ((imm64 & (0x1FF<<7)) << 20) + | ((imm64 & (0x1F<<16)) << 6) + | (imm64 & (0x01<<21)) ; + slots12[0] = (imm64 & (0x1FFFFFFFFFF<<22)) >> 22; + return slots12; + } + + static uint64 * X3(uint64 imm60, uint64 d, uint64 wh, uint64 p, uint64 qp, uint64 * slots12) { + // (qp) brl.btype.bwh.ph.dh b1 = target64 + // target64 = IP + ((i << 59 | imm39 << 20 | imm20b) << 4) + slots12[1] = ((uint64)0xC << 37) | ((imm60 >> 59) << 36) | (d << 35) + | (wh << 33) | (p << 12) | qp + | ((imm60 & 0xFFFFF) << 13); + slots12[0] = (imm60 & (0x7FFFFFFFFF<<20)) >> 18; + return slots12; + } + + static uint64 * X4(uint64 imm60, uint64 d, uint64 wh, uint64 p, uint64 b1, uint64 qp, uint64 * slots12) { + // (qp) brl.btype.bwh.ph.dh b1 = target64 + // target64 = IP + ((i << 59 | imm39 << 20 | imm20b) << 4) + slots12[1] = ((uint64)0xD << 37) | ((imm60 >> 59) << 36) | (d << 35) + | (wh << 33) | (p << 12) | (b1 << 6) | qp + | ((imm60 & 0xFFFFF) << 13); + slots12[0] = (imm60 & (0x7FFFFFFFFF<<20)) >> 18; + return slots12; + } + + static uint64 * X5(uint64 y, int64 imm62, uint64 qp, uint64 * slots12) { + // imm62 = imm41 << 21 | i << 20 | imm20a + slots12[1] = ((y & 0x01) << 26) | qp + | ((imm62 & 0xFFFFF) << 6) + | ((imm62 & 0x100000) << 16); + slots12[0] = (imm62 & (0x1FFFFFFFFFF<<21)) >> 21; + return slots12; + } + + protected: + static const InstDescription instDesc[]; + static const CmpltDescription cmpltDesc[]; +}; + +} // IPF +} // Jitrino + +#endif /*IPFENCODER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfIrPrinter.h vm/jitrino/src/codegenerator/ipf/include/IpfIrPrinter.h new file mode 100644 index 0000000..93e6c7e --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfIrPrinter.h @@ -0,0 +1,75 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IRPRINTER_H_ +#define IRPRINTER_H_ + +#include <string> +#include <iostream> +#include <fstream> +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//=======================================================================================// +// IrPrinter +//========================================================================================// + +class IrPrinter { +public: + IrPrinter(Cfg&, char*); + void printCfgDot(char*); + void printLayoutDot(char*); + void printAsm(ostream&); + + static string toString(Inst*); + static string toString(Opnd*); + static string toString(OpndSet&); + static string toString(RegOpndSet&); + static string toString(OpndVector&); + static string toString(InstVector&); + static string toString(InstList&); + static string toString(NodeKind); + static string toString(EdgeKind); + static string toString(OpndKind); + static string toString(DataKind); + +protected: + void printEdgeDot(Edge*); + void printNodeDot(Node*); + void printNodeAsm(BbNode*); + + void printHead(); + void printTail(); + + MemoryManager &mm; + Cfg &cfg; + char *logDirName; // name of log dir + ostream *os; // output stream + ofstream *ofs; // file output stream +}; + +} // IPF +} // Jitrino + +#endif /*IRPRINTER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfLiveAnalyzer.h vm/jitrino/src/codegenerator/ipf/include/IpfLiveAnalyzer.h new file mode 100644 index 0000000..271fdc5 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfLiveAnalyzer.h @@ -0,0 +1,56 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFLIVEANALYZER_H_ +#define IPFLIVEANALYZER_H_ + +#include "IpfCfg.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// LiveAnalyzer +//========================================================================================// + +class LiveAnalyzer { +public: + LiveAnalyzer(Cfg&); + void makeLiveSets(bool); + + static void updateLiveSet(RegOpndSet&, Inst*); + static void defOpnds(RegOpndSet&, Inst*); + static void useOpnds(RegOpndSet&, Inst*); + +protected: + bool analyzeNode(Node*); + + Cfg &cfg; + bool verify; +}; + +} // IPF +} // Jitrino + +#endif /*IPFLIVEANALYZER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfOpndManager.h vm/jitrino/src/codegenerator/ipf/include/IpfOpndManager.h new file mode 100644 index 0000000..bcbe6ee --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfOpndManager.h @@ -0,0 +1,246 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFOPNDMANAGER_H_ +#define IPFOPNDMANAGER_H_ + +#include "IpfType.h" +#include "MemoryManager.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Forward declaration +//========================================================================================// + +class Opnd; +class RegOpnd; + +//========================================================================================// +// RegStack +//========================================================================================// + +class RegStack { +public: + RegStack(); + + int32 newInReg(int32); + int32 newOutReg(int32); + void setLocRegSize(int32 locRegSize_) { locRegSize = locRegSize_; } + int32 getInRegSize() { return inRegSize; } + int32 getLocRegSize() { return locRegSize; } + int32 getOutRegSize() { return outRegSize; } + bool isOutReg(RegOpnd*); + + //----------------------------------------------------------------------------// + // Reg masks + //----------------------------------------------------------------------------// + + RegBitSet scratchGrMask; // grs that can be used as scratch registers + RegBitSet preservGrMask; // grs that can be used as preserv registers + RegBitSet spillGrMask; // grs that can be used for spilling/filling + + RegBitSet scratchFrMask; // frs that can be used as scratch registers + RegBitSet preservFrMask; // frs that can be used as preserv registers + RegBitSet spillFrMask; // frs that can be used for spilling/filling + + RegBitSet scratchPrMask; // prs that can be used as scratch registers + RegBitSet preservPrMask; // prs that can be used as preserv registers + RegBitSet spillPrMask; // prs that can be used for spilling/filling + + RegBitSet scratchBrMask; // brs that can be used as scratch registers + RegBitSet preservBrMask; // brs that can be used as preserv registers + RegBitSet spillBrMask; // brs that can be used for spilling/filling + +protected: + int32 inRegSize; // number of general registers used for in args passing + int32 locRegSize; // number of general registers actually used in local area (including in args) + int32 outRegSize; // number of general registers used for out args passing +}; + +//========================================================================================// +// MemStack +//========================================================================================// +// +// +--------------------------------+ +// | ... | +// | inarg 10 (8 bytes) | +// | inarg 9 (8 bytes) | +// +--------------------------------+ <--- inarg base +// | scratch area (16 bytes) | +// +================================+ <--- previous stack pointer +// | | +// | fp callee-saved registers | +// | | +// +--------------------------------+ <--- fp callee base +// | | +// | int callee-saved registers | +// | | +// +--------------------------------+ <--- int callee base +// | | +// | spill area | +// | | +// +--------------------------------+ <--- local base +// | ... | +// | outarg 10 (8 bytes) | +// | outarg 9 (8 bytes) | +// +--------------------------------+ <--- outarg base +// | scratch area (16 bytes) | (if there are calls) +// +================================+ <--- stack pointer + +class MemStack { +public: + MemStack(); + int32 newInSlot(int32); + int32 newLocSlot(DataKind); + int32 newOutSlot(int32); + + void calculateOffset(RegOpnd*); + int32 calculateOffset(int32); + int32 getMemStackSize(); + int32 getSavedBase(); + +protected: + int32 align(int32, int32); + + int32 locMemSize; // size of memory stack area used for opnd spilling (bytes) + int32 outMemSize; // size of memory stack area used for out args passing (bytes) + + int32 inBase; // first memory inArg offset + int32 locBase; // first local memory opnd offset + int32 outBase; // first memory outArg offset +}; + +//========================================================================================// +// StackInfo +//========================================================================================// + +class StackInfo { +public: + StackInfo(); + int32 rpBak; // num of gr or stack offset containing return pointer (e.g. r33) + int32 prBak; // num of gr or stack offset containing predicate registers (e.g. r34) + int32 pfsBak; // num of gr or stack offset containing AR.PFS (e.g. r35) + int32 unatBak; // num of gr or stack offset containing AR.UNAT (e.g. r36) + int32 savedBase; // mem stack offset of first saved gr (bytes) + uint32 savedGrMask; // mask of preserved grs saved on stack + uint32 savedFrMask; // mask of preserved frs saved on stack + uint32 savedBrMask; // mask of preserved brs saved on stack + uint32 memStackSize; // mem stack frame size (bytes) +}; + +//========================================================================================// +// OpndManager +//========================================================================================// + +class OpndManager : public RegStack, public MemStack, public StackInfo { +public: + OpndManager(MemoryManager&, CompilationInterface&); + + //----------------------------------------------------------------------------// + // Opnd constructors + //----------------------------------------------------------------------------// + + Opnd *newOpnd(OpndKind = OPND_INVALID); + RegOpnd *newRegOpnd(OpndKind, DataKind, int32 = LOCATION_INVALID); + Opnd *newImm(int64 = 0); + ConstantRef *newConstantRef(Constant*, DataKind = DATA_CONST_REF); + NodeRef *newNodeRef(BbNode* = NULL); + MethodRef *newMethodRef(MethodDesc* = NULL); + + //----------------------------------------------------------------------------// + // set / get methods + //----------------------------------------------------------------------------// + + RegOpnd *getR0(); + RegOpnd *getR0(RegOpnd*); + RegOpnd *getF0(); + RegOpnd *getF1(); + + RegOpnd *getP0(); + RegOpnd *getB0(); + RegOpnd *getR12(); + RegOpnd *getTau(); + + void setContainCall(bool containCall_) { containCall = containCall_; } + bool getContainCall() { return containCall; } + + uint getNumOpnds() { return maxOpndId; } + + //----------------------------------------------------------------------------// + // Reg allocation support + //----------------------------------------------------------------------------// + + void assignLocation(RegOpnd*); + int32 newLocation(OpndKind, DataKind, RegBitSet, bool); + int32 newScratchReg(OpndKind, RegBitSet&); + int32 newPreservReg(OpndKind, RegBitSet&); + + //----------------------------------------------------------------------------// + // Compressed references + //----------------------------------------------------------------------------// + + bool areRefsCompressed() { return refsCompressed; } + bool areVtablePtrsCompressed() { return vtablePtrsCompressed; } + RegOpnd *getHeapBase(); + RegOpnd *getVtableBase(); + Opnd *getVtableOffset(); + void initCompBases(BbNode*); + + //----------------------------------------------------------------------------// + // Misc + //----------------------------------------------------------------------------// + + int64 getElemBaseOffset(); + void printStackInfo(); + void saveThisArg(); + void initSavedBase(); + void initMemStackSize(); + +protected: + MemoryManager &mm; + CompilationInterface &compilationInterface; + + int32 maxOpndId; // used for creating new opnds + + RegOpnd *r0; // 0 (8 bytes unsigned) + RegOpnd *f0; // 0.0 + RegOpnd *f1; // 1.0 + RegOpnd *p0; // true + RegOpnd *b0; // return address + RegOpnd *r12; // stack pointer + RegOpnd *tau; // opnd ignored + + RegOpnd *heapBase; // opnd containing base for references decompression + RegOpnd *vtableBase; // opnd containing base for vtable pointers decompression + Opnd *vtableOffset; // opnd containing vtable offset inside class object + + bool containCall; // method contains call instruction + bool refsCompressed; // references are compressed + bool vtablePtrsCompressed; // vtable pointers are compressed +}; + +} // IPF +} // Jitrino + +#endif /*IPFOPNDMANAGER_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfPrologEpilogGenerator.h vm/jitrino/src/codegenerator/ipf/include/IpfPrologEpilogGenerator.h new file mode 100644 index 0000000..3c35509 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfPrologEpilogGenerator.h @@ -0,0 +1,110 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFPROLOGEPILOGGENERATOR_H_ +#define IPFPROLOGEPILOGGENERATOR_H_ + +#include "IpfCfg.h" +#include "IpfOpndManager.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Defines +//========================================================================================// + +#define SITE_REG 1 +#define SITE_STACK 2 + +//========================================================================================// +// PrologEpilogGenerator +//========================================================================================// + +class PrologEpilogGenerator { +public: + PrologEpilogGenerator(Cfg&); + void genPrologEpilog(); + +private: + void buildSets(); + void reassignOutRegArgs(); + void genCode(); + + void saveRestoreRp(); + void saveRestorePr(); + void genAlloc(); + Opnd* saveRestorePfs(); + void saveRestoreUnat(); + void saveRestorePreservedBr(); + void saveRestorePreservedGr(); + void saveRestorePreservedFr(); + void saveRestoreSp(); + + RegOpnd* newStorage(DataKind, uint16); + void setRegUsage(RegOpnd*, bool); + int32 calculateLocRegSize(); + void printRegMasks(); + + MemoryManager &mm; + Cfg &cfg; + OpndManager *opndManager; + + RegOpndVector outRegArgs; // list of out arg registers + bool containCall; // method contains call + Opnd *p0; // p0 (true predicate) + Opnd *sp; // gr12 (stack pointer) + Opnd *stackAddr; // scratch opnd to hold stack address during saving/restoring + + InstList prologInsts; // prolog instructions + InstList epilogInsts; // epilog instructions + + InstList allocInsts; // "alloc" instruction + InstList saveSpInsts; // instructions to save stack pointer + InstList savePfsInsts; // instructions to save AR.PFS + InstList saveUnatInsts; // instructions to save AR.UNAT + InstList saveGrsInsts; // instructions to save preserved general registers + InstList saveFrsInsts; // instructions to save preserved floating registers + InstList saveBrsInsts; // instructions to save preserved branch registers + InstList savePrsInsts; // instructions to save preserved predicate registers + InstList saveRpInsts; // instructions to save return pointer + InstList restRpInsts; // instructions to restore return pointer + InstList restPrsInsts; // instructions to restore preserved predicate registers + InstList restBrsInsts; // instructions to restore preserved branch registers + InstList restFrsInsts; // instructions to restore preserved floating registers + InstList restGrsInsts; // instructions to restore preserved general registers + InstList restUnatInsts; // instructions to restore AR.UNAT + InstList restPfsInsts; // instructions to restore AR.PFS + InstList restSpInsts; // instructions to restore stack pointer + + RegBitSet usedGrMask; // grs used in current method (1 means reg is free) + RegBitSet usedFrMask; // frs used in current method (1 means reg is used) + RegBitSet usedPrMask; // prs used in current method (1 means reg is free) + RegBitSet usedBrMask; // brs used in current method (1 means reg is free) + + NodeVector epilogNodes; // epilog nodes list (nodes which contain "br.ret") +}; + +} // IPF +} // Jitrino + +#endif /*IPFPROLOGEPILOGGENERATOR_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfRegisterAllocator.h vm/jitrino/src/codegenerator/ipf/include/IpfRegisterAllocator.h new file mode 100644 index 0000000..ccb9723 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfRegisterAllocator.h @@ -0,0 +1,59 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFREGISTERALLOCATOR_H_ +#define IPFREGISTERALLOCATOR_H_ + +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// RegisterAllocator +//========================================================================================// + +class RegisterAllocator { +public: + RegisterAllocator(Cfg&); + void allocate(); + +protected: + void buildInterferenceMatrix(); + void makeInterferenceMatrixSymmetric(); + void removePreassignedOpnds(); + void assignLocations(); + + void updateAllocSet(Opnd*, uint32); + void checkCallSite(Inst*); + + MemoryManager &mm; + Cfg &cfg; + OpndManager *opndManager; + RegOpndSet allocSet; // set of all opnds that need allocation + RegOpndSet liveSet; // set of opnds alive in current node (buildInterferenceMatrix) +}; + +} // IPF +} // Jitrino + +#endif /*IPFREGISTERALLOCATOR_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeInterface.h vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeInterface.h new file mode 100644 index 0000000..1e05c7a --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeInterface.h @@ -0,0 +1,67 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFRUNTIMEINTERFACE_H_ +#define IPFRUNTIMEINTERFACE_H_ + +#include "CodeGenIntfc.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// RuntimeInterface +//========================================================================================// + +class RuntimeInterface : public ::Jitrino::RuntimeInterface { +public: + void unwindStack(MethodDesc*, JitFrameContext*, bool) ; + bool canEnumerate(MethodDesc*, NativeCodePtr); + void getGCRootSet(MethodDesc*, GCInterface*, const JitFrameContext*, bool); + uint32 getInlineDepth(InlineInfoPtr, uint32); + Method_Handle getInlinedMethod(InlineInfoPtr, uint32, uint32); + void fixHandlerContext(MethodDesc*, JitFrameContext*, bool); + void *getAddressOfThis(MethodDesc*, const JitFrameContext*, bool); + void *getAddressOfSecurityObject(MethodDesc*, const JitFrameContext*); + bool recompiledMethodEvent(BinaryRewritingInterface&, MethodDesc*, void*); + bool getBcLocationForNative(MethodDesc*, uint64, uint16*); + bool getNativeLocationForBc(MethodDesc*, uint16, uint64*); + uint16 getInlinedBc(void *v, unsigned int i1, unsigned int i2) { return 0; } // TODO + +protected: + + // getGCRootSet support + Byte *findSafePoint(Byte*, uint32, uint64); + void enumerateRootSet(GCInterface*, const JitFrameContext*, Byte*); + void **getContextValue(int32); + void reportMptr(int32, int32); + void reportBase(int32); + bool isMptr(int32); + + GCInterface *gcInterface; + const JitFrameContext *context; +}; + +} // IPF +} // Jitrino + +#endif /*IPFRUNTIMEINTERFACE_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeSupport.h vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeSupport.h new file mode 100644 index 0000000..90aebff --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfRuntimeSupport.h @@ -0,0 +1,137 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFRUNTIMESUPPORT_H_ +#define IPFRUNTIMESUPPORT_H_ + +#include "IpfCfg.h" +#include "IpfOpndManager.h" +#include "IpfRuntimeInterface.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// Forward declarations +//========================================================================================// + +struct TryRegion; +struct MptrDef; +struct SafePoint; + +//========================================================================================// +// Typedefs +//========================================================================================// + +typedef vector < TryRegion* > RegionVector; +typedef vector < SafePoint > SafePointVector; +typedef map < RegOpnd*, MptrDef > MptrDefMap; + +typedef MptrDefMap::iterator MptrDefMapIterator; + +//========================================================================================// +// TryRegion +//========================================================================================// + +struct TryRegion { + TryRegion(Byte*, Byte*, Byte*, ObjectType*, bool); + + Byte *startAddr; + Byte *endAddr; + Byte *handlerAddr; + ObjectType *exceptionType; + bool isExceptionObjDead; +}; + +//========================================================================================// +// MptrDef +//========================================================================================// + +class MptrDef { +public: + MptrDef() { node=NULL; inst=NULL; base=NULL; } + MptrDef(BbNode *node, Inst *inst, RegOpnd *base) : node(node), inst(inst), base(base) {} + + BbNode *node; // node in which mptr defined + Inst *inst; // inst defining mptr (if inst==NULL - base is merged) + RegOpnd *base; // base the mptr depends on (add mptr = 16, base) +}; + +//========================================================================================// +// InstPosition +//========================================================================================// + +class SafePoint { +public: + SafePoint() { node=NULL; inst=NULL; } + SafePoint(BbNode *node, Inst *inst) : node(node), inst(inst) {} + + BbNode *node; + Inst *inst; + RegOpndVector alivePtrs; +}; + +//========================================================================================// +// RuntimeSupport +//========================================================================================// + +class RuntimeSupport { +public: + RuntimeSupport(Cfg&, CompilationInterface&); + void makeRuntimeInfo(); + void buildRootSet(); + +protected: + MemoryManager &mm; + Cfg &cfg; + CompilationInterface &compilationInterface; + OpndManager *opndManager; + + // Exception registration + void registerExceptionHandlers(); + void makeRegion(Byte* startAddr, Byte* endAddr, Node* dispatchNode); + + RegionVector tryRegions; + + // Make info block which will be used in stack unwind routine + StackInfo *makeStackInfo(); + + // Build root set and extend bases live range + void newSafePoint(BbNode*, Inst*, RegOpndSet&); + void defMptr(BbNode*, Inst*); + void mergeBase(BbNode*, Inst*, RegOpnd*, RegOpnd*); + void replaceBase(Inst*, Opnd*, Opnd*); + void insertMovInst(BbNode*, Inst*, Opnd*, Opnd*); + void insertBases(Inst*, RegOpndVector&); + + void makeRootSetInfo(Uint32Vector&); + void writeSpInfo(Uint32Vector&, uint64, RegOpndVector&); + int32 toInt32(RegOpnd*); + + SafePointVector safePoints; // after buildRootSet() vector contains all safe points + MptrDefMap mptr2def; // +}; + +} // IPF +} // Jitrion + +#endif /*IPFRUNTIMESUPPORT_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfSpillGen.h vm/jitrino/src/codegenerator/ipf/include/IpfSpillGen.h new file mode 100644 index 0000000..1a11c00 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfSpillGen.h @@ -0,0 +1,84 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFSPILLGEN_H_ +#define IPFSPILLGEN_H_ + +#include "IpfCfg.h" + +namespace Jitrino { +namespace IPF { + +//========================================================================================// +// SpillGen +//========================================================================================// + +class SpillGen { +public: + SpillGen(Cfg&); + void genSpillCode(); + +protected: + void spillInst(Inst* inst); + RegOpnd *spillOpnd(RegOpnd*, bool); + void resetSpillRegMasks(); + int32 getAvailableSpillReg(OpndKind); + int32 getAvailableReg(RegBitSet&, int16); + bool containsStackOpnd(Inst*); + void printResult(InstVector&, uint16); + + void spillGr(RegOpnd*); + void spillFr(RegOpnd*); + void spillBr(RegOpnd*); + void spillPr(RegOpnd*); + + void fillGr(RegOpnd*); + void fillFr(RegOpnd*); + void fillBr(RegOpnd*); + void fillPr(RegOpnd*); + + MemoryManager &mm; + Cfg &cfg; + OpndManager *opndManager; + + Opnd *p0; // opnd representing p0 + Opnd *sp; // opnd representing stack pointer + Opnd *stackAddr; // opnd used to calculate stack address (always r14) + InstVector fillCode; // buffer for fill insts to be inserted in node inst list + InstVector spillCode; // buffer for spill insts to be inserted in node inst list + + int32 outOffset; // offset of the first mem out arg (bytes) + int32 locOffset; // offset of the first mem local (bytes) + int32 psfOffset; // offset of previous stack frame (bytes) + int32 inOffset; // offset of the first mem in arg (bytes) + int32 maxOffset; // first unavailable in current frame offset (bytes) + + RegBitSet spillGrMask; // gr available for spilling (true - reg is available) + RegBitSet spillFrMask; // fr available for spilling (true - reg is available) + RegBitSet spillPrMask; // pr available for spilling (true - reg is available) + RegBitSet spillBrMask; // br available for spilling (true - reg is available) +}; + +} // IPF +} // Jitrino + +#endif /*IPFSPILLGEN_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfType.h vm/jitrino/src/codegenerator/ipf/include/IpfType.h new file mode 100644 index 0000000..9833d4e --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfType.h @@ -0,0 +1,254 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFTYPE_H_ +#define IPFTYPE_H_ + +#include <set> +#include <map> +#include <list> +#include <bitset> +#include <vector> +#include <string> +#include <sstream> +#include <algorithm> +#include <utility> +#include <iomanip> +#include "Type.h" +#include "Log.h" +#include "VMInterface.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +// TODO +#define IpfCOUT std::cerr +extern bool isIpfCompiled(MethodDesc* method); +extern bool isIpfMethod(MethodDesc* method); +extern bool isIpfBreakBb(unsigned int nodeid); +extern bool isIpfBreakMethod(MethodDesc* method, bool recompile=false); +extern bool isIpfLogoutMethod(MethodDesc* method); +extern bool ipfEnableSigillBreakActionHandler; +extern bool ipfEnableAutoSigillBreak; +extern bool ipfSigillBreakAllBB; +extern bool ipfNotifyWhenMethodIsRecompiled; +extern bool ipfCompileAllMethods; +extern int ipfSigillBreakCount; +extern bool ipfLogoutAllMethods; +extern bool __IPF_ONLY__; + +//========================================================================================// +// Forward declaration +//========================================================================================// + +class Opnd; +class RegOpnd; +class ConstantRef; +class NodeRef; +class MethodRef; +class Constant; +class Inst; +class Node; +class BbNode; +class Edge; +class Cfg; + +//========================================================================================// +// Defines +//========================================================================================// + +#define NUM_G_REG 128 // num of general registers +#define NUM_F_REG 128 // num of floating-point registers +#define NUM_P_REG 64 // num of predicate registers +#define NUM_B_REG 8 // num of branch registers +#define NUM_A_REG 128 // num of application registers + +#define MAX_REG_ARG 8 // args number that must be located on regs +#define REG_STACK_BASE 32 // gr stack base +#define G_INARG_BASE 32 // num of register containing first general input arg (not fp) +#define F_INARG_BASE 8 // num of register containing first fp input arg (not general) +#define G_OUTARG_BASE 127 // num of register containing first general output arg (temporary) +#define F_OUTARG_BASE 8 // num of register containing first fp output arg + +#define LOCATION_INVALID 400000 // invalid location for register and stack operands +#define S_INARG_BASE 300000 // memory stack offset containing first input arg (temporary) +#define S_LOCAL_BASE 200000 // first byte of memory stack local storage (temporary) +#define S_OUTARG_BASE 100000 // memory stack offset containing ninth output arg (temporary) +#define S_BASE 200 // memory stack opnds offset in LOCATION space (if location<S_BASE it is reg num else - stack offset) +#define S_SCRATCH_SIZE 16 // size of memory stack scratch area +#define S_ALIGNMENT 16 // alignment of memory stack size + +#define RET_F_REG 8 // num of register containing general return value +#define RET_G_REG 8 // num of register containing fp return value +#define ARG_SLOT_SIZE 8 // size of memory in arg slot +#define SPILL_REG1 14 // register reserved for stack address calculation during spill/fill +#define SPILL_REG2 15 // register reserved for spill/fill + +#define POS_BR_TARGET 1 // position of opnd target25 in inst (qp) br target25 +#define POS_SWITCH_TABLE 2 // position of opnd switchTblAddr in inst (qp) switch branchTgt, switchTblAddr, defTgt, fallThroughTgt +#define POS_SWITCH_DEFAULT 3 // position of opnd defTgt in inst (qp) switch branchTgt, switchTblAddr, defTgt, fallThroughTgt +#define POS_SWITCH_THROUGH 4 // position of opnd fallThroughTgt in inst (qp) switch branchTgt, switchTblAddr, defTgt, fallThroughTgt +#define POS_CMP_P1 1 // position of opnd p1 in inst (qp) cmp p1, p2 = r2, r3 +#define POS_CMP_P2 2 // position of opnd p2 in inst (qp) cmp p1, p2 = r2, r3 +#define LOC_OFFSET 8 // offset of lock owner field in the synchronization header + +#define AR_PFS_NUM 64 // num of AR.PFS register +#define AR_UNAT_NUM 36 // num of AR.UNAT register + +#define ROOT_SET_HEADER_SIZE 4 // header size in root set info block +#define SAFE_POINT_HEADER_SIZE 12 // header size in safe points info block + +//#define LOG_ON ipfLogIsOn // Log for Code Generator is on +//#define VERIFY_ON ipfVerifyIsOn // verification for Code Generator is on +#define LOG_ON 1 // Log for Code Generator is on +#define VERIFY_ON 1 // verification for Code Generator is on +#define LOG_OUT Log::out() +#define STAT_ON 0 // Log for statistic + +#define IPF_ERROR "ERROR in file " << __FILE__ << " line " << __LINE__ << " " +#define IPF_LOG if (LOG_ON) LOG_OUT +#define IPF_STAT if (STAT_ON) LOG_OUT +#define IPF_ERR cerr << IPF_ERROR +#define IPF_ASSERT(condition) if (LOG_ON && !(condition)) { IPF_ERR << (#condition) << endl; } + +extern bool ipfLogIsOn; +extern bool ipfVerifyIsOn; + +//========================================================================================// +// Enums +//========================================================================================// + +enum EdgeKind { + EDGE_BRANCH, // taken branch + EDGE_THROUGH, // untaken branch + EDGE_DISPATCH, // to dispatch or unwind node + EDGE_EXCEPTION, // from dispatch node to exception handler node + EDGE_INVALID +}; + +//----------------------------------------------------------------------------------------// + +enum NodeKind { + NODE_BB, // node containing instructions + NODE_DISPATCH, // represents data flow during exception handling process (try block) + NODE_UNWIND, // represents data flow during handling exception not cought + NODE_INVALID +}; + +//----------------------------------------------------------------------------------------// +// OpndKind shows how Opnd::value field should be treated in encoder + +enum OpndKind { + OPND_G_REG, // general register number + OPND_F_REG, // floating-point register number + OPND_P_REG, // predicate register number + OPND_B_REG, // branch register number + OPND_A_REG, // application register number + OPND_IP_REG, // instruction pointer register (Opnd::value ignored) + OPND_UM_REG, // user mask register (Opnd::value ignored) + OPND_IMM, // immediate value + OPND_INVALID // something wrong with jit developers +}; + +//----------------------------------------------------------------------------------------// +// DataKind shows how Opnd::value should be treated during compilation + +enum DataKind { + DATA_I8, // signed 8 bit value + DATA_U8, // unsigned 8 bit value + DATA_I16, // signed 16 bit value + DATA_U16, // unsigned 16 bit value + DATA_I32, // signed 32 bit value + DATA_U32, // unsigned 32 bit value + DATA_I64, // signed 64 bit value + DATA_U64, // unsigned 64 bit value + DATA_S, // IEEE single precision + DATA_D, // IEEE double precision + DATA_F, // IEEE double-extended precision + DATA_P, // unsigned 8 bit value (0/1) + DATA_B, // unsigned 64 bit value + DATA_BASE, // object reference (should be reported to GC) + DATA_MPTR, // field reference (should be reported to GC) + DATA_IMM, // imm constant (value known durind code selection) + DATA_NODE_REF, // imm constant (method reference - is resolved during code emission) + DATA_METHOD_REF, // imm constant (node reference - is resolved during code emission) + DATA_CONST_REF, // imm constant (memory constant pool - is resolved during code emission) + DATA_SWITCH_REF, // imm constant (memory constant pool - is resolved during code emission) + DATA_INVALID +}; + +//----------------------------------------------------------------------------------------// + +enum SearchKind { + SEARCH_DIRECT_ORDER, // all predecessors stay before successor + SEARCH_POST_ORDER, // all successors stay before predecessor + SEARCH_LAYOUT_ORDER, // order nodes laid out in memory + SEARCH_UNDEF_ORDER // invalidate current order +}; + +//========================================================================================// +// Typedefs +//========================================================================================// + +typedef vector< Opnd* > OpndVector; +typedef vector< RegOpnd* > RegOpndVector; +typedef vector< Inst* > InstVector; +typedef vector< Node* > NodeVector; +typedef vector< Edge* > EdgeVector; +typedef vector< uint32 > Uint32Vector; +typedef list< Inst* > InstList; +typedef set< Opnd* > OpndSet; +typedef set< RegOpnd* > RegOpndSet; +typedef set< Node* > NodeSet; +typedef map< Inst*, RegOpndSet > Inst2RegOpndSetMap; +typedef map< uint64, RegOpndSet > Uint642RegOpndSetMap; +typedef bitset< NUM_G_REG > RegBitSet; + +typedef NodeVector::iterator NodeIterator; +typedef InstVector::iterator InstIterator; +typedef OpndVector::iterator OpndIterator; +typedef OpndSet::iterator OpndSetIterator; +typedef RegOpndSet::iterator RegOpndSetIterator; +typedef InstList::iterator InstListIterator; +typedef Inst2RegOpndSetMap::iterator Inst2RegOpndSetMapIterator; +typedef Uint642RegOpndSetMap::iterator Uint642RegOpndSetMapIterator; + +//========================================================================================// +// IpfType +//========================================================================================// + +class IpfType { +public: + + static int16 getSize(DataKind); // opnd value size in bytes + static bool isReg(OpndKind); // is opnd resides on register + static bool isImm(OpndKind); // is opnd resides in imm + static bool isSigned(DataKind); // is opnd value is signed + static bool isFloating(DataKind); // is opnd value can be placed in fp reg +}; + +} // IPF +} // Jitrino + +#endif /*IPFTYPE_H_*/ diff --git vm/jitrino/src/codegenerator/ipf/include/IpfVerifier.h vm/jitrino/src/codegenerator/ipf/include/IpfVerifier.h new file mode 100644 index 0000000..cb42fe3 --- /dev/null +++ vm/jitrino/src/codegenerator/ipf/include/IpfVerifier.h @@ -0,0 +1,76 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Konstantin M. Anisimov, Igor V. Chebykin + * @version $Revision$ + * + */ + +#ifndef IPFVERIFIER_H_ +#define IPFVERIFIER_H_ + +#include <vector> +#include <bitset> +#include <string> +#include "Type.h" +#include "IpfIrPrinter.h" + +using namespace std; + +namespace Jitrino { +namespace IPF { + +class IpfVerifier { + public: + IpfVerifier(Cfg & cfg, CompilationInterface & compilationinterface); + + bool verifyMethod(char * str=NULL); + bool verifyMethodInsts(char * str=NULL); + bool verifyMethodNodes(char * str=NULL); + bool verifyMethodEdges(char * str=NULL); + bool verifyNodeInsts(BbNode * node); + bool verifyNodeEdges(BbNode * node); + bool verifyInst(string * res, Inst *); + +protected: + static bool cmp_cmp4(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool fcmp(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool ldx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool stx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool ldfx(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool mov(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + static bool br(string * res, Inst * inst, InstCode icode, OpndVector & opnds, CompVector & cmpls); + + static char * getDataKindStr(DataKind datakind); + + static void edgeInvalid(Node* node, ostream& os); + static void edgeBranch( Node* node, Edge* edge, ostream& os); + static void edgeThrough(Node* node, Edge* edge, ostream& os); + +private: + Cfg & cfg; + CompilationInterface & compilationinterface; + MemoryManager & mm; + MethodDesc * methodDesc; + string * methodString; + +}; + +} // IPF +} // Jitrino + +#endif /*IPFVERIFIER_H_*/ diff --git vm/jitrino/src/dynopt/EdgeProfiler.cpp vm/jitrino/src/dynopt/EdgeProfiler.cpp new file mode 100644 index 0000000..6582130 --- /dev/null +++ vm/jitrino/src/dynopt/EdgeProfiler.cpp @@ -0,0 +1,724 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/* COPYRIGHT_NOTICE */ + +/** +* @author Jack Liu, Mikhail Y. Fursov, Chen-Dong Yuan +* @version $Revision$ +*/ + + +#include "Jitrino.h" +#include "EdgeProfiler.h" +#include "Inst.h" +#include "Stl.h" +#include "StaticProfiler.h" +#include "Dominator.h" +#include "Loop.h" +#include "FlowGraph.h" + +#include <string.h> +#include <stdio.h> +#include <limits.h> +#include <sstream> + +namespace Jitrino { + +static bool isMethodTrivial( ControlFlowGraph& cfg ); +static uint32 computeCheckSum( MemoryManager& mm, ControlFlowGraph& cfg, const StlSet<Node*>& nodesToIgnore); +static void calculateProbsFromProfile(MemoryManager& mm, ControlFlowGraph& fg, const Edges& edges, DominatorTree* dt, LoopTree* lt, EdgeMethodProfile* profile, bool bcLevelProfiling, const StlSet<Node*>& nodesToIgnore); +static Node* selectNodeToInstrument(IRManager& irm, Edge* edge); +static void selectEdgesToInstrument(MemoryManager& mm, IRManager& irm, Edges& result, const StlSet<Node*>& nodesToIgnore); +static uint32 genKey( uint32 n, Edge* edge, bool bcLevel, bool debug); +static bool hasCatch( Node* node ); +static void selectedNodesToIgnore(IRManager& irm, LoopTree* lt, StlSet<Node*>& result); + + +DEFINE_SESSION_ACTION(EdgeProfilerInstrumentationPass, edge_instrument, "Perform edge instrumentation pass") + +void EdgeProfilerInstrumentationPass::_run(IRManager& irm) +{ + ControlFlowGraph& flowGraph = irm.getFlowGraph(); + MemoryManager mm( 1024, "Edge InstrumentationPass"); + MethodDesc& md = irm.getMethodDesc(); + InstFactory& instFactory = irm.getInstFactory(); + OptPass::computeDominatorsAndLoops(irm); + bool debug = Log::isEnabled(); + LoopTree* lt = irm.getLoopTree(); + + //printDotFile(irm, true, "inside"); + //printHIR(irm, true, "inside"); + + //set of nodes with out-edges are not taken into account during instrumentation + //and checksum calculation + //such nodes are optional in CFG. E.g. nodes with class initializers insts + StlSet<Node*> nodesToIgnore(mm); + selectedNodesToIgnore(irm, lt, nodesToIgnore); + + //compute checksum first + uint32 _checkSum = computeCheckSum(mm, flowGraph, nodesToIgnore); + + StlVector<uint32> counterKeys(mm); + // Instrument method entry first. + Node* entryNode = flowGraph.getEntryNode(); + entryNode->prependInst(instFactory.makeIncCounter(0)); + bool methodIsTrivial = isMethodTrivial(flowGraph); + bool bcLevelProfiling = false; + if (!methodIsTrivial) { + // Scan the CFG node in topological order and record the blocks and + // edges where we need to add instrumentation code. + // The actual instrumentation will be done in a separate phase so that + // we won't disturb the CFG as we are traversing it. + + Edges edgesToInstrument(mm); + selectEdgesToInstrument(mm, irm, edgesToInstrument, nodesToIgnore); + //compute edge-ids before CFG modification: edge-ids are part of CFG consistency check. + for (Edges::const_iterator it = edgesToInstrument.begin(), end = edgesToInstrument.end(); it!=end; ++it) { + Edge* edge = *it; + uint32 key = genKey(counterKeys.size() + 1, edge, bcLevelProfiling, debug); + assert( key != 0 ); + counterKeys.push_back(key); + } + + // Now revisit all of the edges that need to be instrumented + // and generate instrumentation code. + uint32 i = 0; + for (Edges::const_iterator it = edgesToInstrument.begin(), end = edgesToInstrument.end(); it!=end; ++it, ++i) { + Edge* edge = *it; + Node* nodeToInstrument = selectNodeToInstrument(irm, edge); + assert(nodeToInstrument!=NULL && nodeToInstrument->isBlockNode()); + uint32 key = counterKeys[i]; + Inst* incInst = instFactory.makeIncCounter( key ); + assert(((Inst*)nodeToInstrument->getFirstInst())->getOpcode() != Op_IncCounter ); + nodeToInstrument->prependInst(incInst); + } + } + + irm.getCompilationInterface().lockMethodData(); + + ProfilingInterface* pi = irm.getProfilingInterface(); + if (!pi->hasMethodProfile(ProfileType_Edge, md, JITProfilingRole_GEN)) { + pi->createEdgeMethodProfile(mm , md, counterKeys.size(), (uint32*)&counterKeys.front(), _checkSum); + } + + irm.getCompilationInterface().unlockMethodData(); + + if (debug) { + Log::out() << std::endl << "EdgePC:: instrumented, nCounters="<<counterKeys.size() <<" checksum="<<_checkSum << std::endl; + } + +} + +DEFINE_SESSION_ACTION(EdgeProfilerAnnotationPass, edge_annotate, "Perform edge annotation pass") + +void EdgeProfilerAnnotationPass::_run(IRManager& irm) { + ControlFlowGraph& flowGraph = irm.getFlowGraph(); + MethodDesc& md = irm.getMethodDesc(); + MemoryManager mm( 1024, "Edge AnnotationPass"); + bool debug = Log::isEnabled(); + // Create the edge profile structure for the compiled method in 'irm'. + ProfilingInterface* pi = irm.getProfilingInterface(); + bool edgeProfilerMode = pi->isProfilingEnabled(ProfileType_Edge, JITProfilingRole_USE); + bool entryBackedgeProfilerMode = !edgeProfilerMode && pi->isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_USE); + uint32 entryCount = (edgeProfilerMode || entryBackedgeProfilerMode) ? pi->getProfileMethodCount(md) : 0; + if (isMethodTrivial(flowGraph) || !edgeProfilerMode || entryCount == 0) { + // Annotate the CFG using static profiler heuristics. + if (debug) { + Log::out()<<"Using static profiler to estimate graph"<<std::endl; + } + StaticProfiler::estimateGraph(irm, entryCount); + return; + } + + OptPass::computeDominatorsAndLoops(irm); + DominatorTree* dt = irm.getDominatorTree(); + +// printDotFile(irm, true, "inside"); + + LoopTree* lt = irm.getLoopTree(); + + // sync checksum + StlSet<Node*> nodesToIgnore(mm); //see instrumentation pass for comments + selectedNodesToIgnore(irm, lt, nodesToIgnore); + + uint32 cfgCheckSum = computeCheckSum(mm, flowGraph, nodesToIgnore); + + EdgeMethodProfile* edgeProfile = pi->getEdgeMethodProfile(mm, md); + uint32 profileCheckSum = edgeProfile->getCheckSum(); + assert(profileCheckSum == cfgCheckSum); + if (cfgCheckSum != profileCheckSum) { + if (Log::isEnabled()) { + Log::out() << "ERROR: invalid CFG checksum!"; + } + return; + } + + // Start propagating the CFG from instrumented edges. + Edges edges(mm); + selectEdgesToInstrument(mm, irm, edges, nodesToIgnore); + assert(edges.size() == edgeProfile->getNumCounters()); + bool bcLevelProfiling = false; //TODO: + calculateProbsFromProfile(mm, flowGraph, edges, dt, lt, edgeProfile, bcLevelProfiling, nodesToIgnore); + flowGraph.setEdgeProfile(true); + + if (irm.getParent() == NULL) { + // fix profile: estimate cold paths that was never executed and recalculate frequencies + StaticProfiler::fixEdgeProbs(irm); + flowGraph.smoothEdgeProfile(); + } +} + +static inline void setEdgeFreq(StlVector<double>& edgeFreqs, Edge* edge, double freq, bool debug) { + if (debug) { + Log::out()<<"\t settings edge(id="<<edge->getId()<<") freq ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode()); + Log::out() << "->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode()); Log::out()<<") to "<<freq << std::endl; + } + assert(freq>=0); + edgeFreqs[edge->getId()] = freq; +} + +static void updateDispatchPathsToCatch(Node* node, StlVector<double>& edgeFreqs, bool debug) { + double freq = node->getExecCount(); + const Edges& inEdges = node->getInEdges(); + for (Edges::const_iterator it = inEdges.begin(), end = inEdges.end(); it!=end; ++it) { + Edge* edge = *it; + Node* srcNode = edge->getSourceNode(); + if (srcNode->isDispatchNode() && freq > edgeFreqs[edge->getId()]) { + setEdgeFreq(edgeFreqs, edge, freq, debug); + srcNode->setExecCount(std::max(0.0, srcNode->getExecCount()) + freq); + updateDispatchPathsToCatch(srcNode, edgeFreqs, debug); + } + } +} + +static void calculateProbsFromProfile(MemoryManager& mm, ControlFlowGraph& fg, const Edges& pEdges, + DominatorTree* dt, LoopTree* lt, EdgeMethodProfile* profile, + bool bcLevelProfiling, const StlSet<Node*>& nodesToIgnore) +{ + //calculate edge freqs and use them to calculate edge probs. + + bool debug = Log::isEnabled(); + if (debug) { + Log::out()<<"Starting probs calculation" <<std::endl; + } + uint32 entryCount = *profile->getEntryCounter(); + + //1. assign default value to nodes and edges, this value is used for consistency checks latter + StlVector<Node*> nodes(mm); + fg.getNodesPostOrder(nodes); + for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + node->setExecCount(-1); + const Edges& edges = node->getOutEdges(); + for (Edges::const_iterator it2 = edges.begin(), end2 = edges.end(); it2!=end2; ++it2) { + Edge* edge = *it2; + edge->setEdgeProb(-1); + } + } + + //2. calculate edge-freq for every edge. + + //2.1 get freqs for instrumented edges from profile + StlVector<double> edgeFreqs(mm, fg.getMaxEdgeId(), -1); + uint32 n = 1; + for (Edges::const_iterator it = pEdges.begin(), end = pEdges.end(); it!=end; ++it, ++n) { + Edge* edge = *it; + uint32 key = genKey(n, edge, bcLevelProfiling, debug); + uint32 freq = *profile->getCounter(key); + setEdgeFreq(edgeFreqs, edge, freq, debug); + } + + + //2.2 fix catch freqs, so we will have estimated D->C edges + if (debug) { + Log::out()<<"\tFixing catch freqs"<<std::endl; + } + for (StlVector<Node*>::reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end(); + if (!node->isCatchBlock() || ignored) { + continue; + } + //set up catch block prob -> will be used for dispatch nodes. + double nodeFreq = 0; + const Edges& outEdges = node->getOutEdges(); + for (Edges::const_iterator it2 = outEdges.begin(), end2 = outEdges.end(); it2!=end2; ++it2) { + Edge* edge = *it2; + double edgeFreq = edgeFreqs[edge->getId()]; + assert(edgeFreq >= 0); + nodeFreq+=edgeFreq; + } + node->setExecCount(nodeFreq); + if (debug) { + Log::out()<<"\t\t fixing catch node ";FlowGraph::printLabel(Log::out(), node);Log::out()<<" freq="<<nodeFreq<<std::endl; + } + updateDispatchPathsToCatch(node, edgeFreqs, debug); + } + + //2.3 propagate freqs to every edge and save node freqs + if (debug) { + Log::out()<<"\tPropagating edge freqs"<<std::endl; + } + for (StlVector<Node*>::reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end(); + double nodeFreq = 0; + const Edges& outEdges = node->getOutEdges(); + const Edges& inEdges = node->getInEdges(); + if (debug) { + Log::out()<<"\t\tNode="; FlowGraph::printLabel(Log::out(), node);Log::out()<<" in-edges="<<inEdges.size() << " was ignored="<<ignored<<std::endl; + } + if (node->getInDegree() == 0) { + assert(node == fg.getEntryNode()); + nodeFreq = entryCount; + } else if (node->isCatchBlock()) { //set up catch block prob -> will be used for dispatch nodes. + if (ignored) { + // ignored catch edge (successor of ignored node or catch-loop) + // max we can do here is to try to get catch freq from in-edge + double _freq = 0; + Edge* inEdge = *node->getInEdges().begin(); + if (node->getInDegree() == 1 && edgeFreqs[inEdge->getId()]>=0) { + _freq = edgeFreqs[inEdge->getId()]; + } + Edge* outEdge = *node->getOutEdges().begin(); + nodeFreq = edgeFreqs[outEdge->getId()] = _freq; + } else {//all out-edges were instrumented -> easy to calculate freq + nodeFreq = node->getExecCount(); //already assigned + assert(nodeFreq>=0); + } + } else { + for (Edges::const_iterator it2 = inEdges.begin(), end2 = inEdges.end(); it2!=end2; ++it2) { + Edge* edge = *it2; + Node* srcNode = edge->getSourceNode(); + //assign edge-freq when available + //or 0-freq when source is dispatch (catches handled separately) + //or freq of src node when src node was removed from instrumentation(equal freq for all out-edges) + double edgeFreq = 0; + if (nodesToIgnore.find(srcNode)!=nodesToIgnore.end()) { + assert(srcNode->getExecCount()!= -1 || (srcNode->isCatchBlock() && dt->dominates(node, srcNode)) || (hasCatch(node) && srcNode->isEmpty())); + edgeFreq = srcNode->getExecCount(); + } else if (srcNode->isBlockNode()) { + edgeFreq = edgeFreqs[edge->getId()]; + } + if (debug) { + Log::out()<<"\t\t\tedge id="<<edge->getId()<<" from="; FlowGraph::printLabel(Log::out(), srcNode); + Log::out()<<" freq="<<edgeFreq<<std::endl; + } + if (edgeFreq == -1) { +#ifdef _DEBUG + Node* head = lt->getLoopHeader(node, false); //catch loops are not instrumented + assert(head != NULL && (head->isCatchBlock() || head->isDispatchNode() || hasCatch(head))); +#endif + edgeFreq = 0; + setEdgeFreq(edgeFreqs, edge, edgeFreq, debug); + } + nodeFreq +=edgeFreq; + } + } + if (debug) { + Log::out()<<"\t\t\tnode freq="<<nodeFreq<<std::endl; + } + assert(nodeFreq!=-1); + node->setExecCount(nodeFreq); + if (node->isExitNode()) { + continue; + } + //now we able to calculate all outgoing edge freqs for current node + //if node is bb -> only 1 edge is allowed to be without freq here and we will fix it + //if node is dispatch -> use catch node freqs + //if node was ignored -> equal freq for every bb edge, 0 to dispatch edge + double freqLeft = nodeFreq; + if (ignored) { + if ( outEdges.size()==1 ) { + Edge* edge = *outEdges.begin(); + setEdgeFreq(edgeFreqs, edge, nodeFreq, debug); + } else { + double freqPerBB = nodeFreq / (outEdges.size() - (node->getExceptionEdge() == NULL ? 0 : 1)); + for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) { + Edge* edge = *it; + setEdgeFreq(edgeFreqs, edge, edge->getTargetNode()->isBlockNode() ? freqPerBB : 0, debug); + } + } + } else if (node->isBlockNode()) { + Edge* notEstimatedEdge = NULL; + for (Edges::const_iterator it2 = outEdges.begin(), end2 = outEdges.end(); it2!=end2; ++it2) { + Edge* edge = *it2; + double edgeFreq = edgeFreqs[edge->getId()]; + if (edgeFreq != -1) { + freqLeft-=edgeFreq; + } else { + assert(notEstimatedEdge==NULL || ignored); // for ignored nodes we can't estimate every edge + if (notEstimatedEdge == NULL) { + notEstimatedEdge = edge; + } else if (notEstimatedEdge->getTargetNode()->isDispatchNode()) { + setEdgeFreq(edgeFreqs, notEstimatedEdge, 0, debug); + notEstimatedEdge = edge; + } else { + setEdgeFreq(edgeFreqs, edge, 0, debug); + } + } + } + if (notEstimatedEdge!=NULL) { + freqLeft = freqLeft < 0 ? 0 : freqLeft; + setEdgeFreq(edgeFreqs, notEstimatedEdge, freqLeft, debug); + } + } else if (node->isDispatchNode()) { + //for all not estimated on step 2.2 D->X edges set edge prob to min (0). + for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) { + Edge* edge = *it; + double _freq = edgeFreqs[edge->getId()]; + if (_freq==-1) { + setEdgeFreq(edgeFreqs, edge, 0, false); + } + } + } + } + +#ifdef _DEBUG + //2.99 debug check : check that every child node in dom-tree that is in the same loop as parent + //has nodeFreq <= parent freq + if (debug) { + Log::out()<<"Running check using dominator tree.."<<std::endl; + } + uint32 rootHeight = dt->getHeight(); + for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it, n++) { + Node* node = *it; + DominatorNode* dNode = dt->getDominatorNode(node); + if (dNode->getHeight()!=rootHeight) { + Node* parent = dNode->getParent()->getNode(); + //have wrong nodes freqs on BB->DN (see 2.3), but edge freqs are OK. + //bool parentIgnored = nodesToIgnore.find(parent)!=nodesToIgnore.end(); + if (node->isBlockNode() && parent->isBlockNode() + && lt->getLoopHeader(parent, false) == lt->getLoopHeader(node, false)) + { + assert(parent->getExecCount() >= node->getExecCount()); + } + } + } +#endif + + //3. calculate edge probs using edge freqs. + if (debug) { + Log::out()<<"Calculating edge probs using freqs.."<<std::endl; + } + for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it, n++) { + Node* node = *it; + double nodeFreq = node->getExecCount(); + assert(nodeFreq!=-1); + const Edges& edges = node->getOutEdges(); + for (Edges::const_iterator it2 = edges.begin(), end2 = edges.end(); it2!=end2; ++it2) { + Edge* edge = *it2; + double edgeFreq =edgeFreqs[edge->getId()]; + assert(edgeFreq!=-1); + double edgeProb = nodeFreq == 0 ? 0 : edgeFreq / nodeFreq ; + assert(edgeProb >= 0 && edgeProb <= 1); + edge->setEdgeProb(edgeProb); + } + } + if (debug) { + Log::out()<<"Finished probs calculation"; + } + +} + +// +// Compute the checksum contribution of the given Edge +// +static uint32 _computeCheckSum(Node* node, const StlSet<Node*>& nodesToIgnore, StlVector<bool>& flags, uint32 depth, bool debug) { + assert(flags[node->getId()] == false); + flags[node->getId()] = true; + //node is removed from checksum calculation if + // 1) it's in ignore list + // 2) it's dispatch or catch -> due to the fact that ignore-list nodes can add more dispatches & catches(finally-blocks) + bool ignored = nodesToIgnore.find(node)!=nodesToIgnore.end(); + bool skipped = ignored || node->getOutDegree()==1 + || (node->isCatchBlock() && node->isEmpty()) || node->isDispatchNode() || node->isExitNode(); + uint32 dSum = skipped ? 0 : depth; + uint32 childDepth = skipped ? depth : depth + 1; + const Edges& outEdges = node->getOutEdges(); + uint32 childsSum = 0; + for (Edges::const_iterator it = outEdges.begin(), end = outEdges.end(); it!=end; ++it) { + Edge* edge = *it; + Node* childNode = edge->getTargetNode(); + //visit only those not visited child nodes that are not dispatch edges of ignored nodes + if (flags[childNode->getId()] == false && !(ignored && childNode->isDispatchNode())) { + childsSum+=_computeCheckSum(childNode, nodesToIgnore, flags, childDepth, debug); + } + } + if (debug){ + Log::out()<< "\t<checksum calculation: node:"; FlowGraph::printLabel(Log::out(), node); + Log::out() << "=+"<<dSum<<" depth="<<depth<< " child sum="<<childsSum<<std::endl; + } + return dSum+childsSum; +} + +static uint32 computeCheckSum( MemoryManager& mm, ControlFlowGraph& cfg, const StlSet<Node*>& nodesToIgnore) { + bool debug = Log::isEnabled(); + if (debug) { + Log::out()<< "calculating checksum.." << std::endl; + } + StlVector<bool> flags(mm, cfg.getMaxNodeId(), false); + uint32 checkSum = _computeCheckSum(cfg.getEntryNode(), nodesToIgnore, flags, 1, debug); + if( debug){ + Log::out()<< "checkSum= "<<checkSum<<std::endl; + } + return checkSum; +} + + +static Node* selectNodeToInstrument(IRManager& irm, Edge* edge) { + ControlFlowGraph& fg = irm.getFlowGraph(); + Node* srcNode = edge->getSourceNode(); + Node* dstNode = edge->getTargetNode(); + Node* result = NULL; + assert(srcNode->isBlockNode() && dstNode->isBlockNode()); + if (srcNode->isCatchBlock()) { + // catch blocks handled separately. We must add counter only after catch inst + assert(srcNode->hasOnlyOneSuccEdge() || hasCatch(srcNode)); + if (srcNode->hasOnlyOneSuccEdge() && hasCatch(srcNode)) { //filter-out catches with ret -> instrument srcNode + result = srcNode; + } else { + result = dstNode; + } + } else { + result = srcNode->hasOnlyOneSuccEdge() ? srcNode : dstNode; + } + if( result->hasTwoOrMorePredEdges() ){ + // Splice a new block on edge from srcNode to dstNode and put + // instrumentation code there. + result = fg.spliceBlockOnEdge(edge, irm.getInstFactory().makeLabel()); + } + return result; +} + +static bool hasCatch( Node* node ) { + Inst* first = (Inst*)node->getFirstInst(); + assert(first->isLabel()); + if (first->getNextInst()!=NULL && first->getNextInst()->getOpcode() == Op_Catch) { + return true; + } + return false; +} + +/*static bool hasCounter( Node* node ) { + for (Inst* inst = node->getFirstInst()->next(); inst!=node->getFirstInst(); inst = inst->next()) { + if (inst->getOpcode() == Op_IncCounter) { + return true; + } + } + return false; + +}*/ + +static void selectedNodesToIgnore(IRManager& irm, LoopTree* lt, StlSet<Node*>& result) { + ControlFlowGraph& fg = irm.getFlowGraph(); + bool debug = Log::isEnabled(); + if (debug) { + Log::out() << "Selecting nodes to ignore:"<<std::endl; + } + const Nodes& nodes = fg.getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + //first pattern to ignore: class initializers + Node* loopHead = lt->getLoopHeader(node, false); + bool inCatchLoop = loopHead!=NULL && (loopHead->isCatchBlock() || loopHead->isDispatchNode() || hasCatch(loopHead)); + if (node->isBlockNode() + && node->getOutDegree() == 2 && node->getExceptionEdge()!=NULL + && ((Inst*)node->getLastInst())->getOpcode() == Op_InitType) + { + result.insert(node); + if (debug) { + Log::out() << "\tIgnoring Op_InitType node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl; + } + } else if (inCatchLoop && node->isEmpty()) { + //common block for multiple catches in catch loop -> add to ignore + result.insert(node); + if (debug) { + Log::out() << "\tIgnoring catch-loop preheader node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl; + } + } else if (node->isCatchBlock()) { //avoid mon-exit loops (catch loops) instrumentation + Node* blockWithCatchInst = NULL; + if (hasCatch(node)) { + blockWithCatchInst = node; + } else { + assert(node->hasOnlyOneSuccEdge()); + Edge* e = *node->getOutEdges().begin(); + blockWithCatchInst = e->getTargetNode(); + if (blockWithCatchInst->hasTwoOrMorePredEdges()) { + result.insert(node); + if (debug) { + Log::out() << "\tIgnoring '1-catch-inst*N-catches' node:";FlowGraph::printLabel(Log::out(), node);Log::out() << std::endl; + } + } + } + } + } + if (debug) { + Log::out() << "DONE. ignored nodes: " << result.size() << std::endl; + } +} + +static void _selectEdgesToInstrument(Node* srcNode, LoopTree* loopTree, Edges& result, + const StlSet<Node*>& nodesToIgnore, StlVector<bool>& flags) +{ + bool profileDispatchEdges = true; //TODO: cmd-line param + + assert(flags[srcNode->getId()] == false); + flags[srcNode->getId()] = true; + const Edges& oEdges = srcNode->getOutEdges(); + bool ignored = nodesToIgnore.find(srcNode)!=nodesToIgnore.end(); + if (!ignored && srcNode->isBlockNode()) { + Edge* skipEdge = NULL; //instrument all edges except one + if (srcNode->isCatchBlock()) { + // for a catch block we can have only 1 successor edge if catch inst is in next block + // if catch inst is in catch block -> instrument every outgoing edge to be able to restore catch + // node frequency easily. + assert(hasCatch(srcNode) || srcNode->hasOnlyOneSuccEdge()); + } else { + for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){ + Edge* edge = *it; + Node* targetNode = edge->getTargetNode(); + bool isBackEdge = loopTree->isBackEdge(edge); + //we must instrument backedges to be able to restore loop iteration count + if( isBackEdge || (!targetNode->isBlockNode() && profileDispatchEdges) ){ + // We run into a dispatch node, so we have to instrument all the other edges. + skipEdge = NULL; + break; + } + // It is profitable to instrument along the loop exit edge. + if (skipEdge == NULL || loopTree->isLoopExit(skipEdge)) { + skipEdge = edge; + } + } + } + bool debug = Log::isEnabled(); + for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){ + Edge* edge = *it; + Node* targetNode = edge->getTargetNode(); + if( targetNode->isBlockNode() && edge!=skipEdge){ + result.push_back(edge); + if (debug) { + Log::out()<<"\tedge id="<<edge->getId()<<" ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode()); + Log::out()<<"->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode());Log::out()<<")"<<std::endl; + } + } + } + } + // process all child nodes. for ignored nodes we do not process dispatches + // because new catch block can be created that must also be ignored + for(Edges::const_iterator it = oEdges.begin(); it!= oEdges.end(); ++it ){ + Edge* edge = *it; + Node* targetNode = edge->getTargetNode(); + if (flags[targetNode->getId()] == false && !(ignored && targetNode->isDispatchNode())) { + _selectEdgesToInstrument(targetNode, loopTree, result, nodesToIgnore, flags); + } + } +} + +static void selectEdgesToInstrument(MemoryManager& mm, IRManager& irm, Edges& result, + const StlSet<Node*>& nodesToIgnore) +{ + LoopTree* loopTree = irm.getLoopTree(); + ControlFlowGraph& fg = irm.getFlowGraph(); + StlVector<bool> flags(mm, fg.getMaxNodeId(), false); + + bool debug = Log::isEnabled(); + if (debug) { + Log::out() << "List of edges to instrument: "<<std::endl; + } + _selectEdgesToInstrument(fg.getEntryNode(), loopTree, result, nodesToIgnore,flags); + if (debug) { + Log::out() << "End of list.."<<std::endl; + } +} + +// +// Return true if the method represented by <cfg> is trivial. +// A method is trivial if it is a leaf method, and it has no if-then-else +// statement. +// +static bool isMethodTrivial( ControlFlowGraph& cfg ) { + const Nodes& nodes = cfg.getNodes(); + Nodes::const_iterator niter; + + for( niter = nodes.begin(); niter != nodes.end(); niter++ ){ + Node* node = *niter; + if( !node->isBlockNode() || node->isEmpty() ){ + continue; + } + Inst* last = (Inst*)node->getLastInst(); + // This method is not a leaf method. + if( last->getOpcode() >= Op_DirectCall && last->getOpcode() <= Op_IntrinsicCall ){ + return false; + } + Edges::const_iterator eiter; + const Edges& oEdges = node->getOutEdges(); + int succ = 0; + + for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { + Edge* edge = *eiter; + if( edge->getTargetNode()->isBlockNode() ){ + succ++; + } + } + // This method has if-then-else statement(s). + if( succ > 1 ){ + return false; + } + } + return true; +} + +static uint32 genKey( uint32 pos, Edge* edge, bool bcLevel, bool debug) { + uint32 key = 0; + if (bcLevel) { + assert(0); //TODO: + /*Node* node = edge->getSourceNode(); + Inst* lastInst = node->getLastInst(); + + if( lastInst->getOpcode() == Op_Branch || lastInst->getOpcode() == Op_Jump ){ + BranchInst* br = (BranchInst*)lastInst; + const uint32 bcAddr = getBcAddr(br); + Node* targetNode = edge->getTargetNode(); + + // Only instrument valid taken branches. + if( ( bcAddr != 0 ) && ( br->getTargetLabel() == targetNode->getFirstInst() ) ){ + assert( (bcAddr & 0xffff0000) != 0 ); + return (uint32)bcAddr; + } + } + return 0; + }*/ + } else { + uint32 edgePos = 0; + const Edges& edges = edge->getSourceNode()->getOutEdges(); + for (Edges::const_iterator it = edges.begin(), end = edges.end(); it!=end; ++it, edgePos++) { + Edge* outEdge = *it; + if (outEdge == edge) { + break; + } + } + + key = pos + (edgePos << 16); + } + if (debug) { + Log::out()<<"\t\t key for edge with id="<<edge->getId()<<" ("; FlowGraph::printLabel(Log::out(), edge->getSourceNode()); + Log::out() << "->"; FlowGraph::printLabel(Log::out(), edge->getTargetNode()); Log::out()<<") is "<< key << std::endl; + } + return key; +} + +} //namespace diff --git vm/jitrino/src/dynopt/EdgeProfiler.h vm/jitrino/src/dynopt/EdgeProfiler.h new file mode 100644 index 0000000..d9450db --- /dev/null +++ vm/jitrino/src/dynopt/EdgeProfiler.h @@ -0,0 +1,34 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/* COPYRIGHT_NOTICE */ +/** +* @author Jack Liu, Mikhail Y. Fursov, Chen-Dong Yuan +* @version $Revision$ +*/ + + +#include "Jitrino.h" +#include "irmanager.h" +#include "VMInterface.h" +#include "EMInterface.h" +#include "optpass.h" + +#include <stdlib.h> + + +namespace Jitrino { + //todo: remove this file +} diff --git vm/jitrino/src/dynopt/Profiler.cpp vm/jitrino/src/dynopt/Profiler.cpp deleted file mode 100644 index aa7b8c6..0000000 --- vm/jitrino/src/dynopt/Profiler.cpp +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.23.20.5 $ - * - */ - - -#include <string.h> -#include <stdio.h> -#include <limits.h> -#include "Jitrino.h" -#include "Profiler.h" -#include "Inst.h" -#include "Stl.h" -#include "MemoryManager.h" - -#if defined(_MSC_VER) && !defined (__ICL) && !defined (__GNUC__) /* Microsoft C Compiler ONLY */ -#define SCANF_I64 "I64" -#define SPRINTF_I64 "I64" -#else -#define SCANF_I64 "ll" -#define SPRINTF_I64 "ll" -#endif - -namespace Jitrino - { - -#define DEFAULT_ITERATION_COUNT 1.0E5 - - -ProfileControl profileCtrl; - - -// Generates the method string into the given buffer of size 'n'. -// Returns the string length if success. -// Returns 0 if the given buffer is too small. -uint32 -genMethodString(MethodDesc& mdesc, char *methodStr, uint32 n) -{ - const char* className = mdesc.getParentType()->getName(); - const char* methodName = mdesc.getName(); - const char* methodSig = mdesc.getSignatureString(); - - uint32 methodStrLen = (uint32) (strlen(className) + strlen(methodName) - + strlen(methodSig) + 3); - - if (methodStrLen >= n) - return 0; - - sprintf(methodStr, "%s::%s%s", className, methodName, methodSig); - return methodStrLen; -} // genMethodString - - -// Compute the checksum contribution of the given CFGEdge -uint32 -getEdgeCheckSum(CFGEdge* edge) -{ - uint32 srcNodeId = edge->getSourceNode()->getId(); - uint32 dstNodeId = edge->getTargetNode()->getId(); - uint32 edgeId = edge->getId(); - uint32 checkSum = ((srcNodeId & 0x3FF) << 22) + ((dstNodeId & 0x3FF) << 12) - + (edgeId & 0xFFF); - if (profileCtrl.debugCFGCheckSum()) - fprintf(stderr, "<checkSum> %u : %u -> %u\n", edgeId, srcNodeId, dstNodeId); - return checkSum; -} // getEdgeCheckSum - - -LoopProfile::LoopProfile(MemoryManager& mm, LoopNode *loop) - : _mm(mm), _members(mm), _exits(mm) -{ - _iter_count = -1.0; - _exit_prob = NULL; - _loop = loop; - _entry = loop->getHeader(); - addMember(_entry); -} // LoopProfile::LoopProfile - - -void -LoopProfile::addMember(CFGNode *node) -{ - CFGEdge *edge; - CFGNode *dst; - - assert(_loop->inLoop(node)); - _members.push_back(node->getId()); - - // add any exit edges to 'exits'. - const CFGEdgeDeque& oEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dst = edge->getTargetNode(); - if ( !_loop->inLoop(dst) ) - _exits.push_back(edge); - else if (dst == _entry) - _back_edge = edge; - } -} // LoopProfile::addMember - - -void -LoopProfile::dump(FILE *file) -{ - uint32 i; - CFGEdge *e; - - fprintf(file, "LOOP PROFILE: entry [%u] iter_count %g\n", - _entry->getId(), _iter_count); - fprintf(file, "\t back edge : %u -> %u\n", - _back_edge->getSourceNode()->getId(), _back_edge->getTargetNode()->getId()); - fprintf(file, "\t members : "); - for (i = 0; i < _members.size(); i++) - fprintf(file, "%u ", _members[i]); - fprintf(file, "\n\t exits : \n"); - for (i = 0; i < _exits.size(); i++) { - e = _exits[i]; - fprintf(file, "\t\t%u -> %u [%g]\n", e->getSourceNode()->getId(), - e->getTargetNode()->getId(), _exit_prob[i]); - } -} // LoopProfile::dump - - -EdgeProfile::EdgeProfile(MemoryManager& mm, FILE *file, char *str, - uint32 counterSize) : _mm(mm), _method(NULL) -{ - int res; - uint32 i; - uint32 n = (uint32) strlen(str); - - _next = NULL; - _methodStr = new(_mm) char[n+1]; - strcpy(_methodStr, str); - _entryFreq = 0.0; - _numEdges = _checkSum = 0; - _blockInfo = NULL; - _edgeProb = NULL; - _hasCheckSum = false; - _profileType = NoProfile; - - res = fscanf(file, "%u", &_checkSum); - res &= fscanf(file, "%u", &_numEdges); - if (counterSize == 4) { - uint32 val32; - res &= fscanf(file, "%u", &val32); - if (res == 0) { - _entryFreq = 0.0; - _numEdges = _checkSum = 0; - return; - } - _entryFreq = (double) val32; - - _numEdges--; // exclude the entry block freq - _edgeFreq = new(_mm) double[_numEdges]; - - for ( i = 0; i < _numEdges; i++) { - res = fscanf(file, "%u", &val32); - if (res == 0 || res == EOF) { - _entryFreq = 0.0; // incomplete profile - _numEdges = _checkSum = 0; - break; - } - _edgeFreq[i] = (double) val32; - } - } else { // counterSize == 8 - int64 val64; - res &= fscanf(file, "%"SCANF_I64"d", &val64); - if (res == 0) { - _entryFreq = 0.0; - _numEdges = _checkSum = 0; - return; - } - - _numEdges--; // exclude the entry block freq - _entryFreq = (double) val64; - for ( i = 0; i < _numEdges; i++) { - res = fscanf(file, "%"SCANF_I64"d", &val64); - if (res == 0 || res == EOF) { - _entryFreq = 0.0; // incomplete profile - _numEdges = _checkSum = 0; - break; - } - _edgeFreq[i] = (double) val64; - } - } - _hasCheckSum = true; - _profileType = InstrumentedEdge; -} // EdgeProfile::EdgeProfile(MemoryManager&, FILE*, char*, uint32) - - -// Build an edge profile buffer for the method specified by 'mdesc'. -EdgeProfile::EdgeProfile(MemoryManager& mm, MethodDesc& mdesc, bool smoothing) - : _mm(mm), _method(&mdesc) -{ - uint32 i; - char methodStr[MaxMethodStringLength]; - - _entryFreq = 0.0; - _numEdges = _checkSum = 0; - _edgeFreq = NULL; - _next = NULL; - _blockInfo = NULL; - _edgeProb = NULL; - _hasCheckSum = false; - _profileType = NoProfile; - - _methodStr = NULL; - if ((i = genMethodString(mdesc, methodStr, MaxMethodStringLength)) != 0) { - _methodStr = new(_mm) char[i]; - strcpy(_methodStr, methodStr); - } - - return; -} - - -// Validate the profile source is consistent with the CFG. -// Return TRUE if the profile is OK; FALSE otherwise. -bool -EdgeProfile::isProfileValidate( - FlowGraph& flowGraph, - StlVector<CFGNode*>& po, - bool warning_on) -{ - StlVector<CFGNode*>::reverse_iterator niter; - CFGEdgeDeque::const_iterator eiter; - const LoopTree& loopInfo = *(flowGraph.getIRManager()->getLoopTree()); - CFGNode *node; - - if (_profileType == NoProfile) { // no edge profile info - if (warning_on) - ::std::cerr << "WARNING: no profile for [" << _methodStr << "]" << ::std::endl; - return false; - } else if (_profileType == InstrumentedEdge) { - if (_numEdges == 0) { - if (warning_on) - ::std::cerr << "WARNING: no profile for [" << _methodStr - << "] : profile has ZERO edge count" << ::std::endl; - return false; - } - - if (flowGraph.getMaxEdgeId() != _numEdges) { - // the CFG is not consistent with what is assumed in the profile source - if (warning_on) - ::std::cerr << "WARNING: CFG mismatch in [" << _methodStr - << "] : profile edge count = " << (unsigned int) _numEdges - << ", use CFG edge count = " << (unsigned int) flowGraph.getMaxEdgeId() - << ::std::endl; - return false; - } - } - - - if (_hasCheckSum) { - // Compute and verify CFG check sum. - uint32 sum = 0; - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - node = *niter; - const CFGEdgeDeque& oEdges = (node)->getOutEdges(); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - sum += getEdgeCheckSum(*eiter); - } - - // Assume that a loop header node has two predecessors. - if ( loopInfo.isLoopHeader(node) && node->getInDegree() != 2) { - ::std::cerr << "WARNING: [" << _methodStr << "] Loop header (N" - << (unsigned int) node->getId() << ") has " - << (unsigned int) node->getInDegree() << "predecessors!" - << ::std::endl; - return false; - } - } - if (sum != _checkSum) { - // the CFG is not consistent with that in the profile - if (warning_on) - ::std::cerr << "WARNING: CFG checksum mismatch [" << _methodStr << ::std::endl; - return false; // skip profile annotation - } - } - return true; -} // EdgeProfile::isProfileValidate - - -// Set up the edge taken probability out of the source node for each outgoing -// edges from instrumentation-based edge profile. -// It is assumed that a simple propagation phase to propagate the block -// execution frequency have been performed and the CFG is already annotated -// with the propagated profile. -// This function is expected to be invoked to sommth the profile when the -// profile is annotated to the CFG exhinbits inconsistency. -void -EdgeProfile::setupEdgeProbFromInstrumentation( - FlowGraph& cfg, - StlVector<CFGNode*>& po) -{ - StlVector<CFGNode*>::reverse_iterator niter; - CFGEdgeDeque::const_iterator eiter; - CFGNode *srcNode; - CFGEdge *edge, *exception_edge; - uint32 i, id, outDegree, exceptionEdgeCount; - double freqTotal, prob, efreq=0.0; - uint32 edgeCount = cfg.getMaxEdgeId(); - - _edgeProb = new(_mm) double[edgeCount]; - for ( i = 0; i < edgeCount; i++) - _edgeProb[i] = -1.0; - - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - srcNode = *niter; - const CFGEdgeDeque& oEdges = srcNode->getOutEdges(); - - outDegree = (uint32) oEdges.size(); - if (outDegree == 0) - continue; - - if (outDegree == 1) { - edge = *(oEdges.begin()); - _edgeProb[edge->getId()] = 1.0; - continue; - } - - // outDegree >= 2 - - // Compute the total frequency for all outgoing edges. - exceptionEdgeCount = 0; - exception_edge = NULL; - freqTotal = 0.0; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - freqTotal += _edgeFreq[edge->getId()]; - if (edge->getEdgeType() == CFGEdge::Exception) { - exceptionEdgeCount++; - exception_edge = edge; - } - } - assert(exceptionEdgeCount <= 1); - - // Now compute the edge taken probability for all outgoing edges - // from the srcNode. - if (exceptionEdgeCount > 0) { - if (srcNode->getFreq() > freqTotal) { - efreq = srcNode->getFreq() - freqTotal; - freqTotal = srcNode->getFreq(); - } else { - efreq = 0.0; - } - } - - if (freqTotal > 0.0) { // compute edge taken probability from profile - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - id = edge->getId(); - _edgeProb[id] = _edgeFreq[id] / freqTotal; - } - if (exception_edge != NULL) { - _edgeProb[exception_edge->getId()] = efreq / freqTotal; - } - } else { // estimate edge taken probability - // Exception edges are set to probability of 0.0. Non-exception - // edges are assumed to be taken with equal probability. - prob = 1.0 / ((double) (outDegree - exceptionEdgeCount)); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - id = edge->getId(); - _edgeProb[id] = - (edge->getEdgeType() == CFGEdge::Exception) ? 0.0 : prob; - } - } - } -} // EdgeProfile::setupEdgeProbFromInstrumentation - - -// Set up the edge taken probability array _edgeProb from the existing CFG -// profile information. -void -EdgeProfile::setupEdgeProbFromCFG( - FlowGraph& cfg, - StlVector<CFGNode*>& po) -{ - CFGEdgeDeque::const_iterator eiter; - StlVector<CFGNode*>::reverse_iterator niter; - CFGNode *node; - uint32 i, count, edgeCount; - double p, prob; - - // Set the entry node frequency. - node = *po.rbegin(); - assert(node->getInEdges().size() == 0); - _entryFreq = node->getFreq(); - - // Set the edge probability array. - edgeCount = cfg.getMaxEdgeId(); - _edgeProb = new(_mm) double[edgeCount]; - for ( i = 0; i < edgeCount; i++) - _edgeProb[i] = -1.0; - - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - CFGNode *node = *niter; - const CFGEdgeDeque& oEdges = node->getOutEdges(); - - prob = 0.0; - count = 0; // count non-exception edges - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - CFGEdge *edge = *eiter; - p = edge->getEdgeProb(); - _edgeProb[edge->getId()] = p; - prob += p; - if ( edge->getEdgeType() != CFGEdge::Exception ) - count++; - } - - // Fix the taken probability from node if it is corrupted. - if (prob == 0.0) { - // Evenly distribute the probability among non-exception edges. - if (count != 0) { - p = 1.0 / count; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - CFGEdge *edge = *eiter; - if ( edge->getEdgeType() != CFGEdge::Exception ) - _edgeProb[edge->getId()] = p; - } - } else { - p = 1.0 / ((double) oEdges.size()); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - CFGEdge *edge = *eiter; - _edgeProb[edge->getId()] = p; - } - } - } else if (prob != 1.0) { - // Scale the taken probability so that the taken probability of all - // outgoing edges add up to 1,0. - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - CFGEdge *edge = *eiter; - i = edge->getId(); - _edgeProb[i] = _edgeProb[i] / prob; - } - } - } -} // EdgeProfile::setupEdgeProbFromCFG - - - -// Setup Block Info array. -// Also construct the LoopProfile structure if a node belongs to a loop. -// The LoopProfile structure contains several loop-related information -// such as loop entry, exits, members, probability of each exit, and -// the estimated loop iteration count. The exit probability and the -// estimated loop iteration count will be filled in later by -// computeLoopIterCountExitProb(). -void -EdgeProfile::setupBlockInfo(FlowGraph& cfg, StlVector<CFGNode*>& po) -{ - LoopTree *loopInfo = cfg.getIRManager()->getLoopTree(); - StlVector<CFGNode*>::reverse_iterator niter; - CFGNode *node, *header; - LoopProfile *loopPf; - LoopNode *loopNode; - uint32 nodeCount = cfg.getMaxNodeId(); - uint32 i, id; - - _blockInfo = new(_mm) BlockProfile[nodeCount]; - for ( i = 0; i < nodeCount; i++) { - _blockInfo[i].count = -1.0; - _blockInfo[i].block = NULL; - _blockInfo[i].loop = NULL; - } - - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - node = *niter; - id = node->getId(); - _blockInfo[id].block = node; - if ( loopInfo->isLoopHeader(node) ) { - loopNode = loopInfo->getLoopNode(node); - assert(loopNode && loopNode->getHeader() == node); - _blockInfo[id].loop = new(_mm) LoopProfile(_mm, loopNode); - } else if (loopInfo->hasContainingLoopHeader(node)) { - header = loopInfo->getContainingLoopHeader(node); - assert(header); - loopPf = _blockInfo[header->getId()].loop; - if (loopPf) { - loopPf->addMember(node); - _blockInfo[id].loop = loopPf; - } else { - // The header node of a loop should be traversed - // before its other members. - fprintf(stderr, "No loop header found!!\n"); - assert(0); - } - } - } -} // EdgeProfile::setupBlockInfo -// Compute the estimated loop iteration count and the probability of each -// loop exit (normalized so that they sum is equal to 1.0) and record -// them in the LoopProfile structure of the respective loop. -void -EdgeProfile::computeLoopIterCountExitProb( - LoopProfile *loop_profile, - double *edge_prob - ) -{ - double node_prob; // probability of reaching a node from the loop entry - double eprob; - uint32 node_id, i, j, n, eid; - CFGNode *node, *dstNode; - CFGEdgeDeque::const_iterator eiter; - CFGEdge* edge; - LoopProfile *loop_pfl; - bool dbg_dump = false; // profileCtrl.matchSpecifiedMethod(_methodStr); - - - - // Visit each node in the loop in topological order and compute the - // reaching probability from the loop entry node for each node and - // its outgoing edges. - // Note: the members are arranged in topological order. - for (i = 0; i < loop_profile->_members.size(); i++) { - node_id = loop_profile->_members[i]; - node = _blockInfo[node_id].block; - - // Compute the reaching probability to the node from loop entry. - if (i == 0) { // this is the loop entry node - node_prob = 1.0; // entry node freq starts with 1.0 - } else { - // Non-entry node has incoming edges from inside the loop only. - // The node probability is the sum of all its incoming edges. - const CFGEdgeDeque& iEdges = node->getInEdges(); - node_prob = 0.0; - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - node_prob += edge_prob[edge->getId()]; - } - } - - // Compute the probability of each outgoing edge of this node. - const CFGEdgeDeque& oEdges = node->getOutEdges(); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - n = edge->getId(); - edge_prob[n] = node_prob * _edgeProb[n]; - - if (dbg_dump) { - fprintf(stderr, "\t++++ %u -> %u [%g]\n", edge->getSourceNode()->getId(), - edge->getTargetNode()->getId(), edge_prob[n]); - } - - // If the dstNode of an outgoing edge is the header of a loop L - // nested in the current loop, propagate probability to all exits - // of loop L. - eprob = edge_prob[n]; - dstNode = edge->getTargetNode(); - if (loop_profile->_loop->inLoop(dstNode)) { - loop_pfl = _blockInfo[dstNode->getId()].loop; - if (loop_pfl != loop_profile) { - for (j = 0; j < loop_pfl->_exits.size(); j++) { - eid = loop_pfl->_exits[j]->getId(); - edge_prob[eid] = loop_pfl->_exit_prob[j] * eprob; - - if (dbg_dump) { - fprintf(stderr, "\t++++** %u -> %u [%g]\n", - loop_pfl->_exits[j]->getSourceNode()->getId(), - loop_pfl->_exits[j]->getTargetNode()->getId(), - edge_prob[eid]); - } - } - } - } - } - } - - // Compute the estimated loop iteration count as - // 1.0/(1.0 - back_edge_prob). - assert(loop_profile->_back_edge); - n = loop_profile->_back_edge->getId(); - - if (dbg_dump) { - fprintf(stderr, "\t++++ back edge [%g]\n", edge_prob[n]); - } - - eprob = edge_prob[n]; // back edge probability - if (eprob == 1.0) { // an infinite loop - // give a big number instead of infinite so that the profile - // inside the loop can still be derived and differentiated. - loop_profile->_iter_count = DEFAULT_ITERATION_COUNT; - } else { - loop_profile->_iter_count = 1.0 / (1.0 - eprob); - } - - // Setup the probability array for loop exit edges. The sum of all - // exits are normalized to probability of 1.0. - eprob = 1.0 - eprob; // sum of all exit edges probability - loop_profile->allocExitProbArray(); - for (i = 0; i < loop_profile->_exits.size(); i++) { - n = loop_profile->_exits[i]->getId(); - if (eprob <= 0.0) - loop_profile->_exit_prob[i] = 0.0; - else - loop_profile->_exit_prob[i] = edge_prob[n] / eprob; - } -} // EdgeProfile::computeLoopIterCountExitProb - - -// Loop profile is computed and setup in depth-first order. That is, -// from inner-most out. -void -EdgeProfile::setupLoopProfile( - LoopNode *loopNode, - double *work - ) -{ - CFGNode *node; - uint32 n, id; - LoopProfile *loopProfile; - - for ( n = 1; loopNode; loopNode = loopNode->getSiblings(), n++) { - // process inner loops first - setupLoopProfile(loopNode->getChild(), work); - - // process this loop. - node = loopNode->getHeader(); - if (node == NULL) - return; - - id = node->getId(); - loopProfile = _blockInfo[id].loop; - assert(loopProfile != NULL && loopProfile->_loop == loopNode); - if (loopProfile) { - computeLoopIterCountExitProb(loopProfile, work); - } - } -} // EdgeProfile::setupLoopProfile - - -// Derive profile from the edge taken probability and the method entry -// frequency. -void -EdgeProfile::deriveProfile(FlowGraph& cfg, StlVector<CFGNode*>& po) -{ - LoopTree *loopInfo = cfg.getIRManager()->getLoopTree(); - CFGNode *node, *srcNode; - CFGEdge *edge; - CFGEdgeDeque::const_iterator eiter; - StlVector<CFGNode*>::reverse_iterator niter; - uint32 nid, snid, eid; - double freq; - bool dbg_dump = false; - - if (dbg_dump) fprintf(stderr, "deriveProfile> %s\n", _methodStr); - node = *po.rbegin(); - _blockInfo[node->getId()].count = _entryFreq; - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - node = *niter; - nid = node->getId(); - - const CFGEdgeDeque& iEdges = node->getInEdges(); - if (iEdges.size() == 0) { - if (_blockInfo[nid].count < 0.0) - fprintf(stderr, "!?!?!? [%s] unreachable node N%u\n", _methodStr, nid); - continue; - } - - // Current node freq is the sum of freq from all incoming edges. - // If the current node is a loop header (or entry), its freq is - // the freq from the loop pre-header multiplied by the estimated - // loop iteration count. - if (dbg_dump) fprintf(stderr, "deriveProfile> N%u = (", nid); - - freq = 0.0; - if (loopInfo->isLoopHeader(node)) { - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - srcNode = edge->getSourceNode(); - snid = srcNode->getId(); - if (_blockInfo[nid].loop != _blockInfo[snid].loop) { - // count the freq from loop pre-header only - eid = edge->getId(); - - if (_blockInfo[snid].count > 0.0) - freq += _blockInfo[snid].count * _edgeProb[eid]; - - if (dbg_dump) { - fprintf(stderr, "N%u->N%u[%g*%g] ", - snid, edge->getTargetNode()->getId(), - _blockInfo[snid].count, _edgeProb[eid]); - } - } - } - freq = freq * _blockInfo[nid].loop->_iter_count; - if (dbg_dump) fprintf(stderr, ") * %g", _blockInfo[nid].loop->_iter_count); - } else { - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - srcNode = edge->getSourceNode(); - snid = srcNode->getId(); - eid = edge->getId(); - - if (_blockInfo[snid].count > 0.0) - freq += _blockInfo[snid].count * _edgeProb[eid]; - - if (dbg_dump) { - fprintf(stderr, "N%u->N%u[%g*%g] ", - snid, edge->getTargetNode()->getId(), - _blockInfo[snid].count, _edgeProb[eid]); - } - } - if (dbg_dump) fprintf(stderr, ")"); - } - _blockInfo[nid].count = freq; - if (dbg_dump) { - fprintf(stderr, " = %g\n", freq); - fflush(stderr); - } - } - - setProfile(cfg, po); -} // EdgeProfile::deriveProfile - - -// Copy the profile derived from smoothing into the flowgraph. -void -EdgeProfile::setProfile(FlowGraph& cfg, StlVector<CFGNode*>& po) -{ - CFGNode *node; - CFGEdge *edge; - CFGEdgeDeque::const_iterator eiter; - StlVector<CFGNode*>::reverse_iterator niter; - uint32 nid, eid; - double v; - - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - node = *niter; - nid = node->getId(); - v = node->getFreq(); // for debug - node->setFreq(_blockInfo[nid].count); - _blockInfo[nid].count = v; // for debug - - const CFGEdgeDeque& oEdges = node->getOutEdges(); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - eid = edge->getId(); - v = edge->getEdgeProb(); // for debug - edge->setEdgeProb(_edgeProb[eid]); - _edgeProb[eid] = v; // for debug - } - } -} // EdgeProfile::setProfile - - -// Validate the profile information. -bool -EdgeProfile::debugSmoothedProfile(FlowGraph& cfg, StlVector<CFGNode*>& po) -{ - // Check with the profile without smoothing. - CFGNode *node; - CFGEdge *edge; - CFGEdgeDeque::const_iterator eiter; - StlVector<CFGNode*>::reverse_iterator niter; - uint32 nid, eid; - double diff, rel_diff; - double uerr = PROFILE_ERROR_ALLOWED; - double lerr = -PROFILE_ERROR_ALLOWED; - bool pass = true; - - - for(niter = po.rbegin(); niter != po.rend(); ++niter) { - node = *niter; - nid = node->getId(); - - diff = node->getFreq() - _blockInfo[nid].count; - rel_diff = node->getFreq() == 0.0 ? diff : diff / node->getFreq(); - if ( rel_diff > uerr || rel_diff < lerr) { - pass = false; - ::std::cerr << "??? N" << (unsigned int) nid << " : freq " << node->getFreq() - << " old_freq " << _blockInfo[nid].count << " diff " << diff - << " rel_diff " << rel_diff << ::std::endl; - } - - if (node->getFreq() == 0.0) - continue; - - const CFGEdgeDeque& oEdges = node->getOutEdges(); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - eid = edge->getId(); - diff = edge->getEdgeProb() - _edgeProb[eid]; - if ( diff > uerr || diff < lerr) { - pass = false; - ::std::cerr << "??? E" << (unsigned int) eid << "[" << (unsigned int) nid; - if (node->isDispatchNode()) - ::std::cerr << "D"; - ::std::cerr << " -> " << (unsigned int) edge->getTargetNode()->getId(); - if (edge->getTargetNode()->isDispatchNode()) - ::std::cerr << "D"; - ::std::cerr << "] : prob " << edge->getEdgeProb() << " old_prob " << _edgeProb[eid] - << " diff " << diff << ::std::endl; - } - } - } - if (!pass) - ::std::cerr << "??? [" << _methodStr << "] ========== profile validation FAILED" << ::std::endl; - return pass; -} // EdgeProfile::debugSmoothedProfile - - -// Return true if the profile is consistent. Otherwise, return false. -bool -EdgeProfile::printInconsistentProfile(FlowGraph& cfg) -{ - const CFGNodeDeque& nodes = cfg.getNodes(); - CFGEdgeDeque::const_iterator eiter; - CFGNodeDeque::const_iterator niter; - CFGNode *node, *srcNode; - CFGEdge *edge; - double f, diff; - bool consistent = true; - - ::std::cerr << "printInconsistentProfile [" << _methodStr << "]" << ::std::endl; - - for( niter = nodes.begin(); niter != nodes.end(); ++niter) { - node = *niter; - - // Check whether the sum of freq from incoming edges equal the node freq. - const CFGEdgeDeque& iEdges = node->getInEdges(); - if (iEdges.size() > 0) { - f = 0.0; - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - srcNode = edge->getSourceNode(); - f += srcNode->getFreq() * edge->getEdgeProb(); - } - - diff = (f == 0.0 ? node->getFreq() : (f - node->getFreq())/f); - if (diff > PROFILE_ERROR_ALLOWED || diff < -PROFILE_ERROR_ALLOWED) { - consistent = false; - unsigned int nid = node->getId(); - ::std::cerr << "==> N" << nid << " : Incoming freq (" << f - << ") != Node freq (" << node->getFreq() << ")" << ::std::endl; - ::std::cerr << "====> N" << nid << " : freq " << node->getFreq() - << "old_freq " << _blockInfo[nid].count << ::std::endl; - } - } - - - // Check whether the sum of outgoing edge probability is 1.0. - const CFGEdgeDeque& oEdges = node->getOutEdges(); - if (oEdges.size() > 0) { - f = 0.0; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - f += edge->getEdgeProb(); - } - - diff = (f > 1.0) ? (f - 1.0) : (1.0 - f); - if (diff > PROB_ERROR_ALLOWED) { - consistent = false; - unsigned int nid = node->getId(); - ::std::cerr << "==> N" << nid << " -- Outgoing prob (" << f - << ") != 1.0" << ::std::endl; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - ::std::cerr << "====> [E" << (unsigned int) edge->getId() << " N" << nid - << "->N" << (unsigned int) edge->getTargetNode()->getId() - << "] : " << "prob " << edge->getEdgeProb() - << " old_prob " << _edgeProb[edge->getId()] << ::std::endl; - } - } - } - } - return consistent; -} // EdgeProfile::printInconsistentProfile - - -void -EdgeProfile::generateInstrumentedProfile( - FlowGraph& flowGraph, - StlVector<CFGNode*>& poNodes, - bool warning_on) -{ - LoopTree *loopInfo = flowGraph.getIRManager()->getLoopTree(); - uint32 edgeCount = flowGraph.getMaxEdgeId(); -#ifdef _DEBUG - CFGNode* entryNode = flowGraph.getEntry(); -#endif - CFGNode* node; - uint32 i, n; - double srcNodeFreq, f, g; - CFGEdgeDeque::const_iterator eiter; - CFGEdge* edge; - StlVector<CFGNode*>::reverse_iterator niter; - - // Allocate and initialize the working copy of edge freq for profile - // processing. - double *edgeFreq = new(_mm) double[edgeCount]; - for (i = 0; i < edgeCount; i++) { - edgeFreq[i] = _edgeFreq[i]; - } - - // Set entry node frequency. - node = *poNodes.rbegin(); - assert(node == entryNode); - node->setFreq(_entryFreq); - - bool done = false; - while(!done) { - done = true; - for(niter = poNodes.rbegin(); niter != poNodes.rend(); ++niter) { - CFGNode* dstNode; - CFGNode* srcNode = *niter; - - // Compute the node execution freq. - const CFGEdgeDeque& iEdges = srcNode->getInEdges(); - if (iEdges.size() > 0) { - srcNodeFreq = 0.0; - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - srcNodeFreq += edgeFreq[edge->getId()]; - } - if(srcNodeFreq > srcNode->getFreq()) { - // Update with new edge information - done = false; - srcNode->setFreq(srcNodeFreq); - } else { - // Already computed for this node. - assert(srcNodeFreq == srcNode->getFreq()); - } - } else - srcNodeFreq = srcNode->getFreq(); - - // Compute the edge taken probability for each outgoing edge. - const CFGEdgeDeque& oEdges = srcNode->getOutEdges(); - if (oEdges.size() == 0) - continue; - - if (oEdges.size() == 1) { - edge = *(oEdges.begin()); - edgeFreq[edge->getId()] = srcNode->getFreq(); - edge->setEdgeProb(1.0); - continue; - } - - // We have more than one outgoing edges from srcNode. - if (srcNodeFreq == 0.0) { - g = 1.0 / ((double) oEdges.size()); - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - edge->setEdgeProb( g ); - } - continue; - } - - f = srcNodeFreq; - n = 0; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dstNode = edge->getTargetNode(); - if (dstNode->isBlockNode()) { - g = edgeFreq[edge->getId()]; - edge->setEdgeProb( g/srcNodeFreq ); - f -= g; - } else { - n++; // count edges that are not instrumented - edge->setEdgeProb(0.0); // reset edge prob to 0.0 - } - } - - if (f != 0.0) { - if ( n > 0 && f > 0.0 ) { - // Here is the freq for the edges that are not instrumented. - // Revisit the outgoing edges and fix up their probability. - g = f / ((double) n); // the freq for non-instrumented edges - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dstNode = edge->getTargetNode(); - if ( !dstNode->isBlockNode() ) { - edgeFreq[edge->getId()] = g; - edge->setEdgeProb( g/srcNodeFreq ); - } - } - } - } - } - } - - bool profile_inconsistent = !flowGraph.isProfileConsistent(_methodStr, false); - if (profile_inconsistent && profileCtrl.getDebugCtrl() > 0) { - // Derive edge profile from edge probability using profile smoothing. - setupEdgeProbFromInstrumentation(flowGraph, poNodes); - setupBlockInfo(flowGraph, poNodes); - setupLoopProfile((LoopNode *) loopInfo->getRoot(), edgeFreq); - deriveProfile(flowGraph, poNodes); - - if (profileCtrl.getDebugCtrl() != 0 - && flowGraph.isProfileConsistent(_methodStr, warning_on) == false) { - ::std::cerr << "!!!!!!! Profile INCONSISTENT after smoothing (generateInstrumentedProfile)" << ::std::endl; - printCFGDot(flowGraph, "smoothing error", "sma_err"); - debugSmoothedProfile(flowGraph, poNodes); - } - } -} // EdgeProfile::generateInstrumentedProfile - - -void -EdgeProfile::annotateCFGWithProfile(FlowGraph& flowGraph, bool online) -{ - bool warning_on = ((profileCtrl.getDebugCtrl() != 0) || !online); - StlVector<CFGNode*> poNodes(_mm); - flowGraph.getNodesPostOrder(poNodes); - - if ( !isProfileValidate(flowGraph, poNodes, warning_on) ) { - if (warning_on) - ::std::cerr << "WARNING! annotateCFGWithProfile: isProfileValidate returns FALSE on [" - << _methodStr << "]" << ::std::endl; - return; - } - - if (_profileType == InstrumentedEdge) { - generateInstrumentedProfile(flowGraph, poNodes, warning_on); - } else { - assert(0); - return; - } - flowGraph.setEdgeProfile(true); -} // EdgeProfile::annotateCFGWithProfile - - - -// Smooth the profile in the flowGraph by deriving the profile from the edge -// taken probability and the method entry frequency that already exist in -// the flowGraph. -void -EdgeProfile::smoothProfile(FlowGraph& flowGraph) -{ - bool warning_on = ((profileCtrl.getDebugCtrl() != 0)); - LoopTree *loopInfo = flowGraph.getIRManager()->getLoopTree(); - uint32 edgeCount = flowGraph.getMaxEdgeId(); - double *edgeFreq = new(_mm) double[edgeCount]; - - StlVector<CFGNode*> poNodes(_mm); - flowGraph.getNodesPostOrder(poNodes); - - setupEdgeProbFromCFG(flowGraph, poNodes); - setupBlockInfo(flowGraph, poNodes); - setupLoopProfile((LoopNode *) loopInfo->getRoot(), edgeFreq); - deriveProfile(flowGraph, poNodes); - - if (profileCtrl.getDebugCtrl() != 0 - && flowGraph.isProfileConsistent(_methodStr, warning_on) == false) { - ::std::cerr << "!!!!!!! Profile INCONSISTENT after smoothing (smoothProfile)" << ::std::endl; - printCFGDot(flowGraph, "smoothing profile error", "sm_prof_err"); - printInconsistentProfile(flowGraph); - } -} // EdgeProfile::smoothProfile - - -void -EdgeProfile::printCFG(FILE *file, FlowGraph& cfg, char *str) -{ - CFGEdgeDeque::const_iterator eiter; - CFGNodeDeque::const_iterator niter; - CFGNode *dstNode, *srcNode; - CFGEdge *edge; - - fprintf(file, "START CFG dump %s =========== %s\n", _methodStr, str); - - const CFGNodeDeque& nodes = cfg.getNodes(); - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - srcNode = *niter; - fprintf(file, "N%d (Freq: %f)\n", (int)srcNode->getId(), srcNode->getFreq()); - - const CFGEdgeDeque& oEdges = srcNode->getOutEdges(); - if (oEdges.size() > 0) { - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dstNode = edge->getTargetNode(); - fprintf(file, "To: N%d ( E%d %f [%f] )\n", (int)dstNode->getId(), - (int)edge->getId(), edge->getEdgeProb(), - (_edgeFreq != NULL ? _edgeFreq[edge->getId()] : -1.0)); - } - } - } - fprintf(file, "END CFG dump %s ===========\n", _methodStr); -} // EdgeProfile::printCFG - - -void -EdgeProfile::printCFGDot(FlowGraph& cfg, char *str, char *suffix, bool node_label) -{ - CFGEdgeDeque::const_iterator eiter; - CFGNodeDeque::const_iterator niter; - CFGNode *dstNode, *srcNode; - CFGEdge *edge; - char name[1024]; - uint32 i, j; - FILE *file; - - strcpy(name, "dotfiles/"); - for ( i = (uint32) strlen(name), j = 0; - _methodStr[j] != '(' && _methodStr[j] != '\0'; - i++, j++) { - if (_methodStr[j] == '/' || _methodStr[j] == '<' || _methodStr[j] == '>') - name[i] = '_'; - else if (_methodStr[j] == ':') - name[i] = '.'; - else - name[i] = _methodStr[j]; - } - name[i++] = '.'; - strcpy(&name[i], suffix); - i = (uint32) strlen(name); - strcpy(&name[i], ".dot"); - - file = fopen(name, "w"); - if (file == NULL) { - return; - } - - fprintf(file, "digraph dotgraph {\n"); - fprintf(file, "center=TRUE;\n"); - fprintf(file, "ranksep=\".25\";\n"); - fprintf(file, "nodesep=\".20\";\n"); - fprintf(file, "fontpath=\"c:\\winnt\\fonts\";\n"); - fprintf(file, "ratio=auto;\n"); - fprintf(file, "page=\"8.5,11\";\n"); - fprintf(file, "node [shape=record,fontname=\"Courier\",fontsize=11];\n"); - fprintf(file, "label=\"[%s] %s\"\n", _methodStr, str); - - const CFGNodeDeque& nodes = cfg.getNodes(); - - - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - srcNode = *niter; - const CFGEdgeDeque& oEdges = srcNode->getOutEdges(); - - if (node_label) { - // print node - if (srcNode->isDispatchNode()) { - fprintf(file, "N%u [shape=diamond,color=blue,label=\"N%u (%g)", - srcNode->getId(), srcNode->getId(), srcNode->getFreq()); - } else { - fprintf(file, "N%u [label=\"N%u (%g)", - srcNode->getId(), srcNode->getId(), srcNode->getFreq()); - } - - // add node label - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dstNode = edge->getTargetNode(); - fprintf(file, "\\nTo: N%u (%g) (src: %g)", dstNode->getId(), - edge->getEdgeProb(), - (_edgeFreq != NULL ? _edgeFreq[edge->getId()] : -1.0)); - } - fprintf(file, "\"];\n"); - } else { - if (srcNode->isDispatchNode()) { - fprintf(file, "N%u [shape=diamond,color=blue];\n", srcNode->getId()); - } - } - - // print graph edges - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - dstNode = edge->getTargetNode(); - fprintf(file, "N%d -> N%d", (int)srcNode->getId(), (int)dstNode->getId()); - if (dstNode->isDispatchNode()) - fprintf(file, " [style=dotted,color=blue]"); - fprintf(file, ";\n"); - } - } - fprintf(file, "}\n"); - fclose(file); -} // EdgeProfile::printCFGDot - - -// Parse the PROF command line parameters. -void -ProfileControl::init(const char *str) -{ - char *p, *lhs, *rhs; - unsigned lhs_len, rhs_len; - - // default configurations - // * bit 3: add instrumentation on exception branches - config = 0x8; - - // Parse the command line parameters for PROF. - - if (str == NULL) - return; - - p = (char *) (*str == '"' ? str + 1 : str); - while ( *p != '\0' && *p != '"' ) { - lhs = p; - rhs = NULL; - lhs_len = rhs_len = 0; - while (*p != '=' && *p != ',' && *p != '\0' && *p != '"') { - p++; - lhs_len++; - } - if (*p == '=') { - p++; - rhs = p; - while (*p != ',' && *p != '\0' && *p != '"') { - p++; - rhs_len++; - } - } - if (*p == ',') - p++; - - setProfileConfig(lhs, lhs_len, rhs, rhs_len); - } - if (debugCtrl) - fprintf(stderr, "iGen %u profUse %u config %lu debug %lu File %s\n", - instrumentGen, profUse, config, debugCtrl, profileFile); -} // ProfileControl::init - - -// Set profile configuration for one of the following options. -// 'file' -- generate into or use from the specified file -// 'config' -- configuration value -// 'debug' -- debug flag -// 'method' -- method name that specifies the only method to be instrumented -void -ProfileControl::setProfileConfig( - char *lhs, - unsigned lhs_len, - char *rhs, - unsigned rhs_len) -{ - char c, lhs_str[10], rhs_str[128]; - unsigned i, len; - unsigned long n; - - if (lhs_len == 0 || rhs_len == 0) - return; - - len = (lhs_len > 6) ? 9 : lhs_len; - for (i = 0; i < len; i++) - lhs_str[i] = lhs[i]; - lhs_str[i] = '\0'; - - if (lhs_len > 6) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - - switch (lhs_str[0]) { - case 'g': // gen - if (strcmp(lhs_str, "gen") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - - for (i = 0; i < rhs_len; i++) { - c = rhs[i]; - switch (c) { - case 'm': - instrumentGen |= 0x1; - break; - - case 'e': - instrumentGen |= 0x2; - break; - - - default: - fprintf(stderr, "Unsupported 'gen' option '%c' skipped!\n", c); - } - } - break; - - case 'u': // use - if (strcmp(lhs_str, "use") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - - for (i = 0; i < rhs_len; i++) { - c = rhs[i]; - switch (c) { - case 'm': - profUse |= 0x1; - break; - - case 'e': - profUse |= 0x2; - break; - - case 'p': - profUse |= 0x4; - break; - - default: - fprintf(stderr, "Unsupported 'use' option '%c' skipped!\n", c); - } - } - break; - - case 'f': // file - if (strcmp(lhs_str, "file") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - profileFile = (char *) malloc(rhs_len+1); - for (i = 0; i < rhs_len; i++) - profileFile[i] = rhs[i]; - profileFile[i] = '\0'; - break; - - case 'c': // config - if (strcmp(lhs_str, "config") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - - len = (rhs_len > 127) ? 127 : rhs_len; - for (i = 0; i < len; i++) - rhs_str[i] = rhs[i]; - rhs_str[i] = '\0'; - if ( rhs_len > 127 ) { - fprintf(stderr, "Unsupported 'config' option '%s' skipped!\n", - rhs_str); - return; - } - - n = strtoul(rhs_str, NULL, 0); - if (n == ULONG_MAX) { - fprintf(stderr, "Unsupported 'config' option '%s' skipped!\n", - rhs_str); - return; - } - config = n; - break; - - case 'd': // debug control - if (strcmp(lhs_str, "debug") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - - len = (rhs_len > 127) ? 127 : rhs_len; - for (i = 0; i < len; i++) - rhs_str[i] = rhs[i]; - rhs_str[i] = '\0'; - if ( rhs_len > 127 ) { - fprintf(stderr, "Unsupported 'debug' option '%s' skipped!\n", - rhs_str); - return; - } - - n = strtoul(rhs_str, NULL, 0); - if (n == ULONG_MAX) { - fprintf(stderr, "Unsupported 'debug' option '%s' skipped!\n", - rhs_str); - return; - } - debugCtrl = n; - break; - - case 'm': // method - if (strcmp(lhs_str, "method") != 0) { - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - return; - } - methodStr = (char *) malloc(rhs_len+1); - for (i = 0; i < rhs_len; i++) - methodStr[i] = rhs[i]; - methodStr[i] = '\0'; - break; - - default: - fprintf(stderr, "Unsupported option '%s' skipped!\n", lhs_str); - break; - } -} // ProfileControl::setProfileConfig - - -void -ProfileControl::deInit() -{ -} - - - -EdgeProfile* -ProfileControl::readProfileFromFile(MethodDesc& mdesc) { - char methodStr[MaxMethodStringLength]; - EdgeProfile *epf, *lastEpf; - - if ( useProfileFile() == false ) - return NULL; - - if (genMethodString(mdesc, methodStr, MaxMethodStringLength) == 0) - return NULL; // won't handle method whose name exceeds length limit - - if (profileCtrl.debugCFGCheckSum()) - fprintf(stderr, "<checkSum> %s\n", methodStr); - - if ( edgeProfiles == NULL ) { - // This is the first time we want to look up the profile from the - // profile file. - // Read in profile from a file and cache them in edgeProfiles - // (a list of EdgeProfile structures). - int res; - char mStr[MaxMethodStringLength]; - - FILE *profFile = fopen(profileFile, "r"); - if ( profFile == NULL ) { - fprintf(stderr, "Cannot open profile file: %s!!\n", - profileFile); - return NULL; - } - - res = fscanf(profFile, "%u", &counterSize); - if (res == EOF || res == 0) - return NULL; - assert(counterSize == 4 || counterSize == 8); - - MemoryManager& gmm = Jitrino::getGlobalMM(); - lastEpf = NULL; - while ( fscanf(profFile, "%s", mStr) != EOF ) { - epf = new(gmm) EdgeProfile(gmm, profFile, mStr, counterSize); - if (epf->getEntryFreq() <= 0.0) { - // no profile info for this method - } else if (edgeProfiles == NULL) { - edgeProfiles = lastEpf = epf; - } else { - lastEpf->setNext(epf); - lastEpf = epf; - } - } - fclose(profFile); - } - - // Now look up the edge profile list for the given method. - epf = NULL; - if (lastEPPtr != NULL) { - epf = lastEPPtr->next(); - } - - if (epf && strcmp(methodStr, epf->getMethodStr()) == 0) - return epf; - - for (epf = edgeProfiles; epf; epf = epf->next()) - if (strcmp(methodStr, epf->getMethodStr()) == 0) - return epf; - return NULL; -} // ProfileControl::readProfileFromFile - - - - -// Write the current profile data collected for each method into the file -// specified in the profileControl. -void -CodeProfiler::writeProfile( - FILE *file, - const char *className, - const char *methodName, - const char *methodSig) -{ - fprintf(file, "%s::%s%s\n", className, methodName, methodSig); - fprintf(file, "%u\n", checkSum); - fprintf(file, "%u\n", numCounter); - if (counterSize == 4) { - uint32 *counters4B = (uint32 *) counterArrayBase; - for (uint32 i = 0; i < numCounter; i++) - fprintf(file, "%u\n", counters4B[i]); - } else if (counterSize == 8) { - uint64 *counters8B = (uint64 *) counterArrayBase; - for (uint32 i = 0; i < numCounter; i++) - fprintf(file, "%"SPRINTF_I64"u\n", counters8B[i]); - } else - assert(0); - fflush(file); -} // CodeProfiler::writeProfile - - - -void -CodeProfiler::getOfflineProfile(IRManager& irm) -{ - unsigned useProfFlags = profileCtrl.useProf(); - - if ( useProfFlags & 0x2 ) { // use edge profile - MethodDesc& mdesc = irm.getMethodDesc(); - EdgeProfile* edgeProfile = profileCtrl.readProfileFromFile(mdesc); - if ( edgeProfile ) - edgeProfile->annotateCFGWithProfile(irm.getFlowGraph(), false); - } -} // CodeProfiler::getOfflineProfile - - - -void -CodeProfiler::getOnlineProfile(IRManager& irm) -{ - FlowGraph& flowGraph = irm.getFlowGraph(); - - // The memory manager for buffers in the EdgeProfile. - MemoryManager mm(flowGraph.getMaxEdgeId() * counterSize * 16, - "CodeProfiler::getOnlineProfile"); - - // Create the edge profile structure for the compiled method in 'irm'. - EdgeProfile edgeProfile(mm, irm.getMethodDesc(), false); - - // Annotate the CFG with edge profile. - edgeProfile.annotateCFGWithProfile(flowGraph, true); -} // CodeProfiler::getOnlineProfile -} diff --git vm/jitrino/src/dynopt/Profiler.h vm/jitrino/src/dynopt/Profiler.h deleted file mode 100644 index f44cbb4..0000000 --- vm/jitrino/src/dynopt/Profiler.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.15.24.5 $ - * - */ - - -#include <stdlib.h> -#include "irmanager.h" -#include "VMInterface.h" -#include "FlowGraph.h" -#include "Loop.h" - - -#define MaxMethodStringLength 2048 -#define PROFILE_ERROR_ALLOWED 0.001 -#define PROB_ERROR_ALLOWED 0.00001 - -namespace Jitrino - { - -// -// Utility functions -// -extern uint32 genMethodString(MethodDesc& mdesc, char *buf, uint32 n); - -// -// EdgeProfile -- structure for holding edge profile information for a method. -// -// - -class LoopProfile { -public: - LoopProfile(MemoryManager& mm, LoopNode *loop); - - void addMember(CFGNode *node); - void allocExitProbArray() { _exit_prob = new(_mm) double[_exits.size()]; } - void dump(FILE *file); - - MemoryManager& _mm; - StlVector<uint32> _members; // members of the loop (block id) in PostOrder - StlVector<CFGEdge*> _exits; // loop exit edges - LoopNode *_loop; // pointer to the loop node - CFGNode *_entry; // the loop entry (or header) block - CFGEdge *_back_edge; // loop back edge - double *_exit_prob; // loop exit edge probability - double _iter_count; // estimated loop iteration count -}; - -struct BlockProfile { - double count; - CFGNode *block; - LoopProfile *loop; // pointer to LoopProfile if this is a loop header -}; // class LoopProfile - -class EdgeProfile { -public: - EdgeProfile(MemoryManager& mm, FILE *file, char *str, uint32 counterSize); - EdgeProfile(MemoryManager& mm, MethodDesc& mdesc, bool smoothing = false); - ~EdgeProfile() { - } - - const char* getMethodStr() { return _methodStr; } - uint32 getCheckSum() { return _checkSum; } - uint32 getNumEdges() { return _numEdges; } - double getEntryFreq() { return _entryFreq; } - double getEdgeFreq(uint32 i) { return _edgeFreq[i]; } - EdgeProfile* next() { return _next; } - void setNext(EdgeProfile* n) { _next = n; } - - void annotateCFGWithProfile(FlowGraph& flowGraph, bool online); - void smoothProfile(FlowGraph& flowGraph); - -private: - enum EdgeProfileType { - NoProfile, - InstrumentedEdge, - - }; - - bool isProfileValidate(FlowGraph& flowGraph, StlVector<CFGNode*>& po, - bool warning_on); - void generateInstrumentedProfile(FlowGraph& flowGraph, StlVector<CFGNode*>& po, - bool warning_on); - - void setupEdgeProbFromInstrumentation(FlowGraph& cfg, StlVector<CFGNode*>& po); - - - void setupEdgeProbFromCFG(FlowGraph& cfg, StlVector<CFGNode*>& po); - - - void setupBlockInfo(FlowGraph& cfg, StlVector<CFGNode*>& po); - void setupLoopProfile(LoopNode *loopNode, double *work); - - void computeLoopIterCountExitProb(LoopProfile *loop_profile, double *edge_prob); - void deriveProfile(FlowGraph& flowGraph, StlVector<CFGNode*>& po); - void setProfile(FlowGraph& flowGraph, StlVector<CFGNode*>& po); - - bool debugSmoothedProfile(FlowGraph& flowGraph, StlVector<CFGNode*>& po); - bool printInconsistentProfile(FlowGraph& flowGraph); - void printCFG(FILE *file, FlowGraph& cfg, char *str); - void printCFGDot(FlowGraph& cfg, char *str, char *suffix, bool node_label=true); - - MemoryManager& _mm; - MethodDesc* _method; // NULL if the EdgeProfile is built from a file - EdgeProfileType _profileType; - bool _hasCheckSum; - char* _methodStr; - uint32 _checkSum; - uint32 _numEdges; - double _entryFreq; - double* _edgeFreq; - EdgeProfile* _next; - - // work areas - BlockProfile *_blockInfo; - double *_edgeProb; -}; // class EdgeProfile - - -// -// Profile configuration and control. -// - -class ProfileControl { -public: - ProfileControl() : config(0), instrumentGen(0), profUse(0), - profileFile(NULL), methodStr(NULL), - edgeProfiles(NULL), lastEPPtr(NULL) - { - counterSize = 4; - } - - ~ProfileControl() { - - if (profileFile) - free(profileFile); - - } - - void init(const char *str); - void deInit(); - - uint32 getCounterSize() { return counterSize; } - unsigned getInstrumentGen() { return instrumentGen; } - unsigned getInstrumentGen(MethodDesc& mdesc) { - if ( instrumentSpecifiedMethod() ) { - char str[MaxMethodStringLength]; - const char* methodName = mdesc.getName(); - const char* className = mdesc.getParentType()->getName(); - sprintf(str, "%s::%s", className, methodName); - if ( strcmp(methodStr, str) ) - return 0; - } - return instrumentGen; - } - unsigned useProf() { return profUse; } - - bool doMethodInstrument() { return ((instrumentGen & 1) != 0); } - bool doEdgeInstrument() { return ((instrumentGen & 2) != 0); } - bool useProfileFile() { return (profileFile != NULL); } - char* getProfileFileName() { return profileFile; } - - bool printNameToFile() { return ((config & (1 << 1)) != 0); } - bool instrumentSpecifiedMethod() { return ((config & (1 << 2)) != 0); } - bool instrumentForDispatchFreq() { return ((config & (1 << 3)) != 0); } - bool debugCFGCheckSum() { return ((config & (1 << 4)) != 0); } - bool useOptimizedCG() { return ((config & (1 << 5)) != 0); } - bool matchSpecifiedMethod(char *name) { - return (methodStr != NULL && (strstr(name, methodStr) != NULL)); - } - - unsigned long getDebugCtrl() { return debugCtrl; } - - EdgeProfile* readProfileFromFile(MethodDesc& mdesc); - -private: - void setProfileConfig(char *lhs, unsigned lhs_len, char *rhs, - unsigned rhs_len); - - // - // config -- configuration flags - // bit 0: synchronized instrumentation - // bit 1: print instrumented method name to file - // bit 2: only instrument for method specified in 'method=' - // bit 3: instrument to count dispatch edge frequency - // - // bit 4: debug CFG checkSum - // bit 5: use CG optimize path for 1st compilation - unsigned long config; - - // debug -- debug control flags - // bit 0: dump debug info - unsigned long debugCtrl; - - // instrumentGen: 0 -- no edge instrumentation - // 1 -- instrument for method invocation count - // 2 -- instrument for edge profile - // 3 -- instrument for both method and edge profile - unsigned instrumentGen; - - - - // profUse: 0 -- no profile feedback, - // 1 -- use instrumentation-based method profile - // 2 -- use instrumentation-based edge profile - // 3 -- use instrumentation-based method and edge profile - - unsigned profUse; - - // profileFile: NULL -- no profile file; non-NULL -- string pointer to the - // file name for the profile file. - char *profileFile; - - // method: only instrument the specified method if config[2] is set. - char *methodStr; - - // a linked list of edge profiles, one for each method - EdgeProfile *edgeProfiles; - - // Pointer to the last visited edge profile entry in edgeProfiles - EdgeProfile *lastEPPtr; - - // size of counter in byte - uint32 counterSize; -}; // class ProfileControl - -extern ProfileControl profileCtrl; - - -// -// Code Profiler -// - -class CodeProfiler { -public: - CodeProfiler() : numCounter(0), checkSum(0), counterArrayBase(NULL) { - counterSize = profileCtrl.getCounterSize(); - } - - void writeProfile(FILE *file, const char *className, const char *methodName, const char *methodSig); - - void getOfflineProfile(IRManager& irm); - void getOnlineProfile(IRManager& irm); - void *getCounterBaseAddr() { return counterArrayBase; } - void *getCounterAddr(uint32 n) { - if (counterSize == 4) - return (void *) &(((uint32 *) counterArrayBase)[n]); - else - return (void *) &(((uint64 *) counterArrayBase)[n]); - } - uint32 getCounterSize() { return counterSize; } - -private: - uint32 numCounter; - uint32 counterSize; // in Bytes - uint32 checkSum; - void *counterArrayBase; -}; // class CodeProfiler -} diff --git vm/jitrino/src/dynopt/StaticProfiler.cpp vm/jitrino/src/dynopt/StaticProfiler.cpp index 820a555..ecbc74e 100644 --- vm/jitrino/src/dynopt/StaticProfiler.cpp +++ vm/jitrino/src/dynopt/StaticProfiler.cpp @@ -21,42 +21,30 @@ */ #include "StaticProfiler.h" -#include "FlowGraph.h" +#include "ControlFlowGraph.h" #include "Dominator.h" #include "Loop.h" #include "constantfolder.h" - - -#ifdef OLD_FREQ_ALG -#include "Profiler.h" -#endif - +#include "mkernel.h" +#include "Stl.h" +#include "FlowGraph.h" /** see article: "Static Branch Frequency and Program Profile Analysis / Wu, Laurus, IEEE/ACM 1994" */ namespace Jitrino{ -DEFINE_OPTPASS_IMPL(StaticProfilerPass, statprof, "Static Profiler") +DEFINE_SESSION_ACTION(StaticProfilerPass, statprof, "Perform edge annotation pass based on static heuristics"); +class StaticProfilerContext; -struct StaticProfilerContext { - FlowGraph* fg; - CFGNode* node; - CFGEdge* edge1; //trueEdge - CFGEdge* edge2; //falseEdge - DominatorTree* domTree; - DominatorTree* postDomTree; - LoopTree* loopTree; -}; #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define ABS(a) (((a) > (0)) ? (a) : -(a)) //probabilities of taken branch +#define PROB_ALL_EXCEPTIONS 0.0000001 #define PROB_HEURISTIC_FAIL 0.50 -#define PROB_ALL_EXCEPTIONS 0.001 -#define PROB_UNCONDITIONAL (1 - PROB_ALL_EXCEPTIONS) -#define PROB_BACKEDGE 0.88 +#define PROB_LOOP_EXIT 0.10 #define PROB_OPCODE_HEURISTIC 0.84 #define PROB_CALL_HEURISTIC 0.78 #define PROB_LOOP_HEADER_HEURISTIC 0.75 @@ -70,9 +58,9 @@ #define ACCEPTABLE_DOUBLE_PRECISION_LOSS #define DEFAULT_ENTRY_NODE_FREQUENCY 10000 /** returns edge1 probability - Explicit parameters used here help to avoid code duplication in impl functions +Explicit parameters used here help to avoid code duplication in impl functions */ -typedef double(*HeuristicFn) (const StaticProfilerContext*); +typedef double(*HeuristicsFn) (const StaticProfilerContext*); static double callHeuristic(const StaticProfilerContext*); static double returnHeuristic(const StaticProfilerContext*); @@ -81,43 +69,130 @@ static double opcodeHeuristic(const Stat static double storeHeuristic(const StaticProfilerContext*); static double referenceHeuristic(const StaticProfilerContext*); static double devirtGuardHeuristic(const StaticProfilerContext*); +static void setHeatThreshold(IRManager& irm); +typedef std::vector<std::string> StringList; +static void splitString(const char* string, StringList& result, char separator, bool notEmptyTokensOnly); -static HeuristicFn heuristics[] = { - loopHeaderHeuristic, - callHeuristic, - returnHeuristic, - opcodeHeuristic, - storeHeuristic, - referenceHeuristic, - devirtGuardHeuristic, - NULL +struct Heuristics { + std::string name; + HeuristicsFn fn; + + Heuristics(const std::string& _name, HeuristicsFn _fn) : name(_name), fn(_fn){} + Heuristics(){name="", fn=NULL;} }; -static void estimateNode(StaticProfilerContext* c); -static void countFrequenciesFromProbs(FlowGraph* fg, LoopTree* lt); +Heuristics HEURISTICS[] = { + Heuristics("loop", loopHeaderHeuristic), + Heuristics("call", callHeuristic), + Heuristics("ret", returnHeuristic), + Heuristics("opcode", opcodeHeuristic), + Heuristics("store", storeHeuristic), + Heuristics("ref", referenceHeuristic), + Heuristics("guard", devirtGuardHeuristic), + Heuristics("", NULL) +}; -static inline CFGNode* findLoopHeader(LoopTree* lt, CFGNode* node, bool outerLoop = false) { - CFGNode* header = NULL; - if (!outerLoop && lt->isLoopHeader(node)) { - header = node; - } else if (lt->hasContainingLoopHeader(node)) { - header = lt->getContainingLoopHeader(node); +static Heuristics* findHeuristicsByName(const std::string& name) { + for (int i=0;;i++) { + Heuristics* h = &HEURISTICS[i]; + if (h->name == name) { + return h; + } + if (h->name.empty()) { + break; + } } - return header; + return NULL; } +class StaticProfilerContext { +public: + IRManager& irm; + ControlFlowGraph* fg; + Node* node; + Edge* edge1; //trueEdge + Edge* edge2; //falseEdge + DominatorTree* domTree; + DominatorTree* postDomTree; + LoopTree* loopTree; + StlVector<Heuristics*> heuristics; + bool doLoopHeuristicsOverride; + + StaticProfilerContext(IRManager& _irm) + : irm(_irm), fg (&_irm.getFlowGraph()), node(NULL), edge1(NULL), edge2(NULL), + domTree(NULL), postDomTree(NULL), loopTree(NULL), + heuristics(_irm.getMemoryManager()), doLoopHeuristicsOverride(true) + { + initDefaultHeuristics(); + + OptPass::computeDominatorsAndLoops(irm, false); + + loopTree = irm.getLoopTree(); + domTree = irm.getDominatorTree(); + postDomTree = DominatorBuilder().computePostdominators(irm.getNestedMemoryManager(), fg, true); + fillActiveHeuristicsList(); + } + +private: + void fillActiveHeuristicsList() { + const OptimizerFlags& optFlags = irm.getOptimizerFlags(); + doLoopHeuristicsOverride = optFlags.statprof_do_loop_heuristics_override; + const char* heuristicsNamesList = optFlags.statprof_heuristics; + if (heuristicsNamesList == NULL) { + heuristics.resize(defaultHeuristics.size()); + std::copy(defaultHeuristics.begin(), defaultHeuristics.end(), heuristics.begin()); + } else { + getHeuristicsByNamesList(heuristicsNamesList, heuristics); + } + + } + + static void initDefaultHeuristics() { + static Mutex initMutex; + static bool defaultHeuristicsInited = false; + if (!defaultHeuristicsInited) { + initMutex.lock(); + if (!defaultHeuristicsInited) { + getHeuristicsByNamesList("loop,ret,guard", defaultHeuristics); + } + initMutex.unlock(); + } + } + + template <class Container> + static void getHeuristicsByNamesList(const char* list, Container result) { + StringList nameList; + splitString(list, nameList, ',', true); + for (StringList::const_iterator it = nameList.begin(), end = nameList.end(); it!=end; ++it) { + const std::string& name = *it; + Heuristics* h = findHeuristicsByName(name); + assert(h!=NULL); + result.push_back(h); + } + } + +private: + static std::vector<Heuristics*> defaultHeuristics; + +}; + +std::vector<Heuristics*> StaticProfilerContext::defaultHeuristics; + + +static void estimateNode(StaticProfilerContext* c); + /** looks for unconditional path to inner loop header. */ -static bool hasUncondPathToInnerLoopHeader(CFGNode* parentLoopHeader, LoopTree* loopTree, CFGEdge* edge) { - CFGNode* node = edge->getTargetNode(); - if (!node->isBasicBlock() || node == parentLoopHeader) { +static bool hasUncondPathToInnerLoopHeader(Node* parentLoopHeader, LoopTree* loopTree, Edge* edge) { + Node* node = edge->getTargetNode(); + if (!node->isBlockNode() || node == parentLoopHeader) { return false; } if (loopTree->isLoopHeader(node)) { return true; } - CFGEdge* uncondEdge = (CFGEdge*)node->getUnconditionalEdge(); + Edge* uncondEdge = node->getUnconditionalEdge(); if (uncondEdge==NULL) { return false; } @@ -129,17 +204,17 @@ static bool hasUncondPathToInnerLoopHead * 2) if lookForDirectPath == TRUE returns isBackedge(edge->targetNode->targetUncondOutEdge ) * if targetUncondOutEdge is the only unconditional edge of targetNode */ -static inline bool isBackedge(LoopTree* loopTree, CFGEdge* e, bool lookForDirectPath) { - CFGNode* loopHeader = findLoopHeader(loopTree, e->getSourceNode()); +static inline bool isBackedge(LoopTree* loopTree, Edge* e, bool lookForDirectPath) { + Node* loopHeader = loopTree->getLoopHeader(e->getSourceNode(), false); if (loopHeader == NULL) { return false; } - CFGNode* targetNode = e->getTargetNode(); + Node* targetNode = e->getTargetNode(); if (targetNode == loopHeader) { return true; } if (lookForDirectPath) { - CFGEdge* targetUncondOutEdge = (CFGEdge*)targetNode->getUnconditionalEdge(); + Edge* targetUncondOutEdge = targetNode->getUnconditionalEdge(); if (targetUncondOutEdge !=NULL) { return isBackedge(loopTree, targetUncondOutEdge, lookForDirectPath); } @@ -147,58 +222,105 @@ static inline bool isBackedge(LoopTree* return false; } -static bool isLoopExit(LoopTree* loopTree, CFGEdge* e) { - CFGNode* loopHeader = findLoopHeader(loopTree, e->getSourceNode()); - return loopHeader!= NULL && !loopTree->loopContains(loopHeader ,e->getTargetNode()); -} - static bool isLoopHeuristicAcceptable(StaticProfilerContext* c) { - bool edge1IsLoopExit = isLoopExit(c->loopTree, c->edge1); - bool edge2IsLoopExit = isLoopExit(c->loopTree, c->edge2); + bool edge1IsLoopExit = c->loopTree->isLoopExit(c->edge1); + bool edge2IsLoopExit = c->loopTree->isLoopExit(c->edge2); assert (!(edge1IsLoopExit && edge2IsLoopExit)); //both edges could not be loop exits at the same time return edge1IsLoopExit || edge2IsLoopExit; } +void StaticProfiler::estimateGraph( IRManager& irm, double entryFreq, bool cleanOldEstimations) { + assert(entryFreq >= 0); + if (entryFreq == 0) { + entryFreq = DEFAULT_ENTRY_NODE_FREQUENCY; + } + if (irm.getFlowGraph().hasEdgeProfile() && !cleanOldEstimations) { + fixEdgeProbs(irm); + } else { + StaticProfilerContext c(irm); + const Nodes& nodes = c.fg->getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + c.node = node; + c.edge1 = NULL; + c.edge2 = NULL; + estimateNode(&c); + } + c.fg->getEntryNode()->setExecCount(entryFreq); + c.fg->setEdgeProfile(true); + } + irm.getFlowGraph().smoothEdgeProfile(); + + if (irm.getHeatThreshold()<=0) { + setHeatThreshold(irm); + } +} + +static void setHeatThreshold(IRManager& irm) { + const OptimizerFlags& optimizerFlags = irm.getOptimizerFlags(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); + double profile_threshold = optimizerFlags.profile_threshold; + if(optimizerFlags.use_average_threshold) { + // Keep a running average of method counts. + static uint32 count = 0; + static double total = 0.0; + count++; + double methodFreq = flowGraph.getEntryNode()->getExecCount(); + assert(methodFreq > 0); + total += methodFreq; + irm.setHeatThreshold(total / count); + } else if(optimizerFlags.use_minimum_threshold) { + double methodFreq = flowGraph.getEntryNode()->getExecCount(); + if(methodFreq < profile_threshold) { + methodFreq = profile_threshold; + } + irm.setHeatThreshold(methodFreq); + } else if(optimizerFlags.use_fixed_threshold) { + irm.setHeatThreshold(profile_threshold); + } else { + // Use the method entry + irm.setHeatThreshold(flowGraph.getEntryNode()->getExecCount()); + } + if (Log::isEnabled()) { + Log::out() << "Heat threshold = " << irm.getHeatThreshold() << std::endl; + } +} + + void StaticProfilerPass::_run(IRManager& irm) { - computeDominatorsAndLoops(irm); - - StaticProfilerContext c; - c.fg = &irm.getFlowGraph(); - c.loopTree = irm.getLoopTree(); - c.domTree = irm.getDominatorTree(); - c.postDomTree = DominatorBuilder().computePostdominators(irm.getNestedMemoryManager(), c.fg); - - const CFGNodeDeque& nodes = c.fg->getNodes(); - for (CFGNodeDeque::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - CFGNode* node = *it; - c.node = node; - c.edge1 = NULL; - c.edge2 = NULL; - estimateNode(&c); - } - countFrequenciesFromProbs(c.fg, c.loopTree); - c.fg->setEdgeProfile(true); + OptPass::computeDominatorsAndLoops(irm, false); + StaticProfiler::estimateGraph(irm, DEFAULT_ENTRY_NODE_FREQUENCY); } -void estimateNode(StaticProfilerContext* c) { - const CFGEdgeDeque& edges = c->node->getOutEdges(); +static void estimateNode(StaticProfilerContext* c) { + const Edges& edges = c->node->getOutEdges(); if (edges.empty()) { return; } else if (edges.size() == 1) { (*edges.begin())->setEdgeProb(1.0); return; + } else { + for (Edges::const_iterator it = edges.begin(), itEnd = edges.end(); it!=itEnd; it++) { + Edge* e = *it; + e->setEdgeProb(0.0); + } } - CFGEdge* falseEdge = (CFGEdge*)c->node->getFalseEdge(); - CFGEdge* trueEdge = (CFGEdge*)c->node->getTrueEdge(); + Edge* falseEdge = c->node->getFalseEdge(); + Edge* trueEdge = c->node->getTrueEdge(); double probLeft = 1.0; uint32 edgesLeft = edges.size(); if (falseEdge == NULL || trueEdge == NULL) { // can't apply general heuristics. - CFGEdge* uncondEdge = (CFGEdge*)c->node->getUnconditionalEdge(); + Edge* uncondEdge = c->node->getUnconditionalEdge(); if (uncondEdge) { - uncondEdge->setEdgeProb(PROB_UNCONDITIONAL); - probLeft-=PROB_UNCONDITIONAL; + uncondEdge->setEdgeProb(1 - PROB_ALL_EXCEPTIONS); + probLeft-=uncondEdge->getEdgeProb(); edgesLeft--; } + } else if (((Inst*)c->node->getLastInst())->isSwitch()) { + assert(c->node->getExceptionEdge() == 0); + falseEdge->setEdgeProb(0.5); + probLeft = 0.5; + edgesLeft--; } else { assert(falseEdge->getTargetNode()!=trueEdge->getTargetNode()); @@ -207,18 +329,19 @@ void estimateNode(StaticProfilerContext* // separate back-edge heuristic from others heuristics (the way it's done in article) c->edge1 = trueEdge; c->edge2 = falseEdge; - if (isLoopHeuristicAcceptable(c)) { - prob = isLoopExit(c->loopTree, trueEdge) ? 1 - PROB_BACKEDGE : PROB_BACKEDGE; + if (c->doLoopHeuristicsOverride && isLoopHeuristicAcceptable(c)) { + prob = c->loopTree->isLoopExit(trueEdge) ? PROB_LOOP_EXIT : 1 - PROB_LOOP_EXIT; } else { // from this point we can apply general heuristics - for (HeuristicFn* fn = heuristics; *fn!=NULL; fn++) { + for (StlVector<Heuristics*>::const_iterator it = c->heuristics.begin(), end = c->heuristics.end(); it!=end; ++it) { + Heuristics* h = *it; + HeuristicsFn fn = h->fn; double dprob = (*fn)(c); if (dprob!=PROB_HEURISTIC_FAIL) { prob = prob * dprob / (prob*dprob + (1-prob)*(1-dprob)); } } } - // all other edges (exception, catch..) have lower probability double othersProb = edges.size() == 2 ? 0.0 : PROB_ALL_EXCEPTIONS; trueEdge->setEdgeProb(MAX(PROB_ALL_EXCEPTIONS, prob - othersProb/2)); @@ -229,8 +352,8 @@ void estimateNode(StaticProfilerContext* if (edgesLeft != 0) { double probPerEdge = probLeft / edgesLeft; - for (CFGEdgeDeque::const_iterator it = edges.begin(), itEnd = edges.end(); it!=itEnd; it++) { - CFGEdge* e = *it; + for (Edges::const_iterator it = edges.begin(), itEnd = edges.end(); it!=itEnd; it++) { + Edge* e = *it; if (e->getEdgeProb()==0.0) { e->setEdgeProb(probPerEdge); } @@ -239,8 +362,8 @@ void estimateNode(StaticProfilerContext* #ifdef _DEBUG //debug check double probe = 0; - for (CFGEdgeDeque::const_iterator it = edges.begin(), itEnd = edges.end(); it!=itEnd; it++) { - CFGEdge* e = *it; + for (Edges::const_iterator it = edges.begin(), itEnd = edges.end(); it!=itEnd; it++) { + Edge* e = *it; double dprob = e->getEdgeProb(); assert (dprob!=0.0); probe+=dprob; @@ -253,25 +376,22 @@ #endif /** looks for Inst with opcode in specified range (both bounds are included) * in specified node and it's unconditional successors. */ -static inline Inst* findInst(CFGNode* node, Opcode opcodeFrom, Opcode opcodeTo) { - for (Inst *i = node->getFirstInst(), *last = node->getLastInst(); ; i = i->next()) { +static inline Inst* findInst(Node* node, Opcode opcodeFrom, Opcode opcodeTo) { + for (Inst *i = (Inst*)node->getFirstInst(); i!=NULL ; i = i->getNextInst()) { Opcode opcode = i->getOpcode(); if (opcode>=opcodeFrom && opcode<=opcodeTo) { return i; } - if (i == last) { - break; - } } - CFGEdge* uncondEdge = (CFGEdge*)node->getUnconditionalEdge(); + Edge* uncondEdge = node->getUnconditionalEdge(); if (uncondEdge!=NULL && uncondEdge->getTargetNode()->getInEdges().size() == 1) { return findInst(uncondEdge->getTargetNode(), opcodeFrom, opcodeTo); } return NULL; } -static inline Inst* findInst(CFGNode* node, Opcode opcode) { +static inline Inst* findInst(Node* node, Opcode opcode) { return findInst(node, opcode, opcode); } @@ -281,8 +401,8 @@ static inline Inst* findInst(CFGNode* no * a call and does not post-dominate will not be taken. */ static double callHeuristic(const StaticProfilerContext* c) { - CFGNode* node1 = c->edge1->getTargetNode(); - CFGNode* node2 = c->edge2->getTargetNode(); + Node* node1 = c->edge1->getTargetNode(); + Node* node2 = c->edge2->getTargetNode(); bool node1HasCall = findInst(node1, Op_DirectCall, Op_IntrinsicCall)!=NULL; bool node2HasCall = findInst(node2, Op_DirectCall, Op_IntrinsicCall)!=NULL; @@ -332,7 +452,7 @@ static double returnHeuristic(const Stat * and does not post-dominate will be taken */ static double loopHeaderHeuristic(const StaticProfilerContext* c) { - CFGNode* parentLoopHeader = findLoopHeader(c->loopTree, c->node, true); + Node* parentLoopHeader = c->loopTree->getLoopHeader(c->node, true); bool edge1Accepted = hasUncondPathToInnerLoopHeader(parentLoopHeader, c->loopTree, c->edge1) && !c->postDomTree->dominates(c->edge1->getTargetNode(), c->node); @@ -352,7 +472,7 @@ static double loopHeaderHeuristic(const * less than or equal to zero or equal to a constant, will fail. */ static double opcodeHeuristic(const StaticProfilerContext* c) { - Inst* inst = c->node->getLastInst(); + Inst* inst = (Inst*)c->node->getLastInst(); if (!(inst->getOpcode() == Op_Branch && inst->getSrc(0)->getType()->isInteger())) { return PROB_HEURISTIC_FAIL; } @@ -432,8 +552,8 @@ #endif * and does not post dominate will not be taken */ static double storeHeuristic(const StaticProfilerContext* c) { - CFGNode* node1 = c->edge1->getTargetNode(); - CFGNode* node2 = c->edge2->getTargetNode(); + Node* node1 = c->edge1->getTargetNode(); + Node* node2 = c->edge2->getTargetNode(); bool node1Accepted = findInst(node1, Op_TauStInd)!=NULL; bool node2Accepted = findInst(node2, Op_TauStInd)!=NULL; if (!node1Accepted && !node2Accepted) { @@ -454,7 +574,7 @@ static double storeHeuristic(const Stati * against null or two references will fail */ static double referenceHeuristic(const StaticProfilerContext *c) { - Inst* inst = c->node->getLastInst(); + Inst* inst = (Inst*)c->node->getLastInst(); if (inst->getOpcode() != Op_Branch || !inst->getSrc(0)->getType()->isObject()) { return PROB_HEURISTIC_FAIL; } @@ -475,7 +595,7 @@ static double referenceHeuristic(const S * Predict that comparison of VTablePtr will succeed */ static double devirtGuardHeuristic(const StaticProfilerContext *c) { - Inst* inst = c->node->getLastInst(); + Inst* inst = (Inst*)c->node->getLastInst(); if (inst->getOpcode() != Op_Branch || !inst->getSrc(0)->getType()->isVTablePtr()) { return PROB_HEURISTIC_FAIL; } @@ -485,179 +605,90 @@ static double devirtGuardHeuristic(const } +void StaticProfiler::fixEdgeProbs(IRManager& irm) { + assert(irm.getFlowGraph().hasEdgeProfile()); -/************************************************************************/ -/************************************************************************/ -/* FREQUENCY CALCULATION */ -/************************************************************************/ -/************************************************************************/ - -class CountFreqsContext { -public: - FlowGraph* fg; - MemoryManager& mm; - LoopTree* loopTree; - bool useCyclicFreqs; - double* cyclicFreqs; - bool* visitInfo; - StlVector<CFGEdge*> exitEdges; - - CountFreqsContext(MemoryManager& _mm, FlowGraph* _fg, LoopTree* _lt) : - fg(_fg), mm(_mm), loopTree(_lt), useCyclicFreqs(false), exitEdges(mm) - { - uint32 n = fg->getMaxNodeId(); - cyclicFreqs = new (mm) double[n]; - visitInfo = new (mm) bool[n]; - for (uint32 i=0; i< n; i++) { - cyclicFreqs[i]=1; - } - } - - inline void resetVisitInfo() { - memset(visitInfo, false, fg->getMaxNodeId()); - } -}; + double minProb = PROB_ALL_EXCEPTIONS; -static void checkFrequencies(FlowGraph* fg); -static void countLinearFrequency(const CountFreqsContext* c, CFGNode* node); -static void estimateCyclicFrequencies(CountFreqsContext* c, LoopNode* loopHead); -static void findLoopExits(CountFreqsContext* c, LoopNode* loopHead); - -void countFrequenciesFromProbs(FlowGraph* fg, LoopTree* lt) { - MemoryManager& mm = fg->getIRManager()->getMemoryManager(); -#ifdef OLD_FREQ_ALG - fg->getEntry()->setFreq(DEFAULT_ENTRY_NODE_FREQUENCY); - EdgeProfile p(mm, fg->getIRManager()->getMethodDesc(), true); - p.smoothProfile(*fg); -#else - CountFreqsContext c(mm, fg, lt); - c.resetVisitInfo(); - countLinearFrequency(&c, fg->getEntry()); - LoopNode* topLevelLoop = (LoopNode*)lt->getRoot(); - if (topLevelLoop != NULL && topLevelLoop->getChild()!=NULL) { //if there are loops in method - c.useCyclicFreqs = true; - for (LoopNode* loopHead = topLevelLoop->getChild(); loopHead!=NULL; loopHead = loopHead->getSiblings()) { - estimateCyclicFrequencies(&c, loopHead); - } - c.resetVisitInfo(); - countLinearFrequency(&c, fg->getEntry()); - } -#endif - checkFrequencies(fg); -} -static void checkFrequencies(FlowGraph* fg) { -#ifdef _DEBUG - const CFGNodeDeque& nodes = fg->getNodes(); - for (CFGNodeDeque::const_iterator it = nodes.begin(), itEnd = nodes.end(); it!=itEnd; it++) { - CFGNode* node = *it; - assert(node->getFreq() > 0); - const CFGEdgeDeque& inEdges = node->getInEdges(); - if (inEdges.empty()) { - assert(node == fg->getEntry()); - continue; - } - double freq = 0.0; - for(CFGEdgeDeque::const_iterator it = inEdges.begin(), itEnd = inEdges.end(); it!=itEnd; it++) { - CFGEdge* edge = *it; - CFGNode* fromNode = edge->getSourceNode(); - double fromFreq = fromNode->getFreq(); - assert(fromFreq > 0); - freq += fromFreq * edge->getEdgeProb(); + //fix edge-probs, try to reuse old probs as much as possible.. + const Nodes& nodes = irm.getFlowGraph().getNodes(); + StaticProfilerContext* c = NULL; + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + double sumProb = 0; + uint32 nNotEstimated = 0; + const Edges& outEdges = node->getOutEdges(); + for(Edges::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) { + Edge* e = *eit; + double prob = e->getEdgeProb(); + sumProb+=prob; + if (prob <= 0) { + nNotEstimated++; + } } - assert(ABS(node->getFreq()- freq)/freq < ACCEPTABLE_DOUBLE_PRECISION_LOSS); - } - CFGNode* exitNode = fg->getExit(); - double exitFreq = exitNode->getFreq(); - assert(ABS(exitFreq - DEFAULT_ENTRY_NODE_FREQUENCY) < ACCEPTABLE_DOUBLE_PRECISION_LOSS * DEFAULT_ENTRY_NODE_FREQUENCY); -#endif -} - - -static void countLinearFrequency(const CountFreqsContext* c, CFGNode* node) { - const CFGEdgeDeque& inEdges = node->getInEdges(); - if (inEdges.empty()) { //node is entry - node->setFreq(DEFAULT_ENTRY_NODE_FREQUENCY); - } else { - double freq = 0.0; - LoopNode* loopHead = c->loopTree->isLoopHeader(node) ? c->loopTree->getLoopNode(node): NULL; - for(CFGEdgeDeque::const_iterator it = inEdges.begin(), itEnd = inEdges.end(); it!=itEnd; it++) { - CFGEdge* edge = *it; - CFGNode* fromNode = edge->getSourceNode(); - if (loopHead!=NULL && loopHead->inLoop(fromNode)) { //backedge - continue; //only linear freq estimation + if (nNotEstimated==0 && ABS(1 - sumProb) <= ACCEPTABLE_DOUBLE_PRECISION_LOSS) { + continue; //ok, nothing to fix + } + if (nNotEstimated == outEdges.size()) { //apply all active heuristics + if (c == NULL) { + c = new (irm.getMemoryManager()) StaticProfilerContext(irm); + } + c->node = node; + c->edge1 = NULL; + c->edge2 = NULL; + estimateNode(c); + } else { //assign min.possible prob for all not-estimated edges and scale probs to have sum == 1. + double scale = 1; + if (nNotEstimated == 0) { //do scaling only. + scale = 1 / sumProb; + } else { //assign a min possible probs for all not estimated edges, calculate scale + sumProb = 0; + for(Edges::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) { + Edge* e = *eit; + double prob = e->getEdgeProb(); + if (prob <= 0) { + prob = minProb; + e->setEdgeProb(prob); + } + sumProb+=prob; + } + scale = 1 / sumProb; } - if (c->visitInfo[fromNode->getId()] == false) { - return; + sumProb = 0; + for(Edges::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) { + Edge* e = *eit; + double prob = e->getEdgeProb(); + prob = prob * scale; + assert(prob > 0); + e->setEdgeProb(prob); +#ifdef _DEBUG + sumProb+=prob; +#endif } - double fromFreq = fromNode->getFreq(); - freq += fromFreq * edge->getEdgeProb(); - } - if (c->useCyclicFreqs && c->loopTree->isLoopHeader(node)) { - freq *= c->cyclicFreqs[node->getId()]; - } - node->setFreq(freq); - } - c->visitInfo[node->getId()] = true; - CFGNode* outerLoopHead = findLoopHeader(c->loopTree, node, true); - const CFGEdgeDeque& outEdges = node->getOutEdges(); - for(CFGEdgeDeque::const_iterator it = outEdges.begin(), itEnd = outEdges.end(); it!=itEnd; it++) { - CFGEdge* edge = *it; - CFGNode* toNode = edge->getTargetNode(); - if (toNode == node || toNode == outerLoopHead) { //backedge - continue;//do only linear freq estimation - } - if (c->visitInfo[toNode->getId()] == false ) { - countLinearFrequency(c, toNode); - } - } -} - -static void estimateCyclicFrequencies(CountFreqsContext* c, LoopNode* loopHead) { - //process all child loops first - bool hasChildLoop = loopHead->getChild()!=NULL; - if (hasChildLoop) { - for (LoopNode* childHead = loopHead->getChild(); childHead!=NULL; childHead = childHead->getSiblings()) { - estimateCyclicFrequencies(c, childHead); + assert(ABS(1-sumProb) < ACCEPTABLE_DOUBLE_PRECISION_LOSS); } } - findLoopExits(c, loopHead); - if (hasChildLoop) { - c->resetVisitInfo(); - countLinearFrequency(c, c->fg->getEntry()); - } - CFGNode* cfgLoopHead = loopHead->getHeader(); - double inFlow = cfgLoopHead->getFreq(); //node has linear freq here - double exitsFlow = 0; - //sum all exits flow - for (StlVector<CFGEdge*>::const_iterator it = c->exitEdges.begin(), end = c->exitEdges.end(); it!=end; ++it) { - CFGEdge* edge = *it; - CFGNode* fromNode = edge->getSourceNode(); - exitsFlow += edge->getEdgeProb() * fromNode->getFreq(); - } - // if loop will make multiple iteration exitsFlow becomes equals to inFlow - double loopCycles = inFlow / exitsFlow; - assert(loopCycles > 1); - c->cyclicFreqs[cfgLoopHead->getId()] = loopCycles; + setHeatThreshold(irm); } -static void findLoopExits(CountFreqsContext* c, LoopNode* loopHead) { - c->exitEdges.clear(); - const CFGNodeDeque& nodes = c->fg->getNodes(); - for (CFGNodeDeque::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { - CFGNode* node = *it; - if (!loopHead->inLoop(node)) { - continue; - } - const CFGEdgeDeque& outEdges = node->getOutEdges(); - for(CFGEdgeDeque::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) { - CFGEdge* edge = *eit; - CFGNode* targetNode = edge->getTargetNode(); - if (!loopHead->inLoop(targetNode)) { - c->exitEdges.push_back(edge); +static void splitString(const char* string, StringList& result, char separator, bool notEmptyTokensOnly) { + std::string token; + for (const char* suffix = string; *suffix!=0; ++suffix) { + char c = *suffix; + if (c == separator) { + if (token.empty() && notEmptyTokensOnly) { + continue; } + result.push_back(token); + token.clear(); + } else { + token.push_back(c); } } + if (!token.empty()) { //last value + result.push_back(token); + } } -} +} //namespace diff --git vm/jitrino/src/dynopt/StaticProfiler.h vm/jitrino/src/dynopt/StaticProfiler.h index 4e8e4f1..858b60c 100644 --- vm/jitrino/src/dynopt/StaticProfiler.h +++ vm/jitrino/src/dynopt/StaticProfiler.h @@ -27,10 +27,18 @@ #include "optpass.h" namespace Jitrino { class FlowGraph; -class CFGNode; -class CFGEdge; +class Node; +class Edge; -DEFINE_OPTPASS(StaticProfilerPass) -} +class StaticProfiler { +public: + + // estimates edge probabilities and calculates node frequencies + static void estimateGraph(IRManager& irm, double entryFreq, bool cleanOldEstimations=false); + + static void fixEdgeProbs(IRManager& irm); +}; + +}//namespace #endif diff --git vm/jitrino/src/jet/arith_rt.cpp vm/jitrino/src/jet/arith_rt.cpp index 75e1b03..d625015 100644 --- vm/jitrino/src/jet/arith_rt.cpp +++ vm/jitrino/src/jet/arith_rt.cpp @@ -17,11 +17,11 @@ * @author Alexander V. Astapchuk * @version $Revision: 1.3.12.4.4.4 $ */ -/** - * @file - * @brief Implementation of arithmetic helpers. - */ - + /** + * @file + * @brief Implementation of arithmetic helpers declared in arith_rt.h. + */ + #include "arith_rt.h" #include <stdlib.h> @@ -33,6 +33,12 @@ #ifndef PLATFORM_POSIX #define isnan _isnan #define finite _finite #endif +#include "trace.h" + + +#undef isnan +#define isnan(x) ((x) != (x)) + namespace Jitrino { namespace Jet { @@ -57,32 +63,32 @@ int __stdcall rt_h_neg_i32(int v) return -v; } -int __stdcall rt_h_lcmp(jlong v2, jlong v1) +int __stdcall rt_h_lcmp(jlong v1, jlong v2) { - if (v1 > v2 ) return 1; - if (v1 < v2 ) return -1; + if (v1 > v2) return 1; + if (v1 < v2) return -1; return 0; } -int __stdcall rt_h_fcmp_g(float v2, float v1) +int __stdcall rt_h_fcmp_g(float v1, float v2) { if (isnan(v1) || isnan(v2)) { return 1; } - if (v1 > v2 ) return 1; - if (v1 < v2 ) return -1; + if (v1 > v2) return 1; + if (v1 < v2) return -1; return 0; } -int __stdcall rt_h_fcmp_l(float v2, float v1) +int __stdcall rt_h_fcmp_l(float v1, float v2) { if (isnan(v1) || isnan(v2)) { return -1; } - return rt_h_fcmp_g(v2,v1); + return rt_h_fcmp_g(v1,v2); } -int __stdcall rt_h_dcmp_g(double v2, double v1) +int __stdcall rt_h_dcmp_g(double v1, double v2) { if (isnan(v1) || isnan(v2)) { return 1; @@ -96,14 +102,15 @@ int __stdcall rt_h_dcmp_g(double v2, dou return 0; } -int __stdcall rt_h_dcmp_l(double v2, double v1) +int __stdcall rt_h_dcmp_l(double v1, double v2) { if (isnan(v1) || isnan(v2)) { return -1; } - return rt_h_dcmp_g(v2,v1); + return rt_h_dcmp_g(v1,v2); } -double __stdcall rt_h_dbl_a(JavaByteCodes op, double v2, double v1) +double __stdcall rt_h_dbl_a(double v1, double v2, JavaByteCodes op) { + //rt_dbg_out("d%s: %f %f", instrs[op].name, v1, v2); switch(op) { case OPCODE_IADD: return v1 + v2; @@ -133,8 +140,9 @@ double __stdcall rt_h_dbl_a(JavaByteCode return fmod(v1,v2); } -float __stdcall rt_h_flt_a(JavaByteCodes op, float v2, float v1) +float __stdcall rt_h_flt_a(float v1, float v2, JavaByteCodes op) { + //dbg_rt("f%s: %f %f", instrs[op].name, v1, v2); switch( op) { case OPCODE_IADD: return v1 + v2; @@ -164,7 +172,7 @@ float __stdcall rt_h_flt_a(JavaByteCodes return fmod(v1,v2); } -jlong __stdcall rt_h_i64_shift(JavaByteCodes op, int v2, jlong v1) +jlong __stdcall rt_h_i64_shift(jlong v1, int v2, JavaByteCodes op) { switch(op) { case OPCODE_ISHL: @@ -181,9 +189,9 @@ jlong __stdcall rt_h_i64_shift(JavaByteC return 0; } -jlong __stdcall rt_h_i64_a( JavaByteCodes op, jlong v2, jlong v1) +jlong __stdcall rt_h_i64_a(jlong v1, jlong v2, JavaByteCodes op) { - switch( op) { + switch(op) { case OPCODE_IADD: return v1 + v2; case OPCODE_ISUB: @@ -208,9 +216,10 @@ jlong __stdcall rt_h_i64_a( JavaByteCode return 0; } -int __stdcall rt_h_i32_a( JavaByteCodes op, int v2, int v1) +int __stdcall rt_h_i32_a(int v1, int v2, JavaByteCodes op) { - switch( op) { + //dbg_rt("i%s: %u %u", instrs[op].name, v1, v2); + switch(op) { case OPCODE_IADD: return v1 + v2; case OPCODE_ISUB: @@ -232,8 +241,14 @@ int __stdcall rt_h_i32_a( JavaByteCodes (v1 >> (v2&0x1F)) + (2 << ~(v2&0x1F)); // special cases according to JVM Spec case OPCODE_IDIV: + // With v2==0 may be called from gen_a(). In this case, the return + // value will be ignoread anyway. + if (v2 == 0) return -1; return (v2 == -1 && v1 == INT_MIN) ? v1 : v1 / v2; case OPCODE_IREM: + // With v2==0 may be called from gen_a(). In this case, the return + // value will be ignoread anyway. + if (v2 == 0) return -1; return (v2 == -1 && v1 == INT_MIN) ? 0 : v1 % v2; default: break; @@ -270,7 +285,7 @@ jlong __stdcall rt_h_flt_2_i64(float i return 0; } return i<(double)jLONG_MIN ? - jLONG_MIN : (i>=(double)jLONG_MAX ? jLONG_MAX : (jlong)i); + jLONG_MIN : (i>=(double)jLONG_MAX? jLONG_MAX : (jlong)i); } double __stdcall rt_h_flt_2_dbl(float i) @@ -317,3 +332,5 @@ const void * cnv_matrix_impls[num_jtypes }; }}; // ~namespace Jitrino::Jet + + diff --git vm/jitrino/src/jet/arith_rt.h vm/jitrino/src/jet/arith_rt.h index 628edc8..b6864a7 100644 --- vm/jitrino/src/jet/arith_rt.h +++ vm/jitrino/src/jet/arith_rt.h @@ -20,15 +20,16 @@ /** * @file - * @brief Contains various arithmetic helpers. + * @brief Various arithmetic helpers declaration. * * The helpers normally used to implement complex computations (i.e. float - * point remainder) which is not worth to generate inlined. A call to a - * helper inserted instead. - * The set of helpers is wider than single float-point remainder, because - * they are also used for quick start while porting to a new platfrom - - * again, calls to the helpers generated instead of inlining them. Thus, - * the file also includes type conversion utilities. + * point remainder) which do not worth to be inlined. A call to a helper + * inserted instead. The set of helpers is wider than single float-point + * remainder, because they are also used for quick start while porting to a + * new platfrom - again, calls to the helpers generated instead of inlining + * them. + * + * The file also includes type conversion utilities. * * All the helpers from this file follow the contract: * - guaranteed not to invoke GC @@ -41,9 +42,6 @@ #define __ARITH_RT_H_INCLUDED__ #include "jdefs.h" -// resides in Jitrino's share/. Needed for proper stdcall__ definition. -#include "../shared/PlatformDependant.h" - namespace Jitrino { namespace Jet { @@ -119,10 +117,10 @@ extern const void * cnv_matrix_impls[num * @{ */ -int __stdcall rt_h_i32_a(JavaByteCodes op, int v2, int v1) stdcall__; -jlong __stdcall rt_h_i64_a(JavaByteCodes op, jlong v2, jlong v1) stdcall__; -double __stdcall rt_h_dbl_a(JavaByteCodes op, double v2, double v1) stdcall__; -float __stdcall rt_h_flt_a(JavaByteCodes op, float v2, float v1) stdcall__; +int __stdcall rt_h_i32_a(int v2, int v1, JavaByteCodes op) stdcall__; +jlong __stdcall rt_h_i64_a(jlong v2, jlong v1, JavaByteCodes op) stdcall__; +double __stdcall rt_h_dbl_a(double v2, double v1, JavaByteCodes op) stdcall__; +float __stdcall rt_h_flt_a(float v2, float v1, JavaByteCodes op) stdcall__; // // Some operations implemented via separate functions, as they have a bit @@ -139,7 +137,7 @@ int __stdcall rt_h_fcmp_l(float v2, int __stdcall rt_h_dcmp_g(double v2, double v1) stdcall__; int __stdcall rt_h_dcmp_l(double v2, double v1) stdcall__; -jlong __stdcall rt_h_i64_shift(JavaByteCodes op, int v2, jlong v1) stdcall__; +jlong __stdcall rt_h_i64_shift(jlong v1, int v2, JavaByteCodes op) stdcall__; /*@}*/ // ~group of RUNTIME_ARITHMETIC_HELPERS diff --git vm/jitrino/src/jet/bcproc.cpp vm/jitrino/src/jet/bcproc.cpp index c72de02..5d1facd 100644 --- vm/jitrino/src/jet/bcproc.cpp +++ vm/jitrino/src/jet/bcproc.cpp @@ -26,63 +26,25 @@ #include "jit_intf.h" /** * @file - * @brief Implementation of methods for bytecode processing - fetching for - * analysis and handling for code generation. + * @brief Mostly a huge switch(OPCODE), separated to several groups. */ namespace Jitrino { namespace Jet { -void Compiler::handle_inst(const JInst& jinst) +void Compiler::handle_inst(void) { - m_next_bb_is_multiref = false; // is it last instruction in basic block ? - const bool last = m_curr_bb->last_pc == jinst.pc; - const bool has_fall_through = !(jinst.flags & OPF_DEAD_END); - const bool is_jsr = jinst.opcode == OPCODE_JSR || - jinst.opcode == OPCODE_JSR_W; - // Test whether the next basic block will be multiref - if (last) { - if( jinst.is_branch() || jinst.is_switch()) { - for (unsigned i=0; i<jinst.get_num_targets(); i++) { - unsigned target = jinst.get_target(i); - const BBInfo& targetbb = m_bbs[target]; - m_next_bb_is_multiref = m_next_bb_is_multiref || - (targetbb.ref_count > 1); - } - if (jinst.is_switch()) { - unsigned target = jinst.get_def_target(); - const BBInfo& targetbb = m_bbs[target]; - m_next_bb_is_multiref = m_next_bb_is_multiref || - (targetbb.ref_count > 1); - } - } - // this is last instruction in this BB, - // test whether it has fall-through pass and whether it happens - // to be multi-referenced basic block - if (has_fall_through) { - // next instr must: - // ... exist - assert(m_curr_bb->next_bb != NOTHING); - // ... be multi-ref - const BBInfo& nextbb = m_bbs[m_curr_bb->next_bb]; - m_next_bb_is_multiref = m_next_bb_is_multiref || - (nextbb.ref_count > 1); - } - } + //const bool last = m_bbinfo->last_pc == jinst.pc; + const JInst& jinst = m_insts[m_pc]; + unsigned bc_size = m_infoBlock.get_bc_size(); + bool last = jinst.next>=bc_size || (m_insts[jinst.next].flags & OPF_STARTS_BB); -#ifdef _DEBUG - // Perform stack check - store stack pointer before and check it after - // the instruction. It must be the same. - // Skip checks for those who do not have fall-through block, and also - // for conditional branches - bool do_stack_check = (m_infoBlock.get_flags() & DBG_CHECK_STACK) && - has_fall_through && !jinst.is_branch(); - if (do_stack_check) { + if (is_set(DBG_CHECK_STACK)) { gen_dbg_check_stack(true); } -#endif + const InstrDesc& idesc = instrs[jinst.opcode]; switch (idesc.ik) { case ik_a: @@ -107,28 +69,20 @@ #endif handle_ik_stack(jinst); break; case ik_throw: - handle_ik_throw(jinst); + gen_athrow(); break; default: assert(jinst.opcode == OPCODE_NOP); break; }; -#ifdef _DEBUG - if (do_stack_check) { + if (is_set(DBG_CHECK_STACK)) { gen_dbg_check_stack(false); } -#endif - - m_curr_bb_state->seen_gcpt = m_curr_bb_state->seen_gcpt || - (jinst.flags & OPF_GC_PT); - // has_fall_through - also cuts off switch - if (last && m_next_bb_is_multiref && has_fall_through && - (is_jsr || !jinst.is_branch())) { - // Unload vars - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - // Upload stack - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); + + const bool has_fall_through = !(jinst.flags & OPF_DEAD_END); + if (last && has_fall_through && jinst.get_num_targets() == 0) { + gen_bb_leave(jinst.next); } } @@ -399,12 +353,7 @@ void Compiler::handle_ik_ls(const JInst& gen_ld(jobj, jinst.opcode-OPCODE_ALOAD_0); break; case OPCODE_ACONST_NULL: - gen_push(jobj, NULL); - break; - case OPCODE_IASTORE: - gen_check_null(2); - gen_check_bounds(2,1); - gen_astore(i32); + gen_push(jobj, NULL_REF); break; default: assert(false); break; } @@ -423,65 +372,43 @@ void Compiler::handle_ik_meth(const JIns bool is_static = opkod == OPCODE_INVOKESTATIC; get_args_info(is_static, jinst.op0, args, &retType); - if (!is_static) { - unsigned thizDepth = count_slots(args)-1; - gen_check_null(thizDepth); - } - Method_Handle meth = NULL; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - if (opkod == OPCODE_INVOKESTATIC) { - Timers::vmResolve.start(); - meth = resolve_static_method(m_compileHandle, m_klass, - jinst.op0); - Timers::vmResolve.stop(); - if (meth != NULL) { - Class_Handle klass = method_get_class(meth); - if (class_needs_initialization(klass)) { - gen_call_vm(rt_helper_init_class, 1, klass); - } - } - } - else if (opkod == OPCODE_INVOKEVIRTUAL) { - Timers::vmResolve.start(); - meth = resolve_virtual_method(m_compileHandle, m_klass, - jinst.op0); - Timers::vmResolve.stop(); - } - else if (opkod == OPCODE_INVOKEINTERFACE) { - // Workaround: - // When an interface has a method with the same signature as - // in java/lang/Object, then resolve_interface_method returns - // this method from Object. A further call to VM's helper - // get_vtable with this Method_Handle results to - // unpredictable behavior. - // An examples are: - // org/eclipse/ui/keys/KeyStroke::hashCode' of E3.0 - // For E3.1 - - // org/eclipse/jdt/internal/core/JavaProject::equals which - // tries to resolve in - // org/eclipse/core/resources/IProject::equals (Ljava/lang/Object;)Z' - // - // So, doing workaround by replacing INVOKEINTERFACE with - // INVOKEVIRTUAL - Timers::vmResolve.start(); - meth = resolve_interface_method(m_compileHandle, m_klass, jinst.op0); - Timers::vmResolve.stop(); - //assert(class_property_is_interface2(method_get_class(meth))); - // - //*** workaround here: - if (meth != NULL && - !class_property_is_interface2(method_get_class(meth))) { - opkod = OPCODE_INVOKEVIRTUAL; + + if (opkod == OPCODE_INVOKESTATIC) { + meth = resolve_static_method(m_compileHandle, m_klass, + jinst.op0); + if (meth != NULL) { + Class_Handle klass = method_get_class(meth); + if (class_needs_initialization(klass)) { + gen_call_vm(ci_helper_o, rt_helper_init_class, 0, klass); } } - else { - assert(opkod == OPCODE_INVOKESPECIAL); - Timers::vmResolve.start(); - meth = resolve_special_method(m_compileHandle, m_klass, jinst.op0); - Timers::vmResolve.stop(); + } + else if (opkod == OPCODE_INVOKEVIRTUAL) { + meth = resolve_virtual_method(m_compileHandle, m_klass, + jinst.op0); + } + else if (opkod == OPCODE_INVOKEINTERFACE) { + // BUG and HACK - all in one: + // An 'org/eclipse/ui/keys/KeyStroke::hashCode' (e3.0) does + // invokeinterface on java/util/SortedSet::hashCode(), but the + // entry get resolved into the 'java/lang/Object::hashCode' ! + // later: for eclipse 3.1.1 the same problem happens with + // org/eclipse/jdt/internal/core/JavaProject::equals + // which tries to resolve + // 'org/eclipse/core/resources/IProject::equals (Ljava/lang/Object;)Z' + meth = resolve_interface_method(m_compileHandle, m_klass, jinst.op0); + //assert(class_property_is_interface2(method_get_class(meth))); + // + //*** workaround here: + if (meth != NULL && + !class_property_is_interface2(method_get_class(meth))) { + opkod = OPCODE_INVOKEVIRTUAL; } } + else { + meth = resolve_virtual_method(m_compileHandle, m_klass, jinst.op0); + } gen_invoke(opkod, meth, args, retType); return; } @@ -528,22 +455,15 @@ void Compiler::handle_ik_obj(const JInst case OPCODE_CALOAD: jt = u16; break; case OPCODE_SASTORE: store = true; case OPCODE_SALOAD: jt = i16; break; - default: break; + default: break; } if (jt != jvoid) { // that was indeed *aload/*astore if (store) { - bool big = jt == dbl64 || jt == i64; - // stack: [.., aref, idx, val] - gen_check_null(big ? 3 : 2); - gen_check_bounds(big ? 3 : 2, big ? 2 : 1); - gen_astore(jt); + gen_arr_store(jt); } else { - // stack: [.., aref, idx] - gen_check_null(1); - gen_check_bounds(1, 0); - gen_aload(jt); + gen_arr_load(jt); } return; } @@ -551,140 +471,102 @@ void Compiler::handle_ik_obj(const JInst switch(jinst.opcode) { case OPCODE_NEW: { - Class_Handle klass = NULL; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - klass = vm_resolve_class_new(m_compileHandle, m_klass, - jinst.op0); - Timers::vmResolve.stop(); - } - gen_new(klass); + Class_Handle klass; + klass = vm_resolve_class_new(m_compileHandle, m_klass, jinst.op0); + gen_new(klass); } break; case OPCODE_PUTSTATIC: case OPCODE_GETSTATIC: { - jtype jt = to_jtype(class_get_cp_field_type( - m_klass, (unsigned short)jinst.op0)); - Field_Handle fld = NULL; - const bool is_put = jinst.opcode == OPCODE_PUTSTATIC; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - fld = resolve_static_field(m_compileHandle, m_klass, - jinst.op0, is_put); - Timers::vmResolve.stop(); - if (fld && !field_is_static(fld)) { - fld = NULL; - } - if (fld) { - Class_Handle klass = field_get_class(fld); - if (class_needs_initialization(klass)) { - gen_call_vm(rt_helper_init_class, 1, klass); - } - } + jtype jt = to_jtype(class_get_cp_field_type( + m_klass, (unsigned short)jinst.op0)); + const bool is_put = jinst.opcode == OPCODE_PUTSTATIC; + Field_Handle fld; + fld = resolve_static_field(m_compileHandle, m_klass, + jinst.op0, is_put); + if (fld && !field_is_static(fld)) { + fld = NULL; + } + if (fld != NULL) { + Class_Handle klass = field_get_class(fld); + assert(klass); + if (klass != m_klass && class_needs_initialization(klass)) { + gen_call_vm(ci_helper_o, rt_helper_init_class, 0, klass); } - gen_static_op(jinst.opcode, jt, fld); + } + gen_static_op(jinst.opcode, jt, fld); } break; case OPCODE_PUTFIELD: case OPCODE_GETFIELD: // stack: [objref, value] ; op0 - { + jtype jt = to_jtype(class_get_cp_field_type( + m_klass, (unsigned short)jinst.op0)); + bool is_put = jinst.opcode == OPCODE_PUTFIELD; - jtype jt = to_jtype(class_get_cp_field_type( - m_klass, (unsigned short)jinst.op0)); - bool is_put = jinst.opcode == OPCODE_PUTFIELD; - - Field_Handle fld = NULL; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - fld = resolve_nonstatic_field(m_compileHandle, m_klass, - jinst.op0, is_put); - Timers::vmResolve.stop(); - } - // for GETFIELD, check instance @ depth = 0 - // for PUTFIELD, the depth depends on the value width - gen_check_null(is_put ? (is_wide(jt) ? 2 : 1) : 0); - gen_field_op(jinst.opcode, jt, fld); - }; + Field_Handle fld = NULL; + fld = resolve_nonstatic_field(m_compileHandle, m_klass, + jinst.op0, is_put); + gen_field_op(jinst.opcode, jt, fld); + } break; case OPCODE_ARRAYLENGTH: - gen_check_null(0); gen_array_length(); break; case OPCODE_ANEWARRAY: { - Allocation_Handle ah = 0; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - Class_Handle klass = resolve_class(m_compileHandle, m_klass, - jinst.op0); - Timers::vmResolve.stop(); - if (klass != NULL) { - klass = class_get_array_of_class(klass); - } - if (klass != NULL) { - ah = class_get_allocation_handle(klass); - } - } - gen_new_array(ah); + Allocation_Handle ah = 0; + Class_Handle klass = resolve_class(m_compileHandle, m_klass, + jinst.op0); + if (klass != NULL) { + klass = class_get_array_of_class(klass); + } + if (klass != NULL) { + ah = class_get_allocation_handle(klass); + } + gen_new_array(ah); } break; case OPCODE_NEWARRAY: { - VM_Data_Type atype; - switch(jinst.op0) { - case 4: atype = VM_DATA_TYPE_BOOLEAN; break; - case 5: atype = VM_DATA_TYPE_CHAR; break; - case 6: atype = VM_DATA_TYPE_F4; break; - case 7: atype = VM_DATA_TYPE_F8; break; - case 8: atype = VM_DATA_TYPE_INT8; break; - case 9: atype = VM_DATA_TYPE_INT16; break; - case 10: atype = VM_DATA_TYPE_INT32; break; - case 11: atype = VM_DATA_TYPE_INT64; break; - default: assert(false); atype = VM_DATA_TYPE_INVALID; break; - } - Class_Handle elem_class = class_get_class_of_primitive_type(atype); - Class_Handle array_class = class_get_array_of_class(elem_class); - Allocation_Handle ah = class_get_allocation_handle(array_class); - gen_new_array(ah); + VM_Data_Type atype; + switch(jinst.op0) { + case 4: atype = VM_DATA_TYPE_BOOLEAN; break; + case 5: atype = VM_DATA_TYPE_CHAR; break; + case 6: atype = VM_DATA_TYPE_F4; break; + case 7: atype = VM_DATA_TYPE_F8; break; + case 8: atype = VM_DATA_TYPE_INT8; break; + case 9: atype = VM_DATA_TYPE_INT16; break; + case 10: atype = VM_DATA_TYPE_INT32; break; + case 11: atype = VM_DATA_TYPE_INT64; break; + default: assert(false); atype = VM_DATA_TYPE_INVALID; break; + } + Class_Handle elem_class = class_get_class_of_primitive_type(atype); + Class_Handle array_class = class_get_array_of_class(elem_class); + Allocation_Handle ah = class_get_allocation_handle(array_class); + gen_new_array(ah); } break; case OPCODE_MULTIANEWARRAY: - // op0 - cp index ; op1 - number of dimensions - // [..., count1, [..count2] ] => arrayref { - Class_Handle klass = NULL; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - klass = resolve_class(m_compileHandle, m_klass, jinst.op0); - Timers::vmResolve.stop(); - } - gen_multianewarray(klass, jinst.op1); - //m_jframe->stack_attrs(0, SA_NZ); - }; + Class_Handle klass = NULL; + klass = resolve_class(m_compileHandle, m_klass, jinst.op0); + gen_multianewarray(klass, jinst.op1); + } break; case OPCODE_MONITORENTER: case OPCODE_MONITOREXIT: - { - gen_check_null(0); - static const jtype args[1] = {jobj}; - gen_stack_to_args(true, 1, args); - gen_call_vm(jinst.opcode == OPCODE_MONITORENTER ? - rt_helper_monitor_enter : rt_helper_monitor_exit, 0); - } + gen_monitor_ee(); break; case OPCODE_CHECKCAST: case OPCODE_INSTANCEOF: { - const bool chk = jinst.opcode == OPCODE_CHECKCAST; - Class_Handle klazz = NULL; - if (!(m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION)) { - Timers::vmResolve.start(); - klazz = resolve_class(m_compileHandle, m_klass, jinst.op0); - Timers::vmResolve.stop(); - } - gen_instanceof_cast(chk, klazz); + const bool chk = jinst.opcode == OPCODE_CHECKCAST; + Class_Handle klazz = NULL; + klazz = resolve_class(m_compileHandle, m_klass, jinst.op0); + gen_instanceof_cast(chk, klazz); } break; default: assert(false); break; @@ -694,7 +576,7 @@ void Compiler::handle_ik_obj(const JInst void Compiler::handle_ik_stack(const JInst& jinst) { switch(jinst.opcode) { case OPCODE_POP: - gen_pop(m_jframe->top(), NULL); + gen_pop(m_jframe->top()); break; case OPCODE_POP2: gen_pop2(); @@ -712,15 +594,6 @@ void Compiler::handle_ik_stack(const JIn } } -void Compiler::handle_ik_throw(const JInst& jinst) -{ - assert(jinst.opcode == OPCODE_ATHROW); - static const jtype args[1] = {jobj}; - gen_stack_to_args(true, 1, args); - gen_call_vm(rt_helper_throw, 0); -} - - } } // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/bcproc.inl vm/jitrino/src/jet/bcproc.inl index a03849d..f94e6b0 100644 --- vm/jitrino/src/jet/bcproc.inl +++ vm/jitrino/src/jet/bcproc.inl @@ -1,18 +1,35 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.2.4.1 $ + * @author Alexander Astapchuk + * @version $Revision$ */ + /** * @file - * @brief In-lined version of Compiler::fetch(). + * @brief Inlined implementaion of Compiler::fetch(). */ + namespace Jitrino { namespace Jet { inline unsigned Compiler::fetch(unsigned pc, JInst& jinst) { - if(pc >= m_infoBlock.get_bc_size()) { + if (pc >= m_infoBlock.get_bc_size()) { return NOTHING; } @@ -23,7 +40,6 @@ inline unsigned Compiler::fetch(unsigned jinst.opcode = (JavaByteCodes)m_bc[pc]; ++pc; const InstrDesc& idesc = instrs[jinst.opcode]; - jinst.flags = idesc.flags; switch (idesc.len) { case 0: @@ -104,10 +120,12 @@ inline unsigned Compiler::fetch(unsigned default: assert(false); break; } + //Re-read deacription here, just in case we had a WIDE prefix before. + const InstrDesc& idesc_real = instrs[jinst.opcode]; + jinst.flags |= idesc_real.flags; + jinst.next = pc; return pc; } -}}; // ~namespace Jitrino::Jet - - +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg.cpp vm/jitrino/src/jet/cg.cpp index 9221614..7857aac 100644 --- vm/jitrino/src/jet/cg.cpp +++ vm/jitrino/src/jet/cg.cpp @@ -14,206 +14,689 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ + #include "compiler.h" +#include "arith_rt.h" #include "trace.h" +#include "stats.h" #include <malloc.h> -#include <memory.h> -#include <assert.h> -#include <stdlib.h> -#include <jit_import.h> +#include <stdarg.h> +#include <algorithm> +using std::min; + +#include <open/vm.h> +#include <jit_runtime_support.h> +#include <jit_intf.h> +#include <jni_types.h> + /** * @file - * @brief Platform-independent utilities for code generator. + * @brief Common CodeGen's routines and datas. */ - + namespace Jitrino { namespace Jet { -char * VMRuntimeConsts::rt_helper_throw = NULL; -char * VMRuntimeConsts::rt_helper_throw_out_of_bounds = NULL; -char * VMRuntimeConsts::rt_helper_throw_npe = NULL; -char * VMRuntimeConsts::rt_helper_throw_linking_exc = NULL; -char * VMRuntimeConsts::rt_helper_throw_div_by_zero_exc = NULL; - -char * VMRuntimeConsts::rt_helper_monitor_enter = NULL; -char * VMRuntimeConsts::rt_helper_monitor_exit = NULL; -char * VMRuntimeConsts::rt_helper_monitor_enter_static = NULL; -char * VMRuntimeConsts::rt_helper_monitor_exit_static = NULL; - -char * VMRuntimeConsts::rt_helper_ldc_string = NULL; -char * VMRuntimeConsts::rt_helper_new = NULL; -char * VMRuntimeConsts::rt_helper_new_array = NULL; -char * VMRuntimeConsts::rt_helper_init_class = NULL; -char * VMRuntimeConsts::rt_helper_aastore = NULL; -char * VMRuntimeConsts::rt_helper_multinewarray = NULL; -char * VMRuntimeConsts::rt_helper_get_vtable = NULL; -char * VMRuntimeConsts::rt_helper_checkcast = NULL; -char * VMRuntimeConsts::rt_helper_instanceof = NULL; -char * VMRuntimeConsts::rt_helper_ti_method_exit = NULL; -char * VMRuntimeConsts::rt_helper_ti_method_enter = NULL; -char * VMRuntimeConsts::rt_helper_gc_safepoint = NULL; -char * VMRuntimeConsts::rt_helper_get_thread_suspend_ptr = NULL; - -unsigned VMRuntimeConsts::rt_array_length_offset = NOTHING; -unsigned VMRuntimeConsts::rt_suspend_req_flag_offset = NOTHING; - - -void Compiler::ip(char * _ip) +const CallSig ci_helper_o(CCONV_HELPERS, jobj); +const CallSig ci_helper_v(CCONV_HELPERS); +const CallSig ci_helper_io(CCONV_HELPERS, i32, jobj); +const CallSig ci_helper_linkerr(CCONV_HELPERS, jobj, i32, i32); + +void CodeGen::do_mov(const Val& dst_s, const Val& src_s) { - m_codeStream.ip(_ip); - if (m_patchID != -1) { - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.instr_len = m_codeStream.ipoff() - m_curr_bb->ipoff - cpi.bboff; - if (cpi.instr_len == 2 || cpi.instr_len == 3) { - assert(CHAR_MIN <= cpi.target_offset && - cpi.target_offset <= CHAR_MAX); + assert(!dst_s.is_imm()); + jtype sjt = jtmov(src_s.jt()); + jtype djt = jtmov(dst_s.jt()); + assert(sjt == djt); + + if (dst_s.is_mem() && src_s.is_mem()) { + // Need to allocate a reg + Opnd src(sjt, src_s.base(), src_s.disp(), src_s.index(), src_s.scale()); + Opnd dst(djt, dst_s.base(), dst_s.disp(), dst_s.index(), dst_s.scale()); + rlock(dst_s); + rlock(src_s); + AR ar = valloc(src.jt()); + Opnd reg(src.jt(), ar); + mov(reg, src); + mov(dst, reg); + runlock(dst_s); + runlock(src_s); + return; + } + + if (src_s.is_imm() && (is_f(src_s.jt()))) { + // store to memory [first, then upload to register] + rlock(dst_s); + rlock(src_s); + Opnd dst; + if (dst_s.is_mem()) { + dst = dst_s.as_opnd(i32); } - m_patchID = -1; + else { + // 'mov (flt32/dbl64) fr, imm' - store to scratch area first, + // then upload to register + assert(dst_s.is_reg()); + dst = Opnd(i32, m_base, voff(m_stack.scratch())); + } + if (src_s.jt() == flt32) { + float f = src_s.fval(); + Opnd val(*(int*)&f); + mov(dst, val); + } + else { + double d = src_s.dval(); + Opnd val_lo(*(int*)&d); + mov(dst, val_lo); + Opnd dst_hi(i32, dst.base(), dst.disp()+4, dst.index(), + dst.scale()); + Opnd val_hi(*(1+(int*)&d)); + mov(dst_hi, val_hi); + } + // Succesfully stored immediate to memory. Now, if dst_s is regiter + // upload the value to it + if (dst_s.is_reg()) { + Opnd scratch = Opnd(sjt, m_base, voff(m_stack.scratch())); + mov(dst_s.as_opnd(), scratch); + } + runlock(dst_s); + runlock(src_s); + return; } + mov(dst_s.as_opnd(djt), src_s.as_opnd(sjt)); +} + +void CodeGen::gen_check_null(unsigned depth) +{ + Val& obj = vstack(depth); + gen_check_null(obj, true); } -unsigned Compiler::reg_patch(void) +void CodeGen::gen_check_null(Val& obj, bool hw_ok) { - assert(m_patchID == -1); - - CodePatchItem cpi; - cpi.pc = m_pc; - cpi.bb = m_curr_bb->start; - cpi.bboff = m_codeStream.ipoff() - m_curr_bb->ipoff; - cpi.target_ip = NULL; - cpi.target_pc = NOTHING; - cpi.relative = true; - cpi.target_offset = 0; - cpi.data = 0; - cpi.data_addr = NULL; - cpi.is_table_switch = false; + assert(obj.jt() == jobj); + if (obj.has(VA_NZ)) { + STATS_INC(Stats::npesEliminated,1); + if (is_set(DBG_TRACE_CG)) { + dbg(";;>check.npe for %s - skipped\n", + to_str(obj.as_opnd()).c_str()); + } + return; + } + if (obj.is_imm()) { + STATS_INC(Stats::npesEliminated,1); + if (obj.pval() == NULL_REF) { + gen_call_throw(ci_helper_v, rt_helper_throw_npe, 0); + } + return; + } + // Try to guess whether we can use hardware NPE @ this point. + // First, check if the method may use it at all: + // + // No catch handler in the method - any exception exits the method + // !synchronized => to avoid the following: + // synchronized method throws HW NPE + // GC starts during handling in VM + // rt_enum() detects that the exception cames from HW and reports + // nothing => 'this' gets no references and killed by GC + // after the GC, VM gets that exception comes from inside the synch + // method. VM tries to release monitor => asks for + // jit_get_address_of_this, but this address already collected by + // GC as garbage - everyone's dead. + // + // Also, we can not use HW checks for compressed references - the + // uncompressed null reference in not zero. + // + bool useHW = hw_ok && get_bool_arg("hwnpe", true) && !g_refs_squeeze; + if (meth_is_sync_inst() || meth_num_handlers() != 0) { + useHW = false; + } + // Now, all variables must be as if we were entering catch handler - + // the locals on callee-save registers must be on that registers and + // other locals must be in the memory + if (useHW) { + unsigned vars=m_infoBlock.get_num_locals(); + for (unsigned i=0; i<vars; i++){ + const Val& var = m_jframe->var(i); + AR ar = vreg(var.jt(), i); + if (ar == ar_x) continue; // no global allocation - skip it + if (is_callee_save(ar)) { + if (!var.is_reg()) { + // spilled callee-save globally allocated register. + // hmmm... how comes ? anyway, can't use HW check + useHW = false; + break; + } + else { + assert(var.reg() == ar); + } + } + else { + // Scratch register holds a variable - can't use HW check + if (!var.is_mem()) { + useHW = false; + break; + } + } + } + } + if (useHW) { + //TODO: + // Current check is based on the presumption that the fisrt 64K of + // address space raises hardware NPE. However, an object may occupy + // more than 64K - e.g. for array of longs, the (8192+1) items + // reside in more that 64K. Need to check whether 64k+ also raises + // the NPE, or change the NPE checks for field and array accesses. + if (is_set(DBG_TRACE_CG)) { + dbg(";;>check.npe.HW for %s\n", to_str(obj.as_opnd()).c_str()); + } + } + else { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>check.npe for %s\n", to_str(obj.as_opnd()).c_str()); + } + STATS_INC(Stats::npesPerformed,1); + rlock(obj); + Opnd opnd = obj.as_opnd(); + if (g_refs_squeeze) { + //AR gr_null = rfind(Val(jobj, NULL_REF)); + //if (gr_null == ar_x) { + // gr_null = valloc(jobj); + // movp(gr_null, NULL_REF); + // rset(gr_null, Val(jobj, NULL_REF)); + //} + AR gr_null = valloc(jobj); + movp(gr_null, NULL_REF); + alu(alu_cmp, opnd, gr_null); + } + else { + assert(sizeof(void*)==4); + assert(NULL_REF == 0); + if (opnd.is_reg()) { + alu(alu_test, opnd, opnd); + } + else { + alu(alu_cmp, opnd, Opnd((int)(int_ptr)NULL_REF)); + } + } + runlock(obj); + unsigned br_off = br(ne, 0, 0, taken); + gen_call_vm_restore(true, ci_helper_v, rt_helper_throw_npe, 0); + patch(br_off, ip()); + } // if !useHW - m_patchID = m_patchItems.size(); - m_patchItems.push_back(cpi); - return (unsigned)m_patchID; + // Mark the object 'non-null, guaranteed' + obj.set(VA_NZ); + // Propagate 'non-null' attribute to the same items in the frame + for (unsigned i=1; i<m_jframe->size(); i++) { + Val& that = m_jframe->dip(i); + if (that == obj) { + that.set(VA_NZ); + } + } + for (unsigned i=0; i<m_infoBlock.get_num_locals(); i++) { + Val& var = m_jframe->var(i); + if (var == obj) { + var.set(VA_NZ); + } + } + if (is_set(DBG_TRACE_CG) && !useHW) { dbg(";;>~check.npe\n"); } } -void Compiler::reg_data_patch(RefType type, unsigned cp_idx) +void CodeGen::gen_check_bounds(unsigned ref_depth, unsigned index_depth) { - unsigned pid = reg_patch(); - assert(pid == m_patchItems.size()-1 && pid == (unsigned)m_patchID); - pid=pid; // make compiler happy + if (is_set(DBG_TRACE_CG)) {dbg(";;>check.bounds\n");} + const Opnd arr = vstack(ref_depth, true).as_opnd(); + const Opnd idx = vstack(index_depth, vis_mem(index_depth)).as_opnd(); + Opnd len(i32, arr.reg(), rt_array_length_offset); + if (idx.is_reg()) { + alu(alu_cmp, len, Opnd(i32, idx.reg())); + } + else { + alu(alu_cmp, len, Opnd(idx.ival())); + } + // Unsigned condition here - aka 'len > (unsigned)index' - this also + // covers 'index < 0' - in a single comparation. + unsigned br_off = br(above, 0, 0, taken); + gen_call_vm_restore(true, ci_helper_v, rt_helper_throw_out_of_bounds, 0); + patch(br_off, ip()); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.bounds\n");} +} - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.data = ref_key(type, cp_idx); - m_lazyRefs[cpi.data] = NULL; +void CodeGen::gen_check_div_by_zero(jtype jt, unsigned divizor_depth) +{ + const Val& s = vstack(divizor_depth); + // + if ((s.is_imm() && s.ival() != 0) || s.has(VA_NZ)) { + // not zero - guaranteed + return; + } + if (is_set(DBG_TRACE_CG)) {dbg(";;>check.div_by_zero\n");} + // The first Val is immediate and zero + if (s.is_imm() && s.ival() == 0) { + // if it's i32, then nothing to do more - throw exception ... + if (jt == i32) { + // IS zero. Why do people want to divide on zero explicitly?.. + gen_call_throw(ci_helper_v, rt_helper_throw_div_by_zero_exc, 0); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} + return; + } + else if (is_big(jt)) { + // ... otherwise check high part of long constant ... + const Val& shi = m_jframe->dip(divizor_depth+1); + if (shi.is_imm() && shi.ival() == 0) { + // ... yes, it's zero too - throw ... + // Why do people want to divide on zero explicitly?.. + gen_call_throw(ci_helper_v, rt_helper_throw_div_by_zero_exc, 0); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} + return; + } + else if (shi.is_imm() && shi.ival() != 0) { + // ... no, the high part is not zero - may return. + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} + return; + } + } + // fall through to the next checks + } + // Long constant on the stack and we are on 64bit platform - check + // a single constant at once + if (s.is_imm() && jt == i64 && !is_big(i64)) { + if (s.lval() == 0) { + // IS zero. Why do people want to divide on zero explicitly?.. + gen_call_throw(ci_helper_v, rt_helper_throw_div_by_zero_exc, 0); + } + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} + return; + } + // at this point: + assert(!s.is_imm() || (s.is_imm() && s.ival()==0 && jt == i64)); + // .. and 'shi' is not immediate + assert(jt != i64 || !vis_imm(divizor_depth+1)); + + if (s.is_reg()) { + Opnd reg = s.as_opnd(i32); + alu(alu_test, reg, reg); + } + else { + Opnd mem = s.as_opnd(i32); + alu(alu_cmp, mem, Opnd(0)); + } + if (jt == i32 || !is_big(jt)) { + unsigned br_off = br(nz, 0, 0, taken); + gen_call_vm_restore(true, ci_helper_v, rt_helper_throw_div_by_zero_exc, 0); + patch(br_off, ip()); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} + return; + } + unsigned br_off = NOTHING; + const Val& shi = m_jframe->dip(divizor_depth+1); + if (!s.is_imm()) { + // jump around the further check --> [1] + br_off = br(nz, 0, 0, hint_none); + } + + // + // NB: the code generated below (till if(is_set)) may be jumped over + // so no methods should be invoked that may change location of an item + // - like vstack(), vswap() etc. If it's necessary to invoke such + // methods, this should be done before the br() above. + // + + if (shi.is_reg()) { + Opnd reg = shi.as_opnd(i32); + alu(alu_test, reg, reg); + } + else { + Opnd mem = shi.as_opnd(i32); + alu(alu_cmp, mem, Opnd(0)); + } + unsigned br_hi = br(nz, 0, 0, taken); + gen_call_vm_restore(true, ci_helper_v, rt_helper_throw_div_by_zero_exc, 0); + patch(br_hi, ip()); + if (!s.is_imm()) { + // [1] --> connect to here + patch(br_off, ip()); + } + if (is_set(DBG_TRACE_CG)) {dbg(";;>~check.div_by_zero\n");} } -unsigned Compiler::reg_patch(unsigned target_pc) +void CodeGen::gen_brk(void) { - unsigned pid = reg_patch(); - assert(pid == m_patchItems.size()-1 && pid == (unsigned)m_patchID); - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.target_pc = target_pc; - return pid; + trap(); } -unsigned Compiler::reg_patch(unsigned target_pc, bool relative) +void CodeGen::gen_gc_stack(int depth /*=-1*/, bool trackIt /*=false*/) { - unsigned pid = reg_patch(); - assert(pid == m_patchItems.size()-1 && pid == (unsigned)m_patchID); - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.target_pc = target_pc; - cpi.relative = relative; - return pid; + if (depth == -1) { + depth = m_jframe->size(); + } + // prepare GC info for stack + // Store the current depth + if (m_bbstate->stack_depth == (unsigned)depth) { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>GC.stack.depth - skipped (%d)\n", depth); + } + } + else { + Opnd op_depth(i32, m_base, voff(m_stack.info_gc_stack_depth())); + mov(op_depth, depth); + if (trackIt) { + m_bbstate->stack_depth = depth; + } + }; + if (depth == 0) { + return; + } + unsigned n_words = words(depth); + if (n_words != 0) { + unsigned gc_word = 0; + unsigned size = min(m_jframe->size(), WORD_SIZE); + for (unsigned i=0; i<size; i++) { + const Val& s = m_jframe->at(i); + if (s.jt() != jobj) continue; + if (vvar_idx(s) != -1) continue; + if (s.is_reg() && is_callee_save(s.reg())) continue; + if (s.survive_calls()) continue; + gc_word |= 1<<i; + } + // check whether we do need to store first word + if (m_bbstate->stack_mask_valid && + gc_word == m_bbstate->stack_mask) { + // do not need to update the GC mask, it's the same + if (is_set(DBG_TRACE_CG)) { + dbg(";;>GC.stack.mask - skipped(0x%X)\n", gc_word); + } + } + else { + Opnd op_mask(i32, m_base, 0*sizeof(int)+ voff(m_stack.info_gc_stack())); + mov(op_mask, gc_word); + if (trackIt) { + m_bbstate->stack_mask = gc_word; + m_bbstate->stack_mask_valid = true; + } + } + } + // store the bit masks + unsigned size = m_jframe->size(); + for (unsigned i = 1; i < n_words; i++) { + unsigned pos = i*WORD_SIZE; // where to start + unsigned end_pos = min(pos + WORD_SIZE, size); + unsigned gc_word = 0; + for ( ; pos < end_pos; pos++) { + const Val& s = m_jframe->at(pos); + if (s.jt() != jobj) continue; + if (vvar_idx(s) != -1) continue; + if (s.is_reg() && is_callee_save(s.reg())) continue; + if (s.survive_calls()) continue; + gc_word |= 1<<pos; + } + Opnd op_mask(i32, m_base, i*sizeof(int)+ voff(m_stack.info_gc_stack())); + mov(op_mask, gc_word); + } } -unsigned Compiler::reg_patch(const void * target_ip) +void CodeGen::gen_gc_mark_local(jtype jt, unsigned idx) { - unsigned pid = reg_patch(); - assert(pid == m_patchItems.size()-1 && pid == (unsigned)m_patchID); - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.target_ip = (char*)target_ip; - return pid; + jtype jtvar = vtype(idx); + if (jtvar != jvoid && jtvar != jobj) { + // the variable is known as never contains an object. + assert(jt != jobj); + if (m_infoBlock.get_flags() & DBG_TRACE_CG) { + dbg(";;> skipping GC mark - the item is known to be non-object\n"); + } + return; + } + bool mark = jt == jobj; + Val& v = vlocal(jt, idx); + // If an item was already marked and its type is still the same, then + // skip the mark + if ((v.has(VA_MARKED)) && + ((v.type() == jobj && mark) || (v.type() != jobj && !mark))) { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>GC mark skipped - object type is known\n"); + } + return; + } + + // prepare GC info for variable + unsigned offset; + unsigned bitno; + + AR ar = vreg(jt, idx); + if (ar != ar_x && is_callee_save(ar)) { + // mark the callee-save register + offset = m_stack.info_gc_regs(); + bitno = bit_no(ar_idx(ar)); + } + else if (vis_arg(idx)) { + // mark input argument + unsigned i = vget_arg(idx); + assert(m_ci.reg(i) == ar_x); + assert(0 == m_ci.off(i)%STACK_SLOT_SIZE); + int inVal = m_ci.off(i)/STACK_SLOT_SIZE; + unsigned word = word_no(inVal); + offset = word*sizeof(int) + m_stack.info_gc_args(); + bitno = bit_no(inVal); + } + else { + // mark the Val in the stack frame + unsigned word = word_no(idx); + offset = word*sizeof(int) + m_stack.info_gc_locals(); + bitno = bit_no(idx); + } + unsigned mask = 1<<bitno; + if (is_wide(jt)) { + // We must also clear bit for the next Val + assert(!mark); + if (bitno < 31) { + // good. can do in one touch + mask |= 1 << (bitno+1); + } + else { + // Bad, the next Val crosses the word's boundary + unsigned offset2 = offset + sizeof(int); + unsigned mask2 = 1; + const Opnd opnd2(i32, m_base, voff(offset2)); + alu(alu_and, opnd2, Opnd(~mask2)); + } + } + const Opnd opnd(i32, m_base, voff(offset)); + if (mark) { + alu(alu_or, opnd, Opnd(mask)); + } + else { + alu(alu_and, opnd, Opnd(~mask)); + } + v.set(VA_MARKED); } -void Compiler::patch_set_target(unsigned pid, char * _ip) +unsigned CodeGen::gen_stack_to_args(bool pop, const CallSig& cs, + unsigned idx, int cnt) { - CodePatchItem& cpi = m_patchItems[pid]; - assert(cpi.bb == m_curr_bb->start); + assert(idx <= cs.count()); + unsigned num = cs.count() - idx; - // the direct addresses in the code stream can not be used as targets, - // as the stream's buffer may move, making the addresses invalid - // use patch_set_target(, unsigned ipoff) instead ... -#ifdef _DEBUG - if (m_codeStream.data() <= _ip && - _ip < m_codeStream.data() + m_codeStream.size()) { - // _ip lies into the m_codeStream ... - // ... it's only allowed when both the CodePatchItem and _ip - // belong to the same basic block - // As we're currently generating m_curr_bb, then only need to check - // that _ip lies after the beginning of the current BB - and thus - // belong to the current BB - assert(m_codeStream.data() + m_curr_bb->ipoff <= _ip); + if (cnt == -1) { + cnt = num; } + // A special case on IA32 - our frame layout fits best for the managed + // calling convention, and the args can be prepared in a few + // instructions. - later + // TODO: it's not only for 'MANAGED_IA32' but for 'l2r && callee pops + // && !align stack'. + if (false && pop && idx == 0 && cnt == (int)cs.count() && + (cs.cc() == CCONV_MANAGED_IA32)) { + int fix = 0; + if (cnt != 0) { + // find the differenece between last used slot and the end of + // stack frame + int s = m_stack.stack_slot(m_jframe->depth2slot(0)); + fix = m_stack.size() + s; // s is < 0 + } + for (unsigned i=0; i<(unsigned)cnt; i++) { + jtype jt = m_jframe->top(); + vswap(0); + if (is_big(jt)) { + vswap(1); + } + vpop(); + } + if (fix != 0) { + alu(alu_add, sp, fix); + } + return fix; + } + + if (idx == 0 && cs.size() != 0) { + alu(alu_sub, sp, cs.size()); + } + int depth = 0; + // 1st pass - free all register that are used for args passing + for (int i=0; !(cs.cc() & CCONV_MEM) && i<cnt; i++) { + unsigned arg_id = idx+cnt-i-1; + AR ar = cs.reg(arg_id); + if (ar == ar_x) continue; + vpark(ar); + } + + rlock(cs); + + for (int i=0; i<cnt; i++) { + unsigned arg_id = idx+cnt-i-1; + jtype jt = cs.jt(arg_id); + if (jt<i32) { + jt = i32; + } + const Val& s = m_jframe->dip(depth); + if (cs.reg(arg_id) != ar_x) { + Opnd rarg(jt, cs.reg(arg_id)); + do_mov(rarg, s); + } + else { + jtype jtm = jtmov(jt); + Opnd arg(jtm, sp, cs.off(arg_id)); + do_mov(arg, s); + if (is_big(jt)) { + Opnd arg_hi(jtm, sp, cs.off(arg_id)+4); + const Val& s_hi = m_jframe->dip(depth+1); + do_mov(arg_hi, s_hi); + } + } + if (pop) { + vpop(); + } + else { + depth += is_wide(jt) ? 2 : 1; + } + } + return 0; +} + +void CodeGen::gen_call_throw(const CallSig& cs, void * target, + unsigned idx, ...) +{ + // say 'stack is empty' + gen_gc_stack(0, false); + vpark(false); + + va_list valist; + va_start(valist, idx); + rlock(cs); + AR gr = valloc(jobj); + call_va(is_set(DBG_CHECK_STACK), gr, target, cs, idx, valist); + runlock(cs); + +#ifdef _DEBUG + // just to make sure we do not return from there + gen_brk(); #endif - char * inst_ip = m_codeStream.data() + m_curr_bb->ipoff + cpi.bboff; - cpi.target_offset = _ip - inst_ip; } -void Compiler::patch_set_target(unsigned pid, unsigned _ipoff) +void CodeGen::gen_call_vm(const CallSig& cs, void * target, + unsigned idx, ...) { - CodePatchItem& cpi = m_patchItems[pid]; - assert(cpi.bb == m_curr_bb->start); - cpi.target_offset = _ipoff - (m_curr_bb->ipoff + cpi.bboff); + vpark(); + gen_gc_stack(-1, true); + va_list valist; + va_start(valist, idx); + rlock(cs); + AR gr = valloc(jobj); + call_va(is_set(DBG_CHECK_STACK), gr, target, cs, idx, valist); + runlock(cs); } -void Compiler::reg_table_switch_patch(void) +void CodeGen::gen_call_novm(const CallSig& cs, void * target, + unsigned idx, ...) { - reg_patch(); - CodePatchItem& cpi = m_patchItems[m_patchID]; - cpi.is_table_switch = true; + vpark(); + va_list valist; + va_start(valist, idx); + rlock(cs); + AR gr = valloc(jobj); + call_va(is_set(DBG_CHECK_STACK), gr, target, cs, idx, valist); + runlock(cs); } -void Compiler::cg_patch_code(void) +void CodeGen::gen_call_vm_restore(bool exc, const CallSig& cs, + void * target, unsigned idx, ...) { - unsigned didx = 0; - char ** dstart = (char**)m_infoBlock.get_lazy_refs(); - - for (unsigned i=0, n=m_patchItems.size(); i<n; i++) { - CodePatchItem& cpi = m_patchItems[i]; - const BBInfo& bbinfo = m_bbs[cpi.bb]; - char * bc_start_ip = m_vmCode + bbinfo.ipoff; - cpi.ip = bc_start_ip + cpi.bboff; - - if (cpi.is_table_switch) { - const JInst& jinst = m_insts[cpi.pc]; - assert(jinst.opcode == OPCODE_TABLESWITCH); - // Allocate table - unsigned targets = jinst.get_num_targets(); - char * theTable = (char*)method_allocate_data_block( - m_method, jit_handle, - targets * sizeof(void*), 16); - char ** ptargets = (char**)theTable; - // Fill out the table with targets - for (unsigned j=0; j<targets; j++, ptargets++) { - unsigned pc = jinst.get_target(j); - *ptargets = (char*)m_infoBlock.get_ip(pc); - } - cpi.data_addr = theTable; + BBState saveBB = *m_bbstate; + // 1. store scratch registers in a secret place + // 2. park everything + // 3. call whatever + // 4. restore scratch regs from the secret place + // 5. restore the state for callee-save registers + //----------------------------------------------- + // 1. + bool saveScratch = !exc; + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + if (is_callee_save(ar)) continue; + if (saveScratch && rrefs(ar) != 0) { + jtype jt = is_f(ar) ? dbl64 : jobj; + Opnd mem(jt, m_base, voff(m_stack.spill(ar))); + Opnd reg(jt, ar); + mov(mem, reg); } - else if (cpi.data != 0) { - void *& ptr = m_lazyRefs[cpi.data]; - if (ptr == NULL) { - ptr = dstart + didx; - ++didx; - } - cpi.data_addr = (char*)ptr; + if (rlocks(ar) != 0) { + runlock(ar, true); + } + } + // 2. + vpark(); + // 3. + va_list valist; + va_start(valist, idx); + rlock(cs); + AR gr = valloc(jobj); + call_va(is_set(DBG_CHECK_STACK), gr, target, cs, idx, valist); + runlock(cs); + // 4. + // restore the registers state + for (unsigned i=0; saveScratch && i<ar_num; i++) { + AR ar = _ar(i); + if (is_callee_save(ar)) continue; + if (rrefs(ar) != 0) { + jtype jt = is_f(ar) ? dbl64 : jobj; + Opnd mem(jt, m_base, voff(m_stack.spill(ar))); + Opnd reg(jt, ar); + mov(reg, mem); } - gen_patch(m_vmCode, cpi); } - assert(didx == m_infoBlock.get_num_refs()); + // 5. + // Actually nothing to do here. + // If we had a local var on register before, then it's still on the reg + // If we had the var with static assignment which was in memory, before, + // then the memory was not corrupted. + // So, just nothing to do with callee-save regs + // + *m_bbstate = saveBB; } -}}; // ~namespace Jitrino::Jet +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg.h vm/jitrino/src/jet/cg.h index 59d4614..0ed99d9 100644 --- vm/jitrino/src/jet/cg.h +++ vm/jitrino/src/jet/cg.h @@ -14,332 +14,1194 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Pltform-independent code generator's stuff. + * @brief CodeGen class and related datas declaration. */ #if !defined(__CG_H_INCLUDED__) #define __CG_H_INCLUDED__ -namespace Jitrino { namespace Jet { +#include "enc.h" +#include "sconsts.h" + +#include "structs.h" +#include "sframe.h" +#include "csig.h" +#include "mib.h" + +#include "../shared/MemoryManager.h" +#include "../main/PMF.h" +#include "../main/JITInstanceContext.h" +#include "../main/CompilationContext.h" + +#include <map> +using std::map; + +namespace Jitrino { +namespace Jet { /** - * @brief Dynamically grown byte array. - * - * Class CodeStream represents a dynamically growing byte array, which - * always provides buffer of at least minimal guaranteed size (which is - * #BUFFER_ZONE). + * CallSig for a VM helper that takes 1 argument of (#jobj). + */ +extern const CallSig ci_helper_o; +/** + * CallSig for a VM helper that takes no arguments. + */ +extern const CallSig ci_helper_v; +/** + * CallSig for a VM helper that takes 2 args: (#i32, #jobj). + */ +extern const CallSig ci_helper_io; +/** + * CallSig for VM helper THROW_LINKAGE_ERROR. + */ +extern const CallSig ci_helper_linkerr; + +/** + * Flag indicates that a patch item represents a table for + * LOOKUPSWITCH/TABLESWITCH. + */ +#define DATA_SWITCH_TABLE (0x00010000) + +extern void check_arg_has_doc(const char* key); + + +/** +* @brief Counts number of slots occupied by the specified set #jtype items. +* @param args - array of #jtype +* @return number of slots occupied by the specified set of #jtype items +*/ +inline unsigned count_slots(const ::std::vector<jtype>& args) +{ + unsigned slots = 0; + for (unsigned i=0; i<args.size(); i++) { + slots += (args[i] == dbl64 || args[i] == i64 ? 2 : 1); + }; + return slots; +} + + +/** +* @brief Counts number of slots occupied by the specified set #jtype items. +* @param num - number of items in the \c args array +* @param args - array of #jtype +* @return number of slots occupied by the specified set of #jtype items +*/ +inline unsigned count_slots(unsigned num, const jtype * args) +{ + unsigned slots = 0; + for (unsigned i=0; i<num; i++) { + slots += args[i] == dbl64 || args[i] == i64 ? 2 : 1; + } + return slots; +} + +/** + * Code generation routines for most of byte code instructions. * - * The usage is as follows: - * @code - * CodeStream cs; - * cs.init(INITIALLY_EXPECTED_CODE_SIZE); - * unsigned p_start = cs.ipoff(); - * // get buffer to write into - * char * p = cs.ip(); - * // use the buffer - * memcpy(p, otherP, someSize_less_than_BUFFER_ZONE); - * // let know how many bytes were used - * cs.ip(p + someSize_less_than_BUFFER_ZONE); - * ... - * unsigned next_p = cs.ipoff(); - * @endcode + * The class also contains set of methods for <b>local register + * allocation</b>. The method that perform local register allocation if + * valloc(jtype jt). + * */ -class CodeStream { +class CodeGen : public StaticConsts, public Encoder, public MethInfo { +protected: + CodeGen(void) + { + m_pmfPipeline = NULL; + m_pmf = NULL; + } + + /** + * @brief Compilation parameters. + */ + OpenMethodExecutionParams compilation_params; + public: /** - * @brief ctor. + * @brief Generates code for pushing int constant on operand stack. + */ + void gen_push(int); + /** + * @brief Generates code for pushing jlong constant on operand stack. + */ + void gen_push(jlong); + /** + * @brief Generates code which reads a constant value of type 'jt' from + * the address specified by 'p' and pushes it onto the stack. + */ + void gen_push(jtype jt, const void * p); + /** + * @brief Generates code which pops out a value of type 'jt' from the + * operand stack and stores it at the address specified by 'p'. + */ + void gen_pop(jtype jt); + /** + * @brief Generates code to perform POP2 bytecode instruction. + */ + void gen_pop2(void); + /** + * @brief Generates various DUP_ operations. + */ + void gen_dup(JavaByteCodes opc); + /** + * @brief Generates xSTORE operations. + */ + void gen_st(jtype jt, unsigned idx); + /** + * @brief Generates xLOAD operations. + */ + void gen_ld(jtype jt, unsigned idx); + /** + * @brief Generates LDC operation. + */ + void gen_ldc(void); + /** + * @brief Generates PUTFIELD and GETFIELD operations. + * + * Simply invokes do_field_op(). + */ + void gen_field_op(JavaByteCodes op, jtype jt, Field_Handle fld); + /** + * @brief Generates PUTSTATIC and GETSTATIC operations. + * + * Simply invokes do_field_op(). + */ + void gen_static_op(JavaByteCodes op, jtype jt, Field_Handle fld); + /** + * @brief Do all the job for gen_static_op() and gen_field_op(). + * + * Invokes gen_check_null() for GETFIELD and PUTFIELD. + */ + void do_field_op(JavaByteCodes op, jtype jt, Field_Handle fld); + + /** + * @brief Generates code for INVOKE instructions. + */ + void gen_invoke(JavaByteCodes opcod, Method_Handle meth, + const ::std::vector<jtype>& args, jtype retType); + + /** + * @brief Generates IINC operation. + * @param idx - index of local variable. + * @param value - value to add. + */ + void gen_iinc(unsigned idx, int value); + /** + * @brief Generates arithmetic operations. + * + * @note \c op argument always specified as integer operation (for + * example IADD, INEG), even if \c jt specifies float-point or long + * type. + * + * @param op - operation to perform. + * @param jt - types used in the arithmetic operation. + */ + void gen_a(JavaByteCodes op, jtype jt); + /** + * @brief Helper function for #gen_a, generates #i32 arithmetics. + */ + bool gen_a_i32(JavaByteCodes op); + /** + * @brief Helper function for #gen_a, generates #flt32 and #dbl64 + * arithmetics. + */ + bool gen_a_f(JavaByteCodes op, jtype jt); + /** + * @brief Helper function for #gen_a, may implement some + * platform-dependent operations. + */ + bool gen_a_platf(JavaByteCodes op, jtype jt); + /** + * @brief Performs generic operations which do not depend on type. + */ + bool gen_a_generic(JavaByteCodes op, jtype jt); + + /** + * @brief Generates conversion code. + */ + void gen_cnv(jtype from, jtype to); + + /** + * @brief Generates various CMP operations. + */ + void gen_x_cmp(JavaByteCodes op, jtype jt); + + /** + * @brief Generates code for NEW instruction. + */ + void gen_new(Class_Handle klass); + /** + * @brief Generates ANEWARRAY, NEWARRAY. + */ + void gen_new_array(Allocation_Handle ah); + /** + * @brief Generates MULTIANEWARRAY. + */ + void gen_multianewarray(Class_Handle klass, unsigned num_dims); + /** + * @brief Generates code for INSTANCEOF or CHECKCAST operations. + * @param chk - if \b true, generates CHECKCAST, INSTANCEOF otherwise. + * @param klass - Class_Handle of the class to cast to. + */ + void gen_instanceof_cast(bool chk, Class_Handle klass); + /** + * @brief Generates code for MONITOREXTERN and MONITOREXIT. + */ + void gen_monitor_ee(void); + /** + * @brief Generates code for ATHROW. + */ + void gen_athrow(void); + + /** + * @brief Update BBState and pushes the given jtype on operand stack, + * as if the code just executed a call that returned the given jtype. + * + * The item location is set according to the calling convention on + * which registers to use to return value of the given type. + * + * On IA-32 (where the float/double are returned through FPU) the + * item is spilled (code is generated to do so) into memory first. + * @param jtyp - type of the value 'returned' + */ + void gen_save_ret(jtype jtyp); + + /** + * @brief Generates code to call one of the throw_ helpers. + * + * @note The method only synchronize local vars into the memory. + */ + void gen_call_throw(const CallSig& cs, void * target, unsigned idx, ...); + + /** + * @brief Generates code to call non-VM helper. + * + * The method does not update GC info. + */ + void gen_call_novm(const CallSig& cs, void * target, unsigned idx, ...); + /** + * @brief Generates code to call a VM helper. + * + * The method updates GC info and synchronizes both stack and local vars. + */ + void gen_call_vm(const CallSig& cs, void * target, unsigned idx, ...); + + /** + * @brief Generates code to call a VM helper and then restores the + * state of local variable, stack and registers. + * + * The method updates GC info and synchronizes both stack and local vars. + */ + void gen_call_vm_restore(bool exc, const CallSig& cs, void * target, + unsigned idx, ...); + + /** + * @brief Generates code to take arguments from Java operand stack and + * put them to the native stack/registers to prepare a call. + * + * @note The method does rlock(cs), so caller must runlock(cs). + * + * @param pop - if \b true, the arguments are popped out from the operand + * stack. Otherwise, the operand stack is left intact. + * @param cs - CallSig describing args + * @param idx - an index of arguments to start from + * @param cnt - how many arguments to process. -1 means 'till the end' + */ + unsigned gen_stack_to_args(bool pop, const CallSig& cs, unsigned idx, + int cnt=-1); + + /** + * @brief Generates code to prepare arguments for a call. + * + * @note The method does \b not rlock(cs). + * @note All possible conflicts of \c parg registers and registers + * used in \c cs, must be resolved before gen_args call. + */ + void gen_args(const CallSig& cs, unsigned idx, const Val * parg0 = NULL, + const Val * parg1 = NULL, const Val * parg2 = NULL, + const Val * parg3 = NULL, const Val * parg4 = NULL, + const Val * parg5 = NULL, const Val * parg6 = NULL); + + + /** + * @brief Generates ARRAYLENGTH instruction. + */ + void gen_array_length(void); + + /** + * @brief Generates ALOAD instruction. + * + * Also invokes gen_check_bounds() and gen_check_null(). + */ + void gen_arr_load(jtype jt); + /** + * @brief Generates ASTORE instruction. + * + * Also invokes gen_check_bounds() and gen_check_null(). + */ + void gen_arr_store(jtype jt); + /** + * @brief Generates code to check bounds for array access. + * @param aref_depth - depth (in the operand stack) of the array's object + * reference + * @param index_depth - depth (in the operand stack) of the index to be + * used for array's access. + */ + void gen_check_bounds(unsigned aref_depth, unsigned index_depth); + /** + * @brief Generates code to check whether the object ref at the given + * depth in the operand stack is \c null. + * @param stack_depth_of_ref - depth in the operand stack of the object + * reference to test against \c null. + */ + void gen_check_null(unsigned stack_depth_of_ref); + /** + * @brief Generates code to check whether the object apecified by the + * \c Val is not \b NULL. + * @param val - the value to check for \b NULL + * @param hw_ok - whether it's ok to eliminate explicit NPE check in + * favor of hardware NPE check. + */ + void gen_check_null(Val& val, bool hw_ok); + /** + * @brief Generates code to check whether an item used in division + * operation is zero. + * @param jt - type of division operation (#i64 or #i32) to be performed. + * @param stack_depth_of_divizor - depth in the operand stack of the + * divisor. + */ + void gen_check_div_by_zero(jtype jt, unsigned stack_depth_of_divizor); + + /** + * @brief Generates a code which prepares GC info for operand stack - + * stack depth and GC mask. + * + * @param depth - if \b -1, then current stack depth is taken, + * otherwise, the specified depth is stored. + * @param trackIt - if \b true, then the GC info is also reflected in + * the current BB's state (BBState::stack_depth, + * BBState::stack_mask). + * @see BBState + */ + void gen_gc_stack(int depth=-1, bool trackIt=false); + /** + * @brief Generates code which either marks or clears mark on a local + * variable to reflect whether it holds an object or not + * (runtime GC info). + */ + void gen_gc_mark_local(jtype jt, unsigned idx); + + /** + * @brief Generates GC safe point code which facilitate thread + * suspension on back branches. + */ + void gen_gc_safe_point(void); + + /** + * @brief Inserts a break point. + * + * For debugging only. + */ + void gen_brk(void); + + /** + * @brief Generates code to ensure stack integrity at runtime. + * @note For debug checks only. + * @param start - \b true if check start to be generated, false otherwise + */ + void gen_dbg_check_stack(bool start); + + /** + * @brief Generates code to output string during runtime. + * + * The generated code preserves general-purpose registers. + * The string is formatted before the code generation, then + * \link #dbg_rt get printed \endlink during runtime. + * + * For debugging only. + */ + void gen_dbg_rt(bool save_regs, const char * fmt, ...); + /** + * @brief Prints out an argument's (or return value's) type and value. + * + * The method is invoked during runtime from the compiled code. + * + * The output goes through dbg_rt. + * @param val - value of the argument/return value + * @param idx - index of argument or -1 if return value is printed + * @param jt - type of the argument/return value */ - CodeStream() + static void __stdcall dbg_trace_arg(void * val, int idx, jtype jt) stdcall__; + /** + * @brief CallSig object for dbg_trace_arg(). + */ + static const CallSig cs_trace_arg; + /** + * @brief Converts given \c s into human-readable string. + * + * Used for debugging output. + * + * @param s - Val to be converted. + * @param is_stack - \b true if \c s represents operand stack item. + */ + ::std::string toStr2(const Val& s, bool is_stack) const; + /** + * @brief Prints out BBState. + * @param name - a name to print out before the dump, to identify the + * dump in the trace log. + * @param pState - BBState to dump. + */ + void dbg_dump_state(const char * name, BBState * pState); + /** + * @brief Enforces memory check. + * + * Implementation is platform dependent. + * + * Currently, the check is performed only on Windows in debug build, + * using CRT routines. + */ + void dbg_check_mem(void); + /** + * @brief Generates move operation from \c src to \c dst. + * + * The types of both \c src and \c dst must be the same and \c dst must + * not be immediate. If both items reside in the memory, then a + * temporary register is allocated to perform the movement. + * + * The method does not transfer attributes. + * + * @param src - source operand. + * @param dst - destination operand. + */ + void do_mov(const Val& dst, const Val& src); + /** + * @brief Returns a stack item at the given depth. + * + * @param depth - depth of stack item to return. + * @param toReg - if \b true, then ensures that the stack item resides + * on a register. + */ + Val& vstack(unsigned depth, bool toReg = false); + /** + * @brief Returns a local variable item. + * + * The local variable's slot at the given \c idx must be either + * unknown (of #jvoid type) or must be of the same type \c jt. + * + * If operation being generted is defining operation, then vvar_def(). + * must be called before vlocal() and \c willDef must be set to \b true. + * + * If the variable has globally allocated register, but is currently + * spilled out, then the code to upload it back from the memory to + * register is generated. If \c willDef == \b true, no upload code + * is generated. + * + * Also, if \c willDef == \b true, then the method ensures that any + * references to the variable in operand stack are 'unreferenced' - + * that is the value of variable is read and then written into + * operand stack memory cells. + * + * @note As a side effect of this function some items on operand stack + * may change their location. + * + * @param jt - type of the variable. + * @param idx - index of the variable. + * @param willDef - whether the next operation with the variable + * will be defining operation. + * @see vvar_def + */ + Val& vlocal(jtype jt, unsigned idx, bool willDef = false); + /** + * @brief Ensures the local variable slot has the proper type. + * + * If the \c idx slot is occupied by an register of other type (e.g. + * FSTORE followed by ISTORE), then the register is freed, and the + * slot get the proper type assigned to it. + */ + void vvar_def(jtype jt, unsigned idx); + /** + * @brief Returns offset of the given local variable in the stack frame. + * + * May not be equal to m_stack.local(idx) as some local variables that + * come as input args, are not copied into stack frame but are used + * at the same location as the input args are. + * + * The returned value reflect current stack depth (if applicable). + */ + int vlocal_off(unsigned idx) const; + /** + * @brief Returns offset of the operand stack item at the given depth + * in method's stack frame. + * + * The returned value reflect current stack depth (if applicable). + */ + int vstack_off(unsigned depth) const; + /** + * @brief Corrects an offset in the method's stack frame according + * to the current stack depth. + * + * The method is intended for use with sp-based stack frames. + */ + int voff(int off) const; + /** + * @brief Verifies data integrity in current BBState. For debugging + * purposes only. + */ + void vcheck(void); + /** + * @brief Allocates temporary scratch register of the given type. + * + * The allocation is based on reference count for a register, register + * locks and 'last_used' fields in the BBState. + * + * The 'last used' idiom allows to spread operations across several + * registers. When a code is about to allocate temporary register, then + * the allocation routine tries to allocate a register \b other than one + * allocated before. This reduces dependencies between operations and + * increases parallelism chances. + * + * If the allocation routine failed to find an unused register of + * proper type, then it generates spill code. A register to spill is + * chosen on reference count for the register. The reference count is + * current number of usages of the register in both operand stack and + * local variables array. + * + * A non-locked register with the lowest number of references is + * subject to spill out - the code is generated. + * + * The reference count is not calculated in valloc() itself, but used + * from BBState data (rref()). + * + * This presumes that usage of registers in mimic operand stack and + * local variables is tracked properly. Debug method vcheck() ensures + * the proper reference count. + * + * @note As a side effect of this function some non-locked items of + * operand stack or local variables may change its kind from register + * to memory. + */ + AR valloc(jtype jt); + /** + * @brief Ensures operand stack item at the given \c depth resides in + * the memory. + */ + void vswap(unsigned depth); + /** + * @brief Synchronizes all scratch registers into memory. + * + * If \c doStack is \b false, then only processes local variables. + * + * @param doStack - \c true to synchronize operand stack items as well + */ + void vpark(bool doStack = true); + /** + * @brief Synchronizes given register into memory. + * + * If \c doStack is \b false, then only processes local variables. + * + * @param ar - register to be synchronized + * @param doStack - \c true to synchronize operand stack items as well + */ + void vpark(AR ar, bool doStack = true); + + /** + * @brief Tests whether operand stack item at the given depth is + * immediate. + */ + bool vis_imm(unsigned depth) { - m_buf = NULL; - m_size = 0; + return m_jframe->dip(depth).is_imm(); } /** - * @brief Frees allocated memory. + * @brief Tests whether operand stack item at the given depth resides + * in memory. */ - ~CodeStream() + bool vis_mem(unsigned depth) { - if (m_buf) { - free(m_buf); - } + return m_jframe->dip(depth).is_mem(); } - /** - * @brief Performs initial memory allocation. + * @brief Tests whether operand stack item at the given depth resides + * in register. + */ + bool vis_reg(unsigned depth) + { + return m_jframe->dip(depth).is_reg(); + } + /** + * @brief One or 2 (for wide types) empty Val-s on the operand stack. + * @note In contrast to vpush(const Val&) accepts wide types. + */ + void vpush(jtype jt); + /** + * @brief Pushes the given Val into mimic operand stack. + * + * Increments reference counts for registers involved. + */ + void vpush(const Val& op); + /** + * @brief Pushes the given Val into mimic operand stack. + * + * Increments reference counts for registers involved. + */ + void vpush2(const Val& op_lo, const Val& op_hi); + /** + * @brief Pops out 2 parts of \link is_big() big \endlink type from + * mimic operand stack. + * + * Decrements reference counts for involved registers. + */ + void vpop2(Val* pop_low, Val* pop_hi); + /** + * @brief Pops out an item from mimic operand stack. + * + * Decrements reference counts for involved registers. + */ + void vpop(void); + /** + * @brief Marks that the local variable \c idx resides in the given + * register (\c s). + * @param jt - type of local variable + * @param idx - index of local variable + * @param s - must represent a register of proper type, to be assigned + * as current variable's location + */ + void vassign(jtype jt, unsigned idx, const Val& s); + /** + * @brief Tests whether the memory reference in \c s points to an + * operand stack item in the stack frame. + */ + bool vis_stack(const Val& s) const; + /** + * @brief Returns \b true if the local variable is not stored in the + * method's stack frame, but rather a stack slot of input argument is + * reused. + */ + bool vis_arg(unsigned local_idx) const; + /** + * @brief If vis_arg(local_idx) is \b true, the method returns + * index of input argument that corresponds to this local variable. + * + * Must only be called for local variables which really reuse input + * argument stack space (that is, vis_arg()==\b true). + */ + unsigned vget_arg(unsigned local_idx) const; + /** + * @brief Tests whether the memory reference in \c s points to a local + * variable. An index of the variable (>=0) is returned, or -1 if + * the memory does not point to local variable. * - * The memory size allocated is 'bytes' and then grow when necessary. + * This method takes vis_arg() into account - if the variable reuses + * input argument space, then the address is checked against that + * argument's address. */ - void init(unsigned bytes) + int vvar_idx(const Val& s) const; + /** + * @brief Wraps given address into operand. + * + * The method checks whether the address fits into displacement part + * of complex address form (which is always true for IA-32). If so, + * then the operand with no base is returned. + * + * Otherwise, GR register allocated, the code is generated to load + * address into the register and the operand with the register as + * base and zero displacement returned. + */ + Opnd vaddr(jtype jt, const void* p) { - resize(bytes); + const char * addr = (const char*)p; + // If we're going to address more that 4 bytes, ensure the next + // item will also fit into displacement. + if (fits32(addr) && fits32(addr+4)) { + return Opnd(jt, ar_x, (int)(int_ptr)addr); + } + AR ar = valloc(jobj); + movp(ar, addr); + return Opnd(jt, ar, 0); } - - /** - * @brief Returns address of a next available for writing byte. + * @brief Return <i>static type</i> of the local variable. + * + * Static type is the type which is only used to access the variable. + * + * For example, if a variable is only used for ASTORE and ALOAD, then + * the static type is #jobj. Otherwise (e.g. FSTORE/ASTORE mix), static + * type is #jvoid. + */ + jtype vtype(unsigned idx); + /** + * Returns a register allocated for the given local variable, ar_x if + * none. + */ + AR vreg(jtype jt, unsigned idx); + /** + * @brief Dereferences all items of the given type on operand stack. * - * The address returned is guaranteed to contain at least #BUFFER_ZONE - * bytes. - * @note The address returned is valid only till the next call to - * #ip(void) where a memory reallocation can happen. So the address - * must be used only for call to #ip(char*). - * #ipoff() must be used to store offsets, which are consistent during - * the lifetime of CodeStream object. + * Dereference here means the following: + * + * When mimic operand stack operations, CodeGen enforces lazy scheme - + * e.g. for xLOAD operations, the reference on local variable is + * stored onto mimic stack. + * + * However, when we perform a defining operation for a local variable + * we must ensure that operand stack items contain the value of the + * variable before the defining operation. + * + * The method generates code to reload such postponed references from + * the local variable(s) into proper operand stack memory slot(s). */ - char * ip(void) { - if ((total_size - m_size) < BUFFER_ZONE) { - resize(total_size + total_size*GROW_RATE/100); + void vunref(jtype jt); + /** + * Dereferences all items on the operand stack the refer to the given + * Opnd (either register or memory location). + * + * @see vunref(jtype jt) on dereference description. + */ + void vunref(jtype jt, const Val& op, unsigned skipDepth = NOTHING); + + /** + * @brief Locks the given \c ar. + * + * Increases number of locks for the specified \c ar. + * + * Lock on an AR prevents the register from being \link valloc(jtype) + * allocated for temporary needs \endlink. + * + * The lock may be acquired several times, but must be released the + * same number of times. + */ + void rlock(AR ar) + { + if (ar != ar_x && ar != (AR)NOTHING) { + assert(ar_idx(ar)<ar_num); + ++m_bbstate->m_regs[ar_idx(ar)].locks; } - return m_buf + m_size; } - + /** - * @brief Sets current address. This must be an address of a next - * available byte. + * @brief Unlocks the given \c ar. * - * The address is used to determine how many bytes were used since the - * last call of #ip(void) and thus, how many free bytes left. + * Decreases number of locks for the specified \c ar. + * + * @param ar - register to be locked + * @param force - if \b true, then drops the lock count to zero, + * regardless of how many lock(ar) was invoked before. + * @see rlock(AR ar) */ - void ip(char * _ip) + void runlock(AR ar, bool force = false) { - m_size = _ip - m_buf; - assert(m_size < total_size); + if (ar != ar_x && ar != (AR)NOTHING) { + assert(ar_idx(ar)<ar_num); + assert(m_bbstate->m_regs[ar_idx(ar)].locks>0); + if (force) { + m_bbstate->m_regs[ar_idx(ar)].locks = 0; + } + else { + --m_bbstate->m_regs[ar_idx(ar)].locks; + } + } + } + /** + * @brief Locks all the registers used in the \c cs. + */ + void rlock(const CallSig& cs) + { + for (unsigned i=0; i<cs.count(); i++) { + AR ar = cs.reg(i); + if (ar != ar_x) { + rlock(ar); + } + } + } + /** + * @brief Unlocks all the registers used in the \c cs. + */ + void runlock(const CallSig& cs) + { + for (unsigned i=0; i<cs.count(); i++) { + AR ar = cs.reg(i); + if (ar != ar_x) { + runlock(ar); + } + } } - /** - * @brief Returns an offset the next available byte in the stream. + * @brief Locks the registers in the \c s. + * + * If \c s refers to register, then this register is locked. + * + * If \c is memory reference, then all valid registers of complex + * address form are locked. * - * #data() + #ipoff() gets the address. + * For immediate operand it's no-op. */ - unsigned ipoff(void) const + void rlock(const Val& s) { - return m_size; + if (s.is_reg()) { rlock(s.reg()); } + else if (s.is_mem()) { rlock(s.base()); rlock(s.index()); } } - /** - * @brief Returns the size currently used in the stream. + * @brief Unlocks all registers in the \c s. */ - unsigned size(void) const + void runlock(const Val& s) { - return m_size; + if (s.is_reg()) { runlock(s.reg()); } + else if (s.is_mem()) { runlock(s.base()); runlock(s.index()); } } - /** - * @brief Provides a direct access to internal buffer. - * - * @note Never use more than #size() bytes. + * @brief Increments reference counts for registers in the \c s. */ - char * data(void) const + void rref(const Val& s) { - return m_buf; + if (s.is_reg()) { rref(s.reg()); } + else if (s.is_mem()) { rref(s.base()); rref(s.index()); } } - /** - * @brief The minimum guaranteed size of the buffer returned by ip(). - * - * This is also a minimal size of the buffer which triggers - * reallocation of a bigger memory buf. - * '16' here is max size of the native instruction (on IA32/EM64T). - * 3 was chosen heuristically. + * @brief Decrements reference counts for registers in the \c s. */ - static const unsigned BUFFER_ZONE = 16*3; -private: + void rfree(const Val& s) + { + if (s.is_reg()) { rfree(s.reg()); } + else if (s.is_mem()) { rfree(s.base()); rfree(s.index()); } + } /** - * @brief [Re-]allocates memory. - * - * The previously filled memory (if any) is copied into the newly - * allocated buffer. + * @brief Increments reference counts for \c ar; */ - void resize(unsigned how_much) + void rref(AR ar) { - total_size = how_much; - m_buf = (char*)realloc(m_buf, total_size); + if (ar != ar_x && ar != (AR)NOTHING) { + assert(ar_idx(ar)<ar_num); + ++m_bbstate->m_regs[ar_idx(ar)].refs; + } } - /** - * @brief Pointer to the allocated buffer. + * @brief Decrements reference counts for \c ar; */ - char * m_buf; - + void rfree(AR ar) + { + if (ar != ar_x && ar != (AR)NOTHING) { + assert(ar_idx(ar)<ar_num); + assert(m_bbstate->m_regs[ar_idx(ar)].refs>0); + --m_bbstate->m_regs[ar_idx(ar)].refs; + } + } /** - * @brief Total size of the allocated buffer. + * @brief Returns number of references for \c ar; */ - unsigned total_size; - + unsigned rrefs(AR ar) const + { + assert(ar_idx(ar)<ar_num); + return m_bbstate->m_regs[ar_idx(ar)].refs; + } /** - * @brief Size of buffer currently in use. + * @brief Returns number of locks for \c ar; */ - unsigned m_size; - + unsigned rlocks(AR ar) const + { + assert(ar_idx(ar)<ar_num); + return m_bbstate->m_regs[ar_idx(ar)].locks; + } /** - * @brief A rate how to increase the already allocated buffer, in - * percent. + * @brief Tries to find out which register is currently know to hold + * the given value (if \c v is immediate) or a value from the specified + * address (if \c v is memory). + */ + AR rfind(const Val& v) const + { + for (unsigned i=0; i<ar_num; i++) { + if (m_bbstate->m_regs[i].val == v) { + return _ar(i); + } + } + return ar_x; + } + /** + * @brief Set's 'currently known' value for the register. + */ + void rset(AR ar, const Val& v) + { + assert(ar_idx(ar)<ar_num); + m_bbstate->m_regs[ar_idx(ar)].val = v; + } + /** + * @brief Clears all registers-related info in current BBState. + */ + void rclear(void) + { + for (unsigned i=0; i<ar_num; i++) { + m_bbstate->m_regs[i].locks = 0; + m_bbstate->m_regs[i].refs = 0; + m_bbstate->m_regs[i].val = Val(); + } + } + /** + * @brief Returns 'last used' register of the given type. + * @see valloc + */ + AR rlast(jtype jt) const + { + return is_f(jt) ? m_bbstate->m_last_fr : m_bbstate->m_last_gr; + } + /** + * @brief Sets 'last used' register for the given type. + * @see valloc + */ + void rlast(AR ar) + { + assert(ar != ar_x); + if (is_f(ar)) { + m_bbstate->m_last_fr = ar; + } + else { + assert(is_gr(ar)); + m_bbstate->m_last_gr = ar; + } + } +protected: + /** + * @brief Tests whether the specified flag is set in method's compilation + * flags. * - * The default value 25 means that the buffer will grow by 25% each - * allocation: - * i.e. if the first size passed to #init() was 32, the allocations - * will be: 32 ; 40 (=32+32*0.25) ; 50 (=40+50*0.25) etc. + * If \c flag is a set of flags, then checks whether any of the flags + * is set. + * @see InfoBlock#get_flags */ - static const unsigned GROW_RATE = 25; -}; - -/** - * @brief Info used to identify a native instruction for patching. - * - * An instance of CodePatchItem used for 'code patching'. The code patching - * is a process of updating a code after it has been generated. For - * example, on IA32/EM64T a native instruction 'CALL offset' specifies an - * offset to the target relative to the instruction's IP. Thus, the real - * offset can be counted only when the instruction is placed on its real - * location (in the current generation scheme - after the code layout). - * - * The CodePatchItem instance carries info needed to find a native - * instruction after its repositioning (after code layout) and also some - * other info to calculate a data to be written. - * - * #bb and #bboff are used to identify the native instruction to be - * patched, other fields hold instruction-specific info. - */ - -struct CodePatchItem { + bool is_set(unsigned flag) + { + return (m_infoBlock.get_flags() & flag); + } /** - * @brief Points to the byte code basic block, the instruction belongs - * to. + * @brief Returns command line argument for the given \c key, or \c def + * if the \c key was not specified. + * + * Normally, arguments are specified as + * + * '-Djit.\<JIT_NAME\>.arg.\<key\>=value' + * + * Implemented though Jitrino's PMF, refer to PMF docs for more info. + * @note The old-fashion -Xjit options are not processed by this method. */ - unsigned bb; - + const char* get_arg(const char* key, const char* def) + { +#ifdef _DEBUG + check_arg_has_doc(key); +#endif + if (m_pmf == NULL) { + m_pmf = &JITInstanceContext::getContextForJIT(m_hjit)->getPMF(); + m_pmfPipeline = (PMF::Pipeline*)CompilationContext::getCurrentContext()->getPipeline(); + } + return m_pmf->getStringArg(m_pmfPipeline, key, def); + } /** - * @brief An offset of the native code inside the basic block. + * @brief Returns a command-line argument interpreted as integer. */ - unsigned bboff; + int get_int_arg(const char* key, int def) + { + const char* val = get_arg(key, (const char*)NULL); + return val == NULL ? def : atoi(val); + } /** - * @brief PC of the byte code instruction. + * @brief Returns a string command-line argument. + * + * Never returns NULL, but empty constant string ("") if argument + * was not set in through the command line. */ - unsigned pc; + const char* get_arg(const char* key) + { + const char* val = get_arg(key, (const char*)NULL); + return val == NULL ? "" : val; + } /** - * @brief The real IP of the instruction. Only valid during - * gen_patch() call. + * @brief Returns a command-line argument interpreted as integer. + * @see to_bool */ - char * ip; - + bool get_bool_arg(const char* key, bool def) + { + const char* val = get_arg(key, (const char*)NULL); + if (val == NULL) { + return def; + } + return to_bool(val); + } /** - * @brief Length of native instruction. + * PMF instance to get arguments from. */ - unsigned instr_len; - + PMF * m_pmf; /** - * @brief Target pc (if applicable). + * Current filter for PMF. */ - unsigned target_pc; + PMF::HPipeline m_pmfPipeline; + /** + * @brief JIT handle. + */ + JIT_Handle m_hjit; + //********************************************************************* + //* Instrumentation, profiling + //********************************************************************* + /** + * Generates back edge counter increment. + * Does nothing is JMF_PROF_ENTRY_BE not set. + */ + void gen_prof_be(void); /** - * @brief Shows whether address to calculate from #target_pc must be - * relative to instruction's to patch address or not. - * - * @note Only applicable to #target_pc. + * @brief Pointer to method's entrances counter. + * @see JMF_PROF_ENTRY_BE */ - bool relative; - + unsigned * m_p_methentry_counter; + /** + * @brief Pointer to method's back branches counter. + * @see JMF_PROF_ENTRY_BE + */ + unsigned * m_p_backedge_counter; + /** + * @brief Threshold for method entry counter which fires recompilation + * (in synchronized recompilation mode). + */ + unsigned m_methentry_threshold; + /** + * @brief Threshold for back edges counter which fires recompilation + * (in synchronized recompilation mode). + */ + unsigned m_backedge_threshold; + /** + * @brief Profile handle to be passed to recompilation handler (in + * synchronized recompilation mode). + */ + void* m_profile_handle; /** - * @brief Address of target (if applicable). + * @brief Recompilation handler (in synchronized recompilation mode). */ - char * target_ip; + void * m_recomp_handler_ptr; /** - * @brief Offset of target. + * @brief The byte code of the method being compiled. */ - int target_offset; + unsigned char * m_bc; + JFrame * m_jframe; /** - * @brief Offset between instruction and its target. - * - * @note Only used when instruction and its target are in the same - * basic block ! - */ - unsigned target_ipoff; - + * @brief Current basic block's info. + * + * @note Only valid during code generation. + */ + BBInfo* m_bbinfo; /** - * @brief Address for data patching (used in lazy resolution scheme). + * @brief Current basic block's state. + * + * @note Only valid during code generation. */ - char * data_addr; - + BBState * m_bbstate; /** - * @brief A key for data patching (used in lazy resolution scheme). + * @brief PC of an instruction currently processed. */ - unsigned data; + unsigned m_pc; /** - * @brief \b true if this item refers to TABLESWITCH instruction - * implementation, which requires additional allocation of table. + * @brief Instruction currently being processed. */ - bool is_table_switch; -}; - - -/** - * @brief VM constants available at runtime - helper addresses, offsets, - * etc. - * - * The class acts mostly as a namespace around the constants. It's not - * supposed to create instances of the class, thus all members are static. - * - * The names are quite self-descriptive. - */ -struct VMRuntimeConsts { -public: - static char * rt_helper_throw; - static char * rt_helper_throw_out_of_bounds; - static char * rt_helper_throw_linking_exc; - static char * rt_helper_throw_npe; - static char * rt_helper_throw_div_by_zero_exc; - - static char * rt_helper_new; - static char * rt_helper_new_array; - static char * rt_helper_aastore; - - static char * rt_helper_monitor_enter; - static char * rt_helper_monitor_exit; - static char * rt_helper_monitor_enter_static; - static char * rt_helper_monitor_exit_static; - - static char * rt_helper_ldc_string; - static char * rt_helper_init_class; - static char * rt_helper_multinewarray; - static char * rt_helper_get_vtable; - static char * rt_helper_checkcast; - static char * rt_helper_instanceof; - - static char* rt_helper_ti_method_exit; - static char* rt_helper_ti_method_enter; - - static char* rt_helper_gc_safepoint; - static char* rt_helper_get_thread_suspend_ptr; - - static unsigned rt_array_length_offset; - static unsigned rt_suspend_req_flag_offset; - -protected: + const JInst * m_curr_inst; + /** - * @brief Noop. + * @brief Method's info block. */ - VMRuntimeConsts(void) {}; -private: + MethodInfoBlock m_infoBlock; + /** - * @brief Disallow copying. + * @brief Method's native stack layout. */ - VMRuntimeConsts(const VMRuntimeConsts&); + StackFrame m_stack; /** - * @brief Disallow copying. + * @brief Global register allocation. + * + * m_ra[local index] contains a register globally allocated for the + * local variable or ar_x. + */ + vector<AR> m_ra; + /** + * 'Static' types for local variables. + * + * A variable has static type if it's used as this type only (e.g. only + * ISTORE and ILOAD are performed). If a local variable slot is used + * as more than one type (e.g. both ASTORE_0 and DSTORE_0 exist) then + * the static type is #jvoid. + * + * The size of the array is equal to the number of local variables. */ - const VMRuntimeConsts& operator=(const VMRuntimeConsts&); + vector<jtype> m_staticTypes; + /** + * @brief Numbers of def operations of local variables. + */ + vector<unsigned> m_defs; // [num_locals] + /** + * @brief Numbers of use operations of local variables. + */ + vector<unsigned> m_uses; // [num_locals] + /** + * @brief Mapping between input arguments and local variables they + * map to. + */ + vector<int> m_argids; // [m_argSlots]; + /** + * @brief Number of slots occupied by input args of the method. + */ + unsigned m_argSlots; + /** + * @brief The bitset shows whether a register (by its index) was + * globally allocated or not. + * + * <code> + * <pre> + * AR ar = ... + * if (m_global_rusage[ar_idx(ar)]) { + * printf("%s allocated globally", to_str(ar).c_str()); + * } + * </pre> + * </code> + */ + bitset<ar_num> m_global_rusage; + /** + * @brief CallSig instance for method being compiled. + */ + CallSig m_ci; + /** + * @brief A GR register used to make stack frame for the compiled + * method. + * + * Currently, only #bp is allowed here. In future, it's possible to + * implement #sp-based stack frame. + */ + AR m_base; + + /** + * @brief Current stack depth. + * + * For sp-based frame, to track changes of depth of native stack. + */ + unsigned m_depth; + /** + * @brief Maximum value for #m_depth. + */ + unsigned m_max_native_stack_depth; + /** + * @brief Compilation id for the method being compiled. + * + * It's a simple sequential counter for compilation requests came + * through the Jitrino.JET. + * Technically speaking, not equal to the number of compiled methods + * as some methods may be rejected (seen, but not compiled). + */ + unsigned m_methID; + }; + }}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_arith.cpp vm/jitrino/src/jet/cg_arith.cpp new file mode 100644 index 0000000..3d05050 --- /dev/null +++ vm/jitrino/src/jet/cg_arith.cpp @@ -0,0 +1,433 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Arithmetic, conversion and comparison routines. + */ + +#include "cg.h" +#include "arith_rt.h" + +namespace Jitrino { +namespace Jet { + +static int log2(int val) +{ + if (val == 0) return -1; + for (unsigned i=0; i<31; i++) { + if (val&1) { + return val == 1 ? (int)i : -1; + } + val >>= 1; + } + return 31; +} + + +static ALU to_alu(JavaByteCodes opc) +{ + switch(opc) { + case OPCODE_IADD: return alu_add; + case OPCODE_ISUB: return alu_sub; + case OPCODE_IMUL: return alu_mul; + case OPCODE_IOR: return alu_or; + case OPCODE_IXOR: return alu_xor; + case OPCODE_IAND: return alu_and; + case OPCODE_IDIV: return alu_div; + case OPCODE_IREM: return alu_rem; + case OPCODE_ISHL: return alu_shl; + case OPCODE_ISHR: return alu_sar; + case OPCODE_IUSHR: return alu_shr; + default: + break; + } + assert(false); + return (ALU)0; +} + +void CodeGen::gen_iinc(unsigned idx, int value) +{ + Val& var = vlocal(i32, idx, false); + rlock(var); + vunref(i32, var); + alu(alu_add, var.as_opnd(), value); + runlock(var); +} + +bool CodeGen::gen_a_f(JavaByteCodes op, jtype jt) +{ + if (op != OPCODE_IADD && op != OPCODE_ISUB && + op != OPCODE_IMUL && op != OPCODE_IDIV) { + return false; + } + + bool is_dbl = jt == dbl64; + unsigned v1_depth = is_dbl ? 2 : 1; + const Val& v1 = m_jframe->dip(v1_depth); + const Val& v2 = m_jframe->dip(0); + if (v1.is_imm() && v2.is_imm()) { + if (is_dbl) { + double res = rt_h_dbl_a(v1.dval(), v2.dval(), op); + vpop(); + vpop(); + vpush(Val(res)); + } + else { + float res = rt_h_flt_a(v1.fval(), v2.fval(), op); + vpop(); + vpop(); + vpush(Val(res)); + } + return true; + } // if v1.is_imm() && v2.is_imm() + + const Val& val1 = vstack(v1_depth, !(v1.is_reg() && rrefs(v1.reg()))); + rlock(val1); + if (v2.is_imm()) { + //TODO - can optimize a bit for is_caddr() case. + vswap(0); + } + assert(v2.is_mem() || v2.is_reg()); + rlock(v2); + + AR rres = valloc(jt); + Opnd reg(jt, rres); + mov(reg, val1.as_opnd()); + alu(to_alu(op), reg, v2.as_opnd()); + + runlock(v2); + runlock(val1); + vpop(); + vpop(); + vpush(reg); + return true; +} + +bool CodeGen::gen_a_i32(JavaByteCodes op) +{ + Val& v2 = m_jframe->dip(0); + if (op == OPCODE_IMUL && v2.is_imm()) { + assert(!vis_imm(1)); // must be handled in gen_a_generic() + if (v2.ival() == 0) { + // x*0 == 0 + vpop(); + vpop(); + gen_push((int)0); + return true; + } + if (v2.ival() == 1) { + // x*1 == x - nothing to do + vpop(); + //vpop(jt); + vpush(jt); == leaving v1 on stack + return true; + } + int l2 = log2(v2.ival()); + if (l2 != -1) { + // x*<pow_of_2> => replace by shift left + // Force the item to be on register + Val& v = vstack(1, !vis_reg(1)); + Val r; + if (rrefs(v.reg()) != 1) { + // If there are several references on the item, then make a + // copy + rlock(v); + r = Val(i32, valloc(i32)); + do_mov(r, v); + runlock(v); + } + else { + r = v; + } + assert(r.is_reg() && rrefs(r.reg())<=1); + alu(alu_shl, r.as_opnd(), Opnd(l2)); + vpop(); vpop(); + vpush(r); + return true; + } + } + return false; +} + +bool CodeGen::gen_a_generic(JavaByteCodes op, jtype jt) +{ + if (op == OPCODE_INEG) { + return false; // later + } + if (jt == i32) { + bool v2_imm = vis_imm(0); + if (v2_imm && + (op == OPCODE_ISHL || op == OPCODE_ISHL || op == OPCODE_IUSHR)) { + // accept it + } + /*else if (v2_imm && (op == OPCODE_IMUL || op == OPCODE_IDIV)) { + // accept it + } + else if (op == OPCODE_IMUL) { + // accept it + }*/ + else if (op == OPCODE_IADD || op == OPCODE_ISUB) { + // accept it + } + else if (op == OPCODE_IOR || op == OPCODE_IAND || op == OPCODE_IXOR) { + // accept it + } + else if (vis_imm(0) && m_jframe->size()>1 && vis_imm(1)) { + // accept it + } + else { + return false; + } + } + else if (is_f(jt)) { + if (op != OPCODE_IADD && op != OPCODE_ISUB && + op != OPCODE_IMUL && op != OPCODE_IDIV) { + return false; + } + } + else { + return false; + } + + bool is_dbl = jt == dbl64; + unsigned v1_depth = is_dbl?2:1; + + if (vis_imm(v1_depth) && vis_imm(0)) { + const Val& v1 = m_jframe->dip(v1_depth); + const Val& v2 = m_jframe->dip(0); + Val res; + if (jt==dbl64) { + double d = rt_h_dbl_a(v1.dval(), v2.dval(), op); + res = Val(d); + } + else if (jt==flt32) { + float f = rt_h_flt_a(v1.fval(), v2.fval(), op); + res = Val(f); + } + else { + assert(jt==i32); + int i = rt_h_i32_a(v1.ival(), v2.ival(), op); + res = Val(i); + } + vpop(); + vpop(); + vpush(res); + return true; + } // if v1.is_imm() && v2.is_imm() + + + const Val& v1 = vstack(v1_depth, true); + Opnd res = v1.as_opnd(); + if (rrefs(v1.reg()) > 1) { + rlock(v1); + AR ar = valloc(jt); + runlock(v1); + Opnd reg(jt, ar); + mov(reg, v1.as_opnd()); + res = reg; + } + rlock(res); + rlock(v1); + const Val& v2 = m_jframe->dip(0); +/* if (false )v2. + +#ifdef _IA32_ + // on IA32 can use address in a displacement + alu(to_alu(op), v1, ar_x, (int)v2.addr()); +#else + AR addr = valloc(jobj); rlock(addr); + movp(addr, v2.addr()); + alu_mem(jt, to_alu(op), r1, addr); + runlock(addr); +#endif + } + else */ + if(v2.is_mem()) { + // Everyone can do 'reg, mem' operation + alu(to_alu(op), res, v2.as_opnd()); + } + else if(v2.is_imm() && jt==i32) { + // 'reg, imm' is only for i32 operations + alu(to_alu(op), res, v2.ival()); + } + else { + Opnd v2 = vstack(0, true).as_opnd(); + alu(to_alu(op), res, v2); + } + vpop(); + vpop(); + runlock(v1); + runlock(res); + vpush(res); + + return true; +} + +void CodeGen::gen_a(JavaByteCodes op, jtype jt) +{ + if (gen_a_platf(op, jt)) { + return; + } + + if (gen_a_generic(op, jt)) { + return; + } + + if (is_f(jt) && gen_a_f(op, jt)) { + return; + } + + if (jt == i32 && gen_a_i32(op)) { + return; + } + + unsigned stackFix = 0; + bool shft = op == OPCODE_ISHL || op == OPCODE_ISHR || op == OPCODE_IUSHR; + if (is_f(jt)) { + char * helper = NULL; + bool is_dbl = jt == dbl64; + if (op == OPCODE_INEG) { + CallSig cs(CCONV_STDCALL, jt); + stackFix = gen_stack_to_args(true, cs, 0, 1); + helper = is_dbl ? (char*)&rt_h_neg_dbl64 : (char*)&rt_h_neg_flt32; + gen_call_novm(cs, helper, 1); + runlock(cs); + } + else { + //if (m_jframe->dip(1).stype == st_imm && ) + CallSig cs(CCONV_STDCALL, jt, jt, i32); + stackFix = gen_stack_to_args(true, cs, 0, 2); + helper = is_dbl ? (char*)&rt_h_dbl_a : (char*)&rt_h_flt_a; + gen_call_novm(cs, helper, 2, op); + runlock(cs); + } + } + else if (jt==i64) { + if (op == OPCODE_INEG) { + CallSig cs(CCONV_STDCALL, jt); + stackFix = gen_stack_to_args(true, cs, 0, 1); + gen_call_novm(cs, (void*)&rt_h_neg_i64, 1); + runlock(cs); + } + else if (shft) { + CallSig cs(CCONV_STDCALL, jt, i32, i32); + stackFix = gen_stack_to_args(true, cs, 0, 2); + gen_call_novm(cs, (void*)&rt_h_i64_shift, 2, op); + runlock(cs); + } + else { + CallSig cs(CCONV_STDCALL, jt, jt, i32); + stackFix = gen_stack_to_args(true, cs, 0, 2); + gen_call_novm(cs, (void*)&rt_h_i64_a, 2, op); + runlock(cs); + } + } + else { + assert(jt==i32); + if (op == OPCODE_INEG) { + CallSig cs(CCONV_STDCALL, jt); + stackFix = gen_stack_to_args(true, cs, 0, 1); + gen_call_novm(cs, (void*)&rt_h_neg_i32, 1); + runlock(cs); + } + else if (op == OPCODE_IADD || op == OPCODE_ISUB) { + const Val& op2 = vstack(0); + vpop(); + rlock(op2); + const Val& op1 = vstack(0); + vpop(); + rlock(op1); + AR ar = valloc(i32); + Opnd reg(i32, ar); + //TODO: may eliminate additional register allocation + mov(reg, op1.as_opnd()); + alu(op == OPCODE_IADD ? alu_add : alu_sub, reg, op2.as_opnd()); + runlock(op1); + runlock(op2); + vpush(Val(i32, ar)); + return; + } + else { + CallSig cs(CCONV_STDCALL, jt, jt, i32); + stackFix = gen_stack_to_args(true, cs, 0, 2); + gen_call_novm(cs, (void*)&rt_h_i32_a, 2, op); + runlock(cs); + } + } + gen_save_ret(jt); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } +} + +void CodeGen::gen_cnv(jtype from, jtype to) +{ + if (from<i32 && to==i32) { + // no op + return; + } + char *helper = (char *) cnv_matrix_impls[from][to]; + CallSig cs(CCONV_STDCALL, from); + unsigned stackFix = gen_stack_to_args(true, cs, 0); + gen_call_novm(cs, helper, 1); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + runlock(cs); + gen_save_ret(to); +} + +void CodeGen::gen_x_cmp(JavaByteCodes op, jtype jt) +{ + if (is_f(jt)) { + char *helper; + if (jt == dbl64) { + assert(op == OPCODE_DCMPG || op == OPCODE_DCMPL); + helper = op == OPCODE_DCMPG ? + (char*)&rt_h_dcmp_g : (char*)&rt_h_dcmp_l; + } + else { + assert(op == OPCODE_FCMPG || op == OPCODE_FCMPL); + helper = op == OPCODE_FCMPG ? + (char*)&rt_h_fcmp_g : (char*)&rt_h_fcmp_l; + } + const CallSig cs(CCONV_STDCALL, jt, jt); + unsigned stackFix = gen_stack_to_args(true, cs, 0); + gen_call_novm(cs, helper, 2); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + runlock(cs); + gen_save_ret(i32); + return; + } + assert(op == OPCODE_LCMP); + char *helper = (char *)rt_h_lcmp; + static const CallSig cs(CCONV_STDCALL, i64, i64); + unsigned stackFix = gen_stack_to_args(true, cs, 0); + gen_call_novm(cs, helper, 2); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + runlock(cs); + gen_save_ret(i32); +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_br.cpp vm/jitrino/src/jet/cg_br.cpp new file mode 100644 index 0000000..581e4a5 --- /dev/null +++ vm/jitrino/src/jet/cg_br.cpp @@ -0,0 +1,275 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Code generation routines for various branches - GOTO, IF_*, + * TABLE- and LOOKUP switches, JSR and RET. + */ + +#include "compiler.h" + + +namespace Jitrino { +namespace Jet { + +/** + * @brief Maps conditional branches #JavaByteCodes to appropriate + * #ConditionMnemonic. + * + * Accepts only opcode in ranges: [OPCODE_IFEQ; OPCODE_IFLE] and + * [OPCODE_IF_ICMPEQ; OPCODE_IF_ICMPLE]. + * + * @param opcod - a byte code + * @return appropriate ConditionMnemonic + */ +static COND to_cond(JavaByteCodes opcod) +{ + if (opcod==OPCODE_GOTO) { + return cond_none; + } + unsigned cod; + if (OPCODE_IFEQ <= opcod && opcod <= OPCODE_IFLE) { + cod = opcod - OPCODE_IFEQ; + } + else { + assert(OPCODE_IF_ICMPEQ <= opcod && opcod <= OPCODE_IF_ICMPLE); + cod = opcod - OPCODE_IF_ICMPEQ; + } + + switch (cod) { + case 0: return eq; + case 1: return ne; + case 2: return lt; + case 3: return ge; + case 4: return gt; + case 5: return le; + default: + break; + } + assert(false); + return (COND)NOTHING; +} + +/** + * @brief Reverts a condition so operands in comparation may be swapped. + * + * Eg. 'op0 <= op1' may become 'op1 >= op0', which is 'lt' changed to 'gt'. + * + * Used to swap operands in IF_ICMPx operations when we have an immediate + * operand as a first operand. + */ +static COND flip(COND cond) +{ + switch(cond) { + case eq: + case ne: return cond; + case lt: return gt; + case ge: return le; + case gt: return lt; + case le: return ge; + default: + break; + } + assert(false); + return (COND)NOTHING; +} + +void Compiler::gen_goto(unsigned target) +{ + gen_bb_leave(target); + if (target < m_pc) { + // Back branch + gen_prof_be(); + gen_gc_safe_point(); + } + br(cond_none, target, m_bbinfo->start); +} + +void Compiler::gen_if(JavaByteCodes opcod, unsigned target) +{ + if (target < m_pc) { + // have back branch here + gen_prof_be(); + gen_gc_safe_point(); + } + jtype jt = i32; + if (opcod == OPCODE_IFNULL) { + opcod = OPCODE_IFEQ; + jt = jobj; + } + else if (opcod == OPCODE_IFNONNULL) { + opcod = OPCODE_IFNE; + jt = jobj; + } + OpndKind kind = m_jframe->dip(0).kind(); + bool forceReg = (kind == opnd_imm) || (jt == jobj && g_refs_squeeze); + Opnd op1 = vstack(0, forceReg).as_opnd(); + vpop(); + rlock(op1); + COND cond = to_cond(opcod); + static const Opnd zero((int)0); + if (jt == jobj && g_refs_squeeze) { + AR ar = valloc(jobj); + movp(ar, NULL_REF); + alu(alu_cmp, Opnd(jobj, ar), op1); + } + else if (opcod == OPCODE_IFEQ || opcod == OPCODE_IFNE) { + if (op1.is_reg()) { + alu(alu_test, op1, op1); + } + else { + alu(alu_cmp, op1, zero); + } + } + else { + alu(alu_cmp, op1, zero); + } + runlock(op1); + gen_bb_leave(target); + br(cond, target, m_bbinfo->start); +} + +void Compiler::gen_if_icmp(JavaByteCodes opcod, unsigned target) +{ + if (target < m_pc) { + // have back branch here + gen_prof_be(); + gen_gc_safe_point(); + } + if (opcod == OPCODE_IF_ACMPEQ) { + opcod = OPCODE_IF_ICMPEQ; + } + else if (opcod == OPCODE_IF_ACMPNE) { + opcod = OPCODE_IF_ICMPNE; + } + Opnd op2 = vstack(0).as_opnd(); + vpop(); + rlock(op2); + OpndKind kind = m_jframe->dip(0).kind(); + // 'Bad' combinations are 'm,m' and 'imm,<any, but imm>' - have to force + // an item into a register + bool forceReg = (op2.is_mem() && kind == opnd_mem) || + (op2.is_imm() && kind == opnd_imm); + Opnd op1 = vstack(0, forceReg).as_opnd(); + vpop(); + rlock(op1); + + COND cond = to_cond(opcod); + if ( (op1.is_mem() && op2.is_reg()) || op1.is_imm()) { + // here we have 'mem, reg' or 'imm, mem-or-reg' - swap them so it + // become 'reg, mem' (more efficient) or 'mem-or-reg, imm' (existent) + // operations. change the branch condition appropriately. + alu(alu_cmp, op2, op1); + cond = flip(cond); + } + else { + alu(alu_cmp, op1, op2); + } + + runlock(op1); + runlock(op2); + gen_bb_leave(target); + br(cond, target, m_bbinfo->start); +} + +void Compiler::gen_switch(const JInst & jinst) +{ + assert(jinst.opcode == OPCODE_LOOKUPSWITCH + || jinst.opcode == OPCODE_TABLESWITCH); + Opnd val = vstack(0, true).as_opnd(); + vpop(); + rlock(val); + gen_bb_leave(NOTHING); + + if (jinst.opcode == OPCODE_LOOKUPSWITCH) { + unsigned n = jinst.get_num_targets(); + for (unsigned i = 0; i < n; i++) { + Opnd key(jinst.key(i)); + unsigned pc = jinst.get_target(i); + alu(alu_cmp, val, key); + br(eq, pc, m_bbinfo->start); + } + runlock(val); + br(cond_none, jinst.get_def_target(), m_bbinfo->start); + return; + } + // + // TABLESWITCH + // + alu(alu_cmp, val, jinst.high()); + br(gt, jinst.get_def_target(), m_bbinfo->start); + + alu(alu_cmp, val, jinst.low()); + br(lt, jinst.get_def_target(), m_bbinfo->start); + + AR gr_tabl = valloc(jobj); + movp(gr_tabl, DATA_SWITCH_TABLE | m_curr_inst->pc, m_bbinfo->start); +#ifdef _EM64T_ + // On EM64T, we operate with int32 value in a register, but the + // register will be used as 64 bit in address form - have to extend + sx(Opnd(i64, val.reg()), Opnd(i32, val.reg())); +#endif + // Here, we need to extract 'index-=low()' - can pack this into + // complex address form: + // [table + index*sizeof(void*) - low()*sizeof(void*)], + // but only if low()*sizeof(void*) does fit into displacement ... + int tmp = -jinst.low()/sizeof(void*); + const int LO_BOUND = INT_MIN/(int)sizeof(void*); + const int UP_BOUND = INT_MAX/(int)sizeof(void*); + if (LO_BOUND<=tmp && tmp<=UP_BOUND) { + ld(jobj, gr_tabl, gr_tabl, -jinst.low()*sizeof(void*), + val.reg(), sizeof(void*)); + } + else { + // ... otherwise subtract explicitly, but only if the register + // is not used anywhere else + if (rrefs(val.reg()) !=0) { + Opnd vtmp(i32, valloc(i32)); + mov(vtmp, val); // make a copy of val + runlock(val); + val = vtmp; + rlock(val); + } + alu(alu_sub, val, jinst.low()); + ld(jobj, gr_tabl, gr_tabl, 0, val.reg(), sizeof(void*)); + } + runlock(val); + br(gr_tabl); +} + +void Compiler::gen_jsr(unsigned target) +{ + AR gr = valloc(jobj); + const JInst& jinst = *m_curr_inst; + movp(gr, jinst.next, m_bbinfo->start); + vpush(Val(jretAddr, gr)); + gen_bb_leave(target); + br(cond_none, target, m_bbinfo->start); +} + +void Compiler::gen_ret(unsigned idx) +{ + Opnd ret = vlocal(jretAddr, idx, false).as_opnd(); + gen_bb_leave(NOTHING); + br(ret); +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_dbg.cpp vm/jitrino/src/jet/cg_dbg.cpp new file mode 100644 index 0000000..8b18313 --- /dev/null +++ vm/jitrino/src/jet/cg_dbg.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Implementation of debugging and tracing CodeGen routines. + */ + +#include "compiler.h" +#include "trace.h" + +#ifdef _WIN32 + #include <crtdbg.h> +#endif + +namespace Jitrino { +namespace Jet { + +const CallSig CodeGen::cs_trace_arg(CCONV_STDCALL, jobj, i32, i32); + + +void CodeGen::dbg_check_mem(void) +{ +#if defined(_DEBUG) && defined(_WIN32) + static bool done = false; + if (done) { + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_WNDW); + _set_error_mode(_OUT_TO_MSGBOX); + done = true; + } + assert(_CrtCheckMemory()); +#endif +} + +void __stdcall CodeGen::dbg_trace_arg(void * val, int idx, jtype jt) +{ + assert(i8<=jt && jt<num_jtypes); + char str_value[100]; + if (jt<=i32) { + int v = *(int*)&val; + snprintf(str_value, sizeof(str_value)-1, + "%d (0x%x,'%c')", v, v, (v<32 || v>127 ? ' ' : (char)v)); + } + else if (jt==flt32) { + snprintf(str_value, sizeof(str_value)-1, "%f", *(float*)&val); + } + else if (jt==dbl64) { + snprintf(str_value, sizeof(str_value)-1, "%f", *(double*)&val); + } + else if (jt==i64) { + snprintf(str_value, sizeof(str_value)-1, "%lld", *(jlong*)&val); + } + else { + snprintf(str_value, sizeof(str_value)-1, "%p", val); + } + + if (idx == -1) { + dbg_rt("\tret=(%s)%s", jtypes[jt].name, str_value); + } + else { + dbg_rt("\targ#%d=(%s)%s", idx, jtypes[jt].name, str_value); + } +} + +void CodeGen::gen_dbg_check_stack(bool start) +{ + if (start) { + // We store SP before a code to be checked ... + st(jobj, sp, m_base, voff(m_stack.dbg_scratch())); + return; + } + // ... and check right after + AR gr = valloc(jobj); + ld(jobj, gr, m_base, voff(m_stack.dbg_scratch())); + alu(jobj, alu_cmp, gr, sp); + unsigned br_off = br(eq, 0, hint_none); + gen_dbg_rt(false, "Corrupted stack @ %s @ PC=%d", meth_fname(), m_pc); + trap(); + patch(br_off, ip()); +} + +void Compiler::gen_dbg_check_bb_stack(void) +{ + if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { + return; // empty method, nothing to do + } + // With the current code generation scheme, the depth of native stack + // at the beginning of a basic block is exactly the same and is equal + // to the stack depth right after the method prolog. + // So, this check is enforced + + alu(alu_sub, m_base, m_stack.size()); + alu(jobj, alu_cmp, m_base, sp); + unsigned br_off = br(eq, 0, hint_none); + gen_dbg_rt(false, "Corrupted stack @ %s @ BB=%d", meth_fname(), m_pc); + gen_brk(); + patch(br_off, ip(br_off), ip()); + alu(alu_add, m_base, m_stack.size()); +} + +void CodeGen::gen_dbg_rt(bool save_regs, const char * frmt, ...) +{ + char tmp_buf[1024*5], id_buf[20]; + va_list valist; + va_start(valist, frmt); + int len = vsprintf(tmp_buf, frmt, valist); + + len += snprintf(id_buf, sizeof(id_buf)-1, + "| meth_id=%u@%u", m_methID, m_pc); + + // yes, there is a kind of leak here but it's intentional: + // this is debugging only feature and methods live during the whole + // VM's life so the pointer could not be freed anyway. + char *lost = new char[len + 1]; + strcpy(lost, tmp_buf); + strcat(lost, id_buf); + if (save_regs) { push_all(); } + static const CallSig cs(CCONV_STDCALL, jobj); + call(is_set(DBG_CHECK_STACK), gr0, (void*)&dbg_rt_out, cs, 0, lost); + if (save_regs) { pop_all(); } +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_fld_arr.cpp vm/jitrino/src/jet/cg_fld_arr.cpp new file mode 100644 index 0000000..aeef9ea --- /dev/null +++ vm/jitrino/src/jet/cg_fld_arr.cpp @@ -0,0 +1,460 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Implementation of CodeGen routines for fields, statics and array + * accesses. + */ + +#include "cg.h" +#include <open/vm.h> +#include "trace.h" + +namespace Jitrino { +namespace Jet { + +void CodeGen::gen_array_length(void) +{ + Opnd arr = vstack(0, true).as_opnd(); + rlock(arr); + gen_check_null(0); + vpop(); + vpush(Val(i32, arr.reg(), rt_array_length_offset)); + runlock(arr); + // the array length is known to be non-negative, marking it as such + vstack(0, VA_NZ); +} + +void CodeGen::gen_arr_load(jtype jt) +{ + // stack: [.., aref, idx] + // If index is not immediate, then force it to register + Val& idx = vstack(0, !vis_imm(0)); + assert(idx.is_imm() || idx.is_reg()); + rlock(idx); + // Force reference on register + Val& arr = vstack(1, true); + rlock(arr); + // Runtime checks + gen_check_null(1); + gen_check_bounds(1, 0); + + vpop(); + vpop(); + // For compressed refs, the size is always 4 + unsigned size = jt==jobj && g_refs_squeeze ? 4 : jtypes[jt].size; + AR base = arr.reg(); + int disp = jtypes[jt].rt_offset + + (idx.is_imm() ? size*idx.ival() : 0); + + AR index = idx.is_imm() ? ar_x : idx.reg(); + unsigned scale = idx.is_imm() ? 0 : size; + Opnd elem(jt, base, disp, index, scale); + + if (!is_ia32() && jt==jobj && g_refs_squeeze) { + AR gr_base = valloc(jobj); + rlock(gr_base); + AR gr_ref = valloc(jobj); + rlock(gr_ref); + + Opnd where32(i32, elem.base(), elem.disp(), + elem.index(), elem.scale()); + mov(Opnd(i32, gr_ref), where32); + //sx(Opnd(jobj, gr_ref), where32); + movp(gr_base, OBJ_BASE); + Opnd obj(jobj, gr_ref); + alu(alu_add, obj, Opnd(jobj, gr_base)); + // + runlock(gr_ref); + runlock(gr_base); + // + runlock(arr); + runlock(idx); + vpush(obj); + } + else if (is_big(jt)) { + AR ar_lo = valloc(jt); + Opnd lo(jt, ar_lo); + rlock(lo); + + do_mov(lo, elem); + runlock(idx); + + AR ar_hi = valloc(jt); + Opnd hi(jt, ar_hi); + rlock(hi); + Opnd elem_hi(jt, base, disp+4, index, scale); + do_mov(hi, elem_hi); + runlock(arr); + vpush2(lo, hi); + runlock(lo); + runlock(hi); + } + else { + jtype jtm = jt < i32 ? i32 : jt; + runlock(idx); + AR ar = valloc(jtm); + Opnd val(jtm, ar); + rlock(val); + if (jt == i8) { sx1(val, elem); } + else if (jt == i16) { sx2(val, elem); } + else if (jt == u16) { zx2(val, elem); } + else { do_mov(val, elem); } + runlock(val); + runlock(arr); + vpush(val); + } +} + +void CodeGen::gen_arr_store(jtype jt) +{ + vunref(jt); + // stack: [.., aref, idx, val] + if (jt == jobj) { + static const CallSig cs_aastore(CCONV_HELPERS, jobj, i32, jobj); + unsigned stackFix = gen_stack_to_args(true, cs_aastore, 0); +#ifdef _EM64T_ + // Huh ? Do we really have another order of args here ? + AR gr = valloc(jobj); + mov(gr, cs_aastore.reg(0)); + mov(cs_aastore.reg(0), cs_aastore.reg(2)); + mov(cs_aastore.reg(2), gr); +#endif + gen_call_vm(cs_aastore, rt_helper_aastore, 3); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + runlock(cs_aastore); + return; + } + unsigned idx_depth = is_wide(jt) ? 2 : 1; + unsigned ref_depth = idx_depth + 1; + + // Force reference on register + const Val& arr = vstack(ref_depth, true); + rlock(arr); + // If index is not immediate, then force it to register + const Val& idx = vstack(idx_depth, !vis_imm(idx_depth)); + assert(idx.is_imm() || idx.is_reg()); + rlock(idx); + // + // + gen_check_null(ref_depth); + gen_check_bounds(ref_depth, ref_depth-1); + + // Where to store + AR base = arr.reg(); + int disp = jtypes[jt].rt_offset + + (idx.is_imm() ? jtypes[jt].size*idx.ival() : 0); + AR index = idx.is_imm() ? ar_x : idx.reg(); + unsigned scale = idx.is_imm() ? 0 : jtypes[jt].size; + + Opnd where(jt, base, disp, index, scale); + // If we need to perform a narrowing convertion, then have the + // item on a register. + const Val& val = vstack(0, vis_mem(0)); + rlock(val); + if (is_big(jt)) { + do_mov(where, val); + runlock(idx); + runlock(val); + Opnd where_hi(jt, base, disp+4, index, scale); + Val& val_hi = vstack(1); + rlock(val_hi); + do_mov(where_hi, val_hi); + runlock(val_hi); + } + else if (jt<i32) { + do_mov(where, val.as_opnd(jt)); + runlock(idx); + runlock(val); + } + else { + runlock(idx); + runlock(val); + do_mov(where, val); + } + + runlock(arr); + // + vpop(); + vpop(); + vpop(); +} + +void CodeGen::gen_static_op(JavaByteCodes op, jtype jt, Field_Handle fld) { + do_field_op(op, jt, fld); +} + +void CodeGen::gen_field_op(JavaByteCodes op, jtype jt, Field_Handle fld) +{ + do_field_op(op, jt, fld); +} + +void CodeGen::do_field_op(JavaByteCodes opcode, jtype jt, Field_Handle fld) +{ + bool field_op = false, get = false; // PUTSTATIC is default + unsigned ref_depth = 0; + if (opcode == OPCODE_PUTFIELD) { + field_op = true; + ref_depth = is_wide(jt) ? 2 : 1; + } + else if (opcode == OPCODE_GETFIELD) { + field_op = true; + get = true; + } + else if (opcode == OPCODE_GETSTATIC) { + get = true; + } + else { + assert(opcode == OPCODE_PUTSTATIC); + } + + if(fld == NULL) { + const JInst& jinst = *m_curr_inst; + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + } + + Opnd where; + if (field_op) { + Val& ref = vstack(ref_depth, true); + gen_check_null(ref_depth); + unsigned fld_offset = fld ? field_get_offset(fld) : 0; + where = Opnd(jt, ref.reg(), fld_offset); + } + else { + // static s + char * fld_addr = fld ? (char*)field_get_addr(fld) : NULL; + where = vaddr(jt, fld_addr); + } + rlock(where); + + // Presumption: we dont have compressed refs on IA32 and all other + // (64bits) platforms have compressed refs. + // is_ia32() check added below so on IA32 it becomes 'false' during the + // compilation, without access to g_refs_squeeze in runtime. + assert(is_ia32() || g_refs_squeeze); + + if (get) { + if (compilation_params.exe_notify_field_access) { + // Check whether VM need access notifications + + char* fld_tr_add; + char fld_tr_mask; + field_get_track_access_flag(fld, &fld_tr_add, &fld_tr_mask); + + Val fld_track_mask((int)fld_tr_mask); + + AR ar = valloc(jobj); + movp(ar, (void*)fld_tr_add); + Opnd fld_track_opnd(i32, ar, 0); + rlock(fld_track_opnd); + + alu(alu_test, fld_track_opnd, fld_track_mask.as_opnd()); + runlock(fld_track_opnd); + + unsigned br_off = br(z, 0, 0, taken); + + //JVMTI helper takes field handle, method handle, byte code location, pointer + //to reference for fields or NULL for statics + + const CallSig cs_ti_faccess(CCONV_HELPERS, jobj, jobj, i64, jobj); + rlock(cs_ti_faccess); + Val vlocation((jlong)m_pc); + + Val vfield(jobj, fld); + Val vmeth(jobj, m_method); + Val vobject = Val(jobj, NULL); + + if (field_op) { + vobject = vstack(0); + } + + gen_args(cs_ti_faccess, 0, &vfield, &vmeth, &vlocation, &vobject); + gen_call_vm(cs_ti_faccess, rt_helper_ti_field_access, cs_ti_faccess.count()); + runlock(cs_ti_faccess); + + patch(br_off, ip()); + }// end if (compilation_params.exe_notify_field_access) + + if (field_op) { + // pop out ref + vpop(); + } + if (!is_ia32() && g_refs_squeeze && jt == jobj) { + AR gr_base = valloc(jobj); + rlock(gr_base); + AR gr_ref = valloc(jobj); + rlock(gr_ref); + + Opnd where32(i32, where.base(), where.disp(), + where.index(), where.scale()); + mov(Opnd(i32, gr_ref), where32); + movp(gr_base, OBJ_BASE); + Opnd obj(jobj, gr_ref); + alu(alu_add, obj, Opnd(jobj, gr_base)); + // + runlock(gr_ref); + runlock(gr_base); + // + vpush(obj); + } + else if (jt<i32) { + AR gr = valloc(i32); + Opnd reg(i32, gr); + // + if (jt == i8) { sx1(reg, where); } + else if (jt == i16) { sx2(reg, where); } + else if (jt == u16) { zx2(reg, where); } + // + vpush(Val(i32, gr)); + } + else { + if (is_big(jt)){ + Opnd where_hi(jt, where.base(), where.disp()+4, + where.index(), where.scale()); + vpush2(where, where_hi); + } + else { + vpush(where); + } + } + runlock(where); + return; + } // if (get) + + vunref(jt); + + if (compilation_params.exe_notify_field_modification) { + // Check whether VM need access notifications + + char* fld_tr_add; + char fld_tr_mask; + field_get_track_modification_flag(fld, &fld_tr_add, &fld_tr_mask); + + Val fld_track_mask((int)fld_tr_mask); + + AR ar = valloc(jobj); + movp(ar, (void*)fld_tr_add); + Opnd fld_track_opnd(i32, ar, 0); + rlock(fld_track_opnd); + + alu(alu_test, fld_track_opnd, fld_track_mask.as_opnd()); + runlock(fld_track_opnd); + + unsigned br_off = br(z, 0, 0, taken); + + //JVMTI helper takes field handle, method handle, byte code location, pointer + //to reference for fields or NULL for statics, pointer to field value + + Val fieldVal; + Val fieldValPtr = Val(jobj, valloc(jobj)); + rlock(fieldValPtr); + int st_depth = field_op ? 0 :-1; + + if (jt != jvoid) { + // Make sure the top item is on the memory + vswap(st_depth + 1); + if (is_big(jt)) { + vswap(st_depth + 2); + } + const Val& s = vstack(st_depth + 1); + assert(s.is_mem()); + lea(fieldValPtr.as_opnd(), s.as_opnd()); + } + else { + Opnd stackTop(jobj, m_base, voff(m_stack.unused())); + lea(fieldValPtr.as_opnd(), stackTop); + } + runlock(fieldValPtr); + + const CallSig cs_ti_fmodif(CCONV_HELPERS, jobj, jobj, i64, jobj, jobj); + rlock(cs_ti_fmodif); + Val vlocation((jlong)m_pc); + + Val vfield(jobj, fld); + Val vmeth(jobj, m_method); + Val vobject = Val(jobj, NULL); + + if (field_op) { + vobject = vstack(st_depth); + } + + gen_args(cs_ti_fmodif, 0, &vfield, &vmeth, &vlocation, &vobject, &fieldValPtr); + gen_call_vm(cs_ti_fmodif, rt_helper_ti_field_modification, cs_ti_fmodif.count()); + runlock(cs_ti_fmodif); + + patch(br_off, ip()); + }// end if (compilation_params.exe_notify_field_modification) + + + if (!is_ia32() && g_refs_squeeze && jt == jobj && vis_imm(0)) { + const Val& s = m_jframe->dip(0); + unsigned ref = (unsigned)(int_ptr)((const char*)s.pval() - OBJ_BASE); + Opnd where32(i32, where.base(), where.disp(), + where.index(), where.scale()); + mov(where32, Opnd(ref)); + } + else if (!is_ia32() && g_refs_squeeze && jt == jobj) { + // have the reference on a register + Val& s0 = vstack(0, true); + rlock(s0); + // compress the reference + AR tmp = valloc(jobj); + void * inv_base = (void*)-(int_ptr)OBJ_BASE; + movp(tmp, inv_base); + alu(alu_add, Opnd(jobj, tmp), s0.as_opnd()); + // store the resulting int32 + Opnd where32(i32, where.base(), where.disp(), + where.index(), where.scale()); + mov(where32, Opnd(jobj, tmp)); //s0.as_opnd(i32)); + runlock(s0); + } + else if (jt<i32) { + // No need to unref() - we just can't have jt()<i32 on the stack + Val& val = vstack(0, vis_mem(0)); + assert(val.jt() == i32); + do_mov(where, val.as_opnd(jt)); + } + else { + vunref(jt, where); + Val& val = vstack(0, vis_mem(0)); + do_mov(where, val); + if (is_big(jt)) { + Opnd where_hi(jt, where.base(), where.disp()+4, + where.index(), where.scale()); + vunref(jt, where_hi); + Opnd val_hi = vstack(1, vis_mem(1)).as_opnd(); + do_mov(where_hi, val_hi); + } + } + + runlock(where); + + + vpop(); // pop out value + if (field_op) { + vpop(); // pop out ref + } +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_ia32.cpp vm/jitrino/src/jet/cg_ia32.cpp index a025a01..1e2fb5d 100644 --- vm/jitrino/src/jet/cg_ia32.cpp +++ vm/jitrino/src/jet/cg_ia32.cpp @@ -14,2714 +14,84 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.6.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ #include "compiler.h" -#include "arith_rt.h" #include "trace.h" -#include "cg_ia32.h" -#include "stats.h" -#include <limits.h> #include <malloc.h> +#include <memory.h> +#include <assert.h> +#include <stdlib.h> -#include <open/vm.h> - -#include <jit_runtime_support.h> -#include <jit_intf.h> - -#include <stdarg.h> -#include "jni_types.h" +#include <jit_import.h> +#include "enc_ia32.h" /** * @file - * @brief Codegenerator's routines specific for IA32/EM64T. + * @brief CodeGen routines implementations specific for IA-32 and Intel 64. */ - + namespace Jitrino { namespace Jet { -const TypeInfo typeInfo[num_jtypes] = -{ - { OpndKind_GPReg, OpndSize_8, 1, Mnemonic_MOV, }, // i8 - { OpndKind_GPReg, OpndSize_16, 2, Mnemonic_MOV }, // i16 - { OpndKind_GPReg, OpndSize_16, 2, Mnemonic_MOV }, // u16 - { OpndKind_GPReg, OpndSize_32, 4, Mnemonic_MOV }, // i32 - { OpndKind_GPReg, OpndSize_32, 8, Mnemonic_MOV }, // i64 - { OpndKind_XMMReg, OpndSize_32, 4, Mnemonic_MOVSS}, // flt32 - { OpndKind_XMMReg, OpndSize_64, 8, Mnemonic_MOVQ}, // dbl64 - { OpndKind_GPReg, OpndSize_32, 4, Mnemonic_MOV}, // jobj - { OpndKind_Null, OpndSize_Null, 0, Mnemonic_NOP}, // jvoid - { OpndKind_GPReg, OpndSize_32, 4, Mnemonic_MOV}, // jretAddr -}; - -/** - * @brief 32-bit integer constant, with value of zero. - */ -static const EncoderBase::Operand Imm32_0(OpndSize_32, 0); -/** - * @brief 32-bit integer constant, with value of minus one. - */ -static const EncoderBase::Operand Imm32_m1(OpndSize_32, -1); -/** - * @brief 8-bit integer constant, specifies size of one stack slot. - */ -static const EncoderBase::Operand Imm8_StackSlot(OpndSize_8, - STACK_SLOT_SIZE); -/** - * @brief 8-bit integer constant, specifies size of 2 stack slots. - */ -static const EncoderBase::Operand Imm8_StackSlotX2(OpndSize_8, - STACK_SLOT_SIZE*2); -/** - * @brief 8-bit integer constant, specifies size of 3 stack slots. - */ -static const EncoderBase::Operand Imm8_StackSlotX3(OpndSize_8, - STACK_SLOT_SIZE*3); -/** - * @brief Points to the top of native stack, '[ESP]'. - */ -static const EncoderBase::Operand StackTop32(OpndSize_32, RegName_ESP, 0); -/** - * @brief Points to an integer item next to native stack top, - * '[ESP + stack_slot_size]'. - */ -static const EncoderBase::Operand Stack32_1(OpndSize_32, RegName_ESP, - STACK_SLOT_SIZE); -/** - * @brief Handy definition of 32bit integer as Encoder's operand. - */ -#define MK_IMM32(value) EncoderBase::Operand(OpndSize_32, (int)(value)) -/** - * @brief Handy definition of 16bit integer as Encoder's operand. - */ -#define MK_IMM16(value) EncoderBase::Operand(OpndSize_16, (short)(value)) -/** - * @brief Handy definition of 32bit memory location as Encoder's operand. - */ -#define MK_MEM32(base, off) EncoderBase::Operand(OpndSize_32, (base), (off)) - -/** - * @brief Constant value to be used for CMOVcc operations. - */ -static const unsigned g_1 = 1; - -void Compiler::gen_dbg_rt_out(const char *frmt, ...) -{ - char buf[1024 * 5]; - va_list valist; - va_start(valist, frmt); - int len = vsnprintf(buf, sizeof(buf)-1, frmt, valist); - // The pointer get lost and can not be freed - this is intentional, - // as the method's lifetime usually is the same as VM's lifetime. - char *lost = new char[len + 1]; - strcpy(lost, buf); - const int esp_idx = getRegIndex(RegName_ESP); - const int num_gp_regs = 8; - for (int i=0; i<num_gp_regs; i++) { - if (i == esp_idx) { - continue; - } - voper(Mnemonic_PUSH, getRegName(OpndKind_GPReg, OpndSize_32, i)); - } - voper(Mnemonic_PUSH, MK_IMM32(lost)); - voper(Mnemonic_MOV, RegName_EAX, MK_IMM32(&rt_dbg)); - voper(Mnemonic_CALL, RegName_EAX); - for (int i=num_gp_regs-1; i>=0; i--) { - if (i == esp_idx) { - continue; - } - voper(Mnemonic_POP, getRegName(OpndKind_GPReg, OpndSize_32, i)); - } -} - -/** - * @brief Maps conditional branches JavaByteCodes to appropriate - * ConditionMnemonic. - * - * Accepts only opcode in ranges: [OPCODE_IFEQ; OPCODE_IFLE] and - * [OPCODE_IF_ICMPEQ; OPCODE_IF_ICMPLE]. - * - * @param opcod - a byte code - * @return appropriate ConditionMnemonic - */ -static ConditionMnemonic map_cc(JavaByteCodes opcod) -{ - unsigned cod; - if (OPCODE_IFEQ <= opcod && opcod <= OPCODE_IFLE) { - cod = opcod - OPCODE_IFEQ; - } - else { - assert(OPCODE_IF_ICMPEQ <= opcod && opcod <= OPCODE_IF_ICMPLE); - cod = opcod - OPCODE_IF_ICMPEQ; - } - - switch (cod) { - case 0: - return ConditionMnemonic_E; - case 1: - return ConditionMnemonic_NE; - case 2: - return ConditionMnemonic_L; - case 3: - return ConditionMnemonic_GE; - case 4: - return ConditionMnemonic_G; - case 5: - return ConditionMnemonic_LE; - default: - break; - } - assert(false); - return (ConditionMnemonic) -1; -} - -void Compiler::gen_prolog(const::std::vector < jtype > &args) -{ - if (m_infoBlock.get_flags() & DBG_TRACE_EE) { - gen_dbg_rt_out("entering: %s", m_fname); - } - if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { - // Empty method, nothing to do; the same is in gen_return(); - - // So even don't try to do root set enum, regardless of number of - // locals and stack size - m_infoBlock.set_flags(m_infoBlock.get_flags() | JMF_EMPTY_RS); - if (m_infoBlock.get_flags() & DBG_BRK) { - gen_dbg_brk(); - } - return; - } - - if (m_infoBlock.get_flags() & JMF_PROF_ENTRY_BE) { - voper(Mnemonic_INC, MK_MEM32(RegName_Null, (int)m_p_methentry_counter)); - } - - voper(Mnemonic_PUSH, RegName_EBX); - voper(Mnemonic_PUSH, RegName_ESI); - voper(Mnemonic_PUSH, RegName_EDI); - voper(Mnemonic_PUSH, RegName_EBP); - voper(Mnemonic_MOV, REG_BASE, RegName_ESP); - voper(Mnemonic_MOV, RegName_EDX, RegName_ESP); - - if (m_infoBlock.get_flags() & JMF_ALIGN_STACK) { - voper(Mnemonic_SUB, RegName_ESP, EncoderBase::Operand(OpndSize_32, 7)); - voper(Mnemonic_AND, RegName_ESP, EncoderBase::Operand(OpndSize_32, ~7)); - voper(Mnemonic_PUSH, REG_BASE); - voper(Mnemonic_MOV, REG_BASE, RegName_ESP); - } - - // - // @ this point, EDX holds an 'old' ESP which point to the saved EBP - // - - // - // allocate stack frame - // - unsigned frameSize = m_stack.size() * SLOT_SIZE; - const unsigned PAGE_SIZE = 0x1000; - unsigned pages = frameSize / PAGE_SIZE; - // Here is pretty rare case, though still need to be proceeded: - // When we allocate a stack frame of size more than one page - // then the memory page(s) may not be accessible and even not - // allocated. - // A direct access to such page during 'REP STOS' raises 'access - // violation'. To avoid the problem we need simply probe (make read - // access) to the pages sequentially. In response on read-access to - // inaccessible page, the OS grows up the stack, so pages become - // accessible. - // - if (pages>5) { - /* - MOV EAX, pages - XOR ECX, ECX - _tryit: - TEST [esp+ecx], eax - SUB ECX, PAGE_SIZE - DEC EAX - JAE _tryit - */ - // The size of block with cycle about 30 bytes, and the size of - // single TEST is about 7 bytes. So it worths to use loop block - // for pages>5 - voper(Mnemonic_MOV, RegName_EAX, MK_IMM32(pages)); - voper(Mnemonic_XOR, RegName_ECX, RegName_ECX); - char * addr = ip(); - voper(Mnemonic_TEST, - EncoderBase::Operand(OpndSize_32, RegName_ESP, RegName_ECX, 1, 0), - RegName_EAX); - voper(Mnemonic_SUB, RegName_ECX, MK_IMM32(PAGE_SIZE)); - voper(Mnemonic_DEC, RegName_EAX); - unsigned pid = vjcc(ConditionMnemonic_NZ); - patch_set_target(pid, addr); - } - else { - for(unsigned i=0; i<pages; i++) { - voper(Mnemonic_TEST, MK_MEM32(RegName_ESP, -(int)i*PAGE_SIZE), - RegName_EAX); - } - } - voper(Mnemonic_SUB, RegName_ESP, MK_IMM32(frameSize)); - - /* xor eax, eax */ voper(Mnemonic_XOR, RegName_EAX, RegName_EAX); - /* mov ecx, num.slots */ - voper(Mnemonic_MOV, RegName_ECX, MK_IMM32(m_stack.size())); - /* mov edi, esp */ - voper(Mnemonic_MOV, RegName_EDI, RegName_ESP); - /* rep stosd */ - vprefix(InstPrefix_REP); - voper(Mnemonic_STOS); - // - // reload input args into local vars - // - // an initial GC map, basing on the input args - ::std::vector < long > initial_map; - initial_map.resize(words(args.size())); - - unsigned offset = 0; - for (unsigned i = 0; i < args.size(); i++) { - const jtype jt = args[i]; - if (is_wide(jt)) { - if (is_big(jt)) { - EncoderBase::Operand inarg(OpndSize_32, RegName_EDX, - m_stack.in_slot(offset+1) * SLOT_SIZE); - EncoderBase::Operand local(OpndSize_32, REG_BASE, - m_stack.local(offset)* SLOT_SIZE); - voper(Mnemonic_MOV, RegName_EAX, inarg); - voper(Mnemonic_MOV, local, RegName_EAX); - - EncoderBase::Operand inarg_hi(OpndSize_32, RegName_EDX, - m_stack.in_slot(offset) * SLOT_SIZE); - EncoderBase::Operand local_hi(OpndSize_32, REG_BASE, - m_stack.local(offset+1)* SLOT_SIZE); - voper(Mnemonic_MOV, RegName_EAX, inarg_hi); - voper(Mnemonic_MOV, local_hi, RegName_EAX); - } - else { - EncoderBase::Operand inarg(OpndSize_64, RegName_EDX, - m_stack.in_slot(offset+1) * SLOT_SIZE); - EncoderBase::Operand local(OpndSize_64, REG_BASE, - m_stack.local(offset)* SLOT_SIZE); - voper(Mnemonic_MOVQ, RegName_XMM0D, inarg); - voper(Mnemonic_MOVQ, local, RegName_XMM0D); - } - offset += 2; - } - else { - EncoderBase::Operand inarg(OpndSize_32, RegName_EDX, - m_stack.in_slot(offset) * SLOT_SIZE); - EncoderBase::Operand local(OpndSize_32, REG_BASE, - m_stack.local(offset)* SLOT_SIZE); - voper(Mnemonic_MOV, RegName_EAX, inarg); - voper(Mnemonic_MOV, local, RegName_EAX); - if (jt == jobj) { - initial_map[word_no(offset)] = - initial_map[word_no(offset)] | (1 <<bit_no(offset)); - } - ++offset; - } - } - - for (unsigned i = 0; i < initial_map.size(); i++) { - voper(Mnemonic_MOV, - MK_MEM32(REG_BASE, SLOT_SIZE*(m_stack.info_gc_locals()+i)), - MK_IMM32(initial_map[i])); - } - - // - // Ok, now everything is ready, may call VM/whatever, if necessary - // - if (m_infoBlock.get_flags() & JMF_PROF_SYNC_CHECK) { - /* - XOR EAX, EAX - CMP [meth_entry_counter], meth_entry_threshold - CMOVAE EAX, [1] - CMP [back_edge_counter], back_edge_threshold - CMOVAE EAX, [1] - TEST EAX, EAX - JZ _cont - MOV [meth_entry_counter], 0 - MOV [back_edge_counter], 0 - PUSH profile_handle - CALL recomp - JMP _cont - */ - voper(Mnemonic_XOR, RegName_EAX, RegName_EAX); - voper(Mnemonic_CMP, MK_MEM32(RegName_Null, (int)m_p_methentry_counter), - MK_IMM32(m_methentry_threshold)); - voper(Mnemonic_CMOVAE, RegName_EAX, MK_MEM32(RegName_Null, (int)&g_1)); - voper(Mnemonic_CMP, MK_MEM32(RegName_Null, (int)m_p_backedge_counter), - MK_IMM32(m_backedge_threshold)); - voper(Mnemonic_CMOVAE, RegName_EAX, MK_MEM32(RegName_Null, (int)&g_1)); - voper(Mnemonic_TEST, RegName_EAX, RegName_EAX); - unsigned pid = vjcc(ConditionMnemonic_Z, InstPrefix_HintTaken); - // Zero out both the counters - //voper(Mnemonic_MOV, MK_MEM32(RegName_Null, (int)m_p_methentry_counter), - // Imm32_0); - //voper(Mnemonic_MOV, MK_MEM32(RegName_Null, (int)m_p_backedge_counter), - // Imm32_0); - gen_call_vm(m_recomp_handler_ptr, 1, m_profile_handle); - patch_set_target(pid, ip()); - } - - // JVMTI method_enter helper - uncomment after bug #XXX get fixed. - //if (compilation_params.exe_notify_method_entry) { - // if (rt_helper_ti_method_enter == NULL) { - // rt_helper_ti_method_enter = (char *) - // vm_get_rt_support_addr(VM_RT_JVMTI_METHOD_ENTER_CALLBACK); - // } - // voper(Mnemonic_PUSH, MK_IMM32(m_method)); - // vcall(rt_helper_ti_method_enter); - //} - - if (m_java_meth_flags & ACC_SYNCHRONIZED) { - char * helper; - if (method_is_static(m_method)) { - /* push klass */ voper(Mnemonic_PUSH, MK_IMM32(m_klass)); - helper = rt_helper_monitor_enter_static; - } - else { - /* push this */ voper(Mnemonic_PUSH, vmlocal(jobj, 0)); - helper = rt_helper_monitor_enter; - } - voper(Mnemonic_MOV, RegName_EAX, MK_IMM32(helper)); - voper(Mnemonic_CALL, RegName_EAX); - } - if (m_infoBlock.get_flags() & DBG_BRK) { - gen_dbg_brk(); - } -} - -void Compiler::gen_return(jtype retType) -{ - if (m_infoBlock.get_flags() & DBG_TRACE_EE) { - gen_dbg_rt_out("exiting : %s", m_fname); - } - - if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { - // empty method, nothing to do; the same is in gen_prolog(); - // TODO: need to check and make sure whether it's absolutely legal - // to bypass monitors on such an empty method - // TODO2: this op9n bypasses JVMTI notifications - fixit - if (m_infoBlock.get_in_slots() == 0) { - voper(Mnemonic_RET); - } - else { - voper(Mnemonic_RET, - MK_IMM16(m_infoBlock.get_in_slots()*STACK_SLOT_SIZE)); - } - if (retType != jvoid) { - vpop(retType); - } - m_jframe->clear_stack(); - return; - } - - if (m_java_meth_flags & ACC_SYNCHRONIZED) { - if (m_java_meth_flags & ACC_STATIC) { - gen_call_vm(rt_helper_monitor_exit_static, 1, m_klass); - } - else { - // As we don not use gen_call_vm(), then 'manually' update the - // stack info. Don't care about local vars, as the method is - // about to exit anyway - gen_gc_stack(); - gen_mem(MEM_TO_MEM|MEM_STACK|MEM_UPDATE); - // - // show the 'this' incoming argument, as the local vars could be - // overwritten - // - /* - mov edx, [ebp] - mov edx, [edx+m_stack.in_slot(0)] - push edx - */ - if (m_infoBlock.get_flags() & JMF_ALIGN_STACK) { - voper(Mnemonic_MOV, RegName_EDX, MK_MEM32(REG_BASE, 0)); - } - else { - voper(Mnemonic_MOV, RegName_EDX, REG_BASE); - } - voper(Mnemonic_MOV, RegName_EDX, - MK_MEM32(RegName_EDX, m_stack.in_slot(0) * SLOT_SIZE)); - voper(Mnemonic_PUSH, RegName_EDX); - vcall(rt_helper_monitor_exit); - } - } - //XXX - uncomment after the bug#XXXX get fixed - //if (compilation_params.exe_notify_method_exit) { - // jtype args[1] = {m_jframe->top()}; - // gen_stack_to_args(false, 1, args); - // gen_call_vm(rt_helper_ti_method_exit, 1, m_method); - //} - - if (is_f(retType)) { - if (!vstack_swapped(0)) { - vstack_swap(0); - } - voper(Mnemonic_FLD, retType == dbl64 ? RegName_FP0D : RegName_FP0S, - vmstack(0)); - } - else if (retType != jvoid) { - if (vstack_swapped(0)) { - voper(Mnemonic_MOV, RegName_EAX, vstack_mem_slot(0)); - } - else { - voper(Mnemonic_MOV, RegName_EAX, vstack(0)); - } - - if (retType == i64) { - if (vstack_swapped(1)) { - voper(Mnemonic_MOV, RegName_EDX, vstack_mem_slot(1)); - } - else { - voper(Mnemonic_MOV, RegName_EDX, vstack(1)); - } - } - } - - if (m_infoBlock.get_flags() & JMF_ALIGN_STACK) { - voper(Mnemonic_MOV, RegName_ESP, MK_MEM32(REG_BASE, 0)); - } - else { - voper(Mnemonic_MOV, RegName_ESP, REG_BASE); - } - voper(Mnemonic_POP, RegName_EBP); - voper(Mnemonic_POP, RegName_EDI); - voper(Mnemonic_POP, RegName_ESI); - voper(Mnemonic_POP, RegName_EBX); - - if (m_infoBlock.get_in_slots() == 0) { - voper(Mnemonic_RET); - } - else { - voper(Mnemonic_RET, - MK_IMM16(m_infoBlock.get_in_slots() * STACK_SLOT_SIZE)); - } - if (retType != jvoid) { - vpop(retType); - } - m_jframe->clear_stack(); -} - -void Compiler::gen_ldc(void) -{ - jtype jtyp = to_jtype(class_get_const_type( - m_klass, (unsigned short)m_curr_inst->op0)); - if (jtyp != jobj) { // if not loading String - const void * p = class_get_const_addr(m_klass, m_curr_inst->op0); - assert( p ); - if (jtyp == dbl64 || jtyp == flt32) { - gen_push(jtyp, p); - } - else if(jtyp == i64) { - gen_push(*(jlong*)p ); - } - else if( jtyp == i32) { - gen_push(*(int*)p ); - } - else if(jtyp == u16) { - gen_push(*(unsigned short*)p); - } - else if(jtyp == i16) { - gen_push(*(short*)p); - } - else { - assert(jtyp == i8); - gen_push(*(char*)p); - } - return; - } - assert(m_curr_inst->opcode != OPCODE_LDC2_W); - gen_call_vm(rt_helper_ldc_string, 2, m_curr_inst->op0, m_klass); - gen_save_ret(jobj); - m_jframe->stack_attrs(0, SA_NZ); - m_curr_bb_state->seen_gcpt = true; -} - - -void Compiler::gen_push(int lval) -{ - vpush(i32, true); - RegName r0 = vstack(0); - if (lval == 0) { - voper(Mnemonic_XOR, r0, r0); - } - else { - voper(Mnemonic_MOV, r0, EncoderBase::Operand(OpndSize_32, lval)); - } - if (lval>=0) { - m_jframe->stack_attrs(0, SA_NOT_NEG); - } -} - -void Compiler::gen_push(jlong lval) -{ - vpush(i64, true); - - unsigned h32 = hi32(lval); - unsigned l32 = lo32(lval); - - RegName r0 = vstack(0); - RegName r1 = vstack(1); - - if (h32 == 0) { - voper(Mnemonic_XOR, r1, r1); - } - else { - voper(Mnemonic_MOV, r1, MK_IMM32(h32)); - } - if (l32 == 0) { - voper(Mnemonic_XOR, r0, r0); - } - else { - voper(Mnemonic_MOV, r0, MK_IMM32(l32)); - } -} - -void Compiler::gen_push(jtype jt, const void *p) -{ - vpush(jt, true); - RegName r0 = vstack(0); - if (p == &g_dconst_0) { - // dbl64 - voper(Mnemonic_PXOR, r0, r0); - } - else if (p == &g_fconst_0) { - // flt32 - voper(Mnemonic_PXOR, getAliasReg(r0, OpndSize_64), - getAliasReg(r0, OpndSize_64)); - } - else if (NULL == p) { - // aconst_null - voper(Mnemonic_XOR, r0, r0); - } - else { - const EncoderBase::Operand mptr(typeInfo[jt].size,RegName_Null,(int)p); - if (jt == u16 || jt==i8 || jt==i16) { - voper(jt == u16 ? Mnemonic_MOVZX : Mnemonic_MOVSX, r0, mptr); - } - else { - voper(typeInfo[jt].mov, r0, mptr); - } - if (is_big(jt)) { - RegName r1 = vstack(1); - const EncoderBase::Operand mptr1(typeInfo[jt].size,RegName_Null, - (int)p + STACK_SLOT_SIZE); - voper(typeInfo[jt].mov, r1, mptr1); - } - } -} - -void Compiler::gen_pop(jtype jt, void *where) -{ - if (where != NULL) { - // this must be PUTSTATIC ? - RegName r = vstack(0); - if (jt < i32) { - r = valias(jt,r); - } - const EncoderBase::Operand mptr(typeInfo[jt].size,RegName_Null, - (int)where); - voper(typeInfo[jt].mov, mptr, r); - if (is_big(jt)) { - RegName r1 = vstack(1); - const EncoderBase::Operand mptr1(typeInfo[jt].size,RegName_Null, - (int)where + STACK_SLOT_SIZE); - voper(typeInfo[jt].mov, mptr1, r1); - } - } - vpop(jt); -} - -void Compiler::gen_pop2(void) -{ - jtype jt = m_jframe->top(); - if (is_wide(jt)) { - vpop(jt); - } - else { - vpop(jt); - assert(!is_wide(m_jframe->top())); - vpop(m_jframe->top()); - } -} - -void Compiler::gen_dup(JavaByteCodes opc) -{ - // - // Below is a bit over-complicated procedure: - // as the items on operand stack are tracked separately, then for - // a DUP_* operation an action to perform depends on which DUP_* to - // perform and which items are on the top of the stack. The complete - // procedure seems to have too many states, so a quick and easy variant - // implemented: some number (depends of DUP_*) of operand stack items - // are spilled onto a native stack, then stack slots are shuffled - // as appropriate on the native stack, and then they are loaded back to - // registers. TODO: reimplement, make more clean, avoid memory ops - // Most frequent or simple variants of DUPs are implemented directly on - // registers, without spilling out to memory. - // - -#ifdef _DEBUG - // A test JFrame, used to check that spill out-shuffling-uploading - // was performed properly. - JFrame control; - control.init(m_jframe); // make a copy of the current state - control.dup(opc); // perform an operation on operand stack -#endif - // how many slots on native stack affected (in total, after the DUP_* - // performed) - unsigned totalSlots = 0; - // a state of top of operand stack which was before the DUP_* - unsigned num_was = 0; jtype was[6]; - // a state of top of operand stack which to become after the DUP_* - unsigned num_new = 0; jtype _new[6]; - // which items were added during the the DUP_* - unsigned num_added = 0; unsigned added[2]; - - switch (opc) { - case OPCODE_DUP: - // [.. val] => [.. val, val] - { - m_jframe->dup(opc); - vsync(); - const jtype jt = m_jframe->top(); - voper(typeInfo[jt].mov, vstack(0), vstack(1)); - } - break; - case OPCODE_DUP_X1: - // [..., value2, value1] => [.. value1, value2, value1] - totalSlots = 3; - num_added = 1; added[0] = 0; - num_was = 2; was[0] = m_jframe->top(1); was[1] = m_jframe->top(0); - num_new = 3; _new[0] = was[1]; _new[1] = was[0]; _new[2] = was[1]; - break; - case OPCODE_DUP_X2: - // [.. value2.64, value1] => [.. value1, value2.64, value1] - /* - pop op1 ; op1 <= value1 - movSD xmm0, [esp] ; xmm0 <= value2.64 - ; >> add esp, 8 + push op1 + sub esp, 8 : - mov [esp+4], op1 - sub esp, 4 - ; << - movSD [esp], xmm0 - push op1 - */ - // Form 1: - // .. value3, value2, value1 => value1, value3, value2, value1 - // Form 2: - // .. value2, value1 => ..value1, value2, value1 - totalSlots = 4; - num_added = 1; added[0] = 0; - if (is_wide(m_jframe->top(1))) { - // Form 2 - num_was = 2; was[0] = m_jframe->top(2); was[1] = m_jframe->top(0); - num_new = 3; _new[0] = was[1]; _new[1] = was[0]; _new[2] = was[1]; - } - else { - num_was = 3; was[0] = m_jframe->top(2); was[1] = m_jframe->top(1); - was[2] = m_jframe->top(0); - num_new = 4; _new[0] = m_jframe->top(0); _new[1] = m_jframe->top(2); - _new[2] = m_jframe->top(1); _new[3] = m_jframe->top(0); - } - break; - case OPCODE_DUP2: - // [.. value.64] => [.. value.64, value.64] - // [.. value.32.1, value32.0] => [.. value.32.1, value32.0, - // value.32.1, value32.0] - if (m_jframe->top() == dbl64) { - m_jframe->dup(opc); - vsync(); - const jtype jt = m_jframe->top(); - voper(typeInfo[jt].mov, vstack(0), vstack(2)); - } - else { - totalSlots = 4; - num_added = 2; added[0] = 1; added[1] = 0; - if (is_wide(m_jframe->top())) { - num_was = 1; was[0] = m_jframe->top(0); - num_new = 2; _new[0] = _new[1] = was[0]; - } - else { - num_was = 2; was[0] = m_jframe->top(1); - was[1] = m_jframe->top(0); - num_new = 4; _new[0] = m_jframe->top(1); - _new[1] = m_jframe->top(0); - _new[2]=m_jframe->top(1); - _new[3] = m_jframe->top(0); - } - } - break; - case OPCODE_DUP2_X1: - // [.. value2, value1.64] => [.. value1.64, value2, value1.64] - /* - movsd sse0, [esp] - mov eax, [esp+slotSize*2] - sub esp, slotSize*2 ; before: 3 slots - accupied ; after: 5 slots - movsd esp+3*slotSize, xmm0 - mov esp+2*slotSize, eax - movsd [esp], xmm0 - */ - // value3, value2, value1 => value2, value1, value3, value2, value1 - // value2, value1 => value1, value2, value1 - totalSlots = 5; - num_added = 2; added[0] = 1; added[1] = 0; - if (is_wide(m_jframe->top())) { - num_was = 2; was[0] = m_jframe->top(2); was[1] = m_jframe->top(0); - num_new = 3; _new[0] = m_jframe->top(0); - _new[1] = m_jframe->top(2); - _new[2] = m_jframe->top(0); - } - else { - num_was = 3; was[0] = m_jframe->top(2); - was[1] = m_jframe->top(1); was[2] = m_jframe->top(0); - num_new = 5; - _new[0] = m_jframe->top(1); _new[1] = m_jframe->top(0); - _new[2]=m_jframe->top(2); _new[3] = m_jframe->top(1); - _new[4]=m_jframe->top(0); - } - break; - case OPCODE_DUP2_X2: - // [.. value2.64, value1.64] => [.. value1.64, value2.64, value1.64] - // before: 4 slots ; after: 6 slots - /* - movsd xmm0, [esp] - movsd xmm1, [esp+2*slotSize] - sub esp, 2*slotSize - movsd [esp+4*slotSize], xmm0 - movsd [esp+2*slotSize], xmm1 - movsd [esp], xmm0 - */ - totalSlots = 6; - num_added = 2; added[0] = 1; added[1] = 0; - //f1 .., value4, value3, value2, value1 ..., value2, value1, value4, - // value3, value2, value1 - //f2 .., value3, value2, value1 ..., value1, value3, value2, value1 - //f3 .., value3, value2, value1 ..., value2, value1, value3, value2, - // value1 - //f4 .., value2, value1 ..., value1, value2, value1 - if (is_wide(m_jframe->top())) { - // either f4 or f2 - if (is_wide(m_jframe->top(2))) { - // f4 - num_was = 2; was[0] = m_jframe->top(2); - was[1] = m_jframe->top(0); - num_new = 3; _new[0] = was[1]; _new[1] = was[0]; - _new[2] = was[1]; - } - else { - // f2 - num_was = 3; was[0] = m_jframe->top(3); - was[1] = m_jframe->top(2); - was[2] = m_jframe->top(0); - num_new = 4; _new[0] = was[2]; _new[1] = was[0]; - _new[2] = was[1]; _new[3] = was[2]; - } - } - else { - if (is_wide(m_jframe->top(2))) { - // f3 - num_was = 3; was[0] = m_jframe->top(2); - was[1] = m_jframe->top(1); - was[2] = m_jframe->top(0); - num_new = 5; _new[0] = was[1]; _new[1] = was[2]; - _new[2] = was[0]; _new[3] = was[1]; - _new[4] = was[2]; - } - else { - // f1 - num_was = 4; - was[0] = m_jframe->top(3); was[1] = m_jframe->top(2); - was[2] = m_jframe->top(1); was[3] = m_jframe->top(0); - num_new = 6; - _new[0] = m_jframe->top(1); _new[1] = m_jframe->top(0); - _new[2] = m_jframe->top(3); _new[3] = m_jframe->top(2); - _new[4] = m_jframe->top(1); _new[5] = m_jframe->top(0); - } - } - break; - case OPCODE_SWAP: - { - jtype j0 = m_jframe->top(); - jtype j1 = m_jframe->top(1); - // The further pop/push wipes out the correct state, as - // JFrame::push presumes that items go to registers, so we - // need make sure that both the items are indeed on registers - // before any action. - RegName r0 = vstack(0); - RegName r1 = vstack(1); - - vpop(j0); - vpop(j1); - vpush(j0, false); - vpush(j1, true); - if (is_f(j0) != is_f(j1)) { - // they are on the different vstacks, - // thus they're already on different regs - - // nothing to do - } - else if (is_f(j0)) { - EncoderBase::Operand scratch = vlocal(j0, -1, false, true); - voper(typeInfo[j0].mov, scratch, r0); - voper(typeInfo[j0].mov, r0, r1); - voper(typeInfo[j0].mov, r1, scratch); - } - else { - voper(Mnemonic_XCHG, r0, r1); - } - } - break; - default: - assert(false); - } - - if (totalSlots) { - voper(Mnemonic_SUB, RegName_ESP, MK_IMM32(num_added*STACK_SLOT_SIZE)); - gen_stack_to_args(true, num_was, was); - const EncoderBase::Operand rscratch = vlocal(i32, -1, false, true); - for (unsigned i=0; i<num_added; i++) { - unsigned slot2load = added[i]; - EncoderBase::Operand slot(OpndSize_32, RegName_ESP, - slot2load*STACK_SLOT_SIZE); - EncoderBase::Operand new_slot(OpndSize_32, RegName_ESP, - (totalSlots-i-1)*STACK_SLOT_SIZE); - voper(Mnemonic_MOV, rscratch, slot); - voper(Mnemonic_MOV, new_slot, rscratch); - } - unsigned slot_off = totalSlots-1; - for (unsigned i=0; i<num_new; i++) { - jtype jt = _new[i]; - vpush(jt, true); - if (jt == dbl64) { - slot_off -= 1; - } - EncoderBase::Operands args; - if (jt!=i64) { - args.add(EncoderBase::Operand(vstack(0))); - args.add(EncoderBase::Operand(typeInfo[jt].size, RegName_ESP, - slot_off*STACK_SLOT_SIZE)); - voper(typeInfo[jt].mov, args); - } - else { - args.add(EncoderBase::Operand(vstack(1))); - args.add(EncoderBase::Operand(typeInfo[jt].size, RegName_ESP, - slot_off*STACK_SLOT_SIZE)); - voper(typeInfo[jt].mov, args); - args.clear(); - - --slot_off; - - args.add(EncoderBase::Operand(vstack(0))); - args.add(EncoderBase::Operand(typeInfo[jt].size, RegName_ESP, - slot_off*STACK_SLOT_SIZE)); - voper(typeInfo[jt].mov, args); - } - slot_off--; - } - voper(Mnemonic_ADD, RegName_ESP, MK_IMM32(totalSlots*STACK_SLOT_SIZE)); - } - -#ifdef _DEBUG - assert(m_jframe->size() == control.size()); - for (unsigned i = 0; i < control.size(); i++) { - assert(m_jframe->at(i).jt == control.at(i).jt); - } -#endif -} - -void Compiler::gen_st(jtype jt, unsigned idx) -{ - gen_gc_mark_local(idx, jt == jobj); - // the presumption is that if're defining a var, then it will - // be used soon. the presumption may be wrong and need to be checked - - // todo. for now, always requesting a register - if (is_big(jt)) { - RegName r0 = vstack(0); - RegName r1 = vstack(1); - m_jframe->st(jt, idx); - vsync(); - const EncoderBase::Operand vlo = vlocal(jt, idx, false, true); - vsync(); - voper(typeInfo[jt].mov, vlo, r0); - - ++idx; - const EncoderBase::Operand vhi = vlocal(jt, idx, true, true); - vsync(); - voper(typeInfo[jt].mov, vhi, r1); - } - else { - RegName r = vstack(0); - m_jframe->st(jt, idx); - vsync(); - const EncoderBase::Operand v = vlocal(jt, idx, false, true); - vsync(); - voper(typeInfo[jt].mov, v, r); - } -} - -void Compiler::gen_ld(jtype jt, unsigned idx) -{ - m_jframe->ld(jt,idx); - vsync(); - - RegName r = vstack(0); - const EncoderBase::Operand v = vlocal(jt, idx, false, false); - assert(m_jframe->need_update() == 0); - voper(typeInfo[jt].mov, r, v); - - if (is_big(jt)) { - const EncoderBase::Operand vhi = vlocal(jt, idx+1, true, false); - voper(typeInfo[jt].mov, vstack(1), vhi); - } -} - -void Compiler::gen_save_ret(jtype jt) -{ - assert(jt != jvoid); - vpush(jt, true); - if (is_f(jt)) { - const bool is_dbl = jt == dbl64; - voper(Mnemonic_FSTP, vmstack(0), is_dbl ? RegName_FP0D : RegName_FP0S); - m_jframe->stack_state(0, SS_SWAPPED, 0); - } - else { - if (jt==i8 || jt==i16) { - voper(Mnemonic_MOVSX, vstack(0), valias(jt, RegName_EAX)); - } - else if (jt==u16) { - voper(Mnemonic_MOVZX, vstack(0), valias(jt, RegName_EAX)); - } - else { - voper(Mnemonic_MOV, vstack(0), RegName_EAX); - } - if (is_big(jt)) { - voper(Mnemonic_MOV, vstack(1), RegName_EDX); - } - } -} - -void Compiler::gen_invoke(JavaByteCodes opcod, Method_Handle meth, - const ::std::vector<jtype> &args, jtype retType) -{ - - const unsigned slots = count_slots(args); - // where (stack depth) 'this' is stored for the method being invoked - // (if applicable) - const unsigned thiz_depth = slots - 1; - - const JInst& jinst = *m_curr_inst; - - if (args.size() != 0) { - gen_stack_to_args(true, args.size(), &args[0]); - } - gen_gc_stack(-1, true); - gen_mem(MEM_TO_MEM|MEM_STACK|MEM_VARS|MEM_UPDATE); - - const bool lazy = m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION; - - veax(); // allocate/free EAX - - if (lazy) { - gen_lazy_resolve(m_curr_inst->op0, opcod); - } - else if (meth == NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - if (opcod == OPCODE_INVOKEINTERFACE) { - if (lazy) { - vedx(); - voper(Mnemonic_PUSH, RegName_EAX); - voper(Mnemonic_PUSH, RegName_EAX); - // stack: [..., meth, meth] - vcall((void*)&method_get_offset); - // stack: [..., meth, meth] ; EAX = meth_offset - voper(Mnemonic_MOV, Stack32_1, RegName_EAX); - // stack: [..., method_offset, meth] - vcall((void*)&method_get_class); - // - voper(Mnemonic_PUSH, RegName_EAX); - //stack: [..., method_offset, meth, klass] - vcall((void*)&class_property_is_interface2); - voper(Mnemonic_TEST, RegName_EAX, RegName_EAX); - voper(Mnemonic_POP, RegName_EAX); - // stack: [..., method_offset, meth] ; EAX=klass - voper(Mnemonic_MOV, StackTop32, RegName_EAX); - // stack: [..., method_offset, klass] - // - // [taken] JNZ - go to regular INVOKEINTERFACE - // else - switch to INVOKEVIRTUAL. - // See handle_ik_meth() and OPCODE_INVOKEINTERFACE for this - // magic transmutation. - // - unsigned pid = vjcc(ConditionMnemonic_NZ, InstPrefix_HintTaken); - - voper(Mnemonic_POP, RegName_EAX); // pop out 'klass' - // stack: [..., method_offset] - - // '+1' here due to 'method_offset' - const EncoderBase::Operand thiz0(OpndSize_32, RegName_ESP, - (thiz_depth+1)*STACK_SLOT_SIZE); - - voper(Mnemonic_MOV, RegName_EAX, thiz0); - /* mov eax, [eax] */ - voper(Mnemonic_MOV, RegName_EAX, MK_MEM32(RegName_EAX, 0)); - - unsigned pid2 = vjmp8(); // jump to 'ADD eax, [esp]/CALL [eax]' - - patch_set_target(pid, ip()); // connect 'pid' to here - the - // regular INVOKEINTERFACE - // processing - // '+2' here due to 'method_offset' & 'klass' - const EncoderBase::Operand thiz(OpndSize_32, RegName_ESP, - (thiz_depth+2)*STACK_SLOT_SIZE); - voper(Mnemonic_PUSH, thiz); - // stack: [..., method_offset, klass, thiz] - vcall(rt_helper_get_vtable); - // stack: [..., method_offset] ; EAX = vtbl - patch_set_target(pid2, ip()); - voper(Mnemonic_ADD, RegName_EAX, StackTop32); - voper(Mnemonic_ADD, RegName_ESP, MK_IMM32(STACK_SLOT_SIZE)); - voper(Mnemonic_CALL, - EncoderBase::Operand(OpndSize_32, RegName_EAX, 0)); - } - else if (meth != NULL) { - // if it's invokeinterface, then first resolve it - Class_Handle klass = method_get_class(meth); - /*push klass */ voper(Mnemonic_PUSH, MK_IMM32(klass)); - const EncoderBase::Operand thiz(OpndSize_32, RegName_ESP, - (thiz_depth+1)*STACK_SLOT_SIZE); - voper(Mnemonic_PUSH, thiz); - /*call helper_get_vtable */ - gen_call_vm(rt_helper_get_vtable, 0); - // - // Method's vtable is in EAX now, stack is ready - // - // call [eax + offset-of-the-method] - eax is from the helper - unsigned offset = method_get_offset(meth); - voper(Mnemonic_CALL, MK_MEM32(RegName_EAX, offset)); - } - } - else if (opcod == OPCODE_INVOKEVIRTUAL) { - /* mov eax, [obj ref] */ - const EncoderBase::Operand thiz(OpndSize_32, RegName_ESP, - thiz_depth*STACK_SLOT_SIZE); - if (lazy) { - vedx(); // allocate/free EDX - voper(Mnemonic_PUSH, RegName_EAX); - // stack: [..., meth] - vcall((void*)&method_get_offset); - // stack: [..., meth] ; EAX = meth_offset - voper(Mnemonic_ADD, RegName_ESP, MK_IMM32(STACK_SLOT_SIZE)); - // stack: [<args>, ] ; EAX = meth_offset - voper(Mnemonic_MOV, RegName_EDX, thiz); - voper(Mnemonic_MOV, RegName_EDX, - EncoderBase::Operand(OpndSize_32, RegName_EDX, 0)); - voper(Mnemonic_ADD, RegName_EAX, RegName_EDX); - voper(Mnemonic_CALL, MK_MEM32(RegName_EAX, 0)); - } - else if (meth != NULL) { - voper(Mnemonic_MOV, RegName_EAX, thiz); - /* mov eax, [eax] */ - voper(Mnemonic_MOV, RegName_EAX, MK_MEM32(RegName_EAX,0)); - /* call [eax+offset]*/ - unsigned offset = method_get_offset(meth); - voper(Mnemonic_CALL, MK_MEM32(RegName_EAX, offset)); - } - } - else { - // - // invoke special & static - // - if (lazy) { - voper(Mnemonic_CALL, MK_MEM32(RegName_EAX, 0)); - //voper(Mnemonic_CALL, MK_MEM32(RegName_EAX, 0)); - } - else if (meth != NULL) { - void *ppmeth = method_get_indirect_address(meth); - voper(Mnemonic_CALL, MK_MEM32(RegName_Null, (int)ppmeth)); - } - } - if (retType != jvoid) { - gen_save_ret(retType); - } -} - -void Compiler::gen_if(JavaByteCodes opcod, unsigned target) -{ - if (m_next_bb_is_multiref) { - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - } - if (target < m_pc) { - // have back branch here - if (m_infoBlock.get_flags() & JMF_BBPOOLING) { - gen_gc_safe_point(); - } - if (m_infoBlock.get_flags() & JMF_PROF_ENTRY_BE) { - voper(Mnemonic_INC, MK_MEM32(RegName_Null, (int)m_p_backedge_counter)); - } - } - if (opcod == OPCODE_IFNULL) { - opcod = OPCODE_IFEQ; - } - else if (opcod == OPCODE_IFNONNULL) { - opcod = OPCODE_IFNE; - } - assert(m_jframe->dip(0).jt == i32 || m_jframe->dip(0).jt == jobj); - - //vvv an order matters ! - RegName r0 = vstack(0); - vpop(m_jframe->top()); - //^^^ - ConditionMnemonic cond; - if (opcod == OPCODE_IFEQ || opcod == OPCODE_IFNE) { - voper(Mnemonic_TEST, r0, r0); - cond = opcod == OPCODE_IFEQ ? - ConditionMnemonic_Z : ConditionMnemonic_NZ; - } - else { - voper(Mnemonic_CMP, r0, EncoderBase::Operand(OpndSize_32, 0)); - cond = map_cc(opcod); - } - if (m_next_bb_is_multiref) { - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - vjcc(target, cond, InstPrefix_Null); -}; - -void Compiler::gen_if_icmp(JavaByteCodes opcod, unsigned target) -{ - if (m_next_bb_is_multiref) { - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - } - - if (target < m_pc) { - // have back branch here - if (m_infoBlock.get_flags() & JMF_BBPOOLING) { - gen_gc_safe_point(); - } - if (m_infoBlock.get_flags() & JMF_PROF_ENTRY_BE) { - voper(Mnemonic_INC, MK_MEM32(RegName_Null, (int)m_p_backedge_counter)); - } - } - - if (opcod == OPCODE_IF_ACMPEQ) { - opcod = OPCODE_IF_ICMPEQ; - } - else if (opcod == OPCODE_IF_ACMPNE) { - opcod = OPCODE_IF_ICMPNE; - } - - assert(m_jframe->dip(0).jt == i32 || m_jframe->dip(0).jt == jobj); - assert(m_jframe->dip(1).jt == i32 || m_jframe->dip(1).jt == jobj); - - RegName r0 = vstack(0); - RegName r1 = vstack(1); - voper(Mnemonic_CMP, r1, r0); - vpop(m_jframe->top()); - vpop(m_jframe->top()); - if (m_next_bb_is_multiref) { - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - vjcc(target, map_cc(opcod), InstPrefix_Null); -}; - -void Compiler::gen_goto(unsigned target) -{ - if (m_next_bb_is_multiref) { - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - if (target < m_pc) { - // Back branch - if (m_infoBlock.get_flags() & JMF_PROF_ENTRY_BE) { - voper(Mnemonic_INC, - MK_MEM32(RegName_Null, (int)m_p_backedge_counter)); - } - if (m_infoBlock.get_flags() & JMF_BBPOOLING) { - gen_gc_safe_point(); - } - } - vjmp(target); -}; - -void Compiler::gen_gc_safe_point() -{ - if (m_curr_bb_state->seen_gcpt) { - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";; > skipping gc_safe_pt due to known GC point before\n"); - } - return; - } - m_curr_bb_state->seen_gcpt = true; - - veax(); -//#ifdef PLATFORM_POSIX - gen_call_vm(rt_helper_get_thread_suspend_ptr, 0); - voper(Mnemonic_CMP, MK_MEM32(RegName_EAX, 0), Imm32_0); -/* -#else - // This is a bit quicker, but tricky way - VM uses TIB to store - // thread-specific info, and the offset of suspend request flag is - // known, so we may directly get the flag without a need to call VM. - // On Linux, they [perhaps] use GS:[], however this depends on kernel - // version and is not guaranteed, so on Linux we call VM to obtain the - // flags' address. - vprefix(InstPrefix_FS); - voper(Mnemonic_MOV, RegName_EAX, MK_MEM32(RegName_Null, 0x14)); - voper(Mnemonic_MOV, RegName_EAX, - MK_MEM32(RegName_EAX, rt_suspend_req_flag_offset)); - voper(Mnemonic_TEST, RegName_EAX, RegName_EAX); -#endif -*/ - unsigned patch_id = vjcc(ConditionMnemonic_E, InstPrefix_HintTaken); - // - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_STACK|MEM_NO_UPDATE); - gen_gc_stack(-1, false); - vcall(rt_helper_gc_safepoint); - gen_mem(MEM_FROM_MEM|MEM_VARS|MEM_STACK|MEM_NO_UPDATE|MEM_INVERSE); - patch_set_target(patch_id, ip()); -} - -void Compiler::gen_jsr(unsigned target) -{ - // must be last instruction in BB - assert(m_pc == m_curr_bb->last_pc); - vpush(jretAddr, true); - // Always unload vars for JSR. - // todo: actually, we don't know the state *after* the JSR - // so can omit it here, but clear vars state later - after JSR - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - const BBInfo& jsrBlock = m_bbs[target]; - if (jsrBlock.ref_count > 1) { - // Several JSR call this block, need to sync stack - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - // Load address of next BB onto operand stack .. - reg_patch(m_curr_bb->next_bb, false); - voper(Mnemonic_MOV, vstack(0), Imm32_0); - // .. and jump to JSR block - vjmp(target); -} - -void Compiler::gen_ret(unsigned idx) -{ - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - voper(Mnemonic_JMP, vlocal(jretAddr, idx, false, false)); -}; - -void Compiler::gen_array_length(void) -{ - // i0 = istack(0); - // mov i0, [i0 + rt_array_length_offset] - RegName r0 = vstack(0); - voper(Mnemonic_MOV, r0, - EncoderBase::Operand(OpndSize_32, r0, rt_array_length_offset)); - vpop(jobj); - vpush(i32, true); - // the array length is known to be non-negative, marking it as such - m_jframe->stack_attrs(0, SA_NZ); -} - -void Compiler::gen_check_null(unsigned depth) -{ - const JFrame::Slot s0 = m_jframe->dip(depth); - assert(s0.jt == jobj); - if (s0.attrs() & SA_NZ) { - STATS_INC(Stats::npesEliminated,1); - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";;> skipping a null check @ depth=%d, due" - " to a known non-null attr\n", depth); - } - return; - } - - STATS_INC(Stats::npesPerformed,1); - - if (s0.swapped()) { - voper(Mnemonic_TEST, vmstack(depth), MK_IMM32(0xFFFFFFFF)); - } - else { - RegName r0 = vstack(depth); - voper(Mnemonic_TEST, r0, r0); - } - unsigned pid = vjcc(ConditionMnemonic_NZ, InstPrefix_HintTaken); - gen_call_throw(rt_helper_throw_npe, 0); - patch_set_target(pid, ip()); - m_jframe->stack_attrs(depth, SA_NZ); -} - -void Compiler::gen_check_bounds(unsigned aref_depth, unsigned index_depth) -{ - // simply requesting registers here (i.e. for LALOAD) implies - // STACK_REGS >= 3. The check can be rewritten to support less - // stack_regs, but not now. may be later. todo ? - - //const R_Opnd& rref = istack(aref_depth); - //const R_Opnd& ridx = istack(index_depth); - //M_Opnd plen(rref.reg_no(), rt_array_length_offset); - //ip( alu( ip(), cmp_opc, plen, ridx) ); - - RegName rref = vstack(aref_depth); - RegName ridx = vstack(index_depth); - EncoderBase::Operand plen(OpndSize_32, rref, rt_array_length_offset); - voper(Mnemonic_CMP, ridx, plen); - /* - cmp [istack(aref)+rt_array_length_offset], istack(index) - jl good_1 - out-of-bounds - good_1: - cmp istack(infex), 0 - jge good_2 - negative-array-index - */ - //ip( mov( ip(), rs, plen ) ); - unsigned good_1 = vjcc(ConditionMnemonic_L, InstPrefix_Null); - gen_call_throw(rt_helper_throw_out_of_bounds, 0); - // good_1: - patch_set_target(good_1, ip()); - const JFrame::Slot& sidx = m_jframe->dip(index_depth); - // TODO: seems we can eliminate the <0 check completely ? - if (sidx.attrs() & SA_NOT_NEG) { - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";;> skipping <0 check @ depth=%d, due to" - " known non-negative attr\n", index_depth); - } - } - else { - voper(Mnemonic_CMP, ridx, Imm32_0); - unsigned good_2 = vjcc(ConditionMnemonic_GE, InstPrefix_Null); - gen_call_throw(rt_helper_throw_out_of_bounds, 0); - // good_2: - patch_set_target(good_2, ip()); - } -} - -void Compiler::gen_check_div_by_zero(jtype jt, - unsigned stack_depth_of_divizor) +bool CodeGen::gen_a_platf(JavaByteCodes op, jtype jt) { - // for both must sit on a register, which implies I_STACK_REGS >= 4 - assert(m_jframe->regable(stack_depth_of_divizor)); - RegName r0 = vstack(0); - if (jt == i32) { - /*test dvsr, dvsr */ voper(Mnemonic_TEST, r0, r0); - /*[hint.taken] jnz not_zero */ - unsigned pid = vjcc(ConditionMnemonic_NE, InstPrefix_HintTaken); - /*call throw div-by-zero */ - gen_call_throw(rt_helper_throw_div_by_zero_exc, 0); - patch_set_target(pid, ip()); - return; - } - assert(jt == i64); - /* or dvsr.l32, dvsr.l32 - [no hints] jnz not_zero - or dvsr.h32, dvsr.l32 ; as dvsr.l32 is zero at this point, no - ; need to check against immediate - [hint.taken] jnz not_zero - call throw DIV-BY-ZERO - not_zero: - */ - // i0 currently hold dvsr.l32 - /*test dvsr, dvsr */ voper(Mnemonic_TEST, r0, r0); - unsigned pid = vjcc(ConditionMnemonic_NE, InstPrefix_Null); - /* - unsigned h32_depth = stack_depth_of_divizor + 1; - // here is OR, not TEST ! - if (stack_on_mem(h32_depth)) { - ip(alu(ip(), or_opc, mstack(h32_depth), i0)); - } - else { - ip(alu(ip(), or_opc, istack(h32_depth), i0)); - } - */ - RegName r1 = vstack(stack_depth_of_divizor + 1); - voper(Mnemonic_TEST, r1, r1); - unsigned pid2 = vjcc(ConditionMnemonic_NE, InstPrefix_HintTaken); - /*call throw div-by-zero */ - gen_call_throw(rt_helper_throw_div_by_zero_exc, 0); - // connect both branches to here - patch_set_target(pid, ip()); - patch_set_target(pid2, ip()); -} - - -void Compiler::gen_aload(jtype jt) -{ - /* - stack: [... array_ref, index] - pop edx ; edx <- index - pop eax ; eax <- ref - the target is [eax+edx*size + offset_of_1st_element] - mov/movsx/movzx eax, target - - */ - // i1 = aref ; i0 = idx - // item is at [i1 + i0*sizeof(elem) + offset_of_first_elem] - //const R_Opnd& i0_tmp = istack(0); - //const R_Opnd& i1_tmp = istack(1); - //M_Index_Opnd pitem(i1_tmp.reg_no(), i0_tmp.reg_no(), - // jtypes[jt].rt_offset, jtypes[jt].size); - - RegName ridx = vstack(0); - RegName rbase = vstack(1); - vpop(i32); - vpop(jobj); - vpush(jt, true); - - EncoderBase::Operand pitem(typeInfo[jt].size, rbase, ridx, - jtypes[jt].size, jtypes[jt].rt_offset); - if (jt == u16 || jt==i8 || jt==i16) { - voper(jt == u16 ? Mnemonic_MOVZX : Mnemonic_MOVSX, vstack(0), pitem); - } - else if (jt==i64) { - // cant do two simple MOVes here - one will overwrite base/index - // register - // PUSH hi32 - // '4' here as a sizeof(i64)/2 - we're fetching out the high part - // of the i64 item - EncoderBase::Operand phi(typeInfo[jt].size, rbase, ridx, - jtypes[jt].size, jtypes[jt].rt_offset+4); - voper(Mnemonic_PUSH, phi); - // MOV stack(0), lo32 - voper(typeInfo[jt].mov, vstack(0), pitem); - // POP hi32->stack(1) - voper(Mnemonic_POP, vstack(1)); - } - else { - voper(typeInfo[jt].mov, vstack(0), pitem); - } -} - -void Compiler::gen_astore(jtype jt) -{ - // the stack is: [... array_ref, index, value] - if (jt == jobj) { - static const jtype args[3] = {jobj, i32, jobj}; - gen_stack_to_args(true, 3, args); - gen_call_vm(rt_helper_aastore, 0); - return; - } - unsigned idx_depth = is_wide(jt) ? 2 : 1; - RegName ridx = vstack(idx_depth); - RegName rref = vstack(idx_depth+1); - EncoderBase::Operand pitem(typeInfo[jt].size, rref, ridx, - jtypes[jt].size, jtypes[jt].rt_offset); - RegName r0 = vstack(0); - if (jt<i32) { - r0 = valias(jt,r0); - } - voper(typeInfo[jt].mov, pitem,r0); - assert( is_big(i64) ); - if (jt == i64) { - // '4' here as a sizeof(i64)/2 - we're storing out the high part of - // the i64 item - EncoderBase::Operand phi(typeInfo[jt].size, rref, ridx, - jtypes[jt].size, jtypes[jt].rt_offset+4); - voper(Mnemonic_MOV, phi, vstack(1)); - } - vpop(jt); - vpop(i32); - vpop(jobj); - vsync(); -} - -void Compiler::gen_patch(const char *codeBlock, const CodePatchItem & cpi) -{ - - //TODO: a bit sophisticated routine. need improvements. - - assert(cpi.instr_len == 7 || cpi.instr_len == 6 || cpi.instr_len == 5 || - cpi.instr_len == 2 || cpi.instr_len == 10); - char *instr_ip = cpi.ip; - const unsigned char inst_1st_byte = *(unsigned char*)instr_ip; - - if (cpi.instr_len == 2) { - // [currently] the only case: - // 2 bytes instructions used for relative conditional jmps - assert(cpi.target_ip == NULL && cpi.target_pc == NOTHING); - // useless jmp ? - assert(cpi.target_offset != 0); - int offset = cpi.target_offset - cpi.instr_len; - // is in range ? - assert(CHAR_MIN <= offset && offset <= CHAR_MAX); - - char *addr_ip = instr_ip + 1; // 1 byte for opcode - if (cpi.instr_len == 3) { - ++addr_ip; // +1 byte for hint - } - // well, the target_offset already takes care about the Jcc - // instruction length - *(char *) (addr_ip) = (char)offset; - - if (m_infoBlock.get_flags() & DBG_TRACE_LAYOUT) { - dbg("code.patch @ %p, offset=%d (=>%p)\n", instr_ip, - cpi.target_offset, - instr_ip + cpi.target_offset + cpi.instr_len); - } - return; - } - // for 5-bytes instruction, the data is normally one byte ahead of - // the instruction byte - char *addr_ip = instr_ip + 1; - if (cpi.instr_len == 6) { - ++addr_ip; - assert(inst_1st_byte == 0x0F || // prefix + smth - inst_1st_byte == 0x89 || // MOV - inst_1st_byte == 0x87 || // XCHG - inst_1st_byte == 0x8B || - inst_1st_byte == 0xFF // mostly PUSH [mem] - ); // MOV reg, addr - } - else if (cpi.instr_len == 7) { - ++addr_ip; - ++addr_ip; - if (inst_1st_byte == 0xFF) { - // the only case - JMP [table] - assert(cpi.data_addr != NULL); - } - else { - // the only case is hint + Jcc imm32 - assert(inst_1st_byte == 0x2E || inst_1st_byte==0x3E); - } - } - - int offset; - if (cpi.target_pc != NOTHING) { - const char *target_ip = m_infoBlock.get_ip(cpi.target_pc); - offset = (int)target_ip; - if (cpi.relative) { - offset -= (int)(instr_ip + cpi.instr_len); - } - } - else { - if (cpi.data_addr != NULL) { - offset = (unsigned)cpi.data_addr; - // check that all variants, not only JMP [table] were handled - assert(addr_ip != instr_ip); - //addr_ip = instr_ip + (cpi.instr_len == 5 ? 1 : 2); - } - else if (cpi.instr_len == 6 && - (0x89 == inst_1st_byte || 0x87 == inst_1st_byte)) { - offset = (int)instr_ip + cpi.target_offset + 1; - } - else if (cpi.instr_len == 7) { - assert(cpi.target_offset != 0); // useless jmp ? - offset = cpi.target_offset - cpi.instr_len; - } - else { - if (cpi.target_ip != NULL) { - offset = cpi.target_ip - instr_ip - cpi.instr_len; - } - else { - assert(cpi.target_offset != 0); // useless jmp ? - offset = cpi.target_offset - cpi.instr_len; - } - } - } - *(int *)(addr_ip) = offset; - if (m_infoBlock.get_flags() & DBG_TRACE_LAYOUT) { - dbg("code.patch @ %p/bb=%u, byte=%02X, offset=%d (=>%p)\n", - instr_ip, cpi.bb, - (unsigned)inst_1st_byte, offset, offset); - } -} - -void Compiler::gen_iinc(unsigned idx, int value) -{ - m_jframe->var_def(i32, idx, 0); - //const JFrame::Slot& v = m_jframe->var(idx); - EncoderBase::Operand imm_val(OpndSize_32, value); - if (!vlocal_on_mem(idx)) { - voper(Mnemonic_ADD, vlocal(i32, idx, false, true), imm_val); - } - else { - /* add [local_idx], value */ - voper(Mnemonic_ADD, vmlocal(i32,idx), imm_val); - } -} - -void Compiler::gen_a(JavaByteCodes op, jtype jt) -{ - bool shft = op == OPCODE_ISHL || op == OPCODE_ISHR || op == OPCODE_IUSHR; - if (jt == i32) { - gen_a_i32(op); - return; - } - if (jt == i64 && !shft && - (op == OPCODE_IADD || op == OPCODE_ISUB || op == OPCODE_IOR || - op == OPCODE_IXOR || op == OPCODE_IAND || op == OPCODE_INEG)) { - - if (op == OPCODE_INEG) { - RegName r0_lo = vstack(0); - RegName r0_hi = vstack(1); - /* neg lo32 */ voper(Mnemonic_NEG, r0_lo); - /* adc hi32, 0 */ voper(Mnemonic_ADC, r0_hi, Imm32_0); - /* neg hi32 */ voper(Mnemonic_NEG, r0_hi); - vpop(jt); - vpush(jt, true); - return; - } - RegName v1_hi = vstack(3); - RegName v1_lo = vstack(2); - RegName v2_hi = vstack(1); - RegName v2_lo = vstack(0); - if (op == OPCODE_IADD) { - /* add stack_0, eax */ voper(Mnemonic_ADD, v1_lo, v2_lo); - /* adc stack_1, edx */ voper(Mnemonic_ADC, v1_hi, v2_hi); - } - else if (op == OPCODE_ISUB) { - /* sub stack_0, eax */ voper(Mnemonic_SUB, v1_lo, v2_lo); - /* sbb stack_1, edx */ voper(Mnemonic_SBB, v1_hi, v2_hi); - } - else if (op == OPCODE_IOR) { - /* or stack_0, eax */ voper(Mnemonic_OR, v1_lo, v2_lo); - /* or stack_1, edx */ voper(Mnemonic_OR, v1_hi, v2_hi); - } - else if (op == OPCODE_IXOR) { - /* xor stack_0, eax */ voper(Mnemonic_XOR, v1_lo, v2_lo); - /* xor stack_1, edx */ voper(Mnemonic_XOR, v1_hi, v2_hi); - } - else if (op == OPCODE_IAND) { - /* and stack_0, eax */ voper(Mnemonic_AND, v1_lo, v2_lo); - /* and stack_1, edx */ voper(Mnemonic_AND, v1_hi, v2_hi); - } - else { - assert(false); - } - vpop(jt); - vpop(jt); - vpush(jt, true); - return; - } - - if (is_f(jt) && - (op == OPCODE_IADD || op == OPCODE_ISUB || - op == OPCODE_IMUL || op == OPCODE_IDIV || - op == OPCODE_INEG )) { - bool is_dbl = jt == dbl64; - if (op == OPCODE_INEG) { - vstack_swap(0); - RegName freg = is_dbl ? RegName_FP0D : RegName_FP0S; - voper(Mnemonic_FLD, freg, vmstack(0)); - voper(Mnemonic_FCHS, freg); - voper(Mnemonic_FSTP, vmstack(0), freg); - return; - } - - RegName v1 = vstack(is_dbl ? 2 : 1); - RegName v2 = vstack(0); - if (op == OPCODE_IADD) { - voper(is_dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, v1, v2); - } - else if(op == OPCODE_ISUB) { - voper(is_dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, v1, v2); - } - else if(op == OPCODE_IMUL) { - voper(is_dbl ? Mnemonic_MULSD : Mnemonic_MULSS, v1, v2); - } - else if(op == OPCODE_IDIV) { - voper(is_dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, v1, v2); - } - vpop(jt); - vpop(jt); - vpush(jt, true); - return; + if (jt != i32) return false; + if (op != OPCODE_IDIV && op != OPCODE_IREM) { + return false; } - - bool negop = op == OPCODE_INEG; - char * helper = NULL; - if( jt == i64 && shft ) { - helper = (char*)rt_h_i64_shift; - shft = true; - } - else if( jt == dbl64 ) { - helper = negop ? (char*)&rt_h_neg_dbl64 : (char*)&rt_h_dbl_a; - } - else if( jt == flt32 ) { - helper = negop ? (char*)&rt_h_neg_flt32 : (char*)&rt_h_flt_a; - } - else if( jt == i64 ) { - helper = negop ? (char*)&rt_h_neg_i64 : (char*)&rt_h_i64_a; - } - else { - assert( jt == i32 ); - helper = negop ? (char*)&rt_h_neg_i32 : (char*)&rt_h_i32_a; - } - if (negop) { - const jtype args[1] = {jt}; - gen_stack_to_args(true, 1, args); - } - else if(shft) { - const jtype args[2] = {jt, i32}; - gen_stack_to_args(true, 2, args); - } - else { - const jtype args[2] = {jt,jt}; - gen_stack_to_args(true, 2, args); - } - if (negop) { - gen_call_novm(helper, 0); - } - else { - gen_call_novm(helper, 1, op); - } - gen_save_ret( jt ); -} - -void Compiler::gen_a_i32(JavaByteCodes op) { - const jtype jt = i32; - if (op == OPCODE_INEG) { - RegName r0 = vstack(0); - voper(Mnemonic_NEG, r0); - vpop(jt); - vpush(jt, true); - assert(!m_jframe->need_update()); - return; - } - RegName v1 = vstack(1); - RegName v2 = vstack(0); - if (op == OPCODE_IADD) { - voper(Mnemonic_ADD, v1, v2); - } - else if (op == OPCODE_ISUB) { - voper(Mnemonic_SUB, v1, v2); - } - else if (op == OPCODE_IOR) { - voper(Mnemonic_OR, v1, v2); - } - else if (op == OPCODE_IAND) { - voper(Mnemonic_AND, v1, v2); - } - else if (op == OPCODE_IXOR) { - voper(Mnemonic_XOR, v1, v2); - } - else if (op == OPCODE_IMUL) { - voper(Mnemonic_IMUL, v1, v2); - } - else if (op == OPCODE_IDIV || op == OPCODE_IREM) { - vedx(); - veax(); - // pseudo code: - // IDIV: return (v2 == -1 && v1 == INT_MIN) ? v1 : v1 / v2; - // IREM: return (v2 == -1 && v1 == INT_MIN) ? 0 : v1 % v2; - /* - CMP v2, -1 - JNE normal - CMP v1, INT_MIN - if (rem) { - JE cont - MOV v1, 0 - JMP exit - } - else { - JE exit // leave INT_MIN in v1 - } - cont: - MOV eax, v1 - CDQ - IDIV v2 - MOV v1, op == OPCODE_IDIV ? RegName_EAX : RegName_EDX - exit: - */ - voper(Mnemonic_CMP, v2, Imm32_m1); - unsigned pid_normal = vjcc(ConditionMnemonic_NE); - voper(Mnemonic_CMP, v1, MK_IMM32(INT_MIN)); - unsigned pid_cont = NOTHING, pid_exit = NOTHING; - if (op == OPCODE_IREM) { - pid_cont = vjcc(ConditionMnemonic_NE); - voper(Mnemonic_XOR, v1, v1); - pid_exit = vjmp8(); - } - else { - pid_exit = vjcc(ConditionMnemonic_E); - } - patch_set_target(pid_normal, ip()); - if (pid_cont != NOTHING) { - patch_set_target(pid_cont, ip()); - } - voper(Mnemonic_MOV, RegName_EAX, v1); - voper(Mnemonic_CDQ, RegName_EDX, RegName_EAX); - EncoderBase::Operands args(RegName_EDX, RegName_EAX, v2); - voper(Mnemonic_IDIV, args); - voper(Mnemonic_MOV, v1, op == OPCODE_IREM ? RegName_EDX : RegName_EAX); - if (pid_exit != NOTHING) { - patch_set_target(pid_exit, ip()); - } - } - else { - assert(op == OPCODE_ISHL || op == OPCODE_ISHR || op == OPCODE_IUSHR); - // - //todo: might want to change XCHG to mov if there are free registers - //todo: might want to track constants on the stack (need measurement) - // - /*a strategy: - if (v1 is ECX) { xchg v1=ecx, v2 | shift v2, v1=ecx | - mov v1=ecx, v2 } - else if( v2 is ECX) { / * we are so lucky ! * /shift v1, v2=ecx } - else if (is ecx free ?) { mov ecx, v2 | shift v2, ecx } - else { xchg ecx, v2 | shift v1,ecx | mov ecx, v2 } - */ - const Mnemonic shi = op == OPCODE_ISHL ? - Mnemonic_SHL : - (op==OPCODE_ISHR ? Mnemonic_SAR : Mnemonic_SHR); - if (v2 == RegName_ECX) { - voper(shi, v1, RegName_CL); - } - else if (v1 == RegName_ECX) { - voper(Mnemonic_XCHG, RegName_ECX, v2); - voper(shi, v2, RegName_CL); - voper(Mnemonic_MOV, RegName_ECX, v2); - } - else { - voper(Mnemonic_XCHG, RegName_ECX, v2); - voper(shi, v1, RegName_CL); - voper(Mnemonic_MOV, RegName_ECX, v2); - } - } - vpop(jt); - vpop(jt); - vpush(jt, true); -} - -void Compiler::gen_cnv(jtype from, jtype to) -{ - if (from == i32 && to != i64) { - RegName i0 = vstack(0); - vpop(from); - vpush(to, true); - if (to == u16 || to == i16 || to == i8) { - voper(to == u16 ? Mnemonic_MOVZX : Mnemonic_MOVSX, i0, valias(to, i0)); - } - else { - assert(is_f(to)); - RegName f0 = vstack(0); - voper(to == dbl64 ? Mnemonic_CVTSI2SD : Mnemonic_CVTSI2SS, f0, i0); - } - } - else { - char *helper = (char *) cnv_matrix_impls[from][to]; - const jtype args[1] = { from }; - gen_stack_to_args(true, 1, args); - gen_call_novm(helper, 0); - gen_save_ret(to); - } -} - -void Compiler::gen_new_array(Allocation_Handle ah) -{ - const JInst& jinst = *m_curr_inst; - assert(jinst.opcode == OPCODE_NEWARRAY || - jinst.opcode == OPCODE_ANEWARRAY); - - static const jtype args[1] = { i32 }; - gen_stack_to_args(true, 1, args); - // Free EAX - veax(); - const bool do_lazily = (m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION) && - jinst.opcode == OPCODE_ANEWARRAY; - - if (jinst.opcode == OPCODE_NEWARRAY) { - // it's unexpected that that something failed for a primitive type - assert(ah != 0); - } - - if (do_lazily) { - gen_lazy_resolve(jinst.op0, jinst.opcode); - // EAX = allocation handle - voper(Mnemonic_PUSH, RegName_EAX); - } - else if (ah == 0) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - voper(Mnemonic_PUSH, MK_IMM32(ah)); - } - gen_call_vm(rt_helper_new_array, 0); - gen_save_ret(jobj); - // the returned can not be null, marking as such. - m_jframe->stack_attrs(0, SA_NZ); -} - -void Compiler::gen_multianewarray(Class_Handle klass, unsigned num_dims) -{ - // stack: [..., count1, [...count N] ] - // args: (klassHandle, num_dims, count_n, ... count_1) - // native stack to be estblished: ..., count_1, .. count_n, num_dims, - // klassHandle - - const JInst& jinst = *m_curr_inst; - - // note: need to restore the stack - the cdecl-like function - jtype *arrArgs = (jtype *) alloca(num_dims * sizeof(unsigned)); - for (unsigned i = 0; i < num_dims; i++) { - arrArgs[i] = i32; - } - gen_stack_to_args(true, num_dims, arrArgs); - voper(Mnemonic_PUSH, MK_IMM32(num_dims)); - - if (m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION) { - gen_lazy_resolve(jinst.op0, jinst.opcode); - // EAX = klass handle - voper(Mnemonic_PUSH, RegName_EAX); - } - else if (klass == NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - voper(Mnemonic_PUSH, MK_IMM32(klass)); - } - gen_call_vm(rt_helper_multinewarray, 0); - // must restore the stack - the cdecl-like function - voper(Mnemonic_ADD, RegName_ESP, MK_IMM32(STACK_SLOT_SIZE*(num_dims+2))); - gen_save_ret(jobj); -} - -void Compiler::gen_x_cmp(JavaByteCodes op, jtype jt) -{ - if (is_f(jt)) { - const bool is_dbl = jt == dbl64; - RegName v1 = vstack(is_dbl ? 2 : 1); - RegName v2 = vstack(0); - bool is_g = (op == OPCODE_FCMPG || op == OPCODE_DCMPG); - /* - C-kode: - fcmp_g: if( _isnan(v1) || _isnan(v2) ) { return 1; } - fcmp_l: if( _isnan(v1) || _isnan(v2) ) { return -1; } - if( v1 > v2 ) return 1; - if( v1 < v2 ) return -1; - return 0; - */ - vpop(jt); - vpop(jt); - vpush(i32, true); - RegName i0 = vstack(0); - /*ASM: - xor i0, i0 - comiss v1, v2 - cmova i0, 1 ; CF=0 && ZF=0 - cmovb i0, -1 ; CF=1 - ; the order matters - cmovp must be the least ! - cmovp i0, is_g ? 1 : -1 ; PF=1 - ;; if no one of cmov happend, then i0 remains zeroed - */ - voper(Mnemonic_XOR, i0, i0); - voper(is_dbl ? Mnemonic_COMISD : Mnemonic_COMISS, v1, v2); - - EncoderBase::Operand op_m1(OpndSize_32, RegName_Null, (int)&g_iconst_m1); - EncoderBase::Operand op_1(OpndSize_32, RegName_Null, (int)&g_iconst_1); - - //ip(cmov(ip(), ConditionMnemonic_A, i0, opnd_1)); - //ip(cmov(ip(), ConditionMnemonic_B, i0, opnd_m1)); - //ip(cmov(ip(), ConditionMnemonic_P, i0, is_g ? opnd_1 : opnd_m1)); - voper((Mnemonic)(Mnemonic_CMOVcc + ConditionMnemonic_A), i0, op_1); - voper((Mnemonic)(Mnemonic_CMOVcc + ConditionMnemonic_B), i0, op_m1); - voper((Mnemonic)(Mnemonic_CMOVcc + ConditionMnemonic_P), i0, is_g ? op_1 : op_m1); - return; - } - assert(op == OPCODE_LCMP); - char *helper = (char *)rt_h_lcmp; - static const jtype args[2] = { i64, i64 }; - gen_stack_to_args(true, 2, args); - gen_call_novm(helper, 0); - gen_save_ret(i32); -} - -void Compiler::gen_field_op(JavaByteCodes op, jtype jt, Field_Handle fld) -{ - assert(OPCODE_PUTFIELD == op || OPCODE_GETFIELD == op); - assert(I_STACK_REGS > 2); - - const bool put = op == OPCODE_PUTFIELD; - const bool wide = is_wide(jt); - const bool lazy = m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION; - const JInst& jinst = *m_curr_inst; - unsigned fld_offset = fld ? field_get_offset(fld) : 0; - - if (lazy) { - gen_lazy_resolve(jinst.op0, jinst.opcode); - // EAX = field handle - voper(Mnemonic_PUSH, RegName_EAX); - // stack: [.., fld] - gen_call_novm((void*)&field_get_offset, 0); - // stack: [.., fld] ; EAX = offset - voper(Mnemonic_ADD, RegName_ESP, (int)STACK_SLOT_SIZE); - } - else if(fld == NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - } - - const RegName rref = vstack(put ? (wide ? 2 : 1) : 0); -// jtype jt_org = jt; - if (jt<i32) { - jt=i32; - } - - // - // Operand(OpndSize size, RegName base, RegName index, - // unsigned scale, int disp) - const EncoderBase::Operand pfield(typeInfo[jt].size, rref, - lazy ? RegName_EAX : RegName_Null, - lazy ? 1 : 0, // scale - fld_offset); // disp - if (put) { - voper(typeInfo[jt].mov, pfield, vstack(0)); - if (is_big(jt)) { - assert(jt == i64); - // move also the high part of the item - // '4' is sizeof(i64)/4 - EncoderBase::Operand phi(pfield.size(), - pfield.base(), pfield.index(), - pfield.scale(), pfield.disp() + 4); - voper(typeInfo[jt].mov, phi, vstack(1)); - } - // - vpop(jt); - vpop(jobj); - } - else { - vpop(jobj); - vpush(jt, true); - Mnemonic mv = typeInfo[jt].mov; - voper(mv, vstack(0), pfield); - if (is_big(jt)) { - assert(jt == i64); - // move also the high part of the item - - // ****** - // NOTE: order dependency - the high part can not be loaded - // first, as it will rewrite vstack(1), which was vstack(0) - // and is currently used as a base ! - // ****** - - // '4' is sizeof(i64)/4 - EncoderBase::Operand phi(pfield.size(), - pfield.base(), pfield.index(), - pfield.scale(), pfield.disp() + 4); - voper(typeInfo[jt].mov, vstack(1), phi); - } - } -} - -void Compiler::gen_static_op(JavaByteCodes op, jtype jt, Field_Handle fld) { - assert(OPCODE_PUTSTATIC == op || OPCODE_GETSTATIC == op); - - const bool put = op == OPCODE_PUTSTATIC; - const bool lazy = m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION; - const JInst& jinst = *m_curr_inst; - void * fld_addr = fld ? field_get_addr(fld) : 0; - - if (lazy) { - gen_lazy_resolve(jinst.op0, jinst.opcode); - // EAX = field address - } - else if(fld == NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - } - if (jt<i32) { - jt = i32; - } - // - // Operand(OpndSize size, RegName base, RegName index, - // unsigned scale, int disp) - EncoderBase::Operand pstatic(typeInfo[jt].size, - lazy ? RegName_EAX : RegName_Null, RegName_Null, - 0, (int)fld_addr); - - if (put) { - voper(typeInfo[jt].mov, pstatic, vstack(0)); - if (is_big(jt)) { - assert(jt == i64); - // move also the high part of the item - // '4' is sizeof(i64)/4 - EncoderBase::Operand phi(pstatic.size(), - pstatic.base(), pstatic.index(), - pstatic.scale(), pstatic.disp() + 4); - voper(typeInfo[jt].mov, phi, vstack(1)); - } - vpop(jt); - } - else { - vpush(jt, true); - voper(typeInfo[jt].mov, vstack(0), pstatic); - if (is_big(jt)) { - assert(jt == i64); - // move also the high part of the item - // '4' is sizeof(i64)/4 - EncoderBase::Operand phi(pstatic.size(), - pstatic.base(), pstatic.index(), - pstatic.scale(), pstatic.disp() + 4); - voper(typeInfo[jt].mov, vstack(1), phi); - } - } -} - - -void Compiler::gen_switch(const JInst & jinst) -{ - assert(jinst.opcode == OPCODE_LOOKUPSWITCH - || jinst.opcode == OPCODE_TABLESWITCH); - - if (jinst.opcode == OPCODE_LOOKUPSWITCH) { - /* TODO: each comparation takes about 12 bytes. May want to replace - it with SCAS-based version for some number of keys. - LOOKUPSWITCH's data is represented in byte code as array of - pairs - {value, target}. - We split this representation up for our native representation, - with continuous sets of values and targets: - values: {value0, value1, ..., valueN, any-value-here} - targets: {target1, target2, ..., targetN, default} - so may implement something like this: - ;;; - cld - ; free ECX, ESI - mov ecx, count=N+1 - mov esi, values - repnz scas - ;; here the esi point either on the value next after the key found - ;; or ecx is zero and esi points after the last (default) entry - jmp [esi + (values-targtes)-sizeof(int)] - ;;; - - Current approach: - ;;; - N times: - cmp [value], (n) - jz addr - ... - jmp default - ;;; - */ - unsigned n = jinst.get_num_targets(); - const RegName r0 = vstack(0); - vpop(i32); - if (m_next_bb_is_multiref) { - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - for (unsigned i = 0; i < n; i++) { - int key = jinst.key(i); - unsigned pc = jinst.get_target(i); - voper(Mnemonic_CMP, r0, EncoderBase::Operand(OpndSize_32, key)); - vjcc(pc, ConditionMnemonic_Z, InstPrefix_Null); - } - vjmp(jinst.get_def_target()); - return; - } - // - // TABLESWITCH // - const RegName r0 = vstack(0); - vpop(i32); - if (m_next_bb_is_multiref) { - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_UPDATE); - gen_mem(MEM_FROM_MEM|MEM_STACK|MEM_UPDATE); - } - voper(Mnemonic_CMP, r0, EncoderBase::Operand(OpndSize_32, jinst.high())); - vjcc(jinst.get_def_target(), ConditionMnemonic_G, InstPrefix_Null); - voper(Mnemonic_CMP, r0, EncoderBase::Operand(OpndSize_32, jinst.low())); - vjcc(jinst.get_def_target(), ConditionMnemonic_L, InstPrefix_Null); - voper(Mnemonic_SUB, r0, EncoderBase::Operand(OpndSize_32, jinst.low())); - - reg_table_switch_patch(); - EncoderBase::Operand ptable(OpndSize_32, RegName_Null, r0, - sizeof(void*), 0); - voper(Mnemonic_JMP, ptable); -} - -void Compiler::gen_dbg_brk(void) -{ - voper(Mnemonic_INT3); -} - -void Compiler::gen_instanceof_cast(bool checkcast, Class_Handle klass) -{ - const JInst& jinst = *m_curr_inst; - if (m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION) { - gen_lazy_resolve(jinst.op0, jinst.opcode); - voper(Mnemonic_PUSH, RegName_EAX); - } - else if (klass==NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - /*push klass*/voper(Mnemonic_PUSH, MK_IMM32(klass)); - } - static const jtype args[1] = { jobj }; - gen_stack_to_args(true, 1, args); - char * helper = checkcast ? rt_helper_checkcast : rt_helper_instanceof; - gen_call_vm(helper, 0); - gen_save_ret(checkcast ? jobj : i32); -} - -void Compiler::gen_gc_stack(int depth /*=-1*/, bool trackIt /*=false*/) -{ - if (depth == -1) { - depth = m_jframe->size(); - } - // prepare GC info for stack - // Store the current depth - if (m_curr_bb_state->stack_depth == (unsigned)depth) { - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";; > skipping stack depth storage due to known" - " same depth (%d)\n", m_curr_bb_state->stack_depth); - } - } - else { - EncoderBase::Operand stack_depth_info = - MK_MEM32(REG_BASE, SLOT_SIZE * m_stack.info_gc_stack_depth()); - voper(Mnemonic_MOV, stack_depth_info, MK_IMM32(depth)); - if (trackIt) { - m_curr_bb_state->stack_depth = depth; - } - }; - unsigned n_words = words(depth); - if (n_words != 0) { - // check whether we do need to store first word - unsigned gc_word = m_jframe->gc_mask(0); - if (m_curr_bb_state->stack_mask_valid && - gc_word == m_curr_bb_state->stack_mask) { - // do not need to update the GC mask, it's the same - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";; > skipping GC mask due to known same value (0x%X)\n", - gc_word ); - } - } - else { - EncoderBase::Operand info_word = - MK_MEM32(REG_BASE, SLOT_SIZE*(0 + m_stack.info_gc_stack())); - voper(Mnemonic_MOV, info_word, MK_IMM32(gc_word)); - if (trackIt) { - m_curr_bb_state->stack_mask = gc_word; - m_curr_bb_state->stack_mask_valid = true; - } - } - } - // store the bit masks - for (unsigned i = 1; i < n_words; i++) { - EncoderBase::Operand info_word = - MK_MEM32(REG_BASE, SLOT_SIZE*(i + m_stack.info_gc_stack())); - voper(Mnemonic_MOV, info_word, MK_IMM32(m_jframe->gc_mask(i))); - } -} - -void Compiler::gen_gc_mark_local(unsigned idx, bool mark) -{ - const JFrame::Slot& v = m_jframe->var(idx); - // If an item was already marked - // and its type is still the same, than skip the mark - if ((v.state() & SS_MARKED) && - ((v.jt == jobj && mark) || (v.jt != jobj && !mark))) { - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";;> skipping GC mark, due to known object type\n"); - } - return; - } - // prepare GC info for stack - unsigned word = word_no(idx); - unsigned offset = (word + m_stack.info_gc_locals()) * SLOT_SIZE; - EncoderBase::Operand gcinfo = MK_MEM32(REG_BASE, offset); - long mask = 1 << bit_no(idx); - if (mark) { - voper(Mnemonic_OR, gcinfo, MK_IMM32(mask)); - } - else { - voper(Mnemonic_AND, gcinfo, MK_IMM32(~mask)); - } - m_jframe->var_state(idx, SS_MARKED, 0); -} - -void Compiler::gen_stack_to_args(bool pop, unsigned num, const jtype * args) -{ - unsigned slots = count_slots(num, args); - unsigned depth = slots - 1; - for (unsigned i = 0; i < num; i++) { - jtype jt = args[i]; - if (is_f(jt)) { - bool is_dbl = jt == dbl64; - if (is_dbl) { - --depth; - } - const JFrame::Slot& s = m_jframe->dip(depth); - if (s.swapped()) { - if (is_dbl) { - voper(Mnemonic_PUSH, vstack_mem_slot(depth + 1)); - } - voper(Mnemonic_PUSH, vstack_mem_slot(depth)); - } - else { - voper(Mnemonic_SUB, RegName_ESP, - is_dbl ? Imm8_StackSlotX2 : Imm8_StackSlot); - voper(typeInfo[s.jt].mov, - EncoderBase::Operand(typeInfo[s.jt].size, RegName_ESP, 0), - vstack(depth)); - } - assert((m_jframe->dip(depth).jt == jt) || - (m_jframe->dip(depth).jt<=i32 && jt<=i32)); - assert(!m_jframe->dip(depth).hipart()); - } - else { - const JFrame::Slot& s = m_jframe->dip(depth); - if (s.swapped()) { - voper(Mnemonic_PUSH, vstack_mem_slot(depth)); - } - else { - voper(Mnemonic_PUSH, vstack(depth)); - } - assert((m_jframe->dip(depth).jt == jt) || - (m_jframe->dip(depth).jt<=i32 && jt<=i32)); - //assert(m_jframe->dip(depth).jt == jt); - if (jt == i64) { - assert(m_jframe->dip(depth).hipart()); - --depth; - assert(!m_jframe->dip(depth).hipart()); - const JFrame::Slot& s1 = m_jframe->dip(depth); - if (s1.swapped()) { - voper(Mnemonic_PUSH, vstack_mem_slot(depth)); - } - else { - voper(Mnemonic_PUSH, vstack(depth)); - } - } - } - --depth; - } - if (pop) { - for (unsigned i = 0; i < num; i++) { - vpop(args[num - i - 1]); - } - } -} - -void Compiler::gen_new(Class_Handle klass) -{ - const JInst& jinst = *m_curr_inst; - bool lazy = m_infoBlock.get_flags() & JMF_LAZY_RESOLUTION; - const unsigned cp_idx = jinst.op0; - if (lazy) { - gen_lazy_resolve(cp_idx, jinst.opcode); - // EAX - allocation handle - voper(Mnemonic_PUSH, RegName_EAX); - // push size - reg_data_patch(RefType_Size, cp_idx); - voper(Mnemonic_PUSH, MK_MEM32(RegName_Null, 0)); - // stack: [.., alloc_h, size] - gen_call_vm(rt_helper_new, 0); - } - else if (klass == NULL) { - gen_call_throw(rt_helper_throw_linking_exc, 3, m_klass, jinst.op0, - jinst.opcode); - } - else { - unsigned size = class_get_boxed_data_size(klass); - Allocation_Handle ah = class_get_allocation_handle(klass); - gen_call_vm(rt_helper_new, 2, ah, size); - } - gen_save_ret(jobj); - m_jframe->stack_attrs(0, SA_NZ); -} - -void Compiler::gen_lazy_resolve(unsigned idx, JavaByteCodes opkod) -{ - const bool is_new = opkod == OPCODE_NEW; - - veax(); - reg_data_patch(toRefType(opkod), idx); - voper(Mnemonic_MOV, RegName_EAX, MK_MEM32(RegName_Null, 0)); - - if (m_curr_bb_state->resState.test(opkod, idx)) { - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";;>skipping resolution gen due to known resolved state\n"); - }; - return; - } - m_curr_bb_state->resState.done(opkod, idx); - - voper(Mnemonic_TEST, RegName_EAX, RegName_EAX); - unsigned pid_done = vjcc(ConditionMnemonic_NZ, InstPrefix_HintTaken); - - gen_mem(MEM_TO_MEM|MEM_VARS|MEM_STACK|MEM_NO_UPDATE); - gen_gc_stack(-1, false); - - voper(Mnemonic_PUSH, MK_IMM32(opkod)); - voper(Mnemonic_PUSH, MK_IMM32(idx)); - voper(Mnemonic_PUSH, MK_IMM32((int)m_klass)); - vcall((void*)vm_get_rt_support_addr(VM_RT_RESOLVE)); - // For some operations we need some additional work - if (opkod == OPCODE_PUTSTATIC || opkod == OPCODE_GETSTATIC) { - voper(Mnemonic_PUSH, RegName_EAX); - vcall((void*)&field_get_addr); - voper(Mnemonic_ADD, RegName_ESP, Imm8_StackSlot); - } - else if (opkod == OPCODE_INVOKESPECIAL || opkod == OPCODE_INVOKESTATIC) { - voper(Mnemonic_PUSH, RegName_EAX); - vcall((void*)&method_get_indirect_address); - voper(Mnemonic_ADD, RegName_ESP, Imm8_StackSlot); - } - else if(opkod == OPCODE_ANEWARRAY) { - voper(Mnemonic_PUSH, RegName_EAX); - //// stack: [..., Class_Handle] - //vcall((void*)&class_get_array_of_class); - //// stack: [..., Class_Handle] - //voper(Mnemonic_MOV, StackTop32, RegName_EAX); - //// stack: [..., Class_Handle_of_aray] - vcall((void*)&class_get_allocation_handle); - voper(Mnemonic_ADD, RegName_ESP, Imm8_StackSlot); - } - else if(is_new) { - voper(Mnemonic_PUSH, RegName_EAX); - voper(Mnemonic_PUSH, RegName_EAX); - // stack: [..., Class_Handle, Class_Handle] - vcall((void*)&class_get_allocation_handle); - voper(Mnemonic_MOV, Stack32_1, RegName_EAX); - // stack: [..., allocation_handle, Class_Handle] - vcall((void*)&class_get_boxed_data_size); - // stack: [..., allocation_handle, Class_Handle], EAX - size - - reg_data_patch(RefType_Size, idx); - voper(Mnemonic_MOV, MK_MEM32(RegName_Null, 0), RegName_EAX); - - voper(Mnemonic_POP, RegName_EAX); - voper(Mnemonic_POP, RegName_EAX); - // stack: [...], EAX = allocation_handle - } + // The method is supposed to be platform-depended, and may not have + // Encoder support - leaving as-is, without implementing general + // support in Encoder // - /* - Can't use LOCK together with MOV, though there is a problem: according - to the arch manual, the 'mov mem32, ..' is atomic on multi-cores only - when the memory address is 4-bytes aligned. As we can't guarantee here - that the address is 4bytes aligned, then we might have a problem - here - todo ? - - if (!SysInfo::onecpu()) { - voper(Mnemonic_PUSH, RegName_EAX); - vprefix(InstPrefix_LOCK); - reg_data_patch( ); - voper(Mnemonic_XCHG, MK_MEM32(RegName_Null, 0), RegName_EAX); - voper(Mnemonic_POP, RegName_EAX); - } - */ - - reg_data_patch(toRefType(opkod), idx); - voper(Mnemonic_MOV, MK_MEM32(RegName_Null, 0), RegName_EAX); - - // will not touch EAX, as EAX was free-ed earlier - gen_mem(MEM_FROM_MEM|MEM_VARS|MEM_STACK|MEM_NO_UPDATE|MEM_INVERSE); - - patch_set_target(pid_done, ip()); -} - - -void Compiler::gen_call_throw(void * target, unsigned num_args, ...) -{ - // save only vars, and do not update the state - gen_mem(MEM_VARS|MEM_TO_MEM|MEM_NO_UPDATE); - // say 'stack is empty' - gen_gc_stack(0, false); - va_list valist; - va_start(valist, num_args); - for (unsigned i = 0; i < num_args; i++) { - int val = va_arg(valist, int); - voper(Mnemonic_PUSH, MK_IMM32(val)); - } - vcall(target); -#ifdef _DEBUG - // just to make sure we do not return from there - voper(Mnemonic_INT3); -#endif -} - -void Compiler::gen_call_vm(void * target, unsigned num_args, ...) -{ - gen_gc_stack(-1, true); // <= the only difference with gen_call_novm() - gen_mem(MEM_STACK|MEM_VARS|MEM_TO_MEM|MEM_UPDATE); - va_list valist; - va_start(valist, num_args); - for (unsigned i = 0; i < num_args; i++) { - int val = va_arg(valist, int); - voper(Mnemonic_PUSH, MK_IMM32(val)); - } - vcall(target); -} - -void Compiler::gen_call_novm(void * target, unsigned num_args, ...) -{ - gen_mem(MEM_STACK|MEM_VARS|MEM_TO_MEM|MEM_UPDATE); - va_list valist; - va_start(valist, num_args); - for (unsigned i = 0; i < num_args; i++) { - int val = va_arg(valist, int); - voper(Mnemonic_PUSH, MK_IMM32(val)); - } - vcall(target); -} - -void Compiler::gen_mem(unsigned flags) -{ -#ifdef _DEBUG - // - // check contract - // - // either STACK or MEM or both must be specified to synchronize - assert((flags & MEM_STACK) || (flags & MEM_VARS)); - // either TO_MEM or FROM_MEM but not both must be specified - if (flags & MEM_TO_MEM) { - assert(!(flags & MEM_FROM_MEM)); - } - else { - assert(flags & MEM_FROM_MEM); - } - // either UPDATE or NO_UPDATE but not both must be specified - if (flags & MEM_UPDATE) { - assert(!(flags & MEM_NO_UPDATE)); + vpark(eax.reg()); + vpark(edx.reg()); + rlock(eax); + rlock(edx); + Val& v1 = vstack(1, vis_imm(1)); + Val& v2 = vstack(0, true); + alu(alu_cmp, v2.as_opnd(), Opnd(-1)); + unsigned br_normal = br(ne, 0, 0); + alu(alu_cmp, v1.as_opnd(), Opnd(INT_MIN)); + unsigned br_cont = NOTHING, br_exit = NOTHING; + if (op == OPCODE_IREM) { + br_cont = br(ne, 0, 0); + br_exit = br(cond_none, 0, 0); } else { - assert(flags & MEM_NO_UPDATE); + br_exit = br(eq, 0, 0); } - if (flags & MEM_INVERSE) { - assert(flags & MEM_NO_UPDATE); - assert(flags & MEM_FROM_MEM); + patch(br_normal, ip()); + if (br_cont != NOTHING) { + patch(br_cont, ip()); } -#endif // ifdef _DEBUG + do_mov(eax, v1); // - // NOTE: MUST NOT change flags, as the code may be executed - // between a test and conditional jump. + // The method is supposed to be platform-depended, and may not have + // Encoder support - leaving as-is, without implementing general + // support in Encoder // - bool toMem = flags & MEM_TO_MEM; - bool updateState = flags & MEM_UPDATE; - bool inverse = flags & MEM_INVERSE; - - if (flags & MEM_STACK) { - for (unsigned i = 0, n = m_jframe->size(); i < n; i++) { - const JFrame::Slot& s = m_jframe->dip(i); - if (s.hipart() && !is_big(s.jt)) { - continue; - } - if (!m_jframe->regable(i)) { - continue; - } - - assert(s.regid() != -1 && s.vslot() != -1 && s.jt != jvoid); - RegName r = get_regs(s.jt)[s.regid()]; - assert(s.jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[s.jt].size); - // the resulting name must be valid - assert(NULL != getRegNameString(r)); - if (inverse) { - assert(!toMem && !updateState); - if (!s.swapped()) { - voper(typeInfo[s.jt].mov, r, vmstack(i)); - } - } - else if (s.swapped() && !toMem) { - voper(typeInfo[s.jt].mov, r, vmstack(i)); - if (updateState) { - m_jframe->stack_state(i, 0, SS_SWAPPED); - } - } - else if(!s.swapped() && toMem) { - voper(typeInfo[s.jt].mov, vmstack(i), r); - if (updateState) { - m_jframe->stack_state(i, SS_SWAPPED, 0); - } - } - } - } - if (flags & MEM_VARS) { - for (unsigned i=0; i<m_jframe->num_vars(); i++) { - const JFrame::Slot& v = m_jframe->var(i); - // cant operate on a frame which has non-processed items - assert(!v.needswap()); - if (v.regid() == -1) continue; - if (v.hipart() && !is_big(v.jt)) continue; - if (inverse) { - assert(!toMem && !updateState); - if (!v.swapped()) { - voper(typeInfo[v.jt].mov, - vlocal(v.jt, i, v.hipart(), false), vmlocal(v.jt, i)); - } - } - else if (v.swapped() && !toMem) { - voper(typeInfo[v.jt].mov, - vlocal(v.jt, i, v.hipart(), false), vmlocal(v.jt, i)); - if (updateState) { - m_jframe->var_state(i, 0, SS_SWAPPED); - } - } - else if(!v.swapped() && toMem) { - voper(typeInfo[v.jt].mov, - vmlocal(v.jt, i), vlocal(v.jt, i, v.hipart(), false)); - if (updateState) { - m_jframe->var_state(i, SS_SWAPPED, 0); - } - } - } + //CDQ + EncoderBase::Operands args0(RegName_EDX, RegName_EAX); + ip(EncoderBase::encode(ip(), Mnemonic_CDQ, args0)); + //IDIV + EncoderBase::Operands args(RegName_EDX, RegName_EAX, + devirt(v2.reg(), i32)); + ip(EncoderBase::encode(ip(), Mnemonic_IDIV, args)); + if (br_exit != NOTHING) { + patch(br_exit, ip()); } + vpop(); + vpop(); + vpush(op == OPCODE_IREM ? edx : eax); + runlock(eax); + runlock(edx); + return true; } -void Compiler::gen_dbg_check_stack(bool start) { - if (start) { - // We store ESP before a code to be checked ... - voper(Mnemonic_PUSH, RegName_ESP); - // ... then extracts size of stack slot ... - voper(Mnemonic_SUB, StackTop32, Imm8_StackSlot); - // ... so now we have - // ESP == [ESP] - // This condition is checked after the code and it it's not met, - // INT3 raised - return; - } - voper(Mnemonic_CMP, RegName_ESP, StackTop32); - unsigned pid = vjcc(ConditionMnemonic_Z); -// dbg_rt("Stack corrupted !!!\n"); - voper(Mnemonic_INT3); - patch_set_target(pid, ip()); - voper(Mnemonic_ADD, RegName_ESP, Imm8_StackSlot); -} - -void Compiler::gen_dbg_check_bb_stack(void) { - if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { - return; // empty method, nothing to do - } - - // With the current code generation scheme, the depth of native stack - // at the beginning of a basic block is exactly the same and is equal - // to the stack depth right after the method prolog executed. - // So, this check is enforced - // This is not valid for basic blocks which are part of a JSR subroutine - // because we have return address at the top of the stack (or even - // several ones). - // Such a blocks are not checked this way - the check is not called in - // bbs_gen_code. The expectation is that the JSR subroutine is - // self-checked - when we perform RET from JSR subroutine, if we have - // corrupted stack, we'll crash for sure. - voper(Mnemonic_PUSH, REG_BASE); - //voper(Mnemonic_SUB, StackTop32, Imm8_StackSlot); - //voper(Mnemonic_SUB, StackTop32, MK_IMM32(m_stack.size()*STACK_SLOT_SIZE)); - - // '+1' here due to just pushed REG_BASE/EBP - voper(Mnemonic_SUB, StackTop32, - MK_IMM32((m_stack.size()+1)*STACK_SLOT_SIZE)); - voper(Mnemonic_CMP, RegName_ESP, StackTop32); - unsigned pid = vjcc(ConditionMnemonic_Z); - gen_dbg_brk(); - patch_set_target(pid, ip()); - voper(Mnemonic_ADD, RegName_ESP, Imm8_StackSlot); // pop out EBP/REG_BASE -} - -}}; // ~namespace Jitrino::Jet +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_ia32.h vm/jitrino/src/jet/cg_ia32.h deleted file mode 100644 index 436ecba..0000000 --- vm/jitrino/src/jet/cg_ia32.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.3.4.4 $ - */ - -/** - * @file - * @brief Contains code-gen utilities and structures specific to IA32/EM64T. - */ - -#if !defined(__CG_IA32_H_INCLUDED__) -#define __CG_IA32_H_INCLUDED__ - -#include "enc_base.h" -#include "jframe.h" - -namespace Jitrino { -namespace Jet { - - -/** - * @brief Size of the stack slot, in bytes. - */ -#define SLOT_SIZE (sizeof(void*)) - -/** - * @brief Base pointer, for method's stack frame. - */ -#define REG_BASE (RegName_EBP) - -#define PATCH_COUNT_2_BC_SIZE_RATIO (0.7) -#define NATIVE_CODE_SIZE_2_BC_SIZE_RATIO (10) -#define PATCH_COUNT_2_BC_SIZE_RATIO_LAZY (1.1) -#define NATIVE_CODE_SIZE_2_BC_SIZE_RATIO_LAZY (20) - -/** - * @brief Controls layout of the native stack frame. - * - * The class StackFrame represents EBP-based stack frame, organized - * for the methods compiled by Jitrino.JET. - * - * @note Don't mess the slots ! Number of slots occupied by local variables, - * stack and input args refer to 'Java operand stack slots'. Other - * values are measured in 'native stack slots' which are 'number of - * bytes on the stack affected by single regular PUSH or POP - * instruction'. This 'native stack slot' is 4 bytes on IA32 and 8 - * bytes on EM64T. - * - * Below is the stack layout, used for methods compiled by Jitrino.JET. - * -<table color="black" > -<tr align="center"> - <td>Offset</td><td>Purpose</td><td>Comment</td> -</tr> -<tr bgcolor="silver"> - <td> +4+num_input_slots</td><td>in arg 0</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td> </td><td>in 1</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>+4+num_input_slots - i</td><td>...</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>+4</td><td>return address</td><td> </td> -</tr> -<tr> - <td>+3</td><td>saved EBX</td><td> </td> -</tr> -<tr> - <td>+2</td><td>saved ESI</td><td> </td> -</tr> -<tr> - <td>+1</td><td>saved EDI</td><td> </td> -</tr> -<tr> - <td align="right"><b>EBP =></b></td> - <td>saved EBP</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>-1</td><td>GC_Stack_Depth</td> - <td> - Operand stack's depth. Updated during runtime before "GC points".<br> - Used during root-set enumeration to report objects currently on operand - stack. - </td> -</tr> -<tr bgcolor="silver"> - <td> </td><td>... padding ....</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td> </td> - <td>GC_Locals - end</td><td>GC map for locals </td> -</tr> -<tr bgcolor="silver"> - <td>GC_Stack_Depth - 1 - (words(NUM_LOCALS)+1)&~1)</td> - <td>GC_Locals - begin</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td> </td><td>... padding ...</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td> </td> - <td>GC_Stack - end</td><td>GC map for stack</td> -</tr> -<tr bgcolor="silver"> - <td>GC_Locals - ((words(m_max_stack)+1)&~1)</td> - <td>GC_Stack - begin</td><td> </td> -</tr> -<tr> - <td>GC_Locals - 1</td><td>LAST_LOCAL = local N-1</td> - <td>Area to spill out local vars when needed.</td> -</tr> -<tr> - <td> </td><td>...</td><td> </td> -</tr> -<tr> - <td> </td><td>LOCAL_0</td><td> </td> -</tr> -<tr> - <td>LOCAL_0 - 1</td><td>JSTACK_BOTTOM</td> - <td>Bottom of Java operand stack - area to spill out operand stack items - when needed.</td> -</tr> -<tr> - <td> </td><td>...</td><td> </td> -</tr> -<tr> - <td>JSTACK_BOTTOM - (MAX_STACK-1)</td><td>JSTACK_TOP</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>JSTACK_TOP - 1</td><td>native stack bottom</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td> </td><td>...</td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>[ESP-1]</td><td> </td><td> </td> -</tr> -<tr bgcolor="silver"> - <td>[ESP]</td><td>native stack top</td><td> </td> -</tr> -</table> - - */ -class StackFrame { -public: - /** - * @brief Initializes an instance of StackFrame. - * - * @param _num_locals - number of slots occupied by local variables in - * Java method's frame - * @param _max_stack - max depth of Java operand stack - * @param _in_slots - number of slots occupied by input args in Java - * on Java operand stack - * @see #init - */ - StackFrame(unsigned _num_locals, unsigned _max_stack, unsigned _in_slots) - { - m_num_locals = _num_locals; - m_max_stack = _max_stack; - m_in_slots = _in_slots; - } - - /** - * @brief Noop. - */ - StackFrame() {} - - /** - * @brief Initializes fields of this StackFrame instance. - * - * @param _num_locals - number of slots occupied by local variables in - * Java method's frame - * @param _max_stack - max depth of Java operand stack - * @param _in_slots - number of slots occupied by input args in Java - * on Java operand stack - */ - void init(unsigned _num_locals, unsigned _max_stack, unsigned _in_slots) - { - m_num_locals = _num_locals; - m_max_stack = _max_stack; - m_in_slots = _in_slots; - } - -private: - /** - * @brief Returns number of slots occupied by local variables. - * - * @return number of slots occupied by local variables in Java method's - * frame - */ - unsigned get_num_locals(void) const - { - return m_num_locals; - } - - /** - * @brief Returns max stack depth of Java method's operand stack - * @return max stack depth - */ - unsigned get_max_stack(void) const - { - return m_max_stack; - } - - /** - * @brief Returns number of slots occupied by input args, in Java - * method's operand stack - * @return number of slots occupied by input args - */ - unsigned get_in_slots(void) const - { - return m_in_slots; - } -public: - - /** - * @brief Returns overall size of the stack frame (not including input - * args and return value). - * @return size of the stack frame - */ - unsigned size(void) const - { - return -native_stack_bot(); - } - - /** - * @brief Returns offset of the input argument. - * @param i - index of input argument's slot - * @return offset of the input argument. - */ - int in_slot(unsigned i) const - { - return in_ret() + m_in_slots - i; - } - - /** - * @brief Returns offset of location of return address. - * @return offset of location of return address - */ - int in_ret(void) const - { - return 4; - } - - /** - * @brief Returns offset of EBX location. - * @return offset of EBX location - */ - int save_ebx(void) const - { - return 3; - } - - /** - * @brief Returns offset of ESI location. - * @return offset of ESI location - */ - int save_esi(void) const - { - return 2; - } - - /** - * @brief Returns offset of EDI location. - * @return offset of EDI location - */ - int save_edi(void) const - { - return 1; - } - - /** - * @brief Returns offset of EBP location. - * @return offset of EBP location - */ - int save_ebp(void) const - { - return 0; - } - /** - * @brief Returns offset of operands's stack depth. - */ - int info_gc_stack_depth(void) const - { - return -1; - } - /** - * @brief Returns offset of GC map for local variables. - */ - int info_gc_locals(void) const - { - return info_gc_stack_depth() - 1 - ((words(m_num_locals)+1)&~1); - } - /** - * @brief Returns offset of GC map for operand stack. - */ - int info_gc_stack(void) const - { - return info_gc_locals() - ((words(m_max_stack)+1)&~1); - } - /** - * @brief Returns offset of local variable. - */ - int local(unsigned i) const - { - return info_gc_stack() - m_num_locals + i; - } - /** - * @brief Returns offset of bottom item of operand stack. - */ - int stack_bot(void) const - { - return local(0) - 1; - } - /** - * @brief Returns offset of the item of operand stack (\c slot counted - * from the stack's bottom, and it's opposite to depth which - * counted from stack top). - */ - int stack_slot(unsigned slot) const - { - return stack_bot() - slot; - } - /** - * @brief Returns offset of maximum available operand stack's item. - */ - int stack_max(void) const - { - return stack_bot() - (m_max_stack - 1); - } - /** - * @brief Returns offset of bottom item of native stack. - */ - int native_stack_bot(void) const - { - return stack_max() - 1; - } -private: - /** - * @brief Number of locals in method. - */ - unsigned m_num_locals; - /** - * @brief Max depth of Java operand stack. - */ - unsigned m_max_stack; - /** - * @brief Number of input arguments. - */ - unsigned m_in_slots; -}; - -/** - * @brief Describes some info related to a #jtype from IA32/EM64T code - * generator's point of view. - * @see typeInfo - */ -struct TypeInfo { - /// an OpndKind of a register that can be used to store the value of - /// appropriate type - OpndKind reg_kind; - /// Size of the type as OpndSize enum - OpndSize size; - /// Size of type in bytes - unsigned bytes; - /// Mnemonic used to move the type between memory and register - /// of 'reg_kind', or between two registers of 'reg_kind' - Mnemonic mov; -}; - -/** - * @brief Array of TypeInfo, arranged for appropriate #jtype. - */ -extern const TypeInfo typeInfo[num_jtypes]; - -}}; // ~namespace Jitrino::Jet - -#endif // if !defined __CG_IA32_H_INCLUDED__ diff --git vm/jitrino/src/jet/cg_instr.cpp vm/jitrino/src/jet/cg_instr.cpp new file mode 100644 index 0000000..c4cf2fb --- /dev/null +++ vm/jitrino/src/jet/cg_instr.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief CodeGen's routines for instrumentation and profiling. + */ + +#include "cg.h" +#include "trace.h" + +namespace Jitrino { +namespace Jet { + +void CodeGen::gen_prof_be(void) +{ + if (!is_set(JMF_PROF_ENTRY_BE)) { + return; + } + +#ifdef _IA32_ + AR addr = ar_x; + int off = (int)m_p_backedge_counter; +#else + AR addr = valloc(jobj); + movp(addr, m_p_backedge_counter); + int off = 0; +#endif + alu(alu_add, Opnd(i32, addr, off), 1); +} + +void CodeGen::gen_gc_safe_point() +{ + if (!is_set(JMF_BBPOLLING)) { + return; + } + if (m_bbstate->seen_gcpt) { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>gc.safepoint - skipped\n"); + } + return; + } + + m_bbstate->seen_gcpt = true; + // On Windows we could use a bit, but tricky way - we know about VM + // internals and we know how Windows manages TIB, and thus we can get a + // direct access to the flag, without need to call VM: + // mov eax, fs:14 + // test [eax+rt_suspend_req_flag_offset], 0 + // I don't believe this will gain any improvements for .jet, so using + // portable and 'official' way: + gen_call_vm(cs_v, rt_helper_get_thread_suspend_ptr, 0); + // The address of flag is now in gr_ret + Opnd mem(i32, gr_ret, 0); + alu(alu_cmp, mem, Opnd(0)); + unsigned br_off = br(z, 0, 0, taken); + gen_call_vm_restore(false, cs_v, rt_helper_gc_safepoint, 0); + patch(br_off, ip()); +} + + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_meth.cpp vm/jitrino/src/jet/cg_meth.cpp new file mode 100644 index 0000000..3a64189 --- /dev/null +++ vm/jitrino/src/jet/cg_meth.cpp @@ -0,0 +1,865 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief CodeGen's routines for method invocation and prolog/epilogue + * generation. + */ + +#include "compiler.h" +#include "trace.h" + +#include <open/vm.h> +#include <jit_import.h> +#include <jit_intf.h> + +#if !defined(_IPF_) + #include "enc_ia32.h" +#endif + +#include <algorithm> +using std::min; + +namespace Jitrino { +namespace Jet { + +/** + * CallSig for monitor_enter and monitor_exit helpers. + */ +static CallSig cs_mon(CCONV_HELPERS, jobj); + + +void Compiler::gen_prolog(void){ + if (is_set(DBG_TRACE_CG)) { + dbg(";; ========================================================\n"); + dbg(";; Prolog: max_stack=%d, num_locals=%d, in_slots=%d\n", + m_stack.get_max_stack(), + m_stack.get_num_locals(), + m_stack.get_in_slots()); + dbg(";; info_gc_stack_depth=%d, info_gc_locals=%d, info_gc_stack=%d", + m_stack.info_gc_stack_depth(), + m_stack.info_gc_locals(), + m_stack.info_gc_stack()); + dbg(";; stack_bot=%d, stack_max=%d\n", + m_stack.stack_bot(), m_stack.stack_max()); + dbg(";; local(0)=%d\n", m_stack.local(0)); + dbg(";; native_stack_bot=%d\n", m_stack.unused()); + dbg(";; ========================================================\n"); + } + + unsigned prologStart = ipoff(); + // + // Debugging things + // + + // Ensure stack is aligned properly + if (is_set(DBG_CHECK_STACK) && (m_ci.cc() & CCONV_STACK_ALIGN16)){ + alu(alu_test, sp, 0xF); + unsigned br_off = br(eq, 0, 0); + gen_dbg_rt(false, "Misaligned stack @ %s", meth_fname()); + gen_brk(); + patch(br_off, ip()); + } + + if (is_set(DBG_BRK)) { + gen_brk(); + } + + if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { + // empty method, nothing to do; the same is in gen_return(); + return; + } + + // A special stack preparation is performed in order to deal with + // a stack overflow error (SOE) at runtime: + // First, the callee-save registers are not changed until we are + // absolutely sure we have enouhg stack. In this case, if SOE happens, + // we'll simply do nothing in unwind_stack(). + + // + // Allocate stack frame at the very beginning, so we are always in + // the predictable state in unwind_frame(). + // + unsigned frameSize = m_stack.size(); + alu(alu_sub, sp, frameSize); + + // Ensure stack is aligned properly - do it here for _ALIGN_HALF16, + // as the stack must be (sp%16==0) at this point + if (is_set(DBG_CHECK_STACK) && (m_ci.cc() & CCONV_STACK_ALIGN_HALF16)){ + assert((frameSize+8) % 16 == 0); + alu(alu_test, sp, 0xF); + unsigned br_off = br(eq, 0, 0); + gen_dbg_rt(false, "Misaligned stack @ %s", meth_fname()); + gen_brk(); + patch(br_off, ip()); + } + + // Lock all the args registers to avoid them to be rewritten by the + // frame setup procedures + rlock(m_ci); + + // Here is pretty rare case, though still need to be proceeded: + // When we allocate a stack frame of size more than one page then the + // memory page(s) may not be accessible and even not allocated. + // A direct access to such [non existing] page raises 'access + // violation'. To avoid the problem we need simply probe (make read + // access) to the pages sequentially. In response on read-access to + // inaccessible page, the OS grows up the stack, so pages become + // accessible. + const unsigned PAGE_SIZE = 0x1000; + unsigned pages = + (frameSize + m_max_native_stack_depth + + PAGE_SIZE -1)/PAGE_SIZE; + // + for (unsigned i=1; i<pages; i++) { + AR ar = valloc(i32); + ld4(ar, sp, frameSize-i*PAGE_SIZE); + } +#ifdef _DEBUG + // Fill the whole stack frame with a special value + // -1 to avoid erasing retAddr + int num_words = frameSize/sizeof(int) - 1; + AR ar = valloc(i32); + Opnd fill(i32, ar); + rlock(ar); + AR ridx = valloc(i32); + runlock(ar); + Opnd idx(i32, ridx); + mov(fill, 0xDEADBEEF); + mov(idx, num_words); + unsigned _loop = ipoff(); + mov(Opnd(i32, sp, 0, ridx, 4), fill); + alu(alu_sub, idx, 1); + unsigned br_off = br(nz, 0, 0); + patch(br_off, ip(_loop)); +#endif + // save callee-save registers. If frame size is less than 1 page, + // the page was not touched yet, and the SOE may happen here + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + if (ar==sp || !is_callee_save(ar) || !m_global_rusage.test(i)) { + continue; + } + // use maximum possible size to store the register + jtype jt = is_f(ar) ? dbl64 : jobj; + // Here, always use sp-based addressing - bp frame is not ready + // yet. + st(jt, ar, sp, frameSize+m_stack.spill(ar)); + m_infoBlock.saved(ar); + } + + // ok, if we pass to this point at runtime, then we have enough stack + // and we stored all needed registers, so in case of unwind_stack() + // we'll simply restore registers from the stack. + unsigned thisPoint = ipoff() - prologStart; + m_infoBlock.set_warmup_len(thisPoint); + if (m_base != sp) { + // create bp-frame + lea(m_base, Opnd(jobj, sp, frameSize)); + } + + // Must be here, after the stack get aligned + if (is_set(DBG_TRACE_EE)) { + gen_dbg_rt(true, "entering: %s", meth_fname()); + } + + // + // reload input args into local vars + // + + // an initial GC map for local variables which are copied from inputs + ::std::vector<unsigned> locals_map; + locals_map.resize(words(m_ci.count())); + // an initial GC map for input args + ::std::vector<unsigned> args_map; + args_map.resize(words(m_ci.count())); + // an initial GC map for callee-save registers + unsigned regs_map = 0; + + // STACK_SLOT_SIZE <= retAddr + unsigned const sp_offset = frameSize + STACK_SLOT_SIZE; + + // Spill out registers that are both input args and globally allocated + for (unsigned i=0, local=0; i<m_ci.count(); i++, local++) { + jtype jt = m_ci.jt(i); + AR ar = m_ci.reg(i); + if (ar != ar_x && m_global_rusage.test(ar_idx(ar))) { + Opnd arg = m_ci.get(i); + Val& var = vlocal(jt, local, true); + mov(var.as_opnd(), arg); + // A presumption, to simplify the code: if the managed calling + // convention uses registers, then it's a platform without 'big' + // type problem. + assert(!is_big(jt)); + } + if (is_wide(jt)) { + ++local; + } + } + // Now, process input args: + // - set GC maps for objects came as input args, + // - move input args into the slots in the local stack frame (for some + // args) + for (unsigned i = 0, local=0; i<m_ci.count(); i++, local++) { + jtype jt = m_ci.jt(i); + // All values less than 32 bits get moved between methods as int32 + if (jt<i32) { + jt = i32; + } + // If this is an object, then set a bit in appropriate map ... + if (jt == jobj) { + AR ar = vreg(jobj, local); + if (ar != ar_x && is_callee_save(ar)) { + // .. callee-saved GP regs or .. + regs_map |= 1<<ar_idx(m_ra[local]); + } + else if (vis_arg(local)) { + // .. local vars that are kept on the input slots or .. + assert(m_ci.reg(i) == ar_x); + assert(0 == m_ci.off(i)%STACK_SLOT_SIZE); + int inVal = m_ci.off(i)/STACK_SLOT_SIZE; + args_map[word_no(inVal)] = + args_map[word_no(inVal)] | (1 <<bit_no(inVal)); + } + else { + // .. a 'regular' GC map for locals. + locals_map[word_no(local)] = + locals_map[word_no(local)] | (1 <<bit_no(local)); + } + } + jtype jtm = jtmov(jt); + // as_type() => Convert narrow types (<i32) to i32. + Opnd arg = m_ci.get(i, sp_offset).as_type(jt); + + // If we need to store 'this' for special reporting (ie. + // monitor_exit or for stack trace) - store it. + if (i==0 && is_set(JMF_REPORT_THIS)) { + if (is_set(DBG_TRACE_CG)) {dbg(";;>copy thiz\n");} + assert(jt == jobj); + Opnd thiz(jobj, m_base, voff(m_stack.thiz())); + do_mov(thiz, arg); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~copy thizh\n");} + } + // If the local resides on the input arg, then no need to copy it + // from input arg into the frame. + if (vis_arg(local)) { + if (is_wide(jt)) { + ++local; + } + continue; + } + // + // Ok, copy the from input args area, into local variables area + // + + // Define the slot, so it has proper type + vvar_def(jt, local); + if (arg.is_reg() && m_global_rusage.test(ar_idx(arg.reg()))) { + // See a loop above - the argument already spilled into memory, + // nothing to do + } + else { + // forDef = true to avoid uploading, so it only returns memory + // operand + Val& var = vlocal(jt, local, true); + do_mov(var, arg); + if (is_big(jt)) { + // Presumption: on IA32 (<= is_big()==true) no i64 inputs + // are left of input args + assert(!vis_arg(local+1)); + // Presumption: on IA32 (<= is_big()==true) no i64 inputs + // come on registers + assert(arg.is_mem()); + assert(arg.index() == ar_x); + Val arg_hi(jtm, arg.base(), arg.disp()+4); + Val var_hi = vlocal(jt, local+1, true); + do_mov(var_hi, arg_hi); + } + } + if (is_wide(jt)) { + ++local; + } + } + + runlock(m_ci); + + // + // Store the GC map for the local variables that are initialized as + // they come from input args + // + if (is_set(DBG_TRACE_CG) && locals_map.size() != 0) {dbg(";;>locals.gc_map\n");} + for (unsigned i = 0; i<locals_map.size(); i++) { + Opnd map(i32, m_base, voff(m_stack.info_gc_locals()+i*sizeof(int))); + Opnd val(locals_map[i]); + mov(map, val); + } + // + // For other local variables, zero the GC map + // + unsigned locals_gc_size = words(m_infoBlock.get_num_locals()); + if (locals_gc_size != locals_map.size()) { + if (is_set(DBG_TRACE_CG)) {dbg(";;>locals.gc_map\n");} + Opnd reg(i32, valloc(i32)); + alu(alu_xor, reg, reg); + for (unsigned i=locals_map.size(); i<locals_gc_size; i++) { + st4(reg.reg(), m_base, voff(m_stack.info_gc_locals()+i*sizeof(int))); + } + } + // + // Store the GC map for input args + // + if (is_set(DBG_TRACE_CG) && args_map.size() != 0) {dbg(";;>args.gc_map\n");} + for (unsigned i = 0; i<args_map.size(); i++) { + Opnd map(i32, m_base, voff(m_stack.info_gc_args()+i*sizeof(int))); + Opnd val(args_map[i]); + mov(map, val); + } + // + // Store info about objects on registers + // + if (is_set(DBG_TRACE_CG)) {dbg(";;>regs.gc_map\n");} + Opnd map(i32, m_base, voff(m_stack.info_gc_regs())); + Opnd val(regs_map); + mov(map, val); + // + // Initial stack size is zero + // + if (is_set(DBG_TRACE_CG)) {dbg(";;>gc.stack_depth\n");} + Opnd dpth(i32, m_base, voff(m_stack.info_gc_stack_depth())); + mov(dpth, Opnd(0)); + m_bbstate->stack_depth = 0; + + // Make the variables on their places - in a case if call to + // JVMTI/monitor_enter/recompilation helper lead to GC + + // TODO: May optimize a bit by specifying (0) - if the 0th BB is + // ref_count==1. In this case there is no real need to upload all the + // items on their registers. This will require special processing in both + // bb_enter() and bb_leave() + gen_bb_leave(NOTHING); + + // + // now, everything is ready, may call VM/whatever + // + + // Debugging - print out 'Entering ...' + if (is_set(DBG_TRACE_EE)) { + if (is_set(DBG_TRACE_CG)) {dbg(";;>print.ee\n");} + rlock(cs_trace_arg); + // Print out input args + for (unsigned i=0, local=0; i<m_ci.count(); i++, local++) { + // prepare stack + if(cs_trace_arg.size() != 0) { + alu(alu_sub, sp, cs_trace_arg.size()); + } + // 'local'-th argument as a first arg for dbg_trace_arg() ... + jtype jt = m_ci.jt(i); + if (jt<i32) jt = i32; + + Opnd arg = cs_trace_arg.get(0); + Val var; + if (vreg(jt, local) != ar_x) { + AR ar = vreg(jt, local); + if (is_f(ar) && arg.is_reg()) { + // If the local var resides on a float-point register, + // and calling canovention uses registers to pass args + // - we can not simply do 'mov gr, fr'. Store fr to + // memory first, then reload it to gr + assert(is_gr(arg.reg())); + Opnd scratch(jt, m_base, voff(m_stack.scratch())); + mov(scratch, Opnd(jt, ar)); + + jt = jt = flt32 ? i32 : i64; + var = scratch.as_type(jt); + } + else { + var = Val(jt, ar); + } + } + else { + var = Val(jt, m_base, vlocal_off(local)); + } + do_mov(arg, var.as_opnd(arg.jt())); + // ... its type and index ... + gen_call_novm(cs_trace_arg, (void*)&dbg_trace_arg, 1, i, jt); + if (is_wide(jt)) { + ++local; + } + } + runlock(cs_trace_arg); + if (is_set(DBG_TRACE_CG)) {dbg(";;>~print.ee\n");} + } + + // + // Profiling/recompilation support + // + + if (is_set(JMF_PROF_ENTRY_BE)) { + if (is_set(DBG_TRACE_CG)) { dbg(";;>profiling\n"); } + // Increment entry counter + AR ar = valloc(jobj); + movp(ar, m_p_methentry_counter); + Opnd addr(i32, ar, 0); + if (is_set(JMF_PROF_SYNC_CHECK)) { + rlock(ar); + AR gr_val = valloc(i32); + runlock(ar); + + Opnd val(i32, gr_val); + Opnd thr(m_methentry_threshold); + /* mov vreg, [counter] */ mov(val, addr); + /* add vreg, 1 */ alu(alu_add, val, Opnd(1)); + /* mov [counter], vreg */ mov(addr, val); + /* cmp vreg, threshold */ alu(alu_cmp, val, thr); + /* jne keep_going */ + /* call recompile */ + /* keep_going: ... */ + unsigned br_off = br(ne, 0, 0, taken); + gen_call_vm_restore(false, ci_helper_o, m_recomp_handler_ptr, + 0, m_profile_handle); + patch(br_off, ip()); + } + else { + alu(alu_add, addr, Opnd(1)); + } + if (is_set(DBG_TRACE_CG)) { dbg(";;>~profiling\n"); } + } + + // + // JVMTI method_enter notification + // + if (compilation_params.exe_notify_method_entry) { + static const CallSig cs_ti_menter(CCONV_HELPERS, jobj); + gen_call_vm(cs_ti_menter, rt_helper_ti_method_enter, 0, m_method); + } + + + if (meth_is_sync()) { + if (is_set(DBG_TRACE_CG)) { dbg(";;>monitor_enter\n"); } + if (method_is_static(m_method)) { + gen_call_vm(cs_mon, rt_helper_monitor_enter_static, 0, m_klass); + } + else { + AR gr = gr0; + if (cs_mon.reg(0) != gr_x) { + ld(jobj, cs_mon.reg(0), m_base, voff(m_stack.thiz())); + } + else { + assert(cs_mon.size() != 0); + alu(alu_sub, sp, cs_mon.size()); + ld(jobj, gr, m_base, voff(m_stack.thiz())); + st(jobj, gr, sp, cs_mon.off(0)); + } + gen_call_vm(cs_mon, rt_helper_monitor_enter, 1); + } + if (is_set(DBG_TRACE_CG)) { dbg(";;>~monitor_enter\n"); } + } + + if (is_set(DBG_TRACE_CG)) { + dbg_dump_state("after prolog", m_bbstate); + } +} + +void Compiler::gen_return(jtype retType) +{ + if (is_set(DBG_TRACE_EE)) { + gen_dbg_rt(true, "exiting : %s", meth_fname()); + } + + if (m_infoBlock.get_bc_size() == 1 && m_bc[0] == OPCODE_RETURN) { + // empty method, nothing to do; the same is in gen_prolog(); + // TODO: need to check and make sure whether it's absolutely legal + // to bypass monitors on such an empty method + // FIXME: this op9n bypasses JVMTI notifications + ret(m_ci.caller_pops() ? 0 : m_ci.size()); + if (retType != jvoid) { + vpop(); + } + return; + } + + bool is_sync = meth_is_sync(); + if (is_sync && meth_is_static()) { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>monitor_exit\n"); + } + gen_call_vm(cs_mon, rt_helper_monitor_exit_static, 0, m_klass); + if (is_set(DBG_TRACE_CG)) { + dbg(";;>~monitor_exit\n"); + } + } + else if (is_sync) { + if (is_set(DBG_TRACE_CG)) { + dbg(";;>monitor_exit\n"); + } + AR gr = valloc(jobj); + if (cs_mon.reg(0) != gr_x) { + vpark(cs_mon.reg(0)); + ld(jobj, cs_mon.reg(0), m_base, voff(m_stack.thiz())); + } + else { + assert(cs_mon.size() != 0); + alu(alu_sub, sp, cs_mon.size()); + ld(jobj, gr, m_base, voff(m_stack.thiz())); + st(jobj, gr, sp, cs_mon.off(0)); + } + gen_call_vm(cs_mon, rt_helper_monitor_exit, 1); + if (is_set(DBG_TRACE_CG)) { + dbg(";;>~monitor_exit\n"); + } + } + + if (compilation_params.exe_notify_method_exit) { + // JVMTI helper takes pointer to return value and method handle + const CallSig cs_ti_mexit(CCONV_STDCALL, jobj, jobj); + // The call is a bit unusual, and is processed as follows: + // we load an address of the top of the operand stack into + // a temporary register, and then pass this value as pointer + // to return value. If method returns void, then we load address + //of top of the stack anyway. + Val retVal; + rlock(cs_ti_mexit); + Val retValPtr = Val(jobj, valloc(jobj)); + rlock(retValPtr); + if (retType != jvoid) { + // Make sure the top item is on the memory + vswap(0); + if (is_big(retType)) { + vswap(1); + } + const Val& s = vstack(0); + assert(s.is_mem()); + lea(retValPtr.as_opnd(), s.as_opnd()); + } + else { + Opnd stackTop(jobj, m_base, voff(m_stack.unused())); + lea(retValPtr.as_opnd(), stackTop); + } + runlock(retValPtr); + Val vmeth(jobj, m_method); + gen_args(cs_ti_mexit, 0, &vmeth, &retValPtr); + gen_call_vm(cs_ti_mexit, rt_helper_ti_method_exit, cs_ti_mexit.count()); + runlock(cs_ti_mexit); + } + + if (is_f(retType)) { +#ifdef _IA32_ + // On IA-32 always swap to memory first, then upload into FPU + vswap(0); + ld(retType, fr_ret, m_base, vstack_off(0)); +#else + // Make sure the item is not immediate + Val op = vstack(0, vis_imm(0)); + if (!op.is_reg() || op.reg() != fr_ret) { + Opnd ret(retType, fr_ret); + mov(ret, op.as_opnd()); + } +#endif + } + else if (is_big(retType)) { +#ifdef _IA32_ + vswap(0); + vswap(1); + ld4(eax.reg(), m_base, vstack_off(0)); + ld4(edx.reg(), m_base, vstack_off(1)); +#else + assert(false && "Unexpected case - 'big' type on EM64T"); +#endif + + } + else if (retType != jvoid) { + Val& op = vstack(0); + if (!op.is_reg() || op.reg() != gr_ret) { + Opnd ret(retType, gr_ret); + mov(ret, op.as_opnd()); + } + } + + if (retType != jvoid && is_set(DBG_TRACE_EE)) { + //TODO: the same code is in gen_save_ret() - extract into a + // separate method ? + push_all(); + AR gtmp = gr0; + Opnd op = vstack(0, true).as_opnd(); + st(jtmov(retType), op.reg(), m_base, voff(m_stack.scratch())); + ld(jobj, gtmp, m_base, voff(m_stack.scratch())); + if (cs_trace_arg.reg(0) != gr_x) { + assert(cs_trace_arg.size() == 0); + mov(cs_trace_arg.reg(0), gtmp); + } + else { + assert(cs_trace_arg.size() != 0); + alu(alu_sub, sp, cs_trace_arg.size()); + st4(gtmp, sp, cs_trace_arg.off(0)); + } + Encoder::gen_args(cs_trace_arg, gtmp, 1, 2, -1, retType); + movp(gtmp, (void*)&dbg_trace_arg); + call(gtmp, cs_trace_arg, is_set(DBG_CHECK_STACK)); + pop_all(); + } + + unsigned frameSize = m_stack.size(); + // Restore callee-save regs + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + if (ar==sp || !is_callee_save(ar) || !m_global_rusage.test(i)) { + continue; + } + jtype jt = is_f(ar) ? dbl64 : jobj; + // Here, always use sp-based addressing - bp frame may be destroyed + // already by restoring bp. + ld(jt, ar, sp, frameSize+m_stack.spill(ar)); + } + + alu(alu_add, sp, frameSize); + ret(m_ci.caller_pops() ? 0 : m_ci.size()); + //m_jframe->clear_stack(); + if (retType != jvoid) { + // free up registers + vpop(); + } +} + + +void CodeGen::gen_invoke(JavaByteCodes opcod, Method_Handle meth, + const ::std::vector<jtype> &args, jtype retType) +{ + const unsigned slots = count_slots(args); + // where (stack depth) 'this' is stored for the method being invoked + // (if applicable) + const unsigned thiz_depth = slots - 1; + + const JInst& jinst = *m_curr_inst; + + CallSig cs(CCONV_MANAGED, args); + for (unsigned i=0; i<cs.count(); i++) { + AR ar = cs.reg(i); + if (ar == ar_x) continue; + vpark(ar); + } + unsigned stackFix = 0; + rlock(cs); + + const bool is_static = opcod == OPCODE_INVOKESTATIC; + Val thiz = is_static ? Val() : vstack(thiz_depth, true); + if (meth == NULL) { + runlock(cs); // was just locked above - unlock + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + stackFix = gen_stack_to_args(true, cs, 0); // pop out args + runlock(cs); // due to gen_stack_to_args() + gen_gc_stack(-1, true); + if (retType != jvoid) { + gen_save_ret(retType); + } + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + return; + } + + if (!is_static) { + rlock(thiz); + } + + // INVOKEINTERFACE must have VM helper call first, so will place + // its args later, after the call, to avoid destruction of args + // on registers. + if (opcod != OPCODE_INVOKEINTERFACE) { + stackFix = gen_stack_to_args(true, cs, 0); + gen_gc_stack(-1, true); + vpark(); + } + // + // Check for null here - we just spilled all the args and + // parked all the registers, so we have a chance to use HW NPE + // For INVOKEINTERFACE we did not spill args, but we'll call VM first, + // which is pretty expensive by itself, so the HW check does not give + // much. + // + if (!is_static) { + // For invokeSPECIAL, we're using indirect address provided by + // the VM. This means we do not read vtable, which means no + // memory access, so we can't use HW checks - have to use + // explicit one. Not a big loss, as the INVOKESPECIAL mostly + // comes right after NEW which guarantees non-null. + gen_check_null(thiz, opcod != OPCODE_INVOKESPECIAL); + } + + if (opcod == OPCODE_INVOKEINTERFACE) { + // if it's INVOKEINTERFACE, then first resolve it + Class_Handle klass = method_get_class(meth); + const CallSig cs_vtbl(CCONV_STDCALL, jobj, jobj); + // Prepare args for ldInterface helper + if (cs_vtbl.reg(0) == gr_x) { + assert(cs_vtbl.size() != 0); + alu(alu_sub, sp, cs_vtbl.size()); + st(jobj, thiz.reg(), sp, cs_vtbl.off(0)); + } + else { + assert(cs_vtbl.size() == 0); + mov(cs_vtbl.get(0), thiz.as_opnd()); + } + gen_call_vm(cs_vtbl, rt_helper_get_vtable, 1, klass); + // + // Method's vtable is in gr_ret now, prepare stack + // + rlock(gr_ret); + //st(jobj, gr_ret, m_base, voff(m_stack.scratch())); + stackFix = gen_stack_to_args(true, cs, 0); + gen_gc_stack(-1, true); + vpark(); + unsigned offset = method_get_offset(meth); + //ld(jobj, gr_ret, m_base, voff(m_stack.scratch())); + runlock(gr_ret); + ld(jobj, gr_ret, gr_ret, offset); + call(gr_ret, cs, is_set(DBG_CHECK_STACK)); + } + else if (opcod == OPCODE_INVOKEVIRTUAL) { + AR gr = valloc(jobj); + unsigned offset = method_get_offset(meth); + Opnd ptr; + if (g_vtbl_squeeze) { + ld4(gr, thiz.reg(), rt_vtable_offset); + AR gr_vtbase = valloc(jobj); + movp(gr_vtbase, (char*)VTBL_BASE+offset); + alu(jobj, alu_add, gr, gr_vtbase); + ptr = Opnd(jobj, gr, 0); + } + else { + ld(jobj, gr, thiz.reg(), rt_vtable_offset); + ptr = Opnd(jobj, gr, offset); + } + call(ptr, cs, is_set(DBG_CHECK_STACK)); + } + else { + void * paddr = method_get_indirect_address(meth); +#ifdef _IA32_ + Opnd ptr(jobj, ar_x, paddr); +#else + AR gr = valloc(jobj); + movp(gr, paddr); + ld(jobj, gr, gr); + Opnd ptr(jobj, gr); +#endif + call(ptr, cs, is_set(DBG_CHECK_STACK)); + } + + if (!is_static) { + runlock(thiz); + } + // to unlock after gen_stack_to_args() + runlock(cs); + // to unlock after explicit lock at the top of this method + runlock(cs); + + if (retType != jvoid) { + gen_save_ret(retType); + } + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } +} + +void CodeGen::gen_args(const CallSig& cs, unsigned idx, const Val * parg0, + const Val * parg1, const Val * parg2, const Val * parg3, + const Val * parg4, const Val * parg5, const Val * parg6) +{ + if (idx == 0 && cs.size() != 0) { + alu(alu_sub, sp, cs.size()); + } + + const Val* args[] = {parg0, parg1, parg2, parg3, parg4, parg5, parg6}; + unsigned steps = min((int)COUNTOF(args), (int)cs.count()-(int)idx); + for (unsigned i=0; i<steps; i++) { + if (args[i] == 0) { + break; + } + unsigned id = idx + i; + Opnd arg = cs.get(id); + do_mov(arg, *args[i]); + } +} + +void CodeGen::gen_save_ret(jtype jt) +{ + assert(jt != jvoid); + AR ar = is_f(jt) ? fr_ret : gr_ret; + if (jt==i8) { + sx1(Opnd(i32, ar), Opnd(jt,ar)); + jt = i32; + } + else if (jt == i16) { + sx2(Opnd(i32, ar), Opnd(jt,ar)); + jt = i32; + } + else if (jt == u16) { + zx2(Opnd(i32, ar), Opnd(jt,ar)); + jt = i32; + } +#ifdef _IA32_ + if(ar == fr_ret) { + // Cant use vstack_off right here, as the item is not yet pushed. + unsigned slot = m_jframe->size(); + if (is_wide(jt)) { + slot += 1; + } + vpush(Val(jt, m_base, voff(m_stack.stack_slot(slot)))); + // + st(jt, fr_ret, m_base, vstack_off(0)); + } + else if (is_big(jt)) { + assert(jt==i64); + static const AR eax = virt(RegName_EAX); + static const AR edx = virt(RegName_EDX); + vpush2(Val(jt, eax), Val(jt, edx)); + } + else +#endif + { + assert(!is_big(jt)); + vpush(Val(jt, ar)); + } + + if (is_set(DBG_TRACE_EE) && !is_f(jt) && !is_big(jt)) { + push_all(true); + assert(!is_callee_save(gr0)); + AR gtmp = gr0; + //ld(jobj, gtmp, bp, m_stack.stack_slot(m_jframe->depth2slot(0))); + Opnd tmp(jt, gtmp); + mov(tmp, Opnd(jt, gr_ret)); + if (cs_trace_arg.reg(0) != gr_x) { + assert(cs_trace_arg.size() == 0); + mov(cs_trace_arg.reg(0), gtmp); + } + else { + assert(cs_trace_arg.size() != 0); + alu(alu_sub, sp, cs_trace_arg.size()); + mov(Opnd(jt, sp, cs_trace_arg.off(0)), tmp); + } + Encoder::gen_args(cs_trace_arg, gtmp, 1, 2, -1, jt); + movp(gtmp, (void*)&dbg_trace_arg); + call(gtmp, cs_trace_arg, is_set(DBG_CHECK_STACK)); + pop_all(); + } + +} + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_obj.cpp vm/jitrino/src/jet/cg_obj.cpp new file mode 100644 index 0000000..4eefb3a --- /dev/null +++ vm/jitrino/src/jet/cg_obj.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +#include "compiler.h" +#include "trace.h" + +#include <malloc.h> +#include <memory.h> +#include <assert.h> +#include <stdlib.h> + +#include <jit_import.h> + +/** + * @file + * @brief Object creation, monitors and cast checks. + */ + +namespace Jitrino { +namespace Jet { + +void CodeGen::gen_new_array(Allocation_Handle ah) +{ + const JInst& jinst = *m_curr_inst; + assert(jinst.opcode == OPCODE_NEWARRAY || + jinst.opcode == OPCODE_ANEWARRAY); + + if (ah == 0) { + // it's unexpected that that something failed for a primitive type + assert(jinst.opcode != OPCODE_NEWARRAY); + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + } +#ifdef _EM64T_ + static const CallSig cs_new_arr(CCONV_HELPERS, i32, jobj); + unsigned stackFix = gen_stack_to_args(true, cs_new_arr, 0, 1); + gen_call_vm(cs_new_arr, rt_helper_new_array, 1, ah); + runlock(cs_new_arr); +#else + static const CallSig cs_new_arr(CCONV_HELPERS, jobj, i32); + rlock(cs_new_arr); + AR artmp = valloc(jobj); + rlock(artmp); + Encoder::gen_args(cs_new_arr, artmp, 0, 1, ah); + unsigned stackFix = gen_stack_to_args(true, cs_new_arr, 1, 1); + runlock(artmp); + gen_call_vm(cs_new_arr, rt_helper_new_array, cs_new_arr.count()); + runlock(cs_new_arr); +#endif + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + gen_save_ret(jobj); + // the returned can not be null, marking as such. + vstack(0).set(VA_NZ); + // allocation assumes GC invocation + m_bbstate->seen_gcpt = true; +} + +void CodeGen::gen_multianewarray(Class_Handle klass, unsigned num_dims) +{ + // stack: [..., count1, [...count N] ] + // args: (klassHandle, num_dims, count_n, ... count_1) + // native stack to be established (ia32): + // .., count_1, .. count_n, num_dims, klassHandle + + const JInst& jinst = *m_curr_inst; + + vector<jtype> args; + for (unsigned i = 0; i<num_dims; i++) { + args.push_back(i32); + } + args.push_back(i32); + args.push_back(jobj); + + // note: need to restore the stack - the cdecl-like function + CallSig ci(CCONV_CDECL_IA32|CCONV_MEM|CCONV_L2R|CCONV_CALLER_POPS, args); + unsigned stackFix = gen_stack_to_args(true, ci, 0, num_dims); + + if (klass == NULL) { + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + } + + gen_call_vm(ci, rt_helper_multinewarray, num_dims, num_dims, klass); + runlock(ci); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + gen_save_ret(jobj); + // the returned can not be null, marking as such. + vstack(0).set(VA_NZ); + // allocation assumes GC invocation + m_bbstate->seen_gcpt = true; +} + + +void CodeGen::gen_new(Class_Handle klass) +{ + const JInst& jinst = *m_curr_inst; + if (klass == NULL) { + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + } + else { + unsigned size = class_get_boxed_data_size(klass); + Allocation_Handle ah = class_get_allocation_handle(klass); + static CallSig ci_new(CCONV_STDCALL, i32, jobj); + gen_call_vm(ci_new, rt_helper_new, 0, size, ah); + } + gen_save_ret(jobj); + // the returned can not be null, marking as such. + vstack(0).set(VA_NZ); + // allocation assumes GC invocation + m_bbstate->seen_gcpt = true; +} + +void CodeGen::gen_instanceof_cast(bool checkcast, Class_Handle klass) +{ + const JInst& jinst = *m_curr_inst; + if (klass == NULL) { + gen_call_throw(ci_helper_linkerr, rt_helper_throw_linking_exc, 0, + m_klass, jinst.op0, jinst.opcode); + } + static const CallSig cs(CCONV_STDCALL, jobj, jobj); + unsigned stackFix = gen_stack_to_args(true, cs, 0, 1); + char * helper = checkcast ? rt_helper_checkcast : rt_helper_instanceof; + gen_call_vm(cs, helper, 1, klass); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } + runlock(cs); + gen_save_ret(checkcast ? jobj : i32); +} + +void CodeGen::gen_monitor_ee(void) +{ + const JInst& jinst = *m_curr_inst; + gen_check_null(0); + static const CallSig cs_mon(CCONV_MANAGED, jobj); + unsigned stackFix = gen_stack_to_args(true, cs_mon, 0); + gen_call_vm(cs_mon, + jinst.opcode == OPCODE_MONITORENTER ? + rt_helper_monitor_enter : rt_helper_monitor_exit, 1); + runlock(cs_mon); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } +} + +void CodeGen::gen_athrow(void) +{ + static const CallSig cs_throw(CCONV_MANAGED, jobj); + unsigned stackFix = gen_stack_to_args(true, cs_throw, 0); + gen_call_vm(cs_throw, rt_helper_throw, 1); + runlock(cs_throw); + if (stackFix != 0) { + alu(alu_sub, sp, stackFix); + } +} + + + + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_regs.cpp vm/jitrino/src/jet/cg_regs.cpp new file mode 100644 index 0000000..e12b9e3 --- /dev/null +++ vm/jitrino/src/jet/cg_regs.cpp @@ -0,0 +1,876 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +#include "compiler.h" +#include <open/vm.h> +#include "trace.h" + +#include "jit_intf.h" +/** + * @file + * @brief Registers manipulation routines and operand stack mimics. + */ + +namespace Jitrino { +namespace Jet { + + +AR CodeGen::valloc(jtype jt) +{ + unsigned start = is_f(jt) ? ar_idx(fr0) : ar_idx(gr0); + unsigned count = is_f(jt) ? fr_num : gr_num; + // + // We are going to allocate a temporary register - we do several tries + // to reach the following goals: + // - minimize memory accesses + // - minimize callee-saved registers usages + + // Try to find the first SCRATCH (non callee-save) register + + AR last_used = rlast(jt); + for (unsigned i=ar_idx(last_used)+1; i<start+count; i++) { + AR ar = _ar(i); + if (is_callee_save(ar) || ar == sp || ar == m_base) continue; + if (rrefs(ar) == 0 && rlocks(ar) == 0 && !m_global_rusage.test(i)) { + // good, found available scratch register + rlast(ar); + return ar; + } + } + // No free scratch registers above the 'last used'. Try any scratch reg. + for (unsigned i=start; i<start+count; i++) { + AR ar = _ar(i); + if (is_callee_save(ar) || ar == sp || ar == m_base) continue; + if (rrefs(ar) == 0 && rlocks(ar) == 0 && !m_global_rusage.test(i)) { + // good, found available scratch register + rlast(ar); + return ar; + } + } +#if 0 + // + // No free scratch registers. How about free callee-save ? + // + // not now. currently, only scratch regs are used as temporaries, + // and callee-save are used as global regs. may revisit it. + for (unsigned i=start; i<start+count; i++) { + AR ar = _ar(i); + if (ar == sp || ar == m_base) continue; + if (m_bbstate->regs[i].refs == 0 && m_bbstate->regs[i].locks==0 && + !m_static_rs.test(i)) { + last_used = ar; + rrefs(ar); + return ar; + } + } +#endif + // + // Ugh, no free registers of the needed kind available, need to spill + // someone out + + // try to locate first non locked scratch register with min number of + // refs + unsigned min_ref = NOTHING, min_idx = NOTHING; + for (unsigned i=start; i<start+count; i++) { + AR ar = _ar(i); + if (is_callee_save(ar) || ar == sp || ar == m_base) continue; + if (min_ref > rrefs(ar) && rlocks(ar)==0 && !m_global_rusage.test(i)) { + min_ref = rrefs(ar); + min_idx = i; + } + } + + // this means that all scratch registers are locked. Cant happen. + assert(min_idx != NOTHING); + + AR ar = _ar(min_idx); + if (is_set(DBG_TRACE_CG)) { dbg(";;>spill %s\n", to_str(ar).c_str()); } + // Where to spill: + +#if 0 // TODO: checkit + // How about scratch registers of other kind ? + // Storing to a register allows us avoid memory access. This might seem + // questionable, as on IA32 'MOVD xmm, r32' has the latency of incredible + // 10 cycles. + // However, the throughput is just 1 cycle, so the port is free again + // very soon. Also, as we're allocating, say, GP register, then we'll + // operate on it in next few instructions, and will not use FPU during + // this, so the latency will [hopefully] be masked. + // + + //Note: kinda prototype, not even tested. + start = !is_f(jt) ? ar_idx(fr0) : ar_idx(gr0); + count = !is_f(jt) ? fr_num : gr_num; + AR otherKind = ar_x; + for (unsigned i=start; i<start+count; i++) { + AR ar = _ar(i); + if (is_callee_save(ar) || ar == sp || ar == m_base) continue; + if (m_bbstate->regs[i].refs == 0 && !m_bbstate->regs[i].locked) { + otherKind = ar; + break; + } + } + if (otherKind != ar_x) { + // Cool - do have a scratch register of other kind, let's unload there + mov(otherKind, ar); + m_bbstate->regs[min_idx].temp = otherKind; + } +#endif // if 0 + + // Ugh... No way out, have to spill to the memory... + + // Now, update the things + + // First, free out the stack items, which are the register + for (unsigned i=0; i<m_jframe->size(); i++) { + Val& s = m_jframe->dip(i); + if (!s.is_reg() || s.reg() != ar) { continue; }; + jtype mov_jt = jtmov(s.jt()); + st(mov_jt, ar, m_base, vstack_off(i)); + rfree(s); + s.to_mem(m_base, vstack_off(i)); + rref(s); + } + + for (unsigned i=0; i<m_jframe->num_vars(); i++) { + Val& s = m_jframe->var(i); + if (!s.is_reg() || s.reg() != ar) { continue; }; + jtype mov_jt = jtmov(s.jt()); + st(mov_jt, ar, m_base, vlocal_off(i)); + rfree(s); + s.to_mem(m_base, vlocal_off(i)); + rref(s); + } + // + // Now, free up the stack items that are the memory + // + for (unsigned i=0; is_gr(ar) && i<m_jframe->size(); i++) { + Val& s = m_jframe->dip(i); + if (!s.is_mem() || !s.uses(ar)) { continue; }; + push(s.as_opnd(jobj)); + rfree(s); + s.to_mem(m_base, vstack_off(i)); + rref(s); + Opnd stk(jobj, m_base, vstack_off(i)); + pop(stk); + } + if (is_set(DBG_TRACE_CG)) { dbg(";;>~spill\n"); } + return ar; +} + +Val& CodeGen::vstack(unsigned depth, bool toReg) +{ + Val& s = m_jframe->dip(depth); + + if (s.is_reg()) { + return s; + } + + jtype jtm = jtmov(m_jframe->top(depth)); + + if (s.is_mem()) { + if (toReg) { + // TODO: if the item represents the local variable then it may + // worth to upload the local first, then return the register + // reference + AR ar = valloc(jtm); + // 's' must still reside in memory + assert(s.is_mem()); + // but it's location may change. + // Eg if we had arraylength ([gr0+offset]) on the stack, + // after allocation and possible spilling may have + // [m_base+stack_offset]. + Opnd reg(jtm, ar); + do_mov(reg, s.as_opnd(jtm)); + rfree(s); + s.to_reg(ar); + rref(s); + } + return s; + } + + assert(s.is_imm()); + + if (is_f(s.jt()) && s.caddr() != NULL) { + AR fr = valloc(s.jt()); + Opnd reg(s.jt(), fr); + Opnd mem = vaddr(s.jt(), s.caddr()); + do_mov(reg, mem); + rfree(s); + s.to_reg(fr); + rref(s); + return s; + } + + if (is_f(s.jt())) { + if (toReg) { + // swap to memory first + vswap(depth); + // allocate register and move to it from memory + AR ar = valloc(jtm); + Val reg(jtm, ar); + do_mov(reg, s); + rfree(s); + s.to_reg(ar); + rref(s); + } + return s; + } + + + //if (s.jt() == i32 || (s.jt() == i64 && is_big(i64))) { + if (s.jt() == i32 || s.jt() == i64) { + if (toReg) { + AR ar = valloc(jtm); + Val reg(jtm, ar); + do_mov(reg, s); + rfree(s); + s.to_reg(ar); + rref(s); + } + return s; + } + + //if (s.jt() == i64) { + // assert(!is_big(i64)); + // return s; + //} + + if (s.jt() == jobj) { +#ifdef _EM64T_ + //TODO: it may be not always necessary to upload to register. + toReg = true; +#endif + if (toReg) { + AR ar = valloc(s.jt()); + movp(ar, s.pval()); + rfree(s); + s.to_reg(ar); + rref(s); + } + return s; + } + //assert(false); + return s; +} + + +AR CodeGen::vreg(jtype jt, unsigned idx) +{ + return m_ra[idx]; +} + +jtype CodeGen::vtype(unsigned idx) +{ + return m_staticTypes[idx]; +} + +void CodeGen::vassign(jtype jt, unsigned idx, const Val& s) +{ + Val& v = m_jframe->var(idx); + assert(!v.is_reg() && s.is_reg()); + rfree(v); + v = s.as_opnd(jt); + v.attrs(s.attrs()); + rref(v); +} + +bool CodeGen::vis_stack(const Val& s) const +{ + if (!s.is_mem()) return false; + if (s.base() != m_base) return false; + // Presumption about the operand stack layout in the native frame + assert(m_stack.stack_bot() >= m_stack.unused()); + if (m_stack.stack_bot()<s.disp()) return false; + if (s.disp()<m_stack.unused()) return false; + return true; +} + +int CodeGen::vvar_idx(const Val& s) const +{ + if (!s.is_mem()) return -1; + if (s.base() != ar_x && s.base() != m_base) return -1; + for (unsigned i=0; i<m_stack.get_num_locals(); i++) { + int off = vlocal_off(i); + if (s.disp() == off) return i; + } + return -1; +} + +void CodeGen::vunref(jtype jt) +{ + // TODO(?): may optimize a bit. Eg. when we do PUTFIELD, there is no + // need to un-shadow say array items on operand stack and vise versa. + // this will require adding a trait to Val - field, static, array items + bool do_print = true; + for (unsigned i=0; i<m_jframe->size(); i++) { + Val& s = m_jframe->dip(i); + if (s.jt() != jt) continue; + // The stack item itself - dont care + if (vis_stack(s)) continue; + // Not a memory ref or a register/immediate - don't care + if (!s.is_mem() || s.is_dummy()) continue; + // Refers to a local var - will be unreferenced explicitly + // when needed (via vunref(Val&) call) + if (vvar_idx(s) != -1) continue; + if (do_print && is_set(DBG_TRACE_CG)) { + dbg(";;>vunref(%s)\n", jtypes[jt].name); + do_print = false; + } + Val save = s; + Val op = vstack(i, true); + for (unsigned j=i+1; j<m_jframe->size(); j++) { + Val& s1 = m_jframe->dip(j); + if (s1 == save) { + rfree(s1); + s1.to_reg(op.reg()); + rref(s1); + } + } + } + if (!do_print && is_set(DBG_TRACE_CG)) { + dbg(";;>~vunref(%s)\n", jtypes[jt].name); + } +} + +void CodeGen::vunref(jtype jt, const Val& op, unsigned skipDepth) +{ + if (op.is_imm()) { + // Nothing to do with immediates + return; + } + jtype jtm = jtmov(jt); + bool printDone = false; + for (unsigned i=0; i<m_jframe->size(); i++) { + if (i == skipDepth) { + continue; + } + Val& s = m_jframe->dip(i); + if (s != op && !(op.is_reg() && s.uses(op.reg()))) { + continue; + } + if (is_set(DBG_TRACE_CG) && !printDone) { + dbg(";;>vunref for %s\n", to_str(op.as_opnd()).c_str()); + printDone = true; + } + Opnd stk(jtm, m_base, vstack_off(i)); + do_mov(stk, s); + rfree(s); + s.to_mem(m_base, vstack_off(i)); + rref(s); + } + if (is_set(DBG_TRACE_CG) && printDone) { + dbg(";;>~vunref for %s\n", to_str(op.as_opnd()).c_str()); + } +} + +void CodeGen::vvar_def(jtype jt, unsigned idx) +{ + Val& v = m_jframe->var(idx); + if (v.jt() != jt) { + rfree(v); + v = Val(jt, m_base, m_stack.local(idx)); + rref(v); + } + if (is_wide(jt)) { + Val& v1 = m_jframe->var(idx+1); + if (v1.jt() != jt) { + rfree(v1); + v1 = Val(jt, m_base, m_stack.local(idx+1)); + rref(v1); + } + } +} + + +Val& CodeGen::vlocal(jtype jt, unsigned idx, bool forDef) +{ + Val& v = m_jframe->var(idx); + if (v.is_dummy()) { + // Not initialized - set up default values + v.to_mem(m_base, vlocal_off(idx)); + rref(v); + } + // jretAddr - special case for ASTORE_ in JSR block. + assert(v.jt() == jvoid || v.jt() == jt || + (v.jt() == jretAddr && jt == jobj) || + (v.jt() == jobj && jt == jretAddr)); + // The following combinations are possible: + // has global assignment ? | where's currently ? | what to do ? + // yes | reg | if (forDef) {unref} else {noop} + // yes | mem | if (forDef) {no op} else {load into reg} + // + // no | reg | if (forDef) {unref} else {noop} + // no | mem | + + if (v.jt() == jvoid) { + rfree(v); + assert(v.is_mem()); + v = Val(jt, v.base(), v.disp()); + rref(v); + } + + if (forDef) { + vunref(jt, v); + } + + AR ar = vreg(jt, idx); + + if (ar != ar_x && v.is_reg()) { + // Must be exactly the same as statically allocated + assert(v.reg() == ar); + } + else if (ar != ar_x) { + assert(v.is_mem()); + // unref() - actually, no need to unref() - + // as the var has global assignment, we just could not + // load onto the operant stack the memory reference + for (unsigned i=0; i<m_jframe->size(); i++) { + assert(vvar_idx(m_jframe->dip(i)) != (int)idx); + } + rfree(v); + v.to_reg(ar); + rref(v); + if (!forDef) { + ld(jtmov(jt), ar, m_base, vlocal_off(idx)); + } + } + return v; +} + +void CodeGen::vpop(void) +{ + Val& s = m_jframe->dip(0); + rfree(s); + if (is_wide(s.jt())) { + Val& s1 = m_jframe->dip(1); + if (!s1.is_dummy()) rfree(s1); + } + m_jframe->pop(m_jframe->top()); +} + + + +void CodeGen::vpush(jtype jt) +{ + m_jframe->push(jt); + Val& s = m_jframe->dip(0); + s.to_mem(m_base, vstack_off(0)); + rref(s); +} + +void CodeGen::vpush(const Val& s) +{ + assert(s.jt() != jvoid); + // use vpush2() for big types + assert(!is_big(s.jt())); + m_jframe->push(s.jt()); + m_jframe->dip(0) = s; + rref(s); +} + +void CodeGen::vpush2(const Val& op_lo, const Val& op_hi) +{ + assert(op_lo.jt() != jvoid && is_big(op_lo.jt())); + assert(op_hi.jt() != jvoid && is_big(op_hi.jt())); + assert(op_hi.jt() == op_lo.jt()); + // not a big problem, just a self-check - this is expected usage sheme + //assert(op_hi.kind() == op_lo.kind()); + + m_jframe->push(op_lo.jt()); + m_jframe->dip(1) = op_hi; + m_jframe->dip(0) = op_lo; + rref(op_hi); + rref(op_lo); +} + +void CodeGen::vpop2(Val* pop_lo, Val* pop_hi) +{ + assert(is_big(m_jframe->top())); + *pop_hi = vstack(1); + *pop_lo = vstack(0); + rfree(*pop_hi); + rfree(*pop_lo); + m_jframe->pop2(); +} + +bool CodeGen::vis_arg(unsigned local_idx) const +{ + if (local_idx >= m_argSlots)return false; + int argid = m_argids[local_idx]; + if(argid == -1) return false; + if (m_ci.reg(argid) != ar_x) return false; + return true; +} + +unsigned CodeGen::vget_arg(unsigned local_idx) const +{ + assert(vis_arg(local_idx)); + int argid = m_argids[local_idx]; + return argid; +} + + +int CodeGen::vlocal_off(unsigned idx) const +{ + if (!vis_arg(idx)) { + return voff(m_stack.local(idx)); + } + int argid = m_argids[idx]; + assert(argid != -1); + return voff(m_ci.off(argid) + STACK_SLOT_SIZE);//SSS <=retAddr +} + +int CodeGen::vstack_off(unsigned depth) const +{ + unsigned slot = m_jframe->depth2slot(depth); + int off = m_stack.stack_slot(slot); + return voff(off); +} + +int CodeGen::voff(int off) const +{ + if (m_base != sp) { + return off; + } + return off + m_stack.size() + m_depth; +} + +void CodeGen::vswap(unsigned depth) +{ + Val& v = m_jframe->dip(depth); + if (v.is_dummy() || vis_stack(v)) { + return; + } + Val mem(v.jt(), m_base, vstack_off(depth)); + rlock(v); + do_mov(mem, v); + runlock(v); + + rfree(v); + v.to_mem(m_base, vstack_off(depth)); + rref(v); + assert(vis_stack(v)); +} + +void Compiler::gen_bb_leave(unsigned to) +{ + if (is_set(DBG_TRACE_CG)) { dbg(";;>bb_leave to %d\n", to); } + unsigned ref_count; + bool to_eh; + if (to == NOTHING || m_pc == 0) { + // leaving JSR block - act as if were leaving to multiref block + // Also, special processing for 0th BB - see also gen_bb_enter() + // and gen_prolog(). + ref_count = 2; + to_eh = false; + } + else { + ref_count = m_insts[to].ref_count; + const BBInfo& bbto = m_bbs[to]; + // Must be BB + assert(m_bbs.find(to) != m_bbs.end()); + // Jumps to ehandler ? + to_eh = bbto.ehandler; + } + // Must be reachable + assert(ref_count != 0); + + if (to_eh) { + // we're generating a 'goto/fall through/if_' to a basic block + // if the BB is also the catch handler, then it can't have a + // ref_count less than 2. + assert(m_insts[to].ref_count > 1); + // Must have only Exception on the top of stack + assert(m_jframe->size() == 1 && m_jframe->top(0) == jobj); + // if top of the stack is currently not on the gr_ret, then + // force it to be there + assert(m_jframe->dip(0).is_reg() && m_jframe->dip(0).reg() == gr_ret); + } + + if (ref_count == 1 && !to_eh) { + // nothing to do anymore + if (is_set(DBG_TRACE_CG)) { dbg(";;>~bb_leave\n"); } + return; + } + + for (unsigned i=0; !to_eh && i<m_jframe->size(); i++) { + Val& v = m_jframe->dip(i); + // already in the memory - nothing to do + if (vis_stack(v)) continue; + vswap(i); + //assert(vis_stack(v)); + //if (is_wide(v.jt()) && !is_big(v.jt())) { + // ++i; + //} + } + + unsigned vars = m_infoBlock.get_num_locals(); + // park all locals + for (unsigned i=0; i<vars; i++) { + Val& v = m_jframe->var(i); + AR ar = m_ra[i]; + // + if (v.is_mem() && ar == ar_x) { continue; } + if (ar == ar_x) { + assert(v.is_reg()); + // need to spill out + assert(v.jt() != jvoid); + jtype jtm = jtmov(v.jt()); + st(jtm, v.reg(), m_base, vlocal_off(i)); + rfree(v); + v = Val(v.jt(), m_base, vlocal_off(i)); + rref(v); + continue; + } + // must have global assignment + jtype jt = m_staticTypes[i]; + assert(jt != jvoid); + jtype jtm = jtmov(jt); + + if (v.is_mem()) { + if (!is_callee_save(ar) && to_eh) { + // entering catch handler - must leave the var on memory + continue; + } + ld(jtm, ar, m_base, vlocal_off(i)); + rfree(v); + v = Val(jt, ar); + rref(v); + continue; + } + assert(v.is_reg() && v.reg() == ar); + if (is_callee_save(ar) || !to_eh) { + continue; + } + // entering catch handler - must swap the var to memory + st(jtm, ar, m_base, vlocal_off(i)); + rfree(v); + v = Val(jt, m_base, vlocal_off(i)); + rref(v); + } + if (is_set(DBG_TRACE_CG)) { dbg(";;>~bb_leave\n"); } +} + +void Compiler::gen_bb_enter(void) +{ + assert(m_bbs.find(m_pc) != m_bbs.end()); + const BBInfo& bbinfo = m_bbs[m_pc]; + if (is_set(DBG_TRACE_CG)) { dbg(";;>bb_enter to %d\n", m_pc); } + if (bbinfo.ehandler) { + assert(m_jframe->size() == 1); + Val& s = m_jframe->dip(0); + if (!s.is_reg()) { + rref(gr_ret); + s = Val(jobj, gr_ret); + // We're entering exception handler - that do not have 'direct' + // (non exception) ways in it - the object on the top of the + // stack is exception and is guaranteed to be non-null. + if (m_insts[m_pc].ref_count == 1) { + s.set(VA_NZ); + } + } + else { + assert(s.reg() == gr_ret); + } + } + // We always process 0th BB as multiref BB - see also gen_prolog() + // when it calls gen_bb_leave(NOTHING). + if (m_insts[m_pc].ref_count == 1 && m_pc != 0 && !bbinfo.ehandler) { + if (is_set(DBG_TRACE_CG)) { dbg(";;>~bb_enter\n"); } + return; + } + + rclear(); + + unsigned vars = m_infoBlock.get_num_locals(); + for (unsigned i=0; i<vars; i++) { + AR ar = m_ra[i]; + jtype jtglobal = m_staticTypes[i]; + Val& v = m_jframe->var(i); + // If we enter a BB - then every reg-assigned local is on its reg, + // until we're entering exception handler... + if (ar != ar_x && (is_callee_save(ar) || !bbinfo.ehandler)) { + assert(jtglobal != jvoid); + // Overwrite attributes as well + v = Val(jtglobal, ar); + rref(v); + continue; + } + // ... in this case, scratch-regs assigned variables are in memory + assert(ar == ar_x || bbinfo.ehandler); + if (jtglobal != jvoid) { + v = Val(jtglobal, m_base, vlocal_off(i)); + } + else { + v = Val(jvoid, m_base, vlocal_off(i)); + } + assert(v.is_mem()); + rref(v); + } + for (unsigned i=0; i<m_jframe->size(); i++) { + Val& s = m_jframe->dip(i); + if (i==0 && bbinfo.ehandler) { + assert(s.is_reg() && s.reg() == gr_ret); + } + else { + s = Val(s.jt(), m_base, vstack_off(i)); + } + rref(s); + } + // For non-static methods, that also do not write into the 0th slot, + // we can guarantee that 0th slot (thiz) is always non-null. + if (!(meth_is_static()) && m_defs[0] == 0) { + Val& v = m_jframe->var(0); + v.set(VA_NZ); + } + if (is_set(DBG_TRACE_CG)) { dbg(";;>~bb_enter\n"); } +} + +void CodeGen::vpark(bool doStack) +{ + bool do_print = true; + for (unsigned i=0; i<m_infoBlock.get_num_locals(); i++) { + Val& v = m_jframe->var(i); + if (!v.is_reg() || is_callee_save(v.reg())) continue; + if (is_set(DBG_TRACE_CG) && do_print) { + dbg(";; >vpark(all)\n"); + do_print = false; + } + vpark(v.reg(), doStack); + } + for (unsigned i=0; doStack && i<m_jframe->size(); i++) { + Val& s = m_jframe->dip(i); + unsigned saveI = i; + // refers to local variable - will be no changes as result of call + if (vvar_idx(s) != -1) continue; + // the stack item itself, will not change during the call + if (vis_stack(s)) continue; + // Something constant or a register + if (s.survive_calls()) continue; + if (s.is_reg() && is_callee_save(s.reg())) continue; + if (is_set(DBG_TRACE_CG) && do_print) { + dbg(";; >vpark(all)\n"); + do_print = false; + } + vswap(saveI); + } + if (is_set(DBG_TRACE_CG) && !do_print) { + dbg(";; >~vpark(all)\n"); + } +} + +void CodeGen::vpark(AR ar, bool doStack) +{ + bool do_print = true; + rlock(ar); + for (unsigned i=0; i<m_infoBlock.get_num_locals(); i++) { + Val& v = m_jframe->var(i); + if (!v.is_reg() || v.reg() != ar) continue; + if (do_print && is_set(DBG_TRACE_CG)) { + dbg(";;>vpark(%s)\n", to_str(ar).c_str()); + do_print = false; + } + + jtype jtm = jtmov(v.jt()); + if (true || (m_defs[i] != 0)) { + // XXX actually, we need an attribute, whether the variable + // was changed. + // m_defs[i] != 0 works bad for example if float point + // parameter came on an register + st(jtm, v.reg(), m_base, vlocal_off(i)); + } + rfree(v); + v.to_mem(m_base, vlocal_off(i)); + rref(v); + } + for (unsigned k=0; doStack && k<m_jframe->size(); k++) { + Val& s = m_jframe->dip(k); + if (!s.uses(ar)) continue; + jtype jtm = jtmov(s.jt()); + if (do_print && is_set(DBG_TRACE_CG)) { + dbg(";;>vpark(%s)\n", to_str(ar).c_str()); + do_print = false; + } + rfree(s); + Opnd stk(jtm, m_base, vstack_off(k)); + if (s.is_reg()) { + mov(stk, Opnd(jtm, ar)); + } + else { + do_mov(stk, s); + } + s.to_mem(m_base, vstack_off(k)); + rref(s); + } + runlock(ar); + if (!do_print && is_set(DBG_TRACE_CG)) { + dbg(";;>~vpark(%s)\n", to_str(ar).c_str()); + } +} + +void CodeGen::vcheck(void) +{ + unsigned regs[ar_num]; + for (unsigned i=0; i<ar_num; i++) { + regs[i] = 0; + } + const AR noar = (AR)NOTHING; + for (unsigned i=0; i<m_jframe->size(); i++) { + const Val& s = m_jframe->dip(i); + if (s.is_reg()) { + unsigned idx = ar_idx(s.reg()); + regs[idx]++; + } + else if (s.is_mem()) { + if (s.base() != ar_x && s.base() != noar) { regs[ar_idx(s.base())]++; }; + assert(s.index() != noar); + if (s.index() != ar_x) { regs[ar_idx(s.index())]++; }; + } + } + for (unsigned i=0; i<m_jframe->num_vars(); i++) { + Val& s = m_jframe->var(i); + if (s.is_reg()) { + unsigned idx = ar_idx(s.reg()); + regs[idx]++; + } + else if (s.is_mem()) { + if (s.base() != ar_x && s.base() != noar) { regs[ar_idx(s.base())]++; }; + assert(s.index() != noar); + if (s.index() != ar_x) { regs[ar_idx(s.index())]++; }; + } + } + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + // + if (rlocks(ar) != 0) { + dbg_dump_state("Register lock cant cross instruction boundaries", + m_bbstate); + assert(false); + } + if (rrefs(ar) != regs[i]) { + dbg("ERROR: leaked/lost register: %s. refs=%u, must be=%u", + Encoder::to_str(ar).c_str(), rrefs(ar), regs[i]); + dbg_dump_state("Problematic frame:", m_bbstate); + assert(false); + } + } +} + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/cg_stk.cpp vm/jitrino/src/jet/cg_stk.cpp new file mode 100644 index 0000000..9bb69f9 --- /dev/null +++ vm/jitrino/src/jet/cg_stk.cpp @@ -0,0 +1,345 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +#include "compiler.h" +#include "trace.h" + +#include <malloc.h> +#include <memory.h> +#include <assert.h> +#include <stdlib.h> + +#include <jit_import.h> + +/** + * @file + * @brief CodeGen routines for PUSH/POP, LDC and LD/ST. + */ + +namespace Jitrino { +namespace Jet { + +void CodeGen::gen_ldc(void) +{ + jtype jtyp = to_jtype(class_get_const_type( + m_klass, (unsigned short)m_curr_inst->op0)); + if (jtyp != jobj) { // if not loading String + const void * p = class_get_const_addr(m_klass, m_curr_inst->op0); + assert(p); + if (jtyp == dbl64 || jtyp == flt32) { + gen_push(jtyp, p); + } + else if(jtyp == i64) { + gen_push(*(jlong*)p); + } + else if(jtyp == i32) { + gen_push(*(int*)p); + } + else if(jtyp == u16) { + gen_push(*(unsigned short*)p); + } + else if(jtyp == i16) { + gen_push(*(short*)p); + } + else { + assert(jtyp == i8); + gen_push(*(char*)p); + } + return; + } + assert(m_curr_inst->opcode != OPCODE_LDC2_W); + gen_call_vm(ci_helper_io, rt_helper_ldc_string, 0, m_curr_inst->op0, + m_klass); + gen_save_ret(jobj); + vstack(0).set(VA_NZ); + m_bbstate->seen_gcpt = true; +} + +void CodeGen::gen_push(int ival) +{ + vpush(Val(ival)); +} + +void CodeGen::gen_push(jlong lval) +{ + if (is_big(i64)) { + vpush2(Val((jlong)lo32(lval)), Val((jlong)hi32(lval))); + } + else { + vpush(Val(lval)); + } +} + +void CodeGen::gen_push(jtype jt, const void *p) +{ + if (jt == dbl64) { + vpush(Val(*(double*)p, p)); + } + else if (jt == flt32) { + vpush(Val(*(float*)p, p)); + } + else { + assert(jt==jobj); + // This is for brand new 1.5's 'LDC object'. + // The object loaded is marked as constant which can cross a call + // site, however must check with VM/GC guys whether this is indeed + // true. + // XXX: So, are the 'LDC object'-s pinned ? + // For now, using conservative approach. + vpush(Val(jobj, p)); // vpush(Val(jobj, p).long_live()); + } +} + +void CodeGen::gen_pop(jtype jt) +{ + vpop(); +} + +void CodeGen::gen_pop2(void) +{ + jtype jt = m_jframe->top(); + if (is_wide(jt)) { + vpop(); + } + else { + vpop(); + assert(!is_wide(m_jframe->top())); + vpop(); + } +} + +void CodeGen::gen_dup(JavaByteCodes opc) +{ + jtype jtop = m_jframe->top(); + +// Only need to take a special action if 's' is a stack item resides in +// the stack memory area. If it points to +// local/static/const/field/register/whatever then can simply duplicate it. +#define COPY_SLOT(dst, src) \ + { \ + const Val& ssrc = vstack(src); \ + if (vis_stack(ssrc) && !ssrc.is_dummy()) { \ + vstack(src, true); \ + } \ + Val& sdst = vstack(dst); \ + rfree(sdst); \ + sdst = ssrc; \ + rref(sdst); \ + } + + if (opc == OPCODE_SWAP) { + // stack: .. val1, val2 => val2, val1 + Val& val2 = vstack(0, vis_stack(0)); + rlock(val2); + Val& val1 = vstack(1, vis_stack(1)); + runlock(val2); + Val tmp = val1; + val1 = val2; + val2 = tmp; + return; + } + + if (opc == OPCODE_DUP) { + // [.. val] => [.. val, val] + vpush(jtop); + COPY_SLOT(0, 1); + return; + } + + if (opc==OPCODE_DUP2) { + // [.. val64] => [.. val64, val64] + vpush(jtop); + if (!is_wide(jtop)) { + vpush(jtop); + } + COPY_SLOT(0, 2); + COPY_SLOT(1, 3); + return; + } + + if (opc == OPCODE_DUP_X1) { + // [..., value2, value1] => [.. value1, value2, value1] + // 1. push(jtop) + // result: val2, val1, typeof(val1) + // 2. depth(0) = depth(1) + // result: val2, val1, val1 + // 3. depth(1) = depth(2) + // result: val2, val2, val1 + // 4. depth(2) = depth(0) + // result: val1, val2, val1 + vpush(jtop); + COPY_SLOT(0, 1); + COPY_SLOT(1, 2); + COPY_SLOT(2, 0); + return; + } + + // DUP_X2 + if (opc == OPCODE_DUP_X2) { + // Form 1: .. val3, val2, val1 => val1, val3, val2, val1 + // Form 2: .. val2.hi, val2.lo, val1.32 => + // ..val1, val2.hi, val2.lo, val1 + // form1: + // 1. push(typeof(depth(0))) + // result: val3, val2, val1, typeof(val1) + // 2. depth(0) = depth(1) + // result: val3, val2, val1, val1 + // 3. depth(1) = depth(2) + // result: val3, val2, val2, val1 + // 4. depth(2) = depth(3) + // result: val3, val3, val2, val1 + // 5. depth(3) = depth(0) + // result: val1, val3, val2, val1 + vpush(jtop); + COPY_SLOT(0, 1); + COPY_SLOT(1, 2); + COPY_SLOT(2, 3); + COPY_SLOT(3, 0); + return; + } + + if (opc == OPCODE_DUP2_X1) { + // Form 1: val3, val2, val1 => val2, val1, val3, val2, val1 + // Form 2: [..., val2.32, val1.64] => [.. val1, val2, val1] + // A strategy: + // 1. push(typeof(v1)) + // result: .. val2, val1.64, val1.64(unknown location) + // 2. depth(0) = depth(2) ; depth(1) = depth(3) + // result: .. val2, val1.64, val1.64 + // 3. depth(2) = depth(4) ; + // result: .. val2, zzz, val2, val1.64 + // zzz is former high part of val1 + // 4. depth(3) = depth(0) + // result: .. val2, val1.lo, val2, val1.64 + // 5. depth(4) = depth(1) + // result: .. val1.hi, val1.lo, val2, val1.64 + vpush(jtop); + if (!is_wide(jtop)) { + vpush(jtop); + } + COPY_SLOT(0, 2); COPY_SLOT(1, 3); + COPY_SLOT(2, 4); + COPY_SLOT(3, 0); + COPY_SLOT(4, 1); + return; + } + if (opc == OPCODE_DUP2_X2) { + // [.. val2.64, val1.64] => [.. val1.64, val2.64, val1.64] + //f1 .., val4, val3, val2, val1 => val2, val1, val4, val3, val2, val1 + //f2 .., val3, val2, val1 ..., val1, val3, val2, val1 + //f3 .., val3, val2, val1 ..., val2, val1, val3, val2, val1 + //f4 .., val2, val1 ..., val1, val2, val1 + // + // A strategy: + // 1. push(any-wide-type) + // result: val4, val3, val2, val1, xx, xx + // 2. depth(0) = depth(2) + // 3. depth(1) = depth(3) + // result: val4, val3, val2, val1, val2, val1 + // 4. depth(2) = depth(4) + // 5. depth(3) = depth(5) + // result: val4, val3, val4, val3, val2, val1 + // 6. depth(4) = depth(0) + // 7. depth(5) = depth(1) + // result: val2, val1, val2, val1, val2, val1 + vpush(i64); // the type does not really matter + // 2, 3 + COPY_SLOT(0, 2); + COPY_SLOT(1, 3); + // 4, 5 + COPY_SLOT(2, 4); + COPY_SLOT(3, 5); + // 6, 7 + COPY_SLOT(4, 0); + COPY_SLOT(5, 1); + return; + } + assert(false); +} + + +void CodeGen::gen_ld(jtype jt, unsigned idx) +{ + if (is_big(jt)) { + Val vlo = vlocal(jt, idx, false); + rlock(vlo); + Val vhi = vlocal(jt, idx+1, false); + vpush2(vlo, vhi); + runlock(vlo); + } + else { + Val& v = vlocal(jt, idx, false); + vpush(v); + } +} + +void CodeGen::gen_st(jtype jt, unsigned idx) +{ + vvar_def(jt, idx); + gen_gc_mark_local(jt, idx); + // + // v|s + // -|-|------------------------- + // r|m| move + // r|i| move + // r|r| move + // m|m| allocate reg, then move + // m|r| move + // m|i| move + // + Val s0 = vstack(0); + rlock(s0); + Val& var = vlocal(jt, idx, true); + runlock(s0); + vunref(jt, var); + if (var.is_mem() && s0.is_reg() && rrefs(s0.reg()) == 1) { + // The local is on memory, though the stack item is on register + vunref(jt, s0, 0); + vassign(jt, idx, s0); + } + else { + do_mov(var, s0); + } + var.attrs(s0.attrs()); + + if (is_big(jt)) { + // + ++idx; + // + Val s0 = vstack(1); + rlock(s0); + Val& var = vlocal(jt, idx, true); + runlock(s0); + vunref(jt, var); + if (var.is_mem() && s0.is_reg() && rrefs(s0.reg()) == 1) { + // The local is on memory, though the stack item is on register + vunref(jt, s0, 1); + vassign(jt, idx, s0); + } + else { + do_mov(var, s0); + } + var.attrs(s0.attrs()); + } + vpop(); +} + + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/compiler.cpp vm/jitrino/src/jet/compiler.cpp index 3f212bf..76c1f65 100644 --- vm/jitrino/src/jet/compiler.cpp +++ vm/jitrino/src/jet/compiler.cpp @@ -1,3 +1,4 @@ + /* * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. * @@ -14,16 +15,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.7.12.4.4.5 $ - */ - -/** - * @file - * @brief Platform independent part of Compiler methods, mostly related to - * basic blocks processing. + * @author Alexander Astapchuk + * @version $Revision$ */ - + /** + * @file + * @brief Compiler class' main methods implementation. + */ #include <assert.h> #include <algorithm> #include <malloc.h> @@ -35,15 +33,21 @@ #include "jit_intf.h" #include "../shared/mkernel.h" +#include "jet.h" + #include "compiler.h" #include "trace.h" #include "stats.h" +#include <stack> +using std::stack; #if !defined(PROJECT_JET) #include "Jitrino.h" #include "VMInterface.h" #include "DrlVMInterface.h" + #include "EMInterface.h" + #include "JITInstanceContext.h" #else /** * See DrlVMInterface.h/g_compileLock and @@ -52,74 +56,226 @@ #else static Jitrino::Mutex g_compileLock; #endif -namespace Jitrino { -namespace Jet { - -#if defined(JET_PROTO) - -// Only used for compilation's stress testing/performance tuning -static JIT_Handle shared_jit_handle = 0; - -// Only used for compilation's stress testing/performance tuning -extern "C" __declspec(dllexport) void * get_jet_jit(void) { - return shared_jit_handle; -} +#include "../main/Log.h" +using Jitrino::Log; +using Jitrino::LogStream; +#ifndef PLATFORM_POSIX + #define snprintf _snprintf #endif -const int Compiler::g_iconst_m1 = -1; -const int Compiler::g_iconst_0 = 0; -const int Compiler::g_iconst_1 = 1; +namespace Jitrino { +namespace Jet { -const float Compiler::g_fconst_0 = 0.; -const float Compiler::g_fconst_1 = 1.; -const float Compiler::g_fconst_2 = 2.; -const double Compiler::g_dconst_0 = 0.; -const double Compiler::g_dconst_1 = 1.; -#if defined(JIT_STATS) || defined(JIT_LOGS) || \ - defined(JET_PROTO) || defined(_DEBUG) -unsigned Compiler::g_methodsSeen = 0; -#else -const char Compiler::m_fname[1] = {0}; -#endif +unsigned Compiler::defaultFlags = JMF_BBPOLLING; +unsigned Compiler::g_acceptStartID = NOTHING; +unsigned Compiler::g_acceptEndID = NOTHING; +unsigned Compiler::g_rejectStartID = NOTHING; +unsigned Compiler::g_rejectEndID = NOTHING; -unsigned Compiler::defaultFlags = JMF_BBPOOLING; +/** + * Simple counter of how much times the Compiler::compile() was called. + */ +static unsigned methodsSeen = 0; -JIT_Result Compiler::compile(Compile_Handle ch, Method_Handle method) +JIT_Result Compiler::compile(Compile_Handle ch, Method_Handle method, + const OpenMethodExecutionParams& params) { + compilation_params = params; m_compileHandle = ch; - m_method = method; - m_klass = method_get_class(method); - -#if defined(_DEBUG) || defined(JIT_STATS) || defined(JIT_LOGS) - m_fname[0] = 0; - const char * mname = method_get_name(method); - const char * msig = method_get_descriptor(method); msig = msig; - const char * kname = class_get_name(m_klass); - snprintf(m_fname, sizeof(m_fname)-1, "%s::%s", kname, mname); - ++g_methodsSeen; -#else - const char * msig = ""; msig = msig; -#endif + MethInfo::init(method); - STATS_SET_NAME_FILER(NULL); - - unsigned compile_flags = defaultFlags; //JMF_LAZY_RESOLUTION; + // Currently use bp-based frame + m_base = bp; + // Will be used later, with sp-based frame + m_depth = 0; + // + // Check contract with VM + // + assert(!method_is_abstract(method) && + "VM must not try to compile abstract method!"); + assert(!method_is_native(method) && + "VM must not try to compile native method!"); + + STATS_SET_NAME_FILER(NULL); + m_methID = ++methodsSeen; + + unsigned compile_flags = defaultFlags; initProfilingData(&compile_flags); + // + // the latest PMF machinery seems working without much overhead, + // let's try to have tracing functionality on by default + // +#if 1 //def JET_PROTO -#if defined(_DEBUG) || defined(JET_PROTO) - dbg_break_pc = NOTHING; -#endif + // Ensure no memory problems exist on entrance + if (get_bool_arg("checkmem", false)) { + dbg_check_mem(); + } -#if defined(_DEBUG) && defined(JET_PROTO) - compile_flags |= DBG_TRACE_SUMM; -#endif + const char * lp; + // + // Process args, update flags if necessary + // + if (!get_bool_arg("bbp", true)) { + compile_flags &= JMF_BBPOLLING; + } + // + // Debugging support + // + lp = get_arg("log", NULL); + if (lp != NULL) { + if (NULL != strstr(lp, "ct")) { + bool ct = false; + if (NULL != strstr(lp, "sum")) { + compile_flags |= DBG_TRACE_SUMM; + ct = true; + } + static const unsigned TRACE_CG = + DBG_DUMP_BBS | DBG_TRACE_CG | + DBG_TRACE_SUMM | DBG_DUMP_CODE; + if (NULL != strstr(lp, "cg")) { + compile_flags |= TRACE_CG; + ct = true; + } + if (NULL != strstr(lp, "layout")) { + compile_flags |= DBG_TRACE_LAYOUT; + ct = true; + } + if (NULL != strstr(lp, "code")) { + compile_flags |= DBG_DUMP_CODE; + ct = true; + } + if (!ct) { + // No category means 'code+sum' + compile_flags |= DBG_DUMP_CODE|DBG_TRACE_SUMM; + } + } + + if (Log::log_rt().isEnabled()) { + if (NULL != strstr(lp, "rtsupp")) { + compile_flags |= DBG_TRACE_RT; + } + if (NULL != strstr(lp, "ee")) { + compile_flags |= DBG_TRACE_EE; + } + if (NULL != strstr(lp, "bc")) { + compile_flags |= DBG_TRACE_BC; + } + } + } // ~compLS.isEnabled() + + // + // Accept or reject the method ? + // + bool accept = true; + if (g_acceptStartID != NOTHING && m_methID < g_acceptStartID) { + accept = false; + } + if (g_acceptEndID != NOTHING && m_methID > g_acceptEndID) { + accept = false; + } + if (g_rejectStartID != NOTHING && m_methID >= g_rejectStartID) { + accept = false; + } + if (g_rejectEndID != NOTHING && m_methID <= g_rejectEndID) { + accept = false; + } + lp = get_arg("reject", NULL); + if (lp != NULL && isalpha(lp[0])) { + accept = !to_bool(lp); + } + + if (!accept) { + if (compile_flags & DBG_TRACE_SUMM) { + //dbg_trace_comp_start(); + //dbg_trace_comp_end(false, "Due to accept or reject argument."); + } + return JIT_FAILURE; + } + // + // A special way to accept/reject method - list of method in file. + // May be useful to find problematic method in multi threaded + // compilation env when id-s get changed much. + // + static bool loadList = true; + static vector<string> data; + if (loadList) { + lp = get_arg("list", NULL); + if (lp != NULL) { + FILE * f = fopen(lp, "r"); + if (f != NULL) { + char buf[1024*4]; + while(NULL != fgets(buf, sizeof(buf)-1, f)) { + // Skip comments + if (buf[0] == '#') continue; + int len = strlen(buf); + // Trim CRLF + if (len>=1 && buf[len-1]<=' ') { buf[len-1] = 0; } + if (len>=2 && buf[len-2]<=' ') { buf[len-2] = 0; } + data.push_back(buf); + } + fclose(f); + } // if f != NULL + else { + dbg("WARN: list option - can not open '%s'.\b", lp); + } + } + loadList = false; + } + bool found = data.size() == 0; + for (unsigned i=0; i<data.size(); i++) { + const string& s = data[i]; + if (!strcmp(meth_fname(), s.c_str())) { + found = true; + break; + } + } + if (!found) { + if (compile_flags & DBG_TRACE_SUMM) { + //dbg_trace_comp_start(); + //dbg_trace_comp_end(false, "Not in file list."); + } + return JIT_FAILURE; + } + + // + // Only emulate compilation, without registering code in the VM ? + // + m_bEmulation = get_bool_arg("emulate", false); + + // + // Check stack integrity ? + // + if (get_bool_arg("checkstack", false)) { + compile_flags |= DBG_CHECK_STACK; + } + + // + // Insert software breakpoint at specified place of method ? + // + dbg_break_pc = NOTHING; + lp = get_arg("brk", NULL); + if (lp == NULL) { lp = get_arg("break", NULL); }; + if (lp != NULL) { + // PC specified where to insert breakpoint into ... + if (isdigit(lp[0])) { + dbg_break_pc = atoi(lp); + } + else { + // no PC specified - break at entrance. + compile_flags |= DBG_BRK; + } + } +#endif // ~JET_PROTO if (compile_flags & DBG_TRACE_SUMM) { dbg_trace_comp_start(); } + + Encoder::m_trace = (compile_flags & DBG_TRACE_CG); if (NULL == rt_helper_throw) { // The very first call of ::compile(), initialize @@ -127,31 +283,23 @@ #endif initStatics(); } - Timers::compTotal.start(); - Timers::compInit.start(); - + m_max_native_stack_depth = 0; m_bc = (unsigned char*)method_get_byte_code_addr(m_method); unsigned bc_size = method_get_byte_code_size(m_method); unsigned num_locals = method_vars_get_number(m_method); unsigned max_stack = method_get_max_stack(m_method); - - get_args_info(m_method, m_args, &m_retType); - unsigned num_input_slots = count_slots(m_args); - - m_java_meth_flags = method_get_flags(m_method); - - m_patchID = -1; - if (compile_flags & JMF_LAZY_RESOLUTION) { - m_codeStream.init((size_t)(bc_size* - NATIVE_CODE_SIZE_2_BC_SIZE_RATIO_LAZY)); - m_patchItems.reserve((size_t)(bc_size* - PATCH_COUNT_2_BC_SIZE_RATIO_LAZY)); - } - else { - m_codeStream.init((size_t)(bc_size*NATIVE_CODE_SIZE_2_BC_SIZE_RATIO)); - m_patchItems.reserve((size_t)(bc_size*PATCH_COUNT_2_BC_SIZE_RATIO)); - } - + + // Input arguments + ::std::vector<jtype> inargs; + get_args_info(m_method, inargs, &m_retType); + m_ci.init(CCONV_MANAGED, inargs); + unsigned num_input_slots = count_slots(inargs); + m_argSlots = num_input_slots; + m_argids.resize(num_input_slots); //[in_slots]; + m_ra.resize(num_locals, ar_x); + // + + m_codeStream.init((size_t)(bc_size*NATIVE_CODE_SIZE_2_BC_SIZE_RATIO)); m_stack.init(num_locals, max_stack, num_input_slots); // We need to report 'this' additionally for the following cases: // - non-static sync methods - to allow VM to call monitor_exit() for @@ -161,100 +309,135 @@ #endif // stack_trace.cpp + com_openintel_drl_vm_VMStack.cpp: // Java_com_openintel_drl_vm_VMStack_getStackState. // - if (!method_is_static(m_method)) { - if (method_is_synchronized(m_method) || - (class_hint_is_exceptiontype(m_klass) && - !strcmp(method_get_name(m_method), "<init>"))) { - compile_flags |= JMF_REPORT_THIS; - } + if (!meth_is_static() && (meth_is_sync() || meth_is_exc_ctor())) { + compile_flags |= JMF_REPORT_THIS; } + m_infoBlock.init(bc_size, max_stack, num_locals, num_input_slots, compile_flags); - bool eh_ok = bbs_ehandlers_resolve(); - Timers::compInit.stop(); + bool eh_ok = comp_resolve_ehandlers(); if (!eh_ok) { // At least on of the exception handlers classes was not resolved: - // unable to resolve class of Exception => will be unable to - // register exception handlers => can't generate code at - // all => stop here - // Might need/want to [re]consider: seems good for eager - // resolution. Might want to generate LinkageError and throw it at - // runtime for lazy resolution. - if (m_infoBlock.get_flags() & DBG_TRACE_SUMM) { + // unable to resolve class of Exception => will be unable to register + // exception handlers => can't generate code et all => stop here + // TODO - might want to [re]consider and may generate LinkageError + // and throw it at runtime. + if (is_set(DBG_TRACE_SUMM)) { dbg_trace_comp_end(false, "ehandler.resolve"); } - m_infoBlock.release(); + m_infoBlock.release(); return JIT_FAILURE; } // // Initialization done, collect statistics + // STATS_INC(Stats::methodsCompiled, 1); - if (m_handlers.size() == 0) { - STATS_INC(Stats::methodsWOCatchHandlers, 1); - } - + STATS_INC(Stats::methodsWOCatchHandlers, m_handlers.size() ? 0 : 1); // - STATS_MEASURE_MIN_MAX_VALUE(bc_size, m_infoBlock.get_bc_size(), m_fname); - STATS_MEASURE_MIN_MAX_VALUE(jstack, max_stack, m_fname); - STATS_MEASURE_MIN_MAX_VALUE(locals, num_locals, m_fname); + STATS_MEASURE_MIN_MAX_VALUE(bc_size, m_infoBlock.get_bc_size(), meth_fname()); + STATS_MEASURE_MIN_MAX_VALUE(jstack, max_stack, meth_fname()); + STATS_MEASURE_MIN_MAX_VALUE(locals, num_locals, meth_fname()); // - // ~end of Stats + // ~Stats // - - m_insts.alloc(bc_size); - - Timers::compMarkBBs.start(); - bbs_mark_all(); - Timers::compMarkBBs.stop(); - + m_insts.alloc(bc_size, true); + // + // Initialization ends, + // Phase 1 - decoding instructions, finding basic blocks. + // + comp_parse_bytecode(); + comp_alloc_regs(); // Statistics:: number of basic blocks - STATS_MEASURE_MIN_MAX_VALUE(bbs, m_bbs.size(), m_fname); + STATS_MEASURE_MIN_MAX_VALUE(bbs, m_bbs.size(), meth_fname()); - if (m_infoBlock.get_flags() & DBG_DUMP_BBS) { + if (is_set(DBG_DUMP_BBS)) { dbg_dump_bbs(); } + // + // Phase 2 - code generation. + // + SmartPtr<BBState> allStates; + allStates.alloc(m_bbs.size()); + unsigned c = 0; + for (BBMAP::iterator i=m_bbs.begin(); i != m_bbs.end(); i++, c++) { + m_bbStates[i->first] = &allStates[c]; + } + m_bbStates[0]->jframe.init(m_infoBlock.get_stack_max(), + m_infoBlock.get_num_locals()); - Timers::compCodeGen.start(); - // generate code - will recursively generate all the reachable - // code, except the exception handlers - bbs_gen_code(0, NULL, NOTHING); - // generate exception handlers - for (unsigned i=0; i<m_handlers.size(); i++) { - bbs_gen_code(m_handlers[i].handler, NULL, NOTHING); - } - Timers::compCodeGen.stop(); + // Generate the whole code - will recursively generate all the + // reachable code, except the exception handlers ... + comp_gen_code_bb(0); + + // ... now, generate exception handlers ... + for (unsigned i=0; i<m_handlers.size(); i++) { + comp_gen_code_bb(m_handlers[i].handler); + } + + // ... and finally, generate prolog. + // Fake BB data - it's used in gen_prolog() + BBInfo bbinfo; + unsigned prolog_ipoff = bbinfo.ipoff = ipoff(); + BBState bbstate; + bbstate.jframe.init(m_infoBlock.get_stack_max(), + m_infoBlock.get_num_locals()); + m_bbstate = &bbstate; + m_bbinfo = &bbinfo; + m_jframe = &bbstate.jframe; + rclear(); + gen_prolog(); + unsigned prolog_size = ipoff() - prolog_ipoff; + if (is_set(DBG_TRACE_CG)) { + dbg_dump_code(m_codeStream.data() + prolog_ipoff, + prolog_size, "prolog"); + } + // + // phase 2 end. + // Register code and related info in the VM + // // ************* // * LOCK HERE * // ************* g_compileLock.lock(); - if (method_get_code_block_size_jit(m_method, jit_handle) != 0) { + if (method_get_code_block_size_jit(m_method, m_hjit) != 0) { // the code generated already - Stats::methodsCompiledSeveralTimes++; - g_compileLock.unlock(); - m_infoBlock.release(); + STATS_INC(Stats::methodsCompiledSeveralTimes, 1); + g_compileLock.unlock(); /* Unlock here */ + m_infoBlock.release(); + if (get_bool_arg("checkmem", false)) { + dbg_check_mem(); + } return JIT_SUCCESS; } - Timers::compCodeLayout.start(); - const unsigned total_code_size = m_codeStream.size(); - m_vmCode = (char*)method_allocate_code_block(m_method, jit_handle, + const unsigned total_code_size = m_codeStream.size(); + + if (m_bEmulation) { + m_vmCode = (char*)malloc(total_code_size); + } + else { + m_vmCode = (char*)method_allocate_code_block(m_method, m_hjit, total_code_size, 16/*fixme aligment*/, CODE_BLOCK_HEAT_DEFAULT, 0, CAA_Allocate); - bbs_layout_code(); - Timers::compCodeLayout.stop(); + m_infoBlock.set_code_start(m_vmCode); + } + // + // Copy and reposition code from m_codeStream into the allocated buf. + // + comp_layout_code(prolog_ipoff, prolog_size); - STATS_MEASURE_MIN_MAX_VALUE(code_size, total_code_size, m_fname); + STATS_MEASURE_MIN_MAX_VALUE(code_size, total_code_size, meth_fname()); STATS_MEASURE_MIN_MAX_VALUE(native_per_bc_ratio, m_infoBlock.get_bc_size() == 0 ? 0 : total_code_size/m_infoBlock.get_bc_size(), - m_fname); + meth_fname()); #ifdef _DEBUG // At this point, the codeStream content is completely copied into the @@ -265,256 +448,462 @@ #endif // // runtime data. must be initialized before code patching // - m_infoBlock.set_num_refs(m_lazyRefs.size()); unsigned data_size = m_infoBlock.get_total_size(); - char * pdata = (char*)method_allocate_info_block(m_method, jit_handle, - data_size); + char * pdata; + if (m_bEmulation) { + pdata = (char*)malloc(data_size); + } + else { + pdata = (char*)method_allocate_info_block(m_method, m_hjit, + data_size); + } m_infoBlock.save(pdata); // // Finalize addresses // - Timers::compCodePatch.start(); - cg_patch_code(); - Timers::compCodePatch.stop(); + comp_patch_code(); // // register exception handlers // - Timers::compEhandlers.start(); - bbs_ehandlers_set(); - Timers::compEhandlers.stop(); + if (m_bEmulation) { + // no op + } + else { + comp_set_ehandlers(); + } - // **************** - // * UN LOCK HERE * - // **************** + // *************** + // * UNLOCK HERE * + // *************** g_compileLock.unlock(); - m_infoBlock.release(); - - Timers::compTotal.stop(); - STATS_MEASURE_MIN_MAX_VALUE(patchItemsToBcSizeRatioX1000, - m_patchItems.size()*1000/bc_size, m_fname); - + patch_count()*1000/bc_size, meth_fname()); - if (m_infoBlock.get_flags() & DBG_DUMP_CODE) { - dbg_dump_code(); + if (is_set(DBG_DUMP_CODE)) { + dbg_dump_code_bc(m_vmCode, total_code_size); } - if (m_infoBlock.get_flags() & DBG_TRACE_SUMM) { + + if (is_set(DBG_TRACE_SUMM)) { dbg_trace_comp_end(true, "ok"); } + m_infoBlock.release(); + + // Ensure no memory problems appeared during compilation + if (get_bool_arg("checkmem", false)) { + dbg_check_mem(); + } + + if (m_bEmulation) { + free(m_vmCode); + free(pdata); + return JIT_FAILURE; + } return JIT_SUCCESS; } +BBInfo& Compiler::comp_create_bb(unsigned pc) +{ + if (m_bbs.find(pc) == m_bbs.end()) { + BBInfo bbinfo; + bbinfo.start = bbinfo.last_pc = bbinfo.next_bb = pc; + m_bbs[pc] = bbinfo; + } + return m_bbs[pc]; +} + -void Compiler::bbs_mark_all(void) +void Compiler::comp_parse_bytecode(void) { - unsigned pc = 0; - // the very first instruction always start a new BB - a prolog - bbs_mark_one(0, false, true, false, false); + const unsigned vars = m_infoBlock.get_num_locals(); + m_defs.resize(vars, 0); + m_uses.resize(vars, 0); + // jretAddr here is used as 'not initialized yet' value + m_staticTypes.resize(vars, jretAddr); + for (unsigned i=0, var=0; i<m_ci.count(); i++, var++) { + jtype jt = m_ci.jt(i); + if (jt < i32) { jt = i32; } + bool big = is_big(jt); + m_staticTypes[var] = jt; + m_argids[var] = m_ci.reg(i) == ar_x && !big? i : NOTHING; + if (is_wide(jt)) { + ++var; + m_argids[var] = m_ci.reg(i) == ar_x && !big ? i : NOTHING; + m_staticTypes[var] = jt; + } + } + + // PC=0 always starts new basic block + comp_create_bb(0); + JInst& start = m_insts[0]; + start.ref_count = 1; + start.flags |= OPF_STARTS_BB; + + unsigned id = 1; const unsigned bc_size = m_infoBlock.get_bc_size(); - do{ + for (unsigned pc=0; pc<bc_size; ) { JInst& jinst = m_insts[pc]; pc = fetch(pc, jinst); - // 'pc' points to the instructions next to jinst ... - if (jinst.flags & OPF_ENDS_BB) { - // ... and is just considered as BB leader - const bool is_dead_end = jinst.flags&OPF_DEAD_END; - bbs_mark_one(pc, false, !is_dead_end, false, false); - bool is_jsr = jinst.opcode == OPCODE_JSR; - for (unsigned i=0, n = jinst.get_num_targets(); i<n; i++) { - // mark jmp target(s) - bbs_mark_one(jinst.get_target(i), true, true, false, is_jsr); + if (jinst.id != 0) { + continue; + } + jinst.id = id++; + if (jinst.flags & OPF_VAR_DU_MASK) { + // extract variable index + unsigned idx = + (jinst.flags&OPF_VAR_IDX_MASK) == OPF_VAR_OP0 ? + jinst.op0 : jinst.flags&OPF_VAR_IDX_MASK; + assert(idx<vars); + // extract variable type + jtype jt = + (jtype)((jinst.flags&OPF_VAR_TYPE_MASK)>>OPF_VAR_TYPE_SHIFT); + + // update def-use info + if (jinst.flags & OPF_VAR_DEF) { + ++m_defs[idx]; + if (is_big(jt)) { + ++m_defs[idx+1]; + } + } + if (jinst.flags & OPF_VAR_USE) { + ++m_uses[idx]; + if (is_big(jt)) { + ++m_uses[idx+1]; + } } - if (jinst.is_switch()) { - bbs_mark_one(jinst.get_def_target(), true, true, false, false); + + // Store a slot's 'static' type - if a slot is used only as + // one type (say, only i32). If the slot is used to keep various + // types (i.e. we have both ASTORE_1 and DSTORE_1 - then store + // 'jvoid' as 'static' type. + if (m_staticTypes[idx] == jretAddr || m_staticTypes[idx] == jt) { + m_staticTypes[idx] = jt; + if (is_wide(jt)) { + jtype jt_hi = m_staticTypes[idx+1]; + if (jt_hi == jretAddr || jt_hi == jt) { + m_staticTypes[idx+1] = jt; + } + else { + m_staticTypes[idx+1] = jvoid; + m_staticTypes[idx] = jvoid; + } + } + } + else { + m_staticTypes[idx] = jvoid; + if (is_wide(jt)) { + m_staticTypes[idx+1] = jvoid; + } } } - - } while(pc<bc_size); - - // - // mark exception handlers as leads of basic blocks + if (jinst.flags & OPF_STARTS_BB) { + comp_create_bb(jinst.pc); + } + //JInst& next = m_insts[pc]; + if (!(jinst.flags&OPF_DEAD_END)) { + if (pc<bc_size) { ++m_insts[pc].ref_count; } + } + if (!(jinst.flags & OPF_ENDS_BB)) { + continue; + } + if (pc<bc_size) { + m_insts[pc].flags |= OPF_STARTS_BB; + comp_create_bb(pc); + } + for (unsigned i=0, n = jinst.get_num_targets(); i<n; i++) { + // mark jmp target(s) + JInst& ji = m_insts[jinst.get_target(i)]; + ji.flags |= OPF_STARTS_BB; + ++ji.ref_count; + BBInfo& nbb = comp_create_bb(jinst.get_target(i)); + nbb.jsr_target = nbb.jsr_target || jinst.is_jsr(); + } + if (jinst.is_switch()) { + JInst& ji = m_insts[jinst.get_def_target()]; + ji.flags |= OPF_STARTS_BB; + ++ji.ref_count; + comp_create_bb(jinst.get_def_target()); + } + } // + // mark exception handlers as leads of basic blocks for (unsigned i=0; i<m_handlers.size(); i++) { const HandlerInfo& hi = m_handlers[i]; - bbs_mark_one(hi.handler, false, true, true, false); - } - - // - // make list of heads and sort it. - // - // TODO: may eliminate vector here, and use simple scan over byte code - // Another variant is: - // currently, 2 passes over the bytecode performed. Might want to replace - // it with a single DFS pass, and also may eliminate BBInfo structure. - - const unsigned num_bbs = m_bbs.size(); - ::std::vector<unsigned> bb_heads; - bb_heads.reserve(num_bbs); - for (BBMAP::iterator i=m_bbs.begin(); i != m_bbs.end(); i++) { - bb_heads.push_back(i->second.start); - }; - ::std::sort(bb_heads.begin(), bb_heads.end()); - - // initialize with ATHROW to avoid ref_count increment for pc=0 - JavaByteCodes prev = OPCODE_ATHROW; - // for each basic block, find it's last instruction - for (unsigned idx = 0; idx != num_bbs; idx++) { - unsigned pc = bb_heads[idx]; - BBInfo& bb = m_bbs[pc]; - unsigned next_bb_start = idx == num_bbs-1 ? - bc_size : bb_heads[idx + 1]; - while (next_bb_start != m_insts[pc].next) { - pc = m_insts[pc].next; - } - bb.last_pc = m_insts[pc].pc; - bb.next_bb = next_bb_start; - unsigned prev_flags = instrs[prev].flags; - if (!(prev_flags & OPF_ENDS_BB)) { - // here we have an instruction (jinst.opcode) which - // follows an instruction which normally does not - // end a basic block. This normally means, that the - // current instruction is a branch target, and thus become - // a BB leader. As the previous opcode does not end basic - // block, then this means that there is a control flow path - // which leads from the previous instruction to the current one: - // - // GOTO n ; somewhere in the bytecode - // ... - // ALOAD_0 ; sample prev instruction - // n: ASTORE_1 ; sample current instruction. ref_ocunt found - // is '1' because of GOTO - // - // Thus incrementing ref_count and this assertion - //assert(bb.jmp_target || bb.jsr_target || - // bb.start == 0 || bb.ehandler); - bb.ref_count++; - } - prev = m_insts[pc].opcode; - - // Statistics:: size of the basic blocks, in bytes - if (bb.ref_count) { - STATS_MEASURE_MIN_MAX_VALUE( bb_size, bb.next_bb - bb.start, m_fname ); + JInst& ji = m_insts[hi.handler]; + ji.flags |= OPF_STARTS_BB; + comp_create_bb(hi.handler).ehandler = true; + ++ji.ref_count; + if (ji.id == 0) { + ji.id = id++; } } + } -void Compiler::bbs_mark_one(unsigned pc, bool jmp_target, bool add_ref, - bool ehandler, bool jsr_target) +void Compiler::comp_alloc_regs(void) { - assert(pc < USHRT_MAX); - if (pc >= m_infoBlock.get_bc_size()) { + if (g_jvmtiMode) { + // Do not allocate regs. Only ensure the m_base will be saved. + m_global_rusage.set(ar_idx(m_base)); + // Make sure all method args get reloaded into local vars + for (unsigned i=0; i<m_argids.size(); i++) { + m_argids[i] = -1; + } return; } + const unsigned vars = m_infoBlock.get_num_locals(); + // 1. allocate GP registers + for (unsigned i=0; i<g_global_grs.size(); i++) { + AR ar = g_global_grs[i]; + assert(is_callee_save(ar)); + unsigned max_dus = 0; + unsigned idx = NOTHING; + for (unsigned j=0; j<vars; j++) { + jtype jt = m_staticTypes[j]; + bool accept = jt==i32 || (jt==i64 && !is_big(i64)) || jt==jobj; + if (!accept) continue; + if (m_ra[j] != ar_x) continue; + if (m_defs[j]+m_uses[j]>max_dus) { + max_dus = m_defs[j]+m_uses[j]; + idx = j; + } + } + if (idx == NOTHING) { + // no more vars remain + break; + } + m_ra[idx] = ar; + } + + // 2. allocate FP registers + for (unsigned i=0; i<g_global_frs.size(); i++) { + AR ar = g_global_frs[i]; + unsigned max_dus = 0; + unsigned idx = NOTHING; + for (unsigned j=0; j<vars; j++) { + jtype jt = m_staticTypes[j]; + if (!is_f(jt)) continue; + if (m_ra[j] != ar_x) continue; + if (m_defs[j]+m_uses[j]>max_dus) { + max_dus = m_defs[j]+m_uses[j]; + idx = j; + } + } + if (idx == NOTHING) { + // no more vars remain + break; + } + m_ra[idx] = ar; + } + // Set a bitset of globally used registers + // m_base is always used. + m_global_rusage.set(ar_idx(m_base)); + for (unsigned i=0; i<m_ra.size(); i++) { + AR ar = m_ra[i]; + if (ar == ar_x) { continue; } + m_global_rusage.set(ar_idx(ar)); + } + + // Print out + if (is_set(DBG_TRACE_CG)) { + for (unsigned i=0; i<vars; i++) { + jtype jt = m_staticTypes[i]; + // common info on var - type (if any), uses, defs ... + dbg("local#%d (%s): d=%u, u=%u", + i, jt < jvoid ? jtypes[jt].name : "", + m_defs[i], m_uses[i]); + // ... which input arg it came from ... + if (i<m_argSlots && m_argids[i] != -1) { + dbg(" <= arg#%d", m_argids[i]); + } + // ... which register it's assigned on ... + if (m_ra[i] != ar_x) { + dbg(" => %s", to_str(m_ra[i]).c_str()); + } + dbg("\n"); + } + } +} + - BBMAP::iterator i = m_bbs.find(pc); - if (i != m_bbs.end()) { - i->second.jmp_target = i->second.jmp_target || jmp_target; - i->second.ehandler = i->second.ehandler || ehandler; - i->second.jsr_target = i->second.jsr_target || jsr_target; - if (add_ref ) ++i->second.ref_count; +/** + * A helper structure to organize recursive compilation. + */ +struct GenItem { + /** + * No op. + */ + GenItem() {} + /** + * @param _pc - start of basic block to generate + * @param _parent - start of predecessor block (to inherit BBState + * from) or equal to _pc if no predecessor + * @param _jsr - PC of start of JSR subroutine the \c _pc block belongs + * to, or #NOTHING if the block lies outside of JSR subroutines. + */ + GenItem(unsigned _pc, unsigned _parent, unsigned _jsr) + { + pc = _pc; parentPC = _parent; jsr_lead = _jsr; } - else { - BBInfo bbinfo; - bbinfo.start = pc; - bbinfo.last_pc = 0; - bbinfo.next_bb = 0; - bbinfo.ipoff = 0; - - // bbinfo.next_bb = NOTHING; - // bbinfo.code_start = NULL; - // bbinfo.code_size = NOTHING; - bbinfo.code_size = 0; - bbinfo.jmp_target = jmp_target; - bbinfo.ehandler = ehandler; - bbinfo.ref_count = add_ref ? 1 : 0; - bbinfo.jsr_target = jsr_target; - bbinfo.processed = false; - m_bbs[pc] = bbinfo; + /** start of basic block to generate */ + unsigned pc; + /** start of predecessor block */ + unsigned parentPC; + /** start of JSR subroutine the block belongs to*/ + unsigned jsr_lead; +}; + + +void Compiler::comp_gen_code_bb(unsigned pc) +{ +/////////////////////////////////////////////////////////////////////////// + /* + Ok, here is a bit sophisticated code, but the idea is simple: we + emulate recursion, without doing real recursive calls of method. + + We generate code in depth-first search order. Banal recursion is the + most natural, simple and clear way to do so: + // + generate_all_insts_in_bb(head); + foreach target in targets_of_last_instrution { + generate_all_insts_in_bb(target) + } + if (last_inst_has_fall_through) { + generate_all_insts_in_bb(last_inst.next) + } + // + Now, let's count. The max bytecode size is 65535, including RETURN at + the end. GOTO instruction takes 3 bytes, so the hypothetical max number + of basic blocks is (65'535-1(return))/3 = 21'844 which is also maximum + recursion depth for simplest implementation. The default maximum size + of thread's stack is 1 MB (at least on Win32). Having all of this in + mind: 1024*1024/21'844 = 48 bytes we can only spend in comp_gen_code() + for local variables, spilled regs, passed args, etc. In addition, in + real life there are many calls before comp_gen_code() and comp_gen_code() + also do some calls - they all require stack space - and we're in + trouble with the direct approach as we may easily exhaust stack on + a legal and valid bytecode. + + So, here is what we do to avoid this: we emulate recursion, using + heap-based stack structure. + */ + + stack<GenItem> stk; + stk.push(GenItem(pc, pc, NOTHING)); + + while (true) { + if (stk.empty()) { + break; + } + GenItem gi = stk.top(); stk.pop(); + unsigned head = gi.pc; + // + if (!comp_gen_insts(gi.pc, gi.parentPC, gi.jsr_lead)) { + // Basic block was already seen, nothing to do. + continue; + } + const BBInfo& bbi = m_bbs[head]; + const JInst& lastInst = m_insts[bbi.last_pc]; + // Push fall-through block first, so it's processed at the very end + if (!lastInst.is_set(OPF_DEAD_END)) { + unsigned next = lastInst.next; + // If last inst was JSR, then when generating fall through, + // specify the JSR leader as 'parent PC', so the BBState + // to inherit will be taken the JSR's one. + unsigned h = lastInst.is_jsr() ? lastInst.get_target(0): head; + if (lastInst.single_suc() && !m_bbs[next].processed) { + // If instruction has only one successor, so its BBState + // will be used once for inheritance. May eliminate + // copying and in operate directly on this BBState when + // generating next block. + m_bbStates[next] = m_bbStates[head]; + } + stk.push(GenItem(next, h, gi.jsr_lead)); + } + // Then, process target blocks - this is match with how code gen + // for branches works - it expects to visit branch target first, + // and then fall through + // + for (unsigned i=0; !lastInst.is_jsr() && + i<lastInst.get_num_targets(); i++) { + unsigned next = lastInst.get_target(i); + if (lastInst.single_suc() && !m_bbs[next].processed) { + m_bbStates[next] = m_bbStates[head]; + } + stk.push(GenItem(next, head, gi.jsr_lead)); + } + if (lastInst.is_switch()) { + unsigned next = lastInst.get_def_target(); + stk.push(GenItem(next, head, gi.jsr_lead)); + } + // at the very end push JSR target, so JSR subroutine get processed + // first + if (lastInst.is_jsr()) { + unsigned jsr_lead = lastInst.get_target(0); + stk.push(GenItem(jsr_lead, head, jsr_lead)); + } + } } -void Compiler::bbs_gen_code(unsigned pc, BBState * prev, unsigned jsr_lead) +bool Compiler::comp_gen_insts(unsigned pc, unsigned parentPC, + unsigned jsr_lead) { assert(m_bbs.find(pc) != m_bbs.end()); BBInfo& bbinfo = m_bbs[pc]; if (bbinfo.processed) { if (bbinfo.jsr_target) { - // we're processing JSR subroutine as result of JSR call || we - // are processing JSR subroutine as result of fall-through pass - assert(jsr_lead == pc || jsr_lead==NOTHING); - // JSR block was processed already - there must be a stack state - assert(m_stack_states.find(pc) != m_stack_states.end()); + // we're processing JSR subroutine + assert(jsr_lead == pc); // Simply load the state back to the parent's - const JFrame& stackState = m_stack_states[ pc ]; - // make sure we'll not lost anything - assert(prev->jframe.need_update() == 0); - prev->jframe.init(&stackState); + BBState* prevState = m_bbStates[parentPC]; + assert(m_jsrStates.find(jsr_lead) != m_jsrStates.end()); + const BBState* jsrState = m_jsrStates[jsr_lead]; + //prevState.jframe.init(&jsrState.jframe); + *prevState = *jsrState; } - return; + return false; } - - bbinfo.processed = true; - BBState bbstate; - - if (prev == NULL) { - bbstate.jframe.init(m_infoBlock.get_stack_max(), - m_infoBlock.get_num_locals(), - I_STACK_REGS, I_LOCAL_REGS, - F_STACK_REGS, F_LOCAL_REGS); + BBState* pState = m_bbStates[pc]; + BBState * parentState = m_bbStates[parentPC]; + + JInst& bbhead = m_insts[pc]; + if (pc != parentPC) { + if (pState != parentState) { + if (bbhead.ref_count > 1) { + pState->jframe = parentState->jframe; + } + else { + *pState = *parentState; + } + } } else { - bbstate.jframe.init(&prev->jframe); + pState->jframe.init(m_infoBlock.get_stack_max(), + m_infoBlock.get_num_locals()); } - + + BBState& bbstate = *pState; + bbinfo.processed = true; m_jframe = &bbstate.jframe; - m_curr_bb_state = &bbstate; - m_curr_bb = &bbinfo; + m_bbstate = &bbstate; + m_bbinfo = &bbinfo; + m_pc = pc; unsigned bb_ip_start = bbinfo.ipoff = m_codeStream.ipoff(); + // + // If there are several execution paths merged on this basic block, + // then we can not predict many things, including, but not limited to + // type of of local variables, state of stack items, what stack depth + // was saved last, etc. So, clearing all this stuff out. + // - if (pc == 0) { - assert(!bbinfo.ehandler); // cant be at pc=0 - m_pc = 0; - if (!(m_java_meth_flags & ACC_STATIC)) { - // for instance methods, their local_0 is 'this' at entrance, - // so we can say it's not null for sure. - bbstate.jframe.var_def(jobj, 0, SA_NZ); - } - gen_prolog(m_args); - } - - // If there are several execution paths merged on this basic block, then - // we can not predict many things, including, but not limited to type of - // of local variables, state of stack items, what stack depth was saved - // last, etc. So, clearing this out. - // The current convention is that before the execution goes to such - // 'multiref' basic block, then all local vars are in the memory and - // all appropriate stack items are on their registers - // - // The same applies to exception handlers. - if (bbinfo.ehandler || bbinfo.ref_count > 1 || prev==NULL) { - m_jframe->clear_vars(); - m_jframe->clear_attrs(); - //todo: might be useful to extract this several assignments into, say, - // operator=(BBState*) - ? - bbstate.seen_gcpt = false; - bbstate.stack_depth = NOTHING; - bbstate.stack_mask = 0; - bbstate.stack_mask_valid = false; - } - else { - bbstate.seen_gcpt = prev->seen_gcpt; - bbstate.stack_depth = prev->stack_depth; - bbstate.stack_mask = prev->stack_mask; - bbstate.stack_mask_valid = prev->stack_mask_valid; - bbstate.resState = prev->resState; + if (bbinfo.ehandler || bbhead.ref_count > 1) { + bbstate.clear(); } - if (m_infoBlock.get_flags() & DBG_CHECK_STACK && (jsr_lead==NOTHING)){ - // do not check stack for JSR subroutines (at least for IA32/EM64T) - // More comments in cg_ia32.cpp::gen_dbg_check_bb_stack + if (is_set(DBG_CHECK_STACK)){ gen_dbg_check_bb_stack(); } @@ -522,158 +911,131 @@ void Compiler::bbs_gen_code(unsigned pc, // // Here, we invoke gen_save_ret() because this is how the idea of // exception handlers works in DRL VM: - // Loosely speaking, calling something like 'throw_<whatever>' is - // like a regular function call. The only difference is that the - // return point is at another address, not at the next instruction - - // we're 'returning' to the proper exception handler. + // Loosely speaking, calling 'throw_<whatever>' is like a regular + // function call. The only difference is that the return point is + // at another address, not at the next instruction - we're + // 'returning' to the proper exception handler. // // That's why the exception object acts like a return value - for // example on IA32 it's in EAX. // - - // a stack get empty on entrance into exception handler ... - m_jframe->clear_stack(); - - // ... with an reference to Exception object on the top of it gen_save_ret(jobj); - - // We're entering exception handler - the exception object - // on the stack is guaranteed to be non-null, marking it as such - m_jframe->stack_attrs(0, SA_NZ); } - - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg(";; ========================================================\n"); - dbg(";; bb.ref.count=%d%s%s savedStackDepth=%d stackMask=0x%X %s\n", - bbinfo.ref_count, bbinfo.ehandler ? " ehandler " : "", + + if (is_set(DBG_TRACE_CG)) { + dbg("\n"); + dbg(";; ======================================================\n"); + dbg(";; bb.ref.count=%d%s%s savedStackDepth=%d stackMask=0x%X %s" + " jsr_lead=%d\n", + bbhead.ref_count, bbinfo.ehandler ? " ehandler " : "", bbinfo.jsr_target ? " #JSR# " : "", bbstate.stack_depth, bbstate.stack_mask, - bbstate.stack_mask_valid ? "" : "*mask.invalid*"); + bbstate.stack_mask_valid ? "" : "*mask.invalid*", jsr_lead); if (bb_ip_start != m_codeStream.ipoff()) { dbg_dump_code(m_codeStream.data() + bb_ip_start, m_codeStream.ipoff()-bb_ip_start, "bb.head"); } + dbg(";; ======================================================\n"); } + gen_bb_enter(); +#ifdef _DEBUG + vcheck(); +#endif - unsigned next_pc = bbinfo.start; + const unsigned bc_size = m_infoBlock.get_bc_size(); + unsigned next_pc = bbinfo.start; + bool last = false; do { // read out instruction to process - const JInst& jinst = m_insts[next_pc]; m_pc = next_pc; - m_curr_inst = &jinst; - next_pc = jinst.next; + m_curr_inst = &m_insts[m_pc]; + next_pc = m_insts[m_pc].next; + last = next_pc>=bc_size || (m_insts[next_pc].is_set(OPF_STARTS_BB)); + if (last) { + bbinfo.last_pc = m_pc; + bbinfo.next_bb = next_pc; + } unsigned inst_code_start = m_codeStream.ipoff(); + unsigned inst_code_dump_start = inst_code_start; - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { - dbg_dump_jframe("before", &bbstate.jframe); + if (is_set(DBG_TRACE_CG)) { + dbg_dump_state("before", &bbstate); // print an opcode - dbg(";; %-30s\n", toStr(jinst, true).c_str()); + dbg(";; %-30s\n", toStr(m_insts[m_pc], true).c_str()); + } + + if (is_set(DBG_TRACE_BC)) { + gen_dbg_rt(true, "//%s@%u", meth_fname(), m_pc); + inst_code_dump_start = m_codeStream.ipoff(); } -#if defined(_DEBUG) && defined(JET_PROTO) - if (dbg_break_pc == jinst.pc) { - gen_dbg_brk(); +#ifdef JET_PROTO + if (dbg_break_pc == m_pc) { + gen_brk(); } #endif - if (m_infoBlock.get_flags() & DBG_TRACE_BC) { - gen_dbg_rt_out("//%s @ PC = %u", m_fname, m_pc); - } - - STATS_INC(Stats::opcodesSeen[jinst.opcode], 1); - - handle_inst(jinst); - + STATS_INC(Stats::opcodesSeen[m_insts[m_pc].opcode], 1); + handle_inst(); +#ifdef _DEBUG + vcheck(); +#endif unsigned inst_code_end = m_codeStream.ipoff(); - unsigned inst_code_size = inst_code_end-inst_code_start; + unsigned inst_code_dump_size = inst_code_end - inst_code_dump_start; unsigned bb_off = inst_code_start - bb_ip_start; // store a native offset inside the basic block for now, - // this will be adjusted in bbs_layout_code(), by adding the BB's + // this will be adjusted in comp_layout_code(), by adding the BB's // start address - for (unsigned i=jinst.pc; i<next_pc; i++) { - m_infoBlock.set_code_info(i, (const char *)bb_off); + for (unsigned i=m_pc; i<next_pc; i++) { + m_infoBlock.set_code_info(i, (const char *)(int_ptr)bb_off); } - if (m_infoBlock.get_flags() & DBG_TRACE_CG) { // disassemble the code - dbg_dump_code(m_codeStream.data() + inst_code_start, - inst_code_size, NULL); + dbg_dump_code(m_codeStream.data() + inst_code_dump_start, + inst_code_dump_size, NULL); } // no one should change m_pc, it's used right after the loop to get // the same JInst back again - assert(jinst.pc == m_pc); - } while(next_pc != bbinfo.next_bb); + //assert(jinst.pc == m_pc); + } while(!last); + + bbinfo.last_pc = m_pc; + bbinfo.next_bb = next_pc; const JInst& jinst = m_insts[m_pc]; unsigned bb_code_end = m_codeStream.ipoff(); bbinfo.code_size = bb_code_end - bb_ip_start; - // process JSR target first, so it will update the state of jframe - bool is_jsr = jinst.opcode == OPCODE_JSR || jinst.opcode == OPCODE_JSR_W; - if (is_jsr) { - unsigned targetBB = jinst.get_target(0); - bbs_gen_code(targetBB, &bbstate, targetBB); - // - // bbs_gen_code() invalidated m_* fields, so below only use - // local variables, not the instance ones ! - // - - // We just executed/generated the JSR subroutine. - // We must have a state for it: - assert(m_stack_states.find(targetBB) != m_stack_states.end()); - // Reload the stack state into the current one - bbstate.jframe.init(&m_stack_states[targetBB]); - } - else if (jinst.opcode == OPCODE_RET) { + // + // We just finished JSR subroutine - store its state for further use + // + if (jinst.opcode == OPCODE_RET) { assert(jsr_lead != NOTHING); - m_stack_states[jsr_lead] = bbstate.jframe; + assert(m_insts[jsr_lead].ref_count>0); + assert(m_bbs[jsr_lead].processed); + m_jsrStates[jsr_lead] = pState; } - else { - // process jmp target blocks - for (unsigned i=0, n=jinst.get_num_targets(); i<n; i++) { - bbs_gen_code(jinst.get_target(i), &bbstate, jsr_lead); - } - if (jinst.is_switch()) { - bbs_gen_code(jinst.get_def_target(), &bbstate, jsr_lead); - } - } - if (!(jinst.flags & OPF_DEAD_END)) { - // process fall through block - assert(next_pc != NOTHING); - bbs_gen_code(next_pc, &bbstate, jsr_lead); - } - else if ((jinst.flags & OPF_EXIT) && jsr_lead != NOTHING) { - // A special case - when a JSR subroutine ends the method - // (xRETURN, ATHROW) save an empty state, but if there are - // several paths in the subroutine and at least one of them does - // not end the method, then keep that state: - // JSR _jsr - // ... - // _jsr: ASTORE_0 - // IF_xCMPx _ret - // xRETURN // <= here, save an empty state - // _ret: ... RET 0 // <= here, save the stack state - // - // So, only save the empty state if there is no state exists - // otherwise left it as is, this is either a state saved by - // RET or an empty state saved by another xRETURN. - // There is no such check in RET processing, so if we have both - // xRETURN and RET then RET's state always overwrites xRETURN's. - if (m_stack_states.find(jsr_lead) == m_stack_states.end()) { - bbstate.jframe.clear_stack(); - bbstate.jframe.clear_vars(); - m_stack_states[jsr_lead] = bbstate.jframe; - } + else if (jsr_lead != NOTHING && + (jinst.opcode == OPCODE_ATHROW || jinst.is_set(OPF_RETURN))) { + assert(m_insts[jsr_lead].ref_count>0); + assert(m_bbs[jsr_lead].processed); + m_jsrStates[jsr_lead] = pState; } + return true; } -void Compiler::bbs_layout_code(void) + +void Compiler::comp_layout_code(unsigned prolog_ipoff, unsigned prolog_size) { char * p = m_vmCode; + // Copy prolog + memcpy(p, m_codeStream.data() + prolog_ipoff, prolog_size); + p += prolog_size; // copy all BBs - for (unsigned pc = 0; pc<m_infoBlock.get_bc_size(); ) { + unsigned bc_size = m_infoBlock.get_bc_size(); + for (unsigned pc = 0; pc<bc_size; ) { // it's basic block lead. assert(m_bbs.find(pc) != m_bbs.end()); BBInfo& bbinfo = m_bbs[pc]; @@ -681,7 +1043,7 @@ void Compiler::bbs_layout_code(void) if (bbinfo.processed) { // copy the code. memcpy(p, m_codeStream.data()+bbinfo.ipoff, bbinfo.code_size); - bbinfo.ipoff = p - m_vmCode; + bbinfo.addr = p; if (m_infoBlock.get_flags() & DBG_TRACE_LAYOUT) { dbg("code.range: [%u - %u] => [%p - %p)\n", bbinfo.start, bbinfo.last_pc, @@ -693,10 +1055,18 @@ void Compiler::bbs_layout_code(void) dbg("warning - dead code @ %d\n", pc); } assert(bbinfo.code_size == 0); + unsigned j=pc+1; + for (; j<bc_size; j++) { + if (m_insts[j].flags & OPF_STARTS_BB) { + break; + } + } + bbinfo.next_bb = j; } // update runtime info with the mapping pc/ip data for (unsigned j=pc; j<bbinfo.next_bb; j++) { - const char * inst_ip = pBBStart + (int)m_infoBlock.get_code_info(j); + const char * inst_ip = pBBStart + + (int)(int_ptr)m_infoBlock.get_code_info(j); m_infoBlock.set_code_info(j, inst_ip); } p = (char*)(pBBStart+bbinfo.code_size); @@ -704,7 +1074,7 @@ void Compiler::bbs_layout_code(void) } } -bool Compiler::bbs_ehandlers_resolve(void) +bool Compiler::comp_resolve_ehandlers(void) { unsigned num_handlers = method_get_num_handlers(m_method); m_handlers.resize(num_handlers); @@ -721,9 +1091,7 @@ bool Compiler::bbs_ehandlers_resolve(voi hi.handler = handlerStart; hi.type = klassType; if (hi.type != 0) { - Timers::vmResolve.start(); - hi.klass = resolve_class(m_compileHandle, m_klass, hi.type); - Timers::vmResolve.stop(); + hi.klass = resolve_class(m_compileHandle, m_klass, hi.type); eh_ok = eh_ok && (hi.klass != NULL); } if (m_infoBlock.get_flags() & DBG_DUMP_BBS) { @@ -734,12 +1102,12 @@ bool Compiler::bbs_ehandlers_resolve(voi return eh_ok; } -void Compiler::bbs_ehandlers_set(void) +void Compiler::comp_set_ehandlers(void) { unsigned real_num_handlers = 0; for (unsigned i=0, n=m_handlers.size(); i<n; i++) { HandlerInfo& hi = m_handlers[i]; - if (bbs_hi_to_native(m_vmCode, hi)) { + if (comp_hi_to_native(hi)) { ++real_num_handlers; } else { @@ -750,7 +1118,7 @@ void Compiler::bbs_ehandlers_set(void) } } - method_set_num_target_handlers(m_method, jit_handle, real_num_handlers); + method_set_num_target_handlers(m_method, m_hjit, real_num_handlers); for (unsigned i=0, handlerID=0, n=m_handlers.size(); i<n; i++) { const HandlerInfo& hi = m_handlers[i]; @@ -758,14 +1126,14 @@ void Compiler::bbs_ehandlers_set(void) continue; } // The last param is 'is_exception_object_dead' - // In many cases, when an exception handler does not use an exception - // object, the fist bytecode instruction is 'pop' to throw the - // exception object away. Thus, this can used as a quick, cheap but - // good check whether the 'exception_object_is_dead'. - method_set_target_handler_info(m_method, jit_handle, handlerID, + // In many cases, when an exception handler does not use an + // exception object, the fist bytecode instruction is 'pop' to + // throw the exception object away. Thus, this can used as a quick, + // cheap but good check whether the 'exception_object_is_dead'. + method_set_target_handler_info(m_method, m_hjit, handlerID, hi.start_ip, hi.end_ip, hi.handler_ip, hi.klass, - m_bc[hi.handler] == OPCODE_POP ); + m_bc[hi.handler] == OPCODE_POP); ++handlerID; @@ -844,20 +1212,20 @@ void Compiler::get_args_info(Method_Hand jtype Compiler::to_jtype(Type_Info_Handle th) { - if (type_info_is_unboxed(th)) { + if (type_info_is_void(th)) { + return jvoid; + } + if (type_info_is_primitive(th)) { Class_Handle ch = type_info_get_class(th); assert(class_is_primitive(ch)); VM_Data_Type vmdt = class_get_primitive_type_of_class(ch); return to_jtype(vmdt); } - if (type_info_is_void(th)) { - return jvoid; - } assert(type_info_is_reference(th) || type_info_is_vector(th)); return jobj; } -bool Compiler::bbs_hi_to_native(char * codeBlock, HandlerInfo& hi) +bool Compiler::comp_hi_to_native(HandlerInfo& hi) { // Find beginning of the area protected by the handler, // lookup for the first reachable instruction @@ -867,10 +1235,7 @@ bool Compiler::bbs_hi_to_native(char * c } hi.end_ip = (char*)m_infoBlock.get_ip(hi.end); - if (hi.end_ip == NULL) { - assert(false); - } - + // either both are NULLs, or both are not NULLs assert(!((hi.start_ip == NULL) ^ (hi.end_ip == NULL))); @@ -882,7 +1247,7 @@ bool Compiler::bbs_hi_to_native(char * c const BBInfo& handlerBB = m_bbs[hi.handler]; assert(handlerBB.ehandler); - hi.handler_ip = codeBlock + handlerBB.ipoff; + hi.handler_ip = handlerBB.addr; } else { hi.handler_ip = NULL; @@ -890,26 +1255,98 @@ bool Compiler::bbs_hi_to_native(char * c return hi.start_ip != NULL; } -void Compiler::initStatics(void) + +void Compiler::comp_patch_code(void) { + for (void * h=enum_start(); !enum_is_end(h); enum_next(h)) { + unsigned udata, bb, pid; + bool done; + enum_patch_data(&pid, &udata, &bb, &done); + if (done) { + continue; + } + unsigned inst_ipoff = pid; + const BBInfo& bbinfo = m_bbs[bb]; + assert(bbinfo.processed); + void * target; + if (udata & DATA_SWITCH_TABLE) { + assert(DATA_SWITCH_TABLE==(udata&0xFFFF0000)); + unsigned pc = udata&0xFFFF; + assert(bbinfo.start<=pc && pc<=bbinfo.last_pc); + const JInst& jinst = m_insts[pc]; + assert(jinst.opcode == OPCODE_TABLESWITCH); + unsigned targets = jinst.get_num_targets(); + char * theTable; + if (m_bEmulation) { + theTable = (char*)malloc(targets * sizeof(void*)); + } + else { + theTable = (char*)method_allocate_data_block( + m_method, m_hjit, + targets * sizeof(void*), 16); + } + char ** ptargets = (char**)theTable; + // Fill out the table with targets + for (unsigned j=0; j<targets; j++, ptargets++) { + unsigned pc = jinst.get_target(j); + *ptargets = (char*)m_infoBlock.get_ip(pc); + } + target = theTable; + if (m_bEmulation) { + free(theTable); + } + } + else { + target = (void*)m_infoBlock.get_ip(udata); + } + assert(target != NULL); + inst_ipoff -= bbinfo.ipoff; + void * inst_addr = bbinfo.addr + inst_ipoff; + assert(m_infoBlock.get_pc((char*)inst_addr) < m_infoBlock.get_bc_size()); + patch(pid, inst_addr, target); + } +} +void Compiler::initStatics(void) +{ // must only be called once assert(NULL == rt_helper_throw); + + Encoder::init(); + // Fill out lists of registers for global allocation + // ... for GP registers, always using callee-save + for (unsigned i=0; i<gr_num; i++) { + AR gr = _gr(i); + if (!is_callee_save(gr)) { continue; }; + // Do not add bp + // TODO: need to synchronize somehow with JFM_SP_FRAME + if (gr == bp) continue; + g_global_grs.push_back(gr); + } + // ... for fr registers, leave 3 registers available for scratch + for (unsigned i=3; i<fr_num; i++) { + AR fr = _fr(i); + g_global_frs.push_back(fr); + } // // Collect addresses of runtime helpers // - rt_helper_throw = - (char*)vm_get_rt_support_addr(VM_RT_THROW); - rt_helper_throw_out_of_bounds = - (char*)vm_get_rt_support_addr(VM_RT_IDX_OUT_OF_BOUNDS); - rt_helper_throw_npe = - (char*)vm_get_rt_support_addr(VM_RT_NULL_PTR_EXCEPTION); - rt_helper_throw_linking_exc = - (char*)vm_get_rt_support_addr(VM_RT_THROW_LINKING_EXCEPTION); - rt_helper_throw_div_by_zero_exc = - (char*)vm_get_rt_support_addr(VM_RT_DIVIDE_BY_ZERO_EXCEPTION); + rt_helper_init_class = + (char*)vm_get_rt_support_addr(VM_RT_INITIALIZE_CLASS); + rt_helper_ldc_string = + (char*)vm_get_rt_support_addr(VM_RT_LDC_STRING); + rt_helper_new = + (char*)vm_get_rt_support_addr(VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE); + g_refs_squeeze = vm_references_are_compressed(); + g_vtbl_squeeze = vm_vtable_pointers_are_compressed(); + OBJ_BASE = (const char*)vm_heap_base_address(); + VTBL_BASE = (const char*)vm_get_vtable_base(); + NULL_REF = g_refs_squeeze ? OBJ_BASE : NULL; + + g_jvmtiMode = vm_get_property_value_boolean("vm.jvmti.enabled", false); + rt_helper_monitor_enter = (char*)vm_get_rt_support_addr(VM_RT_MONITOR_ENTER); rt_helper_monitor_exit = @@ -918,24 +1355,34 @@ void Compiler::initStatics(void) (char*)vm_get_rt_support_addr(VM_RT_MONITOR_ENTER_STATIC); rt_helper_monitor_exit_static = (char*)vm_get_rt_support_addr(VM_RT_MONITOR_EXIT_STATIC); - - rt_helper_ldc_string = - (char*)vm_get_rt_support_addr(VM_RT_LDC_STRING); - rt_helper_new = - (char*)vm_get_rt_support_addr(VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE); + rt_helper_new_array = (char*)vm_get_rt_support_addr(VM_RT_NEW_VECTOR_USING_VTABLE); - rt_helper_init_class = - (char*)vm_get_rt_support_addr(VM_RT_INITIALIZE_CLASS); rt_helper_aastore = (char*)vm_get_rt_support_addr(VM_RT_AASTORE); - rt_helper_multinewarray = - (char*)vm_get_rt_support_addr(VM_RT_MULTIANEWARRAY_RESOLVED); + rt_helper_get_vtable = (char*)vm_get_rt_support_addr(VM_RT_GET_INTERFACE_VTABLE_VER0); + + rt_helper_throw_npe = + (char*)vm_get_rt_support_addr(VM_RT_NULL_PTR_EXCEPTION); + + rt_helper_throw = + (char*)vm_get_rt_support_addr(VM_RT_THROW); + rt_helper_throw_out_of_bounds = + (char*)vm_get_rt_support_addr(VM_RT_IDX_OUT_OF_BOUNDS); + rt_helper_throw_linking_exc = + (char*)vm_get_rt_support_addr(VM_RT_THROW_LINKING_EXCEPTION); + rt_helper_throw_div_by_zero_exc = + (char*)vm_get_rt_support_addr(VM_RT_DIVIDE_BY_ZERO_EXCEPTION); + rt_helper_checkcast = (char*)vm_get_rt_support_addr(VM_RT_CHECKCAST); rt_helper_instanceof = (char*)vm_get_rt_support_addr(VM_RT_INSTANCEOF); + + rt_helper_multinewarray = + (char*)vm_get_rt_support_addr(VM_RT_MULTIANEWARRAY_RESOLVED); + rt_helper_gc_safepoint = (char*)vm_get_rt_support_addr(VM_RT_GC_SAFE_POINT); rt_helper_get_thread_suspend_ptr = @@ -945,11 +1392,19 @@ void Compiler::initStatics(void) (char*)vm_get_rt_support_addr(VM_RT_JVMTI_METHOD_ENTER_CALLBACK); rt_helper_ti_method_exit = (char*)vm_get_rt_support_addr(VM_RT_JVMTI_METHOD_EXIT_CALLBACK); + + rt_helper_ti_field_access = + (char*)vm_get_rt_support_addr(VM_RT_JVMTI_FIELD_ACCESS_CALLBACK); + rt_helper_ti_field_modification = + (char*)vm_get_rt_support_addr(VM_RT_JVMTI_FIELD_MODIFICATION_CALLBACK);; + + // // Collect runtime constants // rt_array_length_offset = vector_length_offset(); rt_suspend_req_flag_offset = thread_get_suspend_request_offset(); + rt_vtable_offset = object_get_vtable_offset(); Class_Handle clss; clss = class_get_class_of_primitive_type(VM_DATA_TYPE_INT8); @@ -978,16 +1433,16 @@ void Compiler::initStatics(void) jtypes[jvoid].rt_offset = 0xFFFFFFFF; } -void Compiler::initProfilingData(unsigned * pflags) { +void Compiler::initProfilingData(unsigned * pflags) +{ m_p_methentry_counter = NULL; m_p_backedge_counter = NULL; #if !defined(PROJECT_JET) - JITModeData* modeData = Jitrino::getJITModeData(jit_handle); - ProfilingInterface* pi = modeData->getProfilingInterface(); - if (pi->isProfilingEnabled(ProfileType_EntryBackedge, - JITProfilingRole_GEN)) { + JITInstanceContext* jitContext = JITInstanceContext::getContextForJIT(m_hjit); + ProfilingInterface* pi = jitContext->getProfilingInterface(); + if (pi->isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_GEN)) { MemoryManager mm(128, "jet_profiling_mm"); - DrlVMMethodDesc md(m_method, jit_handle); + DrlVMMethodDesc md(m_method, m_hjit); g_compileLock.lock(); @@ -1002,16 +1457,17 @@ #if !defined(PROJECT_JET) m_p_backedge_counter = mp->getBackedgeCounter(); if (pi->isEBProfilerInSyncMode()) { *pflags |= JMF_PROF_SYNC_CHECK; - m_methentry_threshold = pi->getEBProfilerMethodEntryThreshold(); - m_backedge_threshold = pi->getEBProfilerBackedgeThreshold(); + m_methentry_threshold = pi->getMethodEntryThreshold(); + m_backedge_threshold = pi->getBackedgeThreshold(); m_profile_handle = mp->getHandle(); m_recomp_handler_ptr = (void*)pi->getEBProfilerSyncModeCallback(); } - g_compileLock.unlock(); } #endif } + + }}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/compiler.h vm/jitrino/src/jet/compiler.h index 0400e1f..69939f7 100644 --- vm/jitrino/src/jet/compiler.h +++ vm/jitrino/src/jet/compiler.h @@ -14,13 +14,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.4.4.4 $ - */ -/** - * @file - * @brief Declaration of Compiler class and related structures. + * @author Alexander Astapchuk + * @version $Revision$ */ + /** + * @file + * @brief Declaration of Compiler class. + */ #if !defined(__COMPILER_H_INCLUDED__) #define __COMPILER_H_INCLUDED__ @@ -30,13 +30,6 @@ #include "jframe.h" #include "rt.h" #include "cg.h" -#if !defined(_IPF_) - #include "cg_ia32.h" -#endif - - -#include "../shared/PlatformDependant.h" - #include <jit_export.h> #include <assert.h> @@ -51,658 +44,217 @@ namespace Jitrino { namespace Jet { /** - * @brief Simple smart pointer. - * - * A trivial smart pointer implementation for dynamically allocated arrays. - * Allocated memory is deallocated in destructor. - * - * Does not support neither copying, nor resizing of array. Used to avoid - * head ache about controlling raw pointers of allocated memory. - * - * Used for arrays and includes bounds check in debug build - no bound - * checks performed in release one. + * @brief The name says it all. + * + * The constant used to preallocate memory in code stream to avoid + * multiple reallocation during code gen stage. + * + * @todo Was calculated for IA-32 long time ago, may require tuning for + * IA-64 and Intel-64. */ -template<class SomeType> class SmartPtr { -public: - /** - * @brief Initializes empty object. - */ - SmartPtr(void) - { - m_data = NULL; - } - - /** - * @brief Allocates memory for \c count elements of SomeType. - */ - void alloc(unsigned count) - { - m_data = new SomeType[count]; - m_count = count; - } - - /** - * @brief Returns number of elements in the allocates array. - */ - unsigned count(void) const - { - return m_count; - } - - /** - * @brief Provides random access to an item by index. - * - * Bounds check is preformed only in debug build. - */ - SomeType& operator[](unsigned idx) - { - assert(idx<m_count); - return m_data[idx]; - } - - /** - * @brief Provides a direct access to the allocated array. - */ - SomeType* data(void) - { - return m_data; - } - - /** - * @brief Returns size of allocated memory, in bytes. - */ - unsigned bytes(void) - { - return sizeof(SomeType)*m_count; - } - - /** - * @brief Fress allocated resources. - */ - ~SmartPtr() - { - delete[] m_data; - } -private: - /** - * @brief Pointer to the allocated memory. - */ - SomeType * m_data; - /** - * @brief Number of elements in the allocated array. - */ - unsigned m_count; - /** - * @brief Disallow copying. - */ - SmartPtr(const SmartPtr&); - /** - * @brief Disallow copying. - */ - SmartPtr& operator=(const SmartPtr&); -}; - -/** - * @brief Reads out a 4-byte integer stored in the Java's format - 'most - * significant bytes first'. - * @param pbc - a buffer to read from - * @return integer - */ -inline int bc_int(const unsigned char * pbc) -{ - return (int)(((*(pbc+0))<<24) | ((*(pbc+1))<<16) | - ((*(pbc+2))<<8) | ((*(pbc+3))<<0)); -} - -/** - * @brief Counts number of slots occupied by the specified set #jtype items. - * @param args - array of #jtype - * @return number of slots occupied by the specified set of #jtype items - */ -inline unsigned count_slots(const ::std::vector<jtype>& args) -{ - unsigned slots = 0; - for (unsigned i=0; i<args.size(); i++) { - slots += (args[i] == dbl64 || args[i] == i64 ? 2 : 1); - }; - return slots; -} - -/** - * @brief Counts number of slots occupied by the specified set #jtype items. - * @param num - number of items in the \c args array - * @param args - array of #jtype - * @return number of slots occupied by the specified set of #jtype items - */ -inline unsigned count_slots(unsigned num, const jtype * args) -{ - unsigned slots = 0; - for (unsigned i=0; i<num; i++) { - slots += args[i] == dbl64 || args[i] == i64 ? 2 : 1; - } - return slots; -} +#define NATIVE_CODE_SIZE_2_BC_SIZE_RATIO (10) /** - * @brief Java byte code instruction. + * The class represents a JIT compiler for the Java bytecode under DRLVM + * environment. */ -struct JInst { - /** - * @brief Program counter of this instruction. - */ - unsigned pc; - /** - * @brief Program counter of next instruction. - */ - unsigned next; - /** - * @brief Instruction's opcode. - */ - JavaByteCodes opcode; - /** - * @brief Instruction's flags. - */ - unsigned flags; - /** - * @brief Value of the first instrution's operand, if applicable. - * - * @note If instruction has no operands, the value of 'op0' is undefined. - */ - int op0; - - /** - * @brief Value of the second instrution's operand, if applicable. - * - * @note If instruction has no second operands, the value of 'op1' is - * undefined. - */ - int op1; - - /** - * @brief Address of data (the padding bytes skipped) for the switch - * instructions. - * - * @note For instructions other than switch, the value is undefined. - */ - const unsigned char* data; - - /** - * @brief Returns number of targets for a branch or switch instruction. - * - * For branches it's always 1. - * For switches the default target is not included in the value. - * For other instructions returns 0. - */ - unsigned get_num_targets(void) const - { - if (is_branch()) { return 1; }; - if (opcode == OPCODE_TABLESWITCH) { - return high() - low() + 1; - } - if (opcode != OPCODE_LOOKUPSWITCH) { - return 0; - } - // 4 here is the number of bytecode bytes between the values - comes - // from the JVM Spec - return bc_int(data + 4); // +4 - skip the 'defaultbyte*4' - } - - /** - * @brief Returns a PC value for the target 'i'. - * - * Must be only invoked for the branch or switch instructions and 'i' - * must be less or equal to gen_num_targets(). - * For other cases the behavior is unpredictable. - */ - unsigned get_target(unsigned i) const - { - assert(i < get_num_targets()); - if (is_branch()) { - return (unsigned short)(((unsigned short)pc) + - ((unsigned short)op0)); - } - if (opcode == OPCODE_TABLESWITCH) { - // '4+4+4' - skip defaultbyte, lowbyte and hightbyte - const int * poffsets = (int*)(data + 4 + 4 + 4); - return pc + bc_int((unsigned char*)(poffsets + i)); - } - assert(opcode == OPCODE_LOOKUPSWITCH); - // '4+4' - skip defaultbyte and npairs - const int * ppairs = (int*)(data+4+4); - return pc + bc_int((unsigned char*)(ppairs + i*2 + 1)); - } - /** - * @brief Returns default target for switch instructions. - * - * Must only be invoked for TABLESWITCH or LOOKUPSWITCH instructions. - */ - unsigned get_def_target(void) const - { - assert(opcode == OPCODE_TABLESWITCH || opcode == OPCODE_LOOKUPSWITCH); - unsigned offset = bc_int(data); - return (unsigned short)(((unsigned short)pc)+((unsigned short)offset)); - } - - /** - * @brief Returns size of data (in bytes) occupied by LOOKUPSWITCH or - * TABLESWITCH datas. - * - * Must only be invoked for TABLESWITCH or LOOKUPSWITCH instructions. - */ - unsigned get_data_len(void) const - { - if (opcode == OPCODE_TABLESWITCH) { - // 4*3 = defaultbyte,lowbyte,highbyte ; +jmp offsets - return 4*3 + 4*(high()-low()+1); - } - assert(opcode == OPCODE_LOOKUPSWITCH); - // defaultbyte + npairs + (4*2)*npairs - return (4 + 4 + 4*2 * get_num_targets()); - } - - /** - * @brief Returns minimum value of TABLESWITCH instruction. - * - * Must only be invoked for TABLESWITCH instructions. - */ - int low(void) const +class Compiler : public CodeGen { +public: + Compiler(JIT_Handle jh) { - assert(opcode == OPCODE_TABLESWITCH); - // 4 here is the number of bytecode bytes between the values - comes - // from the JVM Spec - return bc_int(data + 4); + m_hjit = jh; + m_bEmulation = false; } - /** - * @brief Returns maximum value of TABLESWITCH instruction. - * - * Must only be invoked for TABLESWITCH instructions. + * @brief Main compilation routine. */ - int high(void) const - { - assert(opcode == OPCODE_TABLESWITCH); - // 4 here is the number of bytecode bytes between the values - comes - // from the JVM Spec - return bc_int(data + 4+4); - } - + JIT_Result compile(Compile_Handle ch, Method_Handle method, + const OpenMethodExecutionParams& params); /** - * @brief Returns Nth key of LOOKUPSWITCH instruction. - * - * Must only be invoked for LOOKUPSWITCH instructions. + * @brief Adds a flag to default compilation flags. + * @see JMF_ */ - int key(unsigned i) const + static void addDefaultFlag(unsigned flag) { - assert(opcode == OPCODE_LOOKUPSWITCH); - // skip defaultbyte(+4), npairs(+4) and 'i' pairs - return bc_int(data+4+4 + i*2*4); + defaultFlags |= flag; } /** - * @brief Tests whether the instruction is branch - either conditional or - * not. JSR-s are also considered branches, but not SWITCH - * instructions. + * @brief Removes a flag from default compilation flags. + * @see JMF_ */ - bool is_branch(void) const + static void deleteDefaultFlag(unsigned flag) { - return (OPCODE_IFEQ <= opcode && opcode <= OPCODE_JSR) || - (OPCODE_IFNULL <= opcode && opcode <= OPCODE_JSR_W); + defaultFlags &= ~flag; } /** - * @brief Tests whether the instruction SWITCH - either TABLESWITCH or - * LOOKUPSWITCH. + * If not NOTHING, then only methods with compilation id more or equal + * to this id are compiled. */ - bool is_switch(void) const - { - return (opcode == OPCODE_TABLESWITCH || opcode == OPCODE_LOOKUPSWITCH); - } -}; - -/** - * @brief General info about basic block - */ -struct BBInfo { + static unsigned g_acceptStartID; /** - * @brief Very first bytecode instruction - the basic block's leader. + * If not NOTHING, then only methods with compilation id less or equal + * to this id are compiled. */ - unsigned start; - + static unsigned g_acceptEndID; /** - *@brief Last bytecode instruction which belongs to this basic block. + * If not NOTHING, then methods with compilation id more or equal + * to this id are rejected (JIT_FAILURE returned) without compilation. */ - unsigned last_pc; - + static unsigned g_rejectStartID; /** - * @brief Leader of the next basic block. - * - * Actually, the next BB's leader can be obtained by a call to - * \link Compiler::fetch Compiler::fetch \endlink. This redundancy is - * intentional to avoid this additional call. + * If not NOTHING, then methods with compilation id less or equal + * to this id are rejected (JIT_FAILURE returned) without compilation. */ - unsigned next_bb; + static unsigned g_rejectEndID; /** - * @brief Offset of the BB's code. - * - * Before layout - offset in codeStream, after layout - in the m_vmCode. - * If the BB has a prolog, then ipoff points to the prolog code. - */ - unsigned ipoff; - - /** - * @brief Total size of native code of the basic block. + * @brief Dumps out the basic blocks structure. + * For debugging only. */ - unsigned code_size; - + void dbg_dump_bbs(void); /** - * @brief Number of ways this basic block can be reached by. + * @brief Dumps out disassembled piece of code. + * For debugging only. */ - unsigned ref_count; - + void dbg_dump_code(const char * code, unsigned length, const char * name); /** - * @brief \b true if this basic block is a target for at least - * one JMP-like instruction (goto/if_*). + * @brief Dumps out disassembled the whole code of the method, mixed with + * appropriate bytecode. + * For debugging only. * - * Was intented to perform branch target aligment on IA32/EM64T, - * but currently unused. - */ - bool jmp_target; - /** - * @brief \b true if the basic block servers as a target for at least one - * JSR instruction. + * The code must be already generated and available for VM - + * \b method_get_code_block_addr_jit is used to obtain the code. */ - bool jsr_target; - + void dbg_dump_code_bc(const char * code, unsigned codeLen); /** - * @brief \b true if this basic block is a catch handler. + * @brief Converts the JInst into the human-readable string. + * For debugging only. * - * Normally this means that is has an additional small prolog which puts - * exception object onto the stack. - */ - bool ehandler; - /** - * @brief \b true if the basic block was processed in bbs_gen_code(). - * - * Used to avoid recursion and to detect unreachable code at the code - * layout stage. - */ - bool processed; -}; - -/** - * @brief Defines a map of PC_of_bb_start -> BBInfo. - */ -typedef ::std::map<unsigned, BBInfo> BBMAP; - -/** - * @brief Set of bitsets which shows whether a code for an item's resolution - * was generated (in lazy resolution scheme). - * - * Each opcode which requires resolution is mapped into one of #RefType - * constants. These constants are then used to select a bitset. In this - * bitset, an constant pool's index is used to select a bit. The bit state - * shows whether the code for resolution was generated or not. If the - * resolution code was already generated, then only code to reuse the result - * is generated. - * - * @deprecated Experimental, not a production feature. - */ -struct ResState { - /* - Actually, the size must be 4096, not 32. - The size of 4096 allows to cover all the real ranges of constant pool - indexes for client applications. However, as the compilation in - bbs_gen_code is recursive, and the ResState items are created on stack, - we'll get stack overflow with 4096. - 512 is the speculative size which does not cause stack overflow. - However the lazy resolution is not a production feature at this moment, - so the size is reduced further to 32, to avoid copying overhead in - bbs_gen_code. - */ - //::std::bitset<512> states[RefType_Count]; - ::std::bitset<32> states[RefType_Count]; - /** - * @brief Tests whether a resolution for the given opcode was performed - * in the current basic block already. - * @return \b true - if the code for the item's resolution was already - * generated - */ - bool test(JavaByteCodes opcod, unsigned idx) const - { - if (idx<states[0].size()) { - return states[toRefType(opcod)].test(idx); - } - return false; - } - /** - * @brief Sets a flags that a resolution for the given opcode was - * performed. - */ - void done(JavaByteCodes opcod, unsigned idx) - { - if (idx<states[0].size()) { - states[toRefType(opcod)].set(idx); - } - } -}; - -/** - * @brief State of a basic block during code generation. - */ -struct BBState { - /** - * @brief No op. - */ - BBState() {}; - /** - * @brief Current stack frame for the BB. + * @param jinst - instruction to be presented as string. + * @param show_names - if \b true, then the string contains symbolic + * names, otherwise only constant pool indexes. */ - JFrame jframe; + ::std::string toStr(const JInst& jinst, bool show_names); /** - * @brief Recently stored stack depth. - * - * Used to eliminate unnecessary stack depth updates. + * @brief Prints out a string 'compilation started'. + * For debugging only. + * @see DBG_TRACE_SUMM */ - unsigned stack_depth; + void dbg_trace_comp_start(void); /** - * @brief Recently stored GC mask for stack. - * - * Used to eliminate unnecessary stack GC map updates. - * - * Only single word of the GC mask is stored - it's enough for most - * applications. + * @brief Prints out a string 'compilation finished', with a reason why + * compilation failed, if \c success is \b false. + * For debugging only. + * @see DBG_TRACE_SUMM */ - unsigned stack_mask; + void dbg_trace_comp_end(bool success, const char * reason); /** - * @brief \b true if #stack_mask contains a 'valid' (that is which was - * really written). + * @brief Generates code to ensure stack integrity at the beginning + * of a basic block at runtime. * - * The #stack_depth field may contain limited set of values and thus - * the field itself may carry info whether it contains 'non-initialized' - * flag (#NOTHING) or the real stack depth (any other value). + * This is used to ensure stack integrity after branches which can not be + * controlled by #gen_dbg_check_stack. * - * In opposite, for the #stack_mask any value is valued combination. Thus - * it's necessary to indicate whether the stack_mask was initialized or - * not. Here is this flag intended for. + * @note For debug checks only. */ - bool stack_mask_valid; + void gen_dbg_check_bb_stack(void); /** - * @brief 'true' if there was at least one GC point in the basic block. + * @brief If not #NOTHING, then software breakpoint inserted before the + * code at the specified PC of the generated code. * - * Set during the code generation and is used to reduce unnecessary back - * branch pooling code. + * For debugging only. */ - bool seen_gcpt; - /** - * @brief Shows which items are already have a code for lazy resolution - * generated. - */ - ResState resState; + unsigned dbg_break_pc; + private: - /** @brief Disallow copying */ - BBState(const BBState&); - /** @brief Disallow copying */ - BBState& operator=(const BBState&); -}; -/** - * @brief Information about exception handler. - */ -struct HandlerInfo { /** - * @brief Start PC of bytecode region protected by this exception handler - * (inclusive). + * @brief Default flags for compilation. + * @see JMF_ */ - unsigned start; - /** - * @brief End PC of bytecode region protected by this exception handler - * (exclusive). - */ - unsigned end; - /** - * @brief Entry point PC of exception handler. - */ - unsigned handler; - /** - * @brief Type of exception handled by this handler. 0 for 'any type'. - */ - unsigned type; - /** - * @brief Class_Handle of the exception class for this handler. - */ - Class_Handle klass; - /** - * @brief IP for #start. - */ - char * start_ip; - /** - * @brief IP for #end. - */ - char * end_ip; - /** - * @brief IP for #handler. - */ - char * handler_ip; -}; - -/** - * @brief Rrepresents a JIT compiler for the Java bytecode under DRLVM - * environment. - */ -class Compiler : public VMRuntimeConsts { -public: + static unsigned defaultFlags; - //*********************************************************************** - //* Public interface - //*********************************************************************** - /** - * @brief Only stores the given parameters. - */ - Compiler(JIT_Handle jh, const OpenMethodExecutionParams& params) : - compilation_params(params) - { - jit_handle = jh; - } - /** - * @brief Main compilation routine. + * @brief Decodes bytecode instructions, finds basic blocks and + * collects local vars usage info. */ - JIT_Result compile(Compile_Handle ch, Method_Handle method); + void comp_parse_bytecode(void); /** - * @brief Default compilation flags propagated to all methods. - * @see \link JITRINO_JET_JAVA_METHOD_FLAGS JMF_ flags \endlink. - */ - static unsigned defaultFlags; -private: - //*********************************************************************** - //* Initialization - //*********************************************************************** - - /** - * @brief Initializes various runtime constants - helpers' addresses, - * runtime constants, etc. - * @see VMRuntimeConsts + * @brief Helper function for comp_parse_bytecode(). + * + * Creates a BBInfo record for the given \c pc or returns an one. */ - static void initStatics(void); + BBInfo& comp_create_bb(unsigned pc); /** - * @brief Initializes profiling data. - * - * Adds appropriate JMF_ flags to \c pflags if necessary. - * @param pflags - flags which will be used for compilation. Must not be - * NULL. + * @brief Performs global register allocation. */ - void initProfilingData(unsigned * pflags); - - //*********************************************************************** - //* Byte code processing - //*********************************************************************** - - /** - * @brief Finds and marks all the basic blocks. - */ - void bbs_mark_all(void); - - /** - * @brief A helper function for #bbs_mark_all(). - * @param pc - a PC of basic block's leader bytecode instruction - * @param jmp_target - \b true is the basic block is a target for an - * goto/ifXX/jsr - * @param add_ref - if \b true, then increments ref_count for the given - * basic block (i.e. if this is fall-through basic block) - * @param ehandler - \b true, if basic block represents catch handler - * @param jsr_target - \b true if basic block is JSR subroutine - */ - void bbs_mark_one(unsigned pc, bool jmp_target, bool add_ref, - bool ehandler, bool jsr_target); + void comp_alloc_regs(void); /** * @brief Generates code for a given basic block. * * When pc=0, also generates prolog code. * - * If \c jsr_lead is not NOTHING (which means that this basic block - * is part of JSR subroutine) then the final state of the stack on a RET + * If \c jsr_lead is not NOTHING, which means that this basic block + * is part of JSR subroutine, then the final state of the stack on a RET * instruction will be stored for this jsr_lead and then reused if there * are several JSR instructions point to the same (jsr_lead) block. * * @param pc - program counter of the basic block - * @param prev - state of the basic block's predecessor, NULL if no - * predecessors (i.e. PC = 0, exception handlers) + */ + void comp_gen_code_bb(unsigned pc); + /** + * @param pc - program counter of the basic block + * @param parentPC - program counter of basic block which is + * predecessor of \c pc block. This is the block the BBState is + * inherited from. * @param jsr_lead - PC of the beginning of the JSR block, we're * currently in, or #NOTHING we're not in JSR block. */ - void bbs_gen_code(unsigned pc, BBState * prev, unsigned jsr_lead); + bool comp_gen_insts(unsigned pc, unsigned parentPC, unsigned jsr_lead); /** * @brief Performs layout of the native code, so it become same as byte * code layout. + * @param prolog_ipoff - offset of prolog code m_codeStream/ + * @param prolog_size - size of prolog code, in bytes. */ - void bbs_layout_code(void); + void comp_layout_code(unsigned prolog_ipoff, unsigned prolog_size); /** * @brief Resolves method's exception handlers. * - * @note Does call resolve_class() and and thus must not be used when the + * @note Does call resolve_class() and thus must not be used when the * lock protecting method's data is locked. - * @return \b true if resolution was successful, \b false otherwise + * @return \c true if resolution was successful, \c false otherwise */ - bool bbs_ehandlers_resolve(void); + bool comp_resolve_ehandlers(void); /** * @brief Registers method's exception handlers. * - * Does not call resolve_class() and may be used when a lock + * @note Does \b not call resolve_class() and may be used when a lock * protecting method's data is locked. */ - void bbs_ehandlers_set(void); - + void comp_set_ehandlers(void); /** * @brief Fills out a native addresses of an exception handler and * a block it protects. + * @param[in,out] hi - info about handler to process. */ - bool bbs_hi_to_native(char * codeBlock, HandlerInfo& hi); + bool comp_hi_to_native(HandlerInfo& hi); /** + * @brief Performs code patching. + * + * The code patching is to finalize addresses for relative-addressing + * instructions like ÎMP, and for instructions which refer to a data + * allocated after the instructions generated (indirect JMPs for + * LOOKUP/TABLE-SWITCH). + */ + void comp_patch_code(void); + /** * @brief Fetches out and decodes a bytecode instruction starting * from the given 'pc'. * @return PC of the next instruction, or NOTHING if end of byte code @@ -712,155 +264,61 @@ private: /** * @brief Invokes appropriate handle_ik_ method to generate native code. */ - void handle_inst(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles method invocation - * instructions. - */ + void handle_inst(void); + /** @brief a helper method for #handle_inst() */ void handle_ik_meth(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles object manipulation - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_obj(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles stack manipulation - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_stack(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles throw instruction. - */ - void handle_ik_throw(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles arithmetic - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_a(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles control flow - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_cf(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles conversion - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_cnv(const JInst& jinst); - /** - * @brief Helper method for #handle_inst(), handles load and store - * instructions. - */ + /** @brief a helper method for #handle_inst() */ void handle_ik_ls(const JInst& jinst); - //*********************************************************************** - //* Code generation routines - //*********************************************************************** - + // + // CodeGeneration stuff. Most of these functions are like CodeGen's + // ones, but they deal with basic blocks, so it's better to place + // them here in Compiler. + // /** * @brief Generates method's prolog code. */ - void gen_prolog(const ::std::vector<jtype>& args); + void gen_prolog(void); /** * @brief Generates method's epilogue (on RETURN instructions) code. */ void gen_return(jtype retType); - /** - * @brief Generates code for pushing int constant on operand stack. - */ - void gen_push(int); - /** - * @brief Generates code for pushing jlong constant on operand stack. - */ - void gen_push(jlong); - /** - * @brief Generates code which reads a constant value of type 'jt' from - * the address specified by 'p' and pushes it onto the stack. - */ - void gen_push(jtype jt, const void * p); - /** - * @brief Generates code which pops out a value of type 'jt' from the - * operand stack and stores it at the address specified by 'p'. - */ - void gen_pop(jtype jt, void * p); - /** - * @brief Generates code to perform POP2 bytecode instruction. - */ - void gen_pop2(void); - /** - * @brief Generates various DUP_ operations. - */ - void gen_dup(JavaByteCodes opc); - /** - * @brief Generates xSTORE operations. - */ - void gen_st(jtype jt, unsigned idx); - /** - * @brief Generates xLOAD operations. - */ - void gen_ld(jtype jt, unsigned idx); - /** - * @brief Generates LDC operation. - */ - void gen_ldc(void); - /** - * @brief Generates code for INVOKE instructions. - */ - void gen_invoke(JavaByteCodes opcod, Method_Handle meth, - const ::std::vector<jtype>& args, jtype retType); - /** - * @brief Generates code to put a value of specified type onto operand - * stack (presuming there was a call which returned the value). - */ - void gen_save_ret(jtype jtyp); - /** - * @brief Generates code to call one of the throw_ helpers. - * - * @note The method only synchronize local vars into the memory, - * and does not update the status ! - */ - void gen_call_throw(void * target, unsigned num_args, ...); /** - * @brief Generates code non-VM helper. - * - * The method does not update GC info. + * @brief Prepares BBState as it was left by gen_bb_leave(). + * @see gen_bb_leave */ - void gen_call_novm(void * target, unsigned num_args, ...); - + void gen_bb_enter(void); /** - * @brief Generates code to call a VM helper. + * @brief Generates code to leave current basic block. * - * The method updates GC info and synchronizes both stack and local vars. - */ - void gen_call_vm(void * target, unsigned num_args, ...); - - /** - * @brief Generates register/memory operations - spill out and upload. + * The leave code is to place operands on their places - stack operands + * go to memory, globally allocated variables are loaded into registers + * and not allocated scratch registers are freed. * - * There are some [obvious] constraints for parameters: - * - either #MEM_VARS or #MEM_STACK must be specified, or both - * - either #MEM_TO_MEM or #MEM_FROM_MEM must be specified, but not both - * - either #MEM_UPDATE or #MEM_NO_UPDATE must be specified, but not both - * - #MEM_INVERSE can only be used with #MEM_FROM_MEM and #MEM_NO_UPDATE - * @see JITRINO_JET_MEM_TRANSF_FLAGS. + * Such leave code is executed only if \c to basic block has more than + * one reference. Otherwise no code generated. + * @see gen_bb_enter */ - void gen_mem(unsigned flags); - + void gen_bb_leave(unsigned to); /** - * @brief Generates code to take arguments from Java operand stack and - * put them to the native stack to prepare a call. - * - * @param pop - if \b true, the arguments are popped out from the operand - * stack. Otherwise, the operand stack is left intact. - * @param num - how many operands are in \c args - * @param args - array of #jtype describing argument types + * @brief Generates either LOOKUPSWITCH or TABLESWITCH. */ - void gen_stack_to_args(bool pop, unsigned num, const jtype * args); + void gen_switch(const JInst& jinst); /** * @brief Generates various IF_ operations. * - * Also inserts back branch pooling (if the \link #JMF_BBPOOLING + * Also inserts back branch polling (if the \link #JMF_BBPOLLING * appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink * instrumentation code. */ @@ -868,7 +326,7 @@ private: /** * @brief Generates various IF_ICMP operations. * - * Also inserts back branch pooling (if the \link #JMF_BBPOOLING + * Also inserts back branch polling (if the \link #JMF_BBPOLLING * appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink * instrumentation code. */ @@ -876,7 +334,7 @@ private: /** * @brief Generates GOTO operation. * - * Also inserts back branch pooling (if the \link #JMF_BBPOOLING + * Also inserts back branch polling (if the \link #JMF_BBPOLLING * appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink * instrumentation code. */ @@ -890,259 +348,15 @@ private: * @param idx - index of local variable. */ void gen_ret(unsigned idx); - /** - * @brief Generates IINC operation. - * @param idx - index of local variable. - * @param value - value to add. - */ - void gen_iinc(unsigned idx, int value); - /** - * @brief Generates arithmetic operations. - * - * @note \c op argument always specified as integer operation (for - * example IADD, INEG), even if \c jt specifies float-point or long - * type. - * - * @param op - operation to perform. - * @param jt - types used in the arithmetic operation. - */ - void gen_a(JavaByteCodes op, jtype jt); - /** - * @brief Helper function for #gen_a, generates #i32 arithmetics. - */ - void gen_a_i32(JavaByteCodes op); - /** - * @brief Generates conversion code. - */ - void gen_cnv(jtype from, jtype to); - /** - * @brief Generates various CMP operations. - */ - void gen_x_cmp(JavaByteCodes op, jtype jt); - /** - * @brief Generates ARRAYLENGTH instruction. - */ - void gen_array_length(void); - /** - * @brief Generates ALOAD instruction. - * - * @note Does not check bounds. It must be done separately. - */ - void gen_aload(jtype jt); - /** - * @brief Generates ASTORE instruction. - * - * @note Does not check bounds. It must be done separately. - */ - void gen_astore(jtype jt); - /** - * @brief Generates PUTFIELD and GETFIELD operations. - */ - void gen_field_op(JavaByteCodes op, jtype jt, Field_Handle fld); - /** - * @brief Generates PUTSTATIC and GETSTATIC operations. - */ - void gen_static_op(JavaByteCodes op, jtype jt, Field_Handle fld); - /** - * @brief Generates code for INSTANCEOF or CHECKCAST operations. - * @param chk - if \b true, generates CHECKCAST, INSTANCEOF otherwise. - * @param klass - Class_Handle of the class to cast to. - */ - void gen_instanceof_cast(bool chk, Class_Handle klass); - - /** - * @brief Generates code to check bounds for array access. - * @param aref_depth - depth (in the operand stack) of the array's object - * reference - * @param index_depth - depth (in the operand stack) of the index to be - * used for array's access. - */ - void gen_check_bounds(unsigned aref_depth, unsigned index_depth); - /** - * @brief Generates code to check whether the object ref at the given - * depth in the operand stack is \c null. - * @param stack_depth_of_ref - depth in the operand stack of the object - * reference to test against \c null. - */ - void gen_check_null(unsigned stack_depth_of_ref); - /** - * @brief Generates code to check whether an item used in division - * operation is zero. - * @param jt - type of division operation (#i64 or #i32) to be performed. - * @param stack_depth_of_divizor - depth in the operand stack of the - * divisor. - */ - void gen_check_div_by_zero(jtype jt, unsigned stack_depth_of_divizor); - /** - * @brief Patches a native instruction identified by \c cpi parameter. - * @see CodePatchItem - */ - void gen_patch(const char * codeBlock, const CodePatchItem& cpi); - /** - * @brief Generates code for NEW instruction. - */ - void gen_new(Class_Handle klass); - - /** - * @brief Generates either LOOKUPSWITCH or TABLESWITCH. - */ - void gen_switch(const JInst& jinst); - - /** - * @brief Generates a code which prepares GC info for operand stack - - * stack depth and GC mask. - * - * @param depth - if \b -1, then current stack depth is taken (#m_jframe), - * otherwise, the specified depth is stored. - * @param trackIt - if \b true, then the GC info is also reflected in the - * current BB's state (BBState::stack_depth, - * BBState::stack_mask). - * @see BBState - */ - void gen_gc_stack(int depth=-1, bool trackIt=false); - - /** - * @brief Generates code which either marks or clears mark on a local - * variable to reflect whether it holds an object or not (runtime - * GC info). - */ - void gen_gc_mark_local(unsigned idx, bool mark); - - /** - * @brief Generates GC safe point code which facilitate thread suspension - * on back branches. - */ - void gen_gc_safe_point(void); - /** - * @brief Generates ANEWARRAY, NEWARRAY. - */ - void gen_new_array(Allocation_Handle ah); - /** - * @brief Generates MULTIANEWARRAY. - */ - void gen_multianewarray(Class_Handle klass, unsigned num_dims); - - /** - * @brief generates code for to resolve an item for the specified - * opcode at runtime (lazy resolution scheme). - * - * @deprecated Not a production feature. - */ - void gen_lazy_resolve(unsigned idx, JavaByteCodes opkod); - //*********************************************************************** - //* Code patching and code buffer related routines - //*********************************************************************** - - /** - * @brief Performs code patching. - * - * The code patching is to finalize addresses for relative-addressing - * instructions like CALL, JMP, and for instructions which refer to a - * data allocated after the instructions generated (indirect JMPs for - * LOOKUPSWITCH, data for lazy resolution stuff). - */ - void cg_patch_code(void); - - /** - * @brief Returns a current 'ip' where to generate code into. - * - * The ip returned is a pointer to an internal \b temporary code buffer. - * - * @see CodeStream - */ - char * ip(void) - { - return m_codeStream.ip(); - } - - /** - * @brief Sets a current ip for the internal code buffer. - * - * If there was a code patch registered before, then finalizes the patch. - * - * @see CodeStream - */ - void ip(char * ip); - /** - * @brief Registers next instruction to be generated as a subject for - * code patching. - * - * This means that after \link #bbs_layout_code code layout \endlink, the - * #gen_patch() method will be invoked with an info to find the generated - * instruction and to update (patch) it. The data to patch depends on the - * reg_patch() invoked. - * - * After the reg_patch() call, the patching machinery awaits for next - * call of #ip(char*) - it allows to determine generated instruction's - * length. - */ - unsigned reg_patch(void); - /** - * @brief Registers next instruction (normally JMP/Jcc) to be patched - * with an address of instruction corresponding to \c target_pc. - * - * Must only be used for JMP/Jcc/CALL instructions as the address to - * write is calculated as relative to the instruction's address. - */ - unsigned reg_patch(unsigned target_pc); - /** - * @brief Same as #reg_patch(unsigned), but may specify whether the - * address to write must be relative to instruction's address. - */ - unsigned reg_patch(unsigned target_pc, bool relative); - /** - * @brief Registers next instruction (normally CALL/JMP) to be patched - * with a \c target_ip address. - */ - unsigned reg_patch(const void * target_ip); - /** - * @brief Sets patch data, so it points to the specified address. - */ - void patch_set_target(unsigned patchID, char * _ip); - /** - * @brief Sets patch data, so it points to the specified offset in the - * #m_codeStream. - */ - void patch_set_target(unsigned patchID, unsigned _ipoff); - /** - * @brief Registers TABLESWITCH instruction which will be patched with - * a table of references. - * - * The table allocated during code patching. - */ - void reg_table_switch_patch(void); - /** - * @brief Special case of patching - data address for lazy resolution - * item. - * @deprecated Not a production feature. - */ - void reg_data_patch(RefType type, unsigned cp_idx); - - //*********************************************************************** - //* Various method data - //*********************************************************************** - - /** - * @brief The byte code of the method being compiled. - */ - unsigned char * m_bc; - /** - * @brief List of types of input arguments (includes 'this' for instance - * methods). - */ - ::std::vector<jtype> m_args; + // + // Method being compiled info + // /** * @brief Return type of the method. */ - jtype m_retType; - - /** - * @brief Method's flags as they are known for VM (ACC_STATIC, etc...). - */ - unsigned m_java_meth_flags; - + jtype m_retType; /** * @brief A list to keep exception handlers' info. */ @@ -1154,170 +368,47 @@ private: * The list preserves the order in which the VM returns the info about * the handlers. */ - HADLERS_LIST m_handlers; - - /** - * @brief Method's info block. - */ - MethodInfoBlock m_infoBlock; + HADLERS_LIST m_handlers; /** * @brief Map of basic blocks. A key is basic block's leader's PC. */ - BBMAP m_bbs; - /** - * @brief Array of decoded instructions. - */ - SmartPtr<JInst> m_insts; - /** - * @brief Current basic block's info. - * - * @note Only valid during code generation. - */ - const BBInfo * m_curr_bb; - /** - * @brief Current basic block's state. - * - * @note Only valid during code generation. - */ - BBState * m_curr_bb_state; - /** - * @brief \b true, if the next basic block has ref_count > 1. - * - * @note Only valid at the very last instruction of \link #m_curr_bb - * basic block \endlink. - */ - bool m_next_bb_is_multiref; - - /** - * @brief PC of an instruction currently processed. - */ - unsigned m_pc; + BBMAP m_bbs; /** - * @brief Instruction currently being processed. - */ - const JInst * m_curr_inst; - - /** - * @brief Maps PC->JFrame state. - */ - typedef ::std::map<unsigned, JFrame> STACK_STATE_MAP; - - /** - * @brief Maps PC(JSR subroutine lead) -> JFrame state. - * - * Used for JSR blocks: + * @brief Bunch of preallocated BBState-s. * - * If more than one JSR points to a single basic block, then the state - * of the stack only calculated once, during the first visit to the BB. - * Then this state is store in the map, and when we process second - * instruction pointing to the same BB, we do not re-iterate over BB's - * instructions, but use already caclulated state. + * A key in the map is basic block's PC. */ - STACK_STATE_MAP m_stack_states; + map<unsigned, BBState*> m_bbStates; /** - * @brief Java method's frame - operand stack and local variables. + * @brief Pre-calculated BBState-s at the end of JSR subroutines. * - * @note Only valid during code-generation phase. + * A key in the map is JSR subroutine beginning PC. */ - JFrame * m_jframe; - - //*********************************************************************** - //* Instrumentation, profiling - //*********************************************************************** + map<unsigned, BBState*> m_jsrStates; /** - * @brief Pointer to method's entrances counter. - * @see JMF_PROF_ENTRY_BE - */ - unsigned * m_p_methentry_counter; - /** - * @brief Pointer to method's back branches counter. - * @see JMF_PROF_ENTRY_BE - */ - unsigned * m_p_backedge_counter; - /** - * @brief Threshold for method entry counter which fires recompilation - * (in synchronized recompilation mode). - */ - unsigned m_methentry_threshold; - /** - * @brief Threshold for back edges counter which fires recompilation - * (in synchronized recompilation mode). - */ - unsigned m_backedge_threshold; - /** - * @brief Profile handle to be passed to recompilation handler (in - * synchronized recompilation mode). + * @brief Array of decoded instructions. + * @todo check whether changing AoS=>SoA gives a compilation speedup. */ - void* m_profile_handle; + SmartPtr<JInst> m_insts; + /** - * @brief Recompilation handler (in synchronized recompilation mode). + * @brief Only emulates compilation - do not register the generated + * code in VM. */ - void * m_recomp_handler_ptr; - - //*********************************************************************** - //* Code generation, patching data - //*********************************************************************** - + bool m_bEmulation; + /** * @brief Code buffer allocated by VM. */ - char * m_vmCode; - /** - * @brief Internal temporary buffer where the generated code is - * accumulated. - * - * Normally not to be used directly, but instead through #ip() methods - * calls. - */ - CodeStream m_codeStream; - /** - * @brief Id of a current patch item, or -1 if no active patch awaiting - * for #ip(char*) call. - */ - int m_patchID; - /** - * @brief List of registered patch items. - */ - ::std::vector<CodePatchItem> m_patchItems; - /** - * @brief A map which maps \link #ref_key reference key \endlink to - * a memory slot. - * @deprecated Not a production feature. - */ - typedef ::std::map<unsigned, void*> U2PTRMAP; - /** - * @brief A map which maps \link #ref_key reference key \endlink to - * a memory slot. - * @deprecated Not a production feature. - */ - U2PTRMAP m_lazyRefs; - - //*********************************************************************** - //* Interface to VM - data and methods - //*********************************************************************** - - /** - * @brief Compilation parameters. - */ - const OpenMethodExecutionParams& compilation_params; - /** - * @brief JIT handle. - */ - JIT_Handle jit_handle; + char * m_vmCode; + /** * @brief Compilation handle. */ - Compile_Handle m_compileHandle; - /** - * @brief Method handle. - */ - Method_Handle m_method; - /** - * @brief Class handle. - */ - Class_Handle m_klass; + Compile_Handle m_compileHandle; + /** * @brief Parses method's signature at the given constant pool entry. * @@ -1337,435 +428,31 @@ private: * @brief Obtains an arguments and return info from the given method. * @param meth - method handle to get the info for. * @param args - an array to fill out. Must be empty. - * @param retType - [out] return type of the method. Must not be NULL. - */ - static void get_args_info(Method_Handle meth, ::std::vector<jtype>& args, - jtype * retType); - /** - * @brief Converts VM_Data_Type to appropriate #jtype. + * @param[out] retType - return type of the method. Must not be NULL. */ - static jtype to_jtype(VM_Data_Type vmtype) + static void get_args_info(Method_Handle meth, + ::std::vector<jtype>& args, jtype * retType); + static jtype to_jtype(VM_Data_Type vmtype) { return ::Jitrino::Jet::to_jtype(vmtype); } /** - * @brief Converts given Type_Info_Handle to appropriate #jtype. + * @brief Converts VM_Data_Type to appropriate #jtype. */ static jtype to_jtype(Type_Info_Handle th); - - //*********************************************************************** - //* Debugging stuff - //*********************************************************************** - - /** - * @brief Dumps out the basic blocks structure. - * For debugging only. - */ - void dbg_dump_bbs(void); - /** - * @brief Dumps out disassembled piece of code. - * For debugging only. - */ - void dbg_dump_code(const char * code, unsigned length, const char * name); - /** - * @brief Dumps out disassembled the whole code of the method, mixed with - * appropriate bytecode. - * For debugging only. - * - * The code must be already generated and available for VM - - * \b method_get_code_block_addr_jit is used to obtain the code. - */ - void dbg_dump_code(void); - /** - * @brief Converts the JInst into the human-readable string. - * For debugging only. - * - * @param jinst - instruction to be presented as string. - * @param show_names - if \b true, then the string contains symbolic - * names, otherwise only constant pool indexes. - */ - ::std::string toStr(const JInst& jinst, bool show_names); - /** - * @brief Prints out a string 'compilation started'. - * For debugging only. - * @see DBG_TRACE_SUMM - */ - void dbg_trace_comp_start(void); - /** - * @brief Prints out a string 'compilation finished', with a reason why - * compilation failed, if \c success is \b false. - * For debugging only. - * @see DBG_TRACE_SUMM - */ - void dbg_trace_comp_end(bool success, const char * reason); - - /** - * @brief Generates code to ensure stack integrity at runtime. - * @note For debug checks only. - * @param start - \b true if check start to be generated, false otherwise - */ - void gen_dbg_check_stack(bool start); - /** - * @brief Generates code to ensure stack integrity at the beginning - * of a basic block at runtime. - * - * This is used to ensure stack integrity after branches which can not be - * controlled by #gen_dbg_check_stack. - * - * @note For debug checks only. - */ - void gen_dbg_check_bb_stack(void); - - /** - * @brief Generates code to output string during runtime. - * - * The generated code preserves general-purpose registers. - * The string is formatted before the code generation, then \link #rt_dbg - * get printed \endlink during runtime. - * - * For debugging only. - */ - void gen_dbg_rt_out(const char * fmt, ...); - - /** - * @brief Inserts a break point. - * - * For debugging only. - */ - void gen_dbg_brk(void); - -#if defined(JIT_STATS) || defined(JIT_LOGS) || \ - defined(JET_PROTO) || defined(_DEBUG) - /** - * @brief Counter for compilation requests came through the Jitrino.JET. - * - * Technically speaking, not equal to the number of compiled methods - * as some methods may be rejected, i.e. if resolution of exception - * handlers (performed at the very beginning) fails. - * - * @note Only used for debugging and tracing purposes, and so available - * only when either of the following macro defined: JIT_STATS, - * JIT_LOGS, JET_PROTO, _DEBUG. - * - * @note If no one of these macro defined, then it get declared and - * defined as a static constant so read-access may be left in the - * code without runtime overhead. - */ - static unsigned g_methodsSeen; - /** - * @brief Contains full name which consists of 'klass name::method name', - * but without a signature. - * - * @note See notes for #g_methodsSeen - the same applied here. - */ - char m_fname[1024*10]; -#else - static const char m_fname[1]; - static const unsigned g_methodsSeen = 0; -#endif - -#if defined(_DEBUG) || defined(JET_PROTO) - /** - * @brief If not #NOTHING, then breakpoint inserted before the code - * generated for the byte code instruction and the specified PC. - * For debugging only. - * @note Absent in production release build. - */ - unsigned dbg_break_pc; -#endif - /** @brief Constant to be used to load predefined float-point constant*/ - static const int g_iconst_m1; - /** @brief Constant to be used to load predefined float-point constant*/ - static const int g_iconst_0; - /** @brief Constant to be used to load predefined float-point constant*/ - static const int g_iconst_1; - /** @brief Constant to be used to load predefined float-point constant*/ - static const float g_fconst_0; - /** @brief Constant to be used to load predefined float-point constant*/ - static const float g_fconst_1; - /** @brief Constant to be used to load predefined float-point constant*/ - static const float g_fconst_2; - /** @brief Constant to be used to load predefined float-point constant*/ - static const double g_dconst_0; - /** @brief Constant to be used to load predefined float-point constant*/ - static const double g_dconst_1; - -#if !defined(_IPF_) - //*********************************************************************** - //* Code generation stuff specific to IA32/EM64T - //*********************************************************************** - - /** - * @brief Layout of native stack frame. - */ - StackFrame m_stack; - -public: // used for debug stuff - enum { - /** - * @brief How many XMM registers dedicated to hold float/double - * values for the operand stack. - */ - // Expected to be not less than 2, this presumption is used across - // the code - F_STACK_REGS = 3, - /** - * @brief How many XMM registers dedicated to hold float/double - * values for local vars. - */ - // Expected to be not less than 2, this presumption is used across - // the code - F_LOCAL_REGS = 3, // expected to be not less than 2 - /** - * @brief How many general-purpose registers dedicated to hold - * integer/long/object values for local vars. - */ - // Expected to be not less than 2, this presumption is used across - // the code - I_LOCAL_REGS = 2, // expected to be not less than 2 - /** - * @brief How many general-purpose registers dedicated to hold - * integer/long/object values for operand stack. - */ - // Expected to be not less than 4, this presumption is used across - // the code - I_STACK_REGS = 4 - }; - /** - * @brief Set of registers for both operand stack and local variables for - * float-pointer items. - */ - static const RegName g_frnames[F_STACK_REGS + F_LOCAL_REGS]; - /** - * @brief Set of registers for both operand stack and local variables for - * integer, long and object items. - */ - static const RegName g_irnames[I_STACK_REGS + I_LOCAL_REGS]; private: /** - * @brief Returns set of registers for the given type \c jt. + * @brief Initializes all global stuff in StaticConsts. */ - static inline const RegName * get_regs(jtype jt) - { - return is_f(jt) ? g_frnames : g_irnames; - } - - /** - * @brief Ensures that EAX register is free. - * - * Swaps it out to the memory, if it's occupied. - */ - void veax(void); - /** - * @brief Ensures that EDX register is free. - * - * Swaps it out to the memory, if it's occupied. - */ - void vedx(void); - /** - * @brief Pushes \c jt onto \link #m_jframe operand stack\endlink, and - * checks whether a registers which keep top of the stack need - * spill. - */ - void vpush(jtype jt, bool sync); - /** - * @brief Pops out \c jt from \link #m_jframe operand stack\endlink. - */ - void vpop(jtype jt); - /** - * @brief 'Synchronizes' operand stack and local variables. - * - * If some items in #m_jframe need either spill to or upload from memory, - * then perform appropriate action. - */ - void vsync(void); - /** - * @brief Returns a register which keeps an item of operand stack at the - * specified depth. - * - * If the item is spilled to the memory, then generates code to upload. - * - * @see JFrame::regable() - */ - RegName vstack(unsigned depth); - - /** - * @brief Returns an 'alias' register. - * - * The 'alias' register is the same as specified register, but with - * size specified by \c jt. - * - * For example, - * - valias(dbl64, RegName_XMM0) is RegName_XMM0D - * - valias(flt32, RegName_XMM0) is RegName_XMM0S - * - valias(i8, RegName_EAX) is RegName_AL - * - valias(i32, RegName_AL) is RegName_EAX - * - * @note A special processing is performed for ESI, EDI and EBP: as they - * do not have 8bit variant, then a scratch register (EAX or EDX) - * allocated, and its 8bit version returned. As a side-effect, - * valias() call may generate code to free the scratch register. - */ - RegName valias(jtype jt, RegName r); - - /** - * @brief Generates specified instruction, with args specified. - */ - void voper(Mnemonic mn, const EncoderBase::Operands& args) - { - ip(EncoderBase::encode(ip(), mn, args)); - } - /** - * @brief Generates specified instruction, which has no args. - */ - void voper(Mnemonic mn) - { - EncoderBase::Operands args; - ip(EncoderBase::encode(ip(), mn, args)); - } - /** - * @brief Generates specified instruction, which has a single operand. - */ - void voper(Mnemonic mn, const EncoderBase::Operand& a0) - { - EncoderBase::Operands args(a0); - ip(EncoderBase::encode(ip(), mn, args)); - } - /** - * @brief Generates specified instruction, which has two operands. - */ - void voper(Mnemonic mn, const EncoderBase::Operand& a0, - const EncoderBase::Operand& a1) - { - EncoderBase::Operands args(a0, a1); - ip(EncoderBase::encode(ip(), mn, args)); - } - - /** - * @brief Generates CALL rel32 instruction, and registers patch for it. - */ - void vcall(const void * addr) - { - reg_patch(addr); - voper(Mnemonic_CALL, EncoderBase::Operand((int)0)); - } - /** - * @brief Generates JMP rel32 instruction, which has its target the - * specified PC and registers patch for it. - */ - void vjmp(unsigned pc) - { - reg_patch(pc); - voper(Mnemonic_JMP, (int)0); - } - /** - * @brief Generates short JMP rel8, and registers patch for it. - * @return patch id - */ - unsigned vjmp8(void) - { - unsigned pid = reg_patch(); - voper(Mnemonic_JMP, EncoderBase::Operand(OpndSize_8, 0)); - return pid; - } - /** - * @brief Inserts specified prefix. - * - * If prefix is InstPrefix_Null, no action is taken. - */ - void vprefix(InstPrefix prefix) { - if (InstPrefix_Null != prefix) { - ip(EncoderBase::prefix(ip(), prefix)); - } - } - /** - * @brief Generates conditional Jcc rel32 instruction, and registers - * patch for it. - * - * If prefix is InstPrefix_Null, no prefix inserted. - * - * @return patch id - */ - unsigned vjcc(ConditionMnemonic cond, - InstPrefix prefix = InstPrefix_Null) - { - vprefix(prefix); - unsigned pid = reg_patch(); - voper((Mnemonic)(Mnemonic_Jcc+cond), EncoderBase::Operand((int)0)); - return pid; - } - - /** - * @brief Generates conditional Jcc rel32 instruction, and registers - * patch for it, so its target is specified PC. - * - * If prefix is InstPrefix_Null, no prefix inserted. - * - * @return patch id - */ - void vjcc(unsigned target_pc, ConditionMnemonic cond, - InstPrefix prefix = InstPrefix_Null) - { - vprefix(prefix); - reg_patch(target_pc); - voper((Mnemonic)(Mnemonic_Jcc+cond), EncoderBase::Operand((int)0)); - } - - /** - * @brief Generates specified instruction to be performed for 2 operand - * stack items. - * - * If an item at depth1 is currently spilled to memory, does not reload - * it to register, but generates 'mn reg(depth0), mem(depth1)' - * instruction. This is to save one load to register. - */ - void vdostack(Mnemonic mn, unsigned depth0, int depth1); - - /** - * @brief Tests whether the given operand stack item is in memory. - */ - bool vstack_swapped(unsigned depth) - { - return m_jframe->dip(depth).swapped(); - } - /** - * @brief Tests whether the given local variable is in memory. - */ - bool vlocal_on_mem(unsigned idx); - /** - * @brief Forces (generates code for) an operand stack's item to be - * spilled to memory. - */ - void vstack_swap(unsigned depth); - /** - * @brief Returns Encoder's memory operand which points to an operand - * stack item in the memory (with the real size of the item). - * - * @see \link StackFrame Stack layout\endlink - */ - EncoderBase::Operand vmstack(unsigned depth); - /** - * @brief Returns Encoder's memory operand which points to an operand - * stack item in the memory as a pointer to 32bit slot. - * - * @see \link StackFrame Stack layout\endlink - */ - EncoderBase::Operand vstack_mem_slot(unsigned depth); - /** - * @brief Returns Encoder's operand which represents local variable. - * - * @see JFrame::alloc(). - */ - EncoderBase::Operand vlocal(jtype jt, int idx, bool upper, - bool willDef); + static void initStatics(void); /** - * @brief Returns Encoder's memory operand which points to a local - * variable's memory slot, with the size determined by the \c jt. + * @brief Initializes profiling data. * - * @see \link StackFrame Stack layout\endlink + * Adds appropriate JMF_ flags to \c pflags if necessary. + * @param[out] pflags - flags which will be used for compilation. Must + * be non-NULL. */ - EncoderBase::Operand vmlocal(jtype jt, unsigned idx); -#endif // if !defined(_IPF_) + void initProfilingData(unsigned * pflags); }; diff --git vm/jitrino/src/jet/csig.cpp vm/jitrino/src/jet/csig.cpp new file mode 100644 index 0000000..3064bce --- /dev/null +++ vm/jitrino/src/jet/csig.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Implementation of CallSig routines. + */ + +#include "csig.h" + + +namespace Jitrino { +namespace Jet { + +const CallSig cs_v(CCONV_STDCALL); + +void CallSig::init(void) +{ + // can't have stack alignment in calling convention when callee pops + // so if any of ALIGN set, then CALLER_POPS must also be set. + assert( !(m_cc&(CCONV_STACK_ALIGN16|CCONV_STACK_ALIGN_HALF16)) || + (m_cc&CCONV_CALLER_POPS)); + + unsigned num = m_args.size(); + m_data.resize(num); + unsigned fps = 0, gps = 0; + + // + // Assign registers + // + bool regs = !(m_cc & CCONV_MEM); + + // Note: Registers are always assigned in left-to-right order, + // regardless of L2R setting in calling convention. This is how all our + // conventions behave - might want to document it somewhere - TODO. + + for (unsigned i=0; i<num; i++) { + jtype jt = m_args[i]; + if (regs && is_f(jt) && get_cconv_fr(fps) != fr_x) { + m_data[i] = get_cconv_fr(fps); + ++fps; + } + else if (regs && !is_f(jt) && get_cconv_gr(gps) != gr_x) { + m_data[i] = get_cconv_gr(gps); + ++gps; + } + else { + // mark the items that need to be assigned to memory + m_data[i] = -1; + } + } + + bool l2r = m_cc & CCONV_L2R; + int start, end, step; + if (l2r) { + start = num-1; + end = -1; + step = -1; + } + else { + start = 0; + end = num; + step = 1; + } + int off = 0; + m_stack = 0; + + for (int i=start; i != end; i+=step) { + jtype jt = m_args[i]; + if (m_data[i]<0) { + m_data[i] = off; + off -= STACK_SIZE(jtypes[jt].size); + } + } + m_stack = -off; + // Do alignment + if (m_stack != 0 && + (m_cc & (CCONV_STACK_ALIGN16|CCONV_STACK_ALIGN_HALF16))) { + m_stack = (m_stack+15) & 0xFFFFFFF0; + } +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/csig.h vm/jitrino/src/jet/csig.h new file mode 100644 index 0000000..3692389 --- /dev/null +++ vm/jitrino/src/jet/csig.h @@ -0,0 +1,383 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief CallSig class and related constants declaration. + */ + +#if !defined(__CSIG_H_INCLUDED__) +#define __CSIG_H_INCLUDED__ + +#include "enc.h" +#include <vector> +using std::vector; + +namespace Jitrino { +namespace Jet { + +/** + * @defgroup JET_CCONV Calling conventions description. + * @{ + */ + + +/** + * @brief Order of parameters is left-to-right. + */ +#define CCONV_L2R (0x00000001) + +/** + * @brief Caller must restore stack (pop out arguments). + */ +#define CCONV_CALLER_POPS (0x00000002) + +/** + * @brief All args go though memory. + */ +#define CCONV_MEM (0x00000004) + +/** + * @brief When entering a function, obey the (sp+8)%%16 == 0 rule (Intel 64 + * convention). + */ +#define CCONV_STACK_ALIGN_HALF16 (0x00000008) + +/** + * @brief When entering a function, obey the (sp)%%16 == 0 rule. + */ +#define CCONV_STACK_ALIGN16 (0x00000010) + +/** + * @brief IA-32's stdcall convention. + */ +#define CCONV_STDCALL_IA32 (CCONV_MEM) + +/** + * @brief IA-32's cdecl convention. + */ +#define CCONV_CDECL_IA32 (CCONV_CALLER_POPS|CCONV_MEM) + +#ifdef _EM64T_ + /** + * @brief EM64T calling convention. + */ + #define CCONV_EM64T (CCONV_STACK_ALIGN_HALF16 | CCONV_CALLER_POPS) + /** + * @brief On IA-32 it's CCONV_CDECL_IA32, on EM64T it's CCONV_EM64T. + */ + #define CCONV_STDCALL CCONV_EM64T + /** + * @brief On IA-32 it's CCONV_CDECL_IA32, on EM64T it's CCONV_EM64T. + */ + #define CCONV_CDECL CCONV_EM64T +#else + #define CCONV_STDCALL CCONV_STDCALL_IA32 + #define CCONV_CDECL CCONV_CDECL_IA32 +#endif + +/** + * @brief IA-32's DRLVM's convention for managed code. + */ +#define CCONV_MANAGED_IA32 (CCONV_L2R | CCONV_MEM) +/** + * @brief A special case - VM's helper MULTIANEWARRAY always has cdecl-like + * convention. + */ +#define CCONV_MULTIANEWARRAY CCONV_CDECL_IA32 + +#ifdef _EM64T_ + /** + * @brief On IA-32 it's CCONV_MANAGED_IA32, on EM64T it's CCONV_EM64T. + */ + #define CCONV_MANAGED CCONV_EM64T + /** + * @brief On IA-32 it's CCONV_MANAGED_IA32, on EM64T it's CCONV_EM64T. + */ + #define CCONV_HELPERS CCONV_EM64T +#else + #define CCONV_MANAGED CCONV_MANAGED_IA32 + #define CCONV_HELPERS CCONV_MANAGED_IA32 //CCONV_STDCALL +#endif + +///@} // ~JET_CCONV + + +/** + * @brief Describes method's signature - number of arguments, their types, + * calling convention, etc. + * + * A CallSig object which describes a function with stdcall calling + * convention which has 2 argument - an integer and float: + * + * @code + * CallSig ssig(CCONV_STDCALL, i32, flt32) + * @endcode + * + * Arguments are always numbered and referred to in left-to-right order: + * @code + * foo(arg 0, arg 1, arg 2) + CallSig csig(cc, arg0 type, arg1 type, arg2 type); + csig.get(2) refers to arg 2. + * @endcode + * + * An offsets of arguments are calculated relative to #sp with a presumption + * that stack frame for argument passing is prepared fist. I.e. the expected + * call preparation sequence would be + * @code + * CallSig csig(); + * sub sp, csig.size() + * for i=0; i<csig.count(); i++ + * mov [sp+csig.off(i)], arg#i + * @endcode + * + * Until #CCONV_L2R specified, the offsets are calculated as if the arguments + * were 'push-ed' to the stack from right-to-left. + * + * In other words, by default the 0th argument is on the top of the stack. + * + * With #CCONV_L2R, the least argument is on the top of the stack. + * + * The current implementation implies the presumption that a set of + * calle-save registers is the same across all calling conventions. + */ +class CallSig { +public: + /** + * @brief No-op. + * + * @note This ctor leaves CallSig object in unpredictable state. + * The #init() method \b must be called before any usage. + */ + CallSig(void) + { + m_cc = (unsigned)~0; + } + + /** + * @brief Initializes CallSig object with the given arg types. + */ + CallSig(unsigned cc, + jtype arg0=jvoid, jtype arg1=jvoid, jtype arg2=jvoid, + jtype arg3=jvoid, jtype arg4=jvoid, jtype arg5=jvoid) + { + m_cc = cc; + if (arg0 != jvoid) { m_args.push_back(arg0); } + if (arg1 != jvoid) { m_args.push_back(arg1); } + if (arg2 != jvoid) { m_args.push_back(arg2); } + if (arg3 != jvoid) { m_args.push_back(arg3); } + if (arg4 != jvoid) { m_args.push_back(arg4); } + if (arg5 != jvoid) { m_args.push_back(arg5); } + // No jvoid type argument can be presented. + assert(find(m_args.begin(), m_args.end(), jvoid) == m_args.end()); + init(); + } + +#if 0 + /** + * Seems there is no need in such ctor. All the existing usage + * cases are covered by CallSig(cc, jtype*N = jvoid) + */ + CallSig(unsigned cc, unsigned num, ...) + { + va_list valist; + va_start(valist, num); + m_args.resize(num); + assert(sizeof(jtype)==sizeof(int)); + for (unsigned i=0; i<num; i++) { + jtype jt = (jtype)va_arg(valist, int); + assert(i8<=jt && jt<num_jtypes); + m_args[i] = jt; + } + m_cc = cc; + init(); + } +#endif + /** + * @brief Constructs and initializes CallSig object with the given + * calling convention and list of args types. + */ + CallSig(unsigned cc, const vector<jtype>& args) + { + init(cc, args); + } + + /** + * @brief Initializes CallSig object with the given calling convention + * and list of args types. + */ + void init(unsigned cc, const vector<jtype>& args) + { + m_args = args; + m_cc = cc; + init(); + } + + /** + * @brief Returns used calling convention. + */ + unsigned cc(void) const + { + return m_cc; + } + + /** + * @brief Returns true if caller must restore the stack. + * @see CCONV_CALLER_POPS + * @see CCONV_CDECL + */ + bool caller_pops(void) const + { + return (m_cc & CCONV_CALLER_POPS); + } + + /** + * @brief Returns size (in bytes) of the stack size needed to pass args + * that go through the stack. + */ + unsigned size(void) const + { + return m_stack; + } + + /** + * @brief Returns number of arguments. + */ + unsigned count(void) const + { + assert(m_data.size() == m_args.size()); + return m_args.size(); + } + + /** + * @brief Returns appropriate AR to pass the given argument, or ar_x + * if the argument comes through the stack. + */ + AR reg(unsigned i) const + { + assert(i<count()); + return m_data[i]<=0 ? ar_x : (AR)m_data[i]; + } + + /** + * @returns Offset (in bytes) from #sp of the given argument, or -1 if + * the argument is passed on register. + */ + int off(unsigned i) const + { + assert(i<count()); + return m_data[i]<=0 ? -m_data[i] : -1; + } + + /** + * @returns An Opnd to refer the given method's argument. + * + * If the argument is passed through the stack, then memory operand + * with base()==sp and appropriate displacement returned. + * + * If the \c offset parameter is not 0, then it's added to the argument's + * displacement. + * + * If the argument is passed through a register, then register operand + * returned, and \c offset parameter is ignored. + * + * The returned Opnd object has proper type. For \link #is_big big type + * \endlink the \link #jtmov appropriate supported type \endlink + * returned. + */ + Opnd get(unsigned i, int offset = 0) const + { + AR ar = reg(i); + jtype jtm = jtmov(jt(i)); + if (ar != ar_x) { + return Opnd(jtm, ar); + } + return Opnd(jtm, sp, off(i) + offset); + } + + /** + * @brief Returns type of the argument. + */ + jtype jt(unsigned i) const + { + assert(i<count()); + return m_args[i]; + } + /** + * @brief Tests whether given AR is used to pass an argument for the + * this CallSig. + */ + bool uses(AR ar) const + { + if (ar != ar_x) { + for (unsigned i=0; i<count(); i++) { + if (reg(i) == ar) { + return true; + } + } + } + return false; + } +private: + /** + * @brief Initializes CallSig object. + * + * Counts args offsets and required stack size. + */ + void init(void); + /** + * @brief An info about argument types. + */ + ::std::vector<jtype> m_args; + /** + * @brief An info about argument offsets (m_data[i]<0) or registers + * (m_data[i]>0 => (AR)m_data[i]). + * + * Though offsets are stored as negative values, they are positive + * offsets to #sp. The sign here is used as additional flag whether the + * value must be interpreted as offset (sig<=0) or as a register + * (sign>0). + * + * This implies presumption that a valid AR is alwys > 0. + */ + ::std::vector<int> m_data; + /** + * @brief Size (in bytes) of stack frame needed to pass arguments. + * + * ... with all the alignment properties taken into account. + */ + unsigned m_stack; + /** + * @brief \link JET_CCONV calling convention \endlink for this + * CallSig object. + */ + unsigned m_cc; +}; + +/** + * @brief CallSig for stdcall function that takes no args. + */ +extern const CallSig cs_v; + + +}}; // ~namespace Jitrino::Jet + +#endif // ~__CSIG_H_INCLUDED__ + diff --git vm/jitrino/src/jet/enc.cpp vm/jitrino/src/jet/enc.cpp new file mode 100644 index 0000000..ed21c92 --- /dev/null +++ vm/jitrino/src/jet/enc.cpp @@ -0,0 +1,613 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Platform-independent stuff of Encoder class. + */ +#include "enc.h" +#include <stdio.h> +#include "trace.h" + +#ifdef PLATFORM_POSIX +#include <signal.h> +#else + +#endif + +#include "compiler.h" + +namespace Jitrino { +namespace Jet { + +bitset<ar_num> Encoder::isCalleeSave; + +void Encoder::init(void) +{ + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + isCalleeSave.set(i, is_callee_save_impl(ar)); + } +} + + +void Encoder::debug(void) +{ +#ifdef PLATFORM_POSIX + raise(SIGTRAP); +#else + __asm { + int 3 + } +#endif +} + +unsigned gen_num_calle_save(void) +{ + static int num = -1; + if (num == -1) { + num = 0; + for (int i=0; i<ar_num; i++) { + AR ar = (AR)(gr0+i); + if (is_callee_save(ar)) { + ++num; + } + } + } + return num; +} + +void Encoder::lea(const Opnd& reg, const Opnd& mem) +{ + assert(reg.is_reg()); + assert(mem.is_mem()); + if (is_trace_on()) { + trace("lea", to_str(reg), to_str(mem)); + } + lea_impl(reg, mem); +} + + +unsigned Encoder::movp(AR op0, unsigned udata, unsigned ubase) +{ + assert(op0 != ar_x); + if (is_trace_on()) { + trace("movp.patch", to_str(op0), to_str(udata)); + } + unsigned pid = reg_patch(true, udata, ubase); + movp_impl(op0, NULL); + reg_patch_end(pid); + return pid; +} + +void Encoder::sx1(const Opnd& op0, const Opnd& op1) +{ + assert(op0 != ar_x && op1 != ar_x); + if (is_trace_on()) { + trace("sx1", to_str(op0), to_str(op1)); + } + sx1_impl(op0, op1); +} + +void Encoder::sx2(const Opnd& op0, const Opnd& op1) +{ + assert(op0 != ar_x && op1 != ar_x); + if (is_trace_on()) { + trace("sx2", to_str(op0), to_str(op1)); + } + sx2_impl(op0, op1); +} + +void Encoder::sx(const Opnd& op0, const Opnd& op1) +{ + assert(op0 != ar_x && op1 != ar_x); + if (is_trace_on()) { + trace("sx", to_str(op0), to_str(op1)); + } + sx_impl(op0, op1); +} + + +void Encoder::zx2(const Opnd& op0, const Opnd& op1) +{ + assert(op0 != ar_x && op1 != ar_x); + if (is_trace_on()) { + trace("zx2", to_str(op0), to_str(op1)); + } + zx2_impl(op0, op1); +} + +void Encoder::fld(jtype jt, AR op0, AR base, int disp, AR index, unsigned scale) +{ + assert(op0 != ar_x); + assert(is_f(jt)); + if (is_trace_on()) { + trace("fld", to_str(op0), to_str(base, disp, index, scale)); + } + fld_impl(jt, op0, base, disp, index, scale); +} + +void Encoder::fst(jtype jt, AR op0, AR base, int disp, AR index, unsigned scale) +{ + assert(op0 != ar_x); + assert(is_f(jt)); + if (is_trace_on()) { + trace("fst", to_str(base, disp, index, scale), to_str(op0)); + } + fst_impl(jt, op0, base, disp, index, scale); +} + + +void Encoder::trap(void) +{ + if (is_trace_on()) { + trace("trap", "", ""); + } + trap_impl(); +} + +void Encoder::trace(const string& func, const string& op0, const string& op1) +{ + if (!m_trace) { + return; + } + dbg("\t; %s%s", m_prefix.c_str(), func.c_str()); + if (!op0.empty()) { + dbg(" %s", op0.c_str()); + if (!op1.empty()) { + dbg(", %s", op1.c_str()); + } + } + else { + assert(op1.empty()); + } + dbg("\n"); +} + +string Encoder::to_str(AR ar, bool platf) +{ + if (ar == ar_x) { + return ""; + } + if (ar == bp) { + return "bp"; + } + if (ar == sp) { + return "sp"; + } +#ifdef _IA32_ + if (ar == fr_ret) { + return "fr_ret"; + } +#endif + if (platf) { + return to_str_impl(ar); + } + char buf[20]; + snprintf(buf, sizeof(buf)-1, "%s%d", + is_f(ar) ? (is_callee_save(ar) ? "FR" : "fr") : + (is_callee_save(ar) ? "GR" : "gr"), + type_idx(ar)); + return string(buf); +} + +string Encoder::to_str(const Opnd& op) +{ + if (op.is_reg()) return to_str(op.reg()); + if (op.is_mem()) return to_str(op.base(), op.disp(), op.index(), op.scale()); + assert(op.is_imm()); + return to_str(op.ival()); +} + +string Encoder::to_str(jtype jt) +{ + return jt == jvoid ? "" : jtypes[jt].name; +} + +string Encoder::to_str(AR base, int disp, AR index, unsigned scale) +{ + if (base == (AR)NOTHING) { + base = ar_x; + } + assert(base == gr_x || is_gr(base)); + assert(index == gr_x || is_gr(index)); + + char buf[100] = "["; + if (base != gr_x) { + strcat(buf, to_str(base).c_str()); + } + if (index != gr_x) { + if (base != gr_x) { + strcat(buf, "+"); + } + strcat(buf, to_str(index).c_str()); + strcat(buf, "*"); + char tmp[20]; + snprintf(tmp, sizeof(tmp)-1, "%d", scale); + strcat(buf, tmp); + } + if (disp != 0) { + char tmp[20]; + if (base == ar_x && index==ar_x) { + snprintf(tmp, sizeof(tmp)-1, "0x%X", disp); + } + else { + bool _plus = (index != gr_x || base != gr_x) && disp>0; + if (_plus) { + strcat(buf, "+"); + } + if (abs(disp)<256*1024) { + snprintf(tmp, sizeof(tmp)-1, "%d", disp); + } + else { + if (_plus) { + snprintf(tmp, sizeof(tmp)-1, "0x%X", disp); + } + else { + snprintf(tmp, sizeof(tmp)-1, "+0x%X", disp); + } + } + } + strcat(buf, tmp); + } + strcat(buf, "]"); + return buf; +} + +string Encoder::to_str(const void * addr) +{ + char buf[50]; + snprintf(buf, sizeof(buf)-1, "%p", addr); + return buf; +} + +string Encoder::to_str(int i) +{ + char buf[50]; + snprintf(buf, sizeof(buf)-1, "0x%X/%d", i, i); + return buf; +} + +string Encoder::to_str(ALU op) +{ + if (op==alu_add) return "add"; + if (op==alu_sub) return "sub"; + if (op==alu_mul) return "mul"; + if (op==alu_div) return "div"; + if (op==alu_rem) return "rem"; + if (op==alu_or) return "or"; + if (op==alu_xor) return "xor"; + if (op==alu_and) return "and"; + if (op==alu_cmp) return "cmp"; + if (op==alu_test) return "test"; + if (op==alu_shl) return "shl"; + if (op==alu_shr) return "shr"; + if (op==alu_sar) return "sar"; + assert(false); + return "???"; +} + +string Encoder::to_str(COND cond) +{ + if (cond==cond_none) return ""; + if (cond==ge) return ":ge"; + if (cond==le) return ":le"; + if (cond==gt) return ":gt"; + if (cond==lt) return ":lt"; + if (cond==eq) return ":eq"; + if (cond==ne) return ":ne"; + if (cond==above) return ":above"; + assert(false); + return "???"; +} + +string Encoder::to_str(HINT hint) +{ + if (hint==hint_none) return ""; + if (hint==taken) return "[hint:taken]"; + if (hint==not_taken) return "[hint:not taken]"; + assert(false); + return "???"; +} + +void Encoder::call(bool check_stack, AR gr, const void * target, + const CallSig& cs, unsigned idx, ...) +{ +//TODO: Add IA-64 check +#ifdef _EM64T_ + if (check_stack) { + alu(alu_test, sp, 0x0F); + unsigned br_off = br(z, 0, 0, hint_none); + trap(); + patch(br_off, ip(br_off), ip()); + } +#endif + va_list valist; + va_start(valist, idx); + call_va(check_stack, gr, target, cs, idx, valist); +} + +void Encoder::call_va(bool check_stack, AR ar, const void *target, + const CallSig& cs, unsigned idx, va_list& valist) +{ + if (is_trace_on()) { + trace("[+]call:", to_str(ar), to_str(target)); + m_prefix = " |"; + } + if (idx == 0 && cs.size()) { + alu(alu_sub, sp, cs.size()); + } + + for (unsigned i=idx; i<cs.count(); i++) { + jtype jt = cs.jt(i); + assert(!is_f(jt)); // not implemented + AR gr = cs.reg(i); ; + if (jt == jobj) { + void * addr = va_arg(valist, void*); + if (gr != ar_x) { + movp(gr, addr); + } + else if (is_ia32()) { + int val = (int)(int_ptr)addr; + mov(Opnd(i32, sp, cs.off(i)), val); + } + else { + int val = lo32((long)addr); + mov(Opnd(i32, sp, cs.off(i)), val); + val = hi32((long)addr); + mov(Opnd(i32, sp, cs.off(i)+4), val); + } + } + else if (jt==i64) { + assert(false); + } + else { + int val = va_arg(valist, int); + mov(gr == gr_x ? Opnd(i32, sp, cs.off(i)) : Opnd(i32, gr), val); + } + } + movp(ar, target); + call(Opnd(jobj, ar), cs, check_stack); + if (is_trace_on()) { + m_prefix.clear(); + trace("[^]call:", to_str(ar), to_str(target)); + } +} + +void Encoder::gen_args(const CallSig& cs, AR grtmp, unsigned idx, + unsigned count, ...) +{ + if (idx == 0 && cs.size() != 0) { + alu(alu_sub, sp, cs.size()); + } + + va_list valist; + va_start(valist, count); + + for (int i=idx; i!=(int)(idx+count); i++) { + jtype jt = cs.jt(i); + assert(!is_f(jt)); // not implemented + AR gr = cs.reg(i); ; + if (gr == gr_x) { + assert(grtmp != gr_x); // NYI + gr = grtmp; + } + else { + //assert(gr_idx(cs.reg(i)) != gr_idx(gr_call)); + } + if (jt == jobj) { + void * addr = va_arg(valist, void*); + movp(gr, addr); + } + else if (jt==i64) { + //jlong jl = va_arg(valist, jlong); + //Opnd op() + //movl(gr, jl); + assert(false); // not expected - there were no usage. + } + else { + int i = va_arg(valist, int); + mov(gr, i); + } + if (cs.reg(i) == gr_x) { + st(jt, gr, sp, cs.off(i)); + } + } +} + +int Encoder::push(const Opnd& op0) +{ + if (is_trace_on()) { + trace("push", to_str(op0), ""); + } + return push_impl(op0); +} + +int Encoder::pop(const Opnd& op0) +{ + if (is_trace_on()) { + trace("pop", to_str(op0), ""); + } + return pop_impl(op0); +} + +int Encoder::push_all(bool includeCalleeSave) +{ + if (is_trace_on()) { + trace("[+]push_all", "", ""); + m_prefix = " |"; + } + int size = get_all_regs_size(); + size = (size+15) & (~0xF); + alu(alu_sub, sp, size); + for (unsigned i=0; i<gr_num; i++) { + AR gr = _gr(i); + if (is_callee_save(gr) && !includeCalleeSave) continue; + Opnd reg(jobj, gr); + Opnd mem(jobj, sp, i*STACK_SLOT_SIZE); + mov(mem, reg); + } + for (unsigned i=0; i<fr_num; i++) { + AR fr = _fr(i); + if (is_callee_save(fr) && !includeCalleeSave) continue; + Opnd reg(dbl64, fr); + Opnd mem(dbl64, sp, gr_num*STACK_SLOT_SIZE+i*8); + mov(mem, reg); + } + if (is_trace_on()) { + m_prefix.clear(); + trace("[^]push_all", "", ""); + } + return -size; +} + +int Encoder::pop_all(bool includeCalleeSave) +{ + if (is_trace_on()) { + trace("[+]pop_all", "", ""); + m_prefix = " |"; + } + int size = get_all_regs_size(); + size = (size+15) & (~0xF); + for (unsigned i=0; i<gr_num; i++) { + AR gr = _gr(i); + if (is_callee_save(gr) && !includeCalleeSave) continue; + Opnd reg(jobj, gr); + Opnd mem(jobj, sp, i*STACK_SLOT_SIZE); + mov(reg, mem); + } + for (unsigned i=0; i<fr_num; i++) { + AR fr = _fr(i); + if (is_callee_save(fr) && !includeCalleeSave) continue; + Opnd reg(dbl64, fr); + Opnd mem(dbl64, sp, gr_num*STACK_SLOT_SIZE+i*8); + mov(reg, mem); + } + alu(alu_add, sp, size); + if (is_trace_on()) { + m_prefix.clear(); + trace("[^]pop_all", "", ""); + } + return size; +} + + +void Encoder::call(const Opnd& target, const CallSig& ci, bool check_stack) +{ + assert(!target.is_reg() || !is_f(target.reg())); + if (is_trace_on()) { + trace("call", to_str(target), ""); + } + if (check_stack && + (ci.cc() & (CCONV_STACK_ALIGN_HALF16|CCONV_STACK_ALIGN16))) { + if (ci.cc() & CCONV_STACK_ALIGN16) { + alu(alu_sub, sp, 8); + } + alu(alu_test, sp, 0x0F); + unsigned br_off = br(z, 0, 0, taken); + trap(); + if (ci.cc() & CCONV_STACK_ALIGN16) { + alu(alu_add, sp, 8); + } + patch(br_off, ip()); + } + call_impl(target); + if (ci.caller_pops() && ci.size() != 0) { + alu(alu_add, sp, ci.size()); + } +} + +void Encoder::ret(unsigned pop) +{ + if (is_trace_on()) { + trace("ret", to_str(pop), ""); + } + ret_impl(pop); +} + +unsigned Encoder::reg_patch(bool data, unsigned udata, unsigned ubase) +{ + CodePatchItem cpi; + cpi.data = data; + cpi.len = (unsigned)-1; + cpi.done = false; + cpi.udata = udata; + cpi.ubase = ubase; + unsigned pid = ipoff(); + assert(m_patches.count(pid) == 0); + m_patches[pid] = cpi; + return pid; +} + +void Encoder::reg_patch_end(unsigned pid) +{ + assert(m_patches.count(pid) != 0); + CodePatchItem& cpi = m_patches[pid]; + assert(cpi.len == (unsigned)-1); + cpi.len = m_codeStream.ipoff() - pid; // pid is ipoff + assert(cpi.len != 0); +} + +unsigned Encoder::br(COND cond, unsigned udata, unsigned base, HINT hint) +{ + if (is_trace_on()) { + trace(to_str(hint) + "br"+to_str(cond), to_str(udata), to_str(base)); + } + unsigned pid = reg_patch(false, udata, base); + br_impl(cond, hint); + reg_patch_end(pid); + return pid; +} + +void Encoder::br(const Opnd& op, COND cond, HINT hint) +{ + if (is_trace_on()) { + trace(to_str(hint)+"br"+to_str(cond), to_str(op), ""); + } + br_impl(op, cond, hint); +} + +void Encoder::patch(unsigned pid, void * inst_addr, void * target_addr) +{ + assert(m_patches.count(pid) != 0); + CodePatchItem& cpi = m_patches[pid]; + if (cpi.done) { + return; + } + if (cpi.data) { + assert(cpi.len>sizeof(void*)); // We're writing address there + // Address is normally placed at the end of instruction + char* addr_addr = (char*)inst_addr+cpi.len-sizeof(void*); + *(void**)addr_addr = target_addr; + } + else { + // only long JMPs currently, short JMPs to be done + assert(cpi.len>4); + int offset = (int)((char*)target_addr-((char*)inst_addr+cpi.len)); + // Offset is normally placed at the end of instruction + char* offset_addr = (char*)inst_addr+cpi.len-4; + *(int*)offset_addr = offset; + } + cpi.done = true; +} + + +} +}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/enc.h vm/jitrino/src/jet/enc.h new file mode 100644 index 0000000..a3e85cd --- /dev/null +++ vm/jitrino/src/jet/enc.h @@ -0,0 +1,1475 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Encoder class and related definitions. + */ + +#if !defined(__ENC_H_INCLUDED__) +#define __ENC_H_INCLUDED__ + +#include "jdefs.h" +#include <assert.h> +#include <stdarg.h> + +#include <bitset> +#include <string> +#include <map> +#include <algorithm> + +using std::string; +using std::bitset; +using std::map; +using std::max; + +/** + * @brief Size of stack slot affected by a regular PUSH/POP instruction. + * + * Normally equals to the size of general-purpose register of the platform. + */ +#define STACK_SLOT_SIZE (sizeof(void*)) + +/** + * @brief Rounds given \c bytes to the integer number of stack slots. + */ +#define STACK_SIZE(bytes) \ + ((bytes + (STACK_SLOT_SIZE-1)) & ~(STACK_SLOT_SIZE-1)) + +namespace Jitrino { +namespace Jet { + +class CallSig; +class Encoder; +/** + * @brief A signed interger type, with the same size as a pointer. + */ +typedef long int_ptr; + +/** + * @brief A dynamically grown byte array. + * + * Class CodeStream represents a dynamically growing byte array, which + * always provides buffer of at least minimal guaranteed size (which is + * #BUFFER_ZONE). + * + * The usage is as follows: + * @code + * CodeStream cs; + * cs.init(INITIALLY_EXPECTED_CODE_SIZE); + * unsigned p_start = cs.ipoff(); + * char * p = cs.ip(); + * memcpy(p, otherP, someSize_less_than_BUFFER_ZONE); + * cs.ip(p + someSize_less_than_BUFFER_ZONE); + * ... + * unsigned next_p = cs.ipoff(); + * @endcode + */ +class CodeStream { +public: + CodeStream() { m_buf = NULL; m_size = 0; } + ~CodeStream() { if (m_buf) { free(m_buf); } }; + + /** + * @brief Performs initial memory allocation. + * + * The memory size allocated is 'bytes' and then grow when necessary. + */ + void init(unsigned bytes) + { + resize(bytes); + } + + + /** + * @brief Returns address of a next available for writing byte. + * + * The address returned is guaranteed to contain at least #BUFFER_ZONE + * bytes. + * The returned address is valid only until the next call to #ip(void) + * where a memory reallocation can be triggered, and thus should not be stored between + * such calls. Use ipoff() instead which is consistent during the lifetime of + * CodeStream object. + */ + char * ip(void) + { + return m_buf + m_size; + } + + char * ip(unsigned ipoff) + { + return data() + ipoff; + } + + /** + * Sets current address. This must be an address of a next available byte. + */ + void ip(char * _ip) + { + m_size = _ip - m_buf; + assert(m_size < total_size); + // Need to be done here, and not in ip(void). + // Otherwise, the following usage template: + // patch(pid, m_codeStream.data() + br_ipoff, ip()) + // may fail, if ip(void) triggers reallocation + if ((total_size - m_size) < BUFFER_ZONE) { + resize(total_size + + max((unsigned)BUFFER_ZONE, total_size*GROW_RATE/100)); + } + } + + /** + * Returns an offset the next available byte in the stream. + */ + unsigned ipoff(void) const + { + return m_size; + } + + /** + * Returns the size used in the stream. + */ + unsigned size(void) const + { + return m_size; + } + + /** + * Provides a direct access to internal buffer. Never use more than + * size() bytes. + */ + char * data(void) const + { + return m_buf; + } + + /** + * The minimum guaranteed size of the buffer returned by ip(). + * This is also a minimal size of the buffer which triggers + * reallocation of a bigger memory buf. '16' here is max size of the + * native instruction (at least on IA32/EM64T). 3 was chosen empirically. + */ + enum { BUFFER_ZONE = 16*3 }; +private: + /** + * Perform the [re-]allocation of a memory. + * The previously filled memory (if any) is copied into the newly allocated buffer. + */ + void resize(unsigned how_much) + { + total_size = max(how_much, (unsigned)BUFFER_ZONE); + m_buf = (char*)realloc(m_buf, total_size); + } + + /** + * A pointer to the allocated buffer. + */ + char * m_buf; + + /** + * A size of the buffer allocated. + */ + unsigned total_size; + + /** + * A size of memory currently in use. + */ + unsigned m_size; + + /** + * A rate how to increase the already allocated buffer, in percent. + * The default value 25 means that the buffer will grow by 25% each allocation: + * i.e. if the first size passed to init() was 32, the allocations will be: + * 32 ; 40 (=32+32*0.25) ; 50 (=40+50*0.25) etc. + */ + static const unsigned GROW_RATE = 25; +}; + +/** + * @brief Tests whether specified #jtype is too big to fit into a single + * register on the current platform. + * + * The only case currently is i64 on IA32. + * + * This is a characteristics of the platform, so it's placed in enc.h. + */ +inline bool is_big(jtype jt) +{ +#if defined(_EM64T_) || defined(_IPF_) + return false; +#else + return jt==i64; +#endif +} + +/** + * @brief Returns a #jtype used to move an item of specified type (or part + * of the item - in case of big type). + * + * The only case currently is that jtmov() returns i32 for jt=i64. + */ +inline jtype jtmov(jtype jt) +{ + return is_big(jt) ? i32 : jt; +} + +/** + * @brief true if current platform is IA32. + * + * Some presumptions are made about IA32 platform: there are no comressed + * references on it (not directly related to Encoder), an address fits into + * 32 bits and fits into displacement of complex address form. + */ +inline bool is_ia32(void) +{ +#if defined(_IA32_) + return true; +#else + return false; +#endif +} + +/** + * @brief Tests whether the specified value fits into 32 bit value. + */ +inline bool fits32(jlong val) +{ + return (INT_MIN <= val) && (val <= INT_MAX); +} + + +/** + * @brief Tests whether the specified address fits into 32 bit value. + * + * Always true on IA32. Not always true on 64 bit platforms. + */ +inline bool fits32(const void* addr) +{ +#ifdef _IA32_ + return true; +#else + return fits32((jlong)(int_ptr)addr); +#endif +} + +/** + * @brief + * + * AR stands for Abstract Register. + * + * Every register may be uniquely identified either by its unique index + * (common index) or by a combination of type and index (which is another - + * type - index). + * + * The common index is unique for each register, and lies in the range of + * (ar_idx(ar_x);ar_num), exclusive. + * + * The type index is unique only within the given group of registers and + * lies in the range of [gr_idx(gr0); gr_idx(gr0+gr_total-1)] for gr + * registers and [fr_idx(fr0); fr_idx(fr0+fr_total-1)], inclusive. + * + * @note On IA-32, fr_ret is treated in a special way - see + * Encoder class description. + * + */ +enum AR { + ar_x, fr_x = ar_x, gr_x = ar_x, + // + // General-purpose registers + // + // EAX, EBX, ECX, EDX, ESI, EDI, + gr0, gr1, gr2, gr3, gr4, gr5, +#ifdef _EM64T_ + // R8, R9, R10, R11, R12, R13, R14, R15 + gr6, gr7, gr8, gr9, gr10, gr11, gr12, gr13, +#endif + bp, sp, + // + // Float-point registers + // + fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, +#ifdef _EM64T_ + fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15, +#endif + // + ar_num, ar_total = ar_num, + // + // Specials + // +#ifdef _EM64T_ + fr_ret = fr0, +#else + fr_ret, +#endif + gr_ret = gr0, + // + // + // +#ifdef _EM64T_ + gr_num=15, // not including sp + gr_total = 16, // including sp + fr_num=16, +#else + gr_num=7, // not including sp + gr_total = 8, // including sp + fr_num=8, +#endif + fr_total=fr_num, +}; + +/** + * @brief Returns true if the register is float-point register. + */ +inline bool is_f(AR ar) +{ + return (fr0 <= ar && ar < (fr0+gr_total)); +} + +/** + * @brief Returns true if the register is float-point register. + */ +inline bool is_fr(AR ar) +{ + return is_f(ar); +} + +/** + * @brief Returns true if the register is general-purpose register. + */ +inline bool is_gr(AR ar) +{ + return (gr0 <= ar && ar < (gr0+gr_total)); +} + +/** + * @brief Constructs AR from with the given index (common index). + */ +inline AR _ar(unsigned idx) +{ + assert(idx<ar_total); + return (AR)(gr0+idx); +} + +/** + * @brief Constructs AR from the given jtype and register index (type index). + */ +inline AR _ar(jtype jt, unsigned idx) +{ + if (is_f(jt)) { + assert(idx<fr_total); + return (AR)(fr0+idx); + } + assert(idx<gr_total); + return (AR)(gr0+idx); +} + +/** + * @brief Contructs 'gr' register with the given type index. + */ +inline AR _gr(unsigned idx) +{ + return _ar(jobj, idx); +} + +/** + * @brief Contructs 'fr' register with the given type index. + */ +inline AR _fr(unsigned idx) +{ + return _ar(dbl64, idx); +} + +/** + * @brief Returns type index of the given 'fr' register. + */ +inline unsigned fr_idx(AR fr) +{ + assert(is_f(fr)); + return fr-fr0; +} + +/** + * @brief Returns type index of the given 'gr' register. + */ +inline unsigned gr_idx(AR gr) +{ + assert(!is_f(gr)); + return gr-gr0; +} + +/** + * @brief Returns common index of the given register. + */ +inline unsigned ar_idx(AR ar) +{ +#ifdef _IA32_ + if (ar == fr_ret) { + // fake usage of fr0 + ar = fr0; + } +#endif + assert(ar-gr0 < ar_total); + return ar-gr0; +} + +/** + * @brief Extracts type index of the given register. + */ +inline unsigned type_idx(AR ar) +{ + return is_f(ar) ? fr_idx(ar) : gr_idx(ar); +} + +/** + * @brief Arithmetic and logical unit's operations supported by Encoder. + */ +enum ALU { + alu_add, alu_sub, alu_mul, alu_div, alu_rem, alu_or, alu_xor, alu_and, + alu_cmp, alu_test, alu_shl, alu_shr, alu_sar, + /// total number of ALU operations + alu_count +}; + +/** + * @brief Condition codes used for Encoder::br(). + * @see Encoder::br + */ +enum COND { + // signed + ge, le, gt, lt, eq, z=eq, ne, nz=ne, + /// unsigned + above, + // + cond_none +}; + +/** + * @brief Condition branches hints. + * @see Encoder::br + */ +enum HINT { + taken, not_taken, hint_none +}; + +/** + * @brief Returns number of callee-save registers. + * + * The presumption used: the set of callee-save registers is constant + * across a platform and does not depend on calling convention used. + */ +unsigned gen_num_calle_save(void); +/** + * @brief Returns i-th float-point register for regiter-based calling + * conventions. + * + * The presumption used: the set of registers is constant across a platform + * and does not depend on calling convention used. + * If we'll have to implement calling conventions with different sets of + * registers (i.e. fastcall6 & fastcall4) then this presumption need to + * be revisited. + */ +AR get_cconv_fr(unsigned i); +/** + * @brief Returns i-th general-purpose register for regiter-based calling + * conventions. + * @see get_cconv_fr + */ +AR get_cconv_gr(unsigned i); + +/** + * @brief Kind of operand. + */ +enum OpndKind { opnd_imm, opnd_mem, opnd_reg }; + +/** + * @brief Represents an operand the Encoder works with. + * + * The Opnd can represent either immediate integer constant, or a register + * operand, or a memory operand with compex address form [base+index*scale+ + * displacement]. + * + * Once created, instances of Opnd class are immutable. E.g. to change the + * type of an Opnd instance, one has to create new Opnd with either + * as_type() call, or with Opnd(jtype, const Opnd&). + * + */ +class Opnd { +public: + /** + * @brief Constructs operand with + * kind=#opnd_imm, type == #i32, ival() == 0. + */ + Opnd() { clear(); } + + /** + * @brief Clones the given Opnd, but with different type. + * @see as_type + */ + Opnd(jtype jt, const Opnd& that) + { + *this = that; m_jt = jt; + } + + /** + * @brief Constructs immediate operand of the given type and + * initializes immediate field with the given value. + * + * The width of any_val is wide enough to fit any neccessary value - + * a pointer, #dbl64 or #i64. + */ + Opnd(jtype jt, jlong any_val) + { + clear(); m_jt = jt; m_kind = opnd_imm; m_lval = (long)any_val; + } + + /** + * @brief Constructs register operand. + */ + Opnd(jtype jt, AR ar) + { + clear(); m_jt = jt; m_kind = opnd_reg; m_reg = ar; + } + + /** + * @brief Constructs register operand with a type of max possible width. + * + * That is #jobj for GR registers and #dbl64 for FR registers. + */ + Opnd(AR ar) + { + clear(); m_jt = is_f(ar) ? dbl64 : jobj; m_kind = opnd_reg; + m_reg = ar; + } + + /** + * @brief Constructs #i32 immediate operand. + */ + Opnd(int ival) + { + clear(); m_jt = i32; m_lval = ival; + } + + /** + * @brief Constructs i32 immediate operand. + */ + Opnd(unsigned ival) + { + clear(); m_jt = i32; m_lval = ival; + } + + /** + * @brief Constructs immediate operand of platform-dependent size. + * + * It's i32 on IA32 and i64 on EM64T and IPF. + */ + Opnd(long lval) + { + clear(); m_jt = iplatf; m_lval = lval; + } + + /** + * @brief Constructs immediate operand of platform-dependent size. + * + * It's i32 on IA32 and i64 on EM64T and IPF. + */ + Opnd(unsigned long lval) + { + clear(); m_jt = iplatf; m_lval = lval; + } + + /** + * @brief Constructs memory operand with no type (jvoid). + */ + Opnd(AR base, int disp, AR index = ar_x, unsigned scale=0) + { + clear(); + m_kind = opnd_mem; m_jt = jvoid; + m_base = base; m_index = index; + m_scale = scale; m_disp = disp; + } + + /** + * @brief Constructs memory operand. + */ + Opnd(jtype jt, AR base, int disp, AR index = ar_x, unsigned scale=0) + { + clear(); + m_kind = opnd_mem; m_jt = jt; + m_base = base; m_index = index; + m_scale = scale; m_disp = disp; + } +#ifdef _IA32_ + /** + * @brief Constructs memory operand, the given pointer is stored as + * displacement. + * @note IA-32 only. + */ + Opnd(jtype jt, AR base, const void* disp) + { + clear(); + m_kind = opnd_mem; m_jt = jt; + m_base = base; m_index = ar_x; + m_scale = 0; m_disp = (int)disp; + } +#endif + + /** + * @brief Returns kind of this operand. + */ + OpndKind kind(void) const + { + return m_kind; + } + + /** + * @brief Returns type of this operand. + */ + jtype jt(void) const + { + return m_jt; + } + /** + * @brief Tests whether this operand is register operand. + */ + bool is_reg(void) const { return kind() == opnd_reg; } + /** + * @brief Tests whether this operand is memory operand. + */ + bool is_mem(void) const { return kind() == opnd_mem; } + /** + * @brief Tests whether this operand is immediate operand. + */ + bool is_imm(void) const { return kind() == opnd_imm; } + + /** + * @brief Tests two operands for equality. + * + * For memory operands, types of operands are ignored (so it only tests + * whether two operands refer to the same memory location). + * + * For immediate operands, types are taken into account (that means + * that zero of i64 type will \b not be equal to zero of i32 type). + */ + bool operator==(const Opnd& that) const + { + if (kind() != that.kind()) return false; + if (is_reg()) return reg() == that.reg(); + if (is_mem()) { + // no test for jt() - it's intentional + return base() == that.base() && + disp() == that.disp() && + index() == that.index() && + scale() == that.scale(); + } + assert(is_imm()); + if (jt() != that.jt()) return false; + return m_lval == that.m_lval; + } + + /** + * @brief Operation reversed to operator==. + */ + bool operator!=(const Opnd& that) const { return !(*this==that); } + + /** + * @brief Returns AR for register operand, or #ar_x for operands of + * other kinds. + */ + AR reg(void) const { return m_kind == opnd_reg ? m_reg : ar_x; } + /** + * Returns integer value for immediate operand, or 0 for operands of + * other kinds. + */ + int ival(void) const { return is_imm() ? (int)m_lval : 0; } + /** + * Returns long value for immediate operand, or 0 for + * operands of other kinds. + */ + long lval(void) const { return is_imm() ? m_lval : 0; } + + /** + * Returns base register for memory operand, or ar_x for operands of + * other kinds. + */ + AR base(void) const { return m_kind == opnd_mem ? m_base : ar_x; } + + /** + * Returns index register for memory operand, or ar_x for operands of + * other kinds. + */ + AR index(void) const { return m_kind == opnd_mem ? m_index : ar_x; } + /** + * Returns displacement of complex address form for memory operand, or + * 0 for operands of other kinds. + */ + int disp(void) const { return m_kind == opnd_mem ? m_disp : 0; } + /** + * Returns scale of complex address form for memory operand, or 0 for + * operands of other kinds. + */ + unsigned scale(void) const { return m_kind == opnd_mem ? m_scale : 0; } + /** + * Returns Opnd which only differs from this Opnd by the type. + * @see Opnd(jtype, const Opnd&) + */ + Opnd as_type(jtype jt) const + { + if (m_jt == jt) { + return *this; + } + Opnd res(*this); + res.m_jt = jt; + return res; + } +private: + /** + * Initializes Opnd instance with default values. + */ + void clear(void) + { + m_kind = opnd_imm; + m_jt = i32; + m_base = m_index = ar_x; + m_disp = 0; + m_lval = 0; + m_scale = 0; + } + /** + * Kind of operand. + */ + OpndKind m_kind; + /** + * Type of operand. + */ + jtype m_jt; + union { + /** + * AR for register operand. + */ + AR m_reg; + /** + * Displacement for memory operand. + */ + int m_disp; + /** + * Integer or long value of immediate operand. + */ + long m_lval; + }; + /** + * Base register for memory operand. + */ + AR m_base; + /** + * Index register for memory operand. + */ + AR m_index; + /** + * Scale for memory operand. + */ + unsigned m_scale; +}; + +/** + * @brief Generation of code for an abstract CPU. + * + * Class Encoder used to generate CPU instructions in a CPU-independent + * manner. + * + * The Encoder's function set represents an abstract CPU which has 2 sets + * of registers - general-purpose (named GP or GR) and float-point (named + * FP or FR), has memory and memory stack. + * + * The Encoder designed to hide specialties of underlying platform as much + * as possible, so most of characteristics are the same: + * - FR reg may hold both #dbl64 and #flt32 + * - FR operations may have either memory or FR reg as second operand, but + * not immediate + * - GR reg is wide enough to carry int32 + * - GR reg is wide enough to carry a memory address + * - a memory may be addressed using complex address form cosists of + * base and index registers, displacement and a scale for index. The + * scale may be any of the following: 1, 2, 4, 8. + * + * Though some differences still exist: + * - GR reg may \b not be wide enough to fit #i64 type (is_big(i64)==true) + * - An arbitrary address may not fit into displacement field of complex + * address form. If is_ia32()==true, then an address always fits into + * displacement. + * + * Special emulations performed for the following cases: + * - (Intel 64) mov [mem64], imm64 - + * the operation is generated as 2 moves of imm32 + * - (IA-32) operations that involve 8bit access to EBP, ESI or EDI - + * in this case, the sequence of XCHG reg, reg; operation ; XCHG is + * generated. + * - (all) 'PUSH fr' is emulated as + * 'sub sp, num_of_slots_for(dbl64) ; mov [sp], fr'. 'POP fr' is emulated + * the same way. + * - (IA-32)fr_ret is 'virtual' register and is treated in a special way - + * all IA-32 calling conventions use FPU stack to return float point + * values, so only 'mov/ld fr_ret, mem' and 'mov/st mem, fr_ret' are + * allowed. In this case, FST/FLD instructions are generated. \b NOTE: + * this simulation is only done in #fld and #fst methods, you can \b not + * do #mov with fr_ret. This limitation is intentional, to remove + * additional check and branch from the hot exectuion path in #mov. + * + * call() operation is made indirect only (trough a GR register). This is + * done intentionally, to reduce differences in code generation between + * platforms - on IA-32 we alway can do relative CALL, though on Intel 64 + * the possibility depends on whether the distance between CALL instruction + * and its target fits into 2Gb. As the code is first generated into + * internal buffer, and then copied to its final location, the distance + * also changes and this may complicate the code generation routine. + * In contrast, the <code>movp(gr, target); call(gr)</code> sequence works + * the same way on all platforms. + * + * The code is generated into internal buffer represented by CodeStream + * object. + * + * The Encoder also have support for \b patching of generated code. + * + * Patching is a process of changing some part of instruction after it has + * been generated. Normally, this is used to finalize addresses that are + * not yet known at the time of code generation (for example, for a forward + * jump). + * + * The following instructions support patching: branches (br(COND) and + * loading address into GR register (#movp). + * + * When the such instruction is generated, then a special \e patch \e record + * is stored in the Encoder internally. The patch record contains some info + * about the instruction - its length, offset, type (data or branch - + * below), whether patching was done for this instruction and so on. + * + * Both methods accept additional user-defined arguments. In no way they + * are interpreted by the Encoder itself, just associated with the + * instruction to be patched. In CodeGen the arguments are used to store + * basic block and instruction's PC. + * + * The method void patch(unsigned pid, void* inst_addr, void* data) + * performs the patching. + * + * \c pid is 'patch id' returned by appropriate #br() or #movp() call. This + * is also the offset of the instruction in the internal Encoder's buffer. + * + * \c inst_addr is the address of instruction to patch and \c data is the + * data to be stored into instruction. + * + * In many cases, \c inst_addr points to the instruction in the internal + * Encoder's buffer, so the short version of patch(unsigned, void*) method + * exists. + * + * There are 2 kinds of patches - \e data and \e branch. The data patch + * is used with instruction that operate with data addresses, e.g. + * <code>mov gr, addr</code>. Branch patch applicable to br() instructions, + * with the presumption that all branches are relative ones. + * + * The key difference is that when patching the \e data, address is stored + * as-is, wihtout modification. When patching a branch, then the offset + * between \c inst_addr and \c data (interpreted as address of target) + * is calculated and the offset is stored into instruction. + * + * @todo FPU-only support, without SSE to work on P3-s. The basic idea + * is to emulate 'mov fr, fr' using FXCH and 'mov fr, mem' and + * 'mov mem, fr' using FLD, FST and FXCH. + * + * @todo IPF support. The basic idea is to hide one or two registers from + * application and use them in Ecoder internally to emulate complex address + * form and other operations that are not natively support in IPF's + * instruction set. + */ +class Encoder { +public: + /** + * No op. + */ + Encoder() { + m_trace = false; + } + + /** + * Tests whether tracing enabled for this Encoder instance. + * @note Only valid when JIT_TRACE macro is defined. Otherwise always + * returns false. + * @see JIT_TRACE + * @see JET_PROTO + */ + bool is_trace_on(void) const + { +#ifdef JIT_TRACE + return m_trace; +#else + return false; +#endif + } + /** + * Tests whether the AR is callee-save. + */ + static bool is_callee_save(AR ar) + { + return isCalleeSave[ar_idx(ar)]; + } + + /** + * Generates MOV operation. + */ + void mov(const Opnd& op0, const Opnd& op1) + { + if (is_trace_on()) { + trace(string("mov")+"("+to_str(op0.jt())+")", + to_str(op0), to_str(op1)); + } + mov_impl(op0, op1); + } + /** + * Generates load of constant address into GR register. + * @see movp(AR, unsigned, unsigned) + */ + void movp(AR op0, const void *op1) + { + assert(op0 != ar_x); + assert(is_gr(op0)); + if (is_trace_on()) { + trace("movP", to_str(op0), to_str(op1)); + } + movp_impl(op0, op1); + } + /** + * Generates load of an address into GR register, for further patching. + * @param gr - register to load + * @param udata - user data (not interpreted by Encoder) + * @param ubase - user data (not interpreted by Encoder) + * @see movp(AR, const void*) + */ + unsigned movp(AR gr, unsigned udata, unsigned ubase); + /** + * Generates load of an address specified by mem argument into the reg + * argument. + * @note \c reg must be register and \c mem can only be memory operand. + */ + void lea(const Opnd& reg, const Opnd& mem); + /** + * Generates sign extension of int8 from op1 into op0. + */ + void sx1(const Opnd& op0, const Opnd& op1); + /** + * Generates sign extension of int16 from op1 into op0. + */ + void sx2(const Opnd& op0, const Opnd& op1); + /** + * Generates sign extension op1 into op0. + */ + void sx(const Opnd& op0, const Opnd& op1); + /** + * Generates zero extension of uint8 from op1 into op0. + */ + void zx1(const Opnd& op0, const Opnd& op1); + /** + * Generates zero extension of uint16 from op1 into op0. + */ + void zx2(const Opnd& op0, const Opnd& op1); + /** + * Generates ALU operation. + */ + void alu(ALU alu, const Opnd& op0, const Opnd& op1) + { + if (is_trace_on()) { + trace(to_str(alu), to_str(op0), to_str(op1)); + } + alu_impl(alu, op0, op1); + } + + /** + * Generates ALU operation between two registers. + * + * The registers are used as \c jt type. + */ + void alu(jtype jt, ALU op, AR op0, AR op1) + { + alu(op, Opnd(jt, op0), Opnd(jt, op1)); + } + + /** + * Loads from memory into the specified register. + * + * Just a wrapper around mov(). + * @note On IA32 fr_ret loads are threated in a special way. + */ + void ld(jtype jt, AR ar, AR base, int disp=0, AR index = ar_x, + unsigned scale=0) + { + if (is_f(jt)) { + fld(jt, ar, base, disp, index, scale); + } + else { + mov(Opnd(jt, ar), Opnd(jt, base, disp, index, scale)); + } + } + /** + * Stores from the specified register into memory . + * Just a wrapper around mov(). + */ + void st(jtype jt, AR ar, AR base, int disp=0, AR index = gr_x, + unsigned scale=0) + { + if (is_f(jt)) { + fst(jt, ar, base, disp, index, scale); + } + else { + mov(Opnd(jt, base, disp, index, scale), Opnd(jt, ar)); + } + } + /** + * Loads from memory into the specified FR register. + * + * Just a wrapper around mov(). + * @note On IA32 fr_ret loads are threated in a special way. + */ + void fld(jtype jt, AR ar, AR base, int disp=0, AR index = ar_x, + unsigned scale=0); + /** + * Stores from the specified FR register into memory . + * + * Just a wrapper around mov(). + * @note On IA32 fr_ret stores are threated in a special way. + */ + void fst(jtype jt, AR ar, AR base, int disp=0, AR index = gr_x, + unsigned scale=0); + /** + * Loads 8bit from memory into GR register. + */ + void ld1(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + ld(i8, ar, base, disp, ridx, scale); + } + /** + * Loads 16bit from memory into GR register. + */ + void ld2(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + ld(i16, ar, base, disp, ridx, scale); + } + /** + * Loads 32bit from memory into a register. + */ + void ld4(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + ld(is_fr(ar) ? flt32 : i32, ar, base, disp, ridx, scale); + } + /** + * Stores 8bit from GR register into memory. + */ + void st1(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + st(i8, ar, base, disp, ridx, scale); + } + /** + * Stores 16bit from GR register into memory. + */ + void st2(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + st(i16, ar, base, disp, ridx, scale); + } + /** + * Stores 32bit from GR or FR register into memory. + */ + void st4(AR ar, AR base, int disp=0, AR ridx = ar_x, unsigned scale=0) + { + st(is_fr(ar) ? flt32 : i32, ar, base, disp, ridx, scale); + } + /** + * Pushes the value onto stack. + * @note Push of FR registers is emulated (sub sp, n ; mov [sp], fr). + * @return Number of bytes spent from the stack - the number + * subtracted from #sp . + */ + int push(const Opnd& op0); + /** + * Pops out the value from stack. + * @note Pop of FR registers is emulated (mov fr, [sp] ; add sp, n). + * @return Number of bytes popped from the stack - the number added to + * #sp. + */ + int pop(const Opnd& op0); + + /** + * Returns number of bytes needed to store all the registers. + */ + static unsigned get_all_regs_size(void) + { + return gr_num*STACK_SLOT_SIZE + fr_num*8; + } + + /** + * Pushes either all or all scratch registers onto stack. + * Number of bytes spent on stack is always rounded to 16. + */ + int push_all(bool includeCalleeSave=false); + /** + * Pops out either all or all scratch registers from stack. + * Number of bytes popped from stack is always rounded to 16. + */ + int pop_all(bool includeCalleeSave=false); + + /** + * Generates return instruction. + * @param pop_bytes - how many bytes to pop out from the stack after + * return. + */ + void ret(unsigned pop_bytes); + + /** + * Generates indirect call instruction. + * + * If calling convention assumes that caller restores stack, then it + * also generates code to restore stack. + * + * If check_stack is \c true and calling conventions obliges stack + * alignment, then a code that checks this alignment is also generated. + * trap() instruction is executed if alignment requirement not met. + */ + void call(const Opnd& target, const CallSig& ci, + bool check_stack = false); + /** + * Generates indirect call to \c target trough the specified register. + * May place constant arguments according to \c cs. \c idx parameter + * specifies which argument to start from. If all arguments are already + * prepared, then set <code>idx = cs.count()</code>. + * + * If \c idx is 0 and any argument is passed via stack, then stack + * preparation sequence is generated (<code>sub sp, cs.size()</code>). + * + * If calling convention assumes that caller restores stack, then + * the proper instructions are generated. + * + * If check_stack is \c true and calling conventions obliges stack + * alignment, then a code that checks this alignment is also generated. + * trap() instruction is executed if alignment requirement not met. + */ + void call(bool check_stack, AR gr, const void * target, + const CallSig& cs, unsigned idx, ...); + /** + * Same as call(...) but takes arguments to pass from \c va_list. + */ + void call_va(bool check_stack, AR ar, const void *target, + const CallSig& cs, unsigned idx, va_list& valist); + /** + * + * @todo the name may be somehow confusing with CodeGen's one, may + * think about renaming. + */ + void gen_args(const CallSig& cs, AR grtmp, unsigned idx, unsigned count, ...); + /** + * Generates conditional or unconditional branch. + * @param op - target operand + * @param cond - condition for conditional branch or cond_none + * @param hint - possible hint whether conditional branch is presumed + * to be taken or not + */ + void br(const Opnd& op, COND cond=cond_none, HINT hint=hint_none); + /** + * Generates conditional or unconditional branch for further patching. + * @param cond - condition for conditional branch or cond_none + * @param udata - user data (not interpreted by Encoder) + * @param ubase - user data (not interpreted by Encoder) + * @param hint - possible hint whenether conditional branch is presumed + * to be taken or not + * @return patching id (which is also ip offset of generated branch + * instruction) + */ + unsigned br(COND cond, unsigned udata, unsigned ubase, + HINT hint=hint_none); + /** + * Generates software breakpoint. + */ + void trap(void); + + /** + * Triggers software breakpoint. + * @note The method does \b not generate software break point, but + * raises it in the current program instead - in platform + * dependent manner. On Win it's DebugBreak() and it's + * raise(SIGTRAP) on Linux. + * @note To generate software break point use trap(). + * @see trap + */ + static void debug(void); + /** + * @brief Returns current offset in the Encoder's internal buffer. + * That is the offset where next instruction will be generated. + */ + unsigned ipoff(void) const + { + return m_codeStream.ipoff(); + } + + /** + * @brief Returns number of patch records registered in current Encoder. + */ + unsigned patch_count(void) const + { + return m_patches.size(); + } + /** + * @brief Returns info about next patch record. + * @param[out] ppid - patch id (which is also offset of instruction + * in the Encoder's internal buffer) + * @param[out] pudata - user data 1 + * @param[out] pubase - user data 1 + * @param[out] pdone - \b true if the instruction was patched already + * @returns \b true if the patch record is for data instruction, \b + * false for branch instruction. + */ + bool enum_patch_data(unsigned* ppid, unsigned* pudata, + unsigned* pubase, bool* pdone) + { + *ppid = iter->first; + const CodePatchItem& cpi = iter->second; + *pudata = cpi.udata; + *pubase = cpi.ubase; + *pdone = cpi.done; + return cpi.data; + } + /** + * @brief Begins enumeration of patch records. + */ + void * enum_start(void) + { + iter = m_patches.begin(); + return NULL; //(void*)&i; + } + /** + * @brief Returns \b true if no more items to enumrate remains. + */ + bool enum_is_end(void *h) + { + return iter == m_patches.end(); + } + + /** + * @brief Advances enumeration iterator on next item. + */ + void enum_next(void * h) + { + assert(iter != m_patches.end()); + ++iter; + } + /** + * @brief Patch the given by \c pid instruction in the Encoder's + * internal buffer. + */ + void patch(unsigned pid, void * data) + { + // pid is also ipoff of the instruction + void * inst_addr = ip(pid); + patch(pid, inst_addr, data); + } + void patch(unsigned pid, void* inst_addr, void* data); + /** + * Returns a current 'ip' for underlying code stream - that is + * an 'ip' where the next emitted instruction will begin. + * The ip returned is a pointer to an internal temporary code buffer. + */ + char * ip(void) + { + return m_codeStream.ip(); + } + /** + * @brief Returns address in Encoder's internal buffer by the given + * offset. + */ + char * ip(unsigned ipoff) + { + return m_codeStream.ip(ipoff); + } + + /** + * Sets a current ip for the internal code buffer. + */ + void ip(char * _ip) + { + m_codeStream.ip(_ip); + } +protected: + unsigned m_trace; +public: + /** + * Initializes internal Encoder's data. + * Must be invoked before any usage of Encoder. + */ + static void init(void); +public: + /** + * Formats the given \c op into human-readable string. + */ + static string to_str(const Opnd& op); + /** + * Formats the given \c ar into human-readable string. + * + * Callee-save registers are presented in capital letters. + * @param ar - register to convert to string. + * @param platf - if \c true, then a native (e.g. EAX) returned instead + * of abstract one (e.g. gr0). + */ + static string to_str(AR ar, bool platf = false); + /** + * Formats the given complex address from into human-readable string. + */ + static string to_str(AR base, int disp, AR index, unsigned scale); + /** + * Formats the given \c addr into human-readable string. + */ + static string to_str(const void * addr); + /** + * Formats the given integer into human-readable string. + */ + static string to_str(int i); + /** + * Formats the given ALU code into human-readable string. + */ + static string to_str(ALU op); + /** + * Formats the given condition code into human-readable string. + */ + static string to_str(COND cond); + /** + * Formats the given HINT into human-readable string. + */ + static string to_str(HINT hint); + /** + * Formats the given jtype into human-readable string. + */ + static string to_str(jtype jt); +protected: + void trace(const string& func, const string& op0, const string& op1); + /** + * Used to beautify debugging output for complex code sequences like + * push_all(). + */ + string m_prefix; + /** + * An internal temporary buffer where the generated code is accumulated. + * Normally not to be used directly, but instead through ip() methods calls. + */ + CodeStream m_codeStream; +private: + /** + * Patch record. + */ + struct CodePatchItem { + /// length + unsigned len; + /// data or branch instruction + bool data; + /// \b true if instruction was patched + bool done; + /// user data 1 + unsigned udata; + /// user data 2 + unsigned ubase; + }; + /** + * Map of patch records. + */ + typedef map<unsigned, CodePatchItem> PATCH_MAP; + /** + * Storage of patch records. + */ + PATCH_MAP m_patches; + /** + * Iterator used during enumeration of patch records. + */ + PATCH_MAP::iterator iter; + /** + * Set of flags which registers are callee-save. + */ + static bitset<ar_num> isCalleeSave; + /** + * Creates patch record for current ipoff(). + */ + unsigned reg_patch(bool data, unsigned udata, unsigned ubase_ipoff); + + /** + * Finalizes current patch record (stores instruction length, etc). + */ + void reg_patch_end(unsigned pid); + + // + // Platform-specific implementations + // + + /// Implementation of mov(). + void mov_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of alu(). + void alu_impl(ALU op, const Opnd& op0, const Opnd& op1); + /// Implementation of lea(). + void lea_impl(const Opnd& reg, const Opnd& mem); + /// Implementation of movp(). + void movp_impl(AR op0, const void *); + /// Implementation of sx1(). + void sx1_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of sx2(). + void sx2_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of sx(). + void sx_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of zx1(). + void zx1_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of zx2(). + void zx2_impl(const Opnd& op0, const Opnd& op1); + /// Implementation of fld(). + void fld_impl(jtype jt, AR op0, AR base, int disp, AR index, + unsigned scale); + /// Implementation of fst(). + void fst_impl(jtype jt, AR op0, AR base, int disp, AR index, + unsigned scale); + /// Implementation of push(). + int push_impl(const Opnd& op0); + /// Implementation of pop(). + int pop_impl(const Opnd& op0); + /// Implementation of call(). + void call_impl(const Opnd& target); + /// Implementation of ret(). + void ret_impl(unsigned pop); + /// Implementation of br(). + void br_impl(COND cond, HINT hint); + /// Implementation of br(). + void br_impl(const Opnd& op, COND cond, HINT hint); + /// Converts \c ar into platform's register name. + static string to_str_impl(AR ar); + /// Implementation of trap(). + void trap_impl(void); + // + static bool is_callee_save_impl(AR gr); +}; + +/** + * Returns \b true if the \c ar is callee-save register. + */ +inline bool is_callee_save(AR ar) +{ + return Encoder::is_callee_save(ar); +} + + +} +}; // ~namespace Jitrino::Jet + +#endif // __ENC_H_INCLUDED__ diff --git vm/jitrino/src/jet/enc_ia32.cpp vm/jitrino/src/jet/enc_ia32.cpp new file mode 100644 index 0000000..b4fb250 --- /dev/null +++ vm/jitrino/src/jet/enc_ia32.cpp @@ -0,0 +1,828 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Implementation of Encoder class for IA-32 and Intel 64 platforms. + */ +#include "enc.h" +#include "enc_ia32.h" +#include "trace.h" + +#ifdef _IA32_ +#include "enc_prvt.h" +#endif + +namespace Jitrino { +namespace Jet { + +const Opnd eax(i32, virt(RegName_EAX)); +const Opnd ecx(i32, virt(RegName_ECX)); +const Opnd edx(i32, virt(RegName_EDX)); + +static OpndSize to_size(jtype jt) +{ + switch (jt) { + case i8: return OpndSize_8; + case i16: + case u16: return OpndSize_16; + case i32: return OpndSize_32; + case i64: return OpndSize_64; + case flt32: return OpndSize_32; + case dbl64: return OpndSize_64; + default: + assert(jt == jretAddr); + // fall through to jobj + case jobj: + assert(sizeof(void*)==4 || sizeof(void*)==8); + return sizeof(void*)==4 ? OpndSize_32 : OpndSize_64; + } +} + +static const RegName reg_map[] = { + RegName_EAX, RegName_EBX, RegName_ECX, RegName_EDX, + RegName_ESI, RegName_EDI, +#ifdef _EM64T_ + RegName_R8D, RegName_R9D, RegName_R10D, RegName_R11D, + RegName_R12D, RegName_R13D, RegName_R14D, RegName_R15D, +#endif //_EM64T_ + RegName_EBP, RegName_ESP +}; + +RegName devirt(AR ar, jtype jt) +{ + RegName reg = RegName_Null; + if (ar != gr_x && ar!=ar_total) { + //return RegName_Null; + assert(COUNTOF(reg_map) == gr_total); + unsigned idx = type_idx(ar); + if (is_f(ar)) { + reg = getRegName(OpndKind_XMMReg, + jt == jvoid ? OpndSize_64 : to_size(jt), idx); + } + else { + assert(idx<COUNTOF(reg_map)); + reg = reg_map[idx]; + +#if !defined(_EM64T_) && defined(_DEBUG) + // On IA32 can not encode the lower 8 bits of the following regs + if (equals(reg, RegName_EBP) || equals(reg, RegName_ESI) || + equals(reg, RegName_EDI) || equals(reg, RegName_ESP)) { + assert(jt != i8); + } +#endif + OpndSize sz; + if (jt == jvoid) { +#ifdef _EM64T_ + sz = OpndSize_64; +#else + sz = OpndSize_32; +#endif + } + else { + sz = to_size(jt); + } + reg = getAliasReg(reg, sz); + } // if !is_f + } + return reg; +} + +static void check_args(const Opnd& op0, const Opnd& op1) +{ + assert(!op0.is_mem() || !op1.is_mem()); + assert(!op0.is_imm()); +} + +static void add_arg(EncoderBase::Operands& args, const Opnd& op, + bool can_shrink = false) +{ + OpndSize sz = to_size(op.jt()); + if (op.is_reg()) { + RegName reg = devirt(op.reg(), op.jt()); + //::OpndKind kind = is_f(op.reg()) ? OpndKind_XMMReg : OpndKind_GPReg; + //args.add(EncoderBase::Operand(sz, kind, reg)); + args.add(EncoderBase::Operand(reg)); + } + else if (op.is_mem()) { + RegName base = op.base() != ar_x ? devirt(op.base()) : RegName_Null; + RegName idx = op.index() == ar_x ? RegName_Null : devirt(op.index()); + EncoderBase::Operand mem(sz, base, idx, op.scale(), op.disp()); + args.add(mem); + } + else { + assert(!is_f(op.jt())); + if (op.jt() == i64) { + EncoderBase::Operand imm(sz, op.lval()); + args.add(imm); + } + else if (op.jt() == jobj) { + EncoderBase::Operand imm(sz, (long)(void*)op.lval()); + args.add(imm); + } + else { + assert(op.jt()<=i32); + if (can_shrink && fits_i8(op.ival())) { + sz = OpndSize_8; + } + EncoderBase::Operand imm(sz, op.ival()); + args.add(imm); + } + } +} + +static void add_args(EncoderBase::Operands& args, const Opnd& op) +{ + add_arg(args, op); +} + +static void add_args(EncoderBase::Operands& args, const Opnd& op0, + const Opnd& op1) +{ + add_arg(args, op0); + add_arg(args, op1); +} + +static void add_args_same_size(EncoderBase::Operands& args, + const Opnd& op0, const Opnd& op1) +{ + OpndSize sz = to_size(op0.jt()); + assert(to_size(op1.jt()) == sz); + if (op0.is_reg()) { + RegName reg = devirt(op0.reg(), op0.jt()); + args.add(EncoderBase::Operand(reg)); + } + else if (op0.is_mem()) { + RegName base = op0.base() != ar_x ? devirt(op0.base()) : RegName_Null; + RegName idx = op0.index() == ar_x ? RegName_Null : devirt(op0.index()); + EncoderBase::Operand mem(sz, base, idx, op0.scale(), op0.disp()); + args.add(mem); + } + else { + assert(false); + } + + if (op1.is_reg()) { + RegName reg = devirt(op1.reg(), op1.jt()); + args.add(EncoderBase::Operand(reg)); + } + else if (op1.is_mem()) { + RegName base = op1.base() != ar_x ? devirt(op1.base()) : RegName_Null; + RegName idx = op1.index() == ar_x ? RegName_Null : devirt(op1.index()); + EncoderBase::Operand mem(sz, base, idx, op1.scale(), op1.disp()); + args.add(mem); + } + else { + assert(!is_f(op1.jt())); + EncoderBase::Operand imm(sz, (long)(void*)op1.lval()); + args.add(imm); + } +} + +AR get_cconv_fr(unsigned i) { +#ifdef _EM64T_ + static const AR frs[] = { + virt(RegName_XMM0), virt(RegName_XMM1), + virt(RegName_XMM2), virt(RegName_XMM3), + virt(RegName_XMM4), virt(RegName_XMM5), + virt(RegName_XMM6), virt(RegName_XMM7), + }; + const unsigned count = COUNTOF(frs); + return (i<count) ? frs[i] : fr_x; +#else + assert(false); + return gr_x; +#endif +} + +AR get_cconv_gr(unsigned i) { +#ifdef _EM64T_ + static const AR grs[] = { + virt(RegName_RDI), virt(RegName_RSI), + virt(RegName_RDX), virt(RegName_RCX), + virt(RegName_R8), virt(RegName_R9), + }; + const unsigned count = COUNTOF(grs); + return (i<count) ? grs[i] : gr_x; +#else + assert(false); + return gr_x; +#endif +} + + +AR virt(RegName reg) +{ + if (getRegKind(reg) == OpndKind_XMMReg) { + return _ar(dbl64, getRegIndex(reg)); + } + assert(getRegKind(reg) == OpndKind_GPReg); + for(unsigned i=0; i<COUNTOF(reg_map); i++) { + if (equals(reg, reg_map[i])) { + return _ar(jobj, i); + } + } + assert(false); + return gr_x; +} + + +ConditionMnemonic devirt(COND cond) +{ + if (cond==ge) return ConditionMnemonic_GE; + if (cond==le) return ConditionMnemonic_LE; + if (cond==gt) return ConditionMnemonic_G; + if (cond==lt) return ConditionMnemonic_L; + if (cond==eq) return ConditionMnemonic_Z; + if (cond==ne) return ConditionMnemonic_NZ; + if (cond==above) return ConditionMnemonic_A; + assert(false); + return ConditionMnemonic_Count; +} + +InstPrefix devirt(HINT hint) +{ + if (hint==taken) return InstPrefix_HintTaken; + if (hint==not_taken) return InstPrefix_HintNotTaken; + assert(false); + return (InstPrefix)0xCC; +} + +static bool is_callee_save(RegName reg) +{ + if(reg == RegName_Null) { + return false; + } + if (getRegKind(reg) != OpndKind_GPReg) { + return false; + } + assert(getRegKind(reg)==OpndKind_GPReg); + if (equals(reg, RegName_EBX)) return true; + if (equals(reg, RegName_EBP)) return true; +#ifdef _EM64T_ + if (equals(reg, RegName_R12)) return true; + if (equals(reg, RegName_R13)) return true; + if (equals(reg, RegName_R14)) return true; + if (equals(reg, RegName_R15)) return true; +#else + if (equals(reg, RegName_ESI)) return true; + if (equals(reg, RegName_EDI)) return true; +#endif + return false; +} + +static Mnemonic to_mn(jtype jt, ALU alu) +{ + assert(alu_add==0); + assert(alu_sub==1); + assert(alu_mul==2); + assert(alu_div==3); + assert(alu_rem==4); + assert(alu_or==5); + assert(alu_xor==6); + assert(alu_and==7); + assert(alu_cmp==8); + assert(alu_test==9); + assert(alu_shl==10); + assert(alu_shr==11); + assert(alu_sar==12); + static const Mnemonic i_map[] = { + Mnemonic_ADD, Mnemonic_SUB, + Mnemonic_IMUL, Mnemonic_IDIV, Mnemonic_IDIV, + Mnemonic_OR, Mnemonic_XOR, Mnemonic_AND, Mnemonic_CMP, Mnemonic_TEST, + Mnemonic_SHL, Mnemonic_SHR, Mnemonic_SAR, + }; + static const Mnemonic s_map[] = { + Mnemonic_ADDSS, Mnemonic_SUBSS, + Mnemonic_MULSS, Mnemonic_DIVSS, Mnemonic_Null, + Mnemonic_Null, Mnemonic_PXOR, Mnemonic_Null, Mnemonic_COMISS, Mnemonic_Null, + Mnemonic_Null, Mnemonic_Null, Mnemonic_Null + }; + static const Mnemonic d_map[] = { + Mnemonic_ADDSD, Mnemonic_SUBSD, + Mnemonic_MULSD, Mnemonic_DIVSD, Mnemonic_Null, + Mnemonic_Null, Mnemonic_PXOR, Mnemonic_Null, Mnemonic_COMISD, Mnemonic_Null, + Mnemonic_Null, Mnemonic_Null, Mnemonic_Null + }; + // all items covered ? + assert(COUNTOF(i_map) == alu_count); + assert(COUNTOF(i_map) == COUNTOF(s_map)); + assert(COUNTOF(i_map) == COUNTOF(d_map)); + Mnemonic mn = (jt==dbl64 ? d_map : (jt==flt32 ? s_map : i_map))[alu]; + assert(mn != Mnemonic_Null); + return mn; +} + +OpndSize to_sz(jtype jt) +{ + if (jt == dbl64 || jt == i64) return OpndSize_64; + if (jt == i32 || jt == flt32) return OpndSize_32; + if (jt == i16 || jt == u16) return OpndSize_16; + if (jt == i8) return OpndSize_8; +#ifdef _IA32_ + if (jt == jobj) return OpndSize_32; +#else + if (jt == jobj) return OpndSize_64; +#endif + assert(false); + return OpndSize_Null; +} + +static void emu_fix_opnds(Encoder * enc, + Opnd& op0, Opnd& op1, + const Opnd& _op0, const Opnd& _op1) +{ +#ifdef _EM64T_ + // no op. + op0 = _op0; + op1 = _op1; + if (true) return; +#endif + op0 = _op0; + op1 = _op1; + if (!op0.is_reg() && !op1.is_reg()) { + return; + } + if (!(op0.is_reg() && op0.jt() == i8) && + !(op1.is_reg() && op1.jt() == i8)) { + return; + } + Opnd& reg_op = op0.is_reg() ? op0 : op1; + const Opnd& mem_op = op0.is_reg() ? op1 : op0; + + RegName reg = devirt(reg_op.reg()); + // On IA32 can not encode the lower 8 bits of the following regs + if (!equals(reg, RegName_EBP) && !equals(reg, RegName_ESI) && + !equals(reg, RegName_EDI)) { + assert(!equals(reg, RegName_ESP)); + return; + } + // Try to find a register which is neither a op0 itself, nor it's used + // in the op1. + RegName r1, r2; + if (mem_op.is_reg()) { + r1 = devirt(mem_op.reg()); + r2 = RegName_Null; + } + else { + assert(mem_op.is_mem()); + r1 = devirt(mem_op.base()); + r2 = devirt(mem_op.index()); + } + RegName emu = RegName_EAX; + if (equals(reg, emu) || equals(r1, emu) || equals(r2, emu)) { + emu = RegName_EDX; + if (equals(reg, emu) || equals(r1, emu) || equals(r2, emu)) { + emu = RegName_ECX; + if (equals(reg, emu) || equals(r1, emu) || equals(r2, emu)) { + emu = RegName_EDX; + } + } + } + EncoderBase::Operands xargs; + xargs.add(emu); + xargs.add(reg); + enc->ip(EncoderBase::encode(enc->ip(), Mnemonic_XCHG, xargs)); + reg_op = Opnd(reg_op.jt(), virt(emu)); +} + +static void emu_unfix_opnds(Encoder * enc, + const Opnd& op0, const Opnd& op1, + const Opnd& _op0, const Opnd& _op1) +{ +#ifdef _EM64T_ + // no op. + if (true) return; +#endif + if (op0 == _op0 && op1 == _op1) { + return; + } + const Opnd& emu_op = op0.is_reg() ? op0 : op1; + const Opnd& true_op = op0.is_reg() ? _op0 : _op1; + + assert(emu_op.is_reg() && true_op.is_reg()); + + RegName emu = devirt(emu_op.reg()); + RegName reg = devirt(true_op.reg()); + + EncoderBase::Operands xargs; + xargs.add(emu); + xargs.add(reg); + enc->ip(EncoderBase::encode(enc->ip(), Mnemonic_XCHG, xargs)); +} + +bool Encoder::is_callee_save_impl(AR gr) +{ + return Jitrino::Jet::is_callee_save(devirt(gr)); +} + +string Encoder::to_str_impl(AR ar) +{ +#ifdef _IA32_ + if (ar == fr_ret) { + return "ST(0)"; + } +#endif + RegName reg = devirt(ar); + return getRegNameString(reg); +} + +#if defined(_IA32_) +static int get_reg_idx(AR ar) +{ + assert(is_gr(ar) && ar != ar_x); + return getRegIndex(reg_map[gr_idx(ar)]); +} + + +/** + * Generates (encodes) memory operand. + * + * Kind of copy of EncoderBase::encodeModRM. + */ +static char* do_mem(char* buf, const Opnd& op) +{ + assert(op.is_mem()); + + ModRM& modrm = *(ModRM*)buf; + ++buf; + SIB& sib = *(SIB*)buf; + AR base = op.base(); + bool haveSib = false; + haveSib = haveSib || (sp == base); + haveSib = haveSib || (op.index() != ar_x); + + if (haveSib) { + ++buf; + } + if ((op.disp() == 0 || base == ar_x) && base != bp) { + modrm.mod = 0; + modrm.rm = haveSib ? 4 : (base==ar_x ? 5 : get_reg_idx(base)); + if (base == ar_x) { + *(int*)buf = op.disp(); + buf += 4; + } + } + else if (fits_i8(op.disp())) { + modrm.mod = 1; + modrm.rm = haveSib ? 4 : get_reg_idx(base); + *buf = (char)op.disp(); + buf += 1; + } + else { + modrm.mod = 2; + modrm.rm = haveSib ? 4 : get_reg_idx(base); + *(int*)buf = op.disp(); + buf += 4; + } + if (haveSib) { + sib.base = base == ar_x ? 5 : get_reg_idx(base); + sib.index = op.index() == ar_x ? 4 : get_reg_idx(op.index()); + if (op.index() != ar_x) { + if (op.scale() == 1) sib.scale = 0; + else if (op.scale() == 2) sib.scale = 1; + else if (op.scale() == 4) sib.scale = 2; + else sib.scale = 3; + } + else { sib.scale = 0; } + } + return buf; +} + +static void do_reg(char* buf, const Opnd& op) +{ + assert(op.is_reg()); + RegName reg = devirt(op.reg(), op.jt()); + ((ModRM*)buf)->reg = getRegIndex(reg); +} + +#endif // ifdef _IA32_ + +void Encoder::mov_impl(const Opnd& _op0, const Opnd& _op1) +{ +#if defined(_IA32_) + // + // mov_impl() and its calls to add_arg() are the hottest methods on + // client startups, especially with the massive ones like Eclipse. + // Here is a simple, but very useful optimization - we do not call + // to regular encoding engine, but rather generate instructions right + // here, in-place. We do this only for the most possible variants, + // that cover about 80-90% of all mov instructions. + // On Eclipse startups this removes about 1'000'000 trips to Encoder + // and related stuff. + // + if (_op0.jt() == _op1.jt() && (_op0.jt() == i32 || _op0.jt() == jobj)) { + char* p = ip(); + char * saveP = p; +#ifdef _DEBUG + char dbgbuff[20]; + unsigned dbglen; + char * dbgSave = saveP; + { + EncoderBase::Operands args; + add_args(args, _op0); + add_args(args, _op1); + char * p = EncoderBase::encode(dbgbuff, Mnemonic_MOV, args); + dbglen = p-dbgbuff; + } +#endif + if (_op0.is_mem() && _op1.is_imm() && (p=do_mem(p+1, _op0)) != NULL) { + // mov mem, imm: C7 /0 + *(unsigned char*)saveP = 0xC7; + ((ModRM*)(saveP+1))->reg = 0; + *(int*)p = _op1.ival(); + assert(!memcmp(dbgbuff, dbgSave, dbglen)); + ip(p+4); + return; + } + else if (_op0.is_reg() && _op1.is_mem() && (p=do_mem(p+1, _op1)) != NULL) { + // mov reg, mem: 8B /r + *(unsigned char*)saveP = 0x8B; + ++saveP; + do_reg(saveP, _op0); + assert(!memcmp(dbgbuff, dbgSave, dbglen)); + ip(p); + return; + } + else if (_op1.is_reg() && _op0.is_mem() && (p=do_mem(p+1, _op0)) != NULL) { + // mov mem, reg: 89 /r + *(unsigned char*)saveP = 0x89; + ++saveP; + do_reg(saveP, _op1); + assert(!memcmp(dbgbuff, dbgSave, dbglen)); + ip(p); + return; + } + } +#endif + EncoderBase::Operands args; + +#ifdef _IA32_ + assert(_op0.reg() != fr_ret && _op1.reg() != fr_ret); +#endif + assert(is_f(_op0.jt()) == is_f(_op1.jt())); + +#ifdef _EM64T_ + // A special case on EM64T - emulation of 'mov mem64, imm64' + if (_op0.is_mem() && _op1.is_imm() && + (_op1.jt() == i64 || _op1.jt() == jobj)) { + // if _op1 fits into 32 bits, then we use a single + // 'MOV mem64, imm32' which sign-extend operand - for i64. + // Otherwise we generate 2 moves. + assert(_op0.jt() == i64 || _op0.jt() == jobj); + if (fits32(_op1.lval()) && _op0.jt() == i64) { + add_arg(args, _op0); + add_arg(args, Opnd(_op1.ival())); + ip(EncoderBase::encode(ip(), Mnemonic_MOV, args)); + } + else { + RegName base = devirt(_op0.base()); + RegName index = devirt(_op0.index()); + int disp = _op0.disp(); + unsigned scale = _op0.scale(); + const OpndSize sz = OpndSize_32; + EncoderBase::Operand mem_lo(sz, base, index, scale, disp); + + args.add(mem_lo); + add_arg(args, Opnd(lo32(_op1.lval()))); + ip(EncoderBase::encode(ip(), Mnemonic_MOV, args)); + + args.clear(); + disp += 4; + EncoderBase::Operand mem_hi(sz, base, index, scale, disp); + args.add(mem_hi); + add_arg(args, Opnd(hi32(_op1.lval()))); + ip(EncoderBase::encode(ip(), Mnemonic_MOV, args)); + } + return; + } +#endif + Opnd op0, op1; + emu_fix_opnds(this, op0, op1, _op0, _op1); + if (op0.jt() == op1.jt()) { + add_args_same_size(args, op0, op1); + } + else { + add_args(args, op0); + add_args(args, op1); + } + Mnemonic mn = + op0.jt() == flt32 ? Mnemonic_MOVSS : + (op0.jt() == dbl64 ? Mnemonic_MOVQ : Mnemonic_MOV); + ip(EncoderBase::encode(ip(), mn, args)); + emu_unfix_opnds(this, op0, op1, _op0, _op1); +} + +void Encoder::alu_impl(ALU alu, const Opnd& op0, const Opnd& op1) +{ + Mnemonic mn = to_mn(op0.jt(), alu); + EncoderBase::Operands args; + add_arg(args, op0, false);//devirt(op0, OpndSize_32)); + // For alu_test can not shrink imm32 to imm8. + add_arg(args, Opnd(op1), alu != alu_test); + ip(EncoderBase::encode(ip(), mn, args)); +} + +void Encoder::lea_impl(const Opnd& reg, const Opnd& mem) +{ + EncoderBase::Operands args; + add_args(args, reg); + add_args(args, mem); + ip(EncoderBase::encode(ip(), Mnemonic_LEA, args)); +} + +void Encoder::movp_impl(AR op0, const void *op1) +{ + EncoderBase::Operands args; + args.add(devirt(op0)); +#ifdef _EM64T_ + args.add(EncoderBase::Operand(OpndSize_64, (::int_ptr)op1)); +#else + args.add(EncoderBase::Operand(OpndSize_32, (::int_ptr)op1)); +#endif + ip(EncoderBase::encode(ip(), Mnemonic_MOV, args)); +} + +void Encoder::sx1_impl(const Opnd& _op0, const Opnd& _op1) +{ + check_args(_op0, _op1); + Opnd op0, op1; + emu_fix_opnds(this, op0, op1, _op0, _op1); + EncoderBase::Operands args; + add_args(args, op0, op1); + ip(EncoderBase::encode(ip(), Mnemonic_MOVSX, args)); + emu_unfix_opnds(this, op0, op1, _op0, _op1); +} + +void Encoder::sx2_impl(const Opnd& op0, const Opnd& op1) +{ + check_args(op0, op1); + EncoderBase::Operands args; + add_args(args, op0, op1); + ip(EncoderBase::encode(ip(), Mnemonic_MOVSX, args)); +} + +void Encoder::sx_impl(const Opnd& op0, const Opnd& op1) +{ + check_args(op0, op1); + if (op1.jt() == i8) { + sx1(op0, op1); + } + else if (op1.jt() == i16 || op1.jt() == u16) { + sx2(op0, op1); + } + else { + EncoderBase::Operands args; + add_args(args, op0, op1); + ip(EncoderBase::encode(ip(), Mnemonic_MOVSX, args)); + } +} + +void Encoder::zx1_impl(const Opnd& _op0, const Opnd& _op1) +{ + check_args(_op0, _op1); + Opnd op0, op1; + emu_fix_opnds(this, op0, op1, _op0, _op1); + EncoderBase::Operands args; + add_args(args, op0, op1); + ip(EncoderBase::encode(ip(), Mnemonic_MOVZX, args)); + emu_unfix_opnds(this, op0, op1, _op0, _op1); +} + +void Encoder::zx2_impl(const Opnd& op0, const Opnd& op1) +{ + check_args(op0, op1); + EncoderBase::Operands args; + add_args(args, op0, op1); + ip(EncoderBase::encode(ip(), Mnemonic_MOVZX, args)); +} + +void Encoder::fld_impl(jtype jt, AR op0, AR base, int disp, AR index, unsigned scale) +{ + EncoderBase::Operands args; + Mnemonic mn = jt == dbl64 ? Mnemonic_MOVSD : Mnemonic_MOVSS; + OpndSize sz = jt == dbl64 ? OpndSize_64 : OpndSize_32; +#ifdef _EM64T_ + args.add(devirt(op0, jt)); +#else + if (op0 == fr_ret) { + mn = Mnemonic_FLD; + args.add(jt == dbl64 ? RegName_FP0D : RegName_FP0S); + } + else { + args.add(devirt(op0, jt)); + } +#endif + args.add(EncoderBase::Operand(sz, devirt(base), devirt(index), scale, disp)); + ip(EncoderBase::encode(ip(), mn, args)); +} + +void Encoder::fst_impl(jtype jt, AR op0, AR base, int disp, AR index, + unsigned scale) +{ + EncoderBase::Operands args; + OpndSize sz = jt == dbl64 ? OpndSize_64 : OpndSize_32; + Mnemonic mn = jt == dbl64 ? Mnemonic_MOVSD : Mnemonic_MOVSS; + args.add(EncoderBase::Operand(sz, devirt(base), devirt(index), scale, disp)); +#ifdef _EM64T_ + args.add(devirt(op0, jt)); +#else + if (op0 == fr_ret) { + mn = Mnemonic_FSTP; + args.add(jt == dbl64 ? RegName_FP0D : RegName_FP0S); + } + else { + args.add(devirt(op0, jt)); + } +#endif + ip(EncoderBase::encode(ip(), mn, args)); +} + +int Encoder::push_impl(const Opnd& op0) +{ + //assert(!is_f(gr)); + EncoderBase::Operands args; + add_args(args, op0); + ip(EncoderBase::encode(ip(), Mnemonic_PUSH, args)); + return STACK_SLOT_SIZE; +} + +int Encoder::pop_impl(const Opnd& op0) +{ + //assert(!is_f(gr)); + EncoderBase::Operands args; + add_args(args, op0); + ip(EncoderBase::encode(ip(), Mnemonic_POP, args)); + return STACK_SLOT_SIZE; +} + +void Encoder::call_impl(const Opnd& target) +{ + EncoderBase::Operands args; + add_args(args, target); + ip(EncoderBase::encode(ip(), Mnemonic_CALL, args)); +} + +void Encoder::ret_impl(unsigned pop) +{ + EncoderBase::Operands args; + if (pop != 0) { + assert(fits_i16(pop)); + args.add(EncoderBase::Operand(OpndSize_16, pop)); + } + ip(EncoderBase::encode(ip(), Mnemonic_RET, args)); +} + +void Encoder::br_impl(COND cond, HINT hint) +{ + if (hint != hint_none) { + // Hints are only allowed for conditional branches + assert(cond != cond_none); + ip(EncoderBase::prefix(ip(), devirt(hint))); + } + EncoderBase::Operands args(0); + Mnemonic mn; + if (cond == cond_none) { + mn = Mnemonic_JMP; + } + else { + mn = (Mnemonic)(Mnemonic_Jcc+devirt(cond)); + } + ip(EncoderBase::encode(ip(), mn, args)); +} + +void Encoder::br_impl(const Opnd& op, COND cond, HINT hint) +{ + // Conditional indirect branches are not supported on IA32/EM64T + assert(cond==cond_none); + // makes no sense to have hint with unconditional branch + assert(hint==hint_none); + EncoderBase::Operands args; + add_args(args, op); + ip(EncoderBase::encode(ip(), Mnemonic_JMP, args)); +} + +void Encoder::trap_impl(void) +{ + ip(EncoderBase::encode(ip(), Mnemonic_INT3, EncoderBase::Operands())); +} + +} +}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/enc_ia32.h vm/jitrino/src/jet/enc_ia32.h new file mode 100644 index 0000000..f2fc9fb --- /dev/null +++ vm/jitrino/src/jet/enc_ia32.h @@ -0,0 +1,58 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Encoder definitions specific for IA-32 and Intel 64 platforms. + */ + +#if !defined(__ENC_IA32_H_INCLUDED__) +#define __ENC_IA32_H_INCLUDED__ + +#include "enc.h" + +//#define ENCODER_ISOLATE +#include "enc_base.h" +#ifdef ENCODER_ISOLATE + using namespace enc_ia32; +#endif + +namespace Jitrino { +namespace Jet { +/** + * @brief Converts given AR into platform-specific register name. + * @param ar - AR to convert. + * @param jt - defines the preferred size of the register. If #jvoid, then + * the wides possible register returned. + */ +RegName devirt(AR ar, jtype jt=jvoid); +/** + * @brief Converts platform-specific register name into AR. + */ +AR virt(RegName reg); + +extern const Opnd eax; +extern const Opnd ecx; +extern const Opnd edx; + +} +}; // ~namespace Jitrino::Jet + +#endif // __ENC_IA32_H_INCLUDED__ diff --git vm/jitrino/src/jet/jdefs.cpp vm/jitrino/src/jet/jdefs.cpp index dd7e679..4d9520f 100644 --- vm/jitrino/src/jet/jdefs.cpp +++ vm/jitrino/src/jet/jdefs.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ #include "jdefs.h" #include <assert.h> @@ -67,37 +67,36 @@ #endif OPCODE(BIPUSH, ik_ls, 2, OPF_NONE) OPCODE(SIPUSH, ik_ls, 3, OPF_NONE) - OPCODE(LDC, ik_ls, 2, OPF_GC_PT) - OPCODE(LDC_W, ik_ls, 3, OPF_GC_PT) - OPCODE(LDC2_W, ik_ls, 3, OPF_GC_PT) - - OPCODE(ILOAD, ik_ls, 2, OPF_NONE) - OPCODE(LLOAD, ik_ls, 2, OPF_NONE) - OPCODE(FLOAD, ik_ls, 2, OPF_NONE) - OPCODE(DLOAD, ik_ls, 2, OPF_NONE) - - OPCODE(ALOAD, ik_ls, 2, OPF_NONE) - - OPCODE(ILOAD_0, ik_ls, 1, OPF_NONE) - OPCODE(ILOAD_1, ik_ls, 1, OPF_NONE) - OPCODE(ILOAD_2, ik_ls, 1, OPF_NONE) - OPCODE(ILOAD_3, ik_ls, 1, OPF_NONE) - OPCODE(LLOAD_0, ik_ls, 1, OPF_NONE) - OPCODE(LLOAD_1, ik_ls, 1, OPF_NONE) - OPCODE(LLOAD_2, ik_ls, 1, OPF_NONE) - OPCODE(LLOAD_3, ik_ls, 1, OPF_NONE) - OPCODE(FLOAD_0, ik_ls, 1, OPF_NONE) - OPCODE(FLOAD_1, ik_ls, 1, OPF_NONE) - OPCODE(FLOAD_2, ik_ls, 1, OPF_NONE) - OPCODE(FLOAD_3, ik_ls, 1, OPF_NONE) - OPCODE(DLOAD_0, ik_ls, 1, OPF_NONE) - OPCODE(DLOAD_1, ik_ls, 1, OPF_NONE) - OPCODE(DLOAD_2, ik_ls, 1, OPF_NONE) - OPCODE(DLOAD_3, ik_ls, 1, OPF_NONE) - OPCODE(ALOAD_0, ik_ls, 1, OPF_NONE) - OPCODE(ALOAD_1, ik_ls, 1, OPF_NONE) - OPCODE(ALOAD_2, ik_ls, 1, OPF_NONE) - OPCODE(ALOAD_3, ik_ls, 1, OPF_NONE) + OPCODE(LDC, ik_ls, 2, OPF_NONE) + OPCODE(LDC_W, ik_ls, 3, OPF_NONE) + OPCODE(LDC2_W, ik_ls, 3, OPF_NONE) + + OPCODE(ILOAD, ik_ls, 2, OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_I32) + OPCODE(LLOAD, ik_ls, 2, OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_I64) + OPCODE(FLOAD, ik_ls, 2, OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_FLT) + OPCODE(DLOAD, ik_ls, 2, OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_DBL) + OPCODE(ALOAD, ik_ls, 2, OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_OBJ) + + OPCODE(ILOAD_0, ik_ls, 1, OPF_VAR_USE|OPF_VAR0|OPF_VAR_TYPE_I32) + OPCODE(ILOAD_1, ik_ls, 1, OPF_VAR_USE|OPF_VAR1|OPF_VAR_TYPE_I32) + OPCODE(ILOAD_2, ik_ls, 1, OPF_VAR_USE|OPF_VAR2|OPF_VAR_TYPE_I32) + OPCODE(ILOAD_3, ik_ls, 1, OPF_VAR_USE|OPF_VAR3|OPF_VAR_TYPE_I32) + OPCODE(LLOAD_0, ik_ls, 1, OPF_VAR_USE|OPF_VAR0|OPF_VAR_TYPE_I64) + OPCODE(LLOAD_1, ik_ls, 1, OPF_VAR_USE|OPF_VAR1|OPF_VAR_TYPE_I64) + OPCODE(LLOAD_2, ik_ls, 1, OPF_VAR_USE|OPF_VAR2|OPF_VAR_TYPE_I64) + OPCODE(LLOAD_3, ik_ls, 1, OPF_VAR_USE|OPF_VAR3|OPF_VAR_TYPE_I64) + OPCODE(FLOAD_0, ik_ls, 1, OPF_VAR_USE|OPF_VAR0|OPF_VAR_TYPE_FLT) + OPCODE(FLOAD_1, ik_ls, 1, OPF_VAR_USE|OPF_VAR1|OPF_VAR_TYPE_FLT) + OPCODE(FLOAD_2, ik_ls, 1, OPF_VAR_USE|OPF_VAR2|OPF_VAR_TYPE_FLT) + OPCODE(FLOAD_3, ik_ls, 1, OPF_VAR_USE|OPF_VAR3|OPF_VAR_TYPE_FLT) + OPCODE(DLOAD_0, ik_ls, 1, OPF_VAR_USE|OPF_VAR0|OPF_VAR_TYPE_DBL) + OPCODE(DLOAD_1, ik_ls, 1, OPF_VAR_USE|OPF_VAR1|OPF_VAR_TYPE_DBL) + OPCODE(DLOAD_2, ik_ls, 1, OPF_VAR_USE|OPF_VAR2|OPF_VAR_TYPE_DBL) + OPCODE(DLOAD_3, ik_ls, 1, OPF_VAR_USE|OPF_VAR3|OPF_VAR_TYPE_DBL) + OPCODE(ALOAD_0, ik_ls, 1, OPF_VAR_USE|OPF_VAR0|OPF_VAR_TYPE_OBJ) + OPCODE(ALOAD_1, ik_ls, 1, OPF_VAR_USE|OPF_VAR1|OPF_VAR_TYPE_OBJ) + OPCODE(ALOAD_2, ik_ls, 1, OPF_VAR_USE|OPF_VAR2|OPF_VAR_TYPE_OBJ) + OPCODE(ALOAD_3, ik_ls, 1, OPF_VAR_USE|OPF_VAR3|OPF_VAR_TYPE_OBJ) OPCODE(IALOAD, ik_obj, 1, OPF_NONE) OPCODE(LALOAD, ik_obj, 1, OPF_NONE) @@ -108,33 +107,33 @@ #endif OPCODE(CALOAD, ik_obj, 1, OPF_NONE) OPCODE(SALOAD, ik_obj, 1, OPF_NONE) - OPCODE(ISTORE, ik_ls, 2, OPF_NONE) - OPCODE(LSTORE, ik_ls, 2, OPF_NONE) - OPCODE(FSTORE, ik_ls, 2, OPF_NONE) - OPCODE(DSTORE, ik_ls, 2, OPF_NONE) - OPCODE(ASTORE, ik_ls, 2, OPF_NONE) - - OPCODE(ISTORE_0, ik_ls, 1, OPF_NONE) - OPCODE(ISTORE_1, ik_ls, 1, OPF_NONE) - OPCODE(ISTORE_2, ik_ls, 1, OPF_NONE) - OPCODE(ISTORE_3, ik_ls, 1, OPF_NONE) - OPCODE(LSTORE_0, ik_ls, 1, OPF_NONE) - OPCODE(LSTORE_1, ik_ls, 1, OPF_NONE) - OPCODE(LSTORE_2, ik_ls, 1, OPF_NONE) - OPCODE(LSTORE_3, ik_ls, 1, OPF_NONE) - OPCODE(FSTORE_0, ik_ls, 1, OPF_NONE) - OPCODE(FSTORE_1, ik_ls, 1, OPF_NONE) - OPCODE(FSTORE_2, ik_ls, 1, OPF_NONE) - OPCODE(FSTORE_3, ik_ls, 1, OPF_NONE) - OPCODE(DSTORE_0, ik_ls, 1, OPF_NONE) - OPCODE(DSTORE_1, ik_ls, 1, OPF_NONE) - OPCODE(DSTORE_2, ik_ls, 1, OPF_NONE) - OPCODE(DSTORE_3, ik_ls, 1, OPF_NONE) - - OPCODE(ASTORE_0, ik_ls, 1, OPF_NONE) - OPCODE(ASTORE_1, ik_ls, 1, OPF_NONE) - OPCODE(ASTORE_2, ik_ls, 1, OPF_NONE) - OPCODE(ASTORE_3, ik_ls, 1, OPF_NONE) + OPCODE(ISTORE, ik_ls, 2, OPF_VAR_DEF|OPF_VAR_OP0|OPF_VAR_TYPE_I32) + OPCODE(LSTORE, ik_ls, 2, OPF_VAR_DEF|OPF_VAR_OP0|OPF_VAR_TYPE_I64) + OPCODE(FSTORE, ik_ls, 2, OPF_VAR_DEF|OPF_VAR_OP0|OPF_VAR_TYPE_FLT) + OPCODE(DSTORE, ik_ls, 2, OPF_VAR_DEF|OPF_VAR_OP0|OPF_VAR_TYPE_DBL) + OPCODE(ASTORE, ik_ls, 2, OPF_VAR_DEF|OPF_VAR_OP0|OPF_VAR_TYPE_OBJ) + + OPCODE(ISTORE_0, ik_ls, 1, OPF_VAR_DEF|OPF_VAR0|OPF_VAR_TYPE_I32) + OPCODE(ISTORE_1, ik_ls, 1, OPF_VAR_DEF|OPF_VAR1|OPF_VAR_TYPE_I32) + OPCODE(ISTORE_2, ik_ls, 1, OPF_VAR_DEF|OPF_VAR2|OPF_VAR_TYPE_I32) + OPCODE(ISTORE_3, ik_ls, 1, OPF_VAR_DEF|OPF_VAR3|OPF_VAR_TYPE_I32) + OPCODE(LSTORE_0, ik_ls, 1, OPF_VAR_DEF|OPF_VAR0|OPF_VAR_TYPE_I64) + OPCODE(LSTORE_1, ik_ls, 1, OPF_VAR_DEF|OPF_VAR1|OPF_VAR_TYPE_I64) + OPCODE(LSTORE_2, ik_ls, 1, OPF_VAR_DEF|OPF_VAR2|OPF_VAR_TYPE_I64) + OPCODE(LSTORE_3, ik_ls, 1, OPF_VAR_DEF|OPF_VAR3|OPF_VAR_TYPE_I64) + OPCODE(FSTORE_0, ik_ls, 1, OPF_VAR_DEF|OPF_VAR0|OPF_VAR_TYPE_FLT) + OPCODE(FSTORE_1, ik_ls, 1, OPF_VAR_DEF|OPF_VAR1|OPF_VAR_TYPE_FLT) + OPCODE(FSTORE_2, ik_ls, 1, OPF_VAR_DEF|OPF_VAR2|OPF_VAR_TYPE_FLT) + OPCODE(FSTORE_3, ik_ls, 1, OPF_VAR_DEF|OPF_VAR3|OPF_VAR_TYPE_FLT) + OPCODE(DSTORE_0, ik_ls, 1, OPF_VAR_DEF|OPF_VAR0|OPF_VAR_TYPE_DBL) + OPCODE(DSTORE_1, ik_ls, 1, OPF_VAR_DEF|OPF_VAR1|OPF_VAR_TYPE_DBL) + OPCODE(DSTORE_2, ik_ls, 1, OPF_VAR_DEF|OPF_VAR2|OPF_VAR_TYPE_DBL) + OPCODE(DSTORE_3, ik_ls, 1, OPF_VAR_DEF|OPF_VAR3|OPF_VAR_TYPE_DBL) + + OPCODE(ASTORE_0, ik_ls, 1, OPF_VAR_DEF|OPF_VAR0|OPF_VAR_TYPE_OBJ) + OPCODE(ASTORE_1, ik_ls, 1, OPF_VAR_DEF|OPF_VAR1|OPF_VAR_TYPE_OBJ) + OPCODE(ASTORE_2, ik_ls, 1, OPF_VAR_DEF|OPF_VAR2|OPF_VAR_TYPE_OBJ) + OPCODE(ASTORE_3, ik_ls, 1, OPF_VAR_DEF|OPF_VAR3|OPF_VAR_TYPE_OBJ) OPCODE(IASTORE, ik_obj, 1, OPF_NONE) OPCODE(LASTORE, ik_obj, 1, OPF_NONE) @@ -202,7 +201,7 @@ #endif OPCODE(IXOR, ik_a, 1, OPF_NONE) OPCODE(LXOR, ik_a, 1, OPF_NONE) - OPCODE(IINC, ik_a, 3, OPF_NONE) + OPCODE(IINC, ik_a, 3, OPF_VAR_DEF|OPF_VAR_USE|OPF_VAR_OP0|OPF_VAR_TYPE_I32) OPCODE(I2L, ik_cnv, 1, OPF_NONE) OPCODE(I2F, ik_cnv, 1, OPF_NONE) @@ -243,17 +242,17 @@ #endif OPCODE(GOTO, ik_cf, 3, OPF_ENDS_BB|OPF_DEAD_END) OPCODE(JSR, ik_cf, 3, OPF_ENDS_BB) - OPCODE(RET, ik_cf, 2, OPF_ENDS_BB|OPF_DEAD_END) + OPCODE(RET, ik_cf, 2, OPF_ENDS_BB|OPF_DEAD_END) // no _USE here, its intentional OPCODE(TABLESWITCH, ik_cf, 0, OPF_ENDS_BB|OPF_DEAD_END) OPCODE(LOOKUPSWITCH, ik_cf, 0, OPF_ENDS_BB|OPF_DEAD_END) - OPCODE(IRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) - OPCODE(LRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) - OPCODE(FRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) - OPCODE(DRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) - OPCODE(ARETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) - OPCODE(RETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_EXIT) + OPCODE(IRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) + OPCODE(LRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) + OPCODE(FRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) + OPCODE(DRETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) + OPCODE(ARETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) + OPCODE(RETURN, ik_meth, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_RETURN) OPCODE(GETSTATIC, ik_obj, 3, OPF_NONE) OPCODE(PUTSTATIC, ik_obj, 3, OPF_NONE) @@ -267,18 +266,18 @@ #endif UNDEFINED_OPCODE_HERE() - OPCODE(NEW, ik_obj, 3, OPF_GC_PT) - OPCODE(NEWARRAY, ik_obj, 2, OPF_GC_PT) - OPCODE(ANEWARRAY, ik_obj, 3, OPF_GC_PT) + OPCODE(NEW, ik_obj, 3, OPF_NONE) + OPCODE(NEWARRAY, ik_obj, 2, OPF_NONE) + OPCODE(ANEWARRAY, ik_obj, 3, OPF_NONE) OPCODE(ARRAYLENGTH, ik_obj, 1, OPF_NONE) - OPCODE(ATHROW, ik_throw, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_GC_PT|OPF_EXIT) - OPCODE(CHECKCAST, ik_obj, 3, OPF_GC_PT) - OPCODE(INSTANCEOF, ik_obj, 3, OPF_GC_PT) - OPCODE(MONITORENTER, ik_obj, 1, OPF_GC_PT) - OPCODE(MONITOREXIT, ik_obj, 1, OPF_GC_PT) + OPCODE(ATHROW, ik_throw, 1, OPF_ENDS_BB|OPF_DEAD_END|OPF_NONE) + OPCODE(CHECKCAST, ik_obj, 3, OPF_NONE) + OPCODE(INSTANCEOF, ik_obj, 3, OPF_NONE) + OPCODE(MONITORENTER, ik_obj, 1, OPF_NONE) + OPCODE(MONITOREXIT, ik_obj, 1, OPF_NONE) OPCODE(WIDE, ik_none, 0, OPF_NONE) - OPCODE(MULTIANEWARRAY, ik_obj, 4, OPF_GC_PT) + OPCODE(MULTIANEWARRAY, ik_obj, 4, OPF_NONE) OPCODE(IFNULL, ik_cf, 3, OPF_ENDS_BB) OPCODE(IFNONNULL, ik_cf, 3, OPF_ENDS_BB) @@ -297,7 +296,7 @@ JTypeDesc jtypes[num_jtypes] = { {dbl64, 8, 0, "dbl" }, {jobj, sizeof(void*), 0, "jobj" }, {jvoid, 0, 0, "void" }, - {jretAddr, 0, 0, "retAddr"}, + {jretAddr,sizeof(void*),0, "retAddr"}, }; #ifdef _DEBUG @@ -316,8 +315,10 @@ static bool dbg_startup_check( void ) { static bool dummy = dbg_startup_check(); #endif + jtype to_jtype(VM_Data_Type vmtype) { + //todo: can we simply table-tize it ? switch (vmtype) { case VM_DATA_TYPE_F8: return dbl64; case VM_DATA_TYPE_F4: return flt32; @@ -335,29 +336,7 @@ jtype to_jtype(VM_Data_Type vmtype) assert(false); } return i8; -} - -RefType toRefType(JavaByteCodes opcode) -{ - switch(opcode) { - case OPCODE_INVOKEINTERFACE: return RefType_InterfaceMeth; - case OPCODE_INVOKEVIRTUAL: return RefType_VirtMethod; - case OPCODE_INVOKESPECIAL: return RefType_SpecMeth; - case OPCODE_INSTANCEOF: - case OPCODE_CHECKCAST: - case OPCODE_MULTIANEWARRAY: return RefType_Class; - case OPCODE_ANEWARRAY: return RefType_ArrayClass; - case OPCODE_NEW: return RefType_ClassNew; - case OPCODE_GETFIELD: - case OPCODE_PUTFIELD: return RefType_Field; - case OPCODE_PUTSTATIC: - case OPCODE_GETSTATIC: return RefType_StaticField; - case OPCODE_INVOKESTATIC: return RefType_StaticMeth; - default: assert(false); - } // ~switch(opcode) - return RefType_Count; -} - +}; };}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/jdefs.h vm/jitrino/src/jet/jdefs.h index a941b6e..234c098 100644 --- vm/jitrino/src/jet/jdefs.h +++ vm/jitrino/src/jet/jdefs.h @@ -14,16 +14,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Common definitions used across the Jitrino.JET. - * - * Contains common definitions used across the Jitrino.JET - VM types, some - * constants and related data and methods. + * @brief Common definitions and constants used across the Jitrino.JET. */ #if !defined(__JDEFS_H_INCLUDED__) @@ -33,30 +30,90 @@ #include "open/types.h" #include "open/bytecodes.h" #include <assert.h> #include <climits> +#include <string.h> -/** - * @def MAX_REGS - * @brief maximum number of registers (of any kind) available on the current - * platform. - */ -#define MAX_REGS 8 // todo: move to encoder +// +// This file is normally included (explicitly or not) in all .jet files, +// so here are some project-wide definitions. +// +// PROJECT_JET (standalone version of Jitrino.JET) implies JET_PROTO. +#if defined(PROJECT_JET) && !defined(JET_PROTO) + #define JET_PROTO 1 +#endif -namespace Jitrino { -namespace Jet { +// _DEBUG also implies JET_PROTO. +#if defined(_DEBUG) && !defined(JET_PROTO) + #define JET_PROTO 1 +#endif + +/** + * JET_PROTO - turns on debugging, tracing and experimental features that + * are normally out of production build. + * + * JET_PROTO at least implies logging (JIT_LOGS), statistics collection + * (JIT_STATS) and various tracings (JIT_TRACE - XXX used ?). + */ +#ifdef JET_PROTO + #if !defined(JIT_LOGS) + #define JIT_LOGS + #endif + #if !defined(JIT_STATS) + #define JIT_STATS + #endif + #if !defined(JIT_TRACE) + #define JIT_TRACE + #endif +#endif -#ifdef PLATFORM_POSIX +#ifdef _WIN32 + #define stdcall__ /** * @brief Defines int64 constant. */ - #define MK_I64(a) ((jlong)(a ## LL)) -#else #define MK_I64(a) ((jlong)(a ## L)) #define snprintf _snprintf #define vsnprintf _vsnprintf + #ifndef strcasecmp + #define strcasecmp stricmp + #endif +#else + // stdcall has no meaning on platforms other than Lin32 + #undef stdcall__ + #if defined(_IA32_) && !defined(stdcall__) + #define stdcall__ __attribute__ ((__stdcall__)) + #else + #define stdcall__ + #endif + #define __stdcall + #define MK_I64(a) ((jlong)(a ## LL)) +#endif +// +// gcc def on EM64T +#if defined(__x86_64__) && !defined(_EM64T_) + #define _EM64T_ 1 + #undef _IA32_ +#endif + +#if defined(__i386__) && !defined(_IA32_) + #undef _EM64T_ + #define _IA32_ 1 +#endif + +#if !defined(_EM64T_) && !defined(_IPF_) && !defined(_IA32_) + // presuming we're working on ia-32 + #define _IA32_ 1 #endif +/** + * @brief Number of elements in array. + */ +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) + +namespace Jitrino { +namespace Jet { + // Nothing (?) portable is defined by lib.c.limits for 64bit integers, thus // declaring our own. @@ -84,6 +141,22 @@ #define jLONG_MIN MK_I64(0x80000000000 #define NOTHING (~(unsigned)0) /** + * @brief Tests whether the value fits into 8 bits. + */ +inline bool fits_i8(int val) +{ + return (CHAR_MIN <= val && val <= CHAR_MAX); +} + +/** + * @brief Tests whether the value fits into 16 bits. + */ +inline bool fits_i16(int val) +{ + return (SHRT_MIN <= val && val <= SHRT_MAX); +} + +/** * @brief Extracts lower 32 bits from the given 64 bits value. */ inline int lo32(jlong jl) { return (int)(jl & 0xFFFFFFFF); }; @@ -94,9 +167,14 @@ inline int lo32(jlong jl) { return (int) inline int hi32(jlong jl) { return (int)(jl>>32); }; /** + * @brief Composes a 64bit value from 2 32 bit values. + */ +inline jlong mk_i64(int hi, int lo) { return ((jlong)hi)<<32 | lo; }; + +/* * @brief Size of the platform's machine word, in bits. */ -const unsigned WORD_SIZE = sizeof(long)*CHAR_BIT; +const unsigned WORD_SIZE = sizeof(unsigned)*CHAR_BIT; /** * @brief Returns word index for a given index in bit array. @@ -116,17 +194,14 @@ inline unsigned bit_no(unsigned idx) /** * @brief Returns number of words needed to store the given number of bits. */ -inline unsigned words(unsigned num) -{ - return (num+WORD_SIZE-1)/WORD_SIZE; -} +#define words(num) ((num+WORD_SIZE-1)/WORD_SIZE) /** * @brief Sets a bit in the bit array at the specified position. * @param p - pointer the the bit array * @param idx - index of the bit */ -inline void set(long * p, unsigned idx) +inline void set(unsigned * p, unsigned idx) { p[ word_no(idx) ] |= 1<<bit_no(idx); } @@ -136,7 +211,7 @@ inline void set(long * p, unsigned idx) * @param p - pointer the the bit array * @param idx - index of the bit */ -inline void clr(long * p, unsigned idx) +inline void clr(unsigned * p, unsigned idx) { p[ word_no(idx) ] &= ~(1<<bit_no(idx)); } @@ -147,61 +222,27 @@ inline void clr(long * p, unsigned idx) * @param idx - index of the bit * @return \b true if the bit set, \b false otherwise */ -inline bool tst(const long * p, unsigned idx) +inline bool tst(const unsigned * p, unsigned idx) { return 0 != (p[word_no(idx)] & (1<<bit_no(idx))); } /** - * @defgroup JITRINO_JET_MEM_TRANSF_FLAGS Flags that control spill to and \ - * uploading from memory. - * - * A bunch of flags controlling \link Jitrino::Jet::Compiler::gen_mem a - * function \endlink which generates unloading and uploading of registers - * to/from the memory. + * @brief Converts string to bool. * - * @{ - */ - -/** - * @brief Unload registers to memory. - */ -#define MEM_TO_MEM (0x00000001) -/** - * @brief Upload registers from memory. - */ -#define MEM_FROM_MEM (0x00000002) -/** - * @brief Process local variables. - */ -#define MEM_VARS (0x00000004) -/** - * @brief Process stack items. + * The following strings (case-insensitive) are considered as \c true: + * on, true, t, yes, y. Any other means \c false. */ -#define MEM_STACK (0x00000008) -/** - * @brief Update state of the processed item. - */ -#define MEM_UPDATE (0x00000010) -/** - * @brief Do not update state of the processed item. - */ -#define MEM_NO_UPDATE (0x00000020) -/** - * @brief Inverse an order in which items are selected for update. - * - * Can only be used with MEM_FROM_MEM and MEM_NO_UPDATE. - * - * When specified, an items marked as 'on register' are \b uploaded - * from the memory. - */ -#define MEM_INVERSE (0x00000040) - +inline bool to_bool(const char * val) +{ + return !strcasecmp(val, "on") || + !strcasecmp(val, "yes") || !strcasecmp(val, "y") || + !strcasecmp(val, "true") || !strcasecmp(val, "t"); +} -///@} // ~ JITRINO_JET_MEM_TRANSF_FLAGS /** - * @defgroup JITRINO_JET_JAVA_METHOD_FLAGS Compilation control flags + * @defgroup JMF_ Compilation control flags * * A bunch of flags, a Java method may be compiled with. Some of them also * affect runtime of the method. @@ -212,39 +253,48 @@ #define MEM_INVERSE (0x00000040) * JMF_ stands for Java method's flag. */ -/// @{ +/// @{ /** @brief Method reports 'this' during root set enumeration.*/ #define JMF_REPORT_THIS (0x00000001) -/** @brief Generate code to perform a GC pooling on back branches.*/ -#define JMF_BBPOOLING (0x00000002) +/** @brief Generate code to perform a GC polling on back branches.*/ +#define JMF_BBPOLLING (0x00000002) /** @brief Generate profiling code for back branches and method entry.*/ #define JMF_PROF_ENTRY_BE (0x00000004) -/** @brief Resolve classes during runtime instead of compile time. */ -#define JMF_LAZY_RESOLUTION (0x00000008) - -#ifdef JET_PROTO -/** @brief Aligns stack */ -#define JMF_ALIGN_STACK (0x00000010) -#else -// experimental feature, not for production build -#define JMF_ALIGN_STACK (0) -#endif - -/** @brief Empty root set - method reports nothing to GC.*/ -#define JMF_EMPTY_RS (0x00000020) - /** * @brief Generate code so back branches and method entry counters get * checked synchronously, during runtime, at method entrance. */ -#define JMF_PROF_SYNC_CHECK (0x00000040) +#define JMF_PROF_SYNC_CHECK (0x00000008) + +#ifdef JET_PROTO +#define JMF_ALIGN_STACK (0x00010000) +#define JMF_SP_FRAME (0x00020000) +#define JMF_STATIC_GC_MAP (0x00040000) +#else +/** + * @brief Aligns stack + * @note Experimental feature, not for production build. + */ +#define JMF_ALIGN_STACK (0) +/** + * @brief Use sp-based stack frame instead of bp-based. + * @note Experimental feature, not for production build. + */ +#define JMF_SP_FRAME (0) +/** + * @brief Use static (computed at compile-time) GC-map for operand stack, + * rather than dynamic (updated at runtime). + * @note Experimental feature, not for production build. + */ +#define JMF_STATIC_GC_MAP (0) +#endif /** - * @defgroup JITRINO_JET_DEBUG_METHOD_FLAGS Debugging flags + * @defgroup DBG_ Debugging flags * * These flags are also 'Java method's flags' but used for the debugging * purposes only. @@ -257,50 +307,59 @@ #define JMF_PROF_SYNC_CHECK (0x00000040) * * @{ */ -#if defined(_DEBUG) || defined(JIT_LOGS) || defined(JET_PROTO) - /** @brief Break at method's entry.*/ +// The latest PMF/Log are working well without noticeable overhead, +// may have the tracing functionality turned on always. +#if 1 //defined(JIT_LOGS) || defined(JET_PROTO) #define DBG_BRK (0x00100000) - /** @brief Trace method's enter/exit.*/ #define DBG_TRACE_EE (0x00200000) - /** @brief Trace execution of each bytecode instruction. */ #define DBG_TRACE_BC (0x00400000) - /** - * @brief Trace runtime support events - stack unwinding, root set - * enumeration, byte code <-> native code mapping, etc. - */ #define DBG_TRACE_RT (0x00800000) - /** @brief Dump basic blocks, before code generation phase.*/ #define DBG_DUMP_BBS (0x01000000) - /** @brief Trace code generation.*/ #define DBG_TRACE_CG (0x02000000) - /** @brief Trace code layout (address ranges).*/ #define DBG_TRACE_LAYOUT (0x04000000) - /** @brief Dump whole code after it's done.*/ #define DBG_DUMP_CODE (0x08000000) - /** @brief Trace short summary about compiled method.*/ #define DBG_TRACE_SUMM (0x10000000) - /** @brief Generates code to ensure stack integrity.*/ #define DBG_CHECK_STACK (0x20000000) #else + /** @brief Break at method's entry.*/ #define DBG_BRK (0x00000000) + /** + * @brief Trace method's enter/exit. + * + * Turns on tracing of input args and return value for a method. + * Also turns on tracing of values returned from a method or a helper + * call. + * @see CodeGen::gen_save_ret + */ #define DBG_TRACE_EE (0x00000000) + /** @brief Trace execution of each bytecode instruction. */ #define DBG_TRACE_BC (0x00000000) + /** + * @brief Trace runtime support events - stack unwinding, root set + * enumeration, byte code <-> native code mapping, etc. + */ #define DBG_TRACE_RT (0x00000000) + /** @brief Dump basic blocks, before code generation phase.*/ #define DBG_DUMP_BBS (0x00000000) + /** @brief Trace code generation.*/ #define DBG_TRACE_CG (0x00000000) + /** @brief Trace code layout (address ranges).*/ #define DBG_TRACE_LAYOUT (0x00000000) + /** @brief Dump whole code after it's done.*/ #define DBG_DUMP_CODE (0x00000000) + /** @brief Trace short summary about compiled method.*/ #define DBG_TRACE_SUMM (0x00000000) + /** @brief Generates code to ensure stack integrity.*/ #define DBG_CHECK_STACK (0x00000000) #endif -/// @{ //~JITRINO_JET_DEBUG_METHOD_FLAGS +/// @{ //~DBG_ -/// @} //~JITRINO_JET_JAVA_METHOD_FLAGS +/// @} //~JMF_ /** - * @brief Describes a kind/group of bytecode instruction, according to - * the JVM Spec. + * Enum which describes a kind/group of bytecode instruction, according to + * the JVM Spec. */ enum InstrKind { /// arithmetics @@ -325,33 +384,106 @@ enum InstrKind { }; /** - * @brief (OPF stands for OPcode Flag) No special flags for the given opcode. + * @defgroup OPF_ Opcode flags - various traits of byte code instructions. + * @{ */ +/** + * @brief (OPF stands for OPcode Flag) No special flags for the given opcode. + */ #define OPF_NONE (0x00000000) /** - * @brief Opcode ends basic block (ATHROW/GOTOs/etc). + * Opcode ends basic block (ATHROW/GOTOs/conditional branch, etc). */ -#define OPF_ENDS_BB (0x00000001) - +#define OPF_ENDS_BB (0x00001000) /** - * @brief Opcode is a dead end in the control flow - no fall through - RET, - * GOTO, RETURN, ATHROW. + * Opcode has no fall through pass (ATHROW/GOTO/RETURN/etc). + */ +#define OPF_DEAD_END (0x00002000) +/** + * An instruction is one of return opcodes. + */ +#define OPF_RETURN (0x00004000) +/** + * An instruction starts a basic block. + * + * @note This is not a trait of an opcode, but rather of an instruction on + * a particular control flow. It's placed into OPF_ section as it's + * stored in the same field of JInst. + */ +#define OPF_STARTS_BB (0x00008000) +/** + * Instruction uses or defines local variable #0. + */ +#define OPF_VAR0 (0x00000000) +/** + * Instruction uses or defines local variable #1. + */ +#define OPF_VAR1 (0x00000001) +/** + * Instruction uses or defines local variable #2. + */ +#define OPF_VAR2 (0x00000002) +/** + * Instruction uses or defines local variable #3. + */ +#define OPF_VAR3 (0x00000003) +/** + * Instruction uses or defines local variable whose index defined by first + * instruction operand (JInst::op0). */ -#define OPF_DEAD_END (0x00000002) +#define OPF_VAR_OP0 (0x00000004) +/** + * Mask used to extract the OPF_VAR_ index. + */ +#define OPF_VAR_IDX_MASK (0x0000000F) /** - * @brief GC may happen on this instruction (calls to VM, method calls). + * Mask used to extract def-use info from opcode flags. + */ +#define OPF_VAR_DU_MASK (0x00000300) +/** + * If set, then opcode defines a local variable an index given by its first + * operand (JInst::op0). + */ +#define OPF_VAR_DEF (0x00000100) +/** + * If set, then opcode uses a local variable an index given by its first + * operand (JInst::op0). */ -#define OPF_GC_PT (0x00000004) +#define OPF_VAR_USE (0x00000200) /** - * @brief Instruction terminates method (xRETURN or ATHROW). + * Mask used to extract from opcode flags a type of operation performed by + * the opcode. */ -#define OPF_EXIT (0x00000008) +#define OPF_VAR_TYPE_MASK (0x000000F0) +#define OPF_VAR_TYPE_SHIFT (4) +/** + * Instruction operates with #i32 (or lesser) type. + */ +#define OPF_VAR_TYPE_I32 (i32<<OPF_VAR_TYPE_SHIFT) +/** + * Instruction operates with #jobj type. + */ +#define OPF_VAR_TYPE_OBJ (jobj<<OPF_VAR_TYPE_SHIFT) +/** + * Instruction operates with #i64 type. + */ +#define OPF_VAR_TYPE_I64 (i64<<OPF_VAR_TYPE_SHIFT) +/** + * Instruction operates with #flt32 type. + */ +#define OPF_VAR_TYPE_FLT (flt32<<OPF_VAR_TYPE_SHIFT) +/** + * Instruction operates with #dbl64 type. + */ +#define OPF_VAR_TYPE_DBL (dbl64<<OPF_VAR_TYPE_SHIFT) + +/// @} // ~OPF_ /** - * @brief An info associated with a byte code instruction. + * @brief An info associated with an bytecode instruction. */ struct InstrDesc { /** @@ -379,7 +511,7 @@ #endif * @brief Printable name of the opcode. */ const char * name; - char padding[32-20]; + char adding[32-20]; }; extern const InstrDesc instrs[OPCODE_COUNT]; @@ -388,6 +520,7 @@ extern const InstrDesc instrs[OPCODE_COU * @brief Enumerates possible Java types * * The values are ordered by complexity ascending. + * The following is intentionally \b true: <code>i8<i16<u16<i32<i64</code>. */ enum jtype { /// signed 8 bits integer - Java's \c boolean or \c byte @@ -411,7 +544,9 @@ enum jtype { /// jretAddr - a very special type for JSR things jretAddr, /// max number of types - num_jtypes, + jtypes_count, + /// max number of types + num_jtypes = jtypes_count, #ifdef _EM64T_ iplatf=i64, #else @@ -420,26 +555,20 @@ #else #endif }; -/** - * @brief Info about #jtype. - */ +/// Info associated with #jtype. struct JTypeDesc { - /** - * @brief #jtype this info refers to. - */ + /// jtype itself jtype jt; /** - * @brief Size of an item of given #jtype, in bytes. + * size in bytes of the type on current platform. + * @note: for #jobj, the size of uncompressed reference is specified. */ unsigned size; - /** - * @brief Offset of this #jtype items in arrays, in bytes. - * @see vector_first_element_offset_unboxed + /** + * offset, in bytes, of first item in an array of items of the type */ unsigned rt_offset; - /** - * @brief Print name. - */ + /// human-readable name of the type const char * name; }; @@ -449,7 +578,7 @@ struct JTypeDesc { extern JTypeDesc jtypes[num_jtypes]; /** - * @brief Tests whether specified #jtype represents floating point value. + *@brief Tests whether specified #jtype represents floating point value. */ inline bool is_f( jtype jt ) { @@ -465,18 +594,7 @@ inline bool is_wide(jtype jt) } /** - * @brief Tests whether specified #jtype is too big to fit into a single - * register on the current platform. - * - * The only case currently is i64 on IA32. - */ -inline bool is_big(jtype jt) -{ - return jt==i64; -} - -/** - * @brief Converts a VM_Data_Type into #jtype. + * @brief Converts a #VM_Data_Type into #jtype. * * Java's byte (VM_DATA_TYPE_INT8) and boolean (VM_DATA_TYPE_BOOLEAN) are * both returned as #i8. @@ -486,63 +604,6 @@ inline bool is_big(jtype jt) */ jtype to_jtype(VM_Data_Type vmtype); -/** - * @brief Types used in lazy resolution scheme. - * - * Each RefType associated with an item to be resolved during runtime. - * For example, RefType_StaticMeth associated with a values returned by - * resolve_static_method function. Composed with constant pool index, - * RefType values form an unique key which may be used to avoid resolving - * the same item several times. - */ -enum RefType { - /// Static method - RefType_StaticMeth, - /// Interface method - RefType_InterfaceMeth, - /// Special method - RefType_SpecMeth, - /// Virtual method - RefType_VirtMethod, - /// Class - RefType_Class, - /// Array calls - RefType_ArrayClass, - /// Class item, resolved via resolve_class_new - RefType_ClassNew, - /// Special case, used to make a key for object's size for new - RefType_Size, - /// Non-static field - RefType_Field, - /// Static field - RefType_StaticField, - /// Number of RefType-s in total - RefType_Count -}; - -/** - * @brief Composes a single int-sized key from the given RefType and - * constant pool index. - * @note Although \c cp_idx is of unsigned type, it's treated as 'unsigned - * short'. - * @param type - one of RefType constants - * @param cp_idx - constant pool index - * @see toRefType() - * @see ResState - * @deprecated Used in lazy resolution scheme, not a production feature. - */ -inline unsigned ref_key(RefType type, unsigned cp_idx) { - assert(type<RefType_Count); - assert(cp_idx<USHRT_MAX); - return (unsigned)((type<<16)|(cp_idx&0xFFFF)); -} - -/** - * @brief Returns #RefType to be used for a given opcode. - * @deprecated Used in lazy resolution scheme, not a production feature. - */ -RefType toRefType(JavaByteCodes opcode); - } }; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/jet.cpp vm/jitrino/src/jet/jet.cpp index 47f31db..5d1ba40 100644 --- vm/jitrino/src/jet/jet.cpp +++ vm/jitrino/src/jet/jet.cpp @@ -14,9 +14,122 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.7.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision: 1.7.12.4.2.8 $ */ + /** + * @file + * @brief Main Jitrino.JET's interface implementation. + */ + +/** + * @mainpage + * @section sec_intro Introduction + * <center> + * Jitrino.JET: <b>J</b>itrino's <b>e</b>xpress compilation pa<b>t</b>h + * </center> + * + * Jitrino.JET is a simple baseline compiler for %Jitrino JIT. + * + * It's primarily targeted for fast compilation to ensure quick start for + * client applications and to support optimizing engine of main %Jitrino + * (instrumentation, profile generation, etc.). + * + * Jitrino.JET performs 2 passes over bytecode. On the first pass, basic + * blocks boundaries are found. On the second pass code is generated. + * + * The code is generated targeting an abstract CPU that is armed with + * registers, memory, memory stack and can perform several operations like + * move between memory/register, ALU operations, branch and call, etc + * (class Encoder generates primitive operations of this abstract CPU). + * + * Technically, Jitrino.JET generates a code that simulates stack-based + * operations of Java byte code using a register CPU. Every method + * compiled by Jitrino.JET creates a stack frame with a structure similar + * to the frame described by JVM spec (3.6). The stack frame contains local + * variables array and an area for operand stack plus some other auxilary + * items. Class StackFrame describes the stack frame structure. + * + * The compilation engine consists of two main classes - Compiler and + * CodeGen. + * + * Though the separation is quite relative, the main idea is that class + * Compiler processes high level method items, like basic blocks, whole + * method's data, code layout etc. The class CodeGen is more targeted to + * process instruction-level things (e.g. the byte code instructions + * themselves). Compiler organizes pass over the byte code, instruments + * CodeGen's fields with actual data (current compiler state, PC, etc) and + * invokes CodeGen's methods to generate code for each instruction.<br> + * Some bytecode instruction (like GOTO) need to deal with basic blocks + * information, thus their generation is placed into Compiler rather than + * in CodeGen. + * + * + * Class Compiler is based on CodeGen which in turn inherits from classes + * StaticConsts, Encoder and MethInfo. The StaticConsts class has no + * funtional interface, it's just used to keep static constants separately. + * Class Encoder represents generation of CPU operations. + * MethInfo provides an interface to obtain various info about method being + * compiled. + * + * As it was stated above, two passes over the byte code is performed. + * + * The first pass is linear scan of byte code (Compiler::comp_parse_bytecode) + * - it decodes all byte code instructions, finds boundaries of basic + * blocks, counts references for instructions and collects statistics about + * usage of local variabled. The reference count for instruction is number + * of incoming edges of control flow. For instructions inside basic block, + * the reference count is 1. For instructions that are basic block leaders, + * it may be more than 1. Reference count of zero means dead code. + * + * Then, a simple global register allocation performed + * (Compiler::comp_alloc_regs) basing on the info collected in + * Compiler::comp_parse_bytecode(). Local (per-basic block) register + * allocation is done during code generation (pass 2) via + * CodeGen::valloc(jtype) calls. + * + * The second pass is performed in depth-first search (DFS) order, and the + * code is generated (Compiler::comp_gen_code_bb). The code at first is + * generated into internal buffer (CodeGen::m_codeStream), and then a code + * layout is performed (Compiler::comp_layout_code) so the layout of + * generated code becomes exactly the same as byte code layout. + * + * During compilation, Jitrino.JET mimics Java operand stack operations + * (class JFrame), so its state is known for every byte code instruction. + * This mimic stack is used to get a GC info and eliminate many unnecessary + * temporary operations caused by stack-based nature of byte code (e.g. + * ICONST_0, ISTORE_1 => mov [local#1], 0). The JFrame class also contains + * local variables array. Both operand stack and local variables array in + * JFrame are used to track item locations (register, memory), known + * attributes (i.e. tested against null). + * + * Instance of JFrame is part of BBState class which is used to maintain + * per-basic block state of compiler. + * + * A special code is generated for GC support. During runtime 2 GC maps + * are maintained. GC map is a set of bits which shows whether an item + * contains a reference. GC map for local variables is build complitely + * during runtime. That is when a write to a local variable is generated, + * the code to set or clear approprate bit in GC map is also generated (see + * CodeGen::gen_gc_mark_local()). + * + * GC map for operand stack is semi-runtime. That is the operand stack + * state is maintaned duirng compilation. Before generate code for a call + * site special code is generated that updates GC map and operand stack + * depth at the given point (CodeGen::gen_gc_stack). + * + * To be accurate, there is on more GC map maintained - the GC map for + * callee-save registers. The code for this is also generated in + * CodeGen::gen_gc_mark_local(), as only local variables may reside on + * such regisers with current approach. + * + * When GC enumeration start, the runtime support code extracts these GC + * maps method's stack frame, and then objects are reported accordingly ( + * see rt_enum()). + * + * + */ + #include "jet.h" #include "compiler.h" #include "stats.h" @@ -24,48 +137,214 @@ #include "stats.h" #include <jit_export_jpda.h> #include <assert.h> +#include "trace.h" +#include "../shared/mkernel.h" + +#include <set> +#include <string> +using std::set; +using std::string; -/** - * @file - * @brief Main interface provided by Jitrino.JET. - */ - -/** - * @mainpage - * @section sec_intro Introduction - * Jitrino.Jet: Jitrino's Express compilation paTh - * - * Jitrino.JET is a simble baseline compiler for Jitrino JIT. - * - * The main goal is fast compilation (to provide quick start for client - * applications) and to produce neccessary support for optimising engine of - * mian Jitrino (instrumentation, profile generation, etc.). - * - */ namespace Jitrino { namespace Jet { -void setup(JIT_Handle jit) + +static void process_global_args(void); + +static PMF* g_pmf = NULL; + +void setup(JIT_Handle jit, const char * name) { -#if defined(_DEBUG) && defined(JET_PROTO) -// shared_jit_handle = jit; -#endif - Timer::init(); - Timers::totalExec.start(); + g_pmf = &JITInstanceContext::getContextForJIT(jit)->getPMF(); + process_global_args(); } void cleanup(void) { - Timers::totalExec.stop(); - //Timer::dump(); - //Stats::dump(); +#ifdef JIT_STATS + const char * lp = g_pmf->getArg(NULL, "stats"); + if (lp != NULL && to_bool(lp)) { + Stats::dump(); + } +#endif // ~JIT_STATS + g_pmf->deinit(); } -void get_id_string(char * buf, unsigned len) + +bool supports_compresed_refs(void) { - const char revision[] = "$Revision: 1.7.12.3.4.4 $"; - const char branch[] = "$Name: $"; +#if defined(_EM64T_) || defined(_IPF_) + return true; +#else + return false; +#endif +} + +const char *args[][2] = +{ +//------------------------------------------------------------------------- +{"show", + " =help - prints out this text \n" + " =info \n" + " =id \n" + " =version - prints out build info \n" + " =all - help,version \n" + " =<empty> - same as all \n" +}, +//------------------------------------------------------------------------- +{"log", + "The following categories are supported: \n" + "Compilation: \n" + "(don't forget to add 'log=ct'. default is code+sum) \n" + " sum - prints out short summary about compiled method \n" + " cg - trace every stage of code generation \n" + " code - dump resulting code \n" + " layout - addresses of generated basic blocks \n" + "Runtime: \n" + "(don't forget to add 'log=rt'!) \n" + " rtsupp - prints out runtime support events (unwind, GC enum, etc) \n" + " ee - logs method's enter and exit events \n" + " bc - logs execution of each bytecode instruction \n" + " \n" + "Examples: \n" + " -Djit.jet.arg.log=ct,sum,code \n" + " -Djit.jet.arg.log=ct (same as log=ct,sum,cg) \n" + " -Djit.jet.arg.log=rt -Djit.jet.filterName.arg.log=ee \n" +}, +//------------------------------------------------------------------------- +{"break", + NULL +}, +{"brk", + "type: bool or uint; default: off; scope: method \n" + "brk=on - triggers software breakpoint at the beginning of the method \n" + "brk=PC - triggers software breakpoint at bytecode @ PC \n" +}, +//------------------------------------------------------------------------- +{"tbreak", + "type: uint; default: none; scope: global \n" + "Break into debugger when counter in dbg_rt reaches the specified \n" + "value. \n" +}, +//------------------------------------------------------------------------- +{"checkstack", + "type: bool; default: off; scope: method \n" + "generates code to verify stack integrity before and after each \n" + "bytecode instruction. \n" +}, +//------------------------------------------------------------------------- +{"checkmem", + "type: bool; default: off; scope: method \n" + "Enforces memory checks before and after compilation of a method. \n" + "Implementation is platform-dependent and may be no op on some \n" + "platforms/build configurations. Currently, only Windows/debug build \n" + "the check implemented. \n" +}, +//------------------------------------------------------------------------- +{"emulate", + "type: bool; default: off; scope: method \n" + "Performs compilation, but do not register compiled code in VM. \n" + "Return JIT_FAILURE after compilation. \n" +}, +//------------------------------------------------------------------------- +{"accept", + NULL, +}, +{"reject", + "both accept and reject:\n" + "type: range of [uint][-uint]; default: none; scope: global \n" + "reject only: \n" + "type: bool; default: off; scope: method \n" + "On global scope defines a range of compilation ids of methods to be \n" + "accepted or rejected for compilation. Any part of range may be omitted.\n" +}, +//------------------------------------------------------------------------- +{"list", + "type: string; default: none; scope: global \n" + "Sets name of file with list of fully qualified names of methods. \n" + "Any method not in the list will be rejected. \n" +}, +//------------------------------------------------------------------------- +{"bbp", + "type: bool; default: on; scope: method \n" + "turns on and off generation of back branches polling code " +}, + +//------------------------------------------------------------------------- +{"hwnpe", + "type: bool; default: on; scope: method \n" + "Controls whether to generate hardware NPE checks instead of explicit \n" + "software checks \n" +}, + +#ifdef JIT_STATS +{"stats", + "type: bool; default: off; scope: global \n" + "Collects and shows various statistics about compiled methods. \n" + "Note: you may need to pass -XcleanupOnExit to VM to view the stats. \n" +}, +#endif // ~JIT_STATS +//------------------------------------------------------------------------- + " \n" +// " \n" +}; + +static void print_id(void); + +static void print_help(void) +{ + static bool help_printed = false; + if (help_printed) return; + print_id(); + for (unsigned i=0; i<COUNTOF(args); i++) { + printf("%s\n", args[i][0]); + if (args[i][1] != NULL) { + printf("%s\n", args[i][1]); + } + } + help_printed = true; +} +#ifdef _DEBUG +static std::set<string> checked; +static Mutex checkedLock; +#endif +void check_arg_has_doc(const char* key) +{ +#ifdef _DEBUG + // + checkedLock.lock(); + if (checked.find(key) == checked.end()) { + checkedLock.unlock(); + return; + } + checked.insert(key); + checkedLock.unlock(); + // + bool found = false; + for (unsigned i=0; i<COUNTOF(args); i++) { + if (!strcmp(args[i][0], key)) { + found = true; + break; + } + } + if (!found) { + printf( + "WARNING: an argument named '%s' has no documentation !\n", key); + printf( + "Please, add appropriate description into \n\t" __FILE__ "\n"); + } +#endif // ifdef _DEBUG +} + +static const char *get_id_string(void) +{ + static char buf[80] = {0}; + if (buf[0] != 0) return buf; + unsigned len = sizeof(buf)-1; + + const char revision[] = "$Revision$"; + const char branch[] = "$Name$"; #ifdef PROJECT_JET #define ALONE_STR ", alone" @@ -99,82 +378,115 @@ #endif "Jitrino.JET" DBG_STR COMP_STR ALONE_STR ": " "Built: " __DATE__ " " __TIME__ ".%s%s", branch_buf, revision_buf); + + return buf; } -static bool id_done = false; +static void print_id(void) +{ + static bool id_printed = false; + if (id_printed) return; + puts(get_id_string()); + id_printed = true; +} -void cmd_line_arg(JIT_Handle jit, const char* name, const char* arg) +static void parse_range(const char* str, unsigned* pStart, unsigned *pEnd) { - static const char help_data[] = { -" \n" -" jet::help - prints out this text \n" -" jet::info, jet::id - prints out build info \n" -" jet::lazyres, jet::lr - generate code with lazy (runtime) resolution\n" -#ifdef JET_PROTO -" jet::stackalign, jet::sa - generate methods with stack alignment \n" -#endif -" jet::no_bbpooling, jet::no_bbp - do not generate back branches pooling \n" -" code \n" - }; - - const char - key_invalid[] = "jet::", - key_help[] = "jet::help", - key_info[] = "jet::info", - key_id[] = "jet::id", - key_lazyres[] = "jet::lazyres", key_lr[] = "jet::lr", -#ifdef JET_PROTO - key_stackalign[] = "jet::stackalign", key_sa[] = "jet::sa", -#endif - key_no_bbpooling[] = "jet::no_bbpooling", key_no_bbp[] = "jet::no_bbp"; - - if (!strncmp(arg, key_help, sizeof(key_help)-1)) { - if (!id_done) { - char buf[81]; - get_id_string(buf, sizeof(buf)-1); - puts(buf); - id_done = true; - } - puts(help_data); + if (str[0] != '-' && !isdigit(str[0])) { + // wrong or empty params. print warning ? + return; } - else if (!strncmp(arg, key_id, sizeof(key_id)-1) || - !strncmp(arg, key_info, sizeof(key_info)-1)) { - if (!id_done) { - char buf[81]; - get_id_string(buf, sizeof(buf)-1); - puts(buf); - id_done = true; - } + if (str[0] != '-') { + //'0-1' or '0' version + sscanf(str, "%u", pStart); } - else if (!strncmp(arg, key_lazyres, sizeof(key_lazyres)-1) || - !strncmp(arg, key_lr, sizeof(key_lr)-1)) { - Compiler::defaultFlags |= JMF_LAZY_RESOLUTION; + const char * pdash = strchr(str, '-'); + if (pdash != NULL) { + sscanf(pdash+1, "%u", pEnd); } -#ifdef JET_PROTO - else if (!strncmp(arg, key_stackalign, sizeof(key_stackalign)-1) || - !strncmp(arg, key_sa, sizeof(key_sa)-1)) { - Compiler::defaultFlags |= JMF_ALIGN_STACK; +} + +static void process_global_args(void) +{ + const char * lp; + lp = g_pmf->getArg(NULL, "show"); + if (lp != NULL) { + // empty string means 'all'; + bool show_all = lp[0] == 0 || !strcmpi(lp, "all"); + bool show_help = show_all || (NULL!=strstr(lp, "help")); + bool show_id = show_all || + (NULL!=strstr(lp, "id")) || + (NULL!=strstr(lp, "info")) || + (NULL!=strstr(lp, "version")); + if (show_help) { + print_help(); + } + if (show_id) { + print_id(); + } } -#endif - else if (!strncmp(arg, key_no_bbpooling, sizeof(key_no_bbpooling)-1) || - !strncmp(arg, key_no_bbp, sizeof(key_no_bbp)-1)) { - Compiler::defaultFlags &= ~JMF_BBPOOLING; + lp = g_pmf->getArg(NULL, "accept"); + if (lp != NULL) { + parse_range(lp, &Compiler::g_acceptStartID, & + Compiler::g_acceptEndID); + } + lp = g_pmf->getArg(NULL, "reject"); + if (lp != NULL) { + parse_range(lp, &Compiler::g_rejectStartID, & + Compiler::g_rejectEndID); + } + lp = g_pmf->getArg(NULL, "tbreak"); + if (lp != NULL) { + g_tbreak_id = NOTHING; + sscanf(lp, "%u", &g_tbreak_id); + } +} + + +void cmd_line_arg(JIT_Handle jit, const char* name, const char* arg) +{ + if (!strcmp(arg, "jet::help")) { + print_help(); + } + else if (!strcmp(arg, "jet::id")) { + print_id(); + } + else if (!strcmp(arg, "jet::info")) { + print_id(); + print_help(); } - else if (!strncmp(arg, key_invalid, sizeof(key_invalid)-1)) { - printf("Warning: unknown flag - %s\n", arg); + else if (!strncmp(arg, "jet::", 5)) { + static bool warning_printed = false; + if (!warning_printed) { + puts( +"*********************************************************************\n" +"* WARNING ! *\n" +"* Command line options in form of -Xjit jet::arg are deprecated ! *\n" +"* *\n" +"* The jet:: parameters are IGNORED *\n" +"* *\n" +"* To pass arguments to Jitrino.JET use *\n" +"* -Djit.<jit_name>.arg=value *\n" +"* Use *\n" +"* -Djit.<jit_name>.show=help *\n" +"* to get the list of supported args. *\n" +"*********************************************************************\n" + ); + warning_printed = true; + } } } + + OpenMethodExecutionParams get_exe_capabilities() { static const OpenMethodExecutionParams supported = { true, // exe_notify_method_entry true, // exe_notify_method_exit - false, // exe_notify_instance_field_read - false, // exe_notify_instance_field_write - false, // exe_notify_static_field_read - false, // exe_notify_static_field_write + false, // exe_notify_field_access + false, // exe_notify_field_modification false, // exe_notify_exception_throw false, // exe_notify_exception_catch false, // exe_notify_monitor_enter @@ -191,41 +503,20 @@ OpenMethodExecutionParams get_exe_capabi return supported; } -JIT_Result compile(JIT_Handle jitHandle, Compile_Handle ch, Method_Handle method, - JIT_Flags flags) +JIT_Result compile(JIT_Handle jitHandle, Compile_Handle ch, + Method_Handle method, JIT_Flags flags) { - static const OpenMethodExecutionParams compileArgs = { - false, // exe_notify_method_entry - false, // exe_notify_method_exit - - false, // exe_notify_instance_field_read - false, // exe_notify_instance_field_write - false, // exe_notify_static_field_read - false, // exe_notify_static_field_write - false, // exe_notify_exception_throw - false, // exe_notify_exception_catch - false, // exe_notify_monitor_enter - false, // exe_notify_monitor_exit - false, // exe_notify_contended_monitor_enter - false, // exe_notify_contended_monitor_exit - false, // exe_do_method_inlining - - true, // exe_do_code_mapping - true, // exe_do_local_var_mapping - - false, // exe_insert_write_barriers - }; - - ::Jitrino::Jet::Compiler jit(jitHandle, compileArgs); - return jit.compile(ch, method); + // this function is obsolet + assert(false); + return JIT_FAILURE; } JIT_Result compile_with_params(JIT_Handle jit_handle, Compile_Handle ch, Method_Handle method, OpenMethodExecutionParams params) { - ::Jitrino::Jet::Compiler jit(jit_handle, params); - return jit.compile(ch, method); + ::Jitrino::Jet::Compiler jit(jit_handle); + return jit.compile(ch, method, params); } @@ -247,20 +538,147 @@ #ifdef PROJECT_JET * * @{ */ + +#include <map> +using std::map; +#include "../main/Log.h" +#include "../main/LogStream.h" +// +// PMF and JitInstanceContext things uses various stuff from Jitrino::. +// Define it here to allow standalone .jet build. +// +namespace Jitrino { +void crash(const char* fmt, ...) +{ + va_list valist; + va_start(valist, fmt); + vprintf(fmt, valist); + exit(0); +} +// +// JITInstanceContex stub +// +typedef map<JIT_Handle, JITInstanceContext*> JITCTXLIST; +static JITCTXLIST jitContextList; + +JITInstanceContext* Jitrino::getJITInstanceContext(JIT_Handle jitHandle) +{ + assert(jitContextList.find(jitHandle) != jitContextList.end()); + return jitContextList[jitHandle]; +} + +// +// CompilationContext stub +// + +class CompilationContext { +public: + CompilationContext(JIT_Handle jitHandle, Method_Handle meth); + ~CompilationContext(); + static CompilationContext* getCurrentContext(void); + JITInstanceContext* getCurrentJITContext(void) + { + return jitContext; + } + // + JITInstanceContext* jitContext; +}; + +static TlsStack<CompilationContext> ccTls; +static MemoryManager g_mm(4026, "global MM"); + +CompilationContext* CompilationContext::getCurrentContext() { + CompilationContext* currentCC = ccTls.get(); + return currentCC; +} + +CompilationContext::CompilationContext(JIT_Handle jitHandle, + Method_Handle meth) +{ + jitContext = Jitrino::getJITInstanceContext(jitHandle); + ccTls.push(this); + Class_Handle klass = method_get_class(meth); + const char* kname = class_get_name(klass); + const char* mname = method_get_name(meth); + const char* msig = method_get_descriptor(meth); + LogStreams::current(jitContext).beginMethod(kname, mname, msig); +} + +CompilationContext::~CompilationContext() +{ + LogStreams::current(jitContext).endMethod(); +#ifdef _DEBUG + CompilationContext* last = ccTls.pop(); + assert(this == last); +#else + ccTls.pop(); +#endif +} + +// +// LogStream::current() +// + +static size_t threadnb = 0; + +struct TlsLogStreams { + MemoryManager mm; + LogStreams logstreams; + TlsLogStreams (PMF& pmf) + :mm(0, "TlsLogStreams"), logstreams(mm, pmf, ++threadnb) {} + ~TlsLogStreams () + {} +}; + +static TlsStore<TlsLogStreams> tlslogstreams; + +LogStreams& LogStreams::current(JITInstanceContext* jitContext) { + TlsLogStreams* sp = tlslogstreams.get(); + if (sp == NULL) + { // new thread + if (jitContext == NULL) { + jitContext = + CompilationContext::getCurrentContext()->getCurrentJITContext(); + } + sp = new TlsLogStreams(jitContext->getPMF()); + tlslogstreams.put(sp); + } + return sp->logstreams; +} + +// +// Fake XTimer +void XTimer::initialize(bool) {} +double XTimer::getSeconds(void)const { return 0.0; } + + +}; // ~namespace Jitrino + +using Jitrino::JITInstanceContext; +using Jitrino::MemoryManager; +using Jitrino::jitContextList; +using Jitrino::g_mm; /** * @see setup */ extern "C" JITEXPORT -void JIT_init(JIT_Handle jit, const char* name) { - Jitrino::Jet::setup(jit); +void JIT_init(JIT_Handle jit, const char* name) +{ + JITInstanceContext* jic = + new(g_mm) JITInstanceContext(g_mm, jit, name); + assert(Jitrino::jitContextList.find(jit) == Jitrino::jitContextList.end()); + jitContextList[jit] = jic; + jic->getPMF().init(); + Jitrino::Jet::setup(jit, name); } /** * @see cleanup */ extern "C" JITEXPORT -void JIT_deinit(JIT_Handle jit) { +void JIT_deinit(JIT_Handle jit) +{ Jitrino::Jet::cleanup(); } @@ -268,10 +686,32 @@ void JIT_deinit(JIT_Handle jit) { * @see cmd_line_arg */ extern "C" JITEXPORT -void JIT_next_command_line_argument(JIT_Handle jit, const char *name, const char *arg) { +void JIT_next_command_line_argument(JIT_Handle jit, const char *name, + const char *arg) +{ Jitrino::Jet::cmd_line_arg(jit, name, arg); } + +extern "C" JITEXPORT +JIT_Result JIT_compile_method(JIT_Handle jit, Compile_Handle ch, + Method_Handle method, + JIT_Flags flags) +{ + Jitrino::CompilationContext ctx(jit, method); + return Jitrino::Jet::compile(jit, ch, method, flags); +} + +extern "C" JITEXPORT +JIT_Result JIT_compile_method_with_params(JIT_Handle jit, + Compile_Handle ch, + Method_Handle method, + OpenMethodExecutionParams params) +{ + Jitrino::CompilationContext ctx(jit, method); + return Jitrino::Jet::compile_with_params(jit, ch, method, params); +} + /** * Noop. */ @@ -299,27 +739,6 @@ JIT_Result JIT_gen_method_info(JIT_Handl } -extern "C" JITEXPORT -JIT_Result JIT_compile_method(JIT_Handle jit, Compile_Handle ch, - Method_Handle method, - JIT_Flags flags) -{ - return Jitrino::Jet::compile(jit, ch, method, flags); -} - -extern "C" JITEXPORT -JIT_Result JIT_compile_method_with_params(JIT_Handle hjit, - Compile_Handle compilation, - Method_Handle method, - OpenMethodExecutionParams params) -{ - ::Jitrino::Jet::Compiler jit(hjit, params); - JIT_Flags flags; - flags.insert_write_barriers = false; - return jit.compile(compilation, method); -} - - /** * Noop in Jitrino.JET. * @return FALSE @@ -461,12 +880,13 @@ void * JIT_get_address_of_var(JIT_Handle } /** - * @returns \b false + * @returns \b Whether Jitrino.JET support compressed references on current + * platform. */ extern "C" JITEXPORT Boolean JIT_supports_compressed_references(JIT_Handle jit) { - return false; + return ::Jitrino::Jet::supports_compresed_refs(); } @@ -533,6 +953,5 @@ OpenExeJpdaError set_local_var(JIT_Handl /// @} // ~ defgroup JITRINO_JET_STANDALONE - -#endif // ~ifdef PROJECT_JET // standalone interface +#endif // ~ifdef PROJECT_JET // standalone interface diff --git vm/jitrino/src/jet/jet.h vm/jitrino/src/jet/jet.h index 6f1fb14..ec748b8 100644 --- vm/jitrino/src/jet/jet.h +++ vm/jitrino/src/jet/jet.h @@ -14,13 +14,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.5.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Declaration of main interface functions provided by Jitirno.JET. + * @brief Declaration of main interfaces provided by Jitirno.JET. */ #if !defined(__JET_H_INCLUDED__) @@ -70,8 +70,7 @@ bool rt_check_method(JIT_Handle jit, Met * given method. The rt_unwind function updates JitFrameContext: * - 'restores' registers (if necessary) * - sets IP pointer to point to the return addres - * - updates stack pointer - to pop out input args (in case of stack-based - * calling convention) and to pop out caller's address + * - sets SP to 'pop out' IP from stack * * @param jit - JIT handle * @param method - method handle @@ -98,9 +97,9 @@ void rt_enum(JIT_Handle jit, Method_Hand * @brief 'Fixes' a catch handler context to prepare for the control to be * transferred to the handler. * - * 'fix handler context' for a given IP means to correct stack depth, so - * a control can be transferred from the IP to appropriate handler (in the - * same method ?). + * 'fix handler context' for a given IP means to correct stack pointer, so + * a control can be transferred from the IP to appropriate handler <b>in + * the same method</b>. * * @param jit - JIT handle * @param method - method handle @@ -130,7 +129,7 @@ void * rt_get_address_of_this(JIT_Handle * The function finds Java byte code's program counter (PC) for a given * address of a native instruction (IP). * @note If the given IP does not belong to the method, the behavior is - * unpredictable. + * not specified. * * @param jit - JIT handle * @param method - method handle @@ -190,8 +189,9 @@ void rt_bc2native(JIT_Handle jit, Method * @brief Initialization routine, normally called from the JIT_init(). * * @param hjit - JIT handle passed from VM to JIT_init() + * @param name - name assigned to JIT */ -void setup(JIT_Handle hjit); +void setup(JIT_Handle hjit, const char* name); /** * @brief Cleanup routine, normally called from the JIT_deinit(). @@ -208,8 +208,15 @@ void cleanup(void); void cmd_line_arg(JIT_Handle jit, const char * name, const char * arg); /** + * @brief Returns true if Jitrino.JET supports compressed references on + * the current platform. + */ +bool supports_compresed_refs(void); + +/** * @brief Performs compilation of the method. * @returns \b true if the method was compiled, \b false otherwise + * @deprecated Use compile_with_params instead. */ JIT_Result compile(JIT_Handle jit, Compile_Handle compile, Method_Handle method, JIT_Flags flags); @@ -236,4 +243,4 @@ OpenMethodExecutionParams get_exe_capabi }}; // ~namespace Jitrino::Jet -#endif // ~__JET_H_INCLUDED__ +#endif // ~__JET_H_INCLUDED__ diff --git vm/jitrino/src/jet/jframe.cpp vm/jitrino/src/jet/jframe.cpp index 627c19c..0dc65aa 100644 --- vm/jitrino/src/jet/jframe.cpp +++ vm/jitrino/src/jet/jframe.cpp @@ -14,182 +14,84 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ #include "jframe.h" -#include "trace.h" /** * @file - * @brief Implementation of JFrame methods. + * @brief Implementation of JFrame. */ - namespace Jitrino { namespace Jet { -void JFrame::init(const JFrame * pparent) -{ - *this = *pparent; -} - -void JFrame::init(unsigned stack_max, unsigned var_slots, - unsigned istackregs, unsigned ivarregs, - unsigned fstackregs, unsigned fvarregs) -{ - - m_stack.resize(stack_max+1); - m_vars.resize(var_slots); - // - m_fstack_regs = fstackregs; - m_fvar_regs = fvarregs; - m_fvar_regs_mask = (1 << m_fvar_regs) - 1; - m_istack_regs = istackregs; - m_ivar_regs = ivarregs; - m_ivar_regs_mask = (1 << m_ivar_regs) - 1; - // - clear_stack(); - clear_vars(); - m_slotids = 0; - m_need_update = 0; -} - -#ifdef _DEBUG -void JFrame::verify(void) -{ - assert(m_top >= -1); - assert(size() <= m_stack.size()); - assert(((int)m_need_update) >= 0); - //unsigned depth = (unsigned)m_top + 1; - //for( unsigned i=0; i<depth; i++ ) { - // jtype jt = get_jtype(m_stack[i]); - // if( jt == jvoid ) { - // assert( i != depth+1 ); - // assert( m_stack[i+1] == i64 || m_stack[i+1] == dbl64 ); - // } - //} -} -#endif - -unsigned JFrame::devirt(jtype jt, unsigned vslot) -{ - assert(vslot < vslots(jt)); - const bool isf = is_f(jt); - for (unsigned slot = 0; slot < size(); slot++) { - const JFrame::Slot& s = m_stack[slot]; - if (s.vslot() == (int)vslot && (isf == is_f(s.jt))) { - return slot; - } - } - assert(false); - return (unsigned)-1; -}; - void JFrame::push(jtype jt) { - if( jt < i32 ) jt = i32; - switch( jt ) { - //case i8: - //case i16: - //case u16: + assert(m_top<(int)max_size()); + if (jt < i32) { + jt = i32; + } + switch (jt) { + case i8: + case i16: + case u16: case i32: case jobj: - case jretAddr: - m_stack[++m_top] = Slot(jt, false, m_islots++); + m_stack[++m_top] = Val(jt); break; case i64: - m_stack[++m_top] = Slot(jt,true, m_islots++); - m_stack[m_top].m_id = ++m_slotids; - assert( is_big(i64) ); - m_stack[++m_top] = Slot(jt, false, m_islots++); + m_stack[++m_top] = Val(jt); + m_stack[++m_top] = Val(jt); break; case flt32: - m_stack[++m_top] = Slot(jt, false, m_fslots++); + m_stack[++m_top] = Val(jt); break; case dbl64: - m_stack[++m_top] = Slot(jt,true, -1); - m_stack[m_top].m_id = ++m_slotids; - m_stack[++m_top] = Slot(jt, false, m_fslots++); + m_stack[++m_top] = Val(jt); + m_stack[++m_top] = Val(jt); break; default: - assert(false); + assert( jt == jretAddr ); + m_stack[++m_top] = Val(jt); break; } - Slot& s = m_stack[m_top]; - s.m_id = ++m_slotids; - const unsigned rstackregs = _rstackregs(jt); - s.m_regid = s.vslot() % rstackregs; - if (is_big(jt)) { - assert(jt == i64); - Slot& shi = m_stack[m_top-1]; - shi.m_regid = shi.vslot() % rstackregs; - } - // - // check whether an overflow happened and, if so, mark some slots to be - // unloaded - // - const unsigned slots = vslots(jt); - if (slots <= rstackregs) { - verify(); - return; - } - unsigned to_unload = is_big(jt) ? (slots == rstackregs+1 ? 1 : 2) : 1; - unsigned unload_vslot = slots >= rstackregs ? slots - rstackregs - 1 : 0; - unsigned slot = devirt(jt, unload_vslot); - unsigned depth = slot2depth(slot); - Slot& sunl = dip(depth); - if (!(sunl.state() & SS_SWAPPED)) { - sunl.m_state |= SS_NEED_SWAP; - ++m_need_update; - } - if (to_unload > 1) { - assert(unload_vslot > 0); - --unload_vslot; - slot = devirt(jt, unload_vslot); - depth = slot2depth(slot); - Slot& sunl2 = dip(depth); - if (!(sunl2.state() & SS_SWAPPED)) { - sunl2.m_state |= SS_NEED_SWAP; - ++m_need_update; - } - } - verify(); } void JFrame::pop(jtype jt) { - assert(m_top>=0); // cant pop on empty stack + // cant pop on empty stack + assert(m_top>=0); if (jt < i32) { jt = i32; } assert(top() == jt); - switch(jt) { - // case i8: - // case i16: - // case u16: jt = i32; - case jretAddr: + case i8: + case i16: + case u16: case i32: - case jobj: --m_top; --m_islots; break; - case flt32: --m_top; --m_fslots; break; - case i64: m_top -= 2; m_islots -= 2; break; - case dbl64: m_top -= 2; --m_fslots; break; - default: assert(false); break; + case jobj: --m_top; break; + case flt32: --m_top; break; + case i64: m_top -= 2; break; + case dbl64: m_top -= 2; break; + default: + assert(jt == jretAddr); + --m_top; + break; } - verify(); } void JFrame::pop2(void) { if (top() == i64 || top() == dbl64) { - pop( top() ); + pop(top()); } else { pop(top()); assert(top() != i64 && top() != dbl64); pop(top()); } - verify(); } void JFrame::pop_n(const ::std::vector<jtype>& args) @@ -199,433 +101,5 @@ void JFrame::pop_n(const ::std::vector<j } } -void JFrame::dup(JavaByteCodes op) -{ - jtype jt1, jt2; - - jt1 = top(); - if( op != OPCODE_DUP ) { - pop( jt1 ); - } - - switch( op ) { - case OPCODE_DUP: - push( jt1 ); - __get(0).assign( __get(1) ); - break; - case OPCODE_DUP_X1: - // [..., value2, value1] => [.. value1, value2, value1] - // jt1 = top(); pop(jany32); - jt2 = top(); pop(jt2); - push( jt1 ); - push( jt2 ); - push( jt1 ); - break; - case OPCODE_DUP_X2: - // jt1 = top(); pop(jany32); - jt2 = top(); pop(jt2); - if( jt2 == dbl64 || jt2 == i64 ) { - // [.. value2, value1] => [.. value1, value2, value1] - push( jt1 ); - push( jt2 ); - push( jt1 ); - } - else { - // [.. value3, value2, value1] => [.., value1, value3, value2, value1] - jtype jt3 = top(); pop(jt3); - push( jt1 ); - push( jt3 ); - push( jt2 ); - push( jt1 ); - } - break; - case OPCODE_DUP2: - if( jt1 == dbl64 || jt1 == i64 ) { - // [.. value] => [.. value, value] - push( jt1 ); push( jt1 ); - } - else { - // [.. value2, value1] => [.. value2, value1, value2, value1] - jt2 = top(); /*pop(); - push( jt2 );*/ push( jt1 ); push( jt2 ); push( jt1 ); - } - break; - case OPCODE_DUP2_X1: - if( jt1 == dbl64 || jt1 == i64 ) { - // [.. value2, value1.64] => [.. value1.64, value2, value1.64] - jt2 = top(); pop(jt2); - - push(jt1); push(jt2); push(jt1); - } - else { - // [.. value3, value2, value1] => [.. value2, value1, value3, value2, value1] - jt2 = top(); pop(jt2); - jtype jt3 = top(); pop(jt3); - push( jt2 ); push( jt1 ); push( jt3 ); push( jt2 ); push( jt1 ); - } - break; - case OPCODE_DUP2_X2: - if( jt1 == dbl64 || jt1 == i64 ) { - // either Form 2 or Form 4 - jt2 = top(); - if( top() == dbl64 || top() == i64 ) { - // Form 4 - // [.. value2, value1] => [.. value1, value2, value1] - pop2(); - push( jt1 ); push( jt2 ); push( jt1 ); - } - else { - // Form 2 - // [ .. value3, value2, value1] => [.. value1, value3, value2, value1] - pop(jt2); - jtype jt3 = top(); pop(jt3); - push( jt1 ); push( jt3 ); push( jt2 ); push( jt1 ); - } - } - else { - jt2 = top(); pop(jt2); - jtype jt3 = top(); pop(jt3); - if( jt3 == dbl64 || jt3 == i64 ) { - // Form 3 - // [.. value3, value2, value1] => [.. value2, value1, value3, value2, value1] - push( jt2 ); push( jt1 ); push( jt3 ); push( jt2 ); push( jt1 ); - } - else { - // Form 1 - // [.. value4, value3, value2, value1] => [.. value2, value1, value4, value3, value2, value1] - jtype jt4 = top(); pop(jt4); - push(jt2); push(jt1); push(jt4); push(jt3); push(jt2); push(jt1); - } - }; - break; - case OPCODE_SWAP: - // jtype jt1 = top(); pop( jany32 ); - jt2 = top(); pop( jt2 ); - push( jt1 ); - push( jt2 ); - break; - default: assert( false ); - } -} - -unsigned JFrame::gc_mask(unsigned word_no) const -{ - assert( word_no < gc_width() ); - - unsigned pos = word_no*WORD_SIZE; // where to start - unsigned end_pos = ::std::min(pos + WORD_SIZE, size()); - unsigned mask = 0; - - for( ; pos < end_pos; pos++ ) { - if( m_stack[pos].jt == jobj ) { - mask |= (1<<bit_no(pos)); - } - } - return mask; -} - -void JFrame::erase(unsigned idx) -{ - Slot& v = m_vars[idx]; - if (v.m_regid == -1) { - return; - } - const unsigned rbit = 1<<v.m_regid; - assert(_rmask(v.jt) & rbit); - assert(_rmap(v.jt)[v.m_regid] == (int)idx); - _rmap(v.jt)[v.m_regid] = -1; - _rmask(v.jt) &= ~rbit; - v = Slot(); - jtype savejt = v.jt; - unsigned savestate = v.state(); - if (is_wide(savejt)) { - erase(savestate & SS_HI_PART ? idx-1 : idx+1); - } -} - -void JFrame::release(jtype jt, unsigned rid) -{ - const unsigned rbit = 1<<rid; - if (!(_rmask(jt) & rbit)) { - assert(_rmap(jt)[rid] == -1); - return; - } - assert(_rmap(jt)[rid] != -1); - unsigned idx = _rmap(jt)[rid]; - Slot& v = m_vars[idx]; - assert(v.regid() == (int)rid); - _rmap(jt)[rid] = -1; - _rmask(jt) &= ~rbit; - if (v.needswap()) { - // already waiting for unloading - return; - } - if (!v.changed()) { - // not changed - no need to unload - return; - } - v.m_state |= SS_NEED_SWAP; - ++m_need_update; -} - -unsigned JFrame::alloc(jtype jt, int idx, bool upper, bool willDef) -{ - // if its not a scratch register requested, then check whether the slot - // has a register allocated. - if (idx != -1) { - Slot& v = m_vars[idx]; - if (v.jt != jt || upper != (0!=(v.m_state&SS_HI_PART))) { - // the slot either has another type, or represent - // another half of a wide type - release the slot - erase(idx); - } - else if (v.m_regid != -1) { - // type is the same, and the slot already has - // a register allocated - return it - if (v.swapped() && !willDef) { - v.m_state |= SS_NEED_UPLOAD; - ++m_need_update; - } - return v.m_regid; - } - } - // try to allocate register - unsigned& rmask = _rmask(jt); - // is there any register available ? - unsigned avail = _rallmask(jt) & ~rmask; - unsigned rid = 0; - if (avail) { - // yes, we have at least one register - for (rid = 0; !(avail & 0x1); avail >>= 1, rid++); - // mark the register as 'occupied' - rmask |= (1 << rid); - } - else { - // no free registers left, release one - // which to swap ? try to swap out not the recently used register to - // avoid too many register<->memory transfers. - unsigned tmpregid = (rlastused(jt)+1) % _rlocalregs(jt); - assert(rmask & (1<<tmpregid)); - unsigned swapid = _rmap(jt)[tmpregid]; - assert((int)swapid != idx); - JFrame::Slot & sswap = m_vars[swapid]; - assert(is_f(sswap.jt) == is_f(jt)); - assert(sswap.m_regid == (int)tmpregid); - if (sswap.changed()) { - // need to unload - sswap.m_state |= SS_NEED_SWAP; - // temporary keep its regid - ++m_need_update; - } - if (idx != -1) { - if (!willDef) { - m_vars[idx].m_state |= SS_NEED_UPLOAD; - ++m_need_update; - } - else { - m_vars[idx].m_state |= SS_CHANGED; - } - } - rid = tmpregid; - } - - if (idx==-1) { - rmask &= ~(1<<rid); - } - else { - Slot& v = m_vars[idx]; - v.jt = jt; - v.m_regid = rid; - if (upper) { - v.m_state |= SS_HI_PART; - } - _rmap(jt)[rid] = idx; - rlastused(jt) = rid; - } - return rid; -} - - -void JFrame::st(jtype jt, unsigned idx) -{ - //release slot at idx - // if is_wide, then also release idx+1 - //set info about a new slot - - // note: 's' is a copy, not a ref, as the item itself get - // modified in free() - Slot s = m_stack[m_top]; - Slot& var = m_vars[idx]; - - if (s.jt != var.jt ) { //m_id && var.m_id != 0) { - erase(idx); - } - var.assign(s); - if (var.m_id == 0) { - var.m_id = ++m_slotids; - } - if (is_wide(s.type())) { - Slot& v1 = m_vars[idx+1]; - Slot& s1 = m_stack[m_top-1]; - v1.assign(s1); - v1.m_id = ++m_slotids; - } - pop( s.jt ); -} - -void JFrame::ld(jtype jt, unsigned idx) -{ - Slot& v = m_vars[idx]; - assert(v.jt == jt || v.jt == jvoid); - if (v.m_id == 0) { - v.m_id = ++m_slotids; - v.jt = jt; - } - push(jt); - m_stack[m_top].assign(v); - if (is_wide(jt)) { - Slot& v1 = m_vars[idx+1]; - assert(v1.jt == jt || v1.jt == jvoid); - v1.m_state |= SS_HI_PART; - if (v1.m_id == 0) { - assert(v1.jt == jvoid && v1.m_regid == -1); - v1.m_id = ++m_slotids; - v1.jt = jt; - } - m_stack[m_top-1].assign(v1); - } -} - -void JFrame::var_def(jtype jt, unsigned idx, unsigned attrs) -{ - assert(idx<m_vars.size()); - // wide types are not expected here. - assert(!is_wide(jt)); - Slot& v = m_vars[idx]; - assert(v.type() == jvoid || v.type() == jt); - v.jt = jt; - v.m_attrs = attrs; - v.m_id = ++m_slotids; -} - -void JFrame::stack_attrs(unsigned depth, unsigned attrs) -{ - Slot& s = m_stack[m_top-depth]; - s.m_attrs |= attrs; - - if (s.id() == 0) { - return; - } - - // propagate properties to local variables - for(unsigned i=0; i<m_vars.size(); i++) { - Slot& v = m_vars[i]; - if (v.id() == s.id()) { - v.m_attrs |= attrs; - } - } - // propagate properties to other stack slots - for(unsigned i=0; i<size(); i++) { - Slot& stmp = m_stack[i]; - if (stmp.id() == s.id()) { - stmp.m_attrs |= attrs; - } - } -} - -void JFrame::var_state(unsigned idx, unsigned set_state, - unsigned clr_state) -{ - assert(idx<m_vars.size()); - Slot& v = m_vars[idx]; - const unsigned saveState = v.m_state; - v.m_state |= set_state; - v.m_state &= ~clr_state; - if (!(saveState & SS_NEED_SWAP) && (v.m_state & SS_NEED_SWAP)) { - ++m_need_update; - } - if (!(saveState & SS_NEED_UPLOAD) && (v.m_state & SS_NEED_UPLOAD)) { - ++m_need_update; - } - if ((saveState & SS_NEED_SWAP) && !(v.m_state & SS_NEED_SWAP)) { - --m_need_update; - } - if ((saveState & SS_NEED_UPLOAD) && !(v.m_state & SS_NEED_UPLOAD)) { - --m_need_update; - } - if (!(saveState & SS_SWAPPED) && (v.m_state & SS_SWAPPED) && - v.regid() != -1) { - // the item was just swapped out. release its register - const unsigned rbit = 1<<v.regid(); - if (_rmap(v.jt)[v.regid()] == (int)idx) { - _rmap(v.jt)[v.regid()] = -1; - _rmask(v.jt) &= ~rbit; - } - v.m_regid = -1; - // swapped item also implies 'not changed' - v.m_state &= ~SS_CHANGED; - } -} - -void JFrame::stack_state(unsigned depth, unsigned set_state, - unsigned clr_state) { - Slot& s = m_stack[depth2slot(depth)]; - const unsigned saveState = s.m_state; - s.m_state |= set_state; - s.m_state &= ~clr_state; - if (!(saveState & SS_NEED_SWAP) && (s.m_state & SS_NEED_SWAP)) { - ++m_need_update; - } - if (!(saveState & SS_NEED_UPLOAD) && (s.m_state & SS_NEED_UPLOAD)) { - ++m_need_update; - } - if ((saveState & SS_NEED_SWAP) && !(s.m_state & SS_NEED_SWAP)) { - --m_need_update; - } - if ((saveState & SS_NEED_UPLOAD) && !(s.m_state & SS_NEED_UPLOAD)) { - --m_need_update; - } -} - -void JFrame::clear_attrs(void) -{ - assert(need_update()==0); - clear_vars(); - for (unsigned i=0; i<size(); i++) { - Slot& s = m_stack[i]; - s.m_attrs = 0; - s.m_id = ++this->m_slotids; - } -} - -void JFrame::clear_stack(void) -{ - m_top = -1; - m_fslots = 0; - m_islots = 0; -} - -void JFrame::clear_vars(void) -{ - m_fmask = 0; - m_imask = 0; - m_flast_used = 0; - m_ilast_used = 0; - - for (unsigned i=0; i<m_vars.size(); i++) { - m_vars[i] = Slot(); - } - for (unsigned i=0; i<MAX_REGS; i++) { - m_fvarmap[i] = -1; - m_ivarmap[i] = -1; - } -} - -bool JFrame::regable(unsigned depth) const -{ - const Slot& s = m_stack[depth2slot(depth)]; - return vslots(s.jt) - s.vslot() <= _rstackregs(s.jt); -} - };}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/jframe.h vm/jitrino/src/jet/jframe.h index 79ed044..b76e990 100644 --- vm/jitrino/src/jet/jframe.h +++ vm/jitrino/src/jet/jframe.h @@ -14,299 +14,90 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ #if !defined(__JFRAME_H_INCLUDED__) #define __JFRAME_H_INCLUDED__ /** * @file - * @brief Routines and data structures to mimic Java method's frame - - * operand stack and local variables. + * @brief JFrame class declaration. */ #include "jdefs.h" #include <vector> #include <assert.h> +#include "val.h" namespace Jitrino { namespace Jet { -// -// SA_ states for 'Stack item Attributes' -// - -/** - * @brief 'Non Zero' - an items tested to be non-zero/non-null. - */ -#define SA_NZ (0x00000001) -/** - * @brief An item was tested against negative-size and is either positive - * or zero. - */ -#define SA_NOT_NEG (0x00000002) - -// -// SS_ states for 'Stack item State' -// - -/** @brief Item was changed and need to be synch-ed back to memory.*/ -#define SS_CHANGED (0x00000004) -/** @brief Item need to be swapped from a register to the memory.*/ -#define SS_NEED_SWAP (0x00000008) -/** @brief Item need to be uploaded from a memory location to a register.*/ -#define SS_NEED_UPLOAD (0x00000010) -/** - * @brief Item was swapped to memory and might need to be loaded back to a - * register. - */ -#define SS_SWAPPED (0x00000020) -/** - * @brief Item represents a higher part of a wide time - either dbl64 or - * i64. - */ -#define SS_HI_PART (0x00000040) -/** - * @brief An item's type was reflected in GC map. - */ -#define SS_MARKED (0x00000080) // todo: seems useless - remove ? - /** * @brief Emulates Java method's frame (operand stack and local variables) * and its operations. * - * It's used to maintain a valid state for the operand stack and some - * info about locals needed for code generation (i.e. whether a variable - * need to be loaded from memory). And also carries some per-bb info like - * a mask for GC and so on. - * - * JFrame also acts as a trivial local register allocator. - * - * The JFrame instances does not perform any callbacks to notify when spill - * or upload needed. Instead, it sets SS_NEED_SWAP or SS_NEED_UPLOAD on items - * which require such actions. Whether such items exist may be checked - * through #need_update() call. After the spill/upload done, the SS_ state - * need to be cleared by #stack_state() or #var_state() call. - * - * Registers are separated on 2 groups by the type (float-point (FP) and - * general-purpose (GP) registers). - * Registers in each type group referred by indexes (normally denoted as - * \c rid or \c regid), as if they were in a single continuos array. - * - * In the each 'array' there are 2 groups by their function - first group - * to keep top of the operand stack and another one to keep local variables. - * - * The JFrame tracks 'slots' for both operand stack and local variables. Some - * items may occupy 2 slots, for example #i64 or #dbl64. - * - * Each slot has its own unique id and set of attributes, which are changed - * for every defining operation (i.e. IINC operation), but are preserved - * during copying (i.e. for xLOAD, or xSTORE operations). - * - * When the state of the operand stack is tracked, each item on the stack - * gets so called 'virtual slot' (normally referred as \b vslot). The virtual - * slot allows to track items of different types as if they were in the - * different, virtual stacks. The virtual slot shows how many items of the - * similar type are already on the stack. The 'similar' types are: float - * point items (#dbl64 and #flt32) tracked together. All other types are - * tracked also together but separately from float point slots. + * @todo Seems not much reasons to have it as separate class. Move all the + * data into BBState and drop off the JFrame? */ class JFrame { public: /** - * @brief Represents stack or local slot and some info associated with - * it. - */ - struct Slot { - friend class JFrame; - /** - * @brief Initializes instance with empty values. - */ - Slot() - { - jt = jvoid; - m_vslot = m_regid = -1; - m_attrs = m_state = 0; - m_id = 0; - } - /** - * @brief Initializes instance with the given values. - */ - Slot(jtype _jt, bool _half, int _vslot) - { - jt = _jt; - m_vslot = _vslot; - m_regid = -1; - m_attrs = 0; - m_id = 0; - m_state = _half ? SS_HI_PART : 0; - } - /** - * @brief Tests whether slot is swapped into memory. - */ - bool swapped(void) const { return m_state & SS_SWAPPED; } - /** - * @brief Tests whether slot was changed since its last load from - * memory. - * - * If the slot was changed it may need to be saved back to - * memory, i.e. for local variables. - */ - bool changed(void) const { return m_state & SS_CHANGED; } - /** - * @brief Tests whether slot requires swap. - * - * For example, if the item was located on a register and this - * register was allocated for another slot. - */ - bool needswap(void) const { return m_state & SS_NEED_SWAP; } - /** - * @brief Tests whether the slot represents a high part of a - * wide item (i64 or dbl64). - */ - bool hipart(void) const { return m_state & SS_HI_PART; } - - /** - * @brief Type of the slot. - */ - jtype jt; - - /** - * @brief Returns type of the slot. - */ - jtype type(void) const { return jt; } - /** - * @brief Returns id of the slot. - */ - unsigned id(void) const { return m_id; } - /** - * @brief Returns register index for the slot. - */ - int regid(void) const { return m_regid; } - /** - * @brief Returns virtual slot of the slot. - */ - int vslot(void) const { return m_vslot; } - /** - * @brief Returns attributes of the slot. - */ - unsigned attrs(void) const { return m_attrs; } - /** - * @brief Returns state of the slot. - */ - unsigned state(void) const { return m_state; } - private: - /** - * @brief Virtual slot (for stack items) occupied by a given stack - * item. - */ - int m_vslot; - /** - * @brief Attributes that may be assigned to a slot during - * compilation. - */ - unsigned m_attrs; - - /** - * @brief Compile-time state. - */ - unsigned m_state; - - /** - * @brief Unique id of a slot's value. Changes every time when a - * defining operation (write) to the slot happens. - */ - unsigned m_id; - - /** - * @brief Register index assigned to a slot. - */ - int m_regid; - - /** - * @brief Act like an assignment operator but transfers only - * transferable attributes of the slot. - * - * Does not copy \c regid and \c vslot. - * Also sets SS_CHANGED and clears SS_SWAPPED flags. - */ - void assign(const Slot& s) - { - jt = s.jt; - m_id = s.m_id; - m_attrs = s.m_attrs; - m_state = (s.m_state | SS_CHANGED) & ~SS_SWAPPED; - } - }; -public: - /** * @brief No op. */ - JFrame() {} - - /** - * @brief Initializes the JFrame making it exactly the same as parent's - * state. - */ - void init(const JFrame * pparent); - - /** - * @brief Initializes empty JFrame with the given max stack depth, - * slots allocated for local variables and registers allocated - * for all this. - */ - void init(unsigned stack_max, unsigned var_slots, - unsigned istackregs, unsigned ivarregs, - unsigned fstackregs, unsigned fvarregs); -private: - /** - * @brief Returns a bit mask of occupied integer registers. - */ - unsigned& imask(void) + JFrame() { - return m_imask; - } - /** - * @brief Returns a bit mask of occupied float-point registers. - */ - unsigned& fmask(void) + m_stack = m_vars = NULL; + max_stack = num_locals = 0; + }; + ~JFrame() { - return m_fmask; + if (m_stack) { + delete[] m_stack; + } + if (m_vars) { + delete[] m_vars; + } } -public: - /** - * @brief Returns number of slots on stack occupied by the float-point - * (if jt==flt32 or dbl64) or integer items. - */ - unsigned vslots(jtype jt) const + JFrame(const JFrame& that) { - assert(jt!=jvoid); - return is_f(jt) ? fslots() : islots(); + m_stack = m_vars = NULL; + max_stack = num_locals = 0; + *this = that; } -private: - /** - * @brief Returns number of slots on stack occupied by float-point - * items. - */ - unsigned fslots(void) const - { - return m_fslots; +public: + JFrame& operator=(const JFrame& that) + { + assert(that.m_stack != NULL); + assert(that.m_vars != NULL); + if (m_stack == NULL) { + max_stack = that.max_stack; + num_locals = that.num_locals; + m_stack = new Val[max_stack+1]; + m_vars = new Val[num_locals]; + } + else { + assert(max_stack == that.max_stack); + assert(num_locals== that.num_locals); + } + memcpy(m_stack, that.m_stack, sizeof(Val)*(max_stack+1)); + memcpy(m_vars, that.m_vars, sizeof(Val)*(num_locals)); + m_top = that.m_top; + return *this; } /** - * @brief Returns number of slots on stack occupied by integer/object - * items. + * @brief Initializes empty JFrame with the given max stack depth, + * slots allocated for local variables and registers allocated + * for all this. */ - unsigned islots(void) const + void init(unsigned stack_max, unsigned var_slots) { - return m_islots; + max_stack = stack_max; + num_locals = var_slots; + m_stack = new Val[max_stack+1]; + m_vars = new Val[num_locals]; + m_top = -1; } -public: - /** - * @brief 'Devirtualizes' slot - gets a real slot index by its virtual - * slot and a type. - */ - unsigned devirt(jtype jt, unsigned vslot); /** * @brief Converts slot index into depth. */ @@ -316,52 +107,62 @@ public: return size()-slot-1; } /** - * @brief Converts depth into slot index. - */ + * @brief Converts depth into slot index. + */ unsigned depth2slot(unsigned depth) const { assert(depth<size()); return size()-depth-1; } - /** * @brief Returns current stack depth. + * @return current stack depth */ unsigned size(void) const { return m_top+1; } + + /** + * @brief Returns max stack size. + */ + unsigned max_size(void) const + { + return max_stack; + } + + /** + * @brief Returns number of local variables. + */ + unsigned num_vars(void) const + { + return num_locals; //m_vars.size(); + } + /** * @brief Returns type of a slot at the given depth. */ - jtype top(unsigned depth = 0) const + jtype top(unsigned depth = 0) const { assert(depth<size()); - return m_stack[size()-depth-1].jt; + return m_stack[size()-depth-1].type(); } /** - * @brief Returns slot at the given depth. - */ - Slot& dip(unsigned depth) + * @brief Returns slot at the given depth. + */ + Val& dip(unsigned depth) { assert(depth<size()); return m_stack[size()-depth-1]; } /** * @brief Pushes the given jtype into the stack. - * - * Allocates registers for this newly pushed item. - * As result of this call, some items may need to be spilled to memory, - * see #need_update(). */ void push(jtype jt); /** * @brief Pops out an item from the stack. * * The given \c jt must be same as the item on top of the stack. - * - * As result, a state for some slots may change, see #need_update() - * to check whether there are such items. */ void pop(jtype jt); /** @@ -376,337 +177,37 @@ public: */ void pop_n(const ::std::vector<jtype>& args); /** - * @brief Performs various DUP operations over the stack. - * - * Only OPCODE_DUP* and OPCODE_SWAP operations are allowed. - */ - void dup(JavaByteCodes op); - /** - * @brief Makes the stack empty. - */ - void clear_stack(void); - /** - * @brief Assigns attributes to a stack slot on the given depth. - */ - void stack_attrs(unsigned depth, unsigned attrs); - /** - * @brief Sets and clears specified state for a stack slot on the given - * depth. - * - * @param depth - depth of the slot - * @param set_state - a mask of states to set - * @param clr_state - a mask of states to clear - */ - void stack_state(unsigned depth, unsigned set_state, - unsigned clr_state); - /** - * @brief Loads local variable \c idx of type \c jt onto operand stack. - */ - void ld(jtype jt, unsigned idx); - /** - * @brief Stores top of operand stack of type \c jt into local variable - * \c idx. - */ - void st(jtype jt, unsigned idx); - /** - * @brief If local variable \c idx occupies a register, then mark this - * register as 'free'. + * @brief Returns stack slot at the given \b position (not depth). */ - void erase(unsigned idx); - /** - * @brief Clears all slots of local variables, marks all registers of - * local variables 'free'. - */ - void clear_vars(void); - /** - * @brief Sets variable to type \c jt, increases its id and assigns - * specified attributes. - */ - void var_def(jtype jt, unsigned idx, unsigned attrs); - /** - * @brief Sets and/or clears specified state flags for local variable. - * @param idx - slot of local variable to change. - * @param set_state - state to set. - * @param clr_state - state to clear. - */ - void var_state(unsigned idx, unsigned set_state, - unsigned clr_state); - /** - * @brief Allocates a register of specified type for specified local - * variable. - * - * If \c idx is -1, then allocates a scratch register not assigned to - * any variable. If there is an available register of the given type, - * it's returned as scratch. Otherwise one of the local variables slots - * marked as 'SS_NEED_SWAP', its register marked as 'free' and returned. - * - * @param jt - type of local variable/register to allocate. - * @param idx - index of local variable. -1 to allocate a scratch - * register of specified type. - * @param upper - true if this slot represents a high part of wide - * type (i.e. of #i64). - * @param willDef shows whether the next operation with the register - * will be defining operation. If it's not and the variable - * was not located on register, then the slot marked as - * 'SS_NEED_UPLOAD' - so the value need to be loaded from memory - * to register. - */ - unsigned alloc(jtype jt, int idx, bool upper, bool willDef); - /** - * @brief Releases specified register of local variable of the specified - * type. - */ - void release(jtype jt, unsigned rid); - - /** - * @brief Returns number of local variables. - */ - unsigned num_vars(void) const - { - return m_vars.size(); - } - - // - // register-allocation machinery utilities - // - - /** - * @brief Returns mask of free/occupied registers for local vars of - * the given type. - */ - unsigned& _rmask(jtype jt) - { - assert(jt!=jvoid); - return is_f(jt) ? fmask() : imask(); - } - /** - * @brief Returns mask of all available registers for local vars of - * the given type. - */ - unsigned _rallmask(jtype jt) - { - assert(jt!=jvoid); - return is_f(jt) ? m_fvar_regs_mask : m_ivar_regs_mask; - } - /** - * @brief Returns a mapping between register index and a variable index, - * of the given type. - */ - int * _rmap(jtype jt) - { - assert(jt!=jvoid); - return is_f(jt) ? m_fvarmap : m_ivarmap; - } - /** - * @brief Returns number of registers for operand stack of the given - * type. - */ - unsigned _rstackregs(jtype jt) const - { - return is_f(jt) ? m_fstack_regs : m_istack_regs; - } - /** - * @brief Returns number of registers for local vars of the given - * type. - */ - unsigned _rlocalregs(jtype jt) const - { - return is_f(jt) ? m_fvar_regs : m_ivar_regs; - } - /** - * @brief Returns index of last used register of the given type. - */ - unsigned& rlastused(jtype jt) - { - assert(jt!=jvoid); - return is_f(jt) ? m_flast_used : m_ilast_used; - } - /** - * @brief Returns number of items that require update (#SS_NEED_SWAP or - * #SS_NEED_UPLOAD). - */ - unsigned need_update(void) const - { - return m_need_update; - } - /** - * @brief Clears attributes for both vars and stack slots. - */ - void clear_attrs(void); - /** - * @brief Tests whether an item of operand stack at the specified depth - * can be allocated on a register. - */ - bool regable(unsigned depth) const; - // - // GC-related routines - // - - /** - * @brief Returns number of words (currently == long) which need to hold - * a complete GC mask. - */ - unsigned gc_width(void) const { return words(m_stack.size()); }; - /** - * @brief Returns a word representing a bit mask which in reflects - * the state the stack - '1' means 'an object is on the operand - * stack'. - */ - unsigned gc_mask(unsigned word_no) const; - /** - * @brief Returns stack slot at the given position (not depth). - */ - Slot& at(unsigned slot) + Val& at(unsigned slot) { assert(slot<size()); return m_stack[slot]; } /** - * @brief Returns local variable's slot at the given position. + * @brief Returns local variable at the given position. */ - Slot& var(unsigned slot) + Val& var(unsigned slot) { - assert(slot<m_vars.size()); + assert(slot<num_vars()); //m_vars.size()); return m_vars[slot]; } - /** - * @brief Returns read-only item representing local slot. - * @param slot - index of the local slot to return - * @return an item representing local slot, read-only - */ - const Slot& get_var(unsigned slot) const - { - assert(slot<m_vars.size()); - return m_vars[slot]; - } - /** - * @brief Returns read-only item of the stack slot, at the given position. - * - * @note \c pos is \b position, not depth. - * - * @param pos - index of the stack slot to return - * @return an item representing stack slot, read-only - */ - const Slot& get_stack(unsigned pos) const - { - assert(pos<size()); - return m_stack[pos]; - } - - private: -#ifdef _DEBUG - /** - * @brief Check's data consistency. No-op in release mode. - */ - void verify(void ); -#else - void verify(void) {}; -#endif - /** - * @brief Returns stack slot at the given depth. - */ - Slot& __get(unsigned depth) - { - assert(depth<size()); - return m_stack[depth2slot(depth)]; - } /** * @brief Current stack pointer. -1 if stack is empty. */ int m_top; - /** - * @brief Operand tack data. + * @brief Operand stack data. */ - ::std::vector<Slot> m_stack; + Val* m_stack; /** * @brief Local variables data. */ - ::std::vector<Slot> m_vars; - - /** - * @brief Number of stack vslots occupied by flt32 and dbl64 items. - * - * Both dbl64 and flt32 contribute one vslot. - */ - unsigned m_fslots; - - /** - * @brief Bit-mask of which FP registers are occupied. - */ - unsigned m_fmask; - /** - * @brief Mapping between FP registers and local variables they are - * allocated for. - * - * m_fvarmap[regid] contains index of local variable assigned to the - * register \c regid, or -1 if the register is free. - */ - int m_fvarmap[MAX_REGS]; - /** - * @brief Index of last used float-point register. - */ - unsigned m_flast_used; - /** - * @brief Max number of FP registers available to store stack items. - */ - unsigned m_fstack_regs; - /** - * @brief Max number of FP registers available to store local - * variables. - */ - unsigned m_fvar_regs; - /** - * @brief Bit mask which represents all FP registers available to store - * local variables. - */ - unsigned m_fvar_regs_mask; - /** - * @brief Number of stack vslots occupied by integer and object items. - * - * #i64 items contribute 2 vslots. - */ - unsigned m_islots; - /** - * @brief Bit-mask of which GP registers are occupied. - */ - unsigned m_imask; - /** - * @brief Mapping between GP registers and local variables they - * are allocated for. - * - * m_ivarmap[regid] contains index of local variable assigned to the - * register \c regid, or -1 if the register is free. - */ - int m_ivarmap[MAX_REGS]; - /** - * @brief Index of last used GP register. - */ - unsigned m_ilast_used; - /** - * @brief Max number of GP registers available to store stack items. - */ - unsigned m_istack_regs; - /** - * @brief Max number of GP registers available to store local variables. - */ - unsigned m_ivar_regs; - /** - * @brief Bit mask which represents all GP registers available to store - * local variables. - */ - unsigned m_ivar_regs_mask; - /** - * @brief Counter used as unique id for slots for defining operations. - */ - unsigned m_slotids; - /** - * @brief How many items (both stack and local vars) need update (i.e. - * have either #SS_NEED_SWAP or #SS_NEED_UPLOAD states). - */ - unsigned m_need_update; + Val* m_vars; + unsigned max_stack; + unsigned num_locals; }; }}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/mib.cpp vm/jitrino/src/jet/mib.cpp new file mode 100644 index 0000000..489bba2 --- /dev/null +++ vm/jitrino/src/jet/mib.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief MethodInfoBlock implementaion. + */ + +#include "mib.h" + +namespace Jitrino { +namespace Jet { + +MethodInfoBlock::MethodInfoBlock(void) +{ + m_data = NULL; + // + rt_inst_addrs = NULL; + // + rt_header = &m_header; + rt_header->code_start = NULL; +} + +void MethodInfoBlock::init(unsigned bc_size, unsigned stack_max, + unsigned num_locals, unsigned in_slots, + unsigned flags) +{ + memset(rt_header, 0, sizeof(*rt_header)); + rt_header->magic = MAGIC; + // + rt_header->m_bc_size = bc_size; + rt_header->m_num_locals = num_locals; + rt_header->m_max_stack_depth = stack_max; + rt_header->m_in_slots = in_slots; + rt_header->m_flags = flags; + + // All the values must be initialized *before* get_dyn_size() ! + unsigned dyn_size = get_dyn_size(); + m_data = new char[dyn_size]; + memset(m_data, 0, dyn_size); + rt_inst_addrs = (const char**)m_data; +} + +void MethodInfoBlock::save(char * to) +{ + memset(to, 0, get_total_size()); + memcpy(to, rt_header, get_hdr_size()); + memcpy(to + get_hdr_size(), m_data, get_dyn_size()); + rt_inst_addrs = (const char**)(to + get_hdr_size()); +} + +const char * MethodInfoBlock::get_ip(unsigned pc) const +{ + assert(pc < rt_header->m_bc_size); + return (char*)rt_inst_addrs[pc]; +} + +unsigned MethodInfoBlock::get_pc(const char * ip) const +{ + const char ** data = rt_inst_addrs; + // + // Binary search performed, in its classical form - with 'low' + // and 'high'pointers, and plus additional steps specific to the nature + // of the data stored. + // The array where the search is performed, may (and normally does) have + // repetitive values: i.e. [ABBBCDEEFFF..]. Each region with the same + // value relate to the same byte code instruction. + + int l = 0; + int max_idx = (int)rt_header->m_bc_size-1; + int r = max_idx; + int m = 0; + const char * val = NULL; + // + // Step 1. + // Find first element which is above or equal to the given IP. + // + while (l<=r) { + m = (r+l)/2; + val = *(data+m); + assert(val != NULL); + if (ip<val) { + r = m-1; + } + else if(ip>val) { + l = m+1; + } + else { + break; + } + } + + //here, 'val' is '*(data+m)' + + // Step 2. + // If we found an item which is less or equal than key, then this step + // is omitted. + // If an item greater than key found, we need small shift to the previous + // item: + // [ABBB..] if we find any 'B', which is > key, then we need to step back + // to 'A'. + // + if (val > ip) { + // Find very first item of the same IP value (very first 'B' in the + // example) - this is the beginning of the bytecode instruction + while (m && val == *(data+m-1)) { + --m; + } + // here, 'm' points to the first 'B', and 'val' has its value ... + if (m) { + --m; + } + // ... and here 'm' points to last 'A' + val = *(data+m); + } + + // Step 3. + // Find very first item in the range - this is the ûåôêå of the bytecode + // instruction + while (m && val == *(data+m-1)) { + --m; + } + return m; +} + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/mib.h vm/jitrino/src/jet/mib.h new file mode 100644 index 0000000..9bad7de --- /dev/null +++ vm/jitrino/src/jet/mib.h @@ -0,0 +1,525 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Declaration of MethodInfoBlock. + */ + +#if !defined(__MIB_H_INCLUDED__) +#define __MIB_H_INCLUDED__ + +#include "enc.h" + +namespace Jitrino { +namespace Jet { + +/** + * @brief Controls generic information about compiled method. + * + * The MethodInfoBlock instance manages a general (platform-independent) + * info about compiled method. This info includes: flags the method was + * compiled with, max stack depth, number of local variables and size of + * input argsuments, sizes of byte code and native code, and a mapping + * between native and byte code. + * + * The MethodInfoBlock instances used during both compilation and execution. + * + * When used during compile time, an instance of MethodInfoBlock \link #init + * allocates \endlink memory (via malloc call) to temporary store method's + * data. During compilation, this temporary data is filled with method's + * information. Then, Compiler allocates the same amount of memory (method's + * info block) via VM's call, and \link #save copies \endlink the data there. + * The memory is then must be deallocated explicitly by #release call. + * + * When data is stored into a buffer, it stores + * \link MethodInfoBlock::BlockHeader a header of fixed size \endlink, and + * then variable size data. Currently, only a mapping between byte code and + * native addresses is stored as variable sized data. + * + * When used during runtime, the instances of MethodInfoBlock are normally + * \link #MethodInfoBlock(char * pdata) initialized\endlink from the info + * block. + * + * A mapping between native and byte code (#rt_inst_addrs) is organized as + * a plain array of \b char* type and with the number of elements equal to + * the size of bytecode. + * + * For each bytecode instruction, given its program counter (PC), an array + * element at [PC] points to the beginning of the native code for this + * instruction. If the bytecode instruction occupies more than one byte, + * say, PC+1, ..., PC+N, then corresponding array elements at PC+1, ... + * PC+N, also point to the beginning of the native code for the instruction. + * + * Finding an IP by a given PC is trivial, it's \a rt_inst_addrs[PC]. + * + * Finding an PC provided with an IP, requires a seach in the rt_inst_addrs + * array. Luckily, layout of the native code is exactly the same as byte + * code layout, so the \a rt_inst_addrs array is surely sorted in ascending + * order. The binary search is implemented in #get_pc. + * + * @todo the size of info block is known at the very beginning. may + * eliminate this additional malloc()+free() during compilation, so + * allocate the info block, and then operate directly with it. + */ +class MethodInfoBlock { +public: + /** + * @brief Initializes an empty instance of MethodInfoBlock. + */ + MethodInfoBlock(void); + + /** + * @brief Loads info about the method. + * + * Initializes instance of MethodInfoBlock by \link #load loading \endlink + * info from \a pdata, provided that \a pdata points to a valid method's + * data. + * + * @param pdata - pointer to a data to load from + */ + MethodInfoBlock(char * pdata) { + assert(is_valid_data(pdata)); + m_data = NULL; + load(pdata); + } + + /** + * @brief Cleanup, deallocates memory allocated for data. + */ + ~MethodInfoBlock() + { + assert (m_data == NULL); + } + + /** + * @brief Tests whether the provided pointer points to a valid method's + * data (method's info block). + * + * @param p - a pointer to data to test + * @return \b true if data recognized as valid, \b false otherwise. + */ + static bool is_valid_data(const char * p) + { + return MAGIC == ((BlockHeader*)p)->magic; + } + + /** + * @brief Initializes an instance of MethodInfoBlock, and allocates memory + * to temporary store data during compilation. + * + * @note If #init() called, then + * <span style="color: red; text-decoration: underline">caller + * must explicitly call #release()</span> method before object + * goes out of scope. This is to avoid call of 'delete[]' in + * destructor which slows down runtime stuff, i.e. #rt_unwind(). + * + * @param bc_size - size of byte code + * @param stack_max - max stack depth + * @param num_locals - number of slots occupied by local variables + * @param in_slots - number of slots occupied by input args + * @param flags - flags, the method was compiled with + */ + void init(unsigned bc_size, unsigned stack_max, unsigned num_locals, + unsigned in_slots, unsigned flags); + /** + * @brief Releases resources allocated by #init(). + * + * @note If #init() called, then + * <span style="color: red; text-decoration: underline">caller + * must explicitly call #release()</span> method before object + * goes out of scope. This is to avoid call of 'delete[]' in + * destructor which slows down runtime stuff, i.e. #rt_unwind(). + */ + void release(void) + { + delete[] m_data; + m_data = NULL; + } + + /** + * @brief Sets a native address for the given bytecode PC. + * @param pc - bytecode program counter + * @param addr - native address for the given bytecode + */ + void set_code_info(unsigned pc, const char * addr) + { + rt_inst_addrs[pc] = addr; + } + + /** + * @brief Returns an IP previously stored by #set_code_info. + * @param pc - byte code PC + * @return an IP stored for the given PC + */ + const char* get_code_info(unsigned pc) const + { + return rt_inst_addrs[pc]; + } + + /** + * @brief Returns number of slots occupied by input args. + * @return number of slots occupied by input args. + */ + unsigned get_in_slots(void) const + { + return rt_header->m_in_slots; + } + + /** + * @brief Returns size of bytecode. + * @return size of bytecode, in bytes + */ + unsigned get_bc_size(void) const + { + return rt_header->m_bc_size; + } + + /** + * @brief Returns number of slots occupied by local variables. + * @return number of slots occupied by local variables + */ + unsigned get_num_locals(void) const + { + return rt_header->m_num_locals; + } + + /** + * @brief Returns max stack depth. + * @return max stack depth + */ + unsigned get_stack_max(void) const + { + return rt_header->m_max_stack_depth; + } + + /** + * @brief Returns flags the method compiled with. + * @return flags the method was compiled with + */ + unsigned get_flags(void) const + { + return rt_header->m_flags; + } + + /** + * @brief Sets flags the method flags. + * @param _flags - flags the method compiled with + */ + void set_flags(unsigned _flags) const + { + rt_header->m_flags = _flags; + } + + /** + * @brief Returns total size needed to store the whole runtime info. + * @return size needed to store the whole runtime info + */ + unsigned get_total_size(void) const + { + return get_hdr_size() + get_dyn_size(); + } + /** + * @brief Sets a length of 'warm-up code'. + * @see BlockHeader::warmup_len + */ + void set_warmup_len(unsigned len) + { + rt_header->warmup_len = len; + } + + /** + * @brief Returns a length of the 'warm-up code'. + * @see BlockHeader::warmup_len + */ + unsigned get_warmup_len(void) const + { + return rt_header->warmup_len; + } + + /** + * @brief Sets code start address. + */ + void set_code_start(char* code) + { + rt_header->code_start = code; + } + + /** + * @brief Returns code start address. + */ + char* get_code_start(void) + { + return rt_header->code_start; + } + + /** + * @brief Copies MethodInfoBlock's data into a buffer. + * + * @note The provided buffer must be not less than #get_total_size + * bytes long. It's the caller's responsibility to ensure the + * proper capacity. + * + * @param to - points to a buffer to copy data into + */ + void save(char * to); + + /** + * @brief Loads MethodInfoBlock's data from a buffer. + * + * @note The \a from must point to \link #is_valid_data a valid + * data \endlink. If this condition not met, behavior is + * unpredictable. + * @param from - points to a buffer to load data from + */ + void load(char * from) + { + // Actually, there must be no ways in Compiler when a + // MethodInfoBlock's instance initialized via init() call (which + // sets m_data) is later used with a load() call. + // This is not a problem itself, just *highly* unexpected usage of + // MethodInfoBlock. So, this assert() just to force this presumption. + // If something changes, and there is a need to reuse the same + // MethodInfoBlock instance, then feel free to remove this assert(). + // and **UNCOMMENT the delete[]** + assert(m_data == NULL); + //delete[] m_data; m_data = NULL; // just for sure + + rt_header = (BlockHeader*)from; + rt_inst_addrs = (const char**)(from + get_hdr_size()); + } + + /** + * @brief Returns an IP for a given PC. + * + * Returns address of the first native instruction generated for byte + * code instruction located at the provided program counter (PC). + * + * @note The provided PC must be valid (means be \link #get_bc_size in + * range\endlink). Otherwise, behavior is unpredictable. + * + * @param pc - bytecode program counter (PC) + * @return IP for the given PC + */ + const char * get_ip(unsigned pc) const; + + /** + * @brief Returns PC for a given IP. + * + * Returns a byte code program counter (PC) for a given native + * address (IP). + * + * @note The provided address must be valid (means must belong to the + * code generated for this method). Otherwise, behavior is + * unpredictable. + * + * @param ip - native IP + * @return found PC + */ + unsigned get_pc(const char * ip) const; + + /** + * @brief Sets a flag that the given AR was spilled during method's + * prolog. + */ + void saved(AR gr) + { + assert(word_no(ar_idx(gr))<COUNTOF(rt_header->saved_regs)); + unsigned * p = rt_header->saved_regs; + set(p, ar_idx(gr)); + } + + /** + * @brief Tests whether the given AR was spilled during method's + * prolog. + */ + bool is_saved(AR gr) const + { + assert(word_no(ar_idx(gr))<COUNTOF(rt_header->saved_regs)); + unsigned * p = rt_header->saved_regs; + return tst(p, ar_idx(gr)); + } + + /** + * @brief Returns direct pointer to the bit array with of saved + * registers. + */ + const char * saved_map(void) const + { + return (const char*)rt_header->saved_regs; + } +private: + /** + * @brief Returns size occupied by header. + * + * The header size is the same for all MethodInfoBlock instances. + * + * @return size occupied by header + */ + static unsigned get_hdr_size(void) + { + return sizeof(BlockHeader); + } + + /** + * @brief Calculates and returns size occupied by variable part of + * MethodInfoBlock. + * + * @note Obviously, all fields used to calculate the variable size + * must be initialized at this point. Currently, the variable + * part depends only on the value of BlockHeader::m_bc_size. + * + * @return size needed to store variable part of MethodInfoBlock. + */ + unsigned get_dyn_size(void) const + { + return sizeof(rt_inst_addrs[0])*rt_header->m_bc_size; + } + + /** + * @brief Disallows copying. + */ + MethodInfoBlock(const MethodInfoBlock&); + + /** + * @brief Disallows copying. + */ + MethodInfoBlock& operator=(const MethodInfoBlock&); + + /** + * @brief Initializes data from a buffer. + * + * The method simply stores addresses, which point to a header and to + * variable data. + * + * @note The buffer is not checked for validity. + * + * @param ptr - pointer to a buffer + */ + void init_from_ptr(char * ptr); + + /** + * @brief A signature used to control whether the info block is valid. + * + * Here, 'valid' means 'previously written via #save call' which, in turn, + * implies 'the method was compiled by Jitrino.JET'. + * + * The value itself is string \e .JET in hex. + */ + static const unsigned MAGIC = 0x2E4A4554; + + /** + * @brief A fixed header for the info controlled by #MethodInfoBlock. + */ + struct BlockHeader { + /** + * @brief Data signature. + * + * This field is used to control whether the info is valid (means + * stored by MethodInfoBlock). The valid data must have #MAGIC in + * this field. + */ + unsigned magic; + /** + * @brief Start address of native code. + */ + char * code_start; + /** + * @brief Size of native code, in bytes. + */ + unsigned m_code_len; + /** + * @brief Size of bytecode, in bytes. + */ + unsigned m_bc_size; + /** + * @brief Length of array of local variables. + */ + unsigned m_num_locals; + /** + * @brief Max depth of operand stack of the method. + */ + unsigned m_max_stack_depth; + /** + * @brief Number of slots occupied by input args. + */ + unsigned m_in_slots; + /** + * @brief Flags the method was compiled with. + */ + unsigned m_flags; + /** + * @brief A bit array of the flags whether a register was spilled + * in method's prolog (and thus need to be restored during + * unwinding). + */ + unsigned saved_regs[words(ar_total)]; + /** + * @brief Length of 'warm up code sequence'. + * + * The 'warm up code sequence' is very beginning of every method + * compiled by Jitrino.JET. This sequence prepares native stack + * frame and spills out necessary callee-save registers. The code + * does not change callee-save regs. + * + * If something terrible (i.e. stack overflow) happens during + * this sequence, then special unwinding procedure is performed - + * callee-save registers are not restored (as they are untouched). + * + * Beyond this point, a regular unwinding procedure is performed. + */ + unsigned warmup_len; + }; + /** + * @brief Pointer to a temporary buffer. The buffer is allocated in + * #init, and then deallocated in #~MethodInfoBlock. + */ + char * m_data; + /** + * @brief A header which is used during compile-time, to store the + * info. + */ + BlockHeader m_header; + /** + * @brief Pointer to a header structure. + * + * During compilation time it point to #m_header (set in #MethodInfoBlock), + * and during runtime it points into the buffer provided to #load. + */ + BlockHeader * rt_header; + /** + * @brief A mapping between byte code and native code addresses. + * + * The size is [bc_size]. + * + * During compilation time, it points to a buffer in #m_data (set in + * #init). During runtime, it points into the buffer provided to #load. + */ + const char ** rt_inst_addrs; // [bc_size] + char ** data_ips; // [m_num_datas] + unsigned* depths; // [m_num_datas] + unsigned* masks; // [m_num_datas*words(m_max_stack_depth)] +}; + + +}}; // ~namespace Jitrino::Jet + +#endif // ~__MIB_H_INCLUDED__ + diff --git vm/jitrino/src/jet/re_ia32.cpp vm/jitrino/src/jet/re_ia32.cpp deleted file mode 100644 index 9611a7a..0000000 --- vm/jitrino/src/jet/re_ia32.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Alexander V. Astapchuk - * @version $Revision: 1.1.12.3.4.4 $ - */ -#include "compiler.h" - -/** - * @file - * @brief Contains an implementation of register machinery for IA32/EM64T - * platforms. - */ - -namespace Jitrino { -namespace Jet { - -const RegName Compiler::g_frnames[F_STACK_REGS + F_LOCAL_REGS] = { - RegName_XMM0, RegName_XMM1, RegName_XMM2, - RegName_XMM3, RegName_XMM4, RegName_XMM5, -}; - -const RegName Compiler::g_irnames[I_STACK_REGS + I_LOCAL_REGS] = { - RegName_EBX, RegName_EDI, RegName_ESI, RegName_ECX, - RegName_EDX, RegName_EAX, -}; - -void Compiler::vpop(jtype jt) -{ - m_jframe->pop(jt); -} - -void Compiler::veax(void) -{ - static const unsigned idx = 1; - assert(g_irnames[idx+I_STACK_REGS] == RegName_EAX); - m_jframe->release(i32, idx); - vsync(); -} - -void Compiler::vedx(void) -{ - static const unsigned idx = 0; - assert(g_irnames[idx+I_STACK_REGS] == RegName_EDX); - m_jframe->release(i32, idx); - vsync(); -} - -void Compiler::vpush(jtype jt, bool sync) -{ - m_jframe->push(jt); - if (sync && m_jframe->need_update()) { - vsync(); - } -} - -EncoderBase::Operand Compiler::vmstack(unsigned depth) -{ - jtype jt = m_jframe->top(depth); - return EncoderBase::Operand( - typeInfo[jt].size, REG_BASE, - m_stack.stack_slot(m_jframe->depth2slot(depth))*STACK_SLOT_SIZE); -} - -EncoderBase::Operand Compiler::vstack_mem_slot(unsigned depth) -{ - jtype jt = i32; - return EncoderBase::Operand( - typeInfo[jt].size, REG_BASE, - m_stack.stack_slot(m_jframe->depth2slot(depth))*STACK_SLOT_SIZE); -} - - -EncoderBase::Operand Compiler::vmlocal(jtype jt, unsigned idx) -{ - return EncoderBase::Operand( - typeInfo[jt].size, REG_BASE, m_stack.local(idx)*STACK_SLOT_SIZE); -} - - -EncoderBase::Operand Compiler::vlocal(jtype jt, int idx, bool upper, - bool willDef) -{ - if (idx != -1 && !willDef) { - // use of existing var, can return memory location here - const JFrame::Slot& v = m_jframe->var(idx); - if (v.regid() == -1) { - // not on the reg, return memory - return vmlocal(jt, idx); - } - } - unsigned regid = m_jframe->alloc(jt, idx, upper, willDef); - vsync(); - assert(regid < m_jframe->_rlocalregs(jt)); - RegName r = get_regs(jt)[regid + m_jframe->_rstackregs(jt)]; - assert(NULL != getRegNameString(r)); - assert(jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[jt].size); - assert(NULL != getRegNameString(r)); - return EncoderBase::Operand(r); -} - -void Compiler::vsync(void) -{ - if (m_jframe->need_update()==0) { - return; - } - // scan stack - for (unsigned i=0; i<m_jframe->size(); i++) { - const JFrame::Slot& s = m_jframe->dip(i); - if (s.state()&SS_NEED_SWAP) { - assert(s.regid() != -1); - RegName r = get_regs(s.jt)[s.regid()]; - assert(s.jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[s.jt].size); - voper(typeInfo[s.jt].mov, vmstack(i), r); - m_jframe->stack_state(i, SS_SWAPPED, SS_NEED_SWAP); - } - else if (s.state()&SS_NEED_UPLOAD) { - assert(false); // should not happen on stack slots - //voper(typeInfo[s.jt].mov, vmstack(i), r); - //m_jframe->stack_state(i, 0, SS_NEED_UPLOAD); - } - } - // scan locals - for (unsigned i=0; i<m_jframe->num_vars(); i++) { - const JFrame::Slot& s = m_jframe->var(i); - if (s.regid() < 0) { - continue; - } - RegName r = get_regs(s.jt)[s.regid() + m_jframe->_rstackregs(s.jt)]; - assert(s.jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[s.jt].size); - - if (s.state()&SS_NEED_SWAP) { - voper(typeInfo[s.jt].mov, vmlocal(s.jt, i), r); - m_jframe->var_state(i, SS_SWAPPED, SS_NEED_SWAP); - } - else if (s.state()&SS_NEED_UPLOAD) { - voper(typeInfo[s.jt].mov, r, vmlocal(s.jt,i)); - m_jframe->var_state(i, 0, SS_NEED_UPLOAD); - } - } - assert(m_jframe->need_update()==0); -} - -void Compiler::vstack_swap(unsigned depth) -{ - const JFrame::Slot& s = m_jframe->dip(depth); - if (s.swapped()) { - return; - } - RegName r = get_regs(s.jt)[s.regid()]; - assert(s.jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[s.jt].size); - voper(typeInfo[s.jt].mov, vmstack(depth), r); - m_jframe->stack_state(depth, SS_SWAPPED, SS_NEED_SWAP); -} - -RegName Compiler::vstack(unsigned depth) -{ - assert(m_jframe->need_update() == 0); - const JFrame::Slot& s = m_jframe->dip(depth); - assert(s.regid() != -1 && s.vslot() != -1 && s.jt != jvoid); - - assert(m_jframe->regable(depth)); - RegName r = get_regs(s.jt)[s.regid()]; - assert(s.jt != i8); // to avoid cast of ESI/EDI/EBP to CH/DH/BH - r = getAliasReg(r, typeInfo[s.jt].size); - // the resulting name must be valid - assert(NULL != getRegNameString(r)); - if (s.swapped()) { - // bring it back from the memory - voper(typeInfo[s.jt].mov, r, vmstack(depth)); - m_jframe->stack_state(depth, 0, SS_SWAPPED); - } - return r; -} - -RegName Compiler::valias(jtype jt, RegName rbig) -{ - RegName rsmall; - if (jt==i8 && (rbig == RegName_ESI || rbig == RegName_EDI || - rbig == RegName_EBP)) { - // cant use low 8bit part of these register, need to transfer - // somewhere. requesting a scratch register for now, as they are - // known to be good from this point - EDX/EAX. - EncoderBase::Operand rscratch = vlocal(i32,-1,false,true); - voper(Mnemonic_MOV, rscratch, rbig); - rsmall = getAliasReg(rscratch.reg(), OpndSize_8); - } - else { - assert(jt<i32); - rsmall = getAliasReg(rbig, typeInfo[jt].size); - } - return rsmall; -} - -void Compiler::vdostack(Mnemonic mn, unsigned depth0, int depth1) -{ - assert(m_jframe->need_update() == 0); - RegName r0 = vstack(depth0); - - const JFrame::Slot& s = m_jframe->dip(depth1); - assert(s.regid() != -1 && s.vslot() != -1 && s.jt != jvoid); - assert(m_jframe->vslots(s.jt) - s.vslot() < m_jframe->_rstackregs(s.jt)); - if (s.swapped()) { - voper(mn, r0, vmstack(depth1)); - } - else { - voper(mn, r0, vstack(depth1)); - } -} - -bool Compiler::vlocal_on_mem(unsigned idx) -{ - const JFrame::Slot& v = m_jframe->var(idx); - if (v.jt == jvoid ) return true; - return v.regid() == -1 || v.swapped(); -} - - -}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/rt.cpp vm/jitrino/src/jet/rt.cpp index 50effac..78cf82a 100644 --- vm/jitrino/src/jet/rt.cpp +++ vm/jitrino/src/jet/rt.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.5.12.2.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** @@ -25,153 +25,419 @@ #include "compiler.h" #include "trace.h" -#include <jit_import.h> +#include "jet.h" + +#include "jit_import.h" +#include "jit_intf.h" + +#if !defined(_IPF_) +#include "enc_ia32.h" +#endif namespace Jitrino { namespace Jet { -MethodInfoBlock::MethodInfoBlock(void) + +bool rt_check_method(JIT_Handle jit, Method_Handle method) { - m_data = NULL; - // - rt_inst_addrs = NULL; - // - rt_header = &m_header; - rt_header->m_code_start = NULL; + char * pinfo = (char*)method_get_info_block_jit(method, jit); + return MethodInfoBlock::is_valid_data(pinfo); } -void MethodInfoBlock::init(unsigned bc_size, unsigned stack_max, - unsigned num_locals, unsigned in_slots, - unsigned flags) -{ +static JitFrameContext* dummyCTX = NULL; +static unsigned sp_off = (char*)devirt(sp, dummyCTX) - (char*)dummyCTX; +static unsigned ip_off = (char*)devirt(gr_x, dummyCTX) - (char*)dummyCTX; - // - rt_header->m_bc_size = bc_size; - rt_header->m_num_locals = num_locals; - rt_header->m_max_stack_depth = stack_max; - rt_header->m_in_slots = in_slots; - rt_header->m_flags = flags; +static const unsigned bp_off = (char*)devirt(bp, dummyCTX) - (char*)dummyCTX; +static const unsigned bp_idx = ar_idx(bp); +static const unsigned bp_bytes = word_no(bp_idx)*WORD_SIZE/CHAR_BIT; +static const unsigned bp_mask = 1<<bit_no(bp_idx); +static const int bp_spill_off = ((StackFrame*)NULL)->spill(bp); - // All the values must be initialized *before* get_dyn_size() ! - unsigned dyn_size = get_dyn_size(); - m_data = new char[dyn_size]; - memset(m_data, 0, dyn_size); - rt_inst_addrs = (const char**)m_data; - rt_lazy_refs = NULL; -} +#ifdef _IA32_ +// +static AR ebx = virt(RegName_EBX); +static const unsigned ebx_idx = ar_idx(ebx); +static const unsigned ebx_bytes = word_no(ebx_idx)*WORD_SIZE/CHAR_BIT; +static const unsigned ebx_mask = 1<<bit_no(ebx_idx); +static const int ebx_spill_off = ((StackFrame*)NULL)->spill(ebx); +// +static AR esi = virt(RegName_ESI); +static const unsigned esi_idx = ar_idx(esi); +static const unsigned esi_bytes = word_no(esi_idx)*WORD_SIZE/CHAR_BIT; +static const unsigned esi_mask = 1<<bit_no(esi_idx); +static const int esi_spill_off = ((StackFrame*)NULL)->spill(esi); +// +static AR edi = virt(RegName_EDI); +static const unsigned edi_idx = ar_idx(edi); +static const unsigned edi_bytes = word_no(edi_idx)*WORD_SIZE/CHAR_BIT; +static const unsigned edi_mask = 1<<bit_no(edi_idx); +static const int edi_spill_off = ((StackFrame*)NULL)->spill(edi); +// +#endif // _IA32_ -void MethodInfoBlock::save(char * to) + +/** + * @brief Prints out a message to identify a program location. + * + * The message includes method name and class, IP and PC of the location. + * Message is preceded with the specified \c name. + * The function uses #dbg and does not print out new-line character. + */ +static void rt_trace(const char * name, Method_Handle meth, + const MethodInfoBlock& infoBlock, + const JitFrameContext * context) { - memset(to, 0, get_total_size()); - memcpy(to, rt_header, get_hdr_size()); - memcpy(to + get_hdr_size(), m_data, get_dyn_size()); - rt_inst_addrs = (const char**)(to + get_hdr_size()); - if (rt_header->m_num_refs != 0) { - rt_lazy_refs = rt_inst_addrs + rt_header->m_bc_size; - } - else { - rt_lazy_refs = NULL; + void *** pip = devirt(gr_x, context); + char * ip = (char*)**pip; + char * where = ip; + if (context->is_ip_past) { + --where; } + dbg_rt("%s @ %s::%s @ %p/%u: ", + name, + class_get_name(method_get_class(meth)), method_get_name(meth), + ip, infoBlock.get_pc(where)); } -const char * MethodInfoBlock::get_ip(unsigned pc) const +void rt_unwind(JIT_Handle jit, Method_Handle method, + JitFrameContext * context) { - assert(pc < rt_header->m_bc_size); - return (char*)rt_inst_addrs[pc]; + char * pinfo = (char*)method_get_info_block_jit(method, jit); + + assert(MethodInfoBlock::is_valid_data(pinfo)); + + MethodInfoBlock infoBlock(pinfo); + StackFrame sframe(infoBlock.get_num_locals(), + infoBlock.get_stack_max(), + infoBlock.get_in_slots()); + + JitFrameContext saveContextForLogs; + if (infoBlock.get_flags() & DBG_TRACE_RT) { + saveContextForLogs= *context; + } + + //void ** psp = (void**)devirt(sp, context); + void ** psp = (void**)((char*)context + sp_off); + char * sp_val = (char*)*psp; + + // here, gr_x means 'IP' + //void *** pip = devirt(gr_x, context); + void *** pip = (void***)((char*)context + ip_off); + + char * where = (char*)**pip; + if (context->is_ip_past) { + --where; + } + + // A special processing - mostly for StackOverflowError: + // if something terrible happens during the stack preparation sequence, + // then the registers are not saved yet, so we can't restore them from + // the JitFrameContext. The good news is that the callee-save registers + // are also untouched yet, so we only need to restore SP and IP + char * meth_start = infoBlock.get_code_start(); + unsigned whereLen = where - meth_start; + if (whereLen<infoBlock.get_warmup_len()) { + *psp = sp_val + sframe.size(); + // Now, [sp] = retIP + sp_val = (char*)*psp; + *pip = (void**)sp_val; + sp_val += STACK_SLOT_SIZE; // pop out the retIP + *psp = sp_val; + return; + } + + //void *** pbp = devirt(bp, context); + void *** pbp = (void***)((char*)context + bp_off); + char * bp_val = (char*)(**pbp); + + assert(!(infoBlock.get_flags() & JMF_SP_FRAME)); // not yet + + // restore sp + sp_val = bp_val; + // ^^^ now, sp has the same value as it was on method's entrance (points + // to retIP) + *pip = (void**)sp_val; + + // + // restore callee-save regs + // +#ifdef _DEBUG + // presumption: only GP registers can be callee-save + static bool do_check = true; + for (unsigned i=0; do_check && i<ar_num; i++) { + AR ar = _ar(i); + assert(!is_callee_save(ar) || is_gr(ar)); + } + do_check = false; +#endif + +#if defined(_EM64T_) || defined(_IPF_) + // Common version for all platforms but IA32 + for (unsigned i=0; i<gr_num; i++) { + AR ar = _gr(i); + if (infoBlock.is_saved(ar)) { + void *** preg = devirt(ar, context); + assert(preg && *preg); + *preg = (void**)(sp_val+sframe.spill(ar)); + if (infoBlock.get_flags() & DBG_TRACE_RT) { + dbg_rt("\trt.unwind.%s.%s: [%p]=%p\n", + Encoder::to_str(ar, false).c_str(), + Encoder::to_str(ar, true).c_str(), *preg, **preg); + } + } + } +#else + // + // Highly optimized version for IA32 - the loop of 4 callee-save + // register is unrolled, every constant value is precomputed and + // cached. + // + unsigned map_off, mask; + int spill_off; + // + const char * map = infoBlock.saved_map(); + // + // + map_off = bp_bytes; mask = bp_mask; spill_off = bp_spill_off; + // bp is always saved + assert(*(unsigned*)(map+map_off) & mask); + { + context->p_ebp = (unsigned*)(sp_val + spill_off); + } + // + // + map_off = ebx_bytes; mask = ebx_mask; spill_off = ebx_spill_off; + if (*(unsigned*)(map+map_off) & mask) { + context->p_ebx = (unsigned*)(sp_val + spill_off); + } + // + // + map_off = esi_bytes; mask = esi_mask; spill_off = esi_spill_off; + if (*(unsigned*)(map+map_off) & mask) { + context->p_esi = (unsigned*)(sp_val + spill_off); + } + // + // + map_off = edi_bytes; mask = edi_mask; spill_off = edi_spill_off; + if (*(unsigned*)(map+map_off) & mask) { + context->p_edi = (unsigned*)(sp_val + spill_off); + } +#endif + + sp_val += STACK_SLOT_SIZE; // pop out retIP + *psp = sp_val; + + if (infoBlock.get_flags() & DBG_TRACE_RT) { + void *** pip = devirt(gr_x, context); + rt_trace("rt.unwind", method, infoBlock, &saveContextForLogs); + dbg_rt("\t=>=> %p; SP=%p\n", **pip, sp_val); + } } -unsigned MethodInfoBlock::get_pc(const char * ip) const +void rt_enum(JIT_Handle jit, Method_Handle method, + GC_Enumeration_Handle henum, JitFrameContext * context) { - const char ** data = rt_inst_addrs; - // - // Binary search performed, in its classical form - with 'low' - // and 'high'pointers, and plus additional steps specific to the nature - // of the data stored. - // The array where the search is performed, may (and normally does) have - // repetitive values: i.e. [ABBBCDEEFFF..]. Each region with the same - // value relate to the same byte code instruction. - - int l = 0; - int max_idx = (int)rt_header->m_bc_size-1; - int r = max_idx; - int m = 0; - const char * val = NULL; - // - // Step 1. - // Find first element which is above or equal to the given IP. - // - while (l<=r) { - m = (r+l)/2; - val = *(data+m); - assert(val != NULL); - if (ip<val) { - r = m-1; + if (!context->is_ip_past) { + // The IP pointts directly to the instructions - this must be a + // hardware NPE happened. Check the presumption: + assert(method_get_num_handlers(method) == 0); +#ifdef _DEBUG + bool sync = method_is_synchronized(method); + bool inst = !method_is_static(method); + assert(!(sync && inst)); +#endif + // Nothing to report here - the method is about to exit. + return; + } + char * pinfo = (char*)method_get_info_block_jit(method, jit); + assert(MethodInfoBlock::is_valid_data(pinfo)); + + MethodInfoBlock infoBlock(pinfo); + assert(!(infoBlock.get_flags() & JMF_SP_FRAME)); // not yet + + void *** pip = (void***)((char*)context + ip_off); + char * where = (char*)**pip; + char * meth_start = infoBlock.get_code_start(); + unsigned whereLen = where - meth_start; + if (whereLen<infoBlock.get_warmup_len()) { + return; + } + + if (DBG_TRACE_RT & infoBlock.get_flags()) { + rt_trace("rt.enum.start", method, infoBlock, context); + } + StackFrame frame(infoBlock.get_num_locals(), infoBlock.get_stack_max(), + infoBlock.get_in_slots() ); + char * ebp = (char*)**devirt(bp, context); + // + // + // + unsigned * map = (unsigned*)(ebp + frame.info_gc_locals()); + for (unsigned i=0; i<infoBlock.get_num_locals(); i++) { + if (!tst(map, i)) { + continue; } - else if(ip>val) { - l = m+1; + void **p_obj = (void**)(ebp + frame.local(i)); + if (DBG_TRACE_RT & infoBlock.get_flags()) { + //rt_trace("gc.item", method, infoBlock, context); + dbg_rt("\tlocal#%d=>%p (%p)\n", i, p_obj, *p_obj); } - else { - break; + vm_enumerate_root_reference(p_obj, FALSE); + } + // + // Report input args with objects in it + // + map = (unsigned*)(ebp + frame.info_gc_args()); + for (unsigned i=0; i<infoBlock.get_in_slots(); i++) { + if (!tst(map, i)) { + continue; + } + void **p_obj = (void**)(ebp + frame.inargs()+i*STACK_SLOT_SIZE); + if (DBG_TRACE_RT & infoBlock.get_flags()) { + dbg_rt("\tin_arg#%d=>%p (%p)\n", i, p_obj, *p_obj); } + vm_enumerate_root_reference(p_obj, FALSE); + } + // + // + // + map = (unsigned*)(ebp + frame.info_gc_regs()); + unsigned obj_regs = *map; + // only one word is allocated to store a GC map for registers + assert(gr_num < WORD_SIZE); + for (unsigned i=0; i<WORD_SIZE; i++) { + if (obj_regs & 1) { + AR ar = _ar(i); + assert(is_gr(ar) && is_callee_save(ar)); + void ** p_obj; + p_obj = *devirt(ar, context); + if (DBG_TRACE_RT & infoBlock.get_flags()) { + //rt_trace("gc.item", method, infoBlock, context); + dbg_rt("\treg#%s#%s=>%p (%p)\n", + Encoder::to_str(ar, false).c_str(), + Encoder::to_str(ar, true).c_str(), + p_obj, *p_obj); + } + vm_enumerate_root_reference(p_obj, FALSE); + } + obj_regs >>= 1; } - //here, 'val' is '*(data+m)' + map = (unsigned*)(ebp + frame.info_gc_stack()); + unsigned rt_stack_depth = *(unsigned*)(ebp+frame.info_gc_stack_depth()); - // Step 2. - // If we found an item which is less or equal than key, then this step - // is omitted. - // If an item greater than key found, we need small shift to the previous - // item: - // [ABBB..] if we find any 'B', which is > key, then we need to step back - // to 'A'. - // - if (val > ip) { - // Find very first item of the same IP value (very first 'B' in the - // example) - this is the beginning of the bytecode instruction - while (m && val == *(data+m-1)) { - --m; + for (unsigned i=0; i<rt_stack_depth; i++) { + if (!tst(map, i)) { + continue; } - // here, 'm' points to the first 'B', and 'val' has its value ... - if (m) { - --m; + void ** p_obj; + p_obj = (void**)(ebp + frame.stack_slot(i)); + if (DBG_TRACE_RT & infoBlock.get_flags()) { + //rt_trace("gc.item", method, infoBlock, context); + dbg_rt("\tstack#%d=>%p (%p)\n", i, p_obj, *p_obj); } - // ... and here 'm' points to last 'A' - val = *(data+m); + vm_enumerate_root_reference(p_obj, FALSE); + } + + if (infoBlock.get_flags() & JMF_REPORT_THIS) { + void ** p_obj = (void**)rt_get_address_of_this(jit, method, context); + if (DBG_TRACE_RT & infoBlock.get_flags()) { + //rt_trace("gc.item", method, infoBlock, context); + dbg_rt("\tin.this#=>%p (%p)\n", p_obj, *p_obj); + } + vm_enumerate_root_reference(p_obj, FALSE); + } + if (DBG_TRACE_RT & infoBlock.get_flags()) { + rt_trace("rt.enum.done", method, infoBlock, context); + } +} + +void rt_fix_handler_context(JIT_Handle jit, Method_Handle method, + JitFrameContext * context) +{ + char * pinfo = (char*)method_get_info_block_jit(method, jit); + + assert(MethodInfoBlock::is_valid_data(pinfo)); + // + MethodInfoBlock infoBlock(pinfo); + assert(!(infoBlock.get_flags() & JMF_SP_FRAME)); // not yet + + void *** pip = (void***)((char*)context + ip_off); + char * where = (char*)**pip; + char * meth_start = infoBlock.get_code_start(); + unsigned whereLen = where - meth_start; + if (whereLen<infoBlock.get_warmup_len()) { + return; } - // Step 3. - // Find very first item in the range - this is the start of the bytecode - // instruction - while (m && val == *(data+m-1)) { - --m; + StackFrame sframe(infoBlock.get_num_locals(), + infoBlock.get_stack_max(), + infoBlock.get_in_slots()); + + unsigned frameSize = sframe.size(); + + void ** psp = (void**)devirt(sp, context); + void *** pbp = devirt(bp, context); + char * bp_val = (char*)(**pbp); + char * sp_val = bp_val - frameSize; + if (infoBlock.get_flags() & DBG_TRACE_RT) { + rt_trace("rt.fix_handler", method, infoBlock, context); + dbg_rt("oldESP=%p ; newESP=%p\n", *psp, sp_val); } - return m; + *psp = sp_val; } -bool rt_check_method(JIT_Handle jit, Method_Handle method) +void * rt_get_address_of_this(JIT_Handle jit, Method_Handle method, + const JitFrameContext * context) { char * pinfo = (char*)method_get_info_block_jit(method, jit); - return MethodInfoBlock::is_valid_data(pinfo); + + assert(MethodInfoBlock::is_valid_data(pinfo)); + // + MethodInfoBlock infoBlock(pinfo); + assert(!(infoBlock.get_flags() & JMF_SP_FRAME)); // not yet + + void *** pip = (void***)((char*)context + ip_off); + char * where = (char*)**pip; + char * meth_start = infoBlock.get_code_start(); + unsigned whereLen = where - meth_start; + if (whereLen<infoBlock.get_warmup_len()) { + return NULL; + } + + // We did not store 'this' specially + if (!(infoBlock.get_flags() & JMF_REPORT_THIS)) { + return NULL; + } + StackFrame stackframe(infoBlock.get_num_locals(), + infoBlock.get_stack_max(), + infoBlock.get_in_slots()); + + void *** pbp = devirt(bp, context); + char * bp_val = (char*)(**pbp); + void ** p_obj = (void**)(bp_val + stackframe.thiz()); + + if (infoBlock.get_flags() & DBG_TRACE_RT) { + void ** psp = (void**)devirt(sp, context); + char * sp_val = (char*)*psp; + rt_trace("rt.get_thiz", method, infoBlock, context); + dbg_rt("p_thiz=%p, thiz=%p (sp=%p)\n", p_obj, p_obj ? *p_obj : NULL, sp_val); + } + return p_obj; } void rt_bc2native(JIT_Handle jit, Method_Handle method, unsigned short bc_pc, void ** pip) { char * pinfo = (char*)method_get_info_block_jit(method, jit); - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return; - } + assert(MethodInfoBlock::is_valid_data(pinfo)); - MethodInfoBlock rtinfo; - rtinfo.load(pinfo); - if (bc_pc >= rtinfo.get_bc_size()) { - assert(false); - return; - }; + MethodInfoBlock rtinfo(pinfo); + assert(bc_pc < rtinfo.get_bc_size()); *pip = (void*)rtinfo.get_ip(bc_pc); if (rtinfo.get_flags() & DBG_TRACE_RT) { - dbg("rt.bc2ip: @ %u => %p\n", bc_pc, *pip); + dbg_rt("rt.bc2ip: @ %u => %p\n", bc_pc, *pip); } } @@ -179,16 +445,104 @@ void rt_native2bc(JIT_Handle jit, Method unsigned short * pbc_pc) { char * pinfo = (char*)method_get_info_block_jit(method, jit); - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return; - } + assert(MethodInfoBlock::is_valid_data(pinfo)); MethodInfoBlock rtinfo(pinfo); *pbc_pc = (unsigned short)rtinfo.get_pc((char*)ip); if (rtinfo.get_flags() & DBG_TRACE_RT) { - dbg("rt.ip2bc: @ 0x%p => %d\n", ip, *pbc_pc); + dbg_rt("rt.ip2bc: @ 0x%p => %d\n", ip, *pbc_pc); + } +} + +::OpenExeJpdaError rt_get_local_var(JIT_Handle jit, Method_Handle method, + const ::JitFrameContext *context, + unsigned var_num, VM_Data_Type var_type, + void *value_ptr) +{ + // + //FIXME: + // Current implementation will work incorrectly with local variables + // cached on registers and with variables that reuse input args slots. + // + // Need to store regs=>locals into MethodInfo block and also + // locals=>input args (or invent a simple algorithm of how to detect + // this mapping during runtime). + // + + char * pinfo = (char*)method_get_info_block_jit(method, jit); + assert(MethodInfoBlock::is_valid_data(pinfo)); + MethodInfoBlock infoBlock(pinfo); + if (var_num >= infoBlock.get_num_locals()) { + return EXE_ERROR_INVALID_SLOT; } + StackFrame frame(infoBlock.get_num_locals(), + infoBlock.get_stack_max(), + infoBlock.get_in_slots()); + + char * ebp = (char*)**devirt(bp, context); + unsigned * map = (unsigned*)(ebp + frame.info_gc_locals()); + + uint64* var_ptr_to_64; + uint32* var_ptr_to32; + + switch(var_type) { + case VM_DATA_TYPE_INT64: + case VM_DATA_TYPE_UINT64: + case VM_DATA_TYPE_F8: + var_ptr_to_64 = (uint64*)value_ptr; + *var_ptr_to_64 = *(uint64*)(ebp + frame.local(var_num)); + break; + case VM_DATA_TYPE_ARRAY: + case VM_DATA_TYPE_CLASS: + if (!tst(map, var_num)) { + return EXE_ERROR_TYPE_MISMATCH; + } + default: + var_ptr_to32 = (uint32*)value_ptr; + *var_ptr_to32 = *(uint32*)(ebp + frame.local(var_num)); + } + return EXE_ERROR_NONE; +} + +::OpenExeJpdaError rt_set_local_var(JIT_Handle jit, Method_Handle method, + const ::JitFrameContext *context, + unsigned var_num, VM_Data_Type var_type, + void *value_ptr) +{ + char * pinfo = (char*)method_get_info_block_jit(method, jit); + assert(MethodInfoBlock::is_valid_data(pinfo)); + MethodInfoBlock infoBlock(pinfo); + if (var_num >= infoBlock.get_num_locals()) { + return EXE_ERROR_INVALID_SLOT; + } + StackFrame frame(infoBlock.get_num_locals(), + infoBlock.get_stack_max(), + infoBlock.get_in_slots()); + + + char * ebp = (char*)**devirt(bp, context); + uint64* var_ptr_to_64; + uint32* var_ptr_to32; + + switch(var_type) { + case VM_DATA_TYPE_INT64: + case VM_DATA_TYPE_UINT64: + case VM_DATA_TYPE_F8: +#ifdef _EM64T_ + case VM_DATA_TYPE_ARRAY: + case VM_DATA_TYPE_CLASS: + case VM_DATA_TYPE_STRING: +#endif + var_ptr_to_64 = (uint64*)(ebp + frame.local(var_num)); + *var_ptr_to_64 = *(uint64*)value_ptr; + break; + default: + var_ptr_to32 = (uint32*)(ebp + frame.local(var_num)); + *var_ptr_to32 = *(uint32*)value_ptr; + } + + return EXE_ERROR_NONE; } -};}; // ~namespace Jitrino::Jet +}}; // ~namespace Jitrino::Jet + diff --git vm/jitrino/src/jet/rt.h vm/jitrino/src/jet/rt.h index 728af94..3f3121a 100644 --- vm/jitrino/src/jet/rt.h +++ vm/jitrino/src/jet/rt.h @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** @@ -25,447 +25,16 @@ #if !defined(__RT_H_INCLUDED__) #define __RT_H_INCLUDED__ +#include "enc.h" +#include "jit_export_rt.h" // for JitFrameContext + namespace Jitrino { namespace Jet { -/** - * @brief Controls various information about compiled method. - * - * The MethodInfoBlock instance manages a general (platform-independent) - * info about compiled method. This info includes: flags the method was - * compiled with, max stack depth, number of local variables and size of - * input argsuments, sizes of byte code and native code, and a mapping - * between native and byte code. - * - * The MethodInfoBlock instances used during both compilation and execution. - * - * When used during compile time, an instance of MethodInfoBlock \link - * #init allocates \endlink memory (via malloc call) to temporary store - * method's data. During compilation, this temporary data is filled with - * method's information. Then, #::Jitrino::Jet::Compiler allocates the same - * amount of memory (method's info block) via VM's call, and \link #save - * copies \endlink the data there. - * - * The memory then must be deallocated via explicit #release() call. - * - * When data is stored into a buffer, it stores a header of fixed size, and - * then variable size data. Currently, a mapping between byte code and - * native addresses is stored as variable sized data. Also additional space - * used for lazy resolution is allocated (when lazy resolution is in use). - * - * When used during runtime, the instances of MethodInfoBlock are normally - * \link #MethodInfoBlock(char * pdata) initialized\endlink from the info - * block. - * - * A mapping between native and byte code is organized as a plain array - * (namely \a rt_inst_addrs) of \b char* type and with the number of - * elements equal to the size of bytecode. - * - * For each bytecode instruction, given its program counter (PC), an array - * element at [PC] points to the beginning of the native code for this - * instruction. If the bytecode instruction occupies more than one byte, - * say, PC+1, ..., PC+N, then corresponding array elements at PC+1, ... - * PC+N, also point to the beginning of the native code for the instruction. - * - * So, finding an IP by a given PC is trivial, it's \a rt_inst_addrs[PC]. - * - * Finding an PC provided with an IP, requires a seach in the \a - * rt_inst_addrs array. Luckily, layout of the native code is exactly the - * same as byte codelayout, so the \a rt_inst_addrs array is surely sorted - * in ascending order. So, the binary search is implemented in #get_pc. - */ -class MethodInfoBlock { -public: - /** - * @brief Initializes an empty instance of MethodInfoBlock. - */ - MethodInfoBlock(void); - - /** - * @brief Loads info about the method. - * - * Initializes instance of MethodInfoBlock by \link #load loading - * \endlink info from \a pdata, provided that \a pdata points to a - * valid method's data. - * - * @param pdata - pointer to a data to load from - */ - MethodInfoBlock(char * pdata) { - assert(is_valid_data(pdata)); - m_data = NULL; - load(pdata); - } - - /** - * @brief Cleanup, deallocates memory allocated for data. - */ - ~MethodInfoBlock() { - // if init() called, then caller must explicitly call release() - assert (m_data == NULL); - } - - /** - * @brief Tests whether the provided pointer points to a valid method's - * data (method's info block). - * - * @param p - a pointer to data to test - * @return \b true if data recognized as valid, \b false otherwise. - */ - static bool is_valid_data(const char * p) { - return MAGIC == ((BlockHeader*)p)->magic; - } - - /** - * @brief Initializes an instance of MethodInfoBlock, and allocates - * memory to temporary store data during compilation. - * - * @note If #init() called, then - * <span style="color: red; text-decoration: underline">caller - * must explicitly call #release()</span> method before object - * goes out of scope. This is to avoid call of 'delete[]' in - * destructor which slows down runtime stuff, i.e. #rt_unwind(). - * - * @param bc_size - size of byte code - * @param stack_max - max stack depth - * @param num_locals - number of slots occupied by local variables - * @param in_slots - number of slots occupied by input args - * @param flags - flags, the method was compiled with - */ - void init(unsigned bc_size, unsigned stack_max, - unsigned num_locals, unsigned in_slots, - unsigned flags); - /** - * @brief Releases resources allocated by #init(). - * - * @note If #init() called, then - * <span style="color: red; text-decoration: underline">caller - * must explicitly call #release()</span> method before object - * goes out of scope. This is to avoid call of 'delete[]' in - * destructor which slows down runtime stuff, i.e. #rt_unwind(). - */ - void release(void) - { - delete[] m_data; - m_data = NULL; - } - - /** - * @brief Sets a native address for the given bytecode PC. - * @param pc - bytecode program counter - * @param addr - native address for the given bytecode - */ - void set_code_info(unsigned pc, const char * addr) - { - rt_inst_addrs[pc] = addr; - } - - /** - * @brief Returns an IP previously stored by #set_code_info. - * @param pc - byte code PC - * @return an IP stored for the given PC - */ - const char * get_code_info(unsigned pc) const - { - return rt_inst_addrs[pc]; - } - - /** - * @brief Returns number of slots occupied by input args. - * @return number of slots occupied by input args. - */ - unsigned get_in_slots(void) const - { - return rt_header->m_in_slots; - } - - /** - * @brief Returns size of bytecode. - * @return size of bytecode, in bytes - */ - unsigned get_bc_size(void) const - { - return rt_header->m_bc_size; - } - - /** - * @brief Returns number of slots occupied by local variables. - * @return number of slots occupied by local variables - */ - unsigned get_num_locals(void) const - { - return rt_header->m_num_locals; - } - - /** - * @brief Returns max stack depth. - * @return max stack depth - */ - unsigned get_stack_max(void) const - { - return rt_header->m_max_stack_depth; - } - - /** - * @brief Returns flags the method compiled with. - * @return flags the method was compiled with - */ - unsigned get_flags(void) const - { - return rt_header->m_flags; - } - - /** - * @brief Sets flags the method flags. - * @param _flags - flags the method compiled with - */ - void set_flags(unsigned _flags) const - { - rt_header->m_flags = _flags; - } - - /** - * @brief Returns total size needed to store the whole runtime info. - * @return size needed to store the whole runtime info - */ - unsigned get_total_size(void) const - { - // The total size to be allocated consists of header size + - // size needed to store bytecode-to-native mapping + - // size needed to store items for lazy resolution - return get_hdr_size() + get_dyn_size() + - sizeof(char*)*rt_header->m_num_refs; - } - - void set_num_refs(unsigned refs) - { - assert(rt_header->m_num_refs == 0); - rt_header->m_num_refs = refs; - } - unsigned get_num_refs(void) const - { - return rt_header->m_num_refs; - } - const char ** get_lazy_refs(void) - { - return rt_lazy_refs; - } - - /** - * @brief Copies MethodInfoBlock's data into a buffer. - * - * @note The provided buffer must be not less than #get_total_size - * bytes long. It's the caller's responsibility to ensure the - * proper capacity. - * - * @param to - points to a buffer to copy data into - */ - void save(char * to); - - /** - * @brief Loads MethodInfoBlock's data from a buffer. - * - * @note The \a from must point to \link #is_valid_data a valid - * data \endlink. If this condition not met, behavior is - * unpredictable. - * @param from - points to a buffer to load data from - */ - void load(char * from) - { - // Actually, there must be no ways in Compiler when a - // MethodInfoBlock's instance initialized via init() call (which - // sets m_data) is later used with a load() call. - // This is not a problem itself, just *highly* unexpected usage of - // MethodInfoBlock. So, this assert() just to force this - // presumption. - // If something changes, and there is a need to reuse the same - // MethodInfoBlock instance, then feel free to remove this assert(). - // and **UNCOMMENT the delete[]** - assert(m_data == NULL); - //delete[] m_data; // just for sure - - rt_header = (BlockHeader*)from; - rt_inst_addrs = (const char**)(from + get_hdr_size()); - // For lazy resolution, there is no need to access these items - // during runtime from C++ code. Thus eliminating memory access & - // branch - - //if (rt_header->m_num_refs != 0) { - // rt_lazy_refs = rt_inst_addrs + rt_header->m_bc_size; - //} - //else { - // rt_lazy_refs = NULL; - //} - } - - /** - * @brief Returns an IP for a given PC. - * - * Returns address of the first native instruction generated for byte - * code instruction located at the provided program counter (PC). - * - * @note The provided PC must be valid (means be \link #get_bc_size in - * range\endlink). Otherwise, behavior is unpredictable. - * - * @param pc - bytecode program counter (PC) - * @return IP for the given PC - */ - const char * get_ip(unsigned pc) const; - - /** - * @brief Returns PC for a given IP. - * - * Returns a byte code program counter (PC) for a given native - * address (IP). - * - * @note The provided address must be valid (means must belong to the - * code generated for this method). Otherwise, behavior is - * unpredictable. - * - * @param ip - native IP - * @return found PC - */ - unsigned get_pc(const char * ip) const; -private: - - /** - * @brief Returns size occupied by header. - * - * The header size is the same for all MethodInfoBlock instances. - * - * @return size occupied by header - */ - static unsigned get_hdr_size(void) - { - return sizeof(BlockHeader); - } - - /** - * @brief Calculates and returns size occupied by variable part of - * MethodInfoBlock. - * - * @note Obviously, all fields used to calculate the variable size - * must be initialized at this point. Currently, the variable - * part depends only on the value of BlockHeader::m_bc_size. - * - * @return size needed to store variable part of MethodInfoBlock. - */ - unsigned get_dyn_size(void) const - { - return sizeof(rt_inst_addrs[0])*rt_header->m_bc_size; - } - - /** - * @brief Disallows copying. - */ - MethodInfoBlock(const MethodInfoBlock&); - - /** - * @brief Disallows copying. - */ - MethodInfoBlock& operator=(const MethodInfoBlock&); - - /** - * @brief Initializes data from a buffer. - * - * The method simply stores addresses, which point to a header and to - * variable data. - * - * @note The buffer is not checked for validity. - * - * @param ptr - pointer to a buffer - */ - void init_from_ptr(char * ptr); - /** - * @brief A signature used to control whether the info block is valid. - * - * Here, 'valid' means 'previously written via #save call' which, in turn, - * implies 'the method was compiled by Jitrino.JET'. - * - * The value itself means nothing special. - */ - static const unsigned MAGIC = 0x0FD6DFB70; - /** - * @brief A fixed header for the info controlled by #MethodInfoBlock. - */ - struct BlockHeader { - /** - * @brief Noop, only initializes #magic field. - */ - BlockHeader() : magic(MAGIC) - { - m_num_refs = 0; - } +void *** devirt(AR gr, const JitFrameContext * jfc); - /** - * @brief Data signature. - * - * This field is used to control whether the info is valid (means - * stored by MethodInfoBlock). The valid data must have #MAGIC in this - * field. - */ - const unsigned magic; - /** - * @brief Start address of native code. - * @todo Seems redundant, must be equal to get_pc(0). remove ? - */ - char * m_code_start; - /** - * @brief Size of native code, in bytes. - */ - unsigned m_code_len; - /** - * @brief Size of bytecode, in bytes. - */ - unsigned m_bc_size; - /** - * @brief Number of slots occupied by local variables. - */ - unsigned m_num_locals; - /** - * @brief Max stack depth. - */ - unsigned m_max_stack_depth; - /** - * @brief Number of slots occupied by input args. - */ - unsigned m_in_slots; - /** - * @brief Flags the method was compiled with. - */ - unsigned m_flags; - /** - * @brief Number of items in rt_lazy_refs array. - */ - unsigned m_num_refs; - }; - /** - * @brief Pointer to a temporary buffer. The buffer is allocated in - * #init, and then deallocated in #~MethodInfoBlock. - */ - char * m_data; - /** - * @brief A header which is used during compile-time, to store the - * info. - */ - BlockHeader m_header; - /** - * @brief Pointer to a header structure. - * - * During compilation time it point to #m_header (set in #MethodInfoBlock), - * and during runtime it points into the buffer provided to #load. - */ - BlockHeader * rt_header; - /** - * @brief A mapping between byte code and native code addresses. - * - * During compilation time, it points to a buffer in #m_data (set in - * #init). During runtime, it points into the buffer provided to #load. - */ - const char ** rt_inst_addrs; // [bc_size] - const char ** rt_lazy_refs; // [m_num_refs] -}; }}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/rt_ia32.cpp vm/jitrino/src/jet/rt_ia32.cpp index 05fb2ef..18969bf 100644 --- vm/jitrino/src/jet/rt_ia32.cpp +++ vm/jitrino/src/jet/rt_ia32.cpp @@ -14,318 +14,68 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.6.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ -#include "compiler.h" -#include "trace.h" -#include "cg_ia32.h" -#include "jet.h" - -#include "jit_import.h" -#include "jit_intf.h" - -#ifdef _DEBUG -#include "jit_runtime_support.h" -#include "open/vm.h" -#endif - +#include "enc_ia32.h" +#include "jit_export_rt.h" /** * @file - * @brief Runtime support utilities which are platform-dependent and are - * specific for IA32/EM64T. + * @brief Implementation of runtime support routines specific for IA-32 + * Intel 64. */ namespace Jitrino { namespace Jet { -#define STACK_SLOT_SIZE (sizeof(long)) - -/** - * @brief Prints out a message to identify a program location. - * - * The message includes method name and class, IP and PC of the location. - * Message is preceded with the specified \c name. - * The function uses #dbg and does not print out new-line character. - */ -static void rt_trace(const char * name, Method_Handle meth, - const MethodInfoBlock& infoBlock, - const JitFrameContext * context) { - dbg("%s @ %s::%s @ %p/%u: ", - name, - class_get_name(method_get_class(meth)), method_get_name(meth), - *context->p_eip, infoBlock.get_pc((const char*)*context->p_eip)); -} -void rt_unwind(JIT_Handle jit, Method_Handle method, - JitFrameContext * context) +void *** devirt(AR gr, const JitFrameContext * jfc) { - char * pinfo = (char*)method_get_info_block_jit(method, jit); +#ifdef _EM64T_ + if (gr==gr_x) return (void***)&jfc->p_rip; + if (gr == sp) return (void***)&jfc->rsp; + if (gr == bp) return (void***)&jfc->p_rbp; - assert(MethodInfoBlock::is_valid_data(pinfo)); - - MethodInfoBlock infoBlock(pinfo); - StackFrame stackframe(infoBlock.get_num_locals(), - infoBlock.get_stack_max(), - infoBlock.get_in_slots()); - -#if defined(_DEBUG) || defined(JIT_LOGS) || defined(JET_PROTO) - JitFrameContext saveContext = *context; -#endif + RegName reg = devirt(gr, jvoid); - unsigned ebp = *context->p_ebp; - unsigned esp; - if (infoBlock.get_flags() & JMF_ALIGN_STACK) { - /* - mov smth, [ebp] ; get unaligned ESP - addr_of_this = smth + offsef_of_input_arg#0 - */ - esp = *(unsigned *)ebp; - } - else { - esp = ebp; - } - - //mov esp, ebp - context->esp = esp; - //pop ebp - context->p_ebp = ((unsigned*)context->esp) + stackframe.save_ebp(); - // pop edi - context->p_edi = ((unsigned*)context->esp) + stackframe.save_edi(); - // pop esi - context->p_esi = ((unsigned*)context->esp) + stackframe.save_esi(); - // pop ebx - context->p_ebx = ((unsigned*)context->esp) + stackframe.save_ebx(); - //pop out-the-IP - context->p_eip = ((unsigned*)context->esp) + stackframe.in_ret(); + if (reg == RegName_RBX) return (void***)&jfc->p_rbx; + if (reg == RegName_R12) return (void***)&jfc->p_r12; + if (reg == RegName_R13) return (void***)&jfc->p_r13; + if (reg == RegName_R14) return (void***)&jfc->p_r14; + if (reg == RegName_R15) return (void***)&jfc->p_r15; // - context->esp += 5 * SLOT_SIZE; // '5' here is 'ebp+edi+esi+ebx+retIP' -#if defined(_DEBUG) || defined(JIT_LOGS) || defined(JET_PROTO) - if (infoBlock.get_flags() & DBG_TRACE_RT) { - rt_trace("rt.unwind", method, infoBlock, &saveContext); - dbg("=> %p\n", *context->p_eip); - } + if (reg == RegName_RAX) return (void***)&jfc->p_rax; + if (reg == RegName_RCX) return (void***)&jfc->p_rcx; + if (reg == RegName_RDX) return (void***)&jfc->p_rdx; + if (reg == RegName_RSI) return (void***)&jfc->p_rsi; + if (reg == RegName_RDI) return (void***)&jfc->p_rdi; + if (reg == RegName_R8) return (void***)&jfc->p_r8; + if (reg == RegName_R9) return (void***)&jfc->p_r9; + if (reg == RegName_R10) return (void***)&jfc->p_r10; + if (reg == RegName_R11) return (void***)&jfc->p_r11; +#else + if (gr == gr_x) { return (void***)&jfc->p_eip; } + if (gr == sp) { return (void***)&jfc->esp; } + if (gr == bp) { return (void***)&jfc->p_ebp; } + + static AR eax = virt(RegName_EAX); + static AR ebx = virt(RegName_EBX); + static AR ecx = virt(RegName_ECX); + static AR edx = virt(RegName_EDX); + static AR esi = virt(RegName_ESI); + static AR edi = virt(RegName_EDI); + + if (gr == ebx) return (void***)&jfc->p_ebx; + if (gr == esi) return (void***)&jfc->p_esi; + if (gr == edi) return (void***)&jfc->p_edi; + if (gr == eax) return (void***)&jfc->p_eax; + if (gr == ecx) return (void***)&jfc->p_ecx; + if (gr == edx) return (void***)&jfc->p_edx; #endif + assert(false); + return NULL; } -void rt_enum(JIT_Handle jit, Method_Handle method, - GC_Enumeration_Handle henum, JitFrameContext * context) -{ - char * pinfo = (char*)method_get_info_block_jit(method, jit); - - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return; - } - - MethodInfoBlock infoBlock(pinfo); - - if (DBG_TRACE_RT & infoBlock.get_flags()) { - rt_trace("rt.enum.start", method, infoBlock, context); - } - if (infoBlock.get_flags() & JMF_EMPTY_RS) { - if (DBG_TRACE_RT & infoBlock.get_flags()) { - dbg("empty root set\n"); - } - return; - } - - if (DBG_TRACE_RT & infoBlock.get_flags()) { - dbg("\n"); - } - - StackFrame frame(infoBlock.get_num_locals(), infoBlock.get_stack_max(), - infoBlock.get_in_slots() ); - - long * ebp = (long*)(*context->p_ebp); - long * map = ebp + frame.info_gc_locals(); - - for (unsigned i=0; i<infoBlock.get_num_locals(); i++) { - if (!tst( (long*)map, i)) { - continue; - } - void **p_obj = (void**)(ebp + frame.local(i)); - if (DBG_TRACE_RT & infoBlock.get_flags()) { - rt_trace("gc.item", method, infoBlock, context); - dbg(": local#%d=>%X (%X)\n", i, p_obj, *p_obj); - } - vm_enumerate_root_reference(p_obj, FALSE); - } - - map = ebp + frame.info_gc_stack(); - unsigned rt_stack_depth = *(ebp+frame.info_gc_stack_depth()); - - for (unsigned i=0; i<rt_stack_depth; i++) { - if (!tst( map, i)) { - continue; - } - void ** p_obj; - p_obj = (void**)(ebp + frame.stack_slot(i)); - if (DBG_TRACE_RT & infoBlock.get_flags()) { - rt_trace("gc.item", method, infoBlock, context); - dbg(": stack#%d=>%X (%X)\n", i, p_obj, *p_obj); - } - vm_enumerate_root_reference(p_obj, FALSE); - } - - if (infoBlock.get_flags() & JMF_REPORT_THIS) { - void ** p_obj = (void**)rt_get_address_of_this(jit, method, context); - if (DBG_TRACE_RT & infoBlock.get_flags()) { - rt_trace("gc.item", method, infoBlock, context); - dbg(": in.this#=>%X (%X)\n", p_obj, *p_obj); - } - vm_enumerate_root_reference(p_obj, FALSE); - } - if (DBG_TRACE_RT & infoBlock.get_flags()) { - rt_trace("rt.enum.done", method, infoBlock, context); - dbg("\n"); - } -} - -void rt_fix_handler_context(JIT_Handle jit, Method_Handle method, - JitFrameContext * context) -{ - char * pinfo = (char*)method_get_info_block_jit(method, jit); - - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return; - } - // - MethodInfoBlock infoBlock(pinfo); - StackFrame stackframe(infoBlock.get_num_locals(), - infoBlock.get_stack_max(), - infoBlock.get_in_slots()); - - unsigned new_esp = *context->p_ebp + - (stackframe.native_stack_bot())*SLOT_SIZE; - if (infoBlock.get_flags() & DBG_TRACE_RT) { - rt_trace("rt.fix_handler", method, infoBlock, context); - dbg("oldESP=%p ; newESP=%p\n", context->esp, new_esp); - } - context->esp = new_esp; -} - -void * rt_get_address_of_this(JIT_Handle jit, Method_Handle method, - const JitFrameContext * context) -{ - char * pinfo = (char*)method_get_info_block_jit(method, jit); - assert(MethodInfoBlock::is_valid_data(pinfo)); - - MethodInfoBlock infoBlock(pinfo); - if (!(infoBlock.get_flags() & JMF_REPORT_THIS)) { - return NULL; - } - - StackFrame stackframe(infoBlock.get_num_locals(), - infoBlock.get_stack_max(), - infoBlock.get_in_slots()); - - - unsigned ebp = *context->p_ebp; - unsigned esp; - if (infoBlock.get_flags() & JMF_ALIGN_STACK) { - /* - mov smth, [ebp] ; get unaligned ESP - addr_of_this = smth + offsef_of_input_arg#0 - */ - esp = *(unsigned *)ebp; - } - else { - esp = ebp; - } - void ** p_obj = (void**)((char**)esp + stackframe.in_slot(0)); - - if (infoBlock.get_flags() & DBG_TRACE_RT) { - rt_trace("rt.get_thiz", method, infoBlock, context); - dbg("p_thiz=%p, thiz=%p\n", p_obj, p_obj ? *p_obj : NULL); - } - return p_obj; -} - -::OpenExeJpdaError rt_get_local_var(JIT_Handle jit, Method_Handle method, - const ::JitFrameContext *context, - unsigned var_num, VM_Data_Type var_type, - void *value_ptr) -{ - char * pinfo = (char*)method_get_info_block_jit(method, jit); - - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return EXE_ERROR_UNSUPPORTED; - } - - - MethodInfoBlock infoBlock(pinfo); - if (var_num >= infoBlock.get_num_locals()) { - return EXE_ERROR_INVALID_SLOT; - } - StackFrame stackframe(infoBlock.get_num_locals(), - infoBlock.get_stack_max(), - infoBlock.get_in_slots()); - - uint32* ebp = (uint32*)(*context->p_ebp); - uint64* var_ptr_to_64; - uint32* var_ptr_to32; - long* map = (long*) (ebp + stackframe.info_gc_locals()); - - switch(var_type) { - case VM_DATA_TYPE_INT64: - case VM_DATA_TYPE_UINT64: - case VM_DATA_TYPE_F8: - var_ptr_to_64 = (uint64*)value_ptr; - *var_ptr_to_64 = *(uint64*)(ebp + stackframe.local((unsigned)var_num)); - break; - case VM_DATA_TYPE_ARRAY: - case VM_DATA_TYPE_CLASS: - if (!tst((long*)map, var_num)) { - return EXE_ERROR_TYPE_MISMATCH; - } - default: - var_ptr_to32 = (uint32*)value_ptr; - *var_ptr_to32 = *(uint32*)(ebp + stackframe.local((unsigned)var_num)); - } - - return EXE_ERROR_NONE; -} - -::OpenExeJpdaError rt_set_local_var(JIT_Handle jit, Method_Handle method, - const ::JitFrameContext *context, - unsigned var_num, VM_Data_Type var_type, - void *value_ptr) -{ - char * pinfo = (char*)method_get_info_block_jit(method, jit); - - if (!MethodInfoBlock::is_valid_data(pinfo)) { - assert(false); - return EXE_ERROR_UNSUPPORTED; - } - - MethodInfoBlock infoBlock(pinfo); - if (var_num >= infoBlock.get_num_locals()) { - return EXE_ERROR_INVALID_SLOT; - } - StackFrame stackframe(infoBlock.get_num_locals(), - infoBlock.get_stack_max(), - infoBlock.get_in_slots()); - - uint32* ebp = (uint32*)(*context->p_ebp); - uint64* var_ptr_to_64; - uint32* var_ptr_to32; - - switch(var_type) { - case VM_DATA_TYPE_INT64: - case VM_DATA_TYPE_UINT64: - case VM_DATA_TYPE_F8: - var_ptr_to_64 = (uint64*)(ebp + stackframe.local((unsigned)var_num)); - *var_ptr_to_64 = *(uint64*)value_ptr; - break; - default: - var_ptr_to32 = (uint32*)(ebp + stackframe.local((unsigned)var_num)); - *var_ptr_to32 = *(uint32*)value_ptr; - } - return EXE_ERROR_NONE; -} -};}; // ~namespace Jitrino::Jet +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/sconsts.cpp vm/jitrino/src/jet/sconsts.cpp new file mode 100644 index 0000000..b953d6a --- /dev/null +++ vm/jitrino/src/jet/sconsts.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ +/** + * @file + * @brief Definition of constants declared in sconsts.h. + */ + +#include "sconsts.h" + +#include <cstddef> // NULL lives here +#include "jdefs.h" // NOTHING lives there + +namespace Jitrino { +namespace Jet { + +char * StaticConsts::rt_helper_throw = NULL; +char * StaticConsts::rt_helper_throw_out_of_bounds = NULL; +char * StaticConsts::rt_helper_throw_npe = NULL; +char * StaticConsts::rt_helper_throw_linking_exc = NULL; +char * StaticConsts::rt_helper_throw_div_by_zero_exc = NULL; + +char * StaticConsts::rt_helper_monitor_enter = NULL; +char * StaticConsts::rt_helper_monitor_exit = NULL; +char * StaticConsts::rt_helper_monitor_enter_static = NULL; +char * StaticConsts::rt_helper_monitor_exit_static = NULL; + +char * StaticConsts::rt_helper_ldc_string = NULL; +char * StaticConsts::rt_helper_new = NULL; +char * StaticConsts::rt_helper_new_array = NULL; +char * StaticConsts::rt_helper_init_class = NULL; +char * StaticConsts::rt_helper_aastore = NULL; +char * StaticConsts::rt_helper_multinewarray = NULL; +char * StaticConsts::rt_helper_get_vtable = NULL; +char * StaticConsts::rt_helper_checkcast = NULL; +char * StaticConsts::rt_helper_instanceof = NULL; + +char * StaticConsts::rt_helper_ti_method_exit = NULL; +char * StaticConsts::rt_helper_ti_method_enter = NULL; + +char * StaticConsts::rt_helper_ti_field_access= NULL; +char * StaticConsts::rt_helper_ti_field_modification= NULL; + + +char * StaticConsts::rt_helper_gc_safepoint = NULL; +char * StaticConsts::rt_helper_get_thread_suspend_ptr = NULL; + +unsigned StaticConsts::rt_array_length_offset = NOTHING; +unsigned StaticConsts::rt_suspend_req_flag_offset = NOTHING; +int StaticConsts::rt_vtable_offset = 0; + +bool StaticConsts::g_jvmtiMode = false; + +const char* StaticConsts::NULL_REF = NULL; +const char* StaticConsts::OBJ_BASE = NULL; +const char* StaticConsts::VTBL_BASE = NULL; +bool StaticConsts::g_refs_squeeze = false; +bool StaticConsts::g_vtbl_squeeze = false; + +const int StaticConsts::g_iconst_m1 = -1; +const int StaticConsts::g_iconst_0 = 0; +const int StaticConsts::g_iconst_1 = 1; + +const float StaticConsts::g_fconst_0 = 0.; +const float StaticConsts::g_fconst_1 = 1.; +const float StaticConsts::g_fconst_2 = 2.; + +const double StaticConsts::g_dconst_0 = 0.; +const double StaticConsts::g_dconst_1 = 1.; + +vector<AR> StaticConsts::g_global_grs; +vector<AR> StaticConsts::g_global_frs; + + +}}; // ~namespace Jitrino::Jet diff --git vm/jitrino/src/jet/sconsts.h vm/jitrino/src/jet/sconsts.h new file mode 100644 index 0000000..cb79009 --- /dev/null +++ vm/jitrino/src/jet/sconsts.h @@ -0,0 +1,171 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Declaration of global static constants. + */ + +#if !defined(__SCONSTS_H_INCLUDED__) +#define __SCONSTS_H_INCLUDED__ + +#include "enc.h" +#include <vector> +using std::vector; + +namespace Jitrino { +namespace Jet { + +/** + * @brief Static constants that are available at runtime - helper addresses, + * offsets, etc, and are persistent during the whole JIT lifetime. + * + * The class acts mostly as a namespace around the constants. It's not + * supposed to create instances of the class, and all its members are static. + * + * The names are quite self-descriptive. + * + * rt_ prefix stands for 'runtime'. + */ +class StaticConsts { +public: + static char * rt_helper_throw; + static char * rt_helper_throw_out_of_bounds; + static char * rt_helper_throw_linking_exc; + static char * rt_helper_throw_npe; + static char * rt_helper_throw_div_by_zero_exc; + + static char * rt_helper_new; + static char * rt_helper_new_array; + static char * rt_helper_aastore; + + static char * rt_helper_monitor_enter; + static char * rt_helper_monitor_exit; + static char * rt_helper_monitor_enter_static; + static char * rt_helper_monitor_exit_static; + + static char * rt_helper_ldc_string; + static char * rt_helper_init_class; + static char * rt_helper_multinewarray; + static char * rt_helper_get_vtable; + static char * rt_helper_checkcast; + static char * rt_helper_instanceof; + + static char* rt_helper_ti_method_exit; + static char* rt_helper_ti_method_enter; + + static char* rt_helper_ti_field_access; + static char* rt_helper_ti_field_modification; + + static char* rt_helper_gc_safepoint; + /** + * @brief An offset of 'thread suspend requiest' flag in TIB. + * @see rt_helper_get_thread_suspend_ptr + * @see rt_helper_gc_safepoint + * @todo seems unused after the recent ThreadManager changes. + */ + static unsigned rt_suspend_req_flag_offset; + + /** + * @brief Address of helper that returns a pointer to the thread + * suspension request flag. + * @param none + * @return read-only pointer to an int32 flag. + */ + static char* rt_helper_get_thread_suspend_ptr; + + /** + * @brief An offset of vtable in the object's header. + */ + static int rt_vtable_offset; + + /** + * @brief An offset of array's length in the object's header. + */ + static unsigned rt_array_length_offset; + + /** + * @brief \b true when running under debug. + */ + static bool g_jvmtiMode; + + /** + * @brief A value of null reference (aka 'managed null'). + */ + static const char* NULL_REF; + + /** + * @brief Objects base for compressed references. + */ + static const char* OBJ_BASE; + + /** + * @brief Base for compressed vtables. + */ + static const char* VTBL_BASE; + + /** + * @brief true if references are compressed on current platform. + */ + static bool g_refs_squeeze; + + /** + * @brief \c true if vtables are compressed on current platform. + */ + static bool g_vtbl_squeeze; + + /** @brief Predefined integer constant, -1.*/ + static const int g_iconst_m1; + /** @brief Predefined integer constant, 0.*/ + static const int g_iconst_0; + /** @brief Predefined integer constant, 1.*/ + static const int g_iconst_1; + /** @brief Predefined float constant, 0.0.*/ + static const float g_fconst_0; + /** @brief Predefined float constant, 1.0.*/ + static const float g_fconst_1; + /** @brief Predefined float constant, 2.0.*/ + static const float g_fconst_2; + /** @brief Predefined double constant, 0.0.*/ + static const double g_dconst_0; + /** @brief Predefined double constant, 1.0.*/ + static const double g_dconst_1; + + /** + * @brief List of GR-s dedicated for global allocation. + */ + static vector<AR> g_global_grs; + /** + * @brief List of FR-s dedicated for global allocation. + */ + static vector<AR> g_global_frs; + +protected: + /** + * @brief Noop. + */ + StaticConsts(void) {}; +}; + + +}}; // ~namespace Jitrino::Jet + +#endif // ~__SCONSTS_H_INCLUDED__ + diff --git vm/jitrino/src/jet/sframe.h vm/jitrino/src/jet/sframe.h new file mode 100644 index 0000000..98c7f3d --- /dev/null +++ vm/jitrino/src/jet/sframe.h @@ -0,0 +1,361 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Declaration of StackFrame class. + */ + +#if !defined(__SFRAME_H_INCLUDED__) +#define __SFRAME_H_INCLUDED__ + +#include "enc.h" +#include "csig.h" + +namespace Jitrino { +namespace Jet { + +/** + * @brief Controls layout of the native stack frame. + * + * The class StackFrame holds all the arithmetics behind layout of a native + * stack frame. + * + * Below is the stack layout, used for methods compiled by Jitrino.JET. + * +<table> +<tr align="center"> + <td>Method/name</td><td>Purpose</td> +</tr> +<tr> + <td></td><td></td>< +</tr> + + +<tr> + <td>input arg ...</td><td></td> +</tr> +<tr align="center" bgcolor="silver"><td colspan=2>fixed area</td></tr> +<tr> + <td>StackFrame::ret()</td> + <td><=#bp<br>Also, #sp points here at the entrance.</td> +</tr> +<tr> + <td> + StackFrame::spill() - beginning of the area<br> + StackFrame::spill(AR) - address for the particular register + </td> + <td>The spill area used to store callee-save register. + Also, scratch registers may be saved here during runtime (see + CodeGen::gen_call_vm_restore()). + </td> +</tr> +<tr> + <td>StackFrame::thiz()</td> + <td>Saved copy of \c this, when necessary. Size=STACK_SLOT_SIZE.</td> +</tr> + +<tr> + <td>StackFrame::scratch()</td> + <td>Scratch area, used for temporary storage. Size=8 bytes</td> +</tr> + +<tr> + <td>StackFrame::dbg_scratch()</td> + <td>Temporary area for debugging utilities needs. E.g. an #sp is stored + here when method compiled with DBG_CHECK_STACK. Size=STACK_SLOT_SIZE. + </td> +</tr> + +<tr> + <td>StackFrame::info_gc_regs()</td> + <td>GC map for GR registers. Size=4 bytes.</td> +</tr> + +<tr> + <td>StackFrame::info_gc_stack_depth()</td> + <td>GC stack depath of operand stack. Size=4 bytes.</td> +</tr> + +<tr align="center" bgcolor="silver"><td colspan=2>variable size area</td></tr> + +<tr> + <td>StackFrame::info_gc_locals()</td> + <td>GC map for local variables. Size=words(num_locals)</td> +</tr> + +<tr> + <td>StackFrame::info_gc_args()</td> + <td>GC map for input arguments. Size=words(num_in_slots)</td> +</tr> + +<tr> + <td>StackFrame::info_gc_stack()</td> + <td>GC map for operand stack. Size=words(max_stack)</td> +</tr> + +<tr> + <td>StackFrame::local(unsigned)</td> + <td>Array of local varibales of the method. + Size=STACK_SLOT_SIZE*num_locals.</td> +</tr> + +<tr> + <td> + StackFrame::stack_bot()<br>StackFrame::stack_slot(unsigned)<br> + StackFrame::stack_max() + </td> + <td>Operand stack of the method. StackFrame::stack_bot() points to + the very beginning of the stack. StackFrame::stack_slot(unsigned) + address a particular slot in the stack, and StackFrame::stack_max + points to the very last possible slot. + Size=STACK_SLOT_SIZE*max_stack.</td> +</tr> + +<tr> + <td>StackFrame::unused()</td> + <td>Points to the first unused memory address (of STACK_SLOT_SIZE + size) beyond the frame.<br> + Note that though the memory is named 'unused' it may still belog to the + frame - for example, if the frame is aligned according to calling + convention. + </td> +</tr> + +</table> + + * + * + * + * @todo On Intel 64 the fixed size of the frame is quite big - the + * number of registers is much bigger than on IA-32 and each register is + * 8 bytes wide - so the spill area is long. As result, the length of + * the fixed-size area does not fit into +/-127. This makes generated code + * to use addressing with 32 bit displacements [rbp+int32] which make code + * bigger. If we point base pointer (in the method's prolog) not to the + * beginning of the frame but, say, into the middle between + * locals and stack, then we'll be able to address most of them with 8bit + * displacement. Seems the best place to correct the offset would be + * CodeGen::voff(), where all the offsets come through. + */ +class StackFrame { +public: + /** + * @brief Initializes an instance of StackFrame. + * + * @param _num_locals - number of slots occupied by local variables in + * Java method's frame + * @param _max_stack - max depth of Java operand stack + * @param _in_slots - number of slots occupied by input args in Java + * on Java operand stack + * @see #init + */ + StackFrame(unsigned _num_locals, unsigned _max_stack, unsigned _in_slots) + { + m_num_locals = _num_locals; + m_max_stack = _max_stack; + m_in_slots = _in_slots; + } + + /** + * @brief Noop. + */ + StackFrame() {} + + /** + * @brief Initializes fields of this StackFrame instance. + * + * @param _num_locals - number of slots occupied by local variables in + * Java method's frame + * @param _max_stack - max depth of Java operand stack + * @param _in_slots - number of slots occupied by input args in Java + * on Java operand stack + */ + void init(unsigned _num_locals, unsigned _max_stack, unsigned _in_slots) + { + m_num_locals = _num_locals; + m_max_stack = _max_stack; + m_in_slots = _in_slots; + } +public: + /** + * @brief Returns number of slots occupied by local variables. + * + * @return number of slots occupied by local variables in Java method's + * frame + */ + unsigned get_num_locals(void) const + { + return m_num_locals; + } + + /** + * @brief Returns max stack depth of Java method's operand stack + * @return max stack depth + */ + unsigned get_max_stack(void) const + { + return m_max_stack; + } + + /** + * @brief Returns number of slots occupied by input args, in Java + * method's operand stack + * @return number of slots occupied by input args + */ + unsigned get_in_slots(void) const + { + return m_in_slots; + } +public: + + int inargs(void) const { + return ret() + STACK_SLOT_SIZE; + } + + int ret(void) const + { + return 0; + } + + /** + * @brief Returns size of the stack frame. + * + * The size is aligned if \link #CCONV_MANAGED managed calling + * convention \endlink assumes so. + * + * @return size of the stack frame + */ + unsigned size(void) const + { + unsigned sz = -unused(); + if (CCONV_MANAGED & CCONV_STACK_ALIGN16) { + return ((sz + 15) & ~0xF); + } + else if (CCONV_MANAGED & CCONV_STACK_ALIGN_HALF16) { + return ((sz + 15) & ~0xF) + 8; + } + else { + return ((sz + 3) & ~0x03); + } + } + + // + // First, a fixed area - the same size for all methods... + // + + int spill(void) const + { + return ret()-(int)(gr_num*STACK_SLOT_SIZE + fr_num*8); + } + + int spill(AR ar) const + { + if (is_gr(ar)) { + return spill() + STACK_SLOT_SIZE*gr_idx(ar); + } + assert(is_fr(ar)); + return spill() + STACK_SLOT_SIZE*gr_num + 8*fr_idx(ar); + } + + int thiz(void) const + { + return spill() - STACK_SLOT_SIZE; + } + + int scratch(void) const + { + return thiz() - 128/8; + } + + int dbg_scratch(void) const + { + return scratch() - STACK_SLOT_SIZE; + } + + int info_gc_regs(void) const + { + assert(words(gen_num_calle_save()) == 1); + return dbg_scratch() - sizeof(unsigned); + } + + /** + * @brief Returns offset of stack depth in the GC info. + */ + int info_gc_stack_depth(void) const + { + return info_gc_regs()-(int)sizeof(int); + } + // + // ... second, an area which depends on locals count and stack size. + // + int info_gc_locals(void) const + { + return info_gc_stack_depth() - sizeof(int)*words(m_num_locals); + } + + int info_gc_args(void) const + { + return info_gc_locals() - sizeof(int)*words(m_in_slots); + } + + int info_gc_stack(void) const + { + return info_gc_args() - sizeof(int)*words(m_max_stack); + } + + int local(unsigned i) const + { + assert(i<m_num_locals || (i==0)); //XXX comment out + return info_gc_stack() - (m_num_locals - i)*STACK_SLOT_SIZE; + } + + int stack_bot(void) const + { + return local(0) - STACK_SLOT_SIZE; + } + + int stack_slot(unsigned slot) const + { + assert(slot<m_max_stack); + return stack_bot() - slot*STACK_SLOT_SIZE; + } + + int stack_max(void) const + { + return stack_bot() - (m_max_stack - 1)*STACK_SLOT_SIZE; + } + + int unused(void) const + { + return stack_max() - STACK_SLOT_SIZE; + } + // +private: + unsigned m_num_locals; + unsigned m_max_stack; + unsigned m_in_slots; +}; + + +}}; // ~namespace Jitrino::Jet + +#endif // ~__SFRAME_H_INCLUDED__ + diff --git vm/jitrino/src/jet/stats.cpp vm/jitrino/src/jet/stats.cpp index 9cfe519..f91a614 100644 --- vm/jitrino/src/jet/stats.cpp +++ vm/jitrino/src/jet/stats.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Implementation of statistics and measurement utilities. + * @brief Implementation of statistics utilities declared in stats.h. */ #include <stdio.h> @@ -34,101 +34,44 @@ #include "trace.h" namespace Jitrino { namespace Jet { -Timer Timers::totalExec (".jet::total.execution"); -Timer Timers::compTotal (".jet::comp.total"); -Timer Timers::vmResolve (".jet::vm.resolve"); -Timer Timers::compInit (".jet::comp.init"); -Timer Timers::compMarkBBs (".jet::comp.mark-bbs"); -Timer Timers::compCodeGen (".jet::comp.code-gen"); -Timer Timers::compCodeLayout (".jet::comp.code-layout"); -Timer Timers::compCodePatch (".jet::comp.code-patch"); -Timer Timers::compEhandlers (".jet::comp.code-patch"); +// Variables placed on new line to avoid Doxygen warning " +// 'Found ';' while parsing initializer list!' - -STATS_ITEM(unsigned) Stats::methodsCompiled((unsigned)0); -STATS_ITEM(unsigned) Stats::methodsCompiledSeveralTimes((unsigned)0); -STATS_ITEM(unsigned) Stats::methodsWOCatchHandlers((unsigned)0); -STATS_ITEM(unsigned) Stats::opcodesSeen[OPCODE_COUNT]; -STATS_ITEM(unsigned) Stats::npesEliminated((unsigned)0); -STATS_ITEM(unsigned) Stats::npesPerformed((unsigned)0); +STATS_ITEM(unsigned) + Stats::methodsCompiled = 0; +STATS_ITEM(unsigned) + Stats::methodsCompiledSeveralTimes = 0; +STATS_ITEM(unsigned) + Stats::methodsWOCatchHandlers = 0; +STATS_ITEM(unsigned) + Stats::opcodesSeen[OPCODE_COUNT]; +STATS_ITEM(unsigned) + Stats::npesEliminated = 0; +STATS_ITEM(unsigned) + Stats::npesPerformed = 0; const char * Stats::g_name_filter = NULL; -DEF_MIN_MAX_VALUE( bc_size ); -DEF_MIN_MAX_VALUE( code_size ); -DEF_MIN_MAX_VALUE( native_per_bc_ratio ); -DEF_MIN_MAX_VALUE( jstack ); -DEF_MIN_MAX_VALUE( locals ); -DEF_MIN_MAX_VALUE( bbs ); -DEF_MIN_MAX_VALUE( bb_size ); -DEF_MIN_MAX_VALUE( patchItemsToBcSizeRatioX1000 ); - -#ifdef JIT_TIMING - -Timer * Timer::first = NULL; -Timer * Timer::last = NULL; -unsigned long long Timer::freq = 0; -unsigned long long Timer::correction = 0; - -// -// -// -void Timer::init(void) -{ - // query frequency - LARGE_INTEGER get_freq; - QueryPerformanceFrequency(&get_freq); - Timer::freq = get_freq.QuadPart; - - // - // count start/stop overhead - // - Timer atimer; - - // no mathematics beyond this number, simple estimation - static const unsigned NUM_TIMES = 10; - - unsigned long long timeSpent = 0; // keep the Timer::correction zero during the loop - for(unsigned i=0; i<NUM_TIMES; i++ ) { - atimer.startTimer(); - atimer.stopTimer(); - timeSpent += atimer.getTime(); - // let others to work - Sleep(0); - } - Timer::correction = timeSpent/NUM_TIMES; -} - -void Timer::dump(void) -{ - dbg("==================== timers ====================\n"); - Timer * ptimer = Timer::getFirst(); - while (ptimer) { - static const unsigned PRECISION = 1000; - unsigned data = (unsigned)ptimer->getSeconds(PRECISION); - unsigned secs = data/PRECISION; - unsigned parts = data-secs*PRECISION; - dbg("%-35s: %4d.%03d %s\n", - ptimer->getName(), secs, parts, - !ptimer->recursionCount ? "" : "?? start/stop not balanced !"); - ptimer = ptimer->getNext(); - } - dbg("================================================\n"); -} +DEF_MIN_MAX_VALUE(bc_size); +DEF_MIN_MAX_VALUE(code_size); +DEF_MIN_MAX_VALUE(native_per_bc_ratio); +DEF_MIN_MAX_VALUE(jstack); +DEF_MIN_MAX_VALUE(locals); +DEF_MIN_MAX_VALUE(bbs); +DEF_MIN_MAX_VALUE(bb_size); +DEF_MIN_MAX_VALUE(patchItemsToBcSizeRatioX1000); -#endif // ~JIT_TIMING - #ifdef JIT_STATS -bool -opcode_stat_comparator(const ::std::pair<unsigned, unsigned>& one, - const ::std::pair<unsigned, unsigned>& two) +bool opcode_stat_comparator(const ::std::pair<unsigned, unsigned>& one, + const ::std::pair<unsigned, unsigned>& two) { return one.first > two.first; } + void Stats::dump(void) { dbg("\n"); @@ -200,7 +143,7 @@ #define PRINT_MIN_MAX_VALUE( what ) \ else { dbg("name filter: %s\n", g_name_filter); } -} +}; #endif //#ifdef JIT_STATS diff --git vm/jitrino/src/jet/stats.h vm/jitrino/src/jet/stats.h index c289beb..a899161 100644 --- vm/jitrino/src/jet/stats.h +++ vm/jitrino/src/jet/stats.h @@ -14,13 +14,13 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.3.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Definitions for statistics and measurement utilities. + * @brief Statistics utilities declarations. */ #if !defined(__STATS_H_INCLUDED__) @@ -33,367 +33,79 @@ #include <string> namespace Jitrino { namespace Jet { -#if defined(JIT_TIMING) -#include <winsock2.h> -#include <windows.h> -#endif // if defined(JIT_TIMING) - - - -/** - * @brief Class for quick and rough estimations of time spent in various - * parts of program. - * - * Normally, Timer instances are created as static and/or global variables. - * They are automatically connected to a single linked list and may be - * printed out by a single #Timer::dump call. - * - * @note To use Timers, a macro JIT_TIMING must be defined. Otherwise, all - * its methods are no-ops. - * - * So, the Timer-s usage may be left in the code without any conditional - * macros, and they do not contribute any runtime overhead until a macro - * JIT_TIMING defined. An overhead to Timer's #start() and #stop() calls is - * estimated in #init() and then used to correct the measured values. - * - * @note Only Windows implementation currently exists. - */ -class Timer { -public: -//#ifndef DOXYGEN_SHOULD_SKIP_THIS -#if !defined(JIT_TIMING) - Timer(void) {}; - Timer(const char *) {}; - void startTimer(void) const {}; - void stopTimer(void) const {}; - void resetTimer(void) const {}; - void start(void) const {}; - void stop(void) const {}; - static void init(void) {}; - static void dump(void) {}; -#else // if !defined(JIT_TIMING) -//#endif //ifndef DOXYGEN_SHOULD_SKIP_THIS - /** - * @brief A special-purpose constructor, normally used only during an - * init() routine. - * - * @note Does not register the instance in the Timers chain. - */ - Timer(void) : totalTime(0), recursionCount(0), startTime(0) - { - } - - /** - * @brief Creates named instance of Timer, inserts the instance in the - * list of Timer-s. - */ - Timer(const char *_name) : name(_name), totalTime(0), - recursionCount(0), startTime(0) - { - if (!first) { - first = this; - } - if (last) { - last->next = this; - } - next = NULL; - last = this; - } - - - /** - * @brief Initializes the Timers framework, counting overhead spent to - * start/stop pair invocation. - */ - static void init(void); - - /** - * @brief Prints out all Timer-s (their names and values) in the list. - */ - static void dump(void); - - /** - * @brief Returns current value of underlying high-resolution timer. - */ - static unsigned long long getCounter(void) - { - LARGE_INTEGER getCount; - QueryPerformanceCounter(&getCount); - return getCount.QuadPart; - } - - /** - * @brief Clears the Timer. - */ - void resetTimer(void) - { - recursionCount = 0; - totalTime = 0; - } - - /** - * @brief Alias for #start(). - */ - void startTimer(void) - { - start(); - } - /** - * @brief Starts the timer. - */ - void start(void) - { - if (recursionCount++ == 0) { - startTime = getCounter(); - } - } - - /** - * @brief Alias for #stop(). - */ - void stopTimer(void) - { - stop(); - } - - /** - * @brief Stops the timer. - */ - void stop(void) - { - if (--recursionCount == 0) { - const unsigned long long finishTime = getCounter(); - long long deltaT = (finishTime - startTime - correction); - if (deltaT<0) { - deltaT = 0; - } - totalTime = totalTime + deltaT; - } - } - - /** - * @brief Returns a time interval measured by the Timer. - */ - unsigned long long getTime(void) const - { - return totalTime; - } - - /** - * @brief Returns value of the Timer in seconds, with a given accuracy. - * - * I.e. is the measured time interval is '0.1s', then getSeconds(10) - * returns '1', and getSeconds(1000) returns '100'. - */ - unsigned long long getSeconds(unsigned accuracy = 100000) - { - return (totalTime*accuracy)/freq; - } - - /** - * @brief Returns name of the timer. - */ - const char * getName(void) const - { - return name; - } - - /** - * @brief Returns next timer in the list, or NULL if this is last timer. - */ - Timer * getNext(void) const - { - return next; - } - - /** - * @brief Returns very first Timer in a list of Timers. - */ - static Timer * getFirst(void) - { - return first; - } - -private: - /** - * @brief Frequency (ticks-per-second) of the underlying OS - * high-resolution timer. - */ - static unsigned long long freq; - - /** - * @brief Estimated overhead of start/stop calls, including calls to - * OS' API functions. - */ - static unsigned long long correction; - - // actually, a pointer to a head is much enough for enumeration but in - // order to preserve the natural order of the Timers definitions 2 - // pointers are used - - /** - * @brief The 'first' field point onto the head of the list. - * - * The Timers are linked together in a single-linked list for easy - * enumeration and printing. - */ - static Timer * first; - - /** - * @brief The 'last' field point to the tail of the list for fast - * insertion. - */ - static Timer * last; - - /** - * @brief Name of the Timer. - */ - const char * name; - - /** - * @brief Start value. - */ - unsigned long long startTime; - - /** - * @brief Total time measured by this timer. - */ - unsigned long long totalTime; - - /** - * @brief Depth of recursion (repetitive calls of #start()/#stop()). - */ - int recursionCount; - - /** - * @brief Pointer to a next timer. - */ - Timer * next; -#ifndef DOXYGEN_SHOULD_SKIP_THIS -#endif // if !defined(JIT_TIMING) -#endif //ifndef DOXYGEN_SHOULD_SKIP_THIS -}; - - /** - * @brief A simple holder only to visually designate timers through the - * sources. - */ -class Timers { -public: - /** - * @brief Time spent in VM's resolve_xx methods. - */ - static Timer vmResolve; - /** - * @brief Total lifetime - time between JIT_Init() and JIT_Deinit() calls. - */ - static Timer totalExec; - /** - * @brief Summarized time of compilation. - */ - static Timer compTotal; - /** - * @brief Time spent for initialization routines. - */ - static Timer compInit; - /** - * @brief Time spent for Compiler::bbs_mark_all(). - */ - static Timer compMarkBBs; - /** - * @brief Time spent for Compiler::bbs_gen_code(). - */ - static Timer compCodeGen; - /** - * @brief TIme spent for Compiler::bbs_layout_code(). - */ - static Timer compCodeLayout; - /** - * @brief Time spent for code patching. - */ - static Timer compCodePatch; - /** - * @brief Time spent Compiler::bbs_ehandlers_set(). - */ - static Timer compEhandlers; -}; - -/** - * @brief Class for simple statistics collection and dump. - * - * All of its operations are noops until a macro JIT_STATS defined, so - * the operations may be left in code without any runtime overhead. + * Mostly a namespace to keep statistics routines and stuff all together. */ class Stats { -private: - // only statics +private: // only statics Stats(); Stats(const Stats&); - Stats& operator=(const Stats&); public: /** - * @brief An empty type, whose all methods and operators are no-ops. + * Dummy type whose methods are no-ops. * - * Used to replace any other type when no JIT_STATS macro defined. + * Used to substitute a type of a variable, so any manipulation with + * the variable may be left in the code without \#ifdef/\#endif, but + * will be removed by an optimizing compiler. */ class EmptyType { public: // various ctors - EmptyType(void) {}; - EmptyType(const char *) {}; + EmptyType() {}; + //EmptyType(const char *) {}; EmptyType(unsigned) {}; - EmptyType(float) {}; - EmptyType(double) {}; + //EmptyType(jlong) {}; + //EmptyType(float) {}; + //EmptyType(double) {}; EmptyType(const EmptyType&) {}; // - EmptyType& operator=(const EmptyType&) { return *this; } - EmptyType& operator=(unsigned) { return *this; } - EmptyType& operator=(const char*) { return *this; } + EmptyType& operator=(const EmptyType&) { return *this; }; + EmptyType& operator=(unsigned) { return *this; }; + EmptyType& operator=(const char*) { return *this; }; // - bool operator==(const EmptyType&) { return false; } - bool operator!=(const EmptyType&) { return false; } - bool operator<=(const EmptyType&) { return false; } - bool operator>=(const EmptyType&) { return false; } - EmptyType& operator++(void) { return *this; } - EmptyType& operator++(int) { return *this; } - EmptyType& operator+=(const EmptyType&) { return *this; } - operator unsigned() { return 0; } + bool operator==(const EmptyType&) { return false; }; + bool operator!=(const EmptyType&) { return false; }; + //bool operator<(const EmptyType&) { return false; }; + //bool operator>(const EmptyType&) { return false; }; + bool operator<=(const EmptyType&) { return false; }; + bool operator>=(const EmptyType&) { return false; }; + EmptyType& operator++(void) { return *this; }; + EmptyType& operator++(int) { return *this; }; + //EmptyType& operator+(const EmptyType&) { return *this; }; + EmptyType& operator+=(const EmptyType&) { return *this; }; + //EmptyType& operator-(const EmptyType&) { return *this; }; + //EmptyType& operator-=(const EmptyType&) { return *this; }; + //EmptyType& operator*(const EmptyType&) { return *this; }; + //EmptyType& operator*=(const EmptyType&) { return *this; }; + //EmptyType& operator/(const EmptyType&) { return *this; }; + //EmptyType& operator/=(const EmptyType&) { return *this; }; + operator unsigned() { return 0; }; + //operator int() { return 0; }; }; #ifdef JIT_STATS - /** - * @brief A macro used to declare a variable of type \c typ, but - * replaces its type to #EmptyType when no JIT_STATS defined. - */ #define STATS_ITEM(typ) typ - /** - * @brief Prints out collected statistics. - */ static void dump(void); #else #define STATS_ITEM(typ) Stats::EmptyType - static void dump(void) {} + static void init( void ) {}; + static void dump( void ) {}; #endif - /** - * @brief String filter for collected statistics. - * - * Introduces a filter (trough the strstr(fully-qualified-name, filter) - * to collect statistics about. - */ - static const char * g_name_filter; - + /** How many times each opcode was seen during compilation. */ static STATS_ITEM(unsigned) opcodesSeen[OPCODE_COUNT]; - /// how many methods compiled + /** How many methods compiled. */ static STATS_ITEM(unsigned) methodsCompiled; + /** How many methods were compiled several times. */ static STATS_ITEM(unsigned) methodsCompiledSeveralTimes; - /// Methods without catch handlers + /** Some methods statistics. */ static STATS_ITEM(unsigned) methodsWOCatchHandlers; - // - - /// How many null checks are eliminated + /** How many null checks are eliminated. */ static STATS_ITEM(unsigned) npesEliminated; + /** How many null checks were generated. */ static STATS_ITEM(unsigned) npesPerformed; + // introduces a filter (as trough the strstr(fully-qualified-name, filter) + // to collect statistics about + static const char * g_name_filter; #define DEF_MIN_MAX_VALUE(what) \ STATS_ITEM(unsigned) Stats::what##_total = (unsigned)0; \ @@ -412,26 +124,17 @@ #define DECL_MIN_MAX_VALUE(what) \ #ifdef JIT_STATS #define STATS_SET_NAME_FILER(nam) Stats::g_name_filter = nam #define STATS_INC(what, howmany) \ - if ( (NULL == Stats::g_name_filter) || \ - (NULL != strstr(m_fname, Stats::g_name_filter))) { \ + if ( (NULL == Stats::g_name_filter) || (NULL != strstr(meth_fname(), Stats::g_name_filter)) ) { \ what += howmany; \ } #define STATS_MEASURE_MIN_MAX_VALUE( what, value, nam ) \ { \ - if ( (NULL == Stats::g_name_filter) || \ - (NULL != strstr(m_fname, Stats::g_name_filter)) ) { \ + if ( (NULL == Stats::g_name_filter) || (NULL != strstr(meth_fname(), Stats::g_name_filter)) ) { \ Stats::what##_total += value; \ - if (Stats::what##_max < value) { \ - Stats::what##_max = value; \ - Stats::what##_max_name = nam; \ - }; \ + if( Stats::what##_max < value ) { Stats::what##_max = value; Stats::what##_max_name = nam; }; \ static bool what##_done = false; \ - if (!what##_done && Stats::what##_min > value) { \ - what##_done = true; \ - Stats::what##_min = value; \ - Stats::what##_min_name = nam; \ - }; \ + if( !what##_done && Stats::what##_min > value ) { what##_done = true; Stats::what##_min = value; Stats::what##_min_name = nam; }; \ }\ } #else // JIT_STATS @@ -439,6 +142,7 @@ #else // JIT_STATS #define STATS_INC(what, howmany) #define STATS_MEASURE_MIN_MAX_VALUE( what, value, nam ) #endif // JIT_STATS + // byte code size DECL_MIN_MAX_VALUE( bc_size ); diff --git vm/jitrino/src/jet/structs.h vm/jitrino/src/jet/structs.h new file mode 100644 index 0000000..30c9fe4 --- /dev/null +++ vm/jitrino/src/jet/structs.h @@ -0,0 +1,690 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Various simple structures for CodeGen and Compiler needs. + * + * Mostly structures that defer better classification are collected here. + */ + +#if !defined(__BBSTATE_H_INCLUDED__) +#define __BBSTATE_H_INCLUDED__ + + +#include "jdefs.h" +#include "jframe.h" +#include "open/vm.h" +#include "jit_import.h" + +namespace Jitrino { +namespace Jet { + +/** + * @brief Reads out a 4-byte integer stored in the Java's format - 'most + * significant bytes first'. + * @param pbc - a buffer to read from + * @return integer + */ +inline int bc_int(const unsigned char * pbc) +{ + return (int)(((*(pbc+0))<<24) | ((*(pbc+1))<<16) | + ((*(pbc+2))<<8) | ((*(pbc+3))<<0)); +} + +/** + * @brief Simple smart pointer. + * + * A trivial smart pointer implementation for dynamically allocated arrays. + * Allocated memory is deallocated in destructor. + * + * Does not support neither copying, nor resizing of array. Used to avoid + * head ache about controlling raw pointers of allocated memory. + * + * Used for arrays and includes bounds check in debug build - no bound + * checks performed in release one. + */ +template<class SomeType> class SmartPtr { +public: + /** + * @brief Initializes empty object. + */ + SmartPtr(void) + { + m_data = NULL; + } + /** + * @brief Allocates memory for \c count elements of SomeType. + * + * May zero the allocated memory if \c clear parameter is \c true. + */ + void alloc(unsigned count, bool clear = false) + { + m_data = new SomeType[count]; + m_count = count; + if (clear) { + memset(m_data, 0, bytes()); + } + } + /** + * @brief Returns number of elements in the allocates array. + */ + unsigned count(void) const + { + return m_count; + } + + /** + * @brief Provides random access to an item by index. + * + * Bounds check is preformed only in debug build. + */ + SomeType& operator[](unsigned idx) + { + assert(idx<m_count); + return m_data[idx]; + } + + /** + * @brief Provides a direct access to the allocated array. + */ + SomeType* data(void) + { + return m_data; + } + + /** + * @brief Returns size of allocated memory, in bytes. + */ + unsigned bytes(void) + { + return sizeof(SomeType)*m_count; + } + + /** + * @brief Fress allocated resources. + */ + ~SmartPtr() + { + delete[] m_data; + } +private: + /** + * @brief Pointer to the allocated memory. + */ + SomeType * m_data; + /** + * @brief Number of elements in the allocated array. + */ + unsigned m_count; + /** + * @brief Disallow copying. + */ + SmartPtr(const SmartPtr&); + /** + * @brief Disallow copying. + */ + SmartPtr& operator=(const SmartPtr&); +}; + + + +/** + * @brief Decoded byte code instruction. + */ +struct JInst { + unsigned id; + /** + * @brief Number of references on this instruction. + * + * The number of references is number of incoming control flow edges. + * Regular instructions have \c ref_count==1, basic block leaders may + * have \c ref_count > 1. \c ref_count == 0 means the instruction is + * dead code. + */ + unsigned ref_count; + /** + * @brief Program counter of this instruction. + */ + unsigned pc; + /** + * @brief Program counter of next instruction. + */ + unsigned next; + /** + * @brief Instruction's opcode. + */ + JavaByteCodes opcode; + /** + * @brief Instruction's flags. + */ + unsigned flags; + /** + * @brief Value of the first instrution's operand, if applicable. + * + * @note If instruction has no operands, the value of 'op0' is undefined. + */ + int op0; + + /** + * @brief Value of the second instrution's operand, if applicable. + * + * @note If instruction has no second operands, the value of 'op1' is + * undefined. + */ + int op1; + + /** + * @brief Address of data (the padding bytes skipped) for the switch + * instructions. + * + * @note For instructions other than switch, the value is undefined. + */ + const unsigned char* data; + + /** + * @brief Returns number of targets for a branch or switch instruction. + * + * For branches it's always 1. + * For switches the default target is not included in the value. + * For other instructions returns 0. + */ + unsigned get_num_targets(void) const + { + if (is_branch()) { return 1; }; + if (opcode == OPCODE_TABLESWITCH) { + return high() - low() + 1; + } + if (opcode != OPCODE_LOOKUPSWITCH) { + return 0; + } + // 4 here is the number of bytecode bytes between the values - comes + // from the JVM Spec + return bc_int(data + 4); // +4 - skip the 'defaultbyte*4' + } + + /** + * @brief Returns a PC value for the target 'i'. + * + * Must be only invoked for the branch or switch instructions and 'i' + * must be less or equal to gen_num_targets(). + * For other cases the behavior is unpredictable. + */ + unsigned get_target(unsigned i) const + { + assert(i < get_num_targets()); + if (is_branch()) { + return (unsigned short)(((unsigned short)pc) + + ((unsigned short)op0)); + } + if (opcode == OPCODE_TABLESWITCH) { + // '4+4+4' - skip defaultbyte, lowbyte and hightbyte + const int * poffsets = (int*)(data + 4 + 4 + 4); + return pc + bc_int((unsigned char*)(poffsets + i)); + } + assert(opcode == OPCODE_LOOKUPSWITCH); + // '4+4' - skip defaultbyte and npairs + const int * ppairs = (int*)(data+4+4); + return pc + bc_int((unsigned char*)(ppairs + i*2 + 1)); + } + /** + * @brief Returns default target for switch instructions. + * + * Must only be invoked for TABLESWITCH or LOOKUPSWITCH instructions. + */ + unsigned get_def_target(void) const + { + assert(opcode == OPCODE_TABLESWITCH || opcode == OPCODE_LOOKUPSWITCH); + unsigned offset = bc_int(data); + return (unsigned short)(((unsigned short)pc)+((unsigned short)offset)); + } + + /** + * @brief Returns size of data (in bytes) occupied by LOOKUPSWITCH or + * TABLESWITCH datas. + * + * Must only be invoked for TABLESWITCH or LOOKUPSWITCH instructions. + */ + unsigned get_data_len(void) const + { + if (opcode == OPCODE_TABLESWITCH) { + // 4*3 = defaultbyte,lowbyte,highbyte ; +jmp offsets + return 4*3 + 4*(high()-low()+1); + } + assert(opcode == OPCODE_LOOKUPSWITCH); + // defaultbyte + npairs + (4*2)*npairs + return (4 + 4 + 4*2 * get_num_targets()); + } + + /** + * @brief Returns minimum value of TABLESWITCH instruction. + * + * Must only be invoked for TABLESWITCH instructions. + */ + int low(void) const + { + assert(opcode == OPCODE_TABLESWITCH); + // 4 here is the number of bytecode bytes between the values - comes + // from the JVM Spec + return bc_int(data + 4); + } + + /** + * @brief Returns maximum value of TABLESWITCH instruction. + * + * Must only be invoked for TABLESWITCH instructions. + */ + int high(void) const + { + assert(opcode == OPCODE_TABLESWITCH); + // 4 here is the number of bytecode bytes between the values - comes + // from the JVM Spec + return bc_int(data + 4+4); + } + + /** + * @brief Returns Nth key of LOOKUPSWITCH instruction. + * + * Must only be invoked for LOOKUPSWITCH instructions. + */ + int key(unsigned i) const + { + assert(opcode == OPCODE_LOOKUPSWITCH); + // skip defaultbyte(+4), npairs(+4) and 'i' pairs + return bc_int(data+4+4 + i*2*4); + } + + /** + * @brief Tests whether the instruction is branch - either conditional + * or not. JSR-s are also considered branches, but not SWITCH + * instructions. + */ + bool is_branch(void) const + { + return (OPCODE_IFEQ <= opcode && opcode <= OPCODE_JSR) || + (OPCODE_IFNULL <= opcode && opcode <= OPCODE_JSR_W); + } + /** + * @brief Tests whether instruction is either TABLESWITCH or + * LOOKUPSWITCH. + */ + bool is_switch(void) const + { + return (opcode == OPCODE_TABLESWITCH || + opcode == OPCODE_LOOKUPSWITCH); + } + /** + * @brief Tests whether instruction is JSR[_W]. + */ + bool is_jsr(void) const + { + return opcode == OPCODE_JSR || opcode == OPCODE_JSR_W; + } + + /** + * @brief Tests whether the given flag (or set of flags) is set. + * @see OPF_ + */ + bool is_set(unsigned opf_flag) const + { + return (flags & opf_flag); + } + + /** + * @brief Tests whether instruction has single successor. + */ + bool single_suc(void) const + { + // GOTO is the case as well as non-branch instructions with + // fall through pass. + return (get_num_targets()==0 && !is_set(OPF_DEAD_END)) || + opcode == OPCODE_GOTO || opcode == OPCODE_GOTO_W; + + } +}; + +/** + * @brief Information about exception handler. + */ +struct HandlerInfo { + /** + * @brief Start PC of bytecode region protected by this exception handler + * (inclusive). + */ + unsigned start; + /** + * @brief End PC of bytecode region protected by this exception handler + * (exclusive). + */ + unsigned end; + /** + * @brief Entry point PC of exception handler. + */ + unsigned handler; + /** + * @brief Type of exception handled by this handler. 0 for 'any type'. + */ + unsigned type; + /** + * @brief Class_Handle of the exception class for this handler. + */ + Class_Handle klass; + /** + * @brief IP for #start. + */ + char * start_ip; + /** + * @brief IP for #end. + */ + char * end_ip; + /** + * @brief IP for #handler. + */ + char * handler_ip; +}; + + +/** + * @brief General info about basic block + */ +struct BBInfo { + BBInfo() + { + start = last_pc = next_bb = 0; + code_size = 0; + ehandler = false; + jsr_target = false; + processed = false; + } + /** + * @brief Very first bytecode instruction - the basic block's leader. + */ + unsigned start; + + /** + *@brief Last bytecode instruction which belongs to this basic block. + */ + unsigned last_pc; + + /** + * @brief Leader of the next (layout successor) basic block. + * + * Actually, the next BB's leader can be obtained by a call to + * Compiler::fetch(last_pc). The redundancy is intentional to avoid + * this additional call. + */ + unsigned next_bb; + + /** + * An offset of the BB's code before code layout. + * If the BB has a prolog, then ipoff points to the prolog code. + */ + unsigned ipoff; + /** + * @brief Total size of native code of the basic block. + */ + unsigned code_size; + /** + * @brief Code address after layout (the final and real address). + */ + char * addr; + /** + * \b true if the basic block servers as a target for at least one + * JSR instruction. + */ + bool jsr_target; + /** + * \b true if this basic block is a catch handler. + * + * Normally this means that is has an additional small prolog + * before a code which is generated for its first bytecode. + */ + bool ehandler; + /** + * \b true if the basic block was processed in + * Compiler::comp_gen_code_bb(). + * + * Used to avoid recursion and to detect unreachable code + * at the stage of code layout. + */ + bool processed; +}; + +typedef map<unsigned, BBInfo> BBMAP; + +/** + * General info and various attributes of a method. + */ +struct MethInfo +{ + /** + * Initializes emty MethInfo. + * + * init() must be called before a first usage of MethInfo instance. + */ + MethInfo() + { + m_method = NULL; + m_klass = NULL; + m_kname = m_mname = m_sig = NULL; + } + + /** Initializes MethInfo structure. */ + void init(Method_Handle meth) + { + m_method = meth; + m_klass = method_get_class(m_method); + } + + /** Returns name of the method. */ + const char* meth_name(void) + { + if (NULL==m_mname) { + m_mname = method_get_name(m_method); + } + return m_mname; + } + + /** Returns name of method's class. */ + const char* meth_kname(void) + { + if (NULL==m_kname) { + m_kname = class_get_name(m_klass); + } + return m_kname; + } + + /** Returns method's signature. */ + const char* meth_sig(void) + { + if (NULL==m_sig) { + m_sig = method_get_descriptor(m_method); + } + return m_sig; + } + + /** Returns method fully qualified name, without signature.*/ + const char* meth_fname(void) + { + if (m_fname.empty()) { + m_fname = meth_kname(); + m_fname += "::"; + m_fname += meth_name(); + } + return m_fname.c_str(); + } + + /** Returns method fully qualified name, including signature.*/ + const char* meth_fname_sig(void) + { + if (m_fname_sig.empty()) { + m_fname_sig = meth_fname(); + m_fname += meth_sig(); + } + return m_fname_sig.c_str(); + } + /** Returns number of exception handlers in the method. */ + unsigned meth_num_handlers(void) const + { + return method_get_num_handlers(m_method); + } + + /** Tests whether the method is synchronized. */ + bool meth_is_sync(void) const + { + return method_is_synchronized(m_method); + } + /** Tests whether the method is static. */ + bool meth_is_static(void) const + { + return method_is_static(m_method); + } + /** + * Tests whether the method is synchronized and not static (instance). + */ + bool meth_is_sync_inst(void) const + { + return meth_is_sync() && !meth_is_static(); + } + /** Tests whether the method is constructor. */ + bool meth_is_ctor(void) + { + return strcmp(meth_name(), "<init>"); + } + /** Tests whether the method is constructor of Exception. */ + bool meth_is_exc_ctor(void) + { + return class_hint_is_exceptiontype(m_klass) && meth_is_ctor(); + } + +protected: + /** Method handle. */ + Method_Handle m_method; + /** Class handle. */ + Class_Handle m_klass; +private: + /** Class name. */ + const char* m_kname; + /** Method name. */ + const char* m_mname; + /** Method signature. */ + const char* m_sig; + /** Method fully qualified name, without signature.*/ + string m_fname; + /** Method fully qualified name, including signature.*/ + string m_fname_sig; +}; + +/** + * @brief Info about current state of a register in BBState. + */ +struct RegInfo { + /** + * @brief Number of references. + */ + unsigned refs; + /** + * @brief Number of locks. + */ + unsigned locks; + /** + * @brief A value currently known to be loaded into the register. + */ + Val val; +}; + + +/** + * @brief State of a basic block during code generation. + */ +class BBState { +public: + BBState() + { + clear(); + m_last_fr = fr0; + m_last_gr = gr0; + } + + void clear(void) + { + seen_gcpt = false; + stack_depth = NOTHING; + stack_mask = 0; + stack_mask_valid = false; + } + /** + * @brief Current state of mimic frame for the BB. + */ + JFrame jframe; + /** + * @brief State of registers. + */ + RegInfo m_regs[ar_num]; + /** + * @brief Recently stored stack depth. + * + * Used to eliminate unnecessary stack depth updates. + */ + unsigned stack_depth; + /** + * @brief Recently stored GC mask for stack. + * + * Used to eliminate unnecessary stack GC map updates. + * + * Only single word of the GC mask is stored - it's enough for most + * applications. + */ + unsigned stack_mask; + /** + * @brief Last used (allocated) GR register. + */ + AR m_last_gr; + /** + * @brief Last used (allocated) FR register. + */ + AR m_last_fr; + /** + * @brief \b true if #stack_mask contains a 'valid' (that is which was + * really written). + * + * The #stack_depth field may contain limited set of values and thus + * the field itself may carry info whether it contains 'non-initialized' + * flag (#NOTHING) or the real stack depth (any other value). + * + * In opposite, for the #stack_mask any value is valid combination. Thus + * it's necessary to indicate whether the stack_mask was initialized or + * not. Here is this flag intended for. + */ + unsigned stack_mask_valid; + /** + * @brief 'true' if there was at least one GC point in the basic block. + * + * Set during the code generation and is used to reduce unnecessary back + * branch polling code. + */ + unsigned seen_gcpt; + +}; + +}}; // ~namespace Jitrino::Jet2 + +#endif // ~__BBSTATE_H_INCLUDED__ + diff --git vm/jitrino/src/jet/trace.cpp vm/jitrino/src/jet/trace.cpp index 552f3fc..40a0e1e 100644 --- vm/jitrino/src/jet/trace.cpp +++ vm/jitrino/src/jet/trace.cpp @@ -14,28 +14,31 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** * @file - * @brief Implementation of debug tracing utilities. + * @brief Implementation of tracing and logging utilities. */ #include "trace.h" #include "compiler.h" -#include "cg_ia32.h" +#include "../shared/mkernel.h" #include "jit_intf.h" -#if !defined(PLATFORM_POSIX) +#ifdef _WIN32 #include <windows.h> + #define snprintf _snprintf #else #include <dlfcn.h> -#endif // !defined(PLATFORM_POSIX) +#endif // defined(_WIN32) #include <stdio.h> #include <stdarg.h> +#include "enc.h" +#include "Log.h" namespace Jitrino @@ -43,12 +46,45 @@ namespace Jitrino namespace Jet { +unsigned g_tbreak_id = NOTHING; + + +/** + * @defgroup LWDIS Disassembling routine for Jitrino.JET + * + * Jitrino.JET does not include disassembler. Instead, it may call + * external disassembling routine provided via exported function in + * dynamic library. + * + * To add such possibility, the library must export \e stdcall (where + * applicable) routine with the given signature. + * + * The library must be named lwdis (which is lwdis.dll on Windows and + * <b>lib</b>lwdis.so on Linux). The library must be accessible via regular + * library loading routines. On Windows it's normally PATH, System32 or + * application main module's folder. On Linux it's LD_LIBRARY_PATH. + * + * Also, on Linux an attempt will be made to load the library from the + * application main module's folder first (regardless of LD_LIBRARY_PATH). + * + * lwdis stands for <b>l</b>ight-<b>w</b>eight <b>dis</b>assembler. + * + * @see DISFUNC + * @{ + * @} + */ /** * @brief Disassembling function prototype. - * @todo document lwdis library usage + * + * @param[in] kode - code buffer to disassemble + * @param[out] buf - buffer to write disassembled string into + * @param buf_len - max length of the \c buf + * @return length of disassembled instruction, or 0 to indicate error. + * @see LWDIS */ typedef unsigned (*DISFUNC)(const char *kode, char *buf, unsigned buf_len); + /** * @brief Returns directory of currently running module, ended with file * separator. @@ -63,8 +99,8 @@ typedef unsigned (*DISFUNC)(const char * * The function always returns the same address which points to internal * static buffer. The buffer get initialized once, on the first call. * - * @note If called from within dynamic library, the function returns path for - * the 'main' executable module, not for the library itself. + * @note If called from within dynamic library, the function returns path + * for the 'main' executable module, not for the library itself. * * @return directory of currently running module, ended with file separator */ @@ -112,25 +148,57 @@ #endif void dbg(const char *frmt, ...) { + /* due to PMF integration static FILE *fout = fopen(LOG_FILE_NAME, "w"); assert(fout != NULL); va_list valist; va_start(valist, frmt); vfprintf(fout, frmt, valist); fflush(fout); - //vprintf(frmt, valist); + */ + char buf[1024]; + va_list valist; + va_start(valist, frmt); + vsnprintf(buf, sizeof(buf)-1, frmt, valist); + LogStream& log = Log::log(LogStream::CT); + log.printf(buf); + log.flush(); } -void __stdcall rt_dbg(const char *msg) +/* due to PMF integration +static FILE *rtf = NULL; +static Mutex rtf_mutex; +*/ +static int cnt = 0; +static int depth = 0; + +void dbg_rt(const char * frmt, ...) { - static FILE *f = NULL; - if (f == NULL) { - f = fopen(RUNTIME_LOG_FILE_NAME, "w"); - assert(f); + char buf[1024]; + va_list valist; + va_start(valist, frmt); + int len = vsnprintf(buf, sizeof(buf)-1, frmt, valist); + + if (buf[len-1] < ' ') { + buf[len-1] = ' '; + } + if (buf[len-2] < ' ') { + buf[len-2] = ' '; } - static int cnt = 0; + dbg_rt_out(buf); +} + +void __stdcall dbg_rt_out(const char *msg) +{ + /* due to PMF integration + if (rtf == NULL) { + rtf_mutex.lock(); + rtf = fopen(RUNTIME_LOG_FILE_NAME, "w"); + rtf_mutex.unlock(); + assert(rtf); + } + */ ++cnt; - static int depth = 0; if (!strncmp(msg, "enter", 5)) { ++depth; } @@ -138,14 +206,26 @@ void __stdcall rt_dbg(const char *msg) // [call depth] message <total count> // precede the whole string with several spaces, so elements // with big differences in the depth will be visually separated - fprintf(f, "%*c [%u] %s <%u>\n", depth%10, ' ', depth, msg, cnt); - fflush(f); + /* due to PMF integration + fprintf(rtf, "%*c [%u] %s <%u>\n", depth%10, ' ', depth, msg, cnt); + fflush(rtf); + */ + char buf[1024*5]; + snprintf(buf, sizeof(buf)-1, "%*c [%u] %s <%u>\n", + depth%10, ' ', depth, msg, cnt); + LogStream& log = Log::log(LogStream::RT); + log.printf(buf); + log.flush(); + if (!strncmp(msg, "exit", 4)) { --depth; } if (depth<0) { depth = 0; } + if (g_tbreak_id != NOTHING && g_tbreak_id == (unsigned)cnt) { + Encoder::debug(); + } } /** @@ -167,6 +247,10 @@ #else // if !platform_posix char buf[PATH_MAX+1]; snprintf(buf, sizeof(buf), "%sliblwdis.so", get_exe_dir()); void * handle = dlopen(buf, RTLD_NOW); + // An access with full path failed - let's try LD_LIBRARY_PATH. + if (handle==NULL) { + handle = dlopen("liblwdis.so", RTLD_NOW); + } disfunc = handle == NULL ? NULL : dlsym(handle, "disasm"); load_done = true; } @@ -174,104 +258,79 @@ #endif return (DISFUNC)disfunc; } -/** - * @brief Formats a string to describe the passed Slot. - * - * Returns a string formatted with a description of a slot passed. - * The string contains 3 numbers: \b vslot.regid.id and some characters - * which describe the state of the slot. - * - * The following legend is used: - * - * - * - an item was changed, need to be sync-ed to memeory - * - mem - an item is currently swapped to the memory - * - {} - an item represents a high part of a wide type (#dbl64 or #i64) - * - + - an item is positive or zero - * - nz - an item was tested against zero (for int-s) or against null - * (for jobj) - * - ! - an item need swapping (i.e. an overflow in stack regs cache - * happend) - */ -static ::std::string toStr2(const JFrame::Slot & s, bool stackSlot) +static ::std::string toStr(int i) +{ + char buf[20]; + snprintf(buf, sizeof(buf)-1, "%d", i); + return buf; +} + +::std::string CodeGen::toStr2(const Val& s, bool is_stack) const { ::std::string str; - if (s.jt == jvoid) { + if (false && s.jt() == jvoid) { str = "[x]"; return str; } - str = "["; - - //if( s.half ) str += '{'; - if (s.state() & SS_HI_PART) { - str += '{'; - } + str += "["; - if (s.attrs() & SA_NOT_NEG) { + if (s.has(VA_NOT_NEG)) { str += '+'; }; - str += jtypes[s.jt].name; - - str += ','; - if (s.state() & SS_SWAPPED) { - str += "mem"; - } - - if (s.state() & SS_NEED_SWAP) { - str += '!'; - } - - if (s.state() & SS_CHANGED) { - str += '*'; + if (s.jt() != jvoid) { + str += jtypes[s.jt()].name; } - if (s.attrs() & SA_NZ) { - str += "nz"; - } - - str += "#"; - char buf[30]; - if (s.vslot() == -1) { - str += "_"; - } - else { - sprintf(buf, "%d", s.vslot()); - str += buf; - } - - str += '/'; - if (s.regid() == -1) { - str += "_"; - } - else if (!(s.state() & SS_SWAPPED)) { - const RegName * regs; - regs = is_f(s.type()) ? Compiler::g_frnames : Compiler::g_irnames; - if (!stackSlot) { - regs += is_f(s.type()) ? - Compiler::F_STACK_REGS : Compiler::I_STACK_REGS; + if (s.is_imm()) { + str += ",imm="; + char buf[50] = {0}; + if (s.jt()<=i32) { snprintf(buf, sizeof(buf), "%d(0x%X)", s.ival(), s.ival()); } + if (s.jt()==flt32) { snprintf(buf, sizeof(buf), "%g", (double)s.fval()); } + if (s.jt()==dbl64) { snprintf(buf, sizeof(buf), "%g", s.dval()); } + if (s.jt()==jobj) { snprintf(buf, sizeof(buf), "%p", s.pval()); } + if (s.jt()==i64) { + if (is_big(i64)) { + snprintf(buf, sizeof(buf), "%d(0x%X)", s.ival(), s.ival()); + } + else { + snprintf(buf, sizeof(buf), "%ld(0x%LX)", (long int)s.lval(), (long long)s.lval()); + } } - sprintf(buf, "%s", getRegNameString(regs[s.regid()])); str += buf; + if (s.caddr() != NULL) { + snprintf(buf, sizeof(buf), "[@%p]", s.caddr()); + str += buf; + } } - else { - sprintf(buf, "%d", s.regid()); - str += buf; - } - - str += '/'; - if (s.id() == (unsigned) -1) { - str += "_"; + else if (s.is_reg()) { + str += "@"; + str += Encoder::to_str(s.reg()); } else { - sprintf(buf, "%d", s.id()); - str += buf; + assert(s.is_mem()); + int l = vvar_idx(s); + if (s.is_dummy()) { + str += "----"; + } + if (is_stack && l != -1) { + str += "@var#" + toStr(l); + } + else if (vis_stack(s) && is_stack) { + // no op - do not printout stack's offset + } + else if (l != -1 && !is_stack) { + // no op - do not printout local's offset + } + else { + str += "@"; + str += Encoder::to_str(s.base(), s.disp(), s.index(), s.scale()); + } } - - //if (s.changed) str += '*'; - //if (s.swapped) str += '!'; - //if (s.half) str += '}'; - if (s.state() & SS_HI_PART) { - str += '}'; + + if (s.has(VA_NZ)) { + str += ",nz"; } + str += "]"; return str; } @@ -294,17 +353,51 @@ static ::std::string toStr2(const JFrame return s; } -void dump_frame(char *ptr) +void dump_frame(const JitFrameContext* ctx, const MethodInfoBlock& info) { - // outdated - assert(false); // also need method_get_info_block() to collect the complete data + assert(false); // obsolete, need update + StackFrame sframe(info.get_num_locals(), + info.get_stack_max(), + info.get_in_slots()); + // Not yet implemented + assert(!(info.get_flags() & JMF_SP_FRAME)); - // presuming we have a EBP value - MethodInfoBlock rtinfo(NULL); - StackFrame stackframe(rtinfo.get_num_locals(), - rtinfo.get_stack_max(), rtinfo.get_in_slots()); - int *p = (int *) ptr; - + void *** pbp = devirt(bp, ctx); + char * bp_val = (char*)(**pbp); + + dbg_rt("****************************************"); +#define PRN(nam, frmt, type, meth_nam) \ + dbg_rt(#nam "= " #frmt "\n", *(type*)(bp_val+sframe.meth_nam())) + + PRN(retIP, %p, void*, ret); + PRN(info_gc_stack_depth, %d, int, info_gc_stack_depth); + PRN(info_gc_locals, %d, int, info_gc_locals); + PRN(thiz, %p, void*, thiz); + + unsigned num_locals = info.get_num_locals(); + for (unsigned i=0; i<num_locals; i++) { + //dbg_rt("local#%d = %p (%d)\n", i, ) + } + +#undef PRN + //int ret(void) const + //unsigned size(void) const + //int spill(unsigned i) const + //int (void) const + //int (void) const + //int info_gc_args(void) const + //int info_gc_stack(void) const + //int info_gc_regs(void) const + //int (void) const + //int scratch(void) const + //int scratch(AR ar) const + //int dbg_sp(void) const + //int local(unsigned i) const + //int stack_bot(void) const + //int stack_slot(unsigned Val) const + //int stack_max(void) const + //int native_stack_bot(void) const +#if 0 unsigned num_locals = rtinfo.get_num_locals(); unsigned stack_max = rtinfo.get_stack_max(); @@ -367,13 +460,14 @@ void dump_frame(char *ptr) *(p + stackframe.native_stack_bot() + i)); } dbg("===========================\n"); +#endif } void Compiler::dbg_trace_comp_start(void) { // start ; counter ; klass::method ; bytecode size ; signature dbg("start |%5d| %s::%s | bc.size=%d | %s\n", - g_methodsSeen, + m_methID, class_get_name(m_klass), method_get_name(m_method), method_get_byte_code_size(m_method), method_get_descriptor(m_method)); @@ -385,11 +479,11 @@ void Compiler::dbg_trace_comp_end(bool s // [REJECTED][code start ; code end ; code size] ; signature dbg("end |%5d| %s::%s | ", - g_methodsSeen, class_get_name(m_klass), method_get_name(m_method)); + m_methID, class_get_name(m_klass), method_get_name(m_method)); if (success) { - void * start = method_get_code_block_addr_jit(m_method, jit_handle); - unsigned size = method_get_code_block_size_jit(m_method, jit_handle); + unsigned size = method_get_code_block_size_jit(m_method, m_hjit); + void * start = size ? method_get_code_block_addr_jit(m_method, m_hjit) : NULL; dbg("code.start=%p | code.end=%p | code.size=%d", start, (char*)start + size, size); @@ -403,10 +497,8 @@ void Compiler::dbg_trace_comp_end(bool s ::std::string Compiler::toStr(const JInst & jinst, bool show_names) { - char buf[10240], tmp0[1024] = { 0 }, tmp1[1024] = { 0 }; + char tmp0[1024] = { 0 }, tmp1[1024] = { 0 }; - const InstrDesc & idesc = instrs[jinst.opcode]; - if (jinst.op0 != (int) NOTHING) { const char * lpClass = NULL; const char * lpItem = NULL; @@ -462,71 +554,94 @@ void Compiler::dbg_trace_comp_end(bool s if (jinst.op1 != (int) NOTHING) { sprintf(tmp1, " %d ", jinst.op1); } - - snprintf(buf, sizeof(buf)-1, "%c%2d) %-15s %-6s %-6s", - idesc.flags & OPF_GC_PT ? '*' : ' ', jinst.pc, idesc.name, - tmp0, tmp1); - - return::std::string(buf); + + char total[10240] = {0}, buf0[10240] = {0}, buf1[100] = {0}; + snprintf(buf0, sizeof(buf0)-1, "%c%2d) %-15s %-6s %-6s", + jinst.flags & OPF_STARTS_BB ? '@' : ' ', + jinst.pc, instrs[jinst.opcode].name, tmp0, tmp1); + + if (jinst.ref_count != 1 && jinst.ref_count != 0) { + //snprintf(buf1, sizeof(buf1)-1, "| id=%2d, rc=%d", jinst.id, jinst.ref_count); + snprintf(buf1, sizeof(buf1)-1, "| rc=%d", jinst.ref_count); + } + else { + //snprintf(buf1, sizeof(buf1)-1, "| id=%2d", jinst.id); + //snprintf(buf1, sizeof(buf1)-1, "| id=%2d", jinst.id); + } + snprintf(total, sizeof(total)-1, "%-40s %s", buf0, buf1); + return ::std::string(total); } void Compiler::dbg_dump_bbs(void) { static const char *bb_delim = "======================================\n"; - BBInfo bb = m_bbs[0]; - JInst jinst; - unsigned pc = 0; - while (NOTHING != (pc = fetch(pc, jinst))) { - bool bb_head = m_bbs.find(jinst.pc) != m_bbs.end(); - char jmptarget = ' '; + const unsigned bc_size = m_infoBlock.get_bc_size(); + for (unsigned pc=0; pc<bc_size; pc++) { + JInst& jinst = m_insts[pc]; + if (jinst.id == 0) continue; + bool bb_head = jinst.flags & OPF_STARTS_BB; + bool jsr_target = false; if (bb_head) { - bb = m_bbs[jinst.pc]; - if (bb.jmp_target) { - jmptarget = '>'; - } + assert(m_bbs.find(jinst.pc) != m_bbs.end()); dbg(bb_delim); + jsr_target = m_bbs[jinst.pc].jsr_target; } if (bb_head) { - const BBInfo& bbinfo = m_bbs[jinst.pc]; - dbg("ref.count=%d, %s, last=%u, next=%u\n", bbinfo.ref_count, - bbinfo.jsr_target ? "#JSR#" : "", - bbinfo.last_pc, bbinfo.next_bb); - dbg("%c%s\n", jmptarget, toStr(jinst, false).c_str()); - } - else { - dbg("%c%s\n", jmptarget, toStr(jinst, false).c_str()); + dbg("ref.count=%d, %s\n", jinst.ref_count, + jsr_target ? "#JSR#" : ""); } + dbg("%s\n", toStr(jinst, true).c_str()); } dbg(bb_delim); } -void dbg_dump_jframe(const char *name, const JFrame * pjframe) +void CodeGen::dbg_dump_state(const char *name, BBState * pState) { - const JFrame& jframe = *pjframe; - dbg("\n;; frame.%s, need_update=%d\n;;\n", name, jframe.need_update()); + JFrame& jframe = pState->jframe; + dbg("\n;;State: %s\n;;\n", name); // unsigned num_locals = jframe.num_vars(); dbg(";; locals.total=%d\n;; ", num_locals); - // Dump local variables first + // Dump local variables first - by 5 in a row ... for (unsigned i = 0; i < num_locals; i++) { if (i && !(i % 5)) { dbg("\n;; "); } - const JFrame::Slot & s = jframe.get_var(i); - dbg(" %s", toStr2(s, false).c_str()); + Val& s = jframe.var(i); + dbg(" %d)%s", i, toStr2(s, false).c_str()); + if (i>=128) { + dbg("\ntoo many locals, enough to dump.\n"); + break; + } } dbg("\n;;\n"); // ... and stack after that dbg(";; stack.size=%d\n;; ", jframe.size()); for (unsigned i = 0; i < jframe.size(); i++) { - if (i && !(i % 5)) { - dbg("\n;; "); - } - const JFrame::Slot & s = jframe.get_stack(i); + //if (i && !(i % 5)) { + // dbg("\n;; "); + //} + const Val& s = jframe.at(i); dbg(" %s", toStr2(s, true).c_str()); + dbg("\n;; "); + } + dbg("\n;;\n"); + dbg(";; regs: "); + bool not_first = false; + for (unsigned i=0; i<ar_num; i++) { + AR ar = _ar(i); + if (rrefs(ar) != 0 || rlocks(ar) != 0) { + if (not_first) { + dbg(","); + } + if (rlocks(ar)!=0) { dbg(">"); } + dbg("%s[%d]", Encoder::to_str(ar).c_str(), rrefs(ar)); + if (rlocks(ar)!=0) { dbg("<,%d", rlocks(ar)); } + not_first = true; + } } dbg("\n;;\n"); } @@ -543,9 +658,16 @@ void Compiler::dbg_dump_code(const char for (unsigned i = 0; i < length; /**/) { char buf[1024]; unsigned bytes = (disf) (code + i, buf, sizeof(buf)); - assert(bytes); // cant be 0, or we'll fall into infinite loop - i += bytes ? bytes : 1; - dbg("\t%s\n", buf); + if (bytes==0) { + // unknown instruction + unsigned char b = *(unsigned char*)(code+i); + dbg("\tdb 0x%x (%d, %c)\n", b, b, b<33 || b>127 ? '.' : b); + i += 1; // cant be 0, or we'll fall into infinite loop + } + else { + dbg("\t%s\n", buf); + i += bytes; + } } } else { @@ -571,23 +693,27 @@ void Compiler::dbg_dump_code(const char } } -void Compiler::dbg_dump_code(void) +void Compiler::dbg_dump_code_bc(const char * code, unsigned codeLen) { - const char * code = (const char*) - method_get_code_block_addr_jit(m_method, jit_handle); - const unsigned codeLen = - method_get_code_block_size_jit(m_method, jit_handle); + if (codeLen == 0) { + dbg("no code\n"); + return; + } unsigned pc = NOTHING; DISFUNC disf = get_disfunc(); + const char * first_inst = m_infoBlock.get_ip(0); + for (unsigned i=0; i<codeLen; /**/) { const char * ip = code + i; unsigned tmp = m_infoBlock.get_pc(ip); - if (pc != tmp) { + if (ip>=first_inst && pc != tmp) { // we just passed to a new byte code instruction, print it out pc = tmp; JInst jinst; + memset(&jinst, 0, sizeof(jinst)); unsigned next_pc = fetch(pc, jinst); dbg(";; %s\n", toStr(jinst, true).c_str()); + // Dump all instructions that do have the same IP. // check whether we have a code for this instruction - read next // item and compare its IP. If they are the same, then 'jinst' // represents an empty instruction with no real code - NOP, POP, @@ -598,6 +724,7 @@ void Compiler::dbg_dump_code(void) if (next_ip != ip) { break; } + memset(&jinst, 0, sizeof(jinst)); next_pc = fetch(next_pc, jinst); dbg(";; %s\n", toStr(jinst, true).c_str()); } @@ -605,9 +732,17 @@ void Compiler::dbg_dump_code(void) if (disf) { char buf[1024]; unsigned bytes = disf(code + i, buf, sizeof(buf)); - assert(bytes != 0); // cant be 0 - dbg("%p\t%s\n", code + i, buf); - i += bytes; + if (bytes==0) { + // unknown instruction + unsigned char b = *(unsigned char*)(code+i); + dbg("0x%p\tdb 0x%x (%d, %c)\n", code+i, b, b, b<33 || b>127 ? '.' : b); + i += 1; // cant be 0, or we'll fall into infinite loop + } + else { + dbg("0x%p\t%s\n", code + i, buf); + i += bytes; + } + } else { i += 1; diff --git vm/jitrino/src/jet/trace.h vm/jitrino/src/jet/trace.h index caf7e5d..ade8b1b 100644 --- vm/jitrino/src/jet/trace.h +++ vm/jitrino/src/jet/trace.h @@ -14,8 +14,8 @@ * limitations under the License. */ /** - * @author Alexander V. Astapchuk - * @version $Revision: 1.4.12.3.4.4 $ + * @author Alexander Astapchuk + * @version $Revision$ */ /** @@ -26,27 +26,37 @@ #if !defined(__TRACE_H_INCLUDED__) #define __TRACE_H_INCLUDED__ -#include "../shared/PlatformDependant.h" +#include "mib.h" +#include "jit_export_rt.h" // for JitFrameContext #include <string> +using std::string; namespace Jitrino { namespace Jet { class JFrame; +#ifdef _DEBUG /** * @def LOG_FILE_NAME * @brief Name of the file where the \link #dbg debug output \endlink goes. */ -#define LOG_FILE_NAME "jet.log" - -/** - * @def RUNTIME_LOG_FILE_NAME - * @brief Name of the file where the \link #rt_dbg debug output from the - * managed code \endlink goes. - */ -#define RUNTIME_LOG_FILE_NAME "jet.rt.log" + #define LOG_FILE_NAME "jet.dbg.log" +#else + #define LOG_FILE_NAME "jet.log" +#endif + +#ifdef _DEBUG + /** + * @def RUNTIME_LOG_FILE_NAME + * @brief Name of the file where the \link #rt_dbg debug output from the + * managed code \endlink goes. + */ + #define RUNTIME_LOG_FILE_NAME "jet.dbg.rt.log" +#else + #define RUNTIME_LOG_FILE_NAME "jet.rt.log" +#endif /** * @brief Performs debugging output, logged to file #LOG_FILE_NAME @@ -87,39 +97,37 @@ void dbg(const char * frmt, ...); * * @note Use with caution in multi-threaded environment. The function itself * is thread-safe, but counters work is perfromed without interlocked - * operations, somay be inadequate and may show different values from + * operations, so may be inadequate and may show different values from * one run to another for multiple threads. * @note The depth counter does not reflect if method finishes abruptly. * * @param msg - message to print out */ -void __stdcall rt_dbg(const char * msg) stdcall__; +void __stdcall dbg_rt_out(const char * msg) stdcall__; /** - * @brief Dumps the native stack frame, addressed by \c addr. - * @note implementation is obsolete, need update. - * @todo implementation is obsolete, need update. + * Same as dbg(), but the output goes into #RUNTIME_LOG_FILE_NAME. + * + * The output goes through #dbg_rt_out and is processed accordingly. */ -void dump_frame(char * ptr); +void dbg_rt(const char * frmt, ...); /** - * @brief Prints out the state of the JFrame. - * @param name - a name to print out before the JFrame dump, to identify the - * dump in the trace log - * @param pjframe - a JFrame instance to dump + * @brief Dumps the native stack frame, addressed by \c addr. + * @note implementation is obsolete, need update. + * @todo implementation is obsolete, need update. */ -void dbg_dump_jframe(const char * name, const JFrame * pjframe); - - +void dump_frame(const JitFrameContext* ctx, const MethodInfoBlock& info); /** * @brief Removes leading and trailing white spaces. */ ::std::string trim(const char * p); +extern unsigned g_tbreak_id; } }; // ~namespace Jitrino::Jet -#endif // ~__TRACE_H_INCLUDED__ +#endif // ~__TRACE_H_INCLUDED__ diff --git vm/jitrino/src/jet/val.h vm/jitrino/src/jet/val.h new file mode 100644 index 0000000..de4de65 --- /dev/null +++ vm/jitrino/src/jet/val.h @@ -0,0 +1,368 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander Astapchuk + * @version $Revision$ + */ + +/** + * @file + * @brief Val class declaration. + */ + +#if !defined(__VAL_H_INCLUDED__) +#define __VAL_H_INCLUDED__ + +#include "enc.h" + +namespace Jitrino { +namespace Jet { + +/** + * @defgroup VA_ Attributes of Val items. + */ +/** + * @brief 'Non Zero' - an items tested to be non-zero/non-null. + */ +#define VA_NZ (0x00000001) +/** + * @brief An item was tested against negative-size and is either positive or + * zero. + */ +#define VA_NOT_NEG (0x00000002) +/** + * @brief Item was marked in GC map. + */ +#define VA_MARKED (0x00000004) +/** + * @brief Item has its copy in the memory, no need to sync it back. + * + * For example, if the item was just loaded from memory to register - no + * need to store it back, e.g. to outlive CALL. Surely, this attribute + * must be dropped on a defining operation. + * + * Currently unused. + */ +#define VA_FRESH (0x00000008) +/// @} // ~VA_ + + +/** + * @brief Class Val represents various value items that may exist during + * compilation - immediate constants, memory references or values + * in registers. + * + * Val acts similar to Encoder's Opnd, but may carry extended information, + * that Opnd can't handle (e.g. attributes or float point and double items + * - both immediate-s and static constants in memory), and also has + * extended set of operations over it. + */ +class Val { +public: + /** + * Initializes the instance with \e dummy values. + * + * That is the instance gets #opnd_mem kind, but the type is jvoid, + * and the base register gets meaningless value ((AR)NOTHING). + */ + Val() + { + clear(); + } + Val(jtype jt) + { + clear(); m_jt = jt; + } + Val(jtype jt, AR ar) + { + clear(); m_kind = opnd_reg; m_jt = jt; m_reg = ar; + } + Val(int ival) + { + clear(); m_kind = opnd_imm; m_jt = i32; m_lval = ival; + m_surviveCalls = true; + } + Val(jlong lval) + { + clear(); m_kind = opnd_imm; m_jt = i64; m_lval = lval; + m_surviveCalls = true; + } + Val(float fval, const void* caddr = NULL) + { + clear(); + m_kind = opnd_imm; m_jt = flt32; m_fval = fval; m_caddr = caddr; + m_surviveCalls = true; + } + Val(double dval, const void* caddr = NULL) + { + clear(); + m_kind = opnd_imm; m_jt = dbl64; m_dval = dval; m_caddr = caddr; + m_surviveCalls = true; + } + Val(jtype jt, const void* p) + { + clear(); + m_kind = opnd_imm; assert(jt==jobj); m_jt = jt; m_pval = p; + } + Val(AR base, int disp, AR index = ar_x, unsigned scale=0) + { + clear(); + m_kind = opnd_mem; m_jt = jvoid; + m_base = base; m_index = index; + m_scale = scale; m_disp = disp; + } + Val(jtype jt, AR base, int disp, AR index = ar_x, unsigned scale=0) + { + clear(); + m_kind = opnd_mem; m_jt = jt; + m_base = base; m_index = index; + m_scale = scale; m_disp = disp; + } +#ifdef _IA32_ + /** + * Special-purpose ctor, only exists on IA-32. + * + * Packs \c disp address into displacement. + */ + Val(jtype jt, AR base, void* disp) + { + clear(); + m_kind = opnd_mem; m_jt = jt; + m_base = base; m_index = ar_x; + m_scale = 0; m_disp = (int)disp; + } +#endif + Val(const Opnd& op) { + clear(); + m_jt = op.jt(); + m_kind = op.kind(); + if (is_reg()) { + m_reg = op.reg(); + } + else if (is_mem()) { + m_base = op.base(); + m_disp = op.disp(); + m_index = op.index(); + m_scale = op.scale(); + } + else if (m_jt <= i32) { + m_lval = op.ival(); + m_surviveCalls = true; + } + else if (m_jt == jobj) { + m_pval = (const void*)op.lval(); + } + else { + assert(m_jt == i64); + m_lval = op.lval(); + } + } + /** + * Returns kind of the Val. + */ + OpndKind kind(void) const { return m_kind; } + /** + * Returns type of the Val. + */ + jtype jt(void) const { return m_jt; } + /** + * Returns type of the Val. + */ + jtype type(void) const { return m_jt; } + /** + * Tests whether this Val was not initialized to a valid value (e.g. + * created via Val() ctor). + */ + bool is_dummy(void) const + { + return is_mem() && base() == (AR)NOTHING; + } + bool is_reg(void) const { return kind() == opnd_reg; } + bool is_mem(void) const { return kind() == opnd_mem; } + bool is_imm(void) const { return kind() == opnd_imm; } + bool uses(AR ar) const + { + if (is_mem()) return base() == ar || index() == ar; + if (is_reg()) return reg() == ar; + return false; + } + // + bool operator==(const Val& that) const + { + if (kind() != that.kind()) return false; + if (is_reg()) return reg() == that.reg(); + if (is_mem()) { + // no test for jt() + return base() == that.base() && + disp() == that.disp() && + index() == that.index() && + scale() == that.scale(); + } + assert(is_imm()); + if (jt() != that.jt()) return false; + return m_lval == that.m_lval; + } + + bool operator!=(const Val& that) const + { + return !(*this==that); + } + /** + * Converts the Val into Opnd. + */ + Opnd as_opnd(void) const + { + return as_opnd(jt()); + } + /** + * Converts the Val into Opnd, and sets its type to \c jt. + */ + Opnd as_opnd(jtype jt) const + { + if (is_mem()) { + return Opnd(jt, base(), disp(), index(), scale()); + } + if (is_reg()) { + return Opnd(jt, reg()); + } + return Opnd(jt, lval()); + } + // + AR reg(void) const { return m_kind == opnd_reg ? m_reg : ar_x; } + // + int ival(void) const { return is_imm() ? (int)m_lval : 0; } + jlong lval(void) const { return is_imm() ? m_lval : 0; } + // + float fval(void) const { return is_imm() ? m_fval : 0; } + double dval(void) const { return is_imm() ? m_dval : 0; } + const void* pval(void) const { return is_imm() ? m_pval : NULL; } + const void* caddr(void) const { return m_caddr; } + /** + * Sets current Val's property \b survive_calls. + * @return reference to this Val instance + * @todo Make the property as attribute ? + */ + Val& long_live(void) { m_surviveCalls = true; return *this; }; + /** + * Sets a property whether this Val may outlive calls without any + * special preparation (e.g. static fiedls). + */ + void set_survive_calls(bool s = true) { m_surviveCalls = s; }; + /** + * Tests whether this Val may outlive calls without any special + * preparation (e.g. static fiedls). + */ + bool get_survive_calls(void) const { return m_surviveCalls; }; + /** + * Tests whether this Val may outlive calls without any special + * preparation (e.g. static fiedls). + */ + bool survive_calls(void) const { return m_surviveCalls; }; + /** + * Converts Val into memory reference. + */ + void to_mem(AR base, int disp, AR index = ar_x, unsigned scale=0) + { + m_kind = opnd_mem; + m_base = base; m_index = index; + m_scale = scale; m_disp = disp; + } + /** + * Converts Val into register reference. + */ + void to_reg(AR ar) + { + m_kind = opnd_reg; + m_reg = ar; + } + /** + * Returns \link VA_ attributes \endlink. + */ + unsigned attrs(void) const { return m_attrs; } + /** + * Assigns \link VA_ attributes \endlink to this Val. + */ + void attrs(unsigned attrs) + { + m_attrs = attrs; + } + /** + * Adds the specified \link VA_ attributes \endlink to this Val. + */ + void set(unsigned attr) + { + m_attrs |= attr; + } + /** + * Removes the specified \link VA_ attributes \endlink to this Val. + */ + void clr(unsigned attrs) + { + m_attrs &= ~attrs; + } + /** + * Tests whether this Val has at least one given attribute. + */ + bool has(unsigned mask) const + { + return 0 != (m_attrs&mask); + } + AR base(void) const { return m_kind == opnd_mem ? m_base : ar_x; } + AR index(void) const { return m_kind == opnd_mem ? m_index : ar_x; } + int disp(void) const { return m_kind == opnd_mem ? m_disp : 0; } + unsigned scale(void) const { return m_kind == opnd_mem ? m_scale : 0; } +private: + void clear(void) + { + m_kind = opnd_mem; + m_jt = jvoid; + // As we are initializing Val to be mem, then set m_base + // to something meaningless, to avoid confusions with real + // memory operands which has only displacement. + m_base = (AR)NOTHING; + m_index = ar_x; + m_lval = 0; + m_scale = m_disp = 0; + // + m_caddr = NULL; + m_attrs = 0; + m_surviveCalls = false; + } + OpndKind m_kind; + jtype m_jt; + union { + AR m_reg; + int m_disp; + jlong m_lval; + double m_dval; + float m_fval; + const void* m_pval; + }; + AR m_base; + AR m_index; + unsigned m_scale; + // + const void* m_caddr; + unsigned m_attrs; + bool m_surviveCalls; +}; + + + +}}; // ~namespace Jitrino::Jet + +#endif // ~__VAL_H_INCLUDED__ + diff --git vm/jitrino/src/main/CompilationContext.cpp vm/jitrino/src/main/CompilationContext.cpp index a25ee41..b78a9b2 100644 --- vm/jitrino/src/main/CompilationContext.cpp +++ vm/jitrino/src/main/CompilationContext.cpp @@ -19,30 +19,151 @@ */ #include "CompilationContext.h" -#include "optimizer.h" -#include "IRBuilder.h" #include "MemoryManager.h" +#include "EMInterface.h" +#include "JITInstanceContext.h" +#include "Type.h" +#include "PMF.h" +#include "PMFAction.h" +#include "mkernel.h" +namespace Jitrino { + +static TlsStack<CompilationContext> ccTls; + +CompilationContext::CompilationContext(MemoryManager& _mm, CompilationInterface* ci, JITInstanceContext* _jitContext) +: mm(_mm), compilationInterface(ci), compilationFailed(false), compilationFinished(false) +, currentLogStreams(0), pipeline(0), stageId(0) +{ + jitContext = _jitContext; + hirm = NULL; #ifdef _IPF_ #else -#include "ia32/Ia32CodeGenerator.h" + lirm = NULL; #endif + currentSessionAction = NULL; + currentSessionNum = 0; -namespace Jitrino { + ccTls.push((CompilationContext*)this); +} -CompilationContext::CompilationContext(MemoryManager& _mm, CompilationInterface* ci, JITModeData* mode) -: mm(_mm), compilationInterface(ci) -{ - thisPT = NULL; - optFlags = new (mm) OptimizerFlags; - transFlags = new (mm) TranslatorFlags; - irbFlags = new (mm) IRBuilderFlags(); - modeData = mode; -#ifdef _IPF_ +CompilationContext::~CompilationContext() { +#ifdef _DEBUG + CompilationContext* last = ccTls.pop(); + assert(this == last); #else - ia32CGFlags = new (mm) Ia32::CGFlags(); + ccTls.pop(); #endif } + +ProfilingInterface* CompilationContext::getProfilingInterface() const { + return getCurrentJITContext()->getProfilingInterface(); +} + +bool CompilationContext::hasDynamicProfileToUse() const { + ProfilingInterface* pi = getProfilingInterface(); + return pi->hasMethodProfile(ProfileType_Edge, *compilationInterface->getMethodToCompile()) + || pi->hasMethodProfile(ProfileType_EntryBackedge, *compilationInterface->getMethodToCompile()); +} + +CompilationContext* CompilationContext::getCurrentContext() { + CompilationContext* currentCC = ccTls.get(); + return currentCC; +} + +static int thread_nb = 0; + +struct TlsLogStreams { + + int threadnb; + MemoryManager mm; + + typedef std::pair<JITInstanceContext*, LogStreams*> Jit2Log; + + typedef StlVector<Jit2Log> Jit2Logs; + Jit2Logs jit2logs; + + TlsLogStreams () + :threadnb(thread_nb), mm(0, "TlsLogStreams"), jit2logs(mm) {} + + ~TlsLogStreams (); +}; + + +TlsLogStreams::~TlsLogStreams () +{ + Jit2Logs::iterator ptr = jit2logs.begin(), + end = jit2logs.end(); + for (; ptr != end; ++ptr) + ptr->second->~LogStreams(); +} + + +static TlsStore<TlsLogStreams> tlslogstreams; + + +/* + Because CompilationContext is a transient object (it created on start of compilation + and destroyed on end of compilation for every method), LogStreams table cannot reside + in it. Thread-local storage (TLS) is used to keep LogStreams. + On the other hand, different Jits can run on the same thread, so several LogStreams + have to be keept for single thread. + To optimize access, pointer to LogStreams is cached in CompilationContext. + + */ +LogStreams& LogStreams::current(JITInstanceContext* jitContext) { + + CompilationContext* ccp = CompilationContext::getCurrentContext(); + LogStreams* cls = ccp->getCurrentLogs(); + if (cls != 0) + return *cls; + +// No cached pointer is available for this CompilationContext. +// Find TLS for this thread. + + TlsLogStreams* sp = tlslogstreams.get(); + if (sp == 0) + { // new thread + ++thread_nb; + sp = new TlsLogStreams(); + tlslogstreams.put(sp); + } + +// Find which Jit is running now. + if (jitContext == 0) + jitContext = ccp->getCurrentJITContext(); + +// Was LogStreams created for this Jit already? + + TlsLogStreams::Jit2Logs::iterator ptr = sp->jit2logs.begin(), + end = sp->jit2logs.end(); + for (; ptr != end; ++ptr) + if (ptr->first == jitContext) { + // yes, it was - store pointer in the CompilationContext + ccp->setCurrentLogs(cls = ptr->second); + return *cls; + } + +// This is the first logger usage by the running Jit in the current thread. +// Create LogStreams now. + + cls = new (sp->mm) LogStreams(sp->mm, jitContext->getPMF(), sp->threadnb); + sp->jit2logs.push_back(TlsLogStreams::Jit2Log(jitContext, cls)); + ccp->setCurrentLogs(cls); + + return *cls; } + +LogStream& LogStream::log (SID sid, HPipeline* hp) +{ + if (hp == 0) + hp = CompilationContext::getCurrentContext()->getPipeline(); + Str name = ((PMF::Pipeline*)hp)->name; + return LogStream::log(sid, name.ptr, name.count); +} + + + +} //namespace diff --git vm/jitrino/src/main/CompilationContext.h vm/jitrino/src/main/CompilationContext.h index 24503d1..21f1e0d 100644 --- vm/jitrino/src/main/CompilationContext.h +++ vm/jitrino/src/main/CompilationContext.h @@ -25,53 +25,86 @@ namespace Jitrino { class MemoryManager; class CompilationInterface; -class JitrinoParameterTable; -struct OptimizerFlags; -struct TranslatorFlags; -struct IRBuilderFlags; -class JITModeData; +class JITInstanceContext; +class ProfilingInterface; +class IRManager; +class SessionAction; +class LogStreams; +class HPipeline; + #ifdef _IPF_ #else namespace Ia32{ - struct CGFlags; + class IRManager; } #endif class CompilationContext { public: - CompilationContext(MemoryManager& mm, CompilationInterface* ci, JITModeData* mode); - - CompilationInterface* getCompilationInterface() const {return compilationInterface;} + // Context of the current compilation + // Exists only during a compilation of method + // This class uses destructor and must not be created on MemoryManager + CompilationContext(MemoryManager& mm, CompilationInterface* ci, JITInstanceContext* jit); + ~CompilationContext(); + + CompilationInterface* getVMCompilationInterface() const {return compilationInterface;} MemoryManager& getCompilationLevelMemoryManager() const {return mm;} - JitrinoParameterTable* getThisParameterTable() const { return thisPT;} - void setThisParameterTable(JitrinoParameterTable* _thisPT) { assert(!thisPT); thisPT = _thisPT;} + JITInstanceContext* getCurrentJITContext() const {return jitContext;} + ProfilingInterface* getProfilingInterface() const; + + bool hasDynamicProfileToUse() const; + + bool isCompilationFailed() const {return compilationFailed;} + void setCompilationFailed(bool f) {compilationFailed = f;} + + bool isCompilationFinished() const {return compilationFinished;} + void setCompilationFinished(bool f) {compilationFinished = f;} + + IRManager* getHIRManager() const {return hirm;} + void setHIRManager(IRManager* irm) {hirm = irm;} + + SessionAction* getCurrentSessionAction() const {return currentSessionAction;} + void setCurrentSessionAction(SessionAction* sa) {currentSessionAction = sa;} + + void setCurrentSessionNum(int num) {currentSessionNum = num;} + int getCurrentSessionNum() const {return currentSessionNum;} + void setCurrentLogs(LogStreams* lsp) {currentLogStreams = lsp;} + LogStreams* getCurrentLogs() const {return currentLogStreams;} - OptimizerFlags* getOptimizerFlags() const {return optFlags;}; - TranslatorFlags* getTranslatorFlags() const {return transFlags;} - IRBuilderFlags* getIRBuilderFlags() const {return irbFlags;} + void setPipeline(HPipeline* pipe) {pipeline = pipe;} + HPipeline* getPipeline () const {return pipeline;} + + static CompilationContext* getCurrentContext(); - JITModeData* getCurrentModeData() const {return modeData;} #ifdef _IPF_ #else - Ia32::CGFlags* getIa32CGFlags() const {return ia32CGFlags;} + Ia32::IRManager* getLIRManager() const {return lirm;} + void setLIRManager(Ia32::IRManager* irm) {lirm = irm;} #endif private: MemoryManager& mm; CompilationInterface* compilationInterface; - JitrinoParameterTable* thisPT; + bool compilationFailed; + bool compilationFinished; - OptimizerFlags* optFlags; - TranslatorFlags* transFlags; - IRBuilderFlags* irbFlags; - JITModeData* modeData; + JITInstanceContext* jitContext; + IRManager* hirm; #ifdef _IPF_ #else - Ia32::CGFlags* ia32CGFlags; + Ia32::IRManager* lirm; #endif -}; + SessionAction* currentSessionAction; + int currentSessionNum; + LogStreams* currentLogStreams; + HPipeline* pipeline; -} + void initCompilationMode(); + +public: + int stageId; +}; +}//namespace #endif diff --git vm/jitrino/src/main/JITInstanceContext.cpp vm/jitrino/src/main/JITInstanceContext.cpp new file mode 100644 index 0000000..99e3171 --- /dev/null +++ vm/jitrino/src/main/JITInstanceContext.cpp @@ -0,0 +1,40 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ + +#include "JITInstanceContext.h" +#include "PMF.h" + +namespace Jitrino { + +JITInstanceContext::JITInstanceContext(MemoryManager& _mm, JIT_Handle _jitHandle, const char* _jitName) +: jitHandle(_jitHandle), jitName(_jitName) +, profInterface(NULL), mm(_mm) +{ + useJet = isNameReservedForJet(_jitName); + pmf = new (mm) PMF(mm, *this); +} + + +JITInstanceContext* JITInstanceContext::getContextForJIT(JIT_Handle jitHandle) { + return Jitrino::getJITInstanceContext(jitHandle); +} + + +} diff --git vm/jitrino/src/main/JITInstanceContext.h vm/jitrino/src/main/JITInstanceContext.h new file mode 100644 index 0000000..8db546c --- /dev/null +++ vm/jitrino/src/main/JITInstanceContext.h @@ -0,0 +1,71 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ + +#ifndef _JIT_INSTANCE_CONTEXT_H_ +#define _JIT_INSTANCE_CONTEXT_H_ + +#include "jit_export.h" +#include "MemoryManager.h" + +#include <assert.h> +#include <string> + + + +namespace Jitrino { + +class PMF; +class ProfilingInterface; + +class JITInstanceContext { + +public: + + JITInstanceContext(MemoryManager&, JIT_Handle _jitHandle, const char* _jitName); + + JIT_Handle getJitHandle() const {return jitHandle;} + + const std::string& getJITName() const {return jitName;} + + PMF& getPMF () const {return *pmf;} + + ProfilingInterface* getProfilingInterface() const {return profInterface;} + void setProfilingInterface(ProfilingInterface* pi) {assert(profInterface == NULL); profInterface = pi;} + + bool isJet() const {return useJet;} + static bool isNameReservedForJet(const char* jitName) {return strlen(jitName)>=3 && !strncmp(jitName, "JET", 3);} + + static JITInstanceContext* getContextForJIT(JIT_Handle jitHandle); + + MemoryManager& getGlobalMemoryManager() const {return mm;} + +private: + + JIT_Handle jitHandle; + std::string jitName; + PMF* pmf; + ProfilingInterface* profInterface; + bool useJet; + MemoryManager& mm; +}; + +}//namespace + +#endif diff --git vm/jitrino/src/main/Jitrino.cpp vm/jitrino/src/main/Jitrino.cpp index 031d3a7..d149a41 100644 --- vm/jitrino/src/main/Jitrino.cpp +++ vm/jitrino/src/main/Jitrino.cpp @@ -27,24 +27,31 @@ #include "FlowGraph.h" #include "MemoryEstimates.h" #include "TranslatorIntfc.h" #include "CodeGenIntfc.h" -#include "PropertyTable.h" #include "Log.h" -#include "Profiler.h" -//TODO remove -#include "Timer.h" #include "CountWriters.h" #include "XTimer.h" +#include "DrlVMInterface.h" + #ifndef PLATFORM_POSIX -#include <windows.h> -#endif + #pragma pack(push) + #include <windows.h> + #define vsnprintf _vsnprintf + #pragma pack(pop) +#else + #include <stdarg.h> + #include <sys/stat.h> + #include <sys/types.h> +#endif //PLATFORM_POSIX #include "CGSupport.h" #include "PlatformDependant.h" +#include "JITInstanceContext.h" +#include "PMF.h" +#include "PMFAction.h" #if defined(_IPF_) - #include "ipf/IpfRuntimeInterface.h" + #include "IpfRuntimeInterface.h" #else - #include "ia32/Ia32RuntimeInterface.h" - #include "ia32/Ia32InternalProfiler.h" + #include "ia32/Ia32RuntimeInterface.h" #endif #include <ostream> @@ -55,42 +62,11 @@ namespace Jitrino { // the JIT runtime interface RuntimeInterface* Jitrino::runtimeInterface = NULL; -JITModes Jitrino::jitModes; +JITInstances* Jitrino::jitInstances = NULL; struct Jitrino::Flags Jitrino::flags; -void Jitrino::readFlagsFromCommandLine(const JitrinoParameterTable *globalTable, const JitrinoParameterTable *methodTable) -{ - //const char* cg = params->lookup("CG"); - -#if defined(_IPF_) - flags.codegen = CG_IPF; -#else - flags.codegen = CG_IA32; -#endif - - flags.debugging_level = globalTable->lookupInt("debugging_level", -1); -#ifdef SUPPRESS_TOP_SKIP - flags.skip = false; -#else - flags.skip = methodTable->lookupBool("top::skip", false); -#endif - flags.gen_code = methodTable->lookupBool("top::gen_code", true); - flags.optimize = methodTable->lookupBool("top::optimize", true); - flags.time = methodTable->lookupBool("time", false); - flags.code_mapping_supported = methodTable->lookupBool("bc_maps", false); -} - -void Jitrino::showFlagsFromCommandLine() -{ -// Log::out() << " CG={IA32|ipf} = codegen target, currently ignored" << ::std::endl; - Log::out() << " debugging_level=int = ?" << ::std::endl; - Log::out() << " top::optimize[={ON,off}] = do optimizations" << ::std::endl; - Log::out() << " top::gen_code[={ON,off}] = do codegen" << ::std::endl; - Log::out() << " top::skip[={on,OFF}] = do not jit this method" << ::std::endl; - Log::out() << " time[={on,OFF}] = dump phase timing at end of run" << ::std::endl; -} // some demo parameters bool print_hashtable_info = false; @@ -98,316 +74,220 @@ char which_char = 'a'; // read in some flags to test mechanism bool initialized_parameters = false; -void initialize_parameters(CompilationInterface* ci, MethodDesc &md) +void initialize_parameters(CompilationContext* compilationContext, MethodDesc &md) { - - JitrinoParameterTable* parameterTable = Jitrino::getParameterTable(ci->getJitHandle()); - JitrinoParameterTable *thisPT = parameterTable->getTableForMethod(md); - - CompilationContext* compilationContext = ci->getCompilationContext(); - compilationContext->setThisParameterTable(thisPT); - - Jitrino::readFlagsFromCommandLine(parameterTable, thisPT); // must be first - - TranslatorIntfc::readFlagsFromCommandLine(compilationContext, Jitrino::flags.codegen != Jitrino::CG_IPF); - IRBuilder::readFlagsFromCommandLine(compilationContext); - readOptimizerFlagsFromCommandLine(compilationContext); - CodeGenerator::readFlagsFromCommandLine(compilationContext, Jitrino::flags.codegen != Jitrino::CG_IPF); - - // set logging levels - Log::initializeCategories(); - Log::initializeThresholds(thisPT->lookup("LOG")); + // BCMap Info Required + ((DrlVMCompilationInterface*)(compilationContext->getVMCompilationInterface()))->setBCMapInfoRequired(true); // do onetime things if (!initialized_parameters) { initialized_parameters = true; - - - if(Log::cat_root()->isDebugEnabled()) { - ::std::cerr << "\n***\nJitrino parameters:\n"; - parameterTable->print(::std::cerr); - ::std::cerr << "***\n"; - } - - - if (parameterTable->lookup("help")) { - Log::out() << ::std::endl - << "Jitrino command line parameters are:" << ::std::endl; - Jitrino::showFlagsFromCommandLine(); - TranslatorIntfc::showFlagsFromCommandLine(); - showOptimizerFlagsFromCommandLine(); - IRBuilder::showFlagsFromCommandLine(); - CodeGenerator::showFlagsFromCommandLine(Jitrino::flags.codegen != Jitrino::CG_IPF); - } } } -extern bool genCode(IRManager& irManager, - CompilationInterface& compilationInterface, - MethodDesc* methodDesc, - FlowGraph*, - OpndManager&, - Jitrino::Backend cgFlag, - bool sinkConstants, - bool sinkConstantsOne); - MemoryManager* Jitrino::global_mm = 0; -Timer* Jitrino::timers = 0; //TODO remove static CountWriter* countWriter = 0; -static CountTime globalTimer("timer:Total-Compilation"), - codegenTimer("timer:Code-generator"), - optimizerTimer("timer:Optimizer"), - translatorTimer("timer:Translator"), - typecheckerTimer("timer:Typechecker"); +static CountTime globalTimer("total-compilation time"); +static SummTimes summtimes("action times"); void Jitrino::crash (const char* msg) { - std::cerr << std::endl << "Jitrino crashed" << std::endl; - if (msg != 0) - std::cerr << msg << std::endl; + std::cerr << std::endl << "Jitrino crashed" << std::endl; + if (msg != 0) + std::cerr << msg << std::endl; + + exit(11); +} +void crash (const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); - exit(11); + char buff[1024]; + vsnprintf(buff, sizeof(buff), fmt, args); + + std::cerr << buff; + exit(11); } + + bool Jitrino::Init(JIT_Handle jh, const char* name) { //check for duplicate initialization - JitrinoParameterTable* parameterTable = getParameterTable(jh); - if (parameterTable!=NULL) { + JITInstanceContext* jitInstance = getJITInstanceContext(jh); + if (jitInstance!=NULL) { assert(0); return false; } - // check if modeName is already in use - for (JITModes::const_iterator it = jitModes.begin(), end = jitModes.end(); it!=end; ++it) { - JITModeData* modeData = *it; - if (modeData->getModeName() == name) { - assert(0); - return false; + // check if jitName is already in use + + if (jitInstances) { + for (JITInstances::const_iterator it = jitInstances->begin(), end = jitInstances->end(); it!=end; ++it) { + JITInstanceContext* jitContext = *it; + if (jitContext->getJITName() == name) { + assert(0); + return false; + } } - } - - bool firstJITInit = global_mm == 0; - if (firstJITInit) { + }else { global_mm = new MemoryManager(0,"Jitrino::Init.global_mm"); #if defined(_IPF_) - runtimeInterface = new IPF::IpfRuntimeInterface; + runtimeInterface = new IPF::RuntimeInterface; + flags.codegen = CG_IPF; #else runtimeInterface = new Ia32::RuntimeInterface; - + flags.codegen = CG_IA32; #endif - Log::initializeCategories(); + jitInstances = new (*global_mm) JITInstances(*global_mm); + + flags.time=false; } - parameterTable = new (*global_mm) JitrinoParameterTable(*global_mm, 1024); - JITModeData* modeData = new (*global_mm)JITModeData(jh, name, parameterTable); - jitModes.push_back(modeData); + jitInstance = new (*global_mm) JITInstanceContext(*global_mm, jh, name); + jitInstances->push_back(jitInstance); + + jitInstance->getPMF().init(jitInstances->size() == 1); + + if (countWriter == 0 && jitInstance->getPMF().getBoolArg(0, "time", false)) { + countWriter = new CountWriterFile(0); + XTimer::initialize(true); + } return true; } -void Jitrino::DeInit() +void Jitrino::DeInit(JIT_Handle jh) { -//TODO remove - //deinits all modes.. -// if( flags.time ) -// dumpTimers(); - - if (countWriter != 0) - { - delete countWriter; - countWriter = 0; - } - -#ifndef _IPF_ - Ia32::InternalProfiler::deinit(); -#endif + JITInstanceContext* jitInstance = getJITInstanceContext(jh); + if (jitInstance==NULL) { + assert(0); + return; + } + + if (countWriter != 0) { + jitInstance->getPMF().summTimes(summtimes); + } + jitInstance->getPMF().deinit(); + + killJITInstanceContext(jitInstance); + + if (jitInstances->empty()) { + if (countWriter != 0) { + delete countWriter; + countWriter = 0; + } + } } -void Jitrino::NextCommandLineArgument(JIT_Handle jit, const char *name, const char *arg) -{ - if (strnicmp(name, "-xjit", 5) == 0) { - size_t argLen = strlen(arg); - JITModeData* paramMode = NULL; - for (JITModes::const_iterator it = jitModes.begin(), end = jitModes.end(); it!=end; ++it) { - JITModeData* mode = *it; - std::string modeName = mode ->getModeName(); - if (argLen + 2 < modeName.length() && !strncmp(modeName.c_str(), arg, argLen) - && !strncmp(modeName.c_str() + argLen, "::", 2)) - { - paramMode = mode; - arg = arg + argLen + 2; - break; - } - } - JITModeData* currentJitMode = getJITModeData(jit); - if (paramMode == NULL || paramMode == currentJitMode) { - currentJitMode->setParameterTable(currentJitMode->getParameterTable()->insertFromCommandLine(arg)); +class FalseSessionAction: public SessionAction { +public: + virtual void run () {getCompilationContext()->setCompilationFailed(true);} + +}; +static ActionFactory<FalseSessionAction> _false("false"); + +class LockMethodSessionAction : public SessionAction { +public: + virtual void run () { + CompilationContext* cc = getCompilationContext(); + CompilationInterface* ci = cc->getVMCompilationInterface(); + ci->lockMethodData(); + MethodDesc* methDesc = ci->getMethodToCompile(); + if (methDesc->getCodeBlockSize(0) > 0 || methDesc->getCodeBlockSize(1) > 0){ + cc->setCompilationFinished(true); + ci->unlockMethodData(); } } - return; -} +}; +static ActionFactory<LockMethodSessionAction> _lock_method("lock_method"); -static void postTranslator(IRManager& irManager) -{ - FlowGraph& flowGraph = irManager.getFlowGraph(); - MethodDesc& methodDesc = irManager.getMethodDesc(); - if (Log::cat_fe()->isIREnabled()) { - Log::out() << "PRINTING LOG: After Translator" << ::std::endl; - flowGraph.printInsts(Log::out(), methodDesc); +class UnlockMethodSessionAction : public SessionAction { +public: + virtual void run () { + getCompilationContext()->getVMCompilationInterface()->unlockMethodData(); } - flowGraph.cleanupPhase(); - if (Log::cat_fe()->isIR2Enabled()) { - Log::out() << "PRINTING LOG: After Cleanup" << ::std::endl; - flowGraph.printInsts(Log::out(), methodDesc); +}; +static ActionFactory<UnlockMethodSessionAction> _unlock_method("unlock_method"); + + +void runPipeline(CompilationContext* c) { + + globalTimer.start(); + + PMF::PipelineIterator pit((PMF::Pipeline*)c->getPipeline()); + while (pit.next()) { + SessionAction* sa = pit.getSessionAction(); + sa->setCompilationContext(c); + c->setCurrentSessionAction(sa); + c->stageId++; + sa->start(); + sa->run(); + sa->stop(); + c->setCurrentSessionAction(0); + if (c->isCompilationFailed() || c->isCompilationFinished()) { + break; + } } + + globalTimer.stop(); } -bool compileMethod(CompilationInterface& compilationInterface) { - +bool compileMethod(CompilationContext* cc) { + if(Jitrino::flags.skip) { return false; - } + } // // IRManager contains the method's IR for the global optimizer. // It contains a memory manager that is live during optimization // - JitrinoParameterTable* parameterTable = Jitrino::getParameterTable(compilationInterface.getJitHandle()); - JitrinoParameterTable* methodParameterTable = parameterTable->getTableForMethod(*compilationInterface.getMethodToCompile()); - IRManager irManager(compilationInterface, *methodParameterTable); - MethodDesc* methDesc = compilationInterface.getMethodToCompile(); - MemoryManager& ir_mmgr = irManager.getMemoryManager(); + MethodDesc* methDesc = cc->getVMCompilationInterface()->getMethodToCompile(); + MemoryManager& ir_mmgr = cc->getCompilationLevelMemoryManager(); - // init global map for handlers initHandleMap(ir_mmgr, methDesc); - // + // add bc <-> HIR code map handler StlVector<uint64> *bc2HIRMap; - - if (compilationInterface.isBCMapInfoRequired()) { + if (cc->getVMCompilationInterface()->isBCMapInfoRequired()) { bc2HIRMap = new(ir_mmgr) StlVector<uint64>(ir_mmgr, methDesc->getByteCodeSize() - * (ESTIMATED_HIR_SIZE_PER_BYTECODE) + 5); + * (ESTIMATED_HIR_SIZE_PER_BYTECODE) + 5, ILLEGAL_VALUE); addContainerHandler(bc2HIRMap, bcOffset2HIRHandlerName, methDesc); } - if (countWriter == 0) - { - const char* arg = parameterTable->lookup("counters"); - if (arg != 0) // can be empty string "" - { -#ifdef _WIN32 - if (strnicmp(arg, "mail:", 5) == 0) - countWriter = new CountWriterMail(arg+5); - else -#endif - countWriter = new CountWriterFile(arg); - } - else if (Jitrino::flags.time) - countWriter = new CountWriterFile(0); - - XTimer::initialize(countWriter != 0); - } - - // - // translate the method - // - globalTimer.start(); - translatorTimer.start(); - TranslatorIntfc::translateByteCodes(irManager); - - translatorTimer.stop(); - postTranslator(irManager); - // - // optimize it - // - optimizerTimer.start(); - - if (Jitrino::flags.optimize) { - if (!optimize(irManager)) { - globalTimer.stop(); - optimizerTimer.stop(); - return FALSE; // failure optimizing - } - } - - optimizerTimer.stop(); - - // - // generate code - // - bool success = false; - codegenTimer.start(); - if (Jitrino::flags.gen_code) { - // Modification of data only happens during the codegen stage. - // The lock must not surround a code where managed code execution - // may happen. - // It's not expected that code gen phase will lead to a resolution - // (and thus to execution of managed code), so it should be safe to - // lock here. - // Though there is a very little chance that that the resolution (and - // managed code execution) happen in code gen. In this case will - // need to move the lock into code gen code. -#if !defined(_IPF_) // on IPF, the whole compilation session protected by lock - compilationInterface.lockMethodData(); -#endif - - if (methDesc->getCodeBlockSize(0) > 0 || methDesc->getCodeBlockSize(1)){ - success = true; - } - else { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); - success = genCode(irManager, - compilationInterface, - &irManager.getMethodDesc(), - &irManager.getFlowGraph(), - irManager.getOpndManager(), - Jitrino::flags.codegen, - optimizerFlags.sink_constants, - optimizerFlags.sink_constants1); - } -#if !defined(_IPF_) // on IPF, the whole compilation session protected by lock - compilationInterface.unlockMethodData(); -#endif - } - codegenTimer.stop(); - globalTimer.stop(); - + runPipeline(cc); + // remove bc <-> HIR code map handler - if (compilationInterface.isBCMapInfoRequired()) { + if (cc->getVMCompilationInterface()->isBCMapInfoRequired()) { removeContainerHandler(bcOffset2HIRHandlerName, methDesc); } + + bool success = !cc->isCompilationFailed(); return success; } -bool Jitrino::CompileMethod(CompilationInterface* compilationInterface) { +bool Jitrino::CompileMethod(CompilationContext* cc) { + CompilationInterface* compilationInterface = cc->getVMCompilationInterface(); #ifdef _IPF_ //IPF CG params are not safe -> add them to CompilationContext and remove this lock compilationInterface->lockMethodData(); #endif bool success = false; MethodDesc& methodDesc = *compilationInterface->getMethodToCompile(); - const char* methodName = methodDesc.getName(); - const char* methodTypeName = methodDesc.getParentType()->getName(); - const char* methodSignature=methodDesc.getSignatureString(); - - Log::pushSettings(); - - initialize_parameters(compilationInterface, methodDesc); - Log::setMethodToCompile(methodTypeName, methodName, methodSignature, methodDesc.getByteCodeSize()); + initialize_parameters(cc, methodDesc); if (methodDesc.getByteCodeSize() <= 0) { - Log::cat_root()->error << " ... Skipping because of 0 byte codes ..." << ::std::endl; + Log::out() << " ... Skipping because of 0 byte codes ..." << ::std::endl; assert(0); } else { - success = compileMethod(*compilationInterface); + success = compileMethod(cc); } - Log::clearMethodToCompile(success, compilationInterface); - Log::popSettings(); // discard current and restore previous log settings #ifdef _IPF_ compilationInterface->unlockMethodData(); #endif - return success; + return success; } void @@ -435,6 +315,12 @@ Jitrino::GetInlinedMethod(InlineInfoPtr return runtimeInterface->getInlinedMethod(ptr, offset, inline_depth); } +uint16 +Jitrino::GetInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) +{ + return runtimeInterface->getInlinedBc(ptr, offset, inline_depth); +} + bool Jitrino::CanEnumerate(MethodDesc* methodDesc, NativeCodePtr eip) { @@ -476,43 +362,24 @@ Jitrino::GetNativeLocationForBc(MethodDe return runtimeInterface->getNativeLocationForBc(method, bc_pc, native_pc); } -//TODO remove -Timer * -Jitrino::addTimer(const char *name) -{ - Timer *newTimer = new (*global_mm) Timer(name, timers); - timers = newTimer; - return newTimer; -} - -//TODO remove -void -Jitrino::dumpTimers() -{ - Timer *timer = timers; - if (timer) { - Log::out() << ::std::endl; - Log::out() << "Timers: " << ::std::endl; - while (timer) { - timer->print(Log::out()); - timer = timer->getNext(); +JITInstanceContext* Jitrino::getJITInstanceContext(JIT_Handle jitHandle) { + if (jitInstances) + for (JITInstances::const_iterator it = jitInstances->begin(), end = jitInstances->end(); it!=end; ++it) { + JITInstanceContext* jit= *it; + if (jit->getJitHandle() == jitHandle) { + return jit; + } } - } + return NULL; } -JITModeData* Jitrino::getJITModeData(JIT_Handle jit) { - for (JITModes::const_iterator it = jitModes.begin(), end = jitModes.end(); it!=end; ++it) { - JITModeData* modeData = *it; - if (modeData->getJitHandle() == jit) { - return modeData; +void Jitrino::killJITInstanceContext(JITInstanceContext* jit) { + for (JITInstances::iterator it = jitInstances->begin(), end = jitInstances->end(); it!=end; ++it) { + if (*it == jit) { + jitInstances->erase(it); + return; } } - return NULL; -} - -JitrinoParameterTable* Jitrino::getParameterTable(JIT_Handle jit) { - JITModeData* modeData = getJITModeData(jit); - return modeData!=NULL?modeData->getParameterTable(): NULL; } @@ -530,37 +397,30 @@ #if defined(_WIN32) || defined(_WIN64) extern "C" bool __stdcall DllMain(void *dll_handle, uint32 reason, void *reserved) { - switch (reason) { - case DLL_PROCESS_ATTACH: - // allocate a TLS index. - if ((Jitrino::tlsLogKey = TlsAlloc()) == TLS_OUT_OF_INDEXES) { - assert(false); - return false; - } - // fall through, the new process creates a new thread - - case DLL_THREAD_ATTACH: - // notify interested parties (only one now) - Jitrino::Log::notifyThreadStart(&Jitrino::tlsLogKey); - break; - - case DLL_THREAD_DETACH: - // notify interested parties (only one now) - Jitrino::Log::notifyThreadFinish(&Jitrino::tlsLogKey); - break; - - case DLL_PROCESS_DETACH: - // notify interested parties (only one now) - Jitrino::Log::notifyThreadFinish(&Jitrino::tlsLogKey); - // release the TLS index - TlsFree(Jitrino::tlsLogKey); - Jitrino::tlsLogKey = TLS_OUT_OF_INDEXES; - break; - - default: - break; - } -return TRUE; - } + switch (reason) { + case DLL_PROCESS_ATTACH: + // allocate a TLS index. + // fall through, the new process creates a new thread + + case DLL_THREAD_ATTACH: + // notify interested parties (only one now) + break; + + case DLL_THREAD_DETACH: + // notify interested parties (only one now) + Jitrino::Tls::threadDetach(); + break; + + case DLL_PROCESS_DETACH: + // notify interested parties (only one now) + // release the TLS index + Jitrino::Tls::threadDetach(); + break; + + default: + break; + } + return TRUE; +} #endif // defined(_WIN32) || defined(_WIN64) diff --git vm/jitrino/src/main/Jitrino.h vm/jitrino/src/main/Jitrino.h index f085c82..969725c 100644 --- vm/jitrino/src/main/Jitrino.h +++ vm/jitrino/src/main/Jitrino.h @@ -26,9 +26,7 @@ #define _JITRINO_H_ #include "open/types.h" #include "jit_export.h" #include "VMInterface.h" - -#include <vector> -#include <string> +#include "Stl.h" #include <assert.h> // this 'ifndef' makes Jitrino (in jitrino_dev branch) build successfully both on @@ -42,21 +40,21 @@ #endif namespace Jitrino { -class JitrinoParameterTable; +void crash (const char* fmt, ...); + class MemoryManager; -class Timer; class RuntimeInterface; +class ProfilingInterface; -class JITModeData; -typedef std::vector<JITModeData*> JITModes; +class JITInstanceContext; +typedef StlVector<JITInstanceContext*> JITInstances; class Jitrino { public: - static void crash (const char* msg); + static void crash (const char* msg); static bool Init(JIT_Handle jit, const char* name); - static void DeInit(); - static void NextCommandLineArgument(JIT_Handle jit, const char *name, const char *arg); - static bool CompileMethod(CompilationInterface* compilationInterface); + static void DeInit(JIT_Handle jit); + static bool CompileMethod(CompilationContext* compilationContext); static void UnwindStack(MethodDesc* methodDesc, ::JitFrameContext* context, bool isFirst); static void GetGCRootSet(MethodDesc* methodDesc, GCInterface* gcInterface, const ::JitFrameContext* context, bool isFirst); static bool CanEnumerate(MethodDesc* methodDesc, NativeCodePtr eip); @@ -74,68 +72,31 @@ #endif static uint32 GetInlineDepth(InlineInfoPtr ptr, uint32 offset); static Method_Handle GetInlinedMethod(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth); + static uint16 GetInlinedBc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth); enum Backend { CG_IPF, CG_IA32, - CG_IA }; struct Flags { - int debugging_level; - bool skip; - bool optimize; - bool gen_code; Backend codegen; bool time; - bool code_mapping_supported; }; // Global Jitrino Flags (are set on initialization, not modified at runtime) static struct Flags flags; + static JITInstanceContext* getJITInstanceContext(JIT_Handle jitHandle); + static void killJITInstanceContext(JITInstanceContext* jit); - static void readFlagsFromCommandLine(const JitrinoParameterTable *globalTable, const JitrinoParameterTable *methodTable); - static void showFlagsFromCommandLine(); - - static Timer *addTimer(const char *); - static void dumpTimers(); - static JITModeData* getJITModeData(JIT_Handle jit); - static JitrinoParameterTable* getParameterTable(JIT_Handle jit); private: static MemoryManager *global_mm; - static Timer *timers; static RuntimeInterface* runtimeInterface; - - static JITModes jitModes; -}; - -class JITModeData { -public: - JITModeData(JIT_Handle _jitHandle, const char* _modeName, JitrinoParameterTable* _params) - : jitHandle(_jitHandle), modeName(_modeName), parameterTable(_params), profInterface(NULL) - {useJet = isJetModeName(_modeName);} - - JIT_Handle getJitHandle() const {return jitHandle;} - - const std::string& getModeName() const {return modeName;} - - JitrinoParameterTable* getParameterTable() const {return parameterTable;} - void setParameterTable(JitrinoParameterTable* pTable) {parameterTable = pTable;} - - ProfilingInterface* getProfilingInterface() const {return profInterface;} - void setProfilingInterface(ProfilingInterface* pi) {assert(profInterface == NULL); profInterface = pi;} - - bool isJet() const {return useJet;} - static bool isJetModeName(const char* modeName) {return strlen(modeName)>=3 && !strncmp(modeName, "JET", 3);} -private: - JIT_Handle jitHandle; - std::string modeName; - JitrinoParameterTable* parameterTable; - ProfilingInterface* profInterface; - bool useJet; + static JITInstances* jitInstances; }; + } //namespace Jitrino #endif // _JITRINO_H_ diff --git vm/jitrino/src/main/Log.cpp vm/jitrino/src/main/Log.cpp index 3a8b9b3..2008d9f 100644 --- vm/jitrino/src/main/Log.cpp +++ vm/jitrino/src/main/Log.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as appicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,976 +15,142 @@ */ /** - * @author Intel, George A. Timoshenko - * @version $Revision: 1.23.20.4 $ + * @author Intel, Sergey L. Ivashin + * @version $Revision$ * */ -#include <errno.h> // errno -#include <string.h> // strerror -#include <iostream> -#include <fstream> #include "Log.h" -#include "methodtable.h" +#include "PMF.h" +#include "PMFAction.h" +#include "CompilationContext.h" -namespace Jitrino { - -// If NULL, log all methods. -const char* Log::methodNameToLog = NULL; - -static bool singlefile = false; -static bool singlefile_old_log_dropped = false; -static bool fileclasstree = false; -static Method_Table *filter = NULL; - - -// forward declarations -static void mk_dir(const char *dirname); -static Log* get_tls_log(); -static bool close_log_stream(::std::ostream **os_ptr); - -Log::Settings::Settings() { - outp = &::std::cout; - created_outp = false; - logDirName[0] = '\0'; - dotFileDirName[0] = '\0'; - logFileName[0] = '\0'; - className[0] = '\0'; - methodName[0] = '\0'; - methodSignature[0] = '\0'; - logFileCreationPending = false; - truncateLogFileOnCreation = false; - doLogging = true; -} - -Log::Settings* Log::push() { - Log::Settings *s = new Log::Settings(); - settingsStack.push_back(s); - return s; -} - -Log::Settings* Log::pop() { - Log::Settings *res = top(); - assert(res != NULL); - settingsStack.pop_back(); - return res; -} - -Log::Settings* Log::top() { - int stack_size = (int)settingsStack.size(); - return stack_size > 0 ? settingsStack[stack_size-1] : NULL; -} - -void Log::pushSettings() { - // UNUSED_VAR Settings *s = - cur()->push(); -} - -void Log::popSettings() { - Log *tls_log = cur(); - Settings *s = tls_log->pop(); - - // close popped log stream and dispose of settings - close_log_stream(&(s->outp)); - delete s; - - // restore previous settings of the categories - Category *tls_root_category = tls_log->cat_root(); - Log::Settings *s_ptr = tls_log->top(); - - if (s_ptr != NULL) { - Log::Settings &s = *s_ptr; - tls_root_category->setLogging(s.doLogging); - tls_root_category->set_out(s.outp); - } -} - -Log::Log() { - root = NULL; - fe = NULL; - opt_sim = NULL; - opt_vn = NULL; - opt = NULL; - opt_dc = NULL; - opt_abcd = NULL; - opt_inline = NULL; - opt_loop = NULL; - opt_gcm = NULL; - opt_gvn = NULL; - opt_td = NULL; - opt_reassoc = NULL; - opt_mem = NULL; - opt_sync = NULL; - opt_gc = NULL; -// opt_prefetch = NULL; - opt_lazyexc = NULL; - cg = NULL; - cg_cs = NULL; - cg_cl = NULL; - cg_ce = NULL; - cg_sched = NULL; - - rt = new Category("rt"); - rt->setParentOverride(false); - cg_gc = rt->createCategory("gc"); - patch = rt->createCategory("patch"); - ti = NULL; - ti_bc = rt->createCategory("bc"); - - typechecker = NULL; - - rootLogDirName[0] = '\0'; - rt_outp = NULL; - methodCounter=0; - nextStageId=0; -} - -#define DELETE_CATEGORY(name) if (name != NULL) delete name; name = NULL - -Log::~Log() { - DELETE_CATEGORY(root); - DELETE_CATEGORY(fe); - DELETE_CATEGORY(opt_sim); - DELETE_CATEGORY(opt_vn); - DELETE_CATEGORY(opt); - DELETE_CATEGORY(opt_dc); - DELETE_CATEGORY(opt_abcd); - DELETE_CATEGORY(opt_inline); - DELETE_CATEGORY(opt_loop); - DELETE_CATEGORY(opt_gcm); - DELETE_CATEGORY(opt_gvn); - DELETE_CATEGORY(opt_td); - DELETE_CATEGORY(opt_reassoc); - DELETE_CATEGORY(opt_mem); - DELETE_CATEGORY(opt_sync); - DELETE_CATEGORY(opt_gc); -// DELETE_CATEGORY(opt_prefetch); - DELETE_CATEGORY(opt_lazyexc); - DELETE_CATEGORY(cg); - DELETE_CATEGORY(cg_cs); - DELETE_CATEGORY(cg_cl); - DELETE_CATEGORY(cg_ce); - DELETE_CATEGORY(cg_gc); - DELETE_CATEGORY(cg_sched); - DELETE_CATEGORY(rt); - DELETE_CATEGORY(patch); - DELETE_CATEGORY(typechecker); - DELETE_CATEGORY(ti); - DELETE_CATEGORY(ti_bc); - - close_log_stream(&rt_outp); -} - -//---------- +#ifdef _WIN32 +#define snprintf _snprintf +#endif -void -Log::initializeCategories() -{ - cur()->initializeCategories_(); -} -void -Log::initializeCategories_() +namespace Jitrino { - if (!root) { - root = new Category("root"); - fe = root->createCategory("fe"); - opt = root->createCategory("opt"); - opt_sim = opt->createCategory("sim"); - opt_vn = opt->createCategory("vn"); - opt_dc = opt->createCategory("dc"); - opt_abcd = opt->createCategory("abcd"); - opt_inline = opt->createCategory("inline"); - opt_loop = opt->createCategory("loop"); - opt_gcm = opt->createCategory("gcm"); - opt_gvn = opt->createCategory("gvn"); - opt_reassoc = opt->createCategory("reassoc"); - opt_mem = opt->createCategory("mem"); - opt_sync = opt->createCategory("sync"); - opt_td = opt->createCategory("td"); - opt_gc = opt->createCategory("gc"); -// opt_prefetch = opt->createCategory("prefetch"); - opt_lazyexc = opt->createCategory("lazyexc"); - cg = root->createCategory("cg"); - cg_cs = cg->createCategory("cs"); - cg_cl = cg->createCategory("cl"); - cg_ce = cg->createCategory("ce"); - cg_gc = cg->createCategory("gc"); - cg_sched = cg->createCategory("sched"); - patch = root->createCategory("patch"); - typechecker = root->createCategory("typechecker"); - ti = root->createCategory("ti"); - ti_bc = ti->createCategory("bc"); - } else { - root->reset(false); - fe->reset(true); - opt->reset(true); - opt_sim->reset(true); - opt_vn->reset(true); - opt_dc->reset(true); - opt_abcd->reset(true); - opt_inline->reset(true); - opt_reassoc->reset(true); - opt_mem->reset(true); - opt_sync->reset(true); - opt_loop->reset(true); - opt_gcm->reset(true); - opt_gvn->reset(true); - opt_td->reset(true); - opt_gc->reset(true); -// opt_prefetch->reset(true); - opt_lazyexc->reset(true); - cg->reset(true); - cg_cs->reset(true); - cg_cl->reset(true); - cg_ce->reset(true); - cg_gc->reset(true); - cg_sched->reset(true); - patch->reset(true); - typechecker->reset(true); - ti->reset(true); - ti_bc->reset(true); - } -} -//---------- -void -Log::initializeThreshold(const char* catName, const char* level) +#ifndef _NOLOG +bool Log::isLogEnabled (LogStream::SID sid) { - cur()->initializeThreshold_(catName, level); -} - -void -Log::initializeThreshold_(const char* catName, const char* level) -{ - Log::Settings *s_ptr = top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if(catName != NULL) { - if (strncmp(catName,"singlefile",10)==0) { - singlefile = true; - if (!s.created_outp) { - s.created_outp=true; - bool truncate = !singlefile_old_log_dropped; - setLogDir_(getRootLogDirName_(), truncate); - singlefile_old_log_dropped = true; - } - if( strcmp(level, "tree")==0 ) { - fileclasstree = true; - } - } else if (strncmp(catName,"file",4)==0) { - assert(!singlefile); - if (!s.created_outp) { - s.created_outp=true; - setLogDir_(getRootLogDirName_(), false); - } - if( strcmp(level, "tree")==0 ) { - fileclasstree = true; - } - } else if (strncmp(catName,"method",6)==0) { - if (methodNameToLog == NULL) { - static ::std::string methodName; - methodName = level; - methodNameToLog = methodName.c_str(); - } - } else if (strncmp(catName,"filter",6)==0) { - if (filter == NULL) { - filter = new Method_Table(level, "LOG_FILTER", false); - } - } else { - Category* cat = strcmp("root", catName) ? root->getCategory(catName) : root; - - if (cat == NULL) { - if (!strcmp("rt", catName)) { - cat = rt; - - if (!rt->is_out_set()) { - rt->set_out(getRtOutput_()); - } - } else { - ::std::cerr << "***ERROR: invalid category name: " << catName << ::std::endl; - exit(1); - } - } - if(level != NULL && *level != '\0') { - cat->setThreshold(level); - } else { - cat->setThreshold(LogAll); - } - } + if (LogStream::isOn()) + if (sid == LogStream::RT) + return LogStream::log_rt().isEnabled(); + else + { + CompilationContext* cc = CompilationContext::getCurrentContext(); + SessionAction* session = cc->getCurrentSessionAction(); + return (session != 0) ? session->log(sid).isEnabled() + : LogStream::log(sid, cc->getPipeline()).isEnabled(); } + else + return false; } -//---------- -void -Log::initializeThresholds(const char* values) +LogStream& Log::log (LogStream::SID sid) { - cur()->initializeThresholds_(values); -} - -void -Log::initializeThresholds_(const char* values) -{ - if(values != NULL) { - if(*values == '\0') - initializeThreshold(values, NULL); - while(*values != '\0') { - ::std::string catName = ""; - ::std::string level = ""; - while((*values != '\0') && (*values != '=') && (*values != ',')) { - catName += *values; values++; - } - if(*values == '=') - values++; - while((*values != '\0') && (*values != ',')) { - level += *values; values++; - } - initializeThreshold(catName.c_str(), level.c_str()); - if(*values != '\0') - values++; - } - } -} - -::std::ostream& -Log::out_() { - Log::Settings *s_ptr = top(); - - if (s_ptr == NULL) { - // this can happen if client code calls Log::out in run-time routines - // (beyond the CompileMethod scope) - // just return ::std::out in this case - client should have used rt - // category stream for output and "file,rt=..." log option to catch it in a file - return ::std::cout; - } - Log::Settings &s = *s_ptr; - - if (s.logFileCreationPending) { - mk_dir(s.logDirName); - openLogFile_(s.logFileName, s.truncateLogFileOnCreation); - mk_dir(s.dotFileDirName); - } - assert(s.outp != NULL); - return *s.outp; -} - -//---------- - -bool -Log::setLogging(const char* methodName) { - if (methodNameToLog == NULL) { - return true; + if (LogStream::isOn()) + if (sid == LogStream::RT) + return LogStream::log_rt(); + else + { + CompilationContext* cc = CompilationContext::getCurrentContext(); + SessionAction* session = cc->getCurrentSessionAction(); + return (session != 0) ? session->log(sid) + : LogStream::log(sid, cc->getPipeline()); } - Log *log = cur(); - Log::Settings *s_ptr = log->top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - s.doLogging = (strcmp(methodNameToLog, methodName) == 0); - log->cat_root()->setLogging(s.doLogging); - return s.doLogging; -} - -//---------- - -bool -Log::setLogging(const char* className, const char* methodName, const char* methodSig) { - if (methodNameToLog == NULL && filter == NULL) { - return true; - } - Log *tls_log = cur(); - Category *tls_root_category = tls_log->cat_root(); - Log::Settings *s_ptr = tls_log->top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if (filter != NULL) { - bool filter_accepts = filter->accept_this_method(className, methodName, methodSig); - - // turn on/off the doLogging switch only if the filter is not - // in method list generation mode when it accepts no methods - if (!filter->is_in_list_generation_mode()) { - // enable logging only for methods matching the filter (method table) - s.doLogging = filter_accepts; - tls_root_category->setLogging(s.doLogging); - - // ignore methodNameToLog-based filtering in presense of - // method table-based filtering and return - return s.doLogging; - } - } - if (methodNameToLog == NULL) { - return true; - } - uint32 len = (uint32) strlen(className); - // - // Do logging if methodNameToLog is className.methodName or - // methodName. - // - bool fullMatch = (strncmp(methodNameToLog, className, len) == 0) && - (methodNameToLog[len] == '.') && - (strcmp(methodNameToLog+len+1, methodName) == 0); - bool methodMatch = (strcmp(methodNameToLog,methodName) == 0); - bool classMatch = (strcmp(methodNameToLog,className) == 0); - s.doLogging = fullMatch || methodMatch || classMatch; - tls_root_category->setLogging(s.doLogging); - return s.doLogging; -} - -//---------- - -void Log::setMethodToCompile( - const char * clsname, - const char * name, - const char * signature, - uint32 byteCodeSize) -{ - cur()->setMethodToCompile_(clsname, name, signature, byteCodeSize); -} - -void Log::setMethodToCompile_(const char * clsname, const char * name, const char * signature, uint32 byteCodeSize) -{ - setLogging(clsname, name, signature); - Log::Settings *s_ptr = top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if (!s.created_outp) { - return; - } - - assert(clsname!=NULL && name!=NULL && signature!=NULL); - - strcpy(s.className, clsname); - strcpy(s.methodName, name); - strcpy(s.methodSignature, signature); - - ++methodCounter; - - char dirname[1024]; - char logdir[1024]; - - if( fileclasstree ) { - char mdirname[130]; - snprintf(mdirname, 130, "%s%s", name, signature); - if (strlen(mdirname)>128){ - snprintf(mdirname, 130, "_xxx_.%s%s", name, signature); - mdirname[127]=0; - } - fixFileName(mdirname); - snprintf(logdir, 1024, "%s/%s/%s", s.logDirName, s.className, mdirname); - out_() << "__COMPILATION_START__:\t#" << methodCounter - << "\tclassName=" << s.className - << "\tmethodName=" << s.methodName - << "\tmethodSignature=" << s.methodSignature - << "\tbyteCodeSize=" << byteCodeSize - << "\tlogDirName=" << logdir - << ::std::endl; - } else { - sprintf(dirname, "%06d.%s.%s%s", (int)methodCounter, clsname, name, signature); - if (strlen(dirname)>128){ - sprintf(dirname, "%06d._xxx_.%s%s", (int)methodCounter, name, signature); - dirname[127]=0; - } - fixFileName(dirname); - sprintf(logdir, "%s/%s", s.logDirName, dirname); - out_() << "__COMPILATION_START__:\t#" << methodCounter - << "\tclassName=" << s.className - << "\tmethodName=" << s.methodName - << "\tmethodSignature=" << s.methodSignature - << "\tbyteCodeSize=" << byteCodeSize - << "\tlogDirName=" << dirname - << ::std::endl; - } - - setLogDir_(logdir, true); -} - -//---------- - -void Log::clearMethodToCompile(bool compilationResult, CompilationInterface * compilationInterface) -{ - cur()->clearMethodToCompile_(compilationResult, compilationInterface); -} - -void Log::clearMethodToCompile_(bool compilationResult, CompilationInterface * compilationInterface) -{ - Log::Settings *s_ptr = top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if (!s.created_outp) { - return; - } - assert(s.className[0]!=0 && s.methodName[0]!=0 && s.methodSignature[0]!=0); - setLogDir_(getRootLogDirName_(), false); - ::std::ostream& os=out_(); - os<<"__COMPILATION_END__:\t#"<<methodCounter<<"\tclassName="<<s.className<<"\tmethodName="<<s.methodName<<"\tmethodSignature="<<s.methodSignature; - os<<"\tcompilationResult="<<(compilationResult?"SUCCESS":"FAILURE"); - if (compilationResult){ - MethodDesc * md = compilationInterface->getMethodToCompile(); - - Byte * codeAddr=compilationInterface->getCodeBlockAddress(md, 0); - uint32 codeSize=compilationInterface->getCodeBlockSize(md, 0); - if (codeAddr!=NULL && codeSize>0){ - os<<"\tcodeRange=["<<(void*)codeAddr<<","<<(void*)(codeAddr+codeSize)<<"]"; - os<<"\tcodeSize="<<codeSize; - } - - Byte * infoAddr=compilationInterface->getInfoBlock(md); - uint32 infoSize=compilationInterface->getInfoBlockSize(md); - if (infoAddr!=NULL && infoSize>0){ - os<<"\tinfoRange=["<<(void*)infoAddr<<","<<(void*)(infoAddr+infoSize)<<"]"; - os<<"\tinfoSize="<<infoSize; - } - } - os<<::std::endl; + else + return LogStream::log_sink(); } -//---------- -void Log::setLogDir(const char * filename, bool truncate) +LogStream& Log::log_ct () { - cur()->setLogDir_(filename, truncate); -} - -void Log::setLogDir_(const char * filename, bool truncate) -{ - Log::Settings *s_ptr = top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if (!s.created_outp) { - return; - } - s.logFileCreationPending = true; - s.truncateLogFileOnCreation = truncate; - - if (filename==NULL) { - filename=""; - } - strcpy(s.logDirName, filename); - strcpy(s.logFileName, s.logDirName); - strcat(s.logFileName, "/jitrino.log"); - strcpy(s.dotFileDirName, s.logDirName); - strcat(s.dotFileDirName, "/dotfiles"); -} - -::std::ostream* Log::getRtOutput_() { - if (rt_outp == NULL) { - char filename[1024]; - mk_dir(getRootLogDirName_()); - sprintf(filename, "%s/rt.log", getRootLogDirName_()); - rt_outp = new ::std::ofstream(filename, ::std::ios::app); - - if (!rt_outp || !*rt_outp) { - ::std::cerr << "***ERROR: unable to open " << filename << " for log output." << ::std::endl; - ::std::cerr << " " << strerror(errno) << ::std::endl; -//VSH exit(1); - }; - } - return rt_outp; -} - -const char* Log::getRootLogDirName_() { - if (rootLogDirName[0] == '\0') { - if (singlefile) { - sprintf(rootLogDirName, "log"); - } else { - sprintf(rootLogDirName, "log.%x", logId); - } - } - return rootLogDirName; -} - -//---------- - -void Log::fixFileName(char * filename) -{ - if (filename==NULL) - return; - for (; *filename!=0; filename++) { - if (!(isalpha(*filename)||isdigit(*filename)||*filename=='.'||*filename=='-'||*filename=='_')) - *filename='_'; + if (LogStream::isOn()) + { + CompilationContext* cc = CompilationContext::getCurrentContext(); + SessionAction* session = cc->getCurrentSessionAction(); + return (session != 0) ? session->log(LogStream::CT) + : LogStream::log(LogStream::CT, cc->getPipeline()); } + else + return LogStream::log_sink(); } +#endif -//---------- -void Log::openLogFile(const char * filename, bool truncate) +void Log::printStageBegin(std::ostream& out, uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag) { - cur()->openLogFile_(filename, truncate); + out + << "========================================================================" << ::std::endl + << "__STAGE_BEGIN__:\tstageId="<<stageId<<"\tstageGroup="<<stageGroup<<"\tstageName=" << stageName << "\tstageTag=" << stageTag << ::std::endl + << "========================================================================" << ::std::endl << ::std::endl ; } -void Log::openLogFile_(const char * filename, bool truncate) +void Log::printStageEnd(std::ostream& out, uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag) { - Log::Settings *s_ptr = top(); - assert(s_ptr != NULL); - Log::Settings &s = *s_ptr; - - if (close_log_stream(&s.outp)) { - root->set_out(NULL); - } - if (!s.created_outp) { - return; - } - s.outp = new ::std::ofstream(filename, truncate ? ::std::ios::trunc : ::std::ios::app); - - if (!*s.outp) { - ::std::cerr << "***ERROR: unable to open " << filename << " for log output." << ::std::endl; - ::std::cerr << " " << strerror(errno) << ::std::endl; -//VSH exit(1); - }; - root->set_out(s.outp); - s.logFileCreationPending = false; -} - -//---------- - -uint32 Log::getNextStageId() { - return cur()->getNextStageId_(); -} - -uint32 Log::getNextStageId_() { - return nextStageId++; -} - -//---------- - -const char * Log::getLogDirName() -{ - return cur()->getLogDirName_(); -} - -const char * Log::getLogDirName_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->logDirName; -} - -//---------- - -const char * Log::getDotFileDirName() -{ - return cur()->getDotFileDirName_(); -} - -const char * Log::getDotFileDirName_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->dotFileDirName; -} - -//---------- - -const char * Log::getLogFileName() -{ - return cur()->getLogFileName_(); -} - -const char * Log::getLogFileName_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->logFileName; + out + << "========================================================================" << ::std::endl + << "__STAGE_END__:\tstageId="<<stageId<<"\tstageGroup="<<stageGroup<<"\tstageName=" << stageName << "\tstageTag=" << stageTag << ::std::endl + << "========================================================================" << ::std::endl << ::std::endl ; } -//---------- -const char * Log::getClassName() -{ - return cur()->getClassName_(); -} - -const char * Log::getClassName_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->className; -} - -//---------- - -const char * Log::getMethodName() -{ - return cur()->getMethodName_(); -} - -const char * Log::getMethodName_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->methodName; -} - -//---------- - -const char * Log::getMethodSignature() -{ - return cur()->getMethodSignature_(); -} - -const char * Log::getMethodSignature_() -{ - Log::Settings *s = top(); - assert(s != NULL); - return s->methodSignature; -} - -//---------- - -void Log::printStageBegin( - uint32 stageId, - const char * stageGroup, - const char * stageName, - const char * stageTag) -{ - cur()->printStageBegin_(stageId, stageGroup, stageName, stageTag); -} - -void Log::printStageBegin_( - uint32 stageId, - const char * stageGroup, - const char * stageName, - const char * stageTag) +void Log::printIRDumpBegin(std::ostream& out, uint32 stageId, const char * stageName, const char * subKind) { - out_() << "========================================================================" << ::std::endl; - out_() << "__STAGE_BEGIN__:\tstageId="<<stageId<<"\tstageGroup="<<stageGroup<<"\tstageName=" << stageName << "\tstageTag=" << stageTag << ::std::endl; - out_() << "========================================================================" << ::std::endl << ::std::endl ; + out + << "========================================================================" << ::std::endl + << "__IR_DUMP_BEGIN__:\tstageId="<<stageId<<"\tstageName=" << stageName << "\tsubKind=" << subKind << ::std::endl + << "Printing IR " << stageName << " - " << subKind << ::std::endl + << "========================================================================" << ::std::endl << ::std::endl ; } -//---------- -void Log::printStageEnd( - uint32 stageId, - const char * stageGroup, - const char * stageName, - const char * stageTag) +void Log::printIRDumpEnd(std::ostream& out, uint32 stageId, const char * stageName, const char * subKind) { - cur()->printStageEnd_(stageId, stageGroup, stageName, stageTag); + out + << "========================================================================" << ::std::endl + << "__IR_DUMP_END__:\tstageId="<<stageId<<"\tstageName=" << stageName << "\tsubKind=" << subKind << ::std::endl + << "========================================================================" << ::std::endl << ::std::endl ; } -void Log::printStageEnd_( - uint32 stageId, - const char * stageGroup, - const char * stageName, - const char * stageTag) -{ - out_() << "========================================================================" << ::std::endl; - out_() << "__STAGE_END__:\tstageId="<<stageId<<"\tstageGroup="<<stageGroup<<"\tstageName=" << stageName << "\tstageTag=" << stageTag << ::std::endl; - out_() << "========================================================================" << ::std::endl << ::std::endl ; -} - -//---------- -void Log::printIRDumpBegin( - uint32 stageId, - const char * stageName, - const char * subKind) +char* Log::makeDotFileName (const char* suffix) { - cur()->printIRDumpBegin_(stageId, stageName, subKind); -} + const char* fname = log(LogStream::DOTDUMP).getFileName(); -void Log::printIRDumpBegin_( - uint32 stageId, - const char * stageName, - const char * subKind) -{ - out_() << "========================================================================" << ::std::endl; - out_() << "__IR_DUMP_BEGIN__:\tstageId="<<stageId<<"\tstageName=" << stageName << "\tsubKind=" << subKind << ::std::endl; - out_() << "Printing IR " << stageName << " - " << subKind << ::std::endl; - out_() << "========================================================================" << ::std::endl << ::std::endl ; -} - -//---------- - -void Log::printIRDumpEnd( - uint32 stageId, - const char * stageName, - const char * subKind) -{ - cur()->printIRDumpEnd_(stageId, stageName, subKind); -} - -void Log::printIRDumpEnd_( - uint32 stageId, - const char * stageName, - const char * subKind) -{ - out_() << "========================================================================" << ::std::endl; - out_() << "__IR_DUMP_END__:\tstageId="<<stageId<<"\tstageName=" << stageName << "\tsubKind=" << subKind << ::std::endl; - out_() << "========================================================================" << ::std::endl << ::std::endl ; -} + size_t l0 = strlen(fname), + l1 = strlen(suffix); -//---------- + if (l0 >= 4 && strncmp(fname + l0 - 4, ".dot", 4) == 0) + l0 -= 4; -Log* Log::cur() { - return get_tls_log(); -} + char* dotfilename = new char[l0 + 1 + l1 + 4 + 1]; -/** -* Closes a non-null stream other than the standard ones. -* @return true if the stream has been closed, false otherwise -*/ -static bool close_log_stream(::std::ostream **os_ptr) { - assert(os_ptr != NULL); - ::std::ostream *os = *os_ptr; + char* ptr = dotfilename; + memcpy(ptr, fname, l0); + ptr += l0; + if (ptr[-1] != '.' && ptr[-1] != '/') + *ptr++ = '.'; + memcpy(ptr, suffix, l1); + ptr += l1; + memcpy(ptr, ".dot", 4); + ptr += 4; + *ptr = 0; - if (os != NULL && os != &::std::cout && os != &::std::cerr) { - os->flush(); - delete os; - *os_ptr=NULL; - return true; - } else { - return false; - } + return dotfilename; } -/*--------------------------------------------------------------------- - * Platform-dependent stuff - *--------------------------------------------------------------------- - */ - -#if defined(_WIN32) || defined(_WIN64) -#include <Windows.h> -#include <direct.h> -uint32 tlsLogKey=TLS_OUT_OF_INDEXES; - -static void mk_dir(const char *dirname) { - if( strchr(dirname, '/') != NULL ) { - char dir2make[1024]; dir2make[0] = 0; - int tail = 1023; - char *dir = _strdup(dirname); - char *token = strtok( dir, "/"); - - while( token != NULL && tail > 0 ) { - /* While there are tokens in "string" */ - strncat(dir2make, token, tail); - tail -= strlen(token); - _mkdir(dir2make); - strncat(dir2make, "/", tail--); - - /* Get next token: */ - token = strtok( NULL, "/"); - } - } else { - _mkdir(dirname); - } -} - -void Log::notifyThreadStart(void *data) { - uint32 tls_index = *((uint32*)data); - void *cur_value = TlsGetValue(tls_index); - if( !(NULL == cur_value) ) - assert(0); - int thread_id = GetCurrentThreadId(); - Log *log = new Log(thread_id); - - if (!TlsSetValue(tls_index, log)) { - assert(0); - } -} - -void Log::notifyThreadFinish(void *data) { - uint32 tls_index = *((uint32*)data); - Log *log = (Log*)TlsGetValue(tls_index); - assert(log != NULL); - delete log; - TlsSetValue(tls_index, NULL); -} - -static Log* get_tls_log() { - Log *log = (Log*)TlsGetValue(tlsLogKey); - assert(log != NULL); - return log; -} - -#else - -#ifndef PLATFORM_POSIX -#error Unsupported platform -#endif - -#include <pthread.h> -#include <sys/stat.h> -#include <sys/types.h> - -pthread_key_t tlsLogKey; - -static void mk_dir1(const char *dirname) { - if (mkdir(dirname, 0777 /*rwxrwxrwx*/) != 0) { - /* 'dirname' exists do nothing */ - struct stat dir_status; - if ( access(dirname, F_OK) == 0 && - stat(dirname, &dir_status) == 0 && - S_ISDIR(dir_status.st_mode) ) { - return; - }else{ - ::std::cerr << "***ERROR: failed to create directory: " << dirname << ::std::endl; - ::std::cerr << " " << strerror(errno) << ::std::endl; - } - } -} - -static void mk_dir(const char *dirname) { - if( strchr(dirname, '/') != NULL ) { - char dir2make[1024]; dir2make[0] = 0; - int tail = 1023; - char *dir = strdup(dirname); - char *token = strtok( dir, "/"); - - while( token != NULL && tail > 0 ) { - /* While there are tokens in "string" */ - strncat(dir2make, token, tail); - tail -= strlen(token); - mk_dir1(dir2make); - strncat(dir2make, "/", tail--); - - /* Get next token: */ - token = strtok( NULL, "/"); - } - } else { - mk_dir1(dirname); - } -} - -void Log::notifyThreadStart(void *data) {} -void Log::notifyThreadFinish(void *data) {} - -static bool tls_key_created = false; - -static void delete_log(void *log_) { - Log *log = (Log*)log_; - - if (log != NULL) { - delete log; - } -} - -static Log* get_tls_log() { - if (!tls_key_created) { - if (pthread_key_create(&tlsLogKey, delete_log) != 0) { - ::std::cerr << "***ERROR: failed to create TLS key" << ::std::endl; - exit(1); - } - tls_key_created = true; - } - Log *log = (Log*)pthread_getspecific(tlsLogKey); - - if (log == NULL) { - log = new Log(pthread_self()); - pthread_setspecific(tlsLogKey, log); - } - assert(log != NULL); - return log; +int Log::getStageId() +{ + return CompilationContext::getCurrentContext()->stageId;; } -#endif - -} // namespace Jitrino +} //namespace Jitrino diff --git vm/jitrino/src/main/Log.h vm/jitrino/src/main/Log.h index 09a8387..8ec5288 100644 --- vm/jitrino/src/main/Log.h +++ vm/jitrino/src/main/Log.h @@ -15,180 +15,69 @@ */ /** - * @author Intel, George A. Timoshenko - * @version $Revision: 1.18.20.4 $ + * @author Intel, Sergey L. Ivashin + * @version $Revision$ * */ #ifndef _LOG_H_ #define _LOG_H_ -#include <vector> -#include "Category.h" -#include "VMInterface.h" +#include "LogStream.h" +#include "open/types.h" +#include <iostream> -namespace Jitrino { -#ifdef PLATFORM_POSIX -#include <pthread.h> - extern pthread_key_t tlsLogKey; +namespace Jitrino +{ + + +class Log +{ +public: + +#ifndef _NOLOG + +// deprecated methods to mimicry old behavior + + static bool isEnabled () {return LogStream::isOn() && log_ct().isEnabled();} + static std::ostream& out () {return log_ct().out();} + static LogStream* cat_rt () {return &LogStream::log_rt();} + +// new methods + + static LogStream& log_ct (); + static LogStream& log_rt () {return LogStream::log_rt();} + + static bool isLogEnabled (LogStream::SID); + static LogStream& log (LogStream::SID); + #else -#define snprintf _snprintf - extern uint32 tlsLogKey; + + static bool isEnabled () {return false;} + static std::ostream& out () {return log_ct().out();} + static LogStream* cat_rt () {return &log_rt();} + + static LogStream& log_ct () {return LogStream::log_sink();} + static LogStream& log_rt () {return LogStream::log_sink();} + + static bool isLogEnabled (LogStream::SID) {return false;} + static LogStream& log (LogStream::SID) {return LogStream::log_sink();} + #endif -class Log { -public: - Log(); - Log(uint32 id) : logId(id) {new (this) Log();} - ~Log(); - - static void initializeCategories(); - static void initializeThreshold(const char* category, const char* level); - static void initializeThresholds(const char* values); - - static void pushSettings(); - static void popSettings(); - - static void setMethodToCompile(const char * clsname, const char * name, const char * signature, uint32 byteCodeSize); - static void fixFileName(char * filename); - - static void clearMethodToCompile(bool compilationResult, CompilationInterface * compilationInterface); - - static const char * getLogDirName(); - static const char * getDotFileDirName(); - static const char * getLogFileName(); - - static const char * getClassName(); - static const char * getMethodName(); - static const char * getMethodSignature(); - - static void printStageBegin(uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); - static void printStageEnd(uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); - static void printIRDumpBegin(uint32 stageId, const char * stageName, const char * subKind); - static void printIRDumpEnd(uint32 stageId, const char * stageName, const char * subKind); - - static void setLogDir(const char * filename, bool truncate); - static void openLogFile(const char * filename, bool truncate); - - static uint32 getNextStageId(); - -#define DEFINE_CATEGORY(cat_name) \ - Category *cat_name; \ - static Category* cat_##cat_name() { \ - Category *res = cur()->cat_name; \ - assert(res != NULL); \ - return res; \ - } - - DEFINE_CATEGORY(root); // Everything - DEFINE_CATEGORY(fe); // CLI and Java front ends - DEFINE_CATEGORY(opt_sim); // Optimizer - simplifier - DEFINE_CATEGORY(opt_vn); // Optimizer - value numbering - DEFINE_CATEGORY(opt); // Optimizer - DEFINE_CATEGORY(opt_dc); // Optimizer - dead code elimination - DEFINE_CATEGORY(opt_abcd); // Optimizer - array bounds check elimination - DEFINE_CATEGORY(opt_inline);// Optimizer - inliner - DEFINE_CATEGORY(opt_loop); // Optimizer - loop peeling / normalization - DEFINE_CATEGORY(opt_gcm); // Optimizer - global code motion - DEFINE_CATEGORY(opt_gvn); // Optimizer - global value numbering - DEFINE_CATEGORY(opt_td); // Optimizer - tail duplicator - DEFINE_CATEGORY(opt_reassoc); // Optimizer - re-association - DEFINE_CATEGORY(opt_mem); // Optimizer - memory - DEFINE_CATEGORY(opt_sync); // Optimizer - sync - DEFINE_CATEGORY(opt_gc); // Optimizer - GC enumeration support -// DEFINE_CATEGORY(opt_prefetch); // Optimizer - data pre-fetching - DEFINE_CATEGORY(opt_lazyexc); // Optimizer - lazy exception opt - DEFINE_CATEGORY(cg); // Code generator - DEFINE_CATEGORY(cg_cs); // Code generator - code selection - DEFINE_CATEGORY(cg_cl); // Code generator - code lowering (IA32) - DEFINE_CATEGORY(cg_ce); // Code generator - code emission - DEFINE_CATEGORY(cg_gc); // Code generator - garbage collection support - DEFINE_CATEGORY(cg_sched); // Code generator - scheduler - DEFINE_CATEGORY(rt); // Runtime (stack unwinding / GC enumeration) - DEFINE_CATEGORY(patch); // Patching code during the runtime - DEFINE_CATEGORY(typechecker); // The HIR type checker - DEFINE_CATEGORY(ti); // The JVTI support category - DEFINE_CATEGORY(ti_bc); // The JVTI byte code mapping category - - ::std::ostream *rt_outp; - - ::std::ostream &out_(); - static ::std::ostream &out() { return cur()->out_(); }; - - static bool setLogging(const char* methodName); - static bool setLogging(const char* className, const char* methodName, const char* methodSig=NULL); - - static void notifyThreadStart(void *data); - static void notifyThreadFinish(void *data); - -private: - static Log* cur(); - - void initializeCategories_(); - void initializeThreshold_(const char* category, const char* level); - void initializeThresholds_(const char* values); - - void setMethodToCompile_(const char * clsname, const char * name, const char * signature, uint32 byteCodeSize); - void clearMethodToCompile_(bool compilationResult, CompilationInterface * compilationInterface); - - ::std::ostream* getRtOutput_(); - const char * getRootLogDirName_(); - const char * getLogDirName_(); - const char * getDotFileDirName_(); - const char * getLogFileName_(); - - const char * getClassName_(); - const char * getMethodName_(); - const char * getMethodSignature_(); - - void printStageBegin_(uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); - void printStageEnd_(uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); - void printIRDumpBegin_(uint32 stageId, const char * stageName, const char * subKind); - void printIRDumpEnd_(uint32 stageId, const char * stageName, const char * subKind); - - void setLogDir_(const char * filename, bool truncate); - void openLogFile_(const char * filename, bool truncate); - - uint32 getNextStageId_(); - -private: - struct Settings { - Settings(); - - char className[1024]; - char methodName[1024]; - char methodSignature[1024]; - - char logDirName[1024]; - char dotFileDirName[1024]; - char logFileName[1024]; - - bool logFileCreationPending; - bool truncateLogFileOnCreation; - - ::std::ostream *outp; - bool created_outp; - - bool doLogging; - }; - - Settings* push(); - Settings* pop(); - Settings* top(); - - static const char* methodNameToLog; - - char rootLogDirName[1024]; - - uint32 methodCounter; - uint32 nextStageId; - - uint32 logId; - - ::std::vector<Settings*> settingsStack; + static void printStageBegin (std::ostream&, uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); + static void printStageEnd (std::ostream&, uint32 stageId, const char * stageGroup, const char * stageName, const char * stageTag); + static void printIRDumpBegin(std::ostream&, uint32 stageId, const char * stageName, const char * subKind); + static void printIRDumpEnd (std::ostream&, uint32 stageId, const char * stageName, const char * subKind); + + static char* makeDotFileName (const char* suffix); + + static int getStageId(); }; + } // namespace Jitrino + #endif // _LOG_H_ diff --git vm/jitrino/src/main/LogStream.h vm/jitrino/src/main/LogStream.h new file mode 100644 index 0000000..5f97b89 --- /dev/null +++ vm/jitrino/src/main/LogStream.h @@ -0,0 +1,138 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + +#ifndef _LOGSTREAM_H_ +#define _LOGSTREAM_H_ + +#include "mkernel.h" +#include <iostream> +#include <iomanip> +#include <fstream> + + +namespace Jitrino +{ + +class HPipeline; + + +class LogStream +{ +protected: + + static bool ison; + static LogStream logsink; + static LogStream* logrtp; + + char* fname; + bool enabled, + append, + pending_open, + was_open; + + std::ofstream os; + Mutex* mutexp; + int ref_count; + + bool lazy_open (); + +public: + + enum SID + {// numbering must starts with 0 + INFO = 0, + RT, + CT, + IRDUMP, + DOTDUMP, + DBG + + // add corresponding entry to the 'knownstreams' table + }; + + + LogStream(); + LogStream(/*const*/ char* fname); + LogStream(const LogStream&); + ~LogStream(); + + void open (/*const*/ char* fname); + void close (); + void addRef (); + bool releaseRef (); + + bool isEnabled () const {return enabled;} + std::ostream& out () {lazy_open(); return os;} + const char* getFileName () const {return fname;} + + static LogStream& log (SID, HPipeline* pipe = 0); + static LogStream& log (SID, const char* pipename = 0); + static LogStream& log (SID, const char* pipename, size_t namesz); + static LogStream& log (const char* streamname, const char* pipename = 0); + static LogStream& log (const char* streamname, const char* pipename, size_t namesz); + static LogStream& log_sink () {return logsink;} + static LogStream& log_rt () {return *logrtp;} + static bool isOn () {return ison;} + + template <class T> + LogStream& operator << (const T& value) + { +#ifndef _NOLOG + AutoUnlock lock(mutexp); + if (lazy_open()) + os << value; +#endif + return *this; + } + + LogStream& operator << (std::ostream& (*f) (std::ostream&)) + { +#ifndef _NOLOG + AutoUnlock lock(mutexp); + if (lazy_open()) + f(os); +#endif + return *this; + } + + int printf (const char*, ...) +#ifdef _NOLOG + {return 0;} // will be removed during compilation +#else + ; // implementation in the corresponding .cpp file +#endif + + LogStream& flush () + { +#ifndef _NOLOG + AutoUnlock lock(mutexp); + if (lazy_open()) + os.flush(); +#endif + return *this; + } + +friend class LogStreams; +}; + + +} //namespace Jitrino + +#endif //#ifndef _LOGSTREAM_H_ diff --git vm/jitrino/src/main/PMF.cpp vm/jitrino/src/main/PMF.cpp new file mode 100644 index 0000000..be314cf --- /dev/null +++ vm/jitrino/src/main/PMF.cpp @@ -0,0 +1,2590 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + + +#include "PMF.h" +#include "PMFAction.h" +#include "FixFileName.h" +#include "JITInstanceContext.h" +#include "open/vm.h" +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <algorithm> +#include <fstream> +#include <iostream> +#include <iomanip> + +#ifdef _WIN32 + #pragma pack(push) + #include <windows.h> + #pragma pack(pop) + #include <direct.h> + #define vsnprintf _vsnprintf + #define PATHSEPCHAR '\\' +#else //PLATFORM_POSIX + #include <stdarg.h> + #include <sys/stat.h> + #include <sys/types.h> + #define PATHSEPCHAR '/' +#endif //ifdef _WIN32 + + +using namespace std; + + +namespace Jitrino +{ + + +//------ helper functions ---------------------------------------------------// + + +void create_dir (const char* dirname) +{ +#ifdef _WIN32 + int err; + if (_mkdir(dirname) != 0 && (err = errno) != 17) + cerr << "mkdir errno#" << err << " for <" << dirname << ">" << endl; +#else + int err; + if (mkdir(dirname, 0777 /*rwxrwxrwx*/) != 0 && (err = errno) != 17) + cerr << "mkdir errno#" << err << " for <" << dirname << ">" << endl; +#endif +} + + +void mkdir (char* fname) +{ + for (char* sptr = fname; *sptr != 0; ++sptr) + if (*sptr == PATHSEPCHAR) + { + *sptr = 0; + + if (*fname != 0) + create_dir(fname); + + *sptr = PATHSEPCHAR; + } +} + + +static const char* c_str (Str& str) +{ + if (str.count != 0) + { + const_cast<char*>(str.ptr)[str.count] = 0; + return str.ptr; + } + else + return ""; +} + + +static const char* c_str (MemoryManager& mm, Str& str) +{ + char* buffp = ""; + + if (str.count != 0) + { + buffp = new (mm) char[str.count + 1]; + memcpy(buffp, str.ptr, str.count); + buffp[str.count] = 0; + } + + return buffp; +} + + +static const char* c_str (MemoryManager& mm, Str* fqnamep, size_t fqnsize) +{ + char* buffp = ""; + size_t count = 0; + + Str* strp = fqnamep; + for (size_t n = fqnsize; n != 0; --n, ++strp) + count += strp->count + 1; + + if (count != 0) + { + char* ptr = buffp = new (mm) char[count+1]; + strp = fqnamep; + for (size_t n = fqnsize; n != 0; --n, ++strp) + { + const Str& str = *strp; + memcpy(ptr, str.ptr, str.count); + ptr += str.count; + *ptr++ = '.'; + } + --ptr; // skip the last '.' + *ptr = 0; + } + + return buffp; +} + + +static bool operator < (const Str& a, const Str& b) +{ + return (a.count == b.count) ? strncmp(a.ptr, b.ptr, a.count) < 0 : a.count < b.count; +} + + +static bool operator == (const Str& a, const Str& b) +{ + return (a.count == b.count) ? strncmp(a.ptr, b.ptr, a.count) == 0 : false; +} + + +static bool operator == (const Str& a, const char* s) +{ + if (s == 0 || *s == 0) + return a.count == 0; + else + return (a.count == strlen(s)) ? strncmp(a.ptr, s, a.count) == 0 : false; +} + + +static bool compare (Str* p, Str* q, size_t count) +{ + for (; count != 0; --count, ++p, ++q) + if (!(*p == *q)) + return false; + + return true; +} + + +ostream& operator << (ostream& os, const Str& a) +{ + return os.write(a.ptr, a.count); +} + + +#ifdef _DEBUG_PMF +static ostream& operator << (ostream& os, const Strs& fqn) +{ + for (size_t n = 0; n != fqn.size(); ++n) + os << fqn[n] << '.'; + return os; +} +#endif + + +//---------------------------------------------------------------------------// + + +bool getBool (const char* val, bool def) +{ + if (val != NULL) + { + if (strcmp(val, "true") == 0 || strcmp(val, "yes") == 0 || strcmp(val, "on") == 0) + def = true; + else if (strcmp(val, "false") == 0 || strcmp(val, "no") == 0 || strcmp(val, "off") == 0) + def = false; + else + crash("PMF: invalid value for bool parameter '%s' (true|false or yes|no or on|off is expected)\n", val); + } + return def; +} + + +//------ Str implementation -------------------------------------------------// + + +bool Str::trim () +{ + // trim the left end + while (count != 0 && isspace(*ptr)) + --count, ++ptr; + + // trim the right end + while (count != 0 && isspace(ptr[count-1])) + --count; + + return count != 0; +} + + +const char* Str::findNext (char x, const char* nxt) const +{ + if (count != 0) + { + const char* end = ptr + count; + if (nxt == 0) + nxt = ptr; + for (; nxt < end; ++nxt) + if (*nxt == x) + return nxt; + } + return 0; +} + + +const char* Str::find (const char* what) const +{ + if (count != 0) + { + size_t n = strlen(what); + assert(n != 0); + const char* end = ptr + count - n; + for (const char* nxt = ptr; nxt <= end; ++nxt) + if (strncmp(nxt, what, n) == 0) + return nxt; + } + return 0; +} + +//------ StrTokenizer declaration and implementation ------------------------// + + +struct StrTokenizer +{ + const char* ptr; + const char* end; + char sep; + Str token; + + + StrTokenizer (char c, Str& s) : ptr(s.ptr), end(s.ptr + s.count), sep(c) {} + StrTokenizer (char c, const char* p, const char* e) : ptr(p), end(e), sep(c) {} + + bool next (); +}; + + +bool StrTokenizer::next () +{ + if (ptr == end) + return false; + + token.ptr = ptr; + while (ptr != end && *ptr != sep) + ++ptr; + token.count = ptr - token.ptr; + if (ptr != end) + ++ptr; + token.trim(); + return true; +}; + + +//------ StrSubstitution declaration and implementation ---------------------// + + +struct StrSubstitution +{ + typedef void (StrSubstitution::*Replacer) (); + + struct Replace + { + Str what; + Replacer replace; + }; + + static Replace replaces[]; + +// Parameters for replacements + Str jitname; + const char* classname, + * methodname, + * signature; + int threadnb, + seqnb; + Str streamname; + +// Some results of replecement + bool failure, + jit_specific, + thread_specific; + + size_t rescount; + char result[MAXLOGFILENAME]; + + char* dptr, + * dend; + + bool substitute (const Str& from); + + void replace_jit () + { + insert(jitname, false); + jit_specific = true; + } + + void replace_class () + { + insert(Str(classname), true); + } + + void replace_tree () + { + insert(Str(classname), false); + } + + void replace_method () + { + insert(Str(methodname), true); + insert(Str(signature), true); + } + + void replace_seqnb () + { + dptr += sprintf(dptr, "%.6u", seqnb); + } + + void replace_log () + { + insert(Str(streamname), false); + } + + void replace_thread () + { + dptr += sprintf(dptr, "%u", threadnb); + thread_specific = true; + } + + void insert (Str src, bool fix); + + void seekz (); +}; + + +StrSubstitution::Replace StrSubstitution::replaces[] = +{ + {Str("%jit%"), &StrSubstitution::replace_jit}, + {Str("%class%"), &StrSubstitution::replace_class}, + {Str("%class_tree%"), &StrSubstitution::replace_tree}, + {Str("%method%"), &StrSubstitution::replace_method}, + {Str("%seqnb%"), &StrSubstitution::replace_seqnb}, + {Str("%log%"), &StrSubstitution::replace_log}, + {Str("%thread%"), &StrSubstitution::replace_thread} +}; + + +bool StrSubstitution::substitute (const Str& from) +{ + failure = jit_specific = thread_specific = false; + + const char* sptr = from.ptr, + * send = from.ptr + from.count; + + dptr = result, + dend = result + sizeof(result); + + while (sptr != send) + { + bool replace = false; + + size_t n; + Replace* rpend = replaces + sizeof(replaces)/sizeof(Replace); + for (Replace* rp = replaces; rp != rpend ; ++rp) + if (sptr + (n = rp->what.count) <= send && + strncmp(sptr, rp->what.ptr, n) == 0) + { + (this->*rp->replace)(); + sptr += n; + replace = true; + break; + } + + if (!replace) + *dptr++ = *sptr++; + } + + *dptr++ = 0; + + rescount = dptr - result; + return !failure; +}; + + +void StrSubstitution::insert (Str s, bool fix) +{ + assert(dptr + s.count < dend); + + if (s.empty()) + { + failure = true; + return; + } + + if (fix) + { + for (const char* sptr = s.ptr, * send = s.ptr + s.count; sptr != send;) + { + char c = *sptr++; + if (c == '/') + c = '_'; + *dptr++ = c; + } + } + else + { + memcpy(dptr, s.ptr, s.count); + dptr += s.count; + } +} + + +void StrSubstitution::seekz () +{ + while (dptr < dend && *dptr != 0); + ++dptr; +} + + +//------ Known Streams ------------------------------------------------------// + + +static const char* deffmask = "log/%jit%/%class%/%method%/%log%.log"; +static const char* ct_deffmask = "log/%jit%/%class%/%method%/ct.log"; +static const char* dot_deffmask = "log/%jit%/%class%/%method%/.dot"; + +struct KnownStream +{ + LogStream::SID sid; + const char* streamname; + const char* deffmask; +}; + +static KnownStream knownstreams[] = +{ + {LogStream::INFO, "info", "log/info.log"}, + {LogStream::RT, "rt", "log/rt.log"}, + {LogStream::CT, "ct", ct_deffmask}, + {LogStream::IRDUMP, "irdump", ct_deffmask}, + {LogStream::DOTDUMP, "dotdump", dot_deffmask}, + {LogStream::DBG, "dbg", deffmask} +}; + +const size_t nb_knownstreams = sizeof(knownstreams)/sizeof(KnownStream); + + +static KnownStream* isKnownStream (const Str& streamname) +{ + for (size_t i = 0; i != nb_knownstreams; ++i) + if (streamname == knownstreams[i].streamname) + return &knownstreams[i]; + + return 0; +} + + +//------ LogStream implementation -------------------------------------------// + + +/*static*/ bool LogStream::ison = false; +/*static*/ LogStream LogStream::logsink; +/*static*/ LogStream* LogStream::logrtp = &LogStream::logsink; + + +LogStream::LogStream () +:fname(0), enabled(false), append(false), pending_open(false), was_open(false), mutexp(0), ref_count(0) +{ +} + + +LogStream::LogStream (/*const*/ char* s) +:fname(s), enabled(true), append(false), pending_open(true), was_open(false), mutexp(0), ref_count(0) +{ +} + + +LogStream::~LogStream () +{ + close(); +} + + +void LogStream::open (/*const*/ char* s) +{ + assert(!was_open && !pending_open); + fname = s; + enabled = true; + pending_open = true; +} + + + +void LogStream::close () +{ + if (was_open) + { + was_open = false; + os.close(); + } +} + + +#ifndef _NOLOG +int LogStream::printf (const char* fmt, ...) +{ + AutoUnlock lock(mutexp); + if (lazy_open()) + { + va_list args; + va_start(args, fmt); + + char buff[256]; + int n = vsnprintf(buff, sizeof(buff), fmt, args); + + os << buff; + return n; + } + else + return 0; +} +#endif + + +bool LogStream::lazy_open () +{ + if (pending_open) + { + pending_open = false; + + ios_base::openmode mode = ios_base::out; + if (append) + mode |= ios_base::app; + + char temp[MAXFILENAMESIZE]; + fix_file_name(temp, sizeof(temp), fname); + + mkdir(temp); + os.open(temp, mode); + was_open = os.is_open(); + if (!was_open) + cerr << "Failed to open log file '" << temp << "'" << endl; + } + return was_open; +} + + +//TODO: Is it possible to remove locking there? +void LogStream::addRef () +{ + AutoUnlock lock(mutexp); + ++ref_count; +} + + +bool LogStream::releaseRef () +{ + AutoUnlock lock(mutexp); + + if (--ref_count == 0) + close(); + + assert(ref_count >= 0); + + return ref_count == 0; +} + + +LogStream& LogStream::log (LogStream::SID sid, const char* pipename) +{ + return log(sid, pipename, pipename == 0 ? 0 : strlen(pipename)); +} + + +LogStream& LogStream::log (LogStream::SID sid, const char* pipename, size_t namesz) +{ + if (isOn()) + { + Str pipe(pipename, namesz); + LogStreams& streams = LogStreams::current(); + LogStream* lsp = 0; + for (size_t idx = 0, n = streams.size(); idx != n; ++idx) + { + const LogTemplate& lt = streams.logtemplate(idx); + if ((lt.pathp == 0 || lt.pathp->empty()) && lt.sid == sid) + if (lt.filtername == pipe) + return streams.logstream(idx); + else if (lt.filtername.empty()) + lsp = &streams.logstream(idx); + } + if (lsp != 0) + return *lsp; + } + + return log_sink(); +} + + +LogStream& LogStream::log (const char* streamname, const char* pipename) +{ + return log(streamname, pipename, pipename == 0 ? 0 : strlen(pipename)); +} + + +LogStream& LogStream::log (const char* streamname, const char* pipename, size_t namesz) +{ + if (isOn()) + { + assert(streamname != 0 && *streamname != 0); + Str pipe(pipename, namesz); + LogStreams& streams = LogStreams::current(); + LogStream* lsp = 0; + for (size_t idx = 0, n = streams.size(); idx != n; ++idx) + { + const LogTemplate& lt = streams.logtemplate(idx); + if ((lt.pathp == 0 || lt.pathp->empty()) && lt.streamname == streamname) + if (lt.filtername == pipe) + return streams.logstream(idx); + else if (lt.filtername.empty()) + lsp = &streams.logstream(idx); + } + if (lsp != 0) + return *lsp; + } + + return log_sink(); +} + + +//------ LogStreams implementation ------------------------------------------// + + +LogStreams::LogStreams (MemoryManager& mm_, PMF& pmf_, int t) +:mm(mm_), pmf(pmf_), nbos(pmf.getLogTemplates().size()) +, streams(mm, nbos), streamsstack(mm, nbos) +, depth(0), threadnb(t), methodnb(0) +{ + StrSubstitution ss; + ss.jitname = pmf.jitname; + ss.classname = 0; + ss.methodname = 0; + ss.signature = 0; + ss.threadnb = threadnb; + ss.seqnb = methodnb; + + for (size_t sx = 0; sx != nbos; ++sx) + { + streams[sx] = &LogStream::logsink; + + const LogTemplate& ltemplate = pmf.getLogTemplates()[sx]; + if (ltemplate.enabled) + { + streamsstack[sx] = new (mm) Streams(mm); + + ss.streamname = ltemplate.streamname; + if (ss.substitute(ltemplate.fmask)) + {// File name doesn't require compilation context (class or method name) + AutoUnlock(pmf.files); + assign(sx, ss.result, ss.rescount); + } + } + + // Turn on the whole logging if there are log templates defined + LogStream::ison = true; + } +} + + +LogStreams::~LogStreams () +{ + assert(depth == 0); + + LogStream* lsp; + for (size_t sx = 0; sx != nbos; ++sx) + if ((lsp = streams[sx])->enabled) + { + AutoUnlock(pmf.files); + if (lsp->releaseRef()) + pmf.files[lsp->fname] = 0; +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << " free '" << lsp->fname + << "' closed:" << (pmf.files[lsp->fname] == 0) + << endl; +#endif + } +} + + +void LogStreams::beginMethod (const char* cname, + const char* mname, + const char* sig, + int nb) +{ + ++depth; + + StrSubstitution ss; + ss.jitname = pmf.jitname; + ss.classname = cname; + ss.methodname = mname; + ss.signature = sig; + ss.threadnb = threadnb; + ss.seqnb = nb; + + for (size_t sx = 0; sx != nbos; ++sx) + { + const LogTemplate& ltemplate = pmf.getLogTemplates()[sx]; + if (ltemplate.enabled) + { + LogStream* lsp = streams[sx]; + Streams* sstack = streamsstack[sx]; + + ss.streamname = ltemplate.streamname; + ss.substitute(ltemplate.fmask); + if (!lsp->enabled || strcmp(lsp->fname, ss.result) != 0) + {// File name changed: stream will be changed, so save stream on stack + sstack->push_back(lsp); +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << "pushed '" << (lsp->enabled ? lsp->fname : "-none-") + << "'" + << endl; +#endif + // change stream - use new or reuse already open stream + AutoUnlock(pmf.files); + assign(sx, ss.result, ss.rescount); + } + else + {// File name didn't changed, continue the current stream + sstack->push_back(0); + } + } + } +} + + +void LogStreams::endMethod () +{ + assert(depth > 0); + + for (size_t sx = 0; sx != nbos; ++sx) + { + LogStream* lsp = streams[sx]; + if (lsp->enabled) + { + Streams* sstack = streamsstack[sx]; + + if (sstack->back() != 0) + {// Return to the saved stream + AutoUnlock(pmf.files); + + // If this file no longer needed, close it but remember its name. + // Next time the file will be open, it will be open in append mode. + if (lsp->releaseRef()) + pmf.files[lsp->fname] = 0; + +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << " free '" << lsp->fname + << "' closed:" << (pmf.files[lsp->fname] == 0) + << endl; +#endif + streams[sx] = sstack->back(); + +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << " poped '" << (streams[sx]->enabled ? streams[sx]->fname : "-none-") + << "'" + << endl; +#endif + } + else + {// Stream didn't changed + } + + sstack->pop_back(); + } + } + + --depth; +} + + +void LogStreams::assign (size_t sx, const char* fname, size_t fnamesz) +{ + const LogTemplate& ltemplate = pmf.getLogTemplates()[sx]; + LogStream* lsp; + + PMF::Files::iterator ptr = pmf.files.find(fname); + if (ptr == pmf.files.end() || ptr->second == 0) + {// There is no file open with this name. + lsp = new (pmf.mm) LogStream(); + + // If %jit% macros used in the file name template, then this file will + // not be shared by several thread. Otherwise, synchronization is + // neccessary. + if (!ltemplate.thread_specific) + lsp->mutexp = new (mm) Mutex(); + + lsp->append = ltemplate.append; + if (!ltemplate.append && ptr != pmf.files.end()) + lsp->append = true; // the file was opened before + + lsp->enabled = lsp->pending_open = true; + + lsp->fname = new (mm) char[fnamesz]; + memcpy(lsp->fname, fname, fnamesz); + pmf.files[lsp->fname] = lsp; + + // Special case of rt stream - only the single instance of LogStream object can exist + if (ltemplate.sid == LogStream::RT) + LogStream::logrtp = lsp; + +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << " new '" << lsp->fname + << "' seen before:" << (ptr != pmf.files.end()) + << endl; +#endif + } + else + { + lsp = ptr->second; +#ifdef _DEBUG_PMF_STREAMS +cout << "LogStreams[" << threadnb << "] depth:" << depth << " idx:" << sx + << " reuse '" << lsp->fname + << "'" + << endl; +#endif + } + + lsp->addRef(); + streams[sx] = lsp; +} + + +const LogTemplate& LogStreams::logtemplate (size_t idx) const +{ + return pmf.logtemplates.at(idx); +} + + +//------ logDisplay implementation ------------------------------------------// + + +LogDisplay::LogDisplay (MemoryManager& mm) +:streamidxs(mm, nb_knownstreams) +{ + for (size_t sid = 0; sid != nb_knownstreams; ++sid) + streamidxs[sid] = 0; // index of sink stream +} + + +void LogDisplay::add (size_t idx, LogTemplate& lt) +{ + KnownStream* ksp = isKnownStream(lt.streamname); + if (ksp != 0) + streamidxs.at(ksp->sid) = idx; + else + streamidxs.push_back(idx); +} + + +LogStream& LogDisplay::log (LogStream::SID sid) const +{ + size_t idx = streamidxs.at(sid); + return LogStreams::current().logstream(idx); +} + + +//------ PMF::Cmd declaration and implementation ----------------------------// + + +struct PMF::Cmd +{ + char* buff; // own copy of the command source + + Strs* left; // left part (before '=' character) + Str right; // right part (after '=' character) + + bool arg, // true for 'arg' type command + log; // true for 'log' type command + Str jitname, // jit name string (left[0] in fact) + filtername; // filter name string + int xkeyword, // index of keyword found in 'left' array + xlog; // for 'log' type command only - index of 'log' keyword + + Cmd () : buff(0), arg(false), log(false) {} + + int strength (size_t pathsz = 0) const; + void fatal (const char* msg) const; +}; + + +static int cmd_strength (bool jit_known, bool filter_known, size_t path_size) +{ + return ((1 + (filter_known ? 2 : 0) + (jit_known ? 4 : 0)) << 16) + path_size; +} + + +int PMF::Cmd::strength (size_t pathsz) const +{ + return cmd_strength(!jitname.empty(), !filtername.empty(), pathsz); +} + + +void PMF::Cmd::fatal (const char* msg) const +{ + crash("Error in command line '%s'\n%s\n", left->front().ptr, msg); +} + + +//------ PMF::MethodFilter implementation -----------------------------------// + + +// Parse filter specification with the following syntax: +// <class name> . <method name> <signature> +// It is assumed that <signature> starts with the '(' character. +// +void PMF::MethodFilter::init (const Str& filter) +{ + const char* ptr1 = filter.findFirst('.'); + if (ptr1 == 0) + ptr1 = filter.findFirst(':'); + + const char* ptr2 = filter.findNext('(', ptr1); + const char* ptr3 = filter.end(); + + if (ptr1 == 0) + // no class name + classname.count = 0, + methodname.ptr = filter.ptr; + else + {// classname, then method name + classname.ptr = filter.ptr, + classname.count = ptr1 - filter.ptr, + + ++ptr1; // skip the '.'/':' character + if (ptr1 < filter.end() && *ptr1 == ':') + ++ptr1; // skip the second ':' + + methodname.ptr = ptr1; + } + + + if (ptr2 == 0) + // no method signature + methodname.count = ptr3 - methodname.ptr, + signature.count = 0; + else + methodname.count = ptr2 - methodname.ptr, + signature.ptr = ptr2, // include the '(' character + signature.count = ptr3 - ptr2; + + classname.trim(), + methodname.trim(), + signature.trim(); + + if (classname.empty() && methodname.findFirst('/') != 0) + classname = methodname, + methodname.clear(); +} + + +bool PMF::MethodFilter::empty () const +{ + return classname.empty() && + methodname.empty() && + signature.empty(); +} + + +int PMF::MethodFilter::pass (const char* cname, const char* mname, const char* sig) const +{ + if (cname != 0 && strncmp(cname, classname.ptr, classname.count) != 0) + return -1; + if (mname != 0 && strncmp(mname, methodname.ptr, methodname.count) != 0) + return -1; + if (sig != 0 && strncmp(sig, signature.ptr, signature.count) != 0) + return -1; + + return (int)(classname.count + methodname.count + signature.count); +} + + +const char* PMF::MethodFilter::c_str (MemoryManager& mm) const +{ + size_t count = classname.count + 1 + methodname.count + signature.count; + + char* cstr = new (mm) char[count+1]; + + char* ptr = cstr; + memcpy(ptr, classname.ptr, classname.count); + ptr += classname.count; + *ptr++ = '.'; + + memcpy(ptr, methodname.ptr, methodname.count); + ptr += methodname.count; + + memcpy(ptr, signature.ptr, signature.count); + ptr += signature.count; + *ptr = 0; + + return cstr; +} + + +//------ PMF::Args implementation -------------------------------------------// + + +void PMF::Args::add (const char* key, const char* value, int strength, bool filterspec) +{ + Store::iterator end = store.end(), + ptr = find(store.begin(), end, key); + if (ptr == end) + { + Arg arg; + arg.key = key, + arg.value = value; + arg.strength = strength; + arg.filterspec = filterspec; + store.push_back(arg); + } + else if (strength >= ptr->strength) + { + ptr->value = value, + ptr->strength = strength; + ptr->filterspec = filterspec; + } +} + + +const char* PMF::Args::get (const char* key) const +{ + Store::const_iterator end = store.end(), + ptr = find(store.begin(), end, key); + if (ptr == end) + return 0; + else + return ptr->value; +} + + +//------ Alias declaration and implementation ------------------------------// + + +struct PMF::Pipeline::Alias +{ + Str name; + + struct Child + { + Str name; + enum Type {REQUIRED, DEFON, DEFOFF} type; + Alias* aliasp; + + bool operator == (const Str& s) const {return name == s;} + }; + + typedef StlVector<Child> Childs; + Childs childs; + + + Alias (MemoryManager& mm) : childs(mm) {} + Alias (MemoryManager& mm, const Alias&); +}; + + +// shallow copy +// +PMF::Pipeline::Alias::Alias (MemoryManager& mm, const Alias& orig) +:childs(mm) +{ + name = orig.name; + childs.insert(childs.end(), orig.childs.begin(), orig.childs.end()); + for (Childs::iterator it = childs.begin(); it != childs.end(); ++it) + it->aliasp = 0; +} + + +//------ ArgIterator declaration and implementation ------------------------// + + +struct PMF::ArgIterator +{ + const Pipeline::Step& step; + const char* key; + Cmds::iterator it; + bool first; + + + ArgIterator (const Pipeline::Step& s, const char* k) :step(s), key(k), first(true) {} + + bool next (); + + operator Cmd* () {return *it;} +}; + + +bool PMF::ArgIterator::next () +{ + Cmds::iterator end = step.pipeline->pmf.cmds.end(); + + for (;;) + { + if (first) + { + first = false; + it = step.pipeline->pmf.cmds.begin(); + } + else + { + if (it == end) + return false; + ++it; + } + + if (it == end) + return false; + + if (*it == 0 || !(*it)->arg) + continue; + + Cmd& cmd = **it; + + if (!cmd.filtername.empty() && !(cmd.filtername == step.pipeline->name)) + continue; + + // index of argument + size_t xend = cmd.left->size() - 1; + + // size of path in command (i.e. number of items between argument and keuword) + size_t pathsz = xend - cmd.xkeyword - 1; + + if (pathsz > step.fqname->size()) + continue; + + if (key != 0 && !(cmd.left->at(xend) == key)) + continue; + + if (pathsz == 1 && cmd.left->at(cmd.xkeyword + 1) == step.factory->getName()) + return true; + + size_t xl, xs; + for (xl = cmd.xkeyword + 1, xs = 0; xl != xend; ++xl, ++xs) + if (!(cmd.left->at(xl) == step.fqname->at(xs))) + break; + + if (xl == xend) + return true; + } +} + + +//------ PMF implementation ------------------------------------------------// + + +bool PMF::parse (Cmd& cmd, const char* keyword, FilterSpecs& filterspecs) +{ + Strs::iterator i = find(cmd.left->begin(), cmd.left->end(), keyword); + if (i == cmd.left->end()) + return false; + + cmd.xkeyword = (int)(i - cmd.left->begin()); + + Str* tmp; + if (cmd.xkeyword == 0) + {// <keyword> .... + // no jit name + // no filter name + + // obsolete form of filter command: + // filter.a = ... + if (strcmp(keyword, "filter") == 0) + { + if (cmd.left->size() == 2 && !(tmp = &cmd.left->at(1))->empty()) + cmd.filtername = *tmp; + } + } + else if (cmd.xkeyword == 1 && !(tmp = &cmd.left->at(0))->empty()) + {// <a>.<keyword> ... + // <a> can be name of jit name or filter name + if (strcmp(keyword, "filter") == 0 || filterspecs.find(*tmp) != filterspecs.end()) + cmd.filtername = *tmp; + else + cmd.jitname = *tmp; + } + else if (cmd.xkeyword == 2) + {// <a>.<b>.<keyword> ... + // <a> must be jit name + // <b> must be filter name + if (!(tmp = &cmd.left->at(0))->empty()) + cmd.jitname = *tmp; + + if (!(tmp = &cmd.left->at(1))->empty()) + { + cmd.filtername = *tmp; + } + } + else + { + cmd.fatal("Keyword misplaced"); + } + + return cmd.jitname.empty() || cmd.jitname == jitname; +} + + +void PMF::processCmd (Cmd& cmd) +{ + if (strncmp(cmd.buff, "help", 4) == 0 + || strncmp(cmd.buff, "arg.help", 8) == 0) + { + help_requested = true; + return; + } + +// Split line into tokens <left0> . <left1> . .... = <right> + + const char* ptr0 = cmd.buff ; + const char* ptr1; + for (ptr1 = ptr0; *ptr1 != '='; ++ptr1) + if (*ptr1 == 0) + crash("No '=' symbol in command line '%s'\n", ptr0); + + for (StrTokenizer tokens('.', ptr0, ptr1); tokens.next();) + cmd.left->push_back(tokens.token); + + if (cmd.left->empty()) + crash("Empty left part of command line '%s'", ptr0); + + cmd.right.init(ptr1+1); + cmd.right.trim(); + +// Special processing for read command + + if (cmd.left->size() == 1 && cmd.left->at(0) == "read") + { + if (cmd.right.empty()) + cmd.fatal("File name missing in read command"); + + ifstream is(c_str(mm, cmd.right)); + if (is.fail()) + cmd.fatal("File not found"); + + char buff[1024]; + while (is.good()) + { + is.getline(buff, sizeof(buff)); + processCmd(buff); + } + + is.close(); + } + +// Any other command lines are simply stored + + else + cmds.push_back(&cmd); +} + + +void PMF::processCmd (const char* key, const char* value) +{ +// Must be called before init() + assert(!initialized); + + assert(key != 0); + if (*key == 0 || value == 0) + return; + +// Copy to internal buffer + + size_t count1 = strlen(key), + count2 = strlen(value); + + Cmd& cmd = *new (mm) Cmd(); + cmd.buff = new (mm) char[count1 + 1 + count2 + 1]; + cmd.left = new (mm) Strs(mm); + memcpy(cmd.buff, key, count1); + cmd.buff[count1] = '='; + memcpy(cmd.buff+count1+1, value, count2+1); + + processCmd(cmd); +} + + +void PMF::processCmd (const char* ptr) +{ +// Must be called before init() + assert(!initialized); + +// Ignore empty and comment command lines + + while (isspace(*ptr)) + ++ptr; + + size_t count = strlen(ptr); + if (count == 0) + return; // skip empty command + if (ptr[0] == '#') + return; // skip #comment + if (count > 1 && ptr[0] == '/' && ptr[1] == '/') + return; // skip //comment + +// Copy to internal buffer + + Cmd& cmd = *new (mm) Cmd(); + cmd.buff = new (mm) char[count+1]; + cmd.left = new (mm) Strs(mm); + memcpy(cmd.buff, ptr, count+1); + + processCmd(cmd); +} + + +void PMF::processVMProperties () +{ + PropertiesIteratorHandle ph = vm_properties_iterator_create(); + for (;;) + { + const char* key = vm_properties_get_name(ph); + if (strncmp("jit.", key, 4) == 0) + { + const char* value = vm_properties_get_string_value(ph); + processCmd(key+4, value); + } + + if (!vm_properties_iterator_advance(ph)) + break; + } + vm_properties_iterator_destroy(ph); +} + + +PMF::PMF (MemoryManager& m, JITInstanceContext& jit) +:initialized(false),mm(m), jitInstanceContext(jit) +,cmds(mm), logtemplates(mm), files(mm), pipelines(mm) +{ + jitname.init(jitInstanceContext.getJITName().c_str()); +} + + +void PMF::init (bool first_) +{ + assert(!initialized); + first = first_; + help_requested = false; + processVMProperties(); + initialized = true; + +#ifdef _DEBUG_PMF + cout << endl << "Commands received:" << endl; + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + { + Cmd& cmd = **it; + cout << *cmd.left << " = <" << cmd.right << "> " << endl; + } + + cout << endl << "ActionFactory:" << endl; + for (IActionFactory* afp = IActionFactory::getFirst(); afp != 0; afp = afp->getNext()) + cout << " " << afp->getName() << endl; +#endif + + if (first && help_requested) + showHelp(cout); + +// Create common pipeline with empty filter + + pipelines.push_back(new (mm) Pipeline(*this)); + +// Process all filter statements + + FilterSpecs filterspecs(mm); + + Cmd* cmdp; + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && parse(*cmdp, "filter", filterspecs)) + { + *it = 0; + + if (cmdp->right.empty()) + cmdp->fatal("Empty filter"); + + if (cmdp->filtername.empty()) + cmdp->fatal("Invalid filter name"); + + if (cmdp->filtername == jitname) + cmdp->fatal("Invalid filter name - the same as jit name"); + + if (filterspecs.find(cmdp->filtername) != filterspecs.end()) + cmdp->fatal("Duplicate filters defined"); + + filterspecs[cmdp->filtername] = &cmdp->right; + } + +// Process all path statements + + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && parse(*cmdp, "path", filterspecs)) + { + *it = 0; + + if (!cmdp->filtername.empty() && filterspecs.find(cmdp->filtername) == filterspecs.end()) + continue; + + // Process left of '=" part + + Str* namep = 0; + + size_t x = cmdp->left->size() - cmdp->xkeyword - 1; + if (x == 0) + { + } + else if (x == 1) + { + Str& name = cmdp->left->at(cmdp->xkeyword + 1); + if (!name.empty()) + namep = &name; + } + else + cmdp->fatal("Extra items after path name"); + + Pipeline* pipeline = lookup(&cmdp->filtername, true); + Pipeline::Alias* aliasp = pipeline->lookup(namep); + if (aliasp == 0) + { + aliasp = new (mm) Pipeline::Alias(mm); + if (namep == 0) + pipeline->root = aliasp; + else + aliasp->name = *namep; + pipeline->aliases->push_back(aliasp); + } + else + { + cmdp->fatal("Multiple path defined"); + } + + // Process right of '=" part + + for (StrTokenizer tokens(',', cmdp->right); tokens.next();) + { + Pipeline::Alias::Child child; + child.aliasp = 0; + child.type = Pipeline::Alias::Child::DEFON; + if (!tokens.token.empty()) + { + char x = tokens.token.ptr[tokens.token.count-1]; + if (x == '!') + { + child.type = Pipeline::Alias::Child::REQUIRED; + --tokens.token.count; + } + else if (x == '+') + { + child.type = Pipeline::Alias::Child::DEFON; + --tokens.token.count; + } + else if (x == '-') + { + child.type = Pipeline::Alias::Child::DEFOFF; + --tokens.token.count; + } + tokens.token.trim(); + } + if (tokens.token.empty()) + cmdp->fatal("Empty path child name"); + child.name = tokens.token; + + aliasp->childs.push_back(child); + } + } + + else if (cmdp != 0 && !cmdp->jitname.empty() && !(cmdp->jitname == jitname)) + *it = 0; // not for this jit command + +// Process all arg statements + + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && parse(*cmdp, "arg", filterspecs)) + { + cmdp->arg = true; + lookup(&cmdp->filtername, true); + } + + else if (cmdp != 0 && !cmdp->jitname.empty() && !(cmdp->jitname == jitname)) + *it = 0; // not for this jit command + +// Path resolution + + Pipeline& compipeline = **pipelines.begin(); // this is the common (empty) pipeline + if (compipeline.root == 0) + compipeline.stop("PMF: Invalid common pipeline for '%s' - does not have a root path\n"); + + for (Pipelines::iterator k = pipelines.begin(); k != pipelines.end(); ++k) + { + Pipeline& pipeline = **k; + Pipeline::Aliases& aliases = *pipeline.aliases; + + if (&pipeline != &compipeline) + { + FilterSpecs::iterator it = filterspecs.find(pipeline.name); + if (it == filterspecs.end()) + pipeline.stop("PMF: Invalid pipeline for '%s.%s' - unspecified filter\n"); + + pipeline.method.init(*it->second); + if (pipeline.method.empty()) + pipeline.stop("PMF: Invalid pipeline for '%s.%s' - empty filter\n"); + } + + if (pipeline.root == 0) + { + pipeline.root = new (mm) Pipeline::Alias(mm, *compipeline.root); + aliases.push_back(pipeline.root); + } + + for (;;) + { + Pipeline::Aliases newaliases(mm); + + for (Pipeline::Aliases::iterator l = aliases.begin(); l != aliases.end(); ++l) + { + Pipeline::Alias::Childs::iterator end = (*l)->childs.end(), + ptr = (*l)->childs.begin(); + for (; ptr != end; ++ptr) + { + ptr->aliasp = pipeline.lookup(&ptr->name); + if (ptr->aliasp == 0 && &pipeline != &compipeline) + { + Pipeline::Alias* comaliasp; + if ((comaliasp = compipeline.lookup(&ptr->name)) != 0) + newaliases.push_back(new (mm) Pipeline::Alias(mm, *comaliasp)); + } + } + } + + if (newaliases.empty()) + break; + else + aliases.insert(aliases.end(), newaliases.begin(), newaliases.end()); + } + + Strs fqname(mm); + walk(pipeline, pipeline.root, fqname); + } + +// Build parameters map + + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && cmdp->arg) + { + size_t n = cmdp->left->size() - cmdp->xkeyword - 1; + if (n == 0) + cmdp->fatal("No argument name"); + } + + initStreams(); + + for (Pipelines::iterator k = pipelines.begin(); k != pipelines.end(); ++k) + { + Pipeline& pipeline = **k; + for (Pipeline::Steps::iterator s = pipeline.steps->begin(); s != pipeline.steps->end(); ++s) + { + Pipeline::Step& step = *s; + step.setup(mm); + } + } + +// Create actions for common filter + + for (Pipeline::Steps::iterator s = compipeline.steps->begin(); s != compipeline.steps->end(); ++s) + { + Pipeline::Step& step = *s; + step.action = step.factory->createAction(mm); + step.reused = false; + } + +// Create actions for other filters + + for (Pipelines::iterator k = pipelines.begin() + 1; k != pipelines.end(); ++k) + { + Pipeline& pipeline = **k; + + for (Pipeline::Steps::iterator s = pipeline.steps->begin(); s != pipeline.steps->end(); ++s) + { + Pipeline::Step& step = *s; + step.action = 0; + step.reused = false; + + // Check if this step has any filter-specific agruments + bool filterspec = false; + if (step.args != 0) + for (Args::Store::iterator m = step.args->store.begin(); m != step.args->store.end(); ++m) + if (m->filterspec) + { + filterspec = true; + break; + } + + // If step doesn't have such arguments, action from common filter can be reused + if (!filterspec) + for (Pipeline::Steps::iterator m = compipeline.steps->begin(); m != compipeline.steps->end(); ++m) + if (step.factory == m->factory) + { + step.action = m->action; + step.reused = true; + break; + } + + // Otherwise action is created and initiated + if (step.action == 0) + step.action = step.factory->createAction(mm); + } + } + +// Debug output + +#ifdef _DEBUG_PMF + cout << endl << "PMF jit<" << jitname << ">" << endl; + for (Pipelines::iterator k = pipelines.begin(); k != pipelines.end(); ++k) + { + Pipeline& pipeline = **k; + cout << " Pipeline<" << pipeline.name << + "> method<" << pipeline.method.classname + << "><" << pipeline.method.methodname + << "><" << pipeline.method.signature + << ">" << endl; + + for (Pipeline::Aliases::iterator l = pipeline.aliases->begin(); l != pipeline.aliases->end(); ++l) + { + Pipeline::Alias& alias = **l; + cout << " Alias<" << alias.name << ">"; + if (pipeline.root == &alias) + cout << " *root*"; + cout << endl; + + for (Pipeline::Alias::Childs::iterator m = alias.childs.begin(); m != alias.childs.end(); ++m) + { + Pipeline::Alias::Child& child = *m; + cout << " Child<" << child.name << "> kind:" << child.type; + if (child.aliasp!= 0) + cout << " to <" << child.aliasp->name << ">"; + cout << endl; + } + } + + for (Pipeline::Steps::iterator l = pipeline.steps->begin(); l != pipeline.steps->end(); ++l) + { + Pipeline::Step& step = *l; + cout << " Step <" << *step.fqname + << "> action <" << step.factory->getName() + << "> reused:" << step.reused + << endl; + if (step.args != 0) + for (Args::Store::iterator m = step.args->store.begin(); m != step.args->store.end(); ++m) + { + Args::Arg& arg = *m; + cout << " arg <" << arg.key << "> = <" << arg.value + << "> strength:" << arg.strength + << endl; + } + + if (step.logs != 0) + for (size_t sid = 0; sid < step.logs->streamidxs.size(); ++sid) + { + size_t idx = step.logs->streamidxs.at(sid); + LogTemplate& lt = logtemplates.at(idx); + cout << " sid#" << sid + << " idx#" << idx + << endl; + } + } + } +#endif + +// Initialize commom pipeline only (others get intialized as need by PipelineIterator) + + compipeline.init(); +} + + +void PMF::deinit () +{ + for (Pipelines::iterator it = pipelines.begin(); it != pipelines.end(); ++it) + (*it)->deinit(); +} + + +void PMF::initStreams () +{ +// There are two forms of the log command: +// +// 1) stream enable +// [<jit>.][<filter>.]arg.[<path>.]log = <stream>, <stream>, ... +// +// 2) stream assignment +// [<jit>.][<filter>.]arg.[<path>.]log.<stream>.file = <file mask> + + PMF::Cmd* cmdp; + for (PMF::Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && cmdp->arg) + { + Strs::iterator leftbeg = cmdp->left->begin(), + leftend = cmdp->left->end(); + + Strs::iterator i = find(leftbeg + cmdp->xkeyword + 1, leftend, "log"); + // log command must contain the "log" keyword + if (i == leftend) + continue; + + cmdp->log = true; + cmdp->xlog = i - leftbeg; + + int xpath = cmdp->xkeyword + 1, + xlast = cmdp->left->size() - 1; + + if (cmdp->xlog == xlast) + {// stream enable command + for (StrTokenizer tokens(',', cmdp->right); tokens.next();) + { + LogTemplate& lt = lookStream(tokens.token, cmdp, xpath, cmdp->xlog); + lt.enabled = true; + } + } + } + + for (LogTemplates::iterator it = logtemplates.begin(); it != logtemplates.end(); ++it) + { + LogTemplate& lt = *it; + + int file_strength = 0, + append_strength = 0; + + for (PMF::Cmds::iterator kt = cmds.begin(); kt != cmds.end(); ++kt) + if ((cmdp = *kt) != 0 && cmdp->log) + { + if (!cmdp->filtername.empty() && !(cmdp->filtername == lt.filtername)) + continue; + + int xpath = cmdp->xkeyword + 1, + xlast = cmdp->left->size() - 1, + pathsz = cmdp->xlog - xpath; + + Str& key = cmdp->left->at(xlast); + if (key == "log") + continue; + + // compare stream name + + if (cmdp->xlog == xlast - 2) + if (!(cmdp->left->at(cmdp->xlog+1) == lt.streamname)) + continue; + + // compare path names + + int ltpathsz = (lt.pathp == 0) ? 0 : (int)lt.pathp->size(); + if (pathsz > ltpathsz) + continue; + if (pathsz != 0 && !compare(&cmdp->left->at(xpath), <.pathp->at(0), pathsz)) + continue; + + int strength = cmdp->strength(pathsz); + + if (key == "file" && strength > file_strength) + {// stream assignment command + lt.fmask = cmdp->right; + file_strength = strength; + } + else if (key == "append" && strength > append_strength) + { + lt.append = (cmdp->right == "true" || cmdp->right == "yes"); + file_strength = strength; + } + else + cmdp->fatal("Invalid log command"); + } + } + +// Find out if file name mask containds some key macros + + for (LogTemplates::iterator it = logtemplates.begin(); it != logtemplates.end(); ++it) + { + LogTemplate& lt = *it; + lt.jit_specific = lt.fmask.find("%jit%") != 0; + lt.thread_specific = lt.fmask.find("%thread%") != 0; + } + +#ifdef _DEBUG_PMF + cout << endl << "LogTemplates" << endl; + for (size_t idx = 0; idx != logtemplates.size(); ++idx) + { + LogTemplate& lt = logtemplates.at(idx); + cout << idx + << ") stream <" << lt.streamname + << "> enabled=" << lt.enabled + << " append=" << lt.append + << " jit_specific=" << lt.jit_specific + << " thread_specific=" << lt.thread_specific + + << " filter <" << lt.filtername + << "> path <"; + if (lt.pathp != 0) + cout << *lt.pathp; + cout << "> fmask <" << lt.fmask + << ">" << endl; + } +#endif +} + + +LogTemplate& PMF::lookStream (Str& streamname, PMF::Cmd* cmdp, size_t xpath, size_t xlog) +{ + LogTemplates::iterator end = logtemplates.end(), + ptr = logtemplates.begin(); + for (; ptr != end; ++ptr) + { + if (ptr->filtername == cmdp->filtername && + ptr->streamname == streamname) + { + if (ptr->pathp->empty() && xpath != xlog) + continue; + if (!ptr->pathp->empty()) + { + if (ptr->pathp->size() != xlog - xpath) + continue; + if (!compare(&ptr->pathp->at(0), &cmdp->left->at(xpath), xlog - xpath)) + continue; + } + cmdp->fatal("Duplicate streams defined"); + } + } + + if (logtemplates.empty()) + {// create the "sink' stream at index o + logtemplates.push_back(LogTemplate()); + LogTemplate& lt = logtemplates.back(); + lt.idx = 0; + lt.streamname.init("sink"); + } + + logtemplates.push_back(LogTemplate()); + LogTemplate& lt = logtemplates.back(); + lt.idx = logtemplates.size()-1; + lt.filtername = cmdp->filtername; + lt.streamname = streamname; + + lt.pathp = new (mm) Strs(mm); + if (xpath != xlog) + { + Strs::iterator leftbeg = cmdp->left->begin(); + lt.pathp->insert(lt.pathp->end(), leftbeg + xpath, leftbeg + xlog); + } + + lt.fmask = deffmask; + lt.sid = static_cast<LogStream::SID>(nb_knownstreams); + KnownStream* ksp = isKnownStream(streamname); + if (ksp != 0) + { + lt.fmask = ksp->deffmask; + lt.sid = ksp->sid; + } + + if (ksp != 0 && ksp->sid == LogStream::RT) + { + if (!lt.pathp->empty() || !lt.filtername.empty()) + crash("'rt' stream must be defined at global level only\n"); + } + + return lt; +} + + +PMF::HPipeline PMF::selectPipeline (const char* cn, const char* mn, const char* sig) const +{ + Pipeline* pipeline = *pipelines.begin(); + int xs = 0, x; + + if (cn != 0 || mn != 0 || sig != 0) + for (Pipelines::const_iterator i = pipelines.begin()+1; i != pipelines.end(); ++i) + if ((x = (*i)->method.pass(cn, mn, sig)) > xs) + pipeline = *i, + xs = x; + + return pipeline; +} + + +PMF::HPipeline PMF::getPipeline (const char* name) const +{ +// Common filter is always the first in the array of filters + assert(!pipelines.empty()); + if (name == 0 || *name == 0) + return pipelines[0]; + + Pipelines::const_iterator ptr = pipelines.begin()+1, + end = pipelines.end(); + for (; ptr != end; ++ptr) + if ((*ptr)->name == name) + return *ptr; + + return 0; +} + + +const char* PMF::getArg (HPipeline hpipe, const char* key) const +{ + vector<Str> keys; + for (StrTokenizer tokens('.', key, key + strlen(key)); tokens.next();) + keys.push_back(tokens.token); + + const Cmd* cmdp; + for (Cmds::const_iterator it = cmds.begin(); it != cmds.end(); ++it) + if ((cmdp = *it) != 0 && cmdp->arg) + { + if (hpipe == 0 || hpipe->name.empty()) + { + if (!cmdp->filtername.empty()) + continue; + } + else + { + if (cmdp->filtername.empty() || !(cmdp->filtername == hpipe->name)) + continue; + } + if (cmdp->left->size() - cmdp->xkeyword - 1 == keys.size()) + if (compare(&cmdp->left->at(cmdp->xkeyword + 1), &keys.at(0), keys.size())) + return cmdp->right.ptr; + } + + return 0; +} + + +Action* PMF::getAction (HPipeline hpipe, const char* path) +{ + vector<Str> fqname; + for (StrTokenizer tokens('.', path, path + strlen(path)); tokens.next();) + fqname.push_back(tokens.token); + + Pipeline::Steps::iterator ptr = hpipe->steps->begin(), + end = hpipe->steps->end(); + for (; ptr != end; ++ptr) + { + Pipeline::Step& step = *ptr; + if (step.fqname->size() == fqname.size() && + compare(&step.fqname->at(0), &fqname.at(0), fqname.size())) + return step.action; + } + + return 0; +} + + +void PMF::walk (Pipeline& pipeline, Pipeline::Alias* aliasp, Strs& fqname) +{ + Pipeline::Alias::Childs::iterator end = aliasp->childs.end(), + ptr = aliasp->childs.begin(); + for (; ptr != end; ++ptr) + { + Pipeline::Alias::Child& child = *ptr; + fqname.push_back(child.name); + //cout << "walk " << fqname << endl;; + + bool goon = (child.type != Pipeline::Alias::Child::DEFOFF); + Cmd* cmdp = lookArg(pipeline, fqname); + if (cmdp != 0) + { + if (cmdp->right == "on") + { + goon = true; + } + else if (cmdp->right == "off") + { + if (ptr->type == Pipeline::Alias::Child::REQUIRED) + cmdp->fatal("This path item cannot be off"); + goon = false; + } + else + cmdp->fatal("Invalid path item selection"); + } + + if (goon) + if (child.aliasp != 0) + walk(pipeline, child.aliasp, fqname); + else + { + Pipeline::Step step; + if ((step.factory = IActionFactory::find(child.name)) == 0) + crash("PMF: Action '%s' not found\n", c_str(mm, child.name)); + + step.pipeline = &pipeline; + step.fqname = new (mm) Strs(mm, fqname.size()); + *step.fqname = fqname; + pipeline.steps->push_back(step); + } + + fqname.pop_back(); + } +} + + +PMF::Cmd* PMF::lookArg (Pipeline& pipeline, Strs& fqname) +{ + Cmd* cmdp = 0; + int sx = 0; + + for (Cmds::iterator it = cmds.begin(); it != cmds.end(); ++it) + if (*it != 0 && (*it)->arg) + { + Cmd& cmd = **it; + + if (pipeline.name.empty()) + { + if (!cmd.filtername.empty()) + continue; + } + else + { + if (!cmd.filtername.empty() && !(cmd.filtername == pipeline.name)) + continue; + } + + if (cmd.left->size() - cmd.xkeyword -1 != fqname.size()) + continue; + + if (!compare(&cmd.left->at(cmd.xkeyword+1), &fqname[0], fqname.size())) + continue; + + int s = cmd.strength(); + if (cmdp == 0) + cmdp = &cmd, + sx = s; + else + { + if (s == sx) + crash("Ambigiguity between commands '%s' and '%s'", cmdp->buff, cmd.buff); + + if (s > sx) + cmdp = &cmd, + sx = s; + } + } + + return cmdp; +} + + +PMF::Pipeline* PMF::lookup (Str* name, bool create) +{ +// Common filter is always the first in the array of filters + assert(!pipelines.empty()); + if (name == 0 || name->empty()) + return pipelines[0]; + + Pipelines::iterator ptr = pipelines.begin()+1, + end = pipelines.end(); + for (; ptr != end; ++ptr) + if ((*ptr)->name == *name) + return *ptr; + + if (!create) + return 0; + + // add required filter + Pipeline* pipeline = new (mm) Pipeline(*this); + pipeline->name = *name; + pipelines.push_back(pipeline); + return pipeline; +} + + +static bool compFactories (IActionFactory* a, IActionFactory* b) +{ + return strcmp(a->getName(), b->getName()) < 0; +} + + +void PMF::showHelp (std::ostream& os) +{ + typedef vector<IActionFactory*> Factories; + Factories tmp; + + for (IActionFactory* afp = IActionFactory::getFirst(); afp != 0; afp = afp->getNext()) + tmp.push_back(afp); + + sort(tmp.begin(), tmp.end(), compFactories); + + os << endl << "Help for Jitrino Actions (when available)" << endl; + for (Factories::iterator it = tmp.begin(); it != tmp.end(); ++it) + (*it)->showHelp(os); +} + + +void PMF::summTimes (SummTimes& summtimes) +{ + Pipelines::iterator pptr = pipelines.begin(), + pend = pipelines.end(); + for (; pptr != pend; ++pptr) + { + Pipeline::Steps::iterator sptr = (*pptr)->steps->begin(), + send = (*pptr)->steps->end(); + for (; sptr != send; ++sptr) + summtimes.add(sptr->factory->getName(), sptr->getSeconds()); + } +} + + +//------ Pipeline implementation --------------------------------------------// + + +PMF::Pipeline::Pipeline (PMF& p) +:pmf(p), initialized(false), root(0) +{ + aliases = new (pmf.mm) Aliases(pmf.mm); + steps = new (pmf.mm) Steps(pmf.mm); +} + + +PMF::Pipeline::~Pipeline () +{ +} + + +void PMF::Pipeline::init () +{ + if (!initialized) + { + initialized = true; + Pipeline::Steps::iterator ptr = steps->begin(), + end = steps->end(); + for (; ptr != end; ++ptr) + { + Pipeline::Step& step = *ptr; + if (step.action != 0 && !step.reused) + { + step.action->step = &step; + step.action->init(); + } + } + } +} + + +void PMF::Pipeline::deinit () +{ + if (initialized) + { + initialized = false; + Pipeline::Steps::iterator ptr = steps->begin(), + end = steps->end(); + for (; ptr != end; ++ptr) + { + Pipeline::Step& step = *ptr; + if (step.action != 0 && !step.reused) + step.action->deinit(); + } + } +} + + +PMF::Pipeline::Alias* PMF::Pipeline::lookup (Str* name) +{ + Aliases::iterator ptr = aliases->begin(), + end = aliases->end(); + for (; ptr != end; ++ptr) + { + Alias* aliasp = *ptr; + if ((name != 0 && *name == aliasp->name) || + (name == 0 && aliasp->name.empty())) + return aliasp; + } + + return 0; +} + + +PMF::Pipeline::Alias* PMF::Pipeline::findPath (Str* names, size_t count) +{ + Alias* aliasp = root; + + for (; aliasp != 0 && count != 0; --count) + { + Alias::Childs::iterator end = aliasp->childs.end(), + ptr = find(aliasp->childs.begin(), end, *names); + if (ptr == end) + return 0; + + aliasp = ptr->aliasp; + ++names; + } + + return aliasp; +} + + +void PMF::Pipeline::stop (const char* msg) +{ + crash(msg, c_str(pmf.mm, pmf.jitname), c_str(pmf.mm, name)); +} + + +//------ PMF::Pipeline::Step implementation ---------------------------------// + + +void PMF::Pipeline::Step::setup (MemoryManager& mm) +{ + args = 0; + for (ArgIterator it(*this, 0); it.next();) + { + Cmd& cmd = *it; + + if (args == 0) + args = new (mm) Args(mm); + + const char* key = c_str(cmd.left->at(cmd.left->size() - 1)); + const char* value = c_str(cmd.right); + int strength = cmd.strength(cmd.left->size() - cmd.xkeyword - 1); + args->add(key, value, strength, !cmd.filtername.empty()); + } + +// all templates in scope for this step + vector<LogTemplate*> acts; + + LogTemplates& logtemplates = pipeline->pmf.logtemplates; + for (size_t sx = 0; sx != logtemplates.size(); ++sx) + { + LogTemplate& lt = logtemplates[sx]; + + if (!lt.enabled) + continue; + + if (!(lt.filtername == pipeline->name)) + continue; + + if (lt.pathp->size() > fqname->size()) + continue; + + if (lt.pathp->size() != 0 && !compare(<.pathp->at(0), &fqname->at(0), lt.pathp->size())) + continue; + + vector<LogTemplate*>::iterator it, end = acts.end(); + for (it = acts.begin(); it != end; ++it) + if ((*it)->streamname == lt.streamname) + break; + + if (it == end) + acts.push_back(<); + else if (cmd_strength(false, !(*it)->filtername.empty(), (*it)->pathp->size()) + < cmd_strength(false, !lt.filtername.empty(), lt.pathp->size())) + *it = < // this definition is the strongest + } + + logs = 0; + if (!acts.empty()) + { + logs = new (mm) LogDisplay(mm); + + vector<LogTemplate*>::iterator it, end = acts.end(); + for (it = acts.begin(); it != end; ++it) + { + LogTemplate lt = **it; + logs->add(lt.idx, lt); + } + } +} + + +//------ PMF::PipelineIterator implementation -------------------------------// + + +PMF::PipelineIterator::PipelineIterator (PMF& p, const char* cn, const char* mn, const char* sig) +:pmf(p), mm(0, "PMF::PipelineIterator"), smm(0), session(0), first(true) +{ + if (pmf.pipelines.empty()) + crash("PMF: No pipelines defined\n"); + + pipeline = pmf.selectPipeline(cn, mn, sig); + pipeline->init(); +} + + +PMF::PipelineIterator::PipelineIterator (HPipeline hpipe) +:pmf(hpipe->pmf), pipeline(hpipe), mm(0, "PMF::PipelineIterator"), smm(0), session(0), first(true) +{ + pipeline->init(); +} + + +PMF::PipelineIterator::~PipelineIterator () +{ +} + + +bool PMF::PipelineIterator::next () +{ + Pipeline::Steps::iterator end = pipeline->steps->end(); + + if (first) + { + first = false; + it = pipeline->steps->begin(); + } + else + { + assert(it != end); + + // close previous session + session->step = 0; + session->~SessionAction(); + session = 0; + smm->~MemoryManager(); + + // go to new session + ++it; + } + + if (it != end) + {// open new session + smm = new MemoryManager(0, it->factory->getName()); + session = it->factory->createSessionAction(*smm); + assert(session != 0); + session->step = &*it; + return true; + } + else + return false; +} + + +const char* PMF::PipelineIterator::getPipeName (MemoryManager& mm) const +{ + assert(pipeline != 0); + return c_str(mm, pipeline->name); +} + + +const char* PMF::PipelineIterator::getFilterSpec (MemoryManager& mm) const +{ + assert(pipeline != 0); + return pipeline->method.c_str(mm); +} + + +const char* PMF::PipelineIterator::getStepName () const +{ + assert(!first && it != pipeline->steps->end()); + return c_str(*smm, &it->fqname->at(0), it->fqname->size()); +} + + +//------ ActionFactory implementation ---------------------------------------// + + +IActionFactory* IActionFactory::head = 0; + + +IActionFactory::IActionFactory (const char* n) +:name(n) +{ + Str sname(name); + if (find(sname) != 0) + crash("PMF: duplicate Action '%s'\n", name); + + next = head; + head = this; +} + + +void IActionFactory::showHelp (ostream& os, const char* help) const +{ + if (help != 0) + os << endl << getName() << endl + << help; +} + + +IActionFactory* IActionFactory::find (Str& str) +{ + for (IActionFactory* p = getFirst(); p != 0; p = p->getNext()) + if (p->name == str) + return p; + + return 0; +} + + +//------ IAction implementation ---------------------------------------------// + + +bool IAction::getArg (const char* key, unsigned int& v) const +{ + const char* arg = getArg(key); + if (arg == 0) + return false; + else + { + v = atoi(arg); + return true; + } +} + + +bool IAction::getArg (const char* key, unsigned long& v) const +{ + const char* arg = getArg(key); + if (arg == 0) + return false; + else + { + v = atol(arg); + return true; + } +} + + +bool IAction::getArg (const char* key, bool& v) const +{ + const char* arg = getArg(key); + if (arg == 0) + return false; + else + { + if (strcmp(arg, "true") == 0 || strcmp(arg, "yes") == 0) + v = true; + else if (strcmp(arg, "false") == 0 || strcmp(arg, "no") == 0) + v = false; + else + crash("PMF: invalid value for bool parameter '%s' (true|false or yes|no expected)\n", key); + + return true; + } +} + + +const char* IAction::getArg (HPipeline hp, const char* key) const +{ + return step->pipeline->pmf.getArg(const_cast<PMF::HPipeline>(hp), key); +} + + +#ifndef _NOLOG +bool IAction::isLogEnabled (LogStream::SID sid) const +{ + return step->logs != 0 && step->logs->log(sid).isEnabled(); +} +#endif + + +#ifndef _NOLOG +bool IAction::isLogEnabled (const char* streamname) const +{ + LogStream::SID sid; + if (getLogStreamID(sid, streamname)) + return isLogEnabled(sid); + else + return false; +} +#endif + + +#ifndef _NOLOG +LogStream& IAction::log (LogStream::SID sid) const +{ + return (step->logs == 0) ? LogStream::log_sink() : step->logs->log(sid); +} +#endif + + +#ifndef _NOLOG +LogStream& IAction::log (const char* streamname) const +{ + LogStream::SID sid; + if (getLogStreamID(sid, streamname)) + return log(sid); + else + return LogStream::log_sink(); +} +#endif + + +bool IAction::getLogStreamID (LogStream::SID& sid, const char* streamname) const +{ + if ((step->logs) == 0) + return false; + + LogTemplates& logtemplates = step->pipeline->pmf.logtemplates; + LogDisplay::StreamIdxs& idxs = step->logs->streamidxs; + for (size_t i = 0; i != idxs.size(); ++i) + if (logtemplates[idxs[i]].streamname == streamname) + { + sid = static_cast<LogStream::SID>(i); + return true; + } + + return false; +} + + +//------ Action implementation ----------------------------------------------// + + +Action* Action::createAuxAction (const char* name, const char* suffix) const +{ + MemoryManager& mm = step->pipeline->pmf.mm; + return createAuxAction (mm, name, suffix); +} + + +Action* Action::createAuxAction (MemoryManager& mm, const char* name, const char* suffix) const +{ + PMF::Pipeline::Step* auxstep = new (mm) PMF::Pipeline::Step; + auxstep->factory = step->factory; + auxstep->pipeline = getPipeline(); + + Strs* fqname = new (mm) Strs(mm); + fqname->insert(fqname->end(), step->fqname->begin(), step->fqname->end()); + fqname->push_back(Str(suffix)); + auxstep->fqname = fqname; + + Str sname(name); + auxstep->factory = IActionFactory::find(sname); + assert(auxstep->factory != 0); + + Action* auxaction = auxstep->factory->createAction(mm); + auxaction->step = auxstep; + auxstep->action = auxaction; + + auxstep->setup(mm); + return auxaction; +} + + +SessionAction* Action::createSession (MemoryManager& mm) +{ + SessionAction* session = step->factory->createSessionAction(mm); + assert(session != 0); + session->step = step; + return session; +} + + +/* +void Action::destroySession (SessionAction* session) +{ + session->step = 0; + session->~SessionAction(); +} +*/ + + +//---------------------------------------------------------------------------// + + +} //namespace Jitrino diff --git vm/jitrino/src/main/PMF.h vm/jitrino/src/main/PMF.h new file mode 100644 index 0000000..1d21f4a --- /dev/null +++ vm/jitrino/src/main/PMF.h @@ -0,0 +1,366 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + +#ifndef _PMF_H_ +#define _PMF_H_ + +#include "XTimer.h" +#include "LogStream.h" +#include "Jitrino.h" +#include "mkernel.h" +#include "MemoryManager.h" +#include "Stl.h" +#include <iostream> +#include <iomanip> +#include <fstream> + + +namespace Jitrino +{ + + + bool getBool (const char* val, bool def); +inline int getInt (const char* val, int def) {return val == 0 ? def : atoi(val);} +inline const char* getString (const char* val, const char* def) {return val == 0 ? def : val;} + + +struct Str +{ + const char* ptr; + size_t count; + + + Str () :ptr(0), count(0) {} + Str (const char* s, size_t n) :ptr(s), count(n) {} + Str (const char* s) :ptr(s), count(s == 0 ? 0 : strlen(s)) {} + + void init (const char* s) {ptr = s, count = strlen(s);} + bool empty () const {return count == 0;} + void clear () {count = 0;} + bool trim (); + const char* beg () const {return ptr;}; + const char* end () const {return ptr + count;}; + const char* findFirst (char x) const {return findNext(x, ptr);} + const char* findNext (char x, const char*) const; + const char* find (const char*) const; +}; + + +std::ostream& operator << (std::ostream&, const Str&); + + +typedef StlVector<Str> Strs; + + +struct LogTemplate +{ + size_t idx; + Str streamname; + Str filtername; + Strs* pathp; + Str fmask; + LogStream::SID sid; + + bool jit_specific, // true if fmask contains %jit% macros + thread_specific; // true if fmask contains %thread% macros + + bool enabled, + append; + + LogTemplate () :pathp(0), enabled(false), append(false) {} +}; + +typedef StlVector<LogTemplate> LogTemplates; + + +class PMF; + + +class LogStreams +{ +protected: + + MemoryManager& mm; // thread-local MM + PMF& pmf; // synchronized only access + const size_t nbos; + + typedef StlVector <LogStream*> Streams; + Streams streams; + + typedef StlVector <Streams*> StreamsStack; + StreamsStack streamsstack; + + int depth, + threadnb, + methodnb; + + void assign (size_t sx, const char* fname, size_t fnamesz); + +public: + + LogStreams (MemoryManager&, PMF&, int); + ~LogStreams (); + + static LogStreams& current(JITInstanceContext* = 0); + +// Construct log stream file names according to the currently compiled method + void beginMethod (const char* cname, const char* mname, const char* sig, int methodnb); + void endMethod (); + + size_t size () const {return nbos;} + + const LogTemplate& logtemplate (size_t idx) const; + + LogStream& logstream (size_t idx) const + { + return nbos != 0 ? *streams.at(idx) + : LogStream::log_sink(); + } + +friend class PMF; +}; + + +struct LogDisplay +{ + typedef StlVector <size_t> StreamIdxs; + StreamIdxs streamidxs; + + + LogDisplay (MemoryManager&); + + void add (size_t idx, LogTemplate&); + + LogStream& log (LogStream::SID sid) const; +}; + + +class JITInstanceContext; +class IActionFactory; +class Action; +class SessionAction; + + +struct CompareChars +{ + bool operator () (const char* a, const char* b) const {return strcmp(a, b) < 0;} +}; + + +class PMF +{ +protected: + + bool initialized, + first; + MemoryManager& mm; + JITInstanceContext& jitInstanceContext; + Str jitname; + bool help_requested; + + struct Cmd; + + typedef StlVector<Cmd*> Cmds; + Cmds cmds; + + typedef StlMap<Str, Str*> FilterSpecs; + + struct MethodFilter + { + Str classname, + methodname, + signature; + + void init (const Str&); + bool empty () const; + int pass (const char* cname, const char* mname, const char* sig) const; + const char* c_str (MemoryManager&) const; + }; + + struct Args + { + struct Arg + { + const char* key; + const char* value; + int strength; // relative strength of this argument + bool filterspec; // true if this argument is filter specific + + bool operator == (const char* k) const {return strcmp(key, k) == 0;} + }; + + typedef StlVector<Arg> Store; + Store store; + + Args (MemoryManager& mm) : store(mm) {} + + void add (const char* key, const char* value, int strength, bool filterspec); + const char* get (const char* key) const; + }; + + LogTemplates logtemplates; + + typedef StlMap<const char*, LogStream*, CompareChars> FilesDictionary; + struct Files : public Mutex, public FilesDictionary + { + Files (MemoryManager& mm) : FilesDictionary(mm) {} + }; + + Files files; + +public: + + struct Pipeline + { + PMF& pmf; + Str name; + MethodFilter method; + bool initialized; + + struct Alias; + + Alias* root; + + typedef StlVector<Alias*> Aliases; + Aliases* aliases; + + struct Step : public XTimer + { + /*const*/ Pipeline* pipeline; + Strs* fqname; + IActionFactory* factory; + Action* action; + Args* args; // 0 or array of arguments + LogDisplay* logs; + bool reused; + + void setup (MemoryManager&); + }; + + typedef StlVector<Step> Steps; + Steps* steps; + + + Pipeline (PMF& p); + ~Pipeline (); + + void init (); + void deinit (); + Alias* lookup (Str*); + Alias* findPath (Str*, size_t); + void stop (const char* msg); + Str getName () const {return name;} + }; + +protected: + + typedef StlVector<Pipeline*> Pipelines; + Pipelines pipelines; + + struct ArgIterator; + + + bool parse (Cmd&, const char*, FilterSpecs&); + void processCmd (Cmd&); + void initStreams (); + LogTemplate& lookStream (Str& streamname, Cmd* cmdp, size_t xpath, size_t xlog); + void walk (Pipeline&, Pipeline::Alias*, Strs&); + Cmd* lookArg (Pipeline&, Strs&); + Pipeline* lookup (Str* filtername, bool create = false); + +public: + + typedef Pipeline* HPipeline; + + class PipelineIterator + { + protected: + + PMF& pmf; + Pipeline* pipeline; + Pipeline::Steps::iterator it; + MemoryManager mm; + MemoryManager* smm; + SessionAction* session; + bool first; + + public: + + PipelineIterator (PMF& pmf, const char* classname, const char* methodname = 0, const char* signature = 0); + PipelineIterator (HPipeline); + ~PipelineIterator (); + + // pipeline specific methods + + const char* getPipeName (MemoryManager&) const; + const char* getFilterSpec (MemoryManager&) const; + + // step specific methods + + const char* getStepName () const; + IActionFactory* getFactory() const {return it->factory;} + Action* getAction () const {return it->action;} + SessionAction* getSessionAction () const {return session;} + MemoryManager& getSessionMemoryManager () const {return *smm;} + MemoryManager& getMemoryManager () {return mm;} + + bool next (); + }; + + + PMF (MemoryManager&, JITInstanceContext&); + + void processCmd (const char*); + void processCmd (const char*, const char*); + void processVMProperties (); + + void init (bool first = false); + void deinit (); + + const LogTemplates& getLogTemplates () const {return logtemplates;} + JITInstanceContext& getJITInstanceContext () const {return jitInstanceContext;} + void summTimes (SummTimes&); + static Action* getAction (HPipeline, const char* path); + static void showHelp (std::ostream&); + + HPipeline selectPipeline (const char* classname, const char* methname, const char* sig) const; + + HPipeline getPipeline (const char* name) const; + const char* getArg (HPipeline, const char* key) const; + + const char* getStringArg (HPipeline p, const char* key, const char* def) const + {return getString(getArg(p, key), def);} + + int getIntArg (HPipeline p, const char* key, int def) const + {return getInt(getArg(p, key), def);} + + bool getBoolArg (HPipeline p, const char* key, bool def) const + {return getBool(getArg(p, key), def);} + + +friend class LogStreams; +friend class IAction; +friend class Action; +}; + + +} //namespace Jitrino + +#endif //#ifndef _PMF_H_ diff --git vm/jitrino/src/main/PMFAction.h vm/jitrino/src/main/PMFAction.h new file mode 100644 index 0000000..9c7c585 --- /dev/null +++ vm/jitrino/src/main/PMFAction.h @@ -0,0 +1,197 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey L. Ivashin + * @version $Revision$ + */ + +#ifndef _PMFACTION_H_ +#define _PMFACTION_H_ + +#include "PMF.h" // sorry ... + +#include <string.h> + +namespace Jitrino +{ + + +class IActionFactory +{ +public: + + IActionFactory (const char* name); + virtual ~IActionFactory () {} + + virtual Action* createAction (MemoryManager&) {return 0;} + virtual SessionAction* createSessionAction (MemoryManager&) = 0; + virtual void showHelp (std::ostream&) {} + + void showHelp (std::ostream&, const char* help) const; + const char* getName () const {return name;} + + static IActionFactory* find (Str&); + static IActionFactory* getFirst () {return head;} + IActionFactory* getNext () const {return next;} + +protected: + + const char* name; + IActionFactory* next; + static IActionFactory* head; +}; + + +class IAction +{ +public: + + IActionFactory* getFactory () const {return step->factory;} + const char* getName () const {return step->factory->getName();} + const char* getArg (const char* key) const {return (step->args) ? step->args->get(key) : 0;} + bool getArg (const char* key, unsigned int& v) const; + bool getArg (const char* key, unsigned long& v) const; + bool getArg (const char* key, bool& v) const; + + typedef PMF::HPipeline HPipeline; + HPipeline getPipeline () const {return step->pipeline;} + HPipeline getPipeline (const char* name) const {return step->pipeline->pmf.getPipeline(name);} + const char* getArg (HPipeline p, const char* key) const; + + const char* getStringArg (const char* key, const char* def) const + {return getString(getArg(key), def);} + + const char* getStringArg (const std::string& key, const char* def) const + {return getString(getArg(key.c_str()), def);} + + int getIntArg (const char* key, int def) const + {return getInt(getArg(key), def);} + + int getIntArg (const std::string& key, int def) const + {return getInt(getArg(key.c_str()), def);} + + bool getBoolArg (const char* key, bool def) const + {return getBool(getArg(key), def);} + + bool getBoolArg (const std::string& key, bool def) const + {return getBool(getArg(key.c_str()), def);} + + const char* getStringArg (HPipeline p, const char* key, const char* def) const + {return getString(getArg(p, key), def);} + + const char* getStringArg (HPipeline p, const std::string& key, const char* def) const + {return getString(getArg(p, key.c_str()), def);} + + int getIntArg (HPipeline p, const char* key, int def) const + {return getInt(getArg(p, key), def);} + + int getIntArg (HPipeline p, const std::string& key, int def) const + {return getInt(getArg(p, key.c_str()), def);} + + bool getBoolArg (HPipeline p, const char* key, bool def) const + {return getBool(getArg(p, key), def);} + + bool getBoolArg (HPipeline p, const std::string& key, bool def) const + {return getBool(getArg(p, key.c_str()), def);} + + JITInstanceContext& getJITInstanceContext () const {return step->pipeline->pmf.jitInstanceContext;} + +#ifndef _NOLOG + bool isLogEnabled (LogStream::SID) const; + bool isLogEnabled (const char* streamname) const; + + LogStream& log (LogStream::SID) const; + LogStream& log (const char* streamname) const; +#else + bool isLogEnabled (LogStream::SID) const {return false;} + bool isLogEnabled (const char* streamname) const {return false;} + + LogStream& log (LogStream::SID) const {return LogStream::log_sink();} + LogStream& log (const char* streamname) const {return LogStream::log_sink();} +#endif + + bool getLogStreamID (LogStream::SID&, const char* streamname) const; + +protected: + + /*const*/ PMF::Pipeline::Step* step; + +friend struct PMF::Pipeline; +friend class PMF::PipelineIterator; +}; + + +class Action : public IAction +{ +public: + + virtual ~Action () {} + + virtual void init () {} + virtual void deinit () {} + + Action* createAuxAction (const char* name, const char* suffix) const; + Action* createAuxAction (MemoryManager&, const char* name, const char* suffix) const; + SessionAction* createSession (MemoryManager&); +}; + + +class CompilationContext; + +class SessionAction : public IAction +{ +public: + + virtual ~SessionAction () {} + + virtual void run () = 0; + + Action* getAction () const {return step->action;} + + void setCompilationContext(CompilationContext* _cc) {cc = _cc;} + CompilationContext* getCompilationContext() const {return cc;} + + void start () {step->start();} + void stop () {step->stop();} + +private: + + CompilationContext* cc; + +friend class Action; +}; + + +template <class S, class A = Action> +class ActionFactory : public IActionFactory +{ +public: + + ActionFactory (const char* name, const char* h = 0) :IActionFactory(name), help(h) {} + + Action* createAction (MemoryManager& mm) {return new (mm) A();} + SessionAction* createSessionAction (MemoryManager& mm) {return new (mm) S();} + void showHelp (std::ostream& os) {IActionFactory::showHelp(os, help);} + +private: + + const char* help; +}; + + +} //namespace Jitrino + +#endif //#ifndef _PMFACTION_H_ diff --git vm/jitrino/src/optimizer/CSEHash.cpp vm/jitrino/src/optimizer/CSEHash.cpp index 9c4df6c..0f4e97c 100644 --- vm/jitrino/src/optimizer/CSEHash.cpp +++ vm/jitrino/src/optimizer/CSEHash.cpp @@ -35,7 +35,7 @@ Inst* CSEHashTable::lookupKeyBase(CSE Inst* inst = (Inst*)hashTable.lookup(key); if (inst != NULL) { numCSE++; - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "***** CSEHashTable::Lookup succeeded: "; inst->print(Log::out()); Log::out() << ::std::endl; diff --git vm/jitrino/src/optimizer/CSEHash.h vm/jitrino/src/optimizer/CSEHash.h index 8764069..abfd79d 100644 --- vm/jitrino/src/optimizer/CSEHash.h +++ vm/jitrino/src/optimizer/CSEHash.h @@ -124,7 +124,7 @@ public: } bool isNull() const { return ((opcode == 0) && (opnd1 == 0) && (opnd2 == 0) && (opnd3 == 0)); }; - void print (::std::ostream &os) const { + void print (::std::ostream &os) const { os << "(" << (int) opcode << "," << (int) opnd1 << "," << (int) opnd2 << "," @@ -155,6 +155,7 @@ class CSEHashTable { public: CSEHashTable(MemoryManager& mm) : numCSE(0), hashTable(mm, CSE_HASH_TABLE_SIZE) {} + virtual ~CSEHashTable() {} void kill() {hashTable.removeAll();} @@ -211,10 +212,10 @@ private: class ScopedCSEHashTable : public CSEHashTable { public: - virtual ~ScopedCSEHashTable() {} ScopedCSEHashTable(MemoryManager& mm, ScopedCSEHashTable* outerScope) - : CSEHashTable(mm), _outerScope(outerScope) { - } + : CSEHashTable(mm), _outerScope(outerScope) {} + + virtual ~ScopedCSEHashTable() {} Inst* lookupKey(CSEHashKey* key) { ScopedCSEHashTable* table = this; Inst* inst = NULL; diff --git vm/jitrino/src/optimizer/CodeGenerator.cpp vm/jitrino/src/optimizer/CodeGenerator.cpp index e5f3ae8..b4de642 100644 --- vm/jitrino/src/optimizer/CodeGenerator.cpp +++ vm/jitrino/src/optimizer/CodeGenerator.cpp @@ -22,12 +22,11 @@ #include "Jitrino.h" #include "CodeGenIntfc.h" -#include "FlowGraph.h" #if defined(_IPF_) - #include "ipf/IpfCodeGenerator.h" + #include "IpfCodeGenerator.h" #else - #include "ia32/Ia32CodeGenerator.h" + #include "ia32/Ia32CodeGenerator.h" #endif #include "Type.h" @@ -38,9 +37,18 @@ #include "Stl.h" #include "constantfolder.h" #include "optimizer.h" #include "../../vm/drl/DrlVMInterface.h" +#include "PMFAction.h" namespace Jitrino { + +class HIR2LIRSelectorSessionAction: public SessionAction { +public: + virtual void run (); +}; +static ActionFactory<HIR2LIRSelectorSessionAction> _hir2lir("hir2lir"); + + class _VarCodeSelector : public VarCodeSelector { public: _VarCodeSelector(VarOpnd* opnds, uint32* varMap, GCBasePointerMap& gcMap) @@ -56,7 +64,7 @@ public: varIdMap[v->getId()] = callback.defVar(v->getType(),v->isAddrTaken(), v->isPinned()); - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Opt var "; v->print(Log::out()); Log::out() << " is CG var " << (int) varIdMap[v->getId()] << ::std::endl; @@ -68,7 +76,7 @@ public: GCBasePointerMap::iterator i; for(i = gcMap.begin(); i != gcMap.end(); ++i) { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Set GC base of "; i->first->print(Log::out()); Log::out() << "(" << (int) varIdMap[i->first->getId()] << ") to "; @@ -101,7 +109,7 @@ private: class _BlockCodeSelector : public BlockCodeSelector { public: - _BlockCodeSelector(MemoryManager& mm, IRManager& irmanager, CFGNode* b,CG_OpndHandle** map, + _BlockCodeSelector(MemoryManager& mm, IRManager& irmanager, Node* b,CG_OpndHandle** map, uint32* varMap, bool sinkConstants0, bool sinkConstantsOne0) : irmanager(irmanager), memManager(mm), opndToCGInstMap(map), localOpndToCGInstMap(mm), varIdMap(varMap), block(b), @@ -407,7 +415,7 @@ public: return ConvertToIntOp::SignedOvf; case Overflow_Unsigned: return ConvertToIntOp::UnsignedOvf; - default: assert(0); + default: assert(0); } return ConvertToIntOp::NoOvf; // to keep the compiler quiet } @@ -425,6 +433,8 @@ public: switch(callId) { case InitializeArray: return JitHelperCallOp::InitializeArray; case PseudoCanThrow: return JitHelperCallOp::PseudoCanThrow; + case SaveThisState: return JitHelperCallOp::SaveThisState; + case ReadThisState: return JitHelperCallOp::ReadThisState; } assert(0); return JitHelperCallOp::InitializeArray; // to keep compiler quiet @@ -455,7 +465,7 @@ public: void genInstCode(InstructionCallback& instructionCallback, Inst *inst, bool genConsts) { - if(Log::cat_opt()->isIREnabled()) { + if(Log::isEnabled()) { Log::out() << "genInstCode "; inst->print(Log::out()); if (genConsts) { @@ -891,7 +901,7 @@ #endif JitHelperCallId callId = call->getJitHelperId(); if( callId == PseudoCanThrow ){ - cgInst = NULL; + instructionCallback.pseudoInst(); } else { cgInst = @@ -1003,7 +1013,7 @@ #endif isConstant = true; } break; - case Op_LdString: + case Op_LdRef: { if (!genConsts) break; @@ -1011,8 +1021,9 @@ #endif TokenInst *tokenInst = (TokenInst *)inst; uint32 token = tokenInst->getToken(); - cgInst = instructionCallback.ldString(tokenInst->getEnclosingMethod(),token, - acmod==AutoCompress_Yes); + cgInst = instructionCallback.ldRef(inst->getDst()->getType(), + tokenInst->getEnclosingMethod(), + token, acmod==AutoCompress_Yes); isConstant = true; } break; @@ -1222,19 +1233,14 @@ #endif break; case Op_TauLdIntfcVTableAddr: { - assert(inst->getNumSrcOperands() == 2); + assert(inst->getNumSrcOperands() == 1); TypeInst *typeInst = (TypeInst*)inst; Type * vtableType = typeInst->getTypeInfo(); assert(vtableType->isUserObject()); Opnd *base = inst->getSrc(0); - Opnd *tauBaseHasInterface = inst->getSrc(1); - - assert(tauBaseHasInterface->getType()->tag == Type::Tau); - cgInst = instructionCallback.tau_ldIntfTableAddr(inst->getDst()->getType(), getCGInst(base), - (NamedType*)vtableType, - getCGInst(tauBaseHasInterface)); + (NamedType*)vtableType); } break; case Op_TauArrayLen: @@ -1270,8 +1276,12 @@ #endif // Add a scaled index to an array element address case Op_AddScaledIndex: { + PtrType* arrType = (PtrType*) inst->getSrc(0)->getType(); + Type* refType = arrType->getPointedToType(); + assert(inst->getNumSrcOperands() == 2); - cgInst = instructionCallback.addElemIndex(getCGInst(inst->getSrc(0)), + cgInst = instructionCallback.addElemIndex(refType, + getCGInst(inst->getSrc(0)), getCGInst(inst->getSrc(1))); } break; @@ -1280,7 +1290,9 @@ #endif { assert(inst->getNumSrcOperands() == 2); cgInst = instructionCallback.scaledDiffRef(getCGInst(inst->getSrc(0)), - getCGInst(inst->getSrc(1))); + getCGInst(inst->getSrc(1)), + (Type *)inst->getSrc(0)->getType(), + (Type *)inst->getSrc(1)->getType()); } break; case Op_UncompressRef: @@ -1524,7 +1536,7 @@ #endif { assert(inst->getNumSrcOperands() == 1); if ( inst->getDefArgModifier() == NonNullThisArg ) { - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " chknull_NonNullThisArg_check" << ::std::endl; } cgInst = instructionCallback.tau_checkNull(getCGInst(inst->getSrc(0)), true); @@ -1745,8 +1757,22 @@ #endif case Op_Label: break; // nothing to do case Op_MethodEntry: + { + assert(inst->isMethodMarker()); + MethodMarkerInst* methEntryInst = inst->asMethodMarkerInst(); + instructionCallback.methodEntry(methEntryInst->getMethodDesc()); + } break; // nothing to do case Op_MethodEnd: + { + assert(inst->isMethodMarker()); + MethodMarkerInst* methEntryInst = inst->asMethodMarkerInst(); + // check that inst->getSrc(0) is really retOpnd and not thisOpnd + CG_OpndHandle* ret_val = inst->getNumSrcOperands()==0 ? NULL : + getCGInst(inst->getSrc(0)); + instructionCallback.methodEnd(methEntryInst->getMethodDesc(), + ret_val); + } break; // nothing to do case Op_SourceLineNumber: { @@ -1853,7 +1879,7 @@ #endif { TokenInst *counterInst = (TokenInst *)inst; uint32 counter = counterInst->getToken(); - instructionCallback.incCounter(irmanager.getTypeManager().getInt32Type(), counter); + instructionCallback.incCounter(irmanager.getTypeManager().getUInt32Type(), counter); } break; case Op_Prefetch: @@ -1970,7 +1996,7 @@ #endif } // end switch if (cgInst) { // record mapping from dst - if(Log::cat_opt()->isIREnabled()) { + if(Log::isEnabled()) { Log::out() << "genInstCode "; inst->print(Log::out()); if (genConsts) { @@ -1983,23 +2009,23 @@ #endif assert(dst); if (isConstant) { - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " isConstant" << ::std::endl; } assert(genConsts); if (sinkConstants) { - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " sinkConstants=true" << ::std::endl; } setLocalCGInst(cgInst, dst); } else { - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " sinkConstants=false" << ::std::endl; } setCGInst(cgInst, dst); } } else { - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " isConstant=false" << ::std::endl; } setCGInst(cgInst, dst); @@ -2009,7 +2035,7 @@ #endif } } } else { - if(Log::cat_opt()->isIREnabled()) { + if(Log::isEnabled()) { Log::out() << "genInstCode "; inst->print(Log::out()); if (genConsts) { @@ -2027,10 +2053,10 @@ #endif // // go through instructions // - Inst* labelInst = block->getFirstInst(); - Inst* inst = labelInst->next(); - while (inst != labelInst) { - if(Log::cat_opt()->isIREnabled()) { + Inst* labelInst = (Inst*)block->getFirstInst(); + Inst* inst = labelInst->getNextInst(); + while (inst != NULL) { + if(Log::isEnabled()) { Log::out() << "Code select "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -2041,7 +2067,7 @@ #endif instructionCallback.setCurrentHIRInstrID(instID); } genInstCode(instructionCallback, inst, !sinkConstants); - inst = inst->next(); + inst = inst->getNextInst(); } } private: @@ -2079,7 +2105,7 @@ private: CG_OpndHandle** opndToCGInstMap; StlMap<uint32, CG_OpndHandle*> localOpndToCGInstMap; uint32* varIdMap; - CFGNode* block; + Node* block; InstructionCallback* callback; bool sinkConstants; bool sinkConstantsOne; @@ -2088,23 +2114,18 @@ private: class _CFGCodeSelector : public CFGCodeSelector { public: - _CFGCodeSelector(MemoryManager& mm, IRManager& irmanager, FlowGraph* fg,CG_OpndHandle** map, + _CFGCodeSelector(MemoryManager& mm, IRManager& irmanager, ControlFlowGraph* fg,CG_OpndHandle** map, uint32 *varMap, bool sinkConstants0, bool sinkConstantsOne0) : irmanager(irmanager), opndToCGInstMap(map), varIdMap(varMap), flowGraph(fg), numNodes(0), memManager(mm), sinkConstants(sinkConstants0), - sinkConstantsOne(sinkConstantsOne0){ - numNodes = flowGraph->assignDepthFirstNum(); + sinkConstantsOne(sinkConstantsOne0) + { + flowGraph->orderNodes(); + numNodes = flowGraph->getNodeCount(); } void genCode(Callback& callback) { bool hasEdgeProfile = flowGraph->hasEdgeProfile(); // - // If the flags direct us not to pass profile information - // to the code generator, ignore the profile - // - OptimizerFlags& optimizerFlags = *irmanager.getCompilationContext()->getOptimizerFlags(); - if (optimizerFlags.pass_profile_to_cg == false) - hasEdgeProfile = false; - // // go through nodes in flow graph and call genDispatchNode for nodes // that are handlers (dispatchers) and genBlock for nodes that are blocks. // record the integer id that is returned and map it to the node. @@ -2115,26 +2136,26 @@ public: // node id returned by the code selector // uint32* nodeMapTable = new (memManager) uint32[numNodes]; - ::std::vector<CFGNode*> nodes; + ::std::vector<Node*> nodes; nodes.reserve(numNodes); // Compute postorder list to get only reachable nodes. flowGraph->getNodesPostOrder(nodes); - assert(flowGraph->getExit()->getTraversalNum() == flowGraph->getTraversalNum()); - CFGNode* unwind = flowGraph->getUnwind(); - CFGNode* exit = flowGraph->getExit(); + assert(flowGraph->getExitNode()->getTraversalNum() == flowGraph->getTraversalNum()); + Node* unwind = flowGraph->getUnwindNode(); + Node* exit = flowGraph->getExitNode(); // Use reverse iterator to generate nodes in reverse postorder. - ::std::vector<CFGNode*>::reverse_iterator niter; + ::std::vector<Node*>::reverse_iterator niter; for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; // // Count in and out edges // uint32 numOutEdges = node->getOutDegree(); uint32 numInEdges = node->getInDegree(); uint32 nodeId = MAX_UINT32; - double cnt = (hasEdgeProfile? node->getFreq() : -1.0); + double cnt = (hasEdgeProfile? node->getExecCount() : -1.0); if (node == exit) { nodeId = callback.genExitNode(numInEdges,cnt); @@ -2142,7 +2163,7 @@ public: else if (node == unwind) { nodeId = callback.genUnwindNode(numInEdges,numOutEdges,cnt); } - else if (node->isBasicBlock()) { + else if (node->isBlockNode()) { _BlockCodeSelector blockCodeSelector(memManager, irmanager, node, @@ -2156,9 +2177,9 @@ public: // Derive the block kind (prolog, epilog, inner block) // CFGCodeSelector::Callback::BlockKind blockKind; - if (node == flowGraph->getEntry()) + if (node == flowGraph->getEntryNode()) blockKind = CFGCodeSelector::Callback::Prolog; - else if (node == flowGraph->getReturn()) + else if (node == flowGraph->getReturnNode()) blockKind = CFGCodeSelector::Callback::Epilog; else blockKind = CFGCodeSelector::Callback::InnerBlock; @@ -2180,22 +2201,22 @@ public: // for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { double prob; - CFGNode* tailNode = *niter; + Node* tailNode = *niter; uint32 tailNodeId = nodeMapTable[tailNode->getDfNum()]; - if (tailNode->getLastInst()->isSwitch()) { + if (((Inst*)tailNode->getLastInst())->isSwitch()) { // // Generate switch edges // SwitchInst* sw = (SwitchInst *)tailNode->getLastInst(); - CFGNode *defaultNode = sw->getDefaultTarget()->getCFGNode(); + Node *defaultNode = sw->getDefaultTarget()->getNode(); uint32 defaultNodeId = nodeMapTable[defaultNode->getDfNum()]; uint32 numTargets = sw->getNumTargets(); uint32 * targetNodeIds = new (memManager) uint32[numTargets]; double * targetProbs = new (memManager) double[numTargets]; uint32 i; for (i = 0; i < numTargets; i++) { - CFGNode *headNode = sw->getTarget(i)->getCFGNode(); - CFGEdge *edge = (CFGEdge *) tailNode->findTarget(headNode); + Node *headNode = sw->getTarget(i)->getNode(); + Edge *edge = (Edge *) tailNode->findTargetEdge(headNode); targetNodeIds[i] = nodeMapTable[headNode->getDfNum()]; targetProbs[i] = (hasEdgeProfile? edge->getEdgeProb() : -1.0); } @@ -2204,10 +2225,10 @@ public: // // Generate an exception edge if it exists // - CFGEdge* throwEdge = (CFGEdge*) tailNode->getExceptionEdge(); + Edge* throwEdge = (Edge*) tailNode->getExceptionEdge(); if(throwEdge != NULL) { assert(0); - CFGNode *succNode = throwEdge->getTargetNode(); + Node *succNode = throwEdge->getTargetNode(); assert(succNode->isDispatchNode()); uint32 headNodeId = nodeMapTable[succNode->getDfNum()]; prob = (hasEdgeProfile? throwEdge->getEdgeProb() : -1.0); @@ -2218,30 +2239,30 @@ public: // // Gen edges for a node that does not end with a switch // - const CFGEdgeDeque& edges = tailNode->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& edges = tailNode->getOutEdges(); + Edges::const_iterator eiter; for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { - CFGEdge* edge = *eiter; + Edge* edge = *eiter; prob = (hasEdgeProfile? edge->getEdgeProb() : -1.0); - CFGNode * headNode = (CFGNode*)edge->getTargetNode(); + Node * headNode = edge->getTargetNode(); uint32 headNodeId = nodeMapTable[headNode->getDfNum()]; - CFGEdge::Kind edgeKind = edge->getEdgeType(); + Edge::Kind edgeKind = edge->getKind(); switch (edgeKind) { - case CFGEdge::Unconditional: + case Edge::Kind_Unconditional: callback.genUnconditionalEdge(tailNodeId,headNodeId,prob); break; - case CFGEdge::True: + case Edge::Kind_True: callback.genTrueEdge(tailNodeId,headNodeId,prob); break; - case CFGEdge::False: + case Edge::Kind_False: callback.genFalseEdge(tailNodeId,headNodeId,prob); break; - case CFGEdge::Exception: + case Edge::Kind_Dispatch: callback.genExceptionEdge(tailNodeId,headNodeId,prob); break; - case CFGEdge::Catch: + case Edge::Kind_Catch: { - Inst* first = headNode->getFirstInst(); + Inst* first = (Inst*)headNode->getFirstInst(); assert(first->isLabel() && ((LabelInst*)first)->isCatchLabel()); CatchLabelInst * label = (CatchLabelInst *)first; @@ -2251,38 +2272,19 @@ public: prob); break; } - case CFGEdge::Exit: - callback.genExitEdge(tailNodeId,headNodeId,prob); - break; default: assert(0); } } } } - - LoopTree& loopInfo = *(irmanager.getLoopTree()); - assert(loopInfo.isValid()); - for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - uint32 dfNum = node->getDfNum(); - uint32 nodeid = nodeMapTable[dfNum]; - bool isHeader = loopInfo.isLoopHeader(node); - // A loop header should have two in edges - one entry and one back edge. - assert(!isHeader || (node->getInDegree() == 2)); - bool hasHeader = loopInfo.hasContainingLoopHeader(node); - uint32 headerid = (uint32) -1; - if(hasHeader) - headerid = nodeMapTable[loopInfo.getContainingLoopHeader(node)->getDfNum()]; - callback.setLoopInfo(nodeid, isHeader, hasHeader, headerid); - } } uint32 getNumNodes() {return numNodes;} private: IRManager& irmanager; CG_OpndHandle** opndToCGInstMap; uint32* varIdMap; - FlowGraph* flowGraph; + ControlFlowGraph* flowGraph; uint32 numNodes; MemoryManager& memManager; bool sinkConstants; @@ -2294,7 +2296,7 @@ public: _MethodCodeSelector(IRManager& irmanager, MethodDesc *desc, VarOpnd* opnds, - FlowGraph* fg, + ControlFlowGraph* fg, OpndManager& opndManager, bool sinkConstants0, bool sinkConstantsOne0) @@ -2322,16 +2324,9 @@ public: } _CFGCodeSelector cfgCodeSelector(localMemManager,irmanager,flowGraph,opndToCGInstMap, varIdMap, sinkConstants, sinkConstantsOne); - callback.setProfileInfo(irmanager.getCodeProfiler()); bool hasEdgeProfile = flowGraph->hasEdgeProfile(); - // - // If the flags direct us not to pass profile information - // to the code generator, ignore the profile - // - OptimizerFlags& optimizerFlags = *irmanager.getCompilationContext()->getOptimizerFlags(); - if (optimizerFlags.pass_profile_to_cg == false) - hasEdgeProfile = false; + callback.genCFG(cfgCodeSelector.getNumNodes(),cfgCodeSelector, hasEdgeProfile); } private: @@ -2340,7 +2335,7 @@ private: uint32 numArgs; uint32 numVars; VarOpnd* varOpnds; - FlowGraph* flowGraph; + ControlFlowGraph* flowGraph; MethodDesc* methodDesc; bool sinkConstants; bool sinkConstantsOne; @@ -2349,44 +2344,38 @@ private: // // code generator entry point // -bool -genCode(IRManager& irManager, - CompilationInterface& compilationInterface, - MethodDesc* methodDesc, - FlowGraph* flowGraph, - OpndManager& opndManager, - Jitrino::Backend cgFlag, - bool sinkConstants, - bool sinkConstantsOne) { - +void HIR2LIRSelectorSessionAction::run() { + CompilationContext* cc = getCompilationContext(); + IRManager& irManager = *cc->getHIRManager(); + CompilationInterface* ci = cc->getVMCompilationInterface(); + MethodDesc* methodDesc = ci->getMethodToCompile(); + OpndManager& opndManager = irManager.getOpndManager(); + const OptimizerFlags& optFlags = irManager.getOptimizerFlags(); VarOpnd* varOpnds = opndManager.getVarOpnds(); - uint32 byteCodeSize = methodDesc->getByteCodeSize(); - MemoryManager codegenMemManager(byteCodeSize * 128, "genCode.codegenMemManager"); + MemoryManager& mm = cc->getCompilationLevelMemoryManager(); - _MethodCodeSelector methodCodeSelector(irManager,methodDesc,varOpnds,flowGraph,opndManager, - sinkConstants, sinkConstantsOne); + MethodCodeSelector* mcs = new (mm) _MethodCodeSelector(irManager,methodDesc,varOpnds,&irManager.getFlowGraph(), + opndManager, optFlags.sink_constants, optFlags.sink_constants1); #if defined(_IPF_) - IPF::IpfCodeGenerator ipfCodeGenerator(codegenMemManager,compilationInterface); - return ipfCodeGenerator.genCode(methodCodeSelector); + IPF::CodeGenerator cg(mm, *ci); #else - Ia32::CodeGenerator ia32CodeGenerator(codegenMemManager,compilationInterface); - return ia32CodeGenerator.genCode(methodCodeSelector); + Ia32::CodeGenerator cg; #endif - + cg.genCode(this, *mcs); } -uint64 +POINTER_SIZE_INT InlineInfoMap::ptr_to_uint64(void *ptr) { #ifdef POINTER64 - return (uint64)ptr; + return (POINTER_SIZE_INT)ptr; #else - return (uint32)ptr; + return (POINTER_SIZE_INT)ptr; #endif } Method_Handle -InlineInfoMap::uint64_to_mh(uint64 value) +InlineInfoMap::uint64_to_mh(POINTER_SIZE_INT value) { #ifdef POINTER64 return (Method_Handle)value; @@ -2416,7 +2405,7 @@ InlineInfoMap::isEmpty() const // size increased for better portability, // everybody is welcome to optimize this storage // -// size = 8 * (2 * offset_cnt + 1 + total_mh_cnt) +// size = sizeof(POINTER_SIZE_INT) * (2 * offset_cnt + 1 + total_mh_cnt * 2) // uint32 InlineInfoMap::computeSize() const @@ -2428,7 +2417,7 @@ InlineInfoMap::computeSize() const total_mh_cnt += it->inline_info->countLevels(); offset_cnt++; } - return 8 * (2 * offset_cnt + 1 + total_mh_cnt); + return sizeof(POINTER_SIZE_INT) * (2 * offset_cnt + 1 + total_mh_cnt * 2); } void @@ -2436,20 +2425,22 @@ InlineInfoMap::write(InlineInfoPtr outpu { // assert(((uint64)ptr_to_uint64(output) & 0x7) == 0); - uint64* ptr = (uint64 *)output; - *ptr++ = (uint64)list.size(); // offset_cnt + POINTER_SIZE_INT* ptr = (POINTER_SIZE_INT *)output; + *ptr++ = (POINTER_SIZE_INT)list.size(); // offset_cnt InlineInfoList::iterator it = list.begin(); for (; it != list.end(); it++) { - *ptr++ = (uint64) it->offset; - uint64 depth = 0; - uint64* depth_ptr = ptr++; + *ptr++ = (POINTER_SIZE_INT) it->offset; + POINTER_SIZE_INT depth = 0; + POINTER_SIZE_INT* depth_ptr = ptr++; assert(it->inline_info->countLevels() > 0); - InlineInfo::MethodDescList::iterator desc_it = it->inline_info->inlineChain->begin(); + InlineInfo::InlinePairList::iterator desc_it = it->inline_info->inlineChain->begin(); for (; desc_it != it->inline_info->inlineChain->end(); desc_it++) { - MethodDesc* mdesc = *desc_it; + MethodDesc* mdesc = (MethodDesc*)(*desc_it)->first; + uint32 bcOffset = (uint32)(*desc_it)->second; //assert(dynamic_cast<DrlVMMethodDesc*>(mdesc)); // <-- some strange warning on Win32 here *ptr++ = ptr_to_uint64(((DrlVMMethodDesc*)mdesc)->getDrlVMMethod()); + *ptr++ = (POINTER_SIZE_INT)bcOffset; depth++; } assert(depth == it->inline_info->countLevels()); @@ -2458,20 +2449,20 @@ InlineInfoMap::write(InlineInfoPtr outpu assert((POINTER_SIZE_INT)ptr == (POINTER_SIZE_INT)output + computeSize()); } -uint64* +POINTER_SIZE_INT* InlineInfoMap::find_offset(InlineInfoPtr ptr, uint32 offset) { - assert(((uint64)ptr_to_uint64(ptr) & 0x7) == 0); + assert(((POINTER_SIZE_INT)ptr_to_uint64(ptr) & 0x7) == 0); - uint64* tmp_ptr = (uint64 *)ptr; - uint64 offset_cnt = *tmp_ptr++; + POINTER_SIZE_INT* tmp_ptr = (POINTER_SIZE_INT *)ptr; + POINTER_SIZE_INT offset_cnt = *tmp_ptr++; for (uint32 i = 0; i < offset_cnt; i++) { - uint64 curr_offs = *tmp_ptr++ ; + POINTER_SIZE_INT curr_offs = *tmp_ptr++ ; if ( offset == curr_offs ) { return tmp_ptr; } - uint64 curr_depth = *tmp_ptr++ ; + POINTER_SIZE_INT curr_depth = (*tmp_ptr++)*2 ; tmp_ptr += curr_depth; } @@ -2481,7 +2472,7 @@ InlineInfoMap::find_offset(InlineInfoPtr uint32 InlineInfoMap::get_inline_depth(InlineInfoPtr ptr, uint32 offset) { - uint64* tmp_ptr = find_offset(ptr, offset); + POINTER_SIZE_INT* tmp_ptr = find_offset(ptr, offset); if ( tmp_ptr != NULL ) { return (uint32)*tmp_ptr; } @@ -2491,14 +2482,28 @@ InlineInfoMap::get_inline_depth(InlineIn Method_Handle InlineInfoMap::get_inlined_method(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { - uint64* tmp_ptr = find_offset(ptr, offset); + POINTER_SIZE_INT* tmp_ptr = find_offset(ptr, offset); if ( tmp_ptr != NULL ) { - uint64 depth = *tmp_ptr++; + POINTER_SIZE_INT depth = *tmp_ptr++; assert(inline_depth < depth); - tmp_ptr += (depth - 1) - inline_depth; + tmp_ptr += ((depth - 1) - inline_depth ) * 2; return uint64_to_mh(*tmp_ptr); } return NULL; } +uint16 +InlineInfoMap::get_inlined_bc(InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) +{ + POINTER_SIZE_INT* tmp_ptr = find_offset(ptr, offset); + if ( tmp_ptr != NULL ) { + POINTER_SIZE_INT depth = *tmp_ptr++; + assert(inline_depth < depth); + tmp_ptr += ((depth - 1) - inline_depth) * 2 + 1; + return (uint16)(*tmp_ptr); + } + return 0; +} + + } //namespace Jitrino diff --git vm/jitrino/src/optimizer/Dominator.cpp vm/jitrino/src/optimizer/Dominator.cpp deleted file mode 100644 index 9627c5b..0000000 --- vm/jitrino/src/optimizer/Dominator.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Pavel A. Ozhdikhin - * @version $Revision: 1.14.16.1.4.4 $ - * - */ - -#include "FlowGraph.h" -#include "Dominator.h" - -namespace Jitrino { - -// BOTTOM : no idom. idom[entry] = BOTTOM -#define NONE UINT32_MAX -// TOP : no information computed yet -#define UNDEFINED 0 - -// Cooper / Harvey / Kennedy variation on simple iterative dominator algorithm. -// They claim that this is faster than Lengauer / Tarjan in practice. -DominatorTree* -DominatorBuilder::computeDominators(MemoryManager& mm, FlowGraph* flowgraph, bool isPost, bool ignoreUnreach) { - // Temp memory manager - MemoryManager tmm(flowgraph->getMaxNodeId()*(sizeof(CFGNode*)*2), "DominatorBuilder::computeDominators"); - StlVector<CFGNode*> nodes(tmm); - - // Get the nodes of the flowgraph in postorder. - flowgraph->getNodesPostOrder(nodes, !isPost); - uint32 numNodes = (uint32) nodes.size(); -#ifdef _DEBUG - // Start (entry/exit) node should be last. - CFGNode* start = nodes.back(); - assert((start == (isPost ? flowgraph->getExit() : flowgraph->getEntry()) - && start->getPostNum() == numNodes-1)); -#endif - // Initialize the idom array to UNDEFINED. Idiom maps the postorder - // number of a node to the postorder number of its idom. - StlVector<uint32> idom(tmm); - idom.insert(idom.end(), (unsigned int) numNodes-1, UNDEFINED); - // Initialize idom[entry] = NONE. - idom.insert(idom.end(), NONE); - - // Find maximal fixed point - bool changed = true; - while(changed) { - changed = false; - // Process all nodes except entry in reverse postorder. - StlVector<CFGNode*>::reverse_iterator i; - for(i = nodes.rbegin()+1; i != nodes.rend(); ++i) { - ControlFlowNode* node = *i; - uint32 nodeNum = node->getPostNum(); - - // Compute updated idom from predecessors - uint32 newIdom = UNDEFINED; - ControlFlowGraph::EdgeList::const_iterator j; - for(j = node->getEdges(isPost).begin(); j != node->getEdges(isPost).end(); ++j) { - ControlFlowNode* pred = (*j)->getNode(isPost); - // Assert that pred is reachable. - if (!ignoreUnreach) - assert(pred->getTraversalNum() == flowgraph->getTraversalNum()); - if (!ignoreUnreach || (ignoreUnreach && (pred->getTraversalNum() == flowgraph->getTraversalNum()))) { - uint32 predNum = pred->getPostNum(); - // Skip unprocessed preds (only happens on first iteration). - if(idom[predNum] != UNDEFINED) - // Intersect dominator sets. - newIdom = (newIdom == UNDEFINED) ? predNum : intersect(idom, newIdom, predNum); - } - } - assert(newIdom != UNDEFINED); - - // Update if changed - if(newIdom != idom[nodeNum]) { - // Assert that we are converging. - assert(newIdom > idom[nodeNum]); - idom[nodeNum] = newIdom; - changed = true; - } - } - } - - // Build dominator tree and return. - return new (mm) DominatorTree(mm, flowgraph, nodes, idom, isPost); -} - -uint32 -DominatorBuilder::intersect(StlVector<uint32>& idom, uint32 finger1, uint32 finger2) { - // Intersect the dominator sets represented by finger1 and finger2. - while(finger1 != finger2) { - while(finger1 < finger2) - finger1 = idom[finger1]; - while(finger2 < finger1) - finger2 = idom[finger2]; - } - // Set should at least contain root/entry. - assert(finger1 != NONE); - return finger1; -} - -DominatorTree::DominatorTree(MemoryManager& mm, - FlowGraph* fg, - StlVector<CFGNode*>& nodes, - StlVector<uint32>& idom, - bool isPostDominator) - : flowgraph(fg), traversalNum(fg->getTraversalNum()), - numNodes(fg->getMaxNodeId()), - _isPostDominator(isPostDominator), tree(mm, numNodes, NULL) { - // Create the dominator tree nodes.. - uint32 postNum, id=MAX_UINT32; - for(postNum = 0; postNum < nodes.size(); ++postNum) { - CFGNode* node = nodes[postNum]; - id = node->getId(); - tree[id] = new (mm) DominatorNode(node); - } - - // Create tree itself. Note that the children of each - // dominator parent node will be in sorted in - // reverse postorder. It's assumed that nodes is - // in postorder. - for(postNum = 0; postNum < nodes.size(); ++postNum) { - CFGNode* node = nodes[postNum]; - id = node->getId(); - // Assert post-ordering of nodes. - assert((uint32) postNum == node->getPostNum()); - if(idom[postNum] != NONE) { - // Assert that idoms are acyclic. - assert(idom[postNum] > postNum); - CFGNode* parent = nodes[idom[postNum]]; - uint32 parentId = parent->getId(); - assert(tree[parentId] != NULL); - // Assert that new child (added to beginning) has highest postorder number. - assert(tree[parentId]->getChild() == NULL || tree[parentId]->getChild()->getNode()->getPostNum() < postNum); - tree[parentId]->addChild(tree[id]); - } - } - - // Last node is root. - root = tree[id]; - computeOrder(); -} - -bool DominatorTree::dominates(CFGNode* a, CFGNode* b) { - assert(a != NULL && b != NULL); - assert(a->getId() < numNodes && b->getId() < numNodes); - return a==b || isAncestor(tree[a->getId()], tree[b->getId()]); -} - - -DomFrontier::DomFrontier(MemoryManager& mm, - DominatorTree& d, - FlowGraph* fg) -: memManager(mm), dom(d), isPostDominator(d.isPostDominator()) { - // To Do: may want to keep number of nodes in flow graph instead of recomputing every time - numNodes = (uint32) fg->getNodes().size(); - - // if flow graph has been modified since dominator was computed, then - // dominator information needs to be recomputed - if (!dom.isValid()) { - DominatorBuilder db; - dom = *db.computeDominators(memManager,fg); - } - - beenComputed = new (memManager) BitSet(memManager, numNodes); - DF = (List<CFGNode>**) memManager.alloc(sizeof(List<CFGNode>*)*numNodes); - memset(DF, 0, numNodes*sizeof(List<CFGNode>*)); // initialized with NULL -} - -void DomFrontier::printDomFrontier(::std::ostream& cout, CFGNode* node) { - node->printLabel(cout); - ::std::cout << " Frontiers: "; - for (List<CFGNode>* f = DF[node->getDfNum()]; f != NULL; f = f->getNext()) { - f->getElem()->printLabel(cout); ::std::cout << " "; - } - ::std::cout << ::std::endl; -} - -void DomFrontier::addDF(uint32 entry, CFGNode* n) { - assert(entry < numNodes); - // make sure no duplicate entry - for (List<CFGNode>* l = DF[entry]; l != NULL; l = l->getNext()) - if (l->getElem() == n) - return; - DF[entry] = new (memManager) List<CFGNode>(n,DF[entry]); -} - -void DomFrontier::computeDomFrontier(CFGNode* node) { - uint32 dfnum = node->getDfNum(); - // if dom frontiers are not computed yet - if (beenComputed->getBit(dfnum)) - return; - beenComputed->setBit(dfnum,true); - - // If this is a post-dominance frontier, use the reverse graph. - bool forward = !isPostDominator; - - // compute DF local: the successors of node that are not strictly - // dominated by node - const CFGEdgeDeque& edges = (const CFGEdgeDeque&) node->getEdges(forward); - CFGEdgeDeque::const_iterator eiter; - for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { - CFGEdge* e = *eiter; - CFGNode *succ = (CFGNode*) e->getNode(forward); - if (dom.getIdom(succ) != node) { - addDF(dfnum,succ); - } - } - - // compute DF up: Nodes in the dom frontier of node that are dominated - // by node's immediate dominator - for (DominatorNode* c = dom.getDominatorNode(node)->getChild(); c != NULL; c = c->getSiblings()) { - CFGNode* child = c->getNode(); - computeDomFrontier(child); - - // go over each frontier of child - for (List<CFGNode>* f = DF[child->getDfNum()];f != NULL; f = f->getNext()) { - CFGNode *elem = f->getElem(); - // if node does not strictly dominates elem - if (elem == node || !dom.dominates(node,elem)) { - addDF(dfnum,elem); - } - } - } -} - - -} //namespace Jitrino diff --git vm/jitrino/src/optimizer/Dominator.h vm/jitrino/src/optimizer/Dominator.h deleted file mode 100644 index 5bc12e9..0000000 --- vm/jitrino/src/optimizer/Dominator.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Pavel A. Ozhdikhin - * @version $Revision: 1.10.14.1.4.4 $ - * - */ - -#ifndef _FLOWGRAPHDOM_H_ -#define _FLOWGRAPHDOM_H_ - -#include "MemoryManager.h" -#include "Stl.h" -#include "BitSet.h" -#include "Tree.h" - -namespace Jitrino { - -/** - * A DominatorNode represents (post)dominance information computed for a - * ControlFlowNode. A DominatorNode may be use to navigate the - * DominatorTree (see below). - **/ -class DominatorNode : public TreeNode { -public: - DominatorNode(CFGNode* n) : node(n) {} - DominatorNode* getChild() {return (DominatorNode*)child;} - DominatorNode* getSiblings() {return (DominatorNode*)siblings;} - DominatorNode* getParent() {return (DominatorNode*)parent;} - CFGNode* getNode() {return node;} - virtual void print(::std::ostream& os) { node->printLabel(os); } -private: - CFGNode* node; -}; - - -/** - * A DominatorTree represents (post)dominance information computed for a - * ControlFlowGraph. It may be used to query or navigate (post)dominance - * relationships. The root of the tree is the DominatorNode of the - * entry/exit, and the parent of any node (other than the root) is the - * immediate dominator/post-dominator. - * - * Note that a DominatorTree is invalidated when the underlying CFG - * is modified. The DominatorTree can still be queried/navigated, - * but may no longer reflect the CFG. - **/ -class DominatorTree: public Tree, public CFGNode::Annotator { - friend class DominatorBuilder; -public: - // Returns true if a == b or a strictly (post)dominates b. - bool dominates(CFGNode* a, CFGNode* b); - - // Returns the immediate (post)dominator of n. Return NULL if no nodes (post)dominate n. - CFGNode* getIdom(CFGNode* n) { - DominatorNode* idom = getDominatorNode(n)->getParent(); - return (idom == NULL) ? NULL : idom->getNode(); - } - - // Returns the dominator tree node associated with this CFG node. - // Use the tree node to traverse the (post)dominator tree. - DominatorNode* getDominatorNode(CFGNode* n) {return tree[n->getId()];} - - // Returns the root tree node of the (post)dominator tree. If this is a - // dominator tree, this is the tree node of the entry. If this is a - // post-dominator tree, this is the tree node of the exit. - DominatorNode* getDominatorRoot() { - return (DominatorNode*) root; - } - - // Returns the number of nodes in the tree. - uint32 getNumNodes() const { return numNodes; } - - // True if this is a post-dominator tree. - bool isPostDominator() const { return _isPostDominator; } - - // True if the graph was not modified since the dominator was computed. - bool isValid() { - return traversalNum > flowgraph->getModificationTraversalNum(); - } - uint32 getTraversalNum() { return traversalNum; } - - // True if node has dominator information. Note, if the dominator tree - // is not valid overall, it is up to the caller to ensure that an - // individual nodes information is still valid. - bool hasDomInfo(CFGNode *n) { - return (n->getId() < numNodes && tree[n->getId()] != NULL); - } - - void printIdom(::std::ostream& cout, CFGNode* n) { - assert(n->getId() < numNodes); - CFGNode* dom = getIdom(n); - if (dom == NULL) - cout << "NULL"; - else - dom->printLabel(cout); - } - - void annotateNode(::std::ostream& os, ControlFlowNode* node) { - if(isValid()) { - CFGNode* idom = getIdom((CFGNode*) node); - if(idom != NULL) { - os << "[IDom="; - idom->printLabel(os); - os << "]"; - } - } - } - -private: - DominatorTree(MemoryManager& mm, FlowGraph* fg, StlVector<CFGNode*>& nodes, - StlVector<uint32>& idom, bool isPostDominator); - - FlowGraph* flowgraph; - uint32 traversalNum; - uint32 numNodes; - bool _isPostDominator; - StlVector<DominatorNode*> tree; -}; - - -/** - * A DominatorBuilder is used to compute (post)dominator information given - * a CFG. - **/ -class DominatorBuilder { -public: - DominatorBuilder() {} - DominatorTree* computeDominators(MemoryManager& mm, FlowGraph* flowgraph, bool isPost=false, bool ignoreUnreach = false); - DominatorTree* computePostdominators(MemoryManager& mm, FlowGraph* flowgraph) { return computeDominators(mm, flowgraph, true); } -private: - uint32 intersect(StlVector<uint32>& idom, uint32 num1, uint32 num2); -}; - -/** - * DomFrontier provides dominance frontier information given - * a dominator tree. Note, if passed a post-dominator tree, - * the post-dominance frontier is, by definition, the control - * dependence set. - **/ -class DomFrontier { -public: - DomFrontier(MemoryManager& mm, DominatorTree& d, FlowGraph* fg); - void printDomFrontier(::std::ostream&, CFGNode* n); - uint32 getNumNodes() {return numNodes;} - List<CFGNode>* getFrontiersOf(CFGNode* n) { - assert(n->getDfNum() < numNodes); - computeDomFrontier(n); - return DF[n->getDfNum()]; - } - DominatorTree& getDominator() {return dom;} -private: - void computeDomFrontier(CFGNode* n); - void addDF(uint32 entry, CFGNode* n); - - - List<CFGNode>** DF; - uint32 numNodes; - BitSet* beenComputed; - MemoryManager& memManager; - DominatorTree& dom; - bool isPostDominator; -}; - -} //namespace Jitrino - -#endif // _FLOWGRAPHDOM_H_ diff --git vm/jitrino/src/optimizer/FlowGraph.cpp vm/jitrino/src/optimizer/FlowGraph.cpp index a16473c..6eba9dc 100644 --- vm/jitrino/src/optimizer/FlowGraph.cpp +++ vm/jitrino/src/optimizer/FlowGraph.cpp @@ -20,306 +20,61 @@ * */ -#include <stdlib.h> -#include <string.h> #include "Opcode.h" #include "Type.h" #include "FlowGraph.h" #include "Dominator.h" #include "Stack.h" #include "IRBuilder.h" +#include "irmanager.h" #include "Log.h" -#include "Timer.h" -#include "Profiler.h" +#include "XTimer.h" +#include "StaticProfiler.h" #include "escapeanalyzer.h" #include "TranslatorIntfc.h" #include "CGSupport.h" +#include "LoopTree.h" -namespace Jitrino { - -CFGEdge::Kind -CFGEdge::getEdgeType() { - CFGEdge::Kind kind = CFGEdge::Unknown; - // - // determine kind - // - CFGNode* node = getSourceNode(); - CFGNode* succ = getTargetNode(); - if (succ->isDispatchNode()) - kind = CFGEdge::Exception; - else if(succ->isExitNode()) - kind = CFGEdge::Exit; - else if (node->isDispatchNode()) - kind = CFGEdge::Catch; - else { // true, false or unconditional - Inst* last = node->getLastInst(); - assert(last != NULL); - if (last->getOpcode() == Op_Branch) { - BranchInst* br = (BranchInst*)last; - // cfgnode's first inst is a label inst - kind = (br->getTargetLabel() == succ->getFirstInst())? - CFGEdge::True : CFGEdge::False; - } - else if (last->isSwitch()) { - SwitchInst* sw = (SwitchInst *)last; - kind = (sw->getDefaultTarget() == succ->getFirstInst())? - CFGEdge::False : CFGEdge::Switch; - } - else - kind = CFGEdge::Unconditional; // jump - } - return kind; -} - - -// -// assign depth first numbering starting from the prolog node -// - -uint32 FlowGraph::assignDepthFirstNum() { - dfnMap.clear(); - getNodesPreOrder(dfnMap); - return (uint32) dfnMap.size(); -} - -// -// orders the nodes on a breadth-first manner -// -void FlowGraph::orderDepthFirst() { - MemoryManager mm((getMaxNodeId() + 1) * sizeof(CFGNode*), "FlowGraph::orderDepthFirst"); - CFGNodeDeque workSet(mm); - ControlFlowGraph::getNodesPreOrder((ControlFlowGraph::NodeList&) workSet); - - CFGNodeDeque& nodes = (CFGNodeDeque&) getNodes(); - nodes.clear(); - nodes.splice(nodes.begin(), workSet); -} - -// -// as the name says, create a basic block, and put it in the node list ! -// - -CFGNode* -FlowGraph::createBlockNode() -{ - return createBlock(instFactory.makeLabel()); -} - -CFGNode* -FlowGraph::createCatchNode(uint32 order, Type* exceptionType) -{ - return createBlock(instFactory.makeCatchLabel(order, exceptionType)); -} - -CFGNode* FlowGraph::createBlock(LabelInst* label) { - CFGNode* bb = new (memManager) CFGNode(memManager, label); - label->setCFGNode(bb); - addNode(bb); // append bb into the node list - return bb; -} - -CFGNode* -FlowGraph::createDispatchNode() -{ - LabelInst* label = instFactory.makeLabel(); - CFGNode* dn = new (memManager) CFGNode(memManager, label, CFGNode::Dispatch); - label->setCFGNode(dn); - addNode(dn); - return dn; -} - -CFGNode* -FlowGraph::createExitNode() -{ - LabelInst* label = instFactory.makeLabel(); - CFGNode* dn = new (memManager) CFGNode(memManager, label, CFGNode::Exit); - label->setCFGNode(dn); - addNode(dn); - return dn; -} - -// same as before, but put the new node after a known node - - -CFGNode* FlowGraph::createBlockAfter(CFGNode *node) { - return createBlockAfter(instFactory.makeLabel(),node); -} - -CFGNode* FlowGraph::createBlockAfter(LabelInst *label, CFGNode *node) { - CFGNode* bb = new (memManager) CFGNode(memManager, label); - label->setCFGNode(bb); - label->setState(((LabelInst*)node->getFirstInst())->getState()); - - CFGNodeDeque& nodes = (CFGNodeDeque&) getNodes(); - CFGNodeDeque::iterator i; - if (node == NULL) { - i = nodes.begin(); - } else { - i = ::std::find(nodes.begin(), nodes.end(), node); - assert(i != nodes.end()); - ++i; - } - - addNode((ControlFlowGraph::NodeList::iterator&) i, bb); - - return bb; -} - - -CFGNode* FlowGraph::duplicateBlockAfter(LabelInst *label, CFGNode *node, CFGNode *source) { - assert(!source->isExitNode() && (source != getUnwind()) && (source != getReturn())); - CFGNode* bb = new (memManager) CFGNode(memManager, label, source->getKind()); - bb->setFlags(source->getFlags()); +#include <stdlib.h> +#include <string.h> - // the rest is the same as createBlockAfter !!! +namespace Jitrino { - label->setCFGNode(bb); +class NodeRenameTable : public HashTable<Node,Node> { +public: + typedef HashTableIter<Node, Node> Iter; - CFGNodeDeque& nodes = (CFGNodeDeque&) getNodes(); - CFGNodeDeque::iterator i; - if (node == NULL) { - i = nodes.end(); - } else { - label->setState(((LabelInst*)node->getFirstInst())->getState()); - i = ::std::find(nodes.begin(), nodes.end(), node); - assert(i != nodes.end()); - ++i; + NodeRenameTable(MemoryManager& mm,uint32 size) : + HashTable<Node,Node>(mm,size) {} + Node *getMapping(Node *node) { + return (Node*)lookup(node); } - - addNode((ControlFlowGraph::NodeList::iterator&) i, bb); - - return bb; -} - -void -FlowGraph::_moveInstructions(Node* _fromNode, Node* _toNode, bool prepend) -{ - CFGNode* fromNode = (CFGNode*) _fromNode; - CFGNode* toNode = (CFGNode*) _toNode; - - Inst* to = prepend ? toNode->getFirstInst() : toNode->getLastInst(); - Inst* from = fromNode->getFirstInst(); - - for (Inst *inst = from->next(); inst != from; ) { - Inst *next = inst->next(); - inst->unlink(); - inst->insertAfter(to); - to = inst; - assert(prepend || to == toNode->getLastInst()); - inst = next; + void setMapping(Node *node, Node *to) { + insert(node,to); } -} - -void -FlowGraph::_removeBranchInstruction(ControlFlowNode* _source) -{ - CFGNode* source = (CFGNode*) _source; - - // Remove branch instruction - Inst* last = source->getLastInst(); - assert(last != NULL); - if (last->getOpcode() == Op_Branch || last->isSwitch()) { - last->unlink(); + +protected: + virtual bool keyEquals(Node* key1,Node* key2) const { + return key1 == key2; } -} - -void -FlowGraph::_updateBranchInstruction(ControlFlowNode* _source, ControlFlowNode* _oldTarget, ControlFlowNode* _newTarget) -{ - CFGNode* source = (CFGNode*) _source; - CFGNode* oldTarget = (CFGNode*) _oldTarget; - CFGNode* newTarget = (CFGNode*) _newTarget; - assert(oldTarget->getKind() == newTarget->getKind()); - - LabelInst* oldLabel = oldTarget->getLabel(); - LabelInst* newLabel = newTarget->getLabel(); - - // Update source nodes branch instruction - Inst* last = source->getLastInst(); - assert(last != NULL); - if (last->getOpcode() == Op_Branch) { - BranchInst* br = (BranchInst*)last; - if(br->getTargetLabel() == oldLabel) { - assert(newTarget->isBlockNode()); - br->replaceTargetLabel(newLabel); - } + virtual uint32 getKeyHashCode(Node* key) const { + // return hash of address bits + return ((uint32)(((POINTER_SIZE_INT)key) >> sizeof(void*))); } - else if (last->isSwitch()) { - SwitchInst* sw = (SwitchInst *)last; - if (sw->getDefaultTarget() == oldLabel) { - assert(newTarget->isBlockNode()); - sw->replaceDefaultTargetLabel(newLabel); - } - uint32 n = sw->getNumTargets(); - for (uint32 i = 0; i < n; i++) { - if (sw->getTarget(i) == oldLabel) { - assert(newTarget->isBlockNode()); - sw->replaceTargetLabel(i, newLabel); - } - } - } -} - - -// Splice a new empty block on the CFG edge. -CFGNode* FlowGraph::spliceBlockOnEdge(CFGEdge* edge) -{ - CFGNode* source = edge->getSourceNode(); - double edgeProb = edge->getEdgeProb(); - double edgeFreq = source->getFreq()*edgeProb; - - // Split the edge - CFGNode* split = (CFGNode*) splitEdge(edge); - split->setFreq(edgeFreq); - - // Set the incoming edge probability - assert(split->getInDegree() == 1); - split->getInEdges().front()->setEdgeProb(edgeProb); - - // Set the outgoing edge probability - assert(split->getOutDegree() == 1); - split->getOutEdges().front()->setEdgeProb(1.0); - - return split; -} - - -CFGEdge* -FlowGraph::addEdge(CFGNode* source, CFGNode* target) -{ - CFGEdge* edge = (CFGEdge*) source->findTarget(target); - if(edge == NULL) { - edge = new (memManager) CFGEdge; - ControlFlowGraph::addEdge(source, target, edge); - } - return edge; -} - -CFGEdge* -FlowGraph::replaceEdgeTarget(ControlFlowEdge* _edge, ControlFlowNode* newTarget) -{ - CFGEdge* edge = (CFGEdge*) _edge; - double prob = edge->getEdgeProb(); - CFGEdge* newEdge = (CFGEdge*) ControlFlowGraph::replaceEdgeTarget(edge, newTarget); - newEdge->setEdgeProb(prob); - return newEdge; -} +}; void -FlowGraph::foldBranch(CFGNode* block, BranchInst* br, bool isTaken) +FlowGraph::foldBranch(ControlFlowGraph& fg, Node* block, BranchInst* br, bool isTaken) { assert(br == block->getLastInst()); assert(block->getOutDegree() == 2); - if(isTaken) - removeEdge(block->getFalseEdge()); - else - removeEdge(block->getTrueEdge()); + fg.removeEdge(block->getOutEdge(isTaken ? Edge::Kind_False : Edge::Kind_True)); br->unlink(); } void -FlowGraph::foldSwitch(CFGNode* block, SwitchInst* sw, uint32 index) +FlowGraph::foldSwitch(ControlFlowGraph& fg, Node* block, SwitchInst* sw, uint32 index) { assert(sw == block->getLastInst()); LabelInst* target; @@ -328,457 +83,73 @@ FlowGraph::foldSwitch(CFGNode* block, Sw else target = sw->getDefaultTarget(); - CFGEdgeDeque::const_iterator i; - for(i = block->getOutEdges().begin(); i != block->getOutEdges().end();) { - CFGEdge* edge = *i; - ++i; - if(edge->getTargetNode()->getLabel() != target) - removeEdge(edge); + while (!block->getOutEdges().empty()) { + fg.removeEdge(block->getOutEdges().back()); } - assert(block->getOutDegree() == 1); sw->unlink(); + fg.addEdge(block, target->getNode(), 1.0); } + void -FlowGraph::eliminateCheck(CFGNode* block, Inst* check, bool alwaysThrows) +FlowGraph::eliminateCheck(ControlFlowGraph& fg, Node* block, Inst* check, bool alwaysThrows) { - assert(check == block->getLastInst() && - check->getOperation().canThrow()); - + assert(check == (Inst*)block->getLastInst() && check->getOperation().canThrow()); + Edge* edge = NULL; if (alwaysThrows) { #ifndef NDEBUG - Inst *prevInst = check->prev(); + Inst *prevInst = check->getPrevInst(); assert(prevInst->isThrow()); #endif - ControlFlowGraph::Edge* edge = block->getUnconditionalEdge(); - assert(edge != NULL); - removeEdge(edge); + edge = block->getUnconditionalEdge(); } else { - ControlFlowGraph::Edge* edge = block->getExceptionEdge(); - assert(edge != NULL); - removeEdge(edge); + edge = block->getExceptionEdge(); } - + assert(edge != NULL); + fg.removeEdge(edge); check->unlink(); } -// -// prints a readable version of the node information -// -void CFGNode::printLabel(::std::ostream& cout) { - LabelInst *first = (LabelInst*)getFirstInst(); - if (isBasicBlock()) { - if(getInDegree() == 0) - cout << "ENTRY"; - else if(getOutDegree() == 1 && getOutEdges().front()->getTargetNode()->isExitNode()) - cout << "RETURN"; - else - first->printId(cout); - } else if (isDispatchNode()) { - if(getOutDegree() == 1 && getOutEdges().front()->getTargetNode()->isExitNode()) - cout << "UNWIND"; - else - cout << "D" << (int32)first->getLabelId(); - } else { - cout << "EXIT"; - } -} - -// -// print instructions of a basic block -// - -void CFGNode::printInsts(::std::ostream& cout, uint32 indent) { - assert(insts != NULL); - ::std::string indentstr(indent, ' '); - Inst* inst = insts; - do { - cout << indentstr.c_str(); - inst->print(cout); - cout << ::std::endl; - inst = inst->next(); - } while (inst != insts); - - // The IR does not contain explicit GOTOs, so for IR printing purposes - // we should print a GOTO if required, extracted from the CFG. - inst = getLastInst(); - if (!inst->isReturn() && !inst->isLeave() && - !inst->isThrow() && - !inst->isEndFinally() && !inst->isRet()) { - CFGNode *target = NULL; - if (inst->isConditionalBranch()) { - target = ((BranchInst*)inst)->getTakenEdge(FALSE)->getTargetNode(); - } else { - CFGEdgeDeque::const_iterator - j = getOutEdges().begin(), - jend = getOutEdges().end(); - for (; j != jend; ++j) { - CFGEdge* edge = *j; - CFGNode *node = edge->getTargetNode(); - if (!node->isDispatchNode()) { - target = node; - break; - } - } - } - if (target != NULL) { - cout << indentstr.c_str() << "GOTO "; - target->printLabel(cout); - cout << ::std::endl; - } - } -} - - -// -// Print the profile information of a basic block -// -void -CFGNode::printProfile(::std::ostream& cout) -{ - char str[16]; - - sprintf(str, "%u", getId()); - cout << ::std::endl - << "// Node " << str << " : " << " Freq " << freq; - - if ( getOutEdges().size() > 0 ) { - cout << ", Target Taken Probability : "; - CFGEdgeDeque::const_iterator j = getOutEdges().begin(); - CFGEdgeDeque::const_iterator jend = getOutEdges().end(); - for (; j != jend; ++j) { - CFGEdge* edge = *j; - CFGNode *node = edge->getTargetNode(); - sprintf(str, "%u", node->getId()); - cout << " N" << str << " (" << edge->getEdgeProb() << ")"; - } - } - cout << ::std::endl; -} - - -void FlowGraph::printInsts(::std::ostream& cout, MethodDesc& methodDesc, CFGNode::Annotator* annotator) { - const char* methodName = methodDesc.getName(); - cout << ::std::endl - << "-------- irDump: " - << methodDesc.getParentType()->getName() - << "::" << methodName << " --------" << ::std::endl; - print(cout, annotator); -} +Node* +FlowGraph::tailDuplicate(IRManager& irm, Node* pred, Node* tail, DefUseBuilder& defUses) { + MemoryManager mm(1024,"FlowGraph::tailDuplicate.mm"); + ControlFlowGraph& fg = irm.getFlowGraph(); -/******* collection of utilities to duplicate basic blocks, inline, etc... ***/ + // Set region containing only node. + StlBitVector region(mm, fg.getMaxNodeId()*2); + region.setBit(tail->getId()); + // Make copy. + Node* copy = duplicateRegion(irm, tail, region, defUses); -// Renumber all labels in byte code order after inlining. -void FlowGraph::renumberLabels() { - uint32 labelId = 0x7fffffff; - CFGNodeDeque::const_iterator i; - for(i = getNodes().begin(); i != getNodes().end(); ++i) { - CFGNode* node = *i; - LabelInst *label = (LabelInst*)node->getFirstInst(); - uint32 n = label->getLabelId(); - if (n < labelId) - labelId = n; - } - - for(i = getNodes().begin(); i != getNodes().end(); ++i) { - CFGNode* node = *i; - LabelInst *label = (LabelInst*)node->getFirstInst(); - label->setLabelId(labelId++); - } -} - -void FlowGraph::cleanupPhase() { - static Timer * cleanupPhaseTimer=NULL; - PhaseTimer tm(cleanupPhaseTimer, "ptra::fg::cleanupPhase"); - purgeUnreachableNodes(); - inlineJSRs(); - renumberLabels(); - - { - static Timer * cleanupPhaseInternalTimer=NULL; - PhaseTimer tm(cleanupPhaseInternalTimer, "ptra::fg::cleanupPhase::in"); - // Cleanup optimizations - CFGNodeDeque::const_iterator niter; - niter = getNodes().begin(); - while(niter != getNodes().end()) { - CFGNode* node = *niter; - ++niter; - if (node->isDispatchNode() || node == getReturn() || node == getExit()) { - continue; - } - Inst *last = node->getLastInst(); - if (last->getOpcode() == Op_TauMonitorExit) { - // Check for monitor exit loop. - breakMonitorExitLoop(node, last); - } - else if (last->isBranch()) { - if (last->isLeave()) { - // Inline Finally - only necessary after translation - inlineFinally(node); - renumberLabels(); - } else if (last->isConditionalBranch()) { // loop peeling for conditional branches - CFGNode *target = ((BranchInst*)last)->getTargetLabel()->getCFGNode(); - if (target->getLabelId() > node->getLabelId()) { - LabelInst *targetLabel = ((BranchInst*)last)->getTargetLabel(); - CFGNode *fthru = NULL, *taken = NULL; - const CFGEdgeDeque& outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eIter; - for(eIter = outEdges.begin(); eIter != outEdges.end(); ++eIter) { - CFGEdge* edge = *eIter; - CFGNode * tar = edge->getTargetNode(); - if (!tar->isDispatchNode()) { - if (tar->getFirstInst() == targetLabel) { - taken = tar; - } else { - fthru = tar; - } - } - } - Inst *takenLdConst = taken->getFirstInst()->next(); - Inst *fthruLdConst = fthru->getFirstInst()->next(); - Inst *takenStVar = takenLdConst->next(); - Inst *fthruStVar = fthruLdConst->next(); - if (taken->hasOnlyOneSuccEdge() && - taken->hasOnlyOnePredEdge() && - fthru->hasOnlyOneSuccEdge() && - fthru->hasOnlyOnePredEdge() && - (taken->getOutEdges().front()->getTargetNode() == - fthru->getOutEdges().front()->getTargetNode()) && - takenLdConst->getOpcode() == Op_LdConstant && - fthruLdConst->getOpcode() == Op_LdConstant && - takenLdConst->getType() == Type::Int32 && - fthruLdConst->getType() == Type::Int32 && - takenStVar->getOpcode() == Op_StVar && - fthruStVar->getOpcode() == Op_StVar && - takenStVar->getDst() == fthruStVar->getDst() && - takenStVar->next()->getOpcode() == Op_Label && - fthruStVar->next()->getOpcode() == Op_Label) { - - int takenint32 = ((ConstInst*)takenLdConst)->getValue().i4; - int fthruint32 = ((ConstInst*)fthruLdConst)->getValue().i4; - CFGNode *meet = taken->getOutEdges().front()->getTargetNode(); - // find the ldVar for the variable, if any - Inst *meetLdVar = meet->getFirstInst()->next(); - while (meetLdVar->getOpcode()==Op_LdVar) { - if (meetLdVar->getSrc(0) == takenStVar->getDst()) - break; - meetLdVar = meetLdVar->next(); - } - if ((((takenint32==0) && (fthruint32==1)) || - ((takenint32==1) && (fthruint32==0))) && - meetLdVar->getOpcode()==Op_LdVar && - last->getNumSrcOperands()==2) { - // change the instruction to reflect the compare instruction - removeEdge(node,taken); - removeEdge(node,fthru); - addEdge(node,meet); - Opnd* dst = opndManager.createSsaTmpOpnd(meetLdVar->getDst()->getType()); - BranchInst *lastBranch = (BranchInst*)last; - if (takenint32==0) - lastBranch->swapTargets(NULL); - Inst *cmp = instFactory.makeCmp( - lastBranch->getComparisonModifier(), - lastBranch->getType(), dst, - lastBranch->getSrc(0), - lastBranch->getSrc(1)); - cmp->insertBefore(lastBranch); - Inst* newStVar = instFactory.makeStVar(meetLdVar->getSrc(0)->asVarOpnd(), - dst); - newStVar->insertBefore(lastBranch); - lastBranch->unlink(); - } - } - } - } - } - // remove trivial basic blocks - if (node->hasOnlyOnePredEdge()) { - CFGNode *pred = node->getInEdges().front()->getSourceNode(); - if (!pred->isDispatchNode() && !pred->getLastInst()->isSwitch() && - (pred->hasOnlyOneSuccEdge() || - (node->isEmpty() && node->hasOnlyOneSuccEdge()))) { - - // don't merge if the node has an exception edge - CFGEdge *edge = NULL; - CFGEdgeDeque::const_iterator eiter; - for(eiter = node->getOutEdges().begin(); eiter != node->getOutEdges().end(); ++eiter) { - edge = *eiter; - if ((edge->getTargetNode())->isDispatchNode()) { - break; - } - } - // If the node has an exception edge, then merging is potentially illegal, so - // skip. - if (edge == NULL) { - if (Log::cat_opt()->isDebugEnabled()) { - Log::out()<<" MERGE ";pred->printLabel(Log::out());node->printLabel(Log::out());Log::out()<<"\n"; - Log::out().flush(); - } - BranchInst *branch = NULL; - if (!pred->hasOnlyOneSuccEdge() && node->isEmpty()) { - Inst* lastPred = pred->getLastInst(); - CFGNode* nodeSucc = node->getOutEdges().front()->getTargetNode(); - if (lastPred->isBranch()) { - branch = (BranchInst*)lastPred; - if (branch->getTargetLabel() == node->getFirstInst()) { - branch->replaceTargetLabel((LabelInst*)nodeSucc->getFirstInst()); - } - } - } - mergeWithSingleSuccessor(pred,node); - - - // remove useless branches - if (branch != NULL) { - CFGNode *target = NULL; - for(eiter=pred->getOutEdges().begin(); eiter!=pred->getOutEdges().end();) { - CFGEdge* edge = *eiter; - ++eiter; - CFGNode *succ = edge->getTargetNode(); - if (! succ->isDispatchNode()) { - if (target == succ) { - removeEdge(pred,succ); - branch->unlink(); - break; - } - target = succ; - } - } - } - } - } - } - } - } - // - // a quick cleanup of unreachable and empty basic blocks - // - purgeUnreachableNodes(); - purgeEmptyNodes(false); -} - -void -FlowGraph::breakMonitorExitLoop(CFGNode* node, Inst* monExit) { - - // Look for the following type of loop where a handler with a - // monitorexit handles itself. - // D1: - // - // B1: - // t1 = catch - // ... - // - // B2: - // monitorExit t2 ---> D1 - assert(node->getLastInst() == monExit); - assert(monExit->getOpcode() == Op_TauMonitorExit); - - CFGNode* dispatch = (CFGNode*) node->getExceptionEdge()->getTargetNode(); - CFGNode* catchBlock = node; - ::std::vector<CFGEdge*> exceptionEdges; - exceptionEdges.push_back((CFGEdge*) node->getExceptionEdge()); - - // Look for a catchBlock that dominates the node. Assume no control flow. - while(!catchBlock->getFirstInst()->isCatchLabel() && catchBlock->getInEdges().size() == 1) { - catchBlock = catchBlock->getInEdges().front()->getSourceNode(); - CFGEdge* exceptionEdge = (CFGEdge*) catchBlock->getExceptionEdge(); - if(exceptionEdge == NULL || exceptionEdge->getTargetNode() != dispatch) - return; - exceptionEdges.push_back(exceptionEdge); - } - - if(catchBlock->getFirstInst()->isCatchLabel()) { - // We are in a catch. - if(dispatch->findTarget(catchBlock)) { - // We have a cycle! - CFGNode* newDispatch = (CFGNode*) dispatch->getExceptionEdge()->getTargetNode(); - assert(newDispatch != NULL); - - ::std::vector<CFGEdge*>::iterator i; - for(i = exceptionEdges.begin(); i != exceptionEdges.end(); ++i) { - CFGEdge* exceptionEdge = *i; - assert(exceptionEdge->getTargetNode() == dispatch); - replaceEdgeTarget(exceptionEdge, newDispatch); - } - } - } -} - -void -FlowGraph::spliceFlowGraphInline(CFGNode* callNode, Inst* call, FlowGraph& inlineFG) { - assert(callNode->getLastInst() == call); - CFGNode* nextNode = (CFGNode*) callNode->getUnconditionalEdge()->getTargetNode(); - CFGNode* dispatchNode = (CFGNode*) callNode->getExceptionEdge()->getTargetNode(); - - // Unlink call. - call->unlink(); - removeEdge(callNode->getUnconditionalEdge()); - removeEdge(callNode->getExceptionEdge()); - - // Splice inlineFG into this CFG. - - // Need to renumber the edge id from the inlined CFG so that the edge - // profiler can work properly. - - // Add nodes to CFG - CFGNode* entryNode = inlineFG.getEntry(); - CFGNode* returnNode = inlineFG.getReturn(); - CFGNode* unwindNode = inlineFG.getUnwind(); - CFGNode* exitNode = inlineFG.getExit(); - - bool returnSeen = false; - bool unwindSeen = false; - - const CFGNodeDeque& nodes = inlineFG.getNodes(); - CFGNodeDeque::const_iterator i; - for(i = nodes.begin(); i != nodes.end(); ++i) { - if(*i != exitNode) { - addNode(*i); - const CFGEdgeDeque& oEdges = (*i)->getOutEdges(); - CFGEdgeDeque::const_iterator e; - for(e = oEdges.begin(); e != oEdges.end(); ++e) { - setNewEdgeId(*e); - } - } - if(*i == returnNode) - returnSeen = true; - if(*i == unwindNode) - unwindSeen = true; + // Specialize for pred. + Edge* edge = fg.replaceEdgeTarget(pred->findTargetEdge(tail), copy); + copy->setExecCount(pred->getExecCount()*edge->getEdgeProb()); + if(copy->getExecCount() < tail->getExecCount()) { + tail->setExecCount(tail->getExecCount() - copy->getExecCount()); + } else { + tail->setExecCount(0); } - - // Connect nodes. - addEdge(callNode, entryNode)->setEdgeProb(1); - if(returnSeen) { - removeEdge(returnNode, exitNode); - addEdge(returnNode, nextNode)->setEdgeProb(1); - } - if(unwindSeen) { - removeEdge(unwindNode, exitNode); - addEdge(unwindNode, dispatchNode)->setEdgeProb(1); - } + return copy; } - -// -// the following utility will inline a very small basic block, for the time being targeted -// only at 'finally' basic blocks. -// -CFGNode * FlowGraph::duplicateCFGNode(CFGNode *source, - CFGNode *before, - OpndRenameTable *renameTable) { - CFGNode *newblock; - Inst *first = source->getFirstInst(); - if(Log::cat_opt()->isDebugEnabled()) { - first->print(Log::out()); Log::out() << ::std::endl; +static Node* duplicateNode(IRManager& irm, Node *source, Node *before, OpndRenameTable *renameTable) { + Node *newblock; + LabelInst *first = (LabelInst*)source->getFirstInst(); + if(Log::isEnabled()) { + first->print(Log::out()); Log::out() << std::endl; } + InstFactory& instFactory = irm.getInstFactory(); + OpndManager& opndManager = irm.getOpndManager(); + ControlFlowGraph& fg = irm.getFlowGraph(); LabelInst* l = (LabelInst*)instFactory.clone(first,opndManager,renameTable); - newblock = duplicateBlockAfter(l,before,source); + newblock = fg.createNode(source->getKind(), l); + l->setState(first->getState()); // go throw the 'entry' instructions and duplicate them (renaming whenever possible) - for (Inst *inst = first->next(); inst != first; inst = inst->next()) { - if(Log::cat_opt()->isDebugEnabled()) { + for (Inst *inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + if(Log::isEnabled()) { Log::out() << "DUPLICATE "; Log::out().flush(); inst->print(Log::out()); Log::out() << "\n"; @@ -786,8 +157,8 @@ CFGNode * FlowGraph::duplicateCFGNode(CF } Inst* newInst = instFactory.clone(inst,opndManager,renameTable); - newblock->append(newInst); - if(Log::cat_opt()->isDebugEnabled()) { + newblock->appendInst(newInst); + if(Log::isEnabled()) { Log::out() << " "; Log::out() << (int32)inst->getNumSrcOperands(); Log::out() << " " << (int32)inst->getOpcode() << " "; @@ -799,265 +170,40 @@ CFGNode * FlowGraph::duplicateCFGNode(CF return newblock; } -void FlowGraph::renameOperandsInNode(CFGNode *node, OpndRenameTable *renameTable) { - Inst *first = node->getFirstInst(); - for (Inst *inst = first->next(); inst != first; inst = inst->next()) { - uint32 n = inst->getNumSrcOperands(); - for(uint32 i = 0; i < n; ++i) { - Opnd* src = inst->getSrc(i); - Opnd* newsrc = renameTable->getMapping(src); - if(newsrc != NULL) - inst->setSrc(i, newsrc); - } - } -} - -// this utility is used to merge with a single successor node, thus eliminating the successor basic block - -void FlowGraph::mergeWithSingleSuccessor(CFGNode *pred, CFGNode *succ) { - mergeNodes(pred,succ); -} - - -// this utility splits a node at a particular instruction, leaving the instruction in the -// same basic block, and the successor instructions in the newly created node. -// returns the next node after the split instruction - -CFGNode *FlowGraph::splitNodeAtInstruction(Inst *inst) { - CFGNode *nextNode; - CFGNode *node = inst->getNode(); - if (inst == node->getLastInst()) { - assert(node->hasOnlyOneSuccEdge()); - nextNode = (CFGNode*) splitNode(node, true); - } else { - nextNode = (CFGNode*) splitNode(node, true); - // now move the instructions - for (Inst *ins = inst->next(); ins != node->getFirstInst(); ) { - Inst *nextins = ins->next(); - nextNode->append(ins); - ins = nextins; - } - } - nextNode->setFreq(node->getFreq()); - ((CFGEdge*) node->findTarget(nextNode))->setEdgeProb(1.0); - return nextNode; -} - -// Create a new block node in between the return node and its predecessors. - -CFGNode *FlowGraph::splitReturnNode() { - return (CFGNode*) splitNode(getReturn(), false); -} - -void FlowGraph::_fixBranchTargets(Inst *newInst, CFGNodeRenameTable *nodeRenameTable) { - // fix targets of instructions - switch(newInst->getOpcode()) { - case Op_Branch: - case Op_JSR: - case Op_Jump: - { - BranchInst *newBranch = (BranchInst*)newInst; - CFGNode *tar = newBranch->getTargetLabel()->getCFGNode(); - if(nodeRenameTable->getMapping(tar) != NULL) { - LabelInst *label = (LabelInst*)nodeRenameTable->getMapping(tar)->getFirstInst(); - newBranch->replaceTargetLabel(label); - } - } - break; - case Op_Switch: - assert(0); - default: - break; - } -} - - -// Finally inlining - -bool FlowGraph::_inlineFinally(CFGNode *from, CFGNode *to, CFGNode *retTarget, void *info, - CFGNodeRenameTable *nodeRenameTable, - OpndRenameTable *opndRenameTable) { - // if the node has been visited, return - if (nodeRenameTable->getMapping(from) != NULL) return TRUE; - - // if the node is epilogue, add and edge to it - if (to == getReturn() || to->getInfo() != info) { - addEdge(from,to); - return true; - } - CFGNode *newto = nodeRenameTable->getMapping(to); - if (newto != NULL) { - addEdge(from,newto); - return true; - } - // start following the control flow graph, duplicating basic blocks as needed - newto = duplicateCFGNode(to, to, opndRenameTable); - addEdge(from,newto); - nodeRenameTable->setMapping(to,newto); - if (to->getLastInst()->isEndFinally()) { - // remove the duplicate 'end finally' - Inst *endInst = newto->getLastInst(); - endInst->unlink(); - // add edge from the new node to the target - addEdge(newto,retTarget); - } else { - Log::cat_opt()->debug << "LONG FINALLY\n"; - - const CFGEdgeDeque& outEdges = to->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - _inlineFinally(newto,edge->getTargetNode(),retTarget,info, - nodeRenameTable,opndRenameTable); - } - _fixBranchTargets(newto->getLastInst(),nodeRenameTable); - } - return true; -} - - -bool FlowGraph::inlineFinally(CFGNode *block) { - BranchInst* leaveInst = (BranchInst*)block->getLastInst(); - CFGNode * retTarget = leaveInst->getTargetLabel()->getCFGNode(); - // record input operand - CFGNode * entryFinally = NULL; - const CFGEdgeDeque& outEdges = block->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - CFGNode *node = edge->getTargetNode(); - if (node != retTarget && !node->isDispatchNode()) { - entryFinally = node; - break; - } - } - if (Log::cat_opt()->isDebugEnabled()) { - Log::out() << "INLINE FINALLY\n"; - entryFinally->printLabel(Log::out()); - retTarget->printLabel(Log::out()); - Log::out() << ::std::endl; - Log::out().flush(); - } - if (entryFinally->hasOnlyOnePredEdge()) { - setTraversalNum(getTraversalNum()+1); - removeEdge(block,retTarget); - _fixFinally(entryFinally,retTarget); - } else { - MemoryManager inlineManager(0,"FlowGraph::inlineFinally.inlineManager"); - // prepare the hashtable for the operand rename translation - OpndRenameTable *opndRenameTable = - new (inlineManager) OpndRenameTable(inlineManager,10); - CFGNodeRenameTable *nodeRenameTable = - new (inlineManager) CFGNodeRenameTable(inlineManager,10); - removeEdge(block,retTarget); - removeEdge(block,entryFinally); - _inlineFinally(block,entryFinally,retTarget,entryFinally->getInfo(), - nodeRenameTable,opndRenameTable ); - } - leaveInst->unlink(); - return TRUE; -} - - -// Finally inlining - -void FlowGraph::_fixFinally(CFGNode *node, CFGNode *retTarget) { - // if the node has been visited, return - if (node->getTraversalNum() >= getTraversalNum()) return; - node->setTraversalNum(getTraversalNum()); - Inst *last = node->getLastInst(); - if (last->isEndFinally()) { - // remove the 'ret' instruction - last->unlink(); - // add edge from the new node to the target - addEdge(node,retTarget); - } else { - const CFGEdgeDeque& outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - _fixFinally(edge->getTargetNode(),retTarget); - } - } -} - -void -FlowGraph::findNodesInRegion(CFGNode* entry, CFGNode* end, StlBitVector& nodesInRegion) { - if(Log::cat_opt()->isDebugEnabled()) { - Log::out() << "Find nodes in region (entry = "; - entry->printLabel(Log::out()); - Log::out() << ", exit = "; - end->printLabel(Log::out()); - Log::out() << ")" << ::std::endl; - } - - // Return if visited and mark. - if(nodesInRegion.setBit(end->getId())) - return; - - if(end != entry) { - const CFGEdgeDeque& inEdges = end->getInEdges(); - // Must not be method entry. - assert(!inEdges.empty()); - CFGEdgeDeque::const_iterator eiter; - for(eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - findNodesInRegion(entry, edge->getSourceNode(), nodesInRegion); - } +static Node* duplicateNode(IRManager& irm, Node *node, StlBitVector* nodesInRegion, + DefUseBuilder* defUses, OpndRenameTable* opndRenameTable) +{ + if(Log::isEnabled()) { + Log::out() << "DUPLICATE NODE " << std::endl; + FlowGraph::print(Log::out(), node); } - - assert(nodesInRegion.getBit(entry->getId())); -} -CFGNode* -FlowGraph::tailDuplicate(CFGNode* pred, CFGNode* tail, DefUseBuilder& defUses) { - MemoryManager mm(0,"FlowGraph::tailDuplicate.mm"); - - // Set region containing only node. - StlBitVector region(mm, getMaxNodeId()*2); - region.setBit(tail->getId()); - - // Make copy. - CFGNode* copy = duplicateRegion(tail, region, defUses); - - // Specialize for pred. - CFGEdge* edge = (CFGEdge*) replaceEdgeTarget(pred->findTarget(tail), copy); - copy->setFreq(pred->getFreq()*edge->getEdgeProb()); - if(copy->getFreq() < tail->getFreq()) - tail->setFreq(tail->getFreq() - copy->getFreq()); - else - tail->setFreq(0); - return copy; -} - -CFGNode* -FlowGraph::duplicateCFGNode(CFGNode *node, StlBitVector* nodesInRegion, DefUseBuilder* defUses, OpndRenameTable* opndRenameTable) { - if(Log::cat_opt()->isDebugEnabled()) { - Log::out() << "DUPLICATE NODE " << ::std::endl; - node->print(Log::out()); - } + InstFactory& instFactory = irm.getInstFactory(); + OpndManager& opndManager = irm.getOpndManager(); + ControlFlowGraph& fg = irm.getFlowGraph(); - CFGNode *newNode; - Inst *first = node->getFirstInst(); + Node *newNode; + LabelInst *first = (LabelInst*)node->getFirstInst(); LabelInst* l = (LabelInst*)instFactory.clone(first,opndManager,opndRenameTable); - newNode = duplicateBlockAfter(l,NULL,node); + newNode = fg.createNode(node->getKind(), l); + l->setState(first->getState()); // Copy edges - const CFGEdgeDeque& outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& outEdges = node->getOutEdges(); + Edges::const_iterator eiter; for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - CFGNode* succ = edge->getTargetNode(); - CFGEdge* newEdge = addEdge(newNode, succ); + Edge* edge = *eiter; + Node* succ = edge->getTargetNode(); + Edge* newEdge = fg.addEdge(newNode, succ); newEdge->setEdgeProb(edge->getEdgeProb()); } - CFGNode* stBlock = NULL; + Node* stBlock = NULL; // go throw the 'entry' instructions and duplicate them (renaming whenever possible) - for (Inst *inst = first->next(); inst != first; inst = inst->next()) { - if(Log::cat_opt()->isDebugEnabled()) { + for (Inst *inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + if(Log::isEnabled()) { Log::out() << "DUPLICATE "; Log::out().flush(); inst->print(Log::out()); Log::out() << "\n"; @@ -1076,25 +222,25 @@ FlowGraph::duplicateCFGNode(CFGNode *nod DefUseLink* duLink = defUses->getDefUseLinks(inst); for(; duLink != NULL; duLink = duLink->getNext()) { Inst* useInst = duLink->getUseInst(); - if(Log::cat_opt()->isDebugEnabled()) { - Log::out() << "Examine use: "; - useInst->print(Log::out()); - Log::out() << ::std::endl; - } - CFGNode* useNode = useInst->getNode(); + if(Log::isEnabled()) { + Log::out() << "Examine use: "; + useInst->print(Log::out()); + Log::out() << std::endl; + } + Node* useNode = useInst->getNode(); assert(useNode != NULL); if(!nodesInRegion->getBit(useNode->getId())) { // // Need to promote dst. // - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Patch use: "; useInst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Inst* patchdef = NULL; if(ci != NULL) { - MemoryManager mm(0,"FlowGraph::duplicateCFGNode.mm"); + MemoryManager mm(0,"FlowGraph::duplicateNode.mm"); OpndRenameTable table(mm,1); patchdef = instFactory.clone(ci, opndManager, &table)->asConstInst(); assert(patchdef != NULL); @@ -1103,14 +249,14 @@ FlowGraph::duplicateCFGNode(CFGNode *nod var = opndManager.createVarOpnd(dst->getType(), false); Inst* stVar = instFactory.makeStVar(var, dst); if(inst->getOperation().canThrow()) { - stBlock = createBlockNode(); - stBlock->append(stVar); - CFGNode* succ = (CFGNode*) node->getUnconditionalEdge()->getTargetNode(); - CFGEdge* succEdge = (CFGEdge*) node->findTarget(succ); - stBlock->setFreq(node->getFreq()*succEdge->getEdgeProb()); - replaceEdgeTarget(succEdge, stBlock); - replaceEdgeTarget(newNode->findTarget(succ), stBlock); - addEdge(stBlock, succ)->setEdgeProb(1.0); + stBlock = fg.createBlockNode(instFactory.makeLabel()); + stBlock->appendInst(stVar); + Node* succ = node->getUnconditionalEdge()->getTargetNode(); + Edge* succEdge = node->findTargetEdge(succ); + stBlock->setExecCount(node->getExecCount()*succEdge->getEdgeProb()); + fg.replaceEdgeTarget(succEdge, stBlock); + fg.replaceEdgeTarget(newNode->findTargetEdge(succ), stBlock); + fg.addEdge(stBlock, succ)->setEdgeProb(1.0); defUses->addUses(stVar); nodesInRegion->resize(stBlock->getId()+1); nodesInRegion->setBit(stBlock->getId()); @@ -1143,35 +289,37 @@ FlowGraph::duplicateCFGNode(CFGNode *nod // Create clone inst, add to new node, and update defuse links. Inst* newInst = instFactory.clone(inst,opndManager,opndRenameTable); - newNode->append(newInst); + newNode->appendInst(newInst); defUses->addUses(newInst); } - if(Log::cat_opt()->isDebugEnabled()) { - newNode->print(Log::out()); - Log::out() << "---------------" << ::std::endl; + if(Log::isEnabled()) { + FlowGraph::print(Log::out(), newNode); + Log::out() << "---------------" << std::endl; } return newNode; } -CFGNode* -FlowGraph::duplicateRegion(CFGNode* node, CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder* defUses, CFGNodeRenameTable* nodeRenameTable, OpndRenameTable* opndRenameTable) { + + +static Node* _duplicateRegion(IRManager& irm, Node* node, Node* entry, StlBitVector& nodesInRegion, DefUseBuilder* defUses, NodeRenameTable* nodeRenameTable, OpndRenameTable* opndRenameTable) { assert(nodesInRegion.getBit(node->getId())); - CFGNode* newNode = nodeRenameTable->getMapping(node); + Node* newNode = nodeRenameTable->getMapping(node); if(newNode != NULL) return newNode; - newNode = duplicateCFGNode(node, &nodesInRegion, defUses, opndRenameTable); + newNode = duplicateNode(irm, node, &nodesInRegion, defUses, opndRenameTable); nodeRenameTable->setMapping(node, newNode); - const CFGEdgeDeque& outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; + ControlFlowGraph& fg = irm.getFlowGraph(); + const Edges& outEdges = node->getOutEdges(); + Edges::const_iterator eiter; for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - CFGNode* succ = edge->getTargetNode(); + Edge* edge = *eiter; + Node* succ = edge->getTargetNode(); if(succ != entry && nodesInRegion.getBit(succ->getId())) { - CFGNode* newSucc = duplicateRegion(succ, entry, nodesInRegion, defUses, nodeRenameTable, opndRenameTable); + Node* newSucc = _duplicateRegion(irm, succ, entry, nodesInRegion, defUses, nodeRenameTable, opndRenameTable); assert(newSucc != NULL); - replaceEdgeTarget(newNode->findTarget(succ), newSucc); + fg.replaceEdgeTarget(newNode->findTargetEdge(succ), newSucc); } } @@ -1179,93 +327,157 @@ FlowGraph::duplicateRegion(CFGNode* node } -CFGNode* -FlowGraph::duplicateRegion(CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, CFGNodeRenameTable& nodeRenameTable, OpndRenameTable& opndRenameTable, double newEntryFreq) { - CFGNode* newEntry = duplicateRegion(entry, entry, nodesInRegion, &defUses, &nodeRenameTable, &opndRenameTable); - if(newEntryFreq == 0) +static Node* _duplicateRegion(IRManager& irm, Node* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, NodeRenameTable& nodeRenameTable, OpndRenameTable& opndRenameTable, double newEntryFreq) { + Node* newEntry = _duplicateRegion(irm, entry, entry, nodesInRegion, &defUses, &nodeRenameTable, &opndRenameTable); + if(newEntryFreq == 0) { return newEntry; - double scale = newEntryFreq / entry->getFreq(); + } + double scale = newEntryFreq / entry->getExecCount(); assert(scale >=0 && scale <= 1); - CFGNodeRenameTable::Iter iter(&nodeRenameTable); - CFGNode* oldNode = NULL; - CFGNode* newNode = NULL; + NodeRenameTable::Iter iter(&nodeRenameTable); + Node* oldNode = NULL; + Node* newNode = NULL; while(iter.getNextElem(oldNode, newNode)) { - newNode->setFreq(oldNode->getFreq()*scale); - oldNode->setFreq(oldNode->getFreq()*(1-scale)); + newNode->setExecCount(oldNode->getExecCount()*scale); + oldNode->setExecCount(oldNode->getExecCount()*(1-scale)); } return newEntry; } - -CFGNode* -FlowGraph::duplicateRegion(CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, double newEntryFreq) { + + +Node* FlowGraph::duplicateRegion(IRManager& irm, Node* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, double newEntryFreq) { MemoryManager dupMemManager(1024, "FlowGraph::duplicateRegion.dupMemManager"); // prepare the hashtable for the operand rename translation - OpndRenameTable *opndRenameTable = - new (dupMemManager) OpndRenameTable(dupMemManager,10); - CFGNodeRenameTable *nodeRenameTable = - new (dupMemManager) CFGNodeRenameTable(dupMemManager,10); + OpndRenameTable *opndRenameTable = new (dupMemManager) OpndRenameTable(dupMemManager,10); + NodeRenameTable *nodeRenameTable = new (dupMemManager) NodeRenameTable(dupMemManager,10); + return _duplicateRegion(irm, entry, nodesInRegion, defUses, *nodeRenameTable, *opndRenameTable, newEntryFreq); +} - return duplicateRegion(entry, nodesInRegion, defUses, *nodeRenameTable, *opndRenameTable, newEntryFreq); +void FlowGraph::renameOperandsInNode(Node *node, OpndRenameTable *renameTable) { + Inst *first = (Inst*)node->getFirstInst(); + for (Inst *inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + uint32 n = inst->getNumSrcOperands(); + for(uint32 i = 0; i < n; ++i) { + Opnd* src = inst->getSrc(i); + Opnd* newsrc = renameTable->getMapping(src); + if(newsrc != NULL) + inst->setSrc(i, newsrc); + } + } } -void -FlowGraph::inlineJSRs() -{ - MemoryManager jsrMemoryManager(0, "FlowGraph::inlineJSRs.jsrMemoryManager"); - static Timer * inlineJSRTimer=NULL; - PhaseTimer tm(inlineJSRTimer, "ptra::fg::inlineJSRs"); - JsrEntryInstToRetInstMap* jsr_entry_map = irManager->getJsrEntryMap(); - assert(jsr_entry_map); // must be set by translator - if(Log::cat_opt()->isDebugEnabled()) { - Log::out() << "JSR entry map:"; - JsrEntryInstToRetInstMap::const_iterator jsr_entry_it, jsr_entry_end; - for ( jsr_entry_it = jsr_entry_map->begin(), - jsr_entry_end = jsr_entry_map->end(); - jsr_entry_it != jsr_entry_end; ++jsr_entry_it) { - Log::out() << "--> [entry->ret]: "; - jsr_entry_it->first->print(Log::out()); - Log::out() << " || "; - jsr_entry_it->second->print(Log::out()); - Log::out() << std::endl; + +static void breakMonitorExitLoop(ControlFlowGraph& fg, Node* node, Inst* monExit) { + + // Look for the following type of loop where a handler with a + // monitorexit handles itself. + // D1: + // + // B1: + // t1 = catch + // ... + // + // B2: + // monitorExit t2 ---> D1 + assert(node->getLastInst() == monExit); + assert(monExit->getOpcode() == Op_TauMonitorExit); + + Node* dispatch = node->getExceptionEdge()->getTargetNode(); + Node* catchBlock = node; + std::vector<Edge*> exceptionEdges; + exceptionEdges.push_back(node->getExceptionEdge()); + + // Look for a catchBlock that dominates the node. Assume no control flow. + while(!((Inst*)catchBlock->getFirstInst())->isCatchLabel() && catchBlock->getInEdges().size() == 1) { + catchBlock = catchBlock->getInEdges().front()->getSourceNode(); + Edge* exceptionEdge = catchBlock->getExceptionEdge(); + if(exceptionEdge == NULL || exceptionEdge->getTargetNode() != dispatch) + return; + exceptionEdges.push_back(exceptionEdge); + } + + if(((Inst*)catchBlock->getFirstInst())->isCatchLabel()) { + // We are in a catch. + if(dispatch->findTargetEdge(catchBlock)) { + // We have a cycle! + Node* newDispatch = dispatch->getExceptionEdge()->getTargetNode(); + assert(newDispatch != NULL); + + std::vector<Edge*>::iterator i; + for(i = exceptionEdges.begin(); i != exceptionEdges.end(); ++i) { + Edge* exceptionEdge = *i; + assert(exceptionEdge->getTargetNode() == dispatch); + fg.replaceEdgeTarget(exceptionEdge, newDispatch); + } } } +} - DefUseBuilder defUses(jsrMemoryManager); - { - static Timer * findJSRTimer=NULL; - PhaseTimer tm(findJSRTimer, "ptra::fg::inlineJSRs::defuse"); - defUses.initialize(*this); - } - - CFGNodeDeque::const_iterator niter2; - niter2 = getNodes().begin(); - while(niter2 != getNodes().end()) { - CFGNode* node = *niter2; - ++niter2; - Inst* last = node->getLastInst(); - if(last->isJSR()) { - inlineJSR(node, defUses, *jsr_entry_map); + + +// +// used to find 'saveret' that starts the node +// 'labelinst' and 'stvar' are skipped +// +static Inst* findSaveRet(Node* node) { + assert(node); + Inst* first = (Inst*)node->getFirstInst(); + assert(first->getOpcode() == Op_Label); + Inst* i; + for ( i = first->getNextInst(); i != NULL; i = i->getNextInst() ) { + Opcode opc = i->getOpcode(); + if ( opc == Op_SaveRet ) { + return i; + }else if ( opc != Op_LdVar ) { + return NULL; } } + return NULL; } +void static findNodesInRegion(Node* entry, Node* end, StlBitVector& nodesInRegion) { + if(Log::isEnabled()) { + Log::out() << "Find nodes in region (entry = "; + FlowGraph::printLabel(Log::out(), entry); + Log::out() << ", exit = "; + FlowGraph::printLabel(Log::out(), end); + Log::out() << ")" << std::endl; + } -bool FlowGraph::inlineJSR(CFGNode *block, DefUseBuilder& defUses, JsrEntryInstToRetInstMap& entryMap) { + // Return if visited and mark. + if(nodesInRegion.setBit(end->getId())) + return; + + if(end != entry) { + const Edges& inEdges = end->getInEdges(); + // Must not be method entry. + assert(!inEdges.empty()); + Edges::const_iterator eiter; + for(eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { + Edge* edge = *eiter; + findNodesInRegion(entry, edge->getSourceNode(), nodesInRegion); + } + } + assert(nodesInRegion.getBit(entry->getId())); +} + + +static bool inlineJSR(IRManager* irManager, Node *block, DefUseBuilder& defUses, JsrEntryInstToRetInstMap& entryMap) { // Inline the JSR call at the end of block. - Inst* last = block->getLastInst(); + Inst* last = (Inst*)block->getLastInst(); assert(last->isJSR()); BranchInst* jsrInst = (BranchInst*) last; // // Process entry of JSR. // - CFGNode* entryJSR = jsrInst->getTargetLabel()->getCFGNode(); + Node* entryJSR = jsrInst->getTargetLabel()->getNode(); Inst *saveReturn = findSaveRet(entryJSR); assert(saveReturn); // 'stvar' should follow 'saveret' (feature of current IRBuilder) - Inst *stVar = saveReturn->next(); + Inst *stVar = saveReturn->getNextInst(); // If retVar is NULL, JSR never returns. Opnd *retVar = NULL; if(stVar->isStVar() && (stVar->getSrc(0) == saveReturn->getDst())) @@ -1274,25 +486,27 @@ bool FlowGraph::inlineJSR(CFGNode *block // // Find return node for this invocation. // - CFGNode* retTarget = NULL; - const CFGEdgeDeque& outEdges = block->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; + Node* retTarget = NULL; + const Edges& outEdges = block->getOutEdges(); + Edges::const_iterator eiter; for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { - CFGEdge* edge = *eiter; - CFGNode *node = edge->getTargetNode(); + Edge* edge = *eiter; + Node *node = edge->getTargetNode(); if (node != entryJSR && !node->isDispatchNode()) { retTarget = node; break; } } - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "INLINE JSR into "; - block->printLabel(Log::out()); - Log::out() << ":" << ::std::endl; - entryJSR->print(Log::out()); + FlowGraph::printLabel(Log::out(), block); + Log::out() << ":" << std::endl; + FlowGraph::print(Log::out(), entryJSR); } + ControlFlowGraph& fg = irManager->getFlowGraph(); + // // entryMap is a mapping [stVar -> ret inst] // @@ -1304,42 +518,42 @@ bool FlowGraph::inlineJSR(CFGNode *block if(retVar != NULL) stVar->unlink(); - const CFGEdgeDeque& inEdges = entryJSR->getInEdges(); + const Edges& inEdges = entryJSR->getInEdges(); for(eiter = inEdges.begin(); eiter != inEdges.end();) { - CFGEdge* edge = *eiter; + Edge* edge = *eiter; ++eiter; - CFGNode *node = edge->getSourceNode(); - Inst* last = node->getLastInst(); + Node *node = edge->getSourceNode(); + Inst* last = (Inst*)node->getLastInst(); assert(last->isJSR()); last->unlink(); assert(node->getOutDegree() == 2); - CFGNode* t1 = node->getOutEdges().front()->getTargetNode(); - CFGNode* t2 = node->getOutEdges().back()->getTargetNode(); + Node* t1 = node->getOutEdges().front()->getTargetNode(); + Node* t2 = node->getOutEdges().back()->getTargetNode(); if(t1 == entryJSR) { - removeEdge(node, t2); + fg.removeEdge(node, t2); } else { assert(t2 == entryJSR); - removeEdge(node, t1); + fg.removeEdge(node, t1); } } } else if (entryJSR->hasOnlyOnePredEdge()) { // // Inline the JSR in place - no duplication needed. // - removeEdge(block,retTarget); + fg.removeEdge(block,retTarget); jsrInst->unlink(); JsrEntryCIterRange jsr_range = entryMap.equal_range(stVar); JsrEntryInstToRetInstMap::const_iterator i; for(i = jsr_range.first; i != jsr_range.second; ++i) { assert(i->first->getNode() == entryJSR); - CFGNode* retNode = i->second->getNode(); - Inst* ret = retNode->getLastInst(); + Node* retNode = i->second->getNode(); + Inst* ret = (Inst*)retNode->getLastInst(); assert(ret->isRet()); assert(ret->getSrc(0) == retVar); ret->unlink(); - addEdge(retNode, retTarget); + fg.addEdge(retNode, retTarget); } } else { // @@ -1348,7 +562,7 @@ bool FlowGraph::inlineJSR(CFGNode *block MemoryManager inlineManager(0,"FlowGraph::inlineJSR.inlineManager"); // Find the nodes in the JSR. - StlBitVector nodesInJSR(inlineManager, getMaxNodeId()); + StlBitVector nodesInJSR(inlineManager, fg.getMaxNodeId()); JsrEntryCIterRange jsr_range = entryMap.equal_range(stVar); JsrEntryInstToRetInstMap::const_iterator i; @@ -1358,28 +572,26 @@ bool FlowGraph::inlineJSR(CFGNode *block } // prepare the hash tables for rename translation - OpndRenameTable *opndRenameTable = - new (inlineManager) OpndRenameTable(inlineManager,10); - CFGNodeRenameTable *nodeRenameTable = - new (inlineManager) CFGNodeRenameTable(inlineManager,10); + OpndRenameTable *opndRenameTable = new (inlineManager) OpndRenameTable(inlineManager,10); + NodeRenameTable *nodeRenameTable = new (inlineManager) NodeRenameTable(inlineManager,10); - CFGNode* newEntry = duplicateRegion(entryJSR, nodesInJSR, defUses, *nodeRenameTable, *opndRenameTable); + Node* newEntry = _duplicateRegion(*irManager, entryJSR, nodesInJSR, defUses, *nodeRenameTable, *opndRenameTable, 0); - removeEdge(block,retTarget); - removeEdge(block,entryJSR); + fg.removeEdge(block,retTarget); + fg.removeEdge(block,entryJSR); jsrInst->unlink(); - addEdge(block, newEntry); + fg.addEdge(block, newEntry); // // Add edge from inline ret locations to return target. // for(i = jsr_range.first; i != jsr_range.second; ++i) { - CFGNode* inlinedRetNode = nodeRenameTable->getMapping((*i).second->getNode()); - Inst* ret = inlinedRetNode->getLastInst(); + Node* inlinedRetNode = nodeRenameTable->getMapping((*i).second->getNode()); + Inst* ret = (Inst*)inlinedRetNode->getLastInst(); assert(ret->isRet()); assert(ret->getSrc(0) == retVar); ret->unlink(); - addEdge(inlinedRetNode, retTarget); + fg.addEdge(inlinedRetNode, retTarget); } // @@ -1388,7 +600,7 @@ bool FlowGraph::inlineJSR(CFGNode *block assert(entryJSR != newEntry); saveReturn = findSaveRet(newEntry); assert(saveReturn); - stVar = saveReturn->next(); + stVar = saveReturn->getNextInst(); assert(stVar->isStVar() && (stVar->getSrc(0) == saveReturn->getDst())); retVar = stVar->getDst(); @@ -1401,262 +613,568 @@ bool FlowGraph::inlineJSR(CFGNode *block return TRUE; } -// -// used to find 'saveret' that starts the node -// 'labelinst' and 'stvar' are skipped -// -Inst* -FlowGraph::findSaveRet(CFGNode* node) -{ - assert(node); - Inst* first = node->getFirstInst(); - assert(first->getOpcode() == Op_Label); - Inst* i; - for ( i = first->next(); i != first; i = i->next() ) { - Opcode opc = i->getOpcode(); - if ( opc == Op_SaveRet ) { - return i; - }else if ( opc != Op_LdVar ) { - return NULL; + +static void inlineJSRs(IRManager* irManager) { + MemoryManager jsrMemoryManager(0, "FlowGraph::inlineJSRs.jsrMemoryManager"); + static CountTime inlineJSRTimer("ptra::fg::inlineJSRs"); + AutoTimer tm(inlineJSRTimer); + + JsrEntryInstToRetInstMap* jsr_entry_map = irManager->getJsrEntryMap(); + assert(jsr_entry_map); // must be set by translator + + if(Log::isEnabled()) { + Log::out() << "JSR entry map:"; + JsrEntryInstToRetInstMap::const_iterator jsr_entry_it, jsr_entry_end; + for ( jsr_entry_it = jsr_entry_map->begin(), + jsr_entry_end = jsr_entry_map->end(); + jsr_entry_it != jsr_entry_end; ++jsr_entry_it) { + Log::out() << "--> [entry->ret]: "; + jsr_entry_it->first->print(Log::out()); + Log::out() << " || "; + jsr_entry_it->second->print(Log::out()); + Log::out() << std::endl; + } + } + + DefUseBuilder defUses(jsrMemoryManager); + { + static CountTime findJSRTimer("ptra::fg::inlineJSRs::defuse"); + AutoTimer tm(findJSRTimer); + defUses.initialize(irManager->getFlowGraph()); + } + + ControlFlowGraph& fg = irManager->getFlowGraph(); + const Nodes& nodes = fg.getNodes(); + //Nodes nodes(jsrMemoryManager); + //fg.getNodesPostOrder(nodes); + //std::reverse(nodes.begin(), nodes.end()); + //WARN: new nodes created during the iteration + //we use the fact that new nodes added to the end of the collection here. + for (uint32 idx = 0; idx < nodes.size(); ++idx) { + Node* node = nodes[idx]; + Inst* last = (Inst*)node->getLastInst(); + if(last->isJSR()) { + inlineJSR(irManager, node, defUses, *jsr_entry_map); } } - return NULL; +#ifdef _DEBUG + const Nodes& nnodes = fg.getNodes(); + for (uint32 idx = 0; idx < nnodes.size(); ++idx) { + Node* node = nnodes[idx]; + Inst* last = (Inst*)node->getLastInst(); + assert(!last->isJSR()); + } +#endif } -void -FlowGraph::smoothProfileInfo() { - if(!hasEdgeProfile()) +// Finally inlining +static void _fixFinally(ControlFlowGraph& fg, Node *node, Node *retTarget) { + // if the node has been visited, return + if (node->getTraversalNum() >= fg.getTraversalNum()) { return; + } + node->setTraversalNum(fg.getTraversalNum()); + Inst *last = (Inst*)node->getLastInst(); + if (last->isEndFinally()) { + // remove the 'ret' instruction + last->unlink(); + // add edge from the new node to the target + fg.addEdge(node,retTarget); + } else { + const Edges& outEdges = node->getOutEdges(); + Edges::const_iterator eiter; + for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { + Edge* edge = *eiter; + _fixFinally(fg, edge->getTargetNode(),retTarget); + } + } +} - MemoryManager mm(sizeof(Node*)*getMaxNodeId(), "FlowGraph::smoothProfileInfo.mm"); - StlVector<CFGNode*> nodes(mm); - getNodesPostOrder(nodes); - StlVector<CFGNode*>::reverse_iterator i; - // - // Walk over all nodes in reverse postorder. For each node, fix outgoing edge - // probabilities so that they approximately add up to one. - // - for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - const CFGEdgeDeque& outEdges = node->getOutEdges(); - if(!outEdges.empty()) { - double total = 0; - double nblock = 0; - CFGEdgeDeque::const_iterator i2; - for(i2 = outEdges.begin(); i2 != outEdges.end(); ++i2) { - CFGEdge* edge = *i2; - if(edge->getTargetNode()->isBlockNode()) - ++nblock; - total += edge->getEdgeProb(); - } - double scale = -1.0; - double value = -1.0; - if(total < 0.01) { - value = 1.0 / nblock; - } else { - scale = 1 / total; - } - assert(scale > 0 || value > 0); - for(i2 = outEdges.begin(); i2 != outEdges.end(); ++i2) { - CFGEdge* edge = *i2; - if(scale >= 0) - edge->setEdgeProb(scale*edge->getEdgeProb()); - else if(edge->getTargetNode()->isBlockNode()) - edge->setEdgeProb(value); - assert(edge->getEdgeProb() >= 0.0 && edge->getEdgeProb() <= 1.0); +static void _fixBranchTargets(Inst *newInst, NodeRenameTable *nodeRenameTable) { + // fix targets of instructions + switch(newInst->getOpcode()) { + case Op_Branch: + case Op_JSR: + case Op_Jump: + { + BranchInst *newBranch = (BranchInst*)newInst; + Node *tar = newBranch->getTargetLabel()->getNode(); + if(nodeRenameTable->getMapping(tar) != NULL) { + LabelInst *label = (LabelInst*)nodeRenameTable->getMapping(tar)->getFirstInst(); + newBranch->replaceTargetLabel(label); } } + break; + case Op_Switch: + assert(0); + default: + break; } +} - // - // Recompute all node frequencies based upon method entry and incoming edge probabilities. - // - for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - if(node != getEntry()) - node->setFreq(0); +// Finally inlining +static bool _inlineFinally(IRManager& irm, Node *from, Node *to, Node *retTarget, + NodeRenameTable *nodeRenameTable, + OpndRenameTable *opndRenameTable) { + // if the node has been visited, return + if (nodeRenameTable->getMapping(from) != NULL) return true; + + ControlFlowGraph& fg = irm.getFlowGraph(); + // if the node is epilogue, add and edge to it + if (to->isExitNode()) { + fg.addEdge(from,to); + return true; + } + Node *newto = nodeRenameTable->getMapping(to); + if (newto != NULL) { + fg.addEdge(from,newto); + return true; } + // start following the control flow graph, duplicating basic blocks as needed + newto = duplicateNode(irm, to, to, opndRenameTable); + fg.addEdge(from,newto); + nodeRenameTable->setMapping(to,newto); + if (((Inst*)to->getLastInst())->isEndFinally()) { + // remove the duplicate 'end finally' + Inst *endInst =(Inst*)newto->getLastInst(); + endInst->unlink(); + // add edge from the new node to the target + fg.addEdge(newto,retTarget); + } else { + Log::out() << "LONG FINALLY\n"; - // - // Iterate until frequencies converge. - // - bool done = false; - while(!done) { - done = true; - for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - const CFGEdgeDeque& inEdges = node->getInEdges(); - if(!inEdges.empty()) { - double oldFreq = node->getFreq(); - double newFreq = 0.0; - CFGEdgeDeque::const_iterator i2; - for(i2 = inEdges.begin(); i2 != inEdges.end(); ++i2) { - CFGEdge* edge = *i2; - CFGNode* pred = edge->getSourceNode(); - newFreq += pred->getFreq() * edge->getEdgeProb(); - } - if(oldFreq - newFreq > 0.05*oldFreq || newFreq - oldFreq > 0.05*oldFreq) { - done = false; - node->setFreq(newFreq); - } - } + const Edges& outEdges = to->getOutEdges(); + Edges::const_iterator eiter; + for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { + Edge* edge = *eiter; + _inlineFinally(irm, newto,edge->getTargetNode(),retTarget,nodeRenameTable,opndRenameTable); } + _fixBranchTargets((Inst*)newto->getLastInst(),nodeRenameTable); } + return true; } -// Check the profile consistency of the FlowGraph. -// Return true if the profile is consistent. Otherwise, return false. -// If warn is set to TRUE, print out warning message to stderr whenever -// inconsistent profile is detected. -bool -FlowGraph::isProfileConsistent(char *methodStr, bool warn) -{ - const CFGNodeDeque& nodes = getNodes(); - CFGEdgeDeque::const_iterator eiter; - CFGNodeDeque::const_iterator niter; - CFGNode *node, *srcNode; - CFGEdge *edge; - double f, diff; - bool consistent = true; - - // Always return TRUE if the FlowGraph doesn't have edge profile. - if(!hasEdgeProfile()) - return true; - if (warn) { - ::std::cerr << "Check profile consistent : " << methodStr << ::std::endl; +static bool inlineFinally(IRManager& irm, Node *block) { + ControlFlowGraph& fg = irm.getFlowGraph(); + BranchInst* leaveInst = (BranchInst*)block->getLastInst(); + Node * retTarget = leaveInst->getTargetLabel()->getNode(); + // record input operand + Node * entryFinally = NULL; + const Edges& outEdges = block->getOutEdges(); + Edges::const_iterator eiter; + for(eiter = outEdges.begin(); eiter != outEdges.end(); ++eiter) { + Edge* edge = *eiter; + Node *node = edge->getTargetNode(); + if (node != retTarget && !node->isDispatchNode()) { + entryFinally = node; + break; + } + } + if (Log::isEnabled()) { + Log::out() << "INLINE FINALLY\n"; + FlowGraph::printLabel(Log::out(), entryFinally); + FlowGraph::printLabel(Log::out(), retTarget); + Log::out() << std::endl; + Log::out().flush(); } + if (entryFinally->hasOnlyOnePredEdge()) { + fg.setTraversalNum(fg.getTraversalNum()+1); + fg.removeEdge(block,retTarget); + _fixFinally(fg, entryFinally,retTarget); + } else { + MemoryManager inlineManager(0,"FlowGraph::inlineFinally.inlineManager"); + // prepare the hashtable for the operand rename translation + OpndRenameTable *opndRenameTable = + new (inlineManager) OpndRenameTable(inlineManager,10); + NodeRenameTable *nodeRenameTable =new (inlineManager) NodeRenameTable(inlineManager,10); + fg.removeEdge(block,retTarget); + fg.removeEdge(block,entryFinally); + _inlineFinally(irm, block,entryFinally,retTarget, nodeRenameTable,opndRenameTable ); + } + leaveInst->unlink(); + return true; +} - for( niter = nodes.begin(); niter != nodes.end(); ++niter) { - node = *niter; - - // Check whether the sum of freq from incoming edges equal the node - // freq. - const CFGEdgeDeque& iEdges = node->getInEdges(); - if (iEdges.size() > 0) { - f = 0.0; - for(eiter = iEdges.begin(); eiter != iEdges.end(); ++eiter) { - edge = *eiter; - srcNode = edge->getSourceNode(); - f += srcNode->getFreq() * edge->getEdgeProb(); - } +/* +static void renumberLabels(ControlFlowGraph& fg) { + uint32 minLabelId = 0x7fffffff; + for(Nodes::const_iterator i = fg.getNodes().begin(), end = fg.getNodes().end(); i != end; ++i) { + Node* node = *i; + assert(node->getFirstInst()->isLabel()); + LabelInst *label = (LabelInst*)node->getFirstInst(); + uint32 n = label->getLabelId(); + if (n < minLabelId) { + minLabelId = n; + } + } + if (!fg.hasValidOrdering()) { + fg.orderNodes(); + } + for(Nodes::const_iterator i = fg.getNodes().begin(), end = fg.getNodes().end(); i != end; ++i) { + Node* node = *i; + LabelInst *label = (LabelInst*)node->getFirstInst(); + label->setLabelId(node->getPreNum() + minLabelId); + } +} +*/ - diff = (f == 0.0 ? node->getFreq() : (f - node->getFreq())/f); - if (diff > PROFILE_ERROR_ALLOWED || diff < -PROFILE_ERROR_ALLOWED) { - consistent = false; - if (warn) { - ::std::cerr << "Warning (isProfileConsistent): NODE " - << (unsigned int) node->getId() << " : Incoming freq (" - << f << ") != Node freq (" << node->getFreq() << ")" - << ::std::endl; - } - } - } +void FlowGraph::doTranslatorCleanupPhase(IRManager& irm) { + ControlFlowGraph& fg = irm.getFlowGraph(); + InstFactory& instFactory = irm.getInstFactory(); + OpndManager& opndManager = irm.getOpndManager(); + + static CountTime cleanupPhaseTimer("ptra::fg::cleanupPhase"); + AutoTimer tm(cleanupPhaseTimer); + fg.purgeUnreachableNodes(); + inlineJSRs(&irm); - // Check whether the sum of outgoing edge probability is 1.0. - const CFGEdgeDeque& oEdges = node->getOutEdges(); - if (oEdges.size() > 0) { - f = 0.0; - for(eiter = oEdges.begin(); eiter != oEdges.end(); ++eiter) { - edge = *eiter; - f += edge->getEdgeProb(); + { + static CountTime cleanupPhaseInternalTimer("ptra::fg::cleanupPhase::in"); + AutoTimer tm(cleanupPhaseInternalTimer); + // Cleanup optimizations + for (Nodes::const_iterator niter = fg.getNodes().begin(), end = fg.getNodes().end(); niter!=end; ++niter) { + Node* node = *niter; + if (node->isDispatchNode() || node == fg.getReturnNode() || node == fg.getExitNode()) { + continue; } - - diff = (f > 1.0) ? (f - 1.0) : (1.0 - f); - if (diff > PROB_ERROR_ALLOWED) { - consistent = false; - if (warn) { - ::std::cerr << "Warning (isProfileConsistent) NODE " - << (unsigned int) node->getId() << " : Outgoing prob (" - << f << ") != 1.0" << ::std::endl; + Inst *last = (Inst*)node->getLastInst(); + if (last->getOpcode() == Op_TauMonitorExit) { + // Check for monitor exit loop. + breakMonitorExitLoop(fg, node, last); + } + else if (last->isBranch()) { + if (last->isLeave()) { + // Inline Finally - only necessary after translation + inlineFinally(irm, node); + } else if (last->isConditionalBranch()) { // loop peeling for conditional branches + Node *target = ((BranchInst*)last)->getTargetLabel()->getNode(); + if (((LabelInst*)target->getFirstInst())->getLabelId() > ((LabelInst*)node->getFirstInst())->getLabelId()) + { + LabelInst *targetLabel = ((BranchInst*)last)->getTargetLabel(); + Node *fthru = NULL, *taken = NULL; + const Edges& outEdges = node->getOutEdges(); + Edges::const_iterator eIter; + for(eIter = outEdges.begin(); eIter != outEdges.end(); ++eIter) { + Edge* edge = *eIter; + Node * tar = edge->getTargetNode(); + if (!tar->isDispatchNode()) { + if (tar->getFirstInst() == targetLabel) { + taken = tar; + } else { + fthru = tar; + } + } + } + Inst *takenLdConst = (Inst*)taken->getSecondInst(); + Inst *fthruLdConst = (Inst*)fthru->getSecondInst(); + Inst *takenStVar = (takenLdConst!=NULL) ? takenLdConst->getNextInst() : NULL; + Inst *fthruStVar = (fthruLdConst!=NULL) ? fthruLdConst->getNextInst() : NULL; + if (takenStVar!=NULL && fthruStVar!=NULL && + taken->hasOnlyOneSuccEdge() && + taken->hasOnlyOnePredEdge() && + fthru->hasOnlyOneSuccEdge() && + fthru->hasOnlyOnePredEdge() && + (taken->getOutEdges().front()->getTargetNode() == + fthru->getOutEdges().front()->getTargetNode()) && + takenLdConst->getOpcode() == Op_LdConstant && + fthruLdConst->getOpcode() == Op_LdConstant && + takenLdConst->getType() == Type::Int32 && + fthruLdConst->getType() == Type::Int32 && + takenStVar->getOpcode() == Op_StVar && + fthruStVar->getOpcode() == Op_StVar && + takenStVar->getDst() == fthruStVar->getDst() && + takenStVar->getNextInst() == taken->getLastInst() && + fthruStVar->getNextInst() == fthru->getLastInst()) + { + + int takenint32 = ((ConstInst*)takenLdConst)->getValue().i4; + int fthruint32 = ((ConstInst*)fthruLdConst)->getValue().i4; + Node *meet = taken->getOutEdges().front()->getTargetNode(); + // find the ldVar for the variable, if any + Inst *meetLdVar = (Inst*)meet->getSecondInst(); + while (meetLdVar->getOpcode()==Op_LdVar) { + if (meetLdVar->getSrc(0) == takenStVar->getDst()) + break; + meetLdVar = meetLdVar->getNextInst(); + } + if ((((takenint32==0) && (fthruint32==1)) || + ((takenint32==1) && (fthruint32==0))) && + meetLdVar->getOpcode()==Op_LdVar && + last->getNumSrcOperands()==2) { + // change the instruction to reflect the compare instruction + fg.removeEdge(node,taken); + fg.removeEdge(node,fthru); + fg.addEdge(node,meet); + Opnd* dst = opndManager.createSsaTmpOpnd(meetLdVar->getDst()->getType()); + BranchInst *lastBranch = (BranchInst*)last; + if (takenint32==0) + lastBranch->swapTargets(NULL); + Inst *cmp = instFactory.makeCmp( + lastBranch->getComparisonModifier(), + lastBranch->getType(), dst, + lastBranch->getSrc(0), + lastBranch->getSrc(1)); + cmp->insertBefore(lastBranch); + Inst* newStVar = instFactory.makeStVar(meetLdVar->getSrc(0)->asVarOpnd(),dst); + newStVar->insertBefore(lastBranch); + lastBranch->unlink(); + } + } + } + } + } + // remove trivial basic blocks + if (node->hasOnlyOnePredEdge()) { + Node *pred = node->getInEdges().front()->getSourceNode(); + if (!pred->isDispatchNode() && !((Inst*)pred->getLastInst())->isSwitch() && + (pred->hasOnlyOneSuccEdge() || (node->isEmpty() && node->hasOnlyOneSuccEdge()))) + { + + // don't merge if the node has an exception edge + Edge *edge = NULL; + Edges::const_iterator eiter; + for(eiter = node->getOutEdges().begin(); eiter != node->getOutEdges().end(); ++eiter) { + edge = *eiter; + if ((edge->getTargetNode())->isDispatchNode()) { + break; + } + } + // If the node has an exception edge, then merging is potentially illegal, so + // skip. + if (edge == NULL) { + if (Log::isEnabled()) { + Log::out()<<" MERGE ";FlowGraph::printLabel(Log::out(), pred);FlowGraph::printLabel(Log::out(), node);Log::out()<<"\n"; + Log::out().flush(); + } + BranchInst *branch = NULL; + if (!pred->hasOnlyOneSuccEdge() && node->isEmpty()) { + Inst* lastPred = (Inst*)pred->getLastInst(); + Node* nodeSucc = node->getOutEdges().front()->getTargetNode(); + if (lastPred->isBranch()) { + branch = (BranchInst*)lastPred; + if (branch->getTargetLabel() == node->getFirstInst()) { + branch->replaceTargetLabel((LabelInst*)nodeSucc->getFirstInst()); + } + } + } + fg.mergeBlocks(pred,node); + + // remove useless branches + if (branch != NULL) { + Node *target = NULL; + for(eiter=pred->getOutEdges().begin(); eiter!=pred->getOutEdges().end();) { + Edge* edge = *eiter; + ++eiter; + Node *succ = edge->getTargetNode(); + if (! succ->isDispatchNode()) { + if (target == succ) { + fg.removeEdge(pred,succ); + branch->unlink(); + break; + } + target = succ; + } + } + } + } } } } } - return consistent; -} // FlowGraph::isProfileConsistent + // + // a quick cleanup of unreachable and empty basic blocks + // + fg.purgeUnreachableNodes(); + fg.purgeEmptyNodes(false); +// renumberLabels(fg); +} -// Smooth the profile in the FlowGraph by deriving the profile from the edge -// taken probability and the method entry frequency. -void -FlowGraph::smoothProfile(MethodDesc& methodDesc) -{ - if( !hasEdgeProfile() ) - return; - //TODO: use new algorithm in StaticProfiler (works several times faster)! +void FlowGraph::printHIR(std::ostream& os, ControlFlowGraph& fg, MethodDesc& methodDesc) { + const char* methodName = methodDesc.getName(); + os << std::endl << "-------- irDump: " << methodDesc.getParentType()->getName() << "::" << methodName << " --------" << std::endl; + + MemoryManager mm(fg.getMaxNodeId(), "ControlFlowGraph::print.mm"); + Nodes nodes(mm); + fg.getNodesPostOrder(nodes); + Nodes::reverse_iterator iter = nodes.rbegin(), end = nodes.rend(); + for(; iter != end; iter++) { + Node* node = *iter; + print(os, node); + os << std::endl; + } +} - MemoryManager mm(getMaxEdgeId() * sizeof(Node*) * 16, - "FlowGraph::smoothProfileInfo.mm"); - EdgeProfile edgeProfile(mm, methodDesc, true); - edgeProfile.smoothProfile(*this); -} // FlowGraph::smoothProfile +void FlowGraph::print(std::ostream& os, Node* node) { + os << "Block "; + printLabel(os, node); + os << ": "; + os << std::endl; + + // Print predecessors + os << " Predecessors:"; + const Edges& inEdges = node->getInEdges(); + for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + os << " "; + printLabel(os, edge->getSourceNode()); + } + os << std::endl; + + // Print successors + os << " Successors:"; + const Edges& outEdges = node->getOutEdges(); + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + os << " "; + printLabel(os, edge->getTargetNode()); + } + os << std::endl; + // Print instructions + printInsts(os, node, 2); +} + +void FlowGraph::printLabel(std::ostream& cout, Node* node) { + Inst *first = (Inst*)node->getFirstInst(); + assert(first->isLabel()); + if (node->isBlockNode()) { + if(node->getInDegree() == 0) + cout << "ENTRY"; + else if(node->getOutDegree() == 1 && node->getOutEdges().front()->getTargetNode()->isExitNode()) + cout << "RETURN"; + else + ((LabelInst*)first)->printId(cout); + } else if (node->isDispatchNode()) { + if(node->getOutDegree() == 1 && node->getOutEdges().front()->getTargetNode()->isExitNode()) + cout << "UNWIND"; + else + cout << "D" << (int32)((LabelInst*)first)->getLabelId(); + } else { + cout << "EXIT"; + } +} -/*********************** print Dot utilities *****************************/ +void FlowGraph::printInsts(std::ostream& cout, Node* node, uint32 indent){ + std::string indentstr(indent, ' '); + Inst* inst = (Inst*)node->getFirstInst(); + while (inst!=NULL) { + cout << indentstr.c_str(); + inst->print(cout); + cout << std::endl; + inst = inst->getNextInst(); + } -void FlowGraph::printDotFile(MethodDesc& methodDesc,const char *suffix, DominatorTree *tree) { - assert(tree == NULL || tree == irManager->getDominatorTree()); - PrintDotFile::printDotFile(methodDesc,suffix); + // The IR does not contain explicit GOTOs, so for IR printing purposes + // we should print a GOTO if required, extracted from the CFG. + inst = (Inst*)node->getLastInst(); + if (!inst->isReturn() && !inst->isLeave() && + !inst->isThrow() && + !inst->isEndFinally() && !inst->isRet()) { + Node *target = NULL; + if (inst->isConditionalBranch()) { + target = ((BranchInst*)inst)->getTakenEdge(false)->getTargetNode(); + } else { + Edges::const_iterator j = node->getOutEdges().begin(), jend = node->getOutEdges().end(); + for (; j != jend; ++j) { + Edge* edge = *j; + Node *node = edge->getTargetNode(); + if (!node->isDispatchNode()) { + target = node; + break; + } + } + } + if (target != NULL) { + cout << indentstr.c_str() << "GOTO "; + printLabel(cout, target); + cout << std::endl; + } + } } +class HIRDotPrinter : public PrintDotFile { +public: + HIRDotPrinter(ControlFlowGraph& _fg) : fg(_fg), loopTree(NULL), dom(NULL){} + void printDotBody(); + void printDotNode(Node* node); + void printDotEdge(Edge* edge); +private: + ControlFlowGraph& fg; + LoopTree* loopTree; + DominatorTree* dom; +}; + +void FlowGraph::printDotFile(ControlFlowGraph& fg, MethodDesc& methodDesc,const char *suffix) { + HIRDotPrinter printer(fg); + printer.printDotFile(methodDesc, suffix); +} -void FlowGraph::printDotBody() { - ::std::ostream& out = *os; - const CFGNodeDeque& nodes = getNodes(); - CFGNodeDeque::const_iterator niter; - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - DominatorTree* dom = irManager->getDominatorTree(); - node->printDotCFGNode(out,dom,getEntry()->getFreq(), irManager); +void HIRDotPrinter::printDotBody() { + const Nodes& nodes = fg.getNodes(); + dom = fg.getDominatorTree(); + if (dom != NULL && !dom->isValid()) { + dom = NULL; + } + loopTree = fg.getLoopTree(); + if (loopTree!=NULL && !loopTree->isValid()) { + loopTree = NULL; } - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - const CFGEdgeDeque& edges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { - CFGEdge* edge = *eiter; - edge->printDotCFGEdge(out); + for(Nodes::const_iterator niter = nodes.begin(); niter != nodes.end(); ++niter) { + Node* node = *niter; + printDotNode(node); + } + for(Nodes::const_iterator niter = nodes.begin(); niter != nodes.end(); ++niter) { + Node* node = *niter; + const Edges& edges = node->getOutEdges(); + for(Edges::const_iterator eiter = edges.begin(); eiter != edges.end(); ++eiter) { + Edge* edge = *eiter; + printDotEdge(edge); } } } - -void CFGNode::printDotCFGNode(::std::ostream& out, DominatorTree *dom, double methodFreq, IRManager *irMng) { - printLabel(out); +void HIRDotPrinter::printDotNode(Node* node) { + std::ostream& out = *os; + FlowGraph::printLabel(out, node); out << " [label=\""; - if (!isEmpty()) + if (!node->isEmpty()) { out << "{"; - getFirstInst()->print(out); - out << "tn: " << (int) getTraversalNum() << " pre:" << (int)getPreNum() << " post:" << (int)getPostNum() << " "; - out << "id: " << (int) getId() << " "; - if(freq > 0) - out << " freq:" << freq << " "; - // - // dump immediate dom information - // [label="{ (L2(dfn:3) | idom(L5)) | ... if dumping dom is requested - // {label="{ L2 (dfn:3) | ... otherwise - // - if (dom != NULL && dom->isValid()) { - out << "idom("; dom->printIdom(out,this); out << "))"; } - if (!isEmpty()) { - out << "\\l|\\" << ::std::endl; - Inst* first = getFirstInst(); - VectorHandler* bc2HIRMapHandler = NULL; - if (irMng) { - MethodDesc* methDesc = irMng->getCompilationInterface().getMethodToCompile(); - - if (irMng->getCompilationInterface().isBCMapInfoRequired()) { - bc2HIRMapHandler = new(irMng->getMemoryManager()) VectorHandler(bcOffset2HIRHandlerName, methDesc); - assert(bc2HIRMapHandler); - } + ((Inst*)node->getFirstInst())->print(out); + out << "tn: " << (int) node->getTraversalNum() << " pre:" << (int)node->getPreNum() << " post:" << (int)node->getPostNum() << " "; + out << "id: " << (int) node->getId() << " "; + if(fg.hasEdgeProfile()) { + out << " execCount:" << (int)node->getExecCount()<< " "; + } + Node* idom = dom==NULL ? NULL: dom->getIdom(node); + if (idom!=NULL) { + out << "idom("; FlowGraph::printLabel(out, idom); out << ") "; + } + if (loopTree!=NULL) { + Node* loopHeader = loopTree->getLoopHeader(node); + bool isLoopHeader = loopTree->isLoopHeader(node); + out << "loop("; + if (!isLoopHeader) { + out<<"!"; + } + out<<"hdr"; + if (loopHeader!=NULL) { + out<<" head:";FlowGraph::printLabel(out, loopHeader); } - for (Inst* i = first->next(); i != first; i=i->next()) { // skip label inst + out << ") "; + } + + if (!node->isEmpty()) { + out << "\\l|\\" << std::endl; + Inst* first = (Inst*)node->getFirstInst(); + VectorHandler* bc2HIRMapHandler = NULL; + for (Inst* i = first->getNextInst(); i != NULL; i=i->getNextInst()) { // skip label inst i->print(out); if (bc2HIRMapHandler != NULL) { uint64 bcOffset = 0; @@ -1665,29 +1183,54 @@ void CFGNode::printDotCFGNode(::std::ost bcOffset = bc2HIRMapHandler->getVectorEntry(instID); if (bcOffset != ILLEGAL_VALUE) out<<" "<<"bcOff:"<< (uint16)bcOffset<<" "; } - out << "\\l\\" << ::std::endl; + out << "\\l\\" << std::endl; } out << "}"; } out << "\""; - if(freq > methodFreq*10) - out << ",color=red"; - else if(freq > 0 && freq >= 0.85*methodFreq) - out << ",color=orange"; - if (isDispatchNode()) + if (!node->isExitNode() && fg.hasEdgeProfile()) { + double freq = node->getExecCount(); + double methodFreq = fg.getEntryNode()->getExecCount(); + if(freq > methodFreq*10) { + out << ",color=red"; + } else if(freq > 0 && freq >= 0.85*methodFreq) { + out << ",color=orange"; + } + } + if (node->isDispatchNode()) { out << ",shape=diamond,color=blue"; - out << "]" << ::std::endl; + } else if (node->isExitNode()) { + out << ",shape=ellipse,color=green"; + } + + out << "]" << std::endl; } -void CFGEdge::printDotCFGEdge(::std::ostream& out) { - CFGNode *from = getSourceNode(); - CFGNode *to = getTargetNode(); - from->printLabel(out); +void HIRDotPrinter::printDotEdge(Edge* edge) { + std::ostream& out = *os; + Node *from = edge->getSourceNode(); + Node *to = edge->getTargetNode(); + FlowGraph::printLabel(out, from); out << " -> "; - to->printLabel(out); - if (to->isDispatchNode()) - out << " [style=dotted,color=blue]"; - out << ";" << ::std::endl; + FlowGraph::printLabel(out, to); + out<<" ["; + out << "taillabel=\"" ; + if (loopTree) { + if (loopTree->isBackEdge(edge)) { + out<<"(backedge)"; + } + if (loopTree->isLoopExit(edge)) { + out<<"(loopexit)"; + } + } + if (fg.hasEdgeProfile()) { + out<<"p:" << edge->getEdgeProb(); + } + out <<"\""; + if (to->isDispatchNode()) { + out << ",style=dotted,color=blue"; + } + out << "];" << std::endl; } } //namespace Jitrino diff --git vm/jitrino/src/optimizer/FlowGraph.h vm/jitrino/src/optimizer/FlowGraph.h index 30970c6..6d80107 100644 --- vm/jitrino/src/optimizer/FlowGraph.h +++ vm/jitrino/src/optimizer/FlowGraph.h @@ -23,362 +23,65 @@ #ifndef _FLOWGRAPH_ #define _FLOWGRAPH_ -#include "Stl.h" -#include "BitSet.h" -#include "List.h" +#include "TranslatorIntfc.h" + #include "Inst.h" #include "ControlFlowGraph.h" +#include "Dominator.h" #include "PrintDotFile.h" -#include "TranslatorIntfc.h" -#include <iomanip> #include "Log.h" -namespace Jitrino { - -class CFGNode; -class CFGEdge; -class FlowGraph; -class DominatorTree; -class DominatorNode; -class LoopTree; -class IRManager; -class TypeFailStream; - -typedef StlList<CFGEdge*> CFGEdgeDeque; -typedef StlList<CFGNode*> CFGNodeDeque; - -typedef StlMultiMap<Inst*, Inst*> JsrEntryInstToRetInstMap; -typedef std::pair<JsrEntryInstToRetInstMap::const_iterator, - JsrEntryInstToRetInstMap::const_iterator> JsrEntryCIterRange; - -class CFGVector : public StlVector<CFGNode*> { -public: - CFGVector(MemoryManager& mm) : StlVector<CFGNode*>(mm) {} - CFGVector(MemoryManager& mm,uint32 size) : StlVector<CFGNode*>(mm) { - reserve(size); - } - typedef StlVector<CFGNode*>::const_iterator ConstIterator; - typedef StlVector<CFGNode*>::reverse_iterator ReverseIterator; -}; - -// -// Control Flow Graph Edge: same as Edge, with an enumeration !!! -// - -class CFGEdge: public ControlFlowEdge { - friend class FlowGraph; -public: - CFGNode* getSourceNode() { return (CFGNode*) ControlFlowEdge::getSourceNode(); } - CFGNode* getTargetNode() { return (CFGNode*) ControlFlowEdge::getTargetNode(); } - - CFGEdge::Kind getEdgeType(); - Kind getKind() { return getEdgeType(); } - - int getEdgeFlags() const {return edgeFlags;} - void setEdgeFlags(int flags) {edgeFlags = flags;} - - double getEdgeProb() { return prob; } - void setEdgeProb(double p) { prob = p; } - - void printDotCFGEdge(::std::ostream& os); // dot file support - -protected: - friend class CFGNode; - -private: - CFGEdge(ControlFlowNode* source, ControlFlowNode* target) : ControlFlowEdge(source, target), prob(0.0) {} - CFGEdge() : ControlFlowEdge(), prob(0.0) { } - int edgeFlags; - double prob; // the taken probability of the edge WRT source node -}; - - -// -// Control Flow Graph node -// - -class CFGNode : public ControlFlowNode { - -public: - CFGNode(MemoryManager& mm, LabelInst* label, Kind kind=Block) - : ControlFlowNode(mm, kind), flags(0), info(NULL), insts(label), freq(0.0) { } - void* getInfo() {return info;} - void setInfo(void* r) {info = r;} - Inst* getFirstInst() {return insts;} - LabelInst* getLabel() {return (LabelInst*) insts; } - uint32 getLabelId() {return ((LabelInst*)insts)->getLabelId(); } - Inst* getLastInst() {assert(insts != NULL); return insts->prev(); } - bool isEmpty() const {return insts->next() == insts; } - bool isBasicBlock() {return isBlockNode(); } - bool isCatchBlock() {return getLabel()->isCatchLabel();} - int getFlags() {return flags; } - void setFlags(int f) {flags = f; } - void append(Inst* inst) { // append inst to the end of block - assert(insts != NULL); - inst->unlink(); - inst->insertBefore(insts); - } - void appendBeforeBranch(Inst* inst) { // append, but before any branch - assert(insts != NULL); - inst->unlink(); - Inst *lastInst = getLastInst(); - if (lastInst->getOperation().mustEndBlock()) { - assert(!inst->getOperation().mustEndBlock()); - inst->insertBefore(lastInst); - } else { - inst->insertAfter(lastInst); - } - } - void prepend(Inst* inst) { // insert inst to the beginning of the block - assert(insts != NULL); - inst->unlink(); - inst->insertAfter(insts); - } - void prependAfterCriticalInst(Inst* inst) { - // Insert inst to the beginning of block after any critical instruction - // Critical instructions are those that are implicitly assumed to be - // the first in a block. They include: Op_Catch. - assert(insts != NULL); - inst->unlink(); - Inst* realInst = insts->next(); - if (realInst->getOpcode() == Op_Catch) { - inst->insertAfter(realInst); - } else - inst->insertAfter(insts); - } - - // the following utilities are useful in some tests - bool hasOnlyOneSuccEdge() { return getOutEdges().size() == 1; } - bool hasOnlyOnePredEdge() { return getInEdges().size() == 1; } - bool hasTwoOrMoreSuccEdges() { return getOutEdges().size() > 1; } - bool hasTwoOrMorePredEdges() { return getInEdges().size() > 1; } - - const CFGEdgeDeque& getInEdges() { return (const CFGEdgeDeque&) ControlFlowNode::getInEdges(); } - const CFGEdgeDeque& getOutEdges() { return (const CFGEdgeDeque&) ControlFlowNode::getOutEdges(); } - - double getFreq() { return freq; } - void setFreq(double f) { freq = f; } - - virtual void printLabel(::std::ostream& cout); - void printInsts(::std::ostream& cout, uint32 indent=0); // print the instructions in a basic block - void printProfile(::std::ostream& cout); // print the profile of a basic block - void printDotCFGNode(::std::ostream& cout, DominatorTree *dom, double freq = 0, IRManager *irm = NULL); // dot file support +#include "Stl.h" +#include "BitSet.h" +#include "List.h" - class ProfileAnnotator : public ControlFlowNode::Annotator { - public: - virtual ~ProfileAnnotator() {} - void annotateNode(::std::ostream& os, ControlFlowNode* _node) { - CFGNode* node = (CFGNode*) _node; - os << "[Freq=" << ::std::setprecision(4) << node->getFreq(); - if (node->getOutEdges().size() > 0 ) { - os << ", Target Prob:"; - CFGEdgeDeque::const_iterator j = node->getOutEdges().begin(); - CFGEdgeDeque::const_iterator jend = node->getOutEdges().end(); - for (; j != jend; ++j) { - CFGEdge* edge = *j; - CFGNode* target = edge->getTargetNode(); - os << " "; - target->printLabel(os); - os << "=" << edge->getEdgeProb(); - } - } - os << ", id=" << (unsigned int) node->getId() << "]"; - } - }; -protected: - friend class FlowGraph; +#include <iomanip> - // - // scratch flags for any purpose (some of them) - int flags; - // - // scratch field for any purpose - // - void* info; - // - // instruction list: the first inst is a label inst - // - Inst* insts; - // - // The execution frequency as obtained from an execution profile - // - double freq; -}; +namespace Jitrino { -class CFGNodeRenameTable; +class NodeRenameTable; class Opnd; class DefUseBuilder; +class DominatorNode; -typedef StlMultiMap<CFGNode*, CFGNode*> CFG2CFGNodeMap; +typedef StlMultiMap<Node*, Node*> NodeMap; -class FlowGraph : public ControlFlowGraph, public PrintDotFile { +class FlowGraph { +private: + FlowGraph(){} public: - FlowGraph(MemoryManager& mm, InstFactory& instFactory, OpndManager& opndManager) - : ControlFlowGraph(mm), prolog(0), epilog(0), - memManager(mm), opndManager(opndManager), instFactory(instFactory), - dfnMap(mm), edgeProfile(false), irManager(NULL) {} - - CFGNode* getEntry() {return (CFGNode*) ControlFlowGraph::getEntry() ;} - CFGNode* getReturn() {return (CFGNode*) ControlFlowGraph::getReturn() ;} - CFGNode* getUnwind() {return (CFGNode*) ControlFlowGraph::getUnwind();} - CFGNode* getExit() {return (CFGNode*) ControlFlowGraph::getExit() ;} - - bool hasEdgeProfile() {return edgeProfile; } - void setEdgeProfile(bool f) { edgeProfile = f; } - - const CFGNodeDeque& getNodes() const { return (CFGNodeDeque&) ControlFlowGraph::getNodes(); } - void getNodesPreOrder(StlVector<CFGNode*>& container, bool isForward=true) { ControlFlowGraph::getNodesPreOrder((StlVector<Node*>&) container, isForward); } - void getNodesPreOrder(::std::vector<CFGNode*>& container, bool isForward=true) { ControlFlowGraph::getNodesPreOrder((::std::vector<Node*>&) container, isForward); } - void getNodesPostOrder(StlVector<CFGNode*>& container, bool isForward=true) { ControlFlowGraph::getNodesPostOrder((StlVector<Node*>&) container, isForward); } - void getNodesPostOrder(::std::vector<CFGNode*>& container, bool isForward=true) { ControlFlowGraph::getNodesPostOrder((::std::vector<Node*>&) container, isForward); } - - CFGNode* createBlockNode(); - CFGNode* createDispatchNode(); - CFGNode* createExitNode(); - CFGNode* createCatchNode(uint32 order, Type* exceptionType); - CFGNode* createBlock(LabelInst *label); - CFGNode* createBlockAfter(CFGNode *node); - CFGNode* createBlockAfter(LabelInst *label, CFGNode *node); - CFGNode* duplicateBlockAfter(LabelInst *label, CFGNode *afterNode, CFGNode *sourceNode); - CFGNode* spliceBlockOnEdge(CFGEdge* edge); - CFGEdge* addEdge(CFGNode* source, CFGNode* target); - CFGEdge* replaceEdgeTarget(Edge* edge, Node* newTarget); - // Folds the branch at the end of block. If isTaken, the true edge is // converted to an unconditional edge, and the false edge is deleted. // If !isTaken, then the false edge is converted, and the true edge // is deleted. In either case, the branch instruction br is removed // from block. - void foldBranch(CFGNode* block, BranchInst* br, bool isTaken); + static void foldBranch(ControlFlowGraph& fg, Node* block, BranchInst* br, bool isTaken); - void foldSwitch(CFGNode* block, SwitchInst* sw, uint32 target); + static void foldSwitch(ControlFlowGraph& fg, Node* block, SwitchInst* sw, uint32 target); // Eliminates the check at the end of block and the associated exception // edge. If (alwaysThrows), then eliminates the non-exception edge instead; // we should have already inserted throw instruction before the check. - void eliminateCheck(CFGNode* block, Inst* check, bool alwaysThrows); - - // Splices flowgraph of inlined method into this flowgraph, replacing the - // passed call instruction. callNode must be the node that contains call. - void spliceFlowGraphInline(CFGNode* callNode, Inst* call, FlowGraph& inlineFG); + static void eliminateCheck(ControlFlowGraph& fg, Node* block, Inst* check, bool alwaysThrows); - // Finds nodes dominated by entry and post-dominated by end inclusive. Entry must - // dominate end, but end need not post-dominate entry. NodesInRegion must be - // initialized false as it is used to mark visited nodes. - void findNodesInRegion(CFGNode* entry, CFGNode* end, StlBitVector& nodesInRegion); + static Node* tailDuplicate(IRManager& irm, Node* pred, Node* tail, DefUseBuilder& defUses); - CFGNode* duplicateRegion(CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, double newEntryFreq=0.0); - CFGNode* duplicateRegion(CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, - CFGNodeRenameTable& nodeRenameTable, OpndRenameTable& opndRenameTable, double newEntryFreq=0.0); - CFGNode* tailDuplicate(CFGNode* pred, CFGNode* tail, DefUseBuilder& defUses); + static Node* duplicateRegion(IRManager& irm, Node* entry, StlBitVector& nodesInRegion, DefUseBuilder& defUses, double newEntryFreq=0.0); - void smoothProfileInfo(); - void smoothProfile(MethodDesc& methodDesc); // direct-computation version - bool isProfileConsistent(char *methodStr, bool warn); + static void renameOperandsInNode(Node *node, OpndRenameTable *renameTable); + static void doTranslatorCleanupPhase(IRManager& irm); + - void renameOperandsInNode(CFGNode *node, OpndRenameTable *renameTable); - bool inlineFinally(CFGNode *bblock); - void mergeWithSingleSuccessor(CFGNode *to, CFGNode *from); - CFGNode* splitNodeAtInstruction(Inst *inst); - CFGNode* splitReturnNode(); - void renumberLabels(); - void cleanupPhase(); - uint32 assignDepthFirstNum(); - void orderDepthFirst(); - void linkDFS(CFGNode *); - void printInsts(::std::ostream& cout, MethodDesc& methodDesc, CFGNode::Annotator* annotator=NULL); - void printDotFile(MethodDesc& methodDesc,const char *suffix, DominatorTree *dom); - virtual void printDotBody(); - - const StlVector<CFGNode*>& getDFNMap() const { return dfnMap; } - - CFGNode* getNext(CFGNode* node) { - CFGNodeDeque::const_iterator i = ::std::find(getNodes().begin(), getNodes().end(), node); - assert(i != getNodes().end()); - ++i; - if(i == getNodes().end()) - return NULL; - else - return *i; - } - CFGNode* getPrev(CFGNode* node) { - CFGNodeDeque::const_iterator i = ::std::find(getNodes().begin(), getNodes().end(), node); - assert(i != getNodes().end()); - if(i == getNodes().begin()) - return NULL; - else - return *(--i); - } - - bool isModified() {return getModificationTraversalNum() >= getOrderingTraversalNum();} - - IRManager* getIRManager() { return irManager; } - void setIRManager(IRManager* irm) { irManager = irm; } -protected: - // Node factory hook for base class. - ControlFlowNode* _createNode(ControlFlowNode::Kind kind) { return (kind == CFGNode::Block ? createBlockNode() : - (kind == CFGNode::Dispatch ? createDispatchNode() : createExitNode())); - } - ControlFlowEdge* _createEdge(ControlFlowNode* source, ControlFlowNode* target) { return addEdge((CFGNode*) source, (CFGNode*) target); } - - void _updateBranchInstruction(ControlFlowNode* source, ControlFlowNode* oldTarget, ControlFlowNode* newTarget); - void _removeBranchInstruction(ControlFlowNode* source); - void _moveInstructions(Node* fromNode, Node* toNode, bool prepend); - -private: - CFGNode* duplicateRegion(CFGNode* node, CFGNode* entry, StlBitVector& nodesInRegion, DefUseBuilder* defUses, - CFGNodeRenameTable* nodeRenameTable, OpndRenameTable* opndRenameTable); - - CFGNode* duplicateCFGNode(CFGNode* node, StlBitVector* nodesInRegion, - DefUseBuilder* defUses, OpndRenameTable* opndRenameTable); - CFGNode* duplicateCFGNode(CFGNode *source, CFGNode *after, OpndRenameTable *renameTable); - void breakMonitorExitLoop(CFGNode* node, Inst* monExit); - void inlineJSRs(); - bool inlineJSR(CFGNode *bblock, DefUseBuilder& defUses, JsrEntryInstToRetInstMap& entryMap); - Inst* findSaveRet(CFGNode* node); - - bool _inlineFinally(CFGNode *to, CFGNode *from, CFGNode *target, void *info, - CFGNodeRenameTable *nodeRenameTable, - OpndRenameTable *opndRenameTable); - void _fixFinally (CFGNode *node, CFGNode *retTarget); - void _fixBranchTargets(Inst *newInst, CFGNodeRenameTable *nodeRenameTable); - bool validateDefinitions(DominatorNode* dnode, StlHashSet<SsaOpnd*>& defined); - - CFGNode* prolog; - CFGNode* epilog; - MemoryManager& memManager; - OpndManager& opndManager; - InstFactory& instFactory; - StlVector<CFGNode*> dfnMap; - bool edgeProfile; // set if the flow graph is annotated with edgeProfile. - IRManager* irManager; // back pointer to IRManager -}; - + static void printHIR(std::ostream& cout, ControlFlowGraph& fg, MethodDesc& methodDesc); + static void print(std::ostream& cout, Node* node); + static void printLabel(std::ostream& cout, Node* node); + static void printLabel(std::ostream& cout, DominatorNode* dNode) {printLabel(cout, dNode->getNode()); } + static void printInsts(std::ostream& cout, Node* node, uint32 indent); -class CFGNodeRenameTable : public HashTable<CFGNode,CFGNode> { -public: - typedef HashTableIter<CFGNode, CFGNode> Iter; + static void printDotFile(ControlFlowGraph& cfg, MethodDesc& methodDesc,const char *suffix); - CFGNodeRenameTable(MemoryManager& mm,uint32 size) : - HashTable<CFGNode,CFGNode>(mm,size) {} - CFGNode *getMapping(CFGNode *node) { - return (CFGNode*)lookup(node); - } - void setMapping(CFGNode *node, CFGNode *to) { - insert(node,to); - } - -protected: - virtual bool keyEquals(CFGNode* key1,CFGNode* key2) const { - return key1 == key2; - } - virtual uint32 getKeyHashCode(CFGNode* key) const { - // return hash of address bits - return ((uint32)(((POINTER_SIZE_INT)key) >> sizeof(void*))); - } -private: }; } //namespace Jitrino diff --git vm/jitrino/src/optimizer/IRBuilder.cpp vm/jitrino/src/optimizer/IRBuilder.cpp index cc8275d..db265d2 100644 --- vm/jitrino/src/optimizer/IRBuilder.cpp +++ vm/jitrino/src/optimizer/IRBuilder.cpp @@ -38,33 +38,281 @@ #if defined(_MSC_VER) && !defined (__ICL #pragma warning(disable : 4355) #endif -IRBuilder::IRBuilder(IRManager& irm) - : irManager(irm), - opndManager(irm.getOpndManager()), - typeManager(irm.getTypeManager()), - instFactory(irm.getInstFactory()), - flowGraph(irm.getFlowGraph()), - irBuilderFlags(*irm.getCompilationContext()->getIRBuilderFlags()), - tempMemoryManager(0, "IRBuilder::tempMemoryManager"), - cseHashTable(tempMemoryManager), - simplifier(irm, this), - tauMethodSafeOpnd(0), - offset(0) +static const char* help = \ + " expansion flags:\n"\ + " expandMemAddrs[={ON|off}]\n"\ + " expandElemAddrs[={ON|off}]\n"\ + " expandCallAddrs[={on|OFF}]\n"\ + " expandVirtualCallAddrs[={ON|off}]\n"\ + " expandNullChecks[={ON|off}]\n"\ + " expandElemTypeChecks[={ON|off}]\n"\ + " translation-time optimizations:\n"\ + " doCSE[={ON|off}]\n"\ + " doSimplify[={ON|off}]\n"\ + " suppressCheckBounds[={on|OFF}] - omit all bounds checks\n"\ + " insertMethodLabels[={on|OFF}]\n"\ + " compressedReferences[={on|OFF}] - force compressed references\n"; + + +static ActionFactory<IRBuilder, IRBuilderAction> _irbuilder(IRBUILDER_ACTION_NAME, help); + + +class IRBuilderSimplifier : public Simplifier { +public: + IRBuilderSimplifier(IRBuilder& irb) + : Simplifier(*irb.getIRManager(), false), irBuilder(irb) + {} +protected: + // numeric + virtual Inst* genAdd(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ + return irBuilder.genAdd(type, mod, src1, src2)->getInst(); + } + virtual Inst* genSub(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { + return irBuilder.genSub(type, mod, src1, src2)->getInst(); + } + virtual Inst* genNeg(Type* type, Opnd* src) { + return irBuilder.genNeg(type, src)->getInst(); + } + virtual Inst* genMul(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ + return irBuilder.genMul(type, mod, src1, src2)->getInst(); + } + virtual Inst* genMulHi(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ + return irBuilder.genMulHi(type, mod, src1, src2)->getInst(); + } + virtual Inst* genMin(Type* type, Opnd* src1, Opnd* src2){ + return irBuilder.genMin(type, src1, src2)->getInst(); + } + virtual Inst* genMax(Type* type, Opnd* src1, Opnd* src2){ + return irBuilder.genMax(type, src1, src2)->getInst(); + } + virtual Inst* genAbs(Type* type, Opnd* src1){ + return irBuilder.genAbs(type, src1)->getInst(); + } + // bitwise + virtual Inst* genAnd(Type* type, Opnd* src1, Opnd* src2){ + return irBuilder.genAnd(type, src1, src2)->getInst(); + } + virtual Inst* genOr(Type* type, Opnd* src1, Opnd* src2){ + return irBuilder.genOr(type, src1, src2)->getInst(); + } + virtual Inst* genXor(Type* type, Opnd* src1, Opnd* src2){ + return irBuilder.genXor(type, src1, src2)->getInst(); + } + virtual Inst* genNot(Type* type, Opnd* src1){ + return irBuilder.genNot(type, src1)->getInst(); + } + virtual Inst* genSelect(Type* type, Opnd* src1, Opnd* src2, Opnd* src3){ + return irBuilder.genSelect(type, src1, src2, src3)->getInst(); + } + // conversion + virtual Inst* genConv(Type* dstType, Type::Tag toType, Modifier ovfMod, Opnd* src){ + return irBuilder.genConv(dstType, toType, ovfMod, src)->getInst(); + } + // shifts + virtual Inst* genShladd(Type* type, Opnd* src1, Opnd* src2, Opnd *src3){ + return irBuilder.genShladd(type, src1, src2, src3)->getInst(); + } + virtual Inst* genShl(Type* type, Modifier smmod, Opnd* src1, Opnd* src2){ + return irBuilder.genShl(type, smmod, src1, src2)->getInst(); + } + virtual Inst* genShr(Type* type, Modifier mods, Opnd* src1, Opnd* src2){ + return irBuilder.genShr(type, mods, src1, src2)->getInst(); + } + // comparison + virtual Inst* genCmp(Type* type, Type::Tag insttype, ComparisonModifier mod, Opnd* src1, Opnd* src2){ + return irBuilder.genCmp(type, insttype, mod, src1, src2)->getInst(); + } + // control flow + virtual void genJump(LabelInst* label) { + irBuilder.genJump(label); + } + virtual void genBranch(Type::Tag instType, ComparisonModifier mod, LabelInst* label, Opnd* src1, Opnd* src2) { + irBuilder.genBranch(instType, mod, label, src1, src2); + } + virtual void genBranch(Type::Tag instType, ComparisonModifier mod, LabelInst* label, Opnd* src1) { + irBuilder.genBranch(instType, mod, label, src1); + } + virtual Inst* genDirectCall(MethodDesc* methodDesc,Type* returnType,Opnd* tauNullCheckedFirstArg, + Opnd* tauTypesChecked,uint32 numArgs,Opnd* args[],InlineInfoBuilder* inlineBuilder) + { + irBuilder.genDirectCall(methodDesc, returnType, tauNullCheckedFirstArg, tauTypesChecked, + numArgs, args, inlineBuilder); + return (Inst*)irBuilder.getCurrentLabel()->getNode()->getLastInst(); + } + // load, store & mov + virtual Inst* genLdConstant(int32 val) { + return irBuilder.genLdConstant(val)->getInst(); + } + virtual Inst* genLdConstant(int64 val) { + return irBuilder.genLdConstant(val)->getInst(); + } + virtual Inst* genLdConstant(float val) { + return irBuilder.genLdConstant(val)->getInst(); + } + virtual Inst* genLdConstant(double val) { + return irBuilder.genLdConstant(val)->getInst(); + } + virtual Inst* genLdConstant(Type *type, ConstInst::ConstValue val) { + return irBuilder.genLdConstant(type, val)->getInst(); + } + virtual Inst* genTauLdInd(Modifier mod, Type* dstType, Type::Tag ldType, Opnd* src, + Opnd *tauNonNullBase, Opnd *tauAddressInRange) + { + return irBuilder.genTauLdInd(mod, dstType, ldType, src, tauNonNullBase, tauAddressInRange)->getInst(); + } + + virtual Inst* genLdRef(Modifier mod, Type* dstType, uint32 token, MethodDesc *enclosingMethod) { + return irBuilder.genLdRef(mod, dstType, token, enclosingMethod)->getInst(); + } + virtual Inst* genLdFunAddrSlot(MethodDesc* methodDesc) { + return irBuilder.genLdFunAddrSlot(methodDesc)->getInst(); + } + virtual Inst* genGetVTableAddr(ObjectType* type) { + return irBuilder.genGetVTable(type)->getInst(); + } + // compressed references + virtual Inst* genCompressRef(Opnd *uncompref){ + return irBuilder.genCompressRef(uncompref)->getInst(); + } + virtual Inst* genUncompressRef(Opnd *compref){ + return irBuilder.genUncompressRef(compref)->getInst(); + } + virtual Inst *genLdFieldOffsetPlusHeapbase(FieldDesc* fd) { + return irBuilder.genLdFieldOffsetPlusHeapbase(fd)->getInst(); + } + virtual Inst *genLdArrayBaseOffsetPlusHeapbase(Type *elemType) { + return irBuilder.genLdArrayBaseOffsetPlusHeapbase(elemType)->getInst(); + } + virtual Inst *genLdArrayLenOffsetPlusHeapbase(Type *elemType) { + return irBuilder.genLdArrayLenOffsetPlusHeapbase(elemType)->getInst(); + } + virtual Inst *genAddOffsetPlusHeapbase(Type *ptrType, Opnd *compRef, Opnd *offsetPlusHeapbase) { + return irBuilder.genAddOffsetPlusHeapbase(ptrType, compRef, offsetPlusHeapbase)->getInst(); + } + virtual Inst *genTauSafe() { + return irBuilder.genTauSafe()->getInst(); + } + virtual Inst *genTauMethodSafe() { + return irBuilder.genTauMethodSafe()->getInst(); + } + virtual Inst *genTauUnsafe() { + return irBuilder.genTauUnsafe()->getInst(); + } + virtual Inst* genTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) { + return irBuilder.genTauStaticCast(src, tauCheckedCast, castType)->getInst(); + } + virtual Inst* genTauHasType(Opnd *src, Type *castType) { + return irBuilder.genTauHasType(src, castType)->getInst(); + } + virtual Inst* genTauHasExactType(Opnd *src, Type *castType) { + return irBuilder.genTauHasExactType(src, castType)->getInst(); + } + virtual Inst* genTauIsNonNull(Opnd *src) { + return irBuilder.genTauIsNonNull(src)->getInst(); + } + // helper for store simplification, builds/finds simpler src, possibly + // modifies typetag or store modifier. + virtual Opnd* simplifyStoreSrc(Opnd *src, Type::Tag &typetag, Modifier &mod, bool compressRef) { + return 0; + } + virtual void foldBranch(BranchInst* br, bool isTaken) { + assert(0); + } + virtual void foldSwitch(SwitchInst* sw, uint32 index) { + assert(0); + } + virtual void eliminateCheck(Inst* checkInst, bool alwaysThrows) { + assert(0); + } + virtual void genThrowSystemException(CompilationInterface::SystemExceptionId id) { + irBuilder.genThrowSystemException(id); + } +private: + IRBuilder& irBuilder; +}; + +void IRBuilderAction::init() { + readFlags(); +} + +void IRBuilderAction::readFlags() { + // IRBuilder expansion flags + // + irBuilderFlags.expandMemAddrs = getBoolArg("expandMemAddrs", true); + irBuilderFlags.expandElemAddrs = getBoolArg("expandElemAddrs", true); + irBuilderFlags.expandCallAddrs = getBoolArg("expandCallAddrs", false); + irBuilderFlags.expandVirtualCallAddrs = getBoolArg("expandVirtualCallAddrs", true); + irBuilderFlags.expandNullChecks = getBoolArg("expandNullChecks", true); + irBuilderFlags.expandElemTypeChecks = getBoolArg("expandElemTypeChecks", true); + irBuilderFlags.fullBcMap = getBoolArg("fullBcMap", false); + + // + // IRBuilder translation-time optimizations + // + irBuilderFlags.doCSE = getBoolArg("doCSE", true); + irBuilderFlags.doSimplify = getBoolArg("doSimplify", true); + + irBuilderFlags.suppressCheckBounds = getBoolArg("suppressCheckBounds", false); + + irBuilderFlags.insertMethodLabels = getBoolArg("insertMethodLabels", true); + irBuilderFlags.compressedReferences = getBoolArg("compressedReferences", false); + + irBuilderFlags.genMinMaxAbs = getBoolArg("genMinMaxAbs", false); + irBuilderFlags.genFMinMaxAbs = getBoolArg("genFMinMaxAbs", false); + + irBuilderFlags.useNewTypeSystem = getBoolArg("useNewTypeSystem", false); +} + + + + +IRBuilder::IRBuilder() : +irManager(NULL), +opndManager(NULL), +typeManager(NULL), +instFactory(NULL), +flowGraph(NULL), +translatorFlags(NULL), +currentLabel(NULL), +cseHashTable(NULL), +simplifier(NULL), +tauMethodSafeOpnd(NULL), +offset(0), +bc2HIRmapHandler(NULL), +lostBCMapOffsetHandler(NULL) { - currentLabel = NULL; - irBuilderFlags.isBCMapinfoRequired = irm.getCompilationInterface().isBCMapInfoRequired(); + +} + +void IRBuilder::init(IRManager* irm, TranslatorFlags* traFlags, MemoryManager& tmpMM) { + IRBuilderAction* myAction = (IRBuilderAction*)getAction(); + irBuilderFlags = myAction->getFlags(); //copy of flags + + irManager=irm; + opndManager=&irm->getOpndManager(); + typeManager = &irm->getTypeManager(); + instFactory = &irm->getInstFactory(); + flowGraph = &irm->getFlowGraph(); + translatorFlags = traFlags; + MemoryManager& mm = irm->getMemoryManager(); + cseHashTable = new (tmpMM) CSEHashTable(mm); + + simplifier = new (mm) IRBuilderSimplifier(*this); + + CompilationInterface* ci = getCompilationContext()->getVMCompilationInterface(); + irBuilderFlags.insertWriteBarriers = ci->insertWriteBarriers(); + irBuilderFlags.isBCMapinfoRequired = ci->isBCMapInfoRequired(); + irBuilderFlags.compressedReferences = irBuilderFlags.compressedReferences || ci->areReferencesCompressed(); if (irBuilderFlags.isBCMapinfoRequired) { - MethodDesc* meth = irm.getCompilationInterface().getMethodToCompile(); - bc2HIRmapHandler = new(irm.getMemoryManager()) VectorHandler(bcOffset2HIRHandlerName, meth); -//#ifdef _DEBUG -// lostBCMapOffsetHandler = new(tempMemoryManager) MapHandler(lostBCOffsetHandlerName, meth); -//#endif + MethodDesc* meth = irm->getCompilationInterface().getMethodToCompile(); + bc2HIRmapHandler = new(irm->getMemoryManager()) VectorHandler(bcOffset2HIRHandlerName, meth); } } + void IRBuilder::invalid() { - Log::cat_opt()->error << " !!!! ---- IRBuilder::invalid ---- !!!! " << ::std::endl; + Log::out() << " !!!! ---- IRBuilder::invalid ---- !!!! " << ::std::endl; assert(0); } @@ -73,13 +321,17 @@ Inst* IRBuilder::appendInst(Inst* inst) if (irBuilderFlags.isBCMapinfoRequired) { //POINTER_SIZE_INT instAddr = (POINTER_SIZE_INT) inst; uint64 instID = inst->getId(); - bc2HIRmapHandler->setVectorEntry(instID, offset); + if (irBuilderFlags.fullBcMap) { + bc2HIRmapHandler->setVectorEntry(instID, offset); + } else if (inst->asMethodCallInst()) { + bc2HIRmapHandler->setVectorEntry(instID, offset); + } //#ifdef _DEBUG // lostBCMapOffsetHandler->setMapEntry((uint64) offset, 0x01); //#endif } - inst->insertBefore(currentLabel); - if(Log::cat_opt()->isDebugEnabled()) { + currentLabel->getNode()->appendInst(inst); + if(Log::isEnabled()) { inst->print(Log::out()); Log::out() << ::std::endl; Log::out().flush(); @@ -88,13 +340,13 @@ Inst* IRBuilder::appendInst(Inst* inst) } void IRBuilder::killCSE() { - cseHashTable.kill(); + cseHashTable->kill(); } void IRBuilder::genLabel(LabelInst* labelInst) { - cseHashTable.kill(); + cseHashTable->kill(); currentLabel = labelInst; - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { currentLabel->print(Log::out()); Log::out() << ::std::endl; Log::out().flush(); @@ -103,7 +355,7 @@ void IRBuilder::genLabel(LabelInst* labe void IRBuilder::genFallThroughLabel(LabelInst* labelInst) { currentLabel = labelInst; - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { currentLabel->print(Log::out()); Log::out() << ::std::endl; Log::out().flush(); @@ -111,22 +363,21 @@ void IRBuilder::genFallThroughLabel(Labe } LabelInst* IRBuilder::createLabel() { - currentLabel = (LabelInst*)instFactory.makeLabel(); + currentLabel = (LabelInst*)instFactory->makeLabel(); return currentLabel; } void IRBuilder::createLabels(uint32 numLabels, LabelInst** labels) { for (uint32 i=0; i<numLabels; i++) { - labels[i] = (LabelInst*)instFactory.makeLabel(); + labels[i] = (LabelInst*)instFactory->makeLabel(); } } LabelInst* IRBuilder::genMethodEntryLabel(MethodDesc* methodDesc) { - LabelInst* labelInst = - instFactory.makeMethodEntryLabel(methodDesc); + LabelInst* labelInst = instFactory->makeMethodEntryLabel(methodDesc); currentLabel = labelInst; - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { currentLabel->print(Log::out()); Log::out() << ::std::endl; Log::out().flush(); @@ -137,20 +388,20 @@ LabelInst* IRBuilder::genMethodEntryLabe void IRBuilder::genMethodEntryMarker(MethodDesc* methodDesc) { if (! irBuilderFlags.insertMethodLabels) return; - appendInst(instFactory.makeMethodMarker(MethodMarkerInst::Entry, methodDesc)); + appendInst(instFactory->makeMethodMarker(MethodMarkerInst::Entry, methodDesc)); } -void IRBuilder::genMethodEndMarker(MethodDesc* methodDesc, Opnd *obj) { +void IRBuilder::genMethodEndMarker(MethodDesc* methodDesc, Opnd *obj, Opnd *retOpnd) { if (! irBuilderFlags.insertMethodLabels) return; assert(obj && !obj->isNull()); - appendInst(instFactory.makeMethodMarker(MethodMarkerInst::Exit, methodDesc, obj)); + appendInst(instFactory->makeMethodMarker(MethodMarkerInst::Exit, methodDesc, obj, retOpnd)); } -void IRBuilder::genMethodEndMarker(MethodDesc* methodDesc) { +void IRBuilder::genMethodEndMarker(MethodDesc* methodDesc, Opnd *retOpnd) { if (! irBuilderFlags.insertMethodLabels) return; - appendInst(instFactory.makeMethodMarker(MethodMarkerInst::Exit, methodDesc)); + appendInst(instFactory->makeMethodMarker(MethodMarkerInst::Exit, methodDesc, retOpnd)); } // compute instructions @@ -164,11 +415,11 @@ IRBuilder::genAdd(Type* dstType, Modifie if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyAdd(dstType, mod, src1, src2); + dst = simplifier->simplifyAdd(dstType, mod, src1, src2); } if (!dst) { dst = createOpnd(dstType); - Inst *newi = instFactory.makeAdd(mod, dst, src1, src2); + Inst *newi = instFactory->makeAdd(mod, dst, src1, src2); appendInst(newi); } insertHash(hashcode, src1, src2, dst->getInst()); @@ -185,11 +436,11 @@ IRBuilder::genMul(Type* dstType, Modifie if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyMul(dstType, mod, src1, src2); + dst = simplifier->simplifyMul(dstType, mod, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeMul(mod, dst, src1, src2)); + appendInst(instFactory->makeMul(mod, dst, src1, src2)); } insertHash(hashcode, src1, src2, dst->getInst()); return dst; @@ -205,11 +456,11 @@ IRBuilder::genSub(Type* dstType, Modifie if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifySub(dstType, mod, src1, src2); + dst = simplifier->simplifySub(dstType, mod, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeSub(mod, dst, src1, src2)); + appendInst(instFactory->makeSub(mod, dst, src1, src2)); } insertHash(hashcode, src1, src2, dst->getInst()); return dst; @@ -230,11 +481,11 @@ IRBuilder::genDiv(Type* dstType, Modifie if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); + dst = simplifier->simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeTauDiv(mod, dst, src1, src2, tauDivOk)); + appendInst(instFactory->makeTauDiv(mod, dst, src1, src2, tauDivOk)); } insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash return dst; @@ -265,11 +516,11 @@ IRBuilder::genCliDiv(Type* dstType, Modi tauDivOk = genTauSafe(); // safe by construction } if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); + dst = simplifier->simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeTauDiv(mod, dst, src1, src2, tauDivOk)); + appendInst(instFactory->makeTauDiv(mod, dst, src1, src2, tauDivOk)); } insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash return dst; @@ -293,11 +544,11 @@ IRBuilder::genRem(Type* dstType, Modifie tauDivOk = genTauSafe(); // safe by construction if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauRem(dstType, mod, src1, src2, tauDivOk); + dst = simplifier->simplifyTauRem(dstType, mod, src1, src2, tauDivOk); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeTauRem(mod, dst, src1, src2, tauDivOk)); + appendInst(instFactory->makeTauRem(mod, dst, src1, src2, tauDivOk)); } insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash return dst; @@ -329,12 +580,12 @@ IRBuilder::genCliRem(Type* dstType, Modi tauDivOk = genTauSafe(); // safe by construction if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauRem(dstType, mod, src1, src2, tauDivOk); + dst = simplifier->simplifyTauRem(dstType, mod, src1, src2, tauDivOk); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeTauRem(mod, dst, src1, src2, tauDivOk)); + appendInst(instFactory->makeTauRem(mod, dst, src1, src2, tauDivOk)); } insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash return dst; @@ -349,11 +600,11 @@ IRBuilder::genNeg(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyNeg(dstType, src); + dst = simplifier->simplifyNeg(dstType, src); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeNeg(dst, src)); + appendInst(instFactory->makeNeg(dst, src)); } insertHash(Op_Neg, src, dst->getInst()); return dst; @@ -369,11 +620,11 @@ IRBuilder::genMulHi(Type* dstType, Modif if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyMulHi(dstType, mod, src1, src2); + dst = simplifier->simplifyMulHi(dstType, mod, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeMulHi(mod, dst, src1, src2)); + appendInst(instFactory->makeMulHi(mod, dst, src1, src2)); } insertHash(hashcode, src1, src2, dst->getInst()); return dst; @@ -393,18 +644,18 @@ IRBuilder::genMin(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyMin(dstType, src1, src2); + dst = simplifier->simplifyMin(dstType, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeMin(dst, src1, src2)); + appendInst(instFactory->makeMin(dst, src1, src2)); } insertHash(hashcode, src1, src2, dst->getInst()); return dst; } else { // hand-build it - Type* cmpDstType = typeManager.getInt32Type(); + Type* cmpDstType = typeManager->getInt32Type(); Type::Tag typeTag = dstType->tag; switch (typeTag) { case Type::Int32: @@ -476,17 +727,17 @@ IRBuilder::genMax(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyMax(dstType, src1, src2); + dst = simplifier->simplifyMax(dstType, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeMax(dst, src1, src2)); + appendInst(instFactory->makeMax(dst, src1, src2)); } insertHash(hashcode, src1, src2, dst->getInst()); return dst; } else { Type::Tag typeTag = dstType->tag; - Type* cmpDstType = typeManager.getInt32Type(); + Type* cmpDstType = typeManager->getInt32Type(); switch (typeTag) { case Type::Int32: case Type::Int64: @@ -548,11 +799,11 @@ IRBuilder::genAbs(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyAbs(dstType, src1); + dst = simplifier->simplifyAbs(dstType, src1); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeAbs(dst, src1)); + appendInst(instFactory->makeAbs(dst, src1)); } insertHash(hashcode, src1, dst->getInst()); return dst; @@ -560,7 +811,7 @@ IRBuilder::genAbs(Type* dstType, Opnd* s // hand-build it Type::Tag typeTag = src1->getType()->tag; - Type* cmpDstType = typeManager.getInt32Type(); + Type* cmpDstType = typeManager->getInt32Type(); switch (typeTag) { case Type::Int32: case Type::Int64: @@ -607,11 +858,11 @@ IRBuilder::genAnd(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyAnd(dstType, src1, src2); + dst = simplifier->simplifyAnd(dstType, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeAnd(dst, src1, src2)); + appendInst(instFactory->makeAnd(dst, src1, src2)); } insertHash(Op_And, src1, src2, dst->getInst()); return dst; @@ -624,11 +875,11 @@ IRBuilder::genOr(Type* dstType, Opnd* sr if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyOr(dstType, src1, src2); + dst = simplifier->simplifyOr(dstType, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeOr(dst, src1, src2)); + appendInst(instFactory->makeOr(dst, src1, src2)); } insertHash(Op_Or, src1, src2, dst->getInst()); return dst; @@ -641,11 +892,11 @@ IRBuilder::genXor(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyXor(dstType, src1, src2); + dst = simplifier->simplifyXor(dstType, src1, src2); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeXor(dst, src1, src2)); + appendInst(instFactory->makeXor(dst, src1, src2)); } insertHash(Op_Xor, src1, src2, dst->getInst()); return dst; @@ -657,11 +908,11 @@ IRBuilder::genNot(Type* dstType, Opnd* s if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyNot(dstType, src); + dst = simplifier->simplifyNot(dstType, src); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeNot(dst, src)); + appendInst(instFactory->makeNot(dst, src)); } insertHash(Op_Not, src, dst->getInst()); return dst; @@ -677,11 +928,11 @@ IRBuilder::genSelect(Type* dstType, Opnd if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifySelect(dstType, src1, src2, src3); + dst = simplifier->simplifySelect(dstType, src1, src2, src3); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeSelect(dst, src1, src2, src3)); + appendInst(instFactory->makeSelect(dst, src1, src2, src3)); } insertHash(Op_Select, src1, src2, src3, dst->getInst()); return dst; @@ -700,11 +951,11 @@ IRBuilder::genConv(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyConv(dstType, toType, ovfMod, src); + dst = simplifier->simplifyConv(dstType, toType, ovfMod, src); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeConv(ovfMod, toType, dst, src)); + appendInst(instFactory->makeConv(ovfMod, toType, dst, src)); } insertHash(hashcode, src->getId(), dst->getInst()); return dst; @@ -723,11 +974,11 @@ IRBuilder::genShladd(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyShladd(dstType, value, shiftAmount, addTo); + dst = simplifier->simplifyShladd(dstType, value, shiftAmount, addTo); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeShladd(dst, value, shiftAmount, addTo)); + appendInst(instFactory->makeShladd(dst, value, shiftAmount, addTo)); } insertHash(Op_Shladd, value, shiftAmount, addTo, dst->getInst()); return dst; @@ -747,11 +998,11 @@ IRBuilder::genShl(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyShl(dstType, mod, value, shiftAmount); + dst = simplifier->simplifyShl(dstType, mod, value, shiftAmount); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeShl(mod, dst, value, shiftAmount)); + appendInst(instFactory->makeShl(mod, dst, value, shiftAmount)); } insertHash(hashcode, value, shiftAmount, dst->getInst()); return dst; @@ -771,11 +1022,11 @@ IRBuilder::genShr(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyShr(dstType, mods, value, shiftAmount); + dst = simplifier->simplifyShr(dstType, mods, value, shiftAmount); } if (!dst) { dst = createOpnd(dstType); - appendInst(instFactory.makeShr(mods, dst, value, shiftAmount)); + appendInst(instFactory->makeShr(mods, dst, value, shiftAmount)); } insertHash(hashcode, value, shiftAmount, dst->getInst()); return dst; @@ -797,12 +1048,12 @@ IRBuilder::genPredCmp(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyPredCmp(dstType, instType, mod, src1, src2); + dst = simplifier->simplifyPredCmp(dstType, instType, mod, src1, src2); } if (!dst) { // result of comparison is always a 32-bit int dst = createOpnd(dstType); - Inst *i = instFactory.makePredCmp(mod, instType, dst, src1, src2); + Inst *i = instFactory->makePredCmp(mod, instType, dst, src1, src2); appendInst(i); } insertHash(hashcode, src1, src2, dst->getInst()); @@ -825,12 +1076,12 @@ IRBuilder::genCmp(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyCmp(dstType, instType, mod, src1, src2); + dst = simplifier->simplifyCmp(dstType, instType, mod, src1, src2); } if (!dst) { // result of comparison is always a 32-bit int dst = createOpnd(dstType); - Inst *i = instFactory.makeCmp(mod, instType, dst, src1, src2); + Inst *i = instFactory->makeCmp(mod, instType, dst, src1, src2); appendInst(i); } insertHash(hashcode, src1, src2, dst->getInst()); @@ -857,13 +1108,13 @@ IRBuilder::genCmp3(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyCmp3(dstType, instType, mod, + dst = simplifier->simplifyCmp3(dstType, instType, mod, src1, src2); } if (!dst) { // result of comparison is always a 32-bit int dst = createOpnd(dstType); - Inst* i = instFactory.makeCmp3(mod, instType, dst, src1, src2); + Inst* i = instFactory->makeCmp3(mod, instType, dst, src1, src2); appendInst(i); } insertHash(hashcode, src1, src2, dst->getInst()); @@ -883,12 +1134,12 @@ IRBuilder::genBranch(Type::Tag instType, // bad modifier invalid(); if (irBuilderFlags.doSimplify) { - if (simplifier.simplifyBranch(instType, mod, label, src1, src2)) { + if (simplifier->simplifyBranch(instType, mod, label, src1, src2)) { // simplified branch was emitted; return; } } - appendInst(instFactory.makeBranch(mod, instType, src1, src2, label)); + appendInst(instFactory->makeBranch(mod, instType, src1, src2, label)); } void @@ -901,12 +1152,12 @@ IRBuilder::genBranch(Type::Tag instType, // bad modifier invalid(); if (irBuilderFlags.doSimplify) { - if (simplifier.simplifyBranch(instType, mod, label, src)) { + if (simplifier->simplifyBranch(instType, mod, label, src)) { // simplified branch was emitted; return; } } - appendInst(instFactory.makeBranch(mod, instType, src, label)); + appendInst(instFactory->makeBranch(mod, instType, src, label)); } void @@ -914,23 +1165,23 @@ IRBuilder::genPredBranch(LabelInst* labe Opnd* src) { src = propagateCopy(src); if (irBuilderFlags.doSimplify) { - if (simplifier.simplifyPredBranch(label, src)) { + if (simplifier->simplifyPredBranch(label, src)) { // simplified branch was emitted; return; } } - appendInst(instFactory.makePredBranch(src, label)); + appendInst(instFactory->makePredBranch(src, label)); } void IRBuilder::genJump(LabelInst* label) { - appendInst(instFactory.makeJump(label)); + appendInst(instFactory->makeJump(label)); } void IRBuilder::genJSR(LabelInst* label) { - appendInst(instFactory.makeJSR(label)); + appendInst(instFactory->makeJSR(label)); } void @@ -939,63 +1190,63 @@ IRBuilder::genSwitch(uint32 nLabels, LabelInst* defaultLabel, Opnd* src) { src = propagateCopy(src); - appendInst(instFactory.makeSwitch(src, nLabels, labelInsts, defaultLabel)); + appendInst(instFactory->makeSwitch(src, nLabels, labelInsts, defaultLabel)); } void IRBuilder::genThrow(ThrowModifier mod, Opnd* exceptionObj) { exceptionObj = propagateCopy(exceptionObj); - appendInst(instFactory.makeThrow(mod, exceptionObj)); + appendInst(instFactory->makeThrow(mod, exceptionObj)); } void IRBuilder::genThrowSystemException(CompilationInterface::SystemExceptionId id) { - appendInst(instFactory.makeThrowSystemException(id)); + appendInst(instFactory->makeThrowSystemException(id)); } void IRBuilder::genThrowLinkingException(Class_Handle encClass, uint32 CPIndex, uint32 operation) { - appendInst(instFactory.makeThrowLinkingException(encClass, CPIndex, operation)); + appendInst(instFactory->makeThrowLinkingException(encClass, CPIndex, operation)); } Opnd* IRBuilder::genCatch(Type* exceptionType) { Opnd* dst = createOpnd(exceptionType); - appendInst(instFactory.makeCatch(dst)); + appendInst(instFactory->makeCatch(dst)); return dst; } Opnd* IRBuilder::genSaveRet() { - Opnd *dst = createOpnd(typeManager.getIntPtrType()); - appendInst(instFactory.makeSaveRet(dst)); + Opnd *dst = createOpnd(typeManager->getIntPtrType()); + appendInst(instFactory->makeSaveRet(dst)); return dst; } void IRBuilder::genEndFinally() { - appendInst(instFactory.makeEndFinally()); + appendInst(instFactory->makeEndFinally()); } void IRBuilder::genEndFilter() { - appendInst(instFactory.makeEndFilter()); + appendInst(instFactory->makeEndFilter()); } void IRBuilder::genEndCatch() { - appendInst(instFactory.makeEndCatch()); + appendInst(instFactory->makeEndCatch()); } void IRBuilder::genLeave(LabelInst* label) { - appendInst(instFactory.makeLeave(label)); + appendInst(instFactory->makeLeave(label)); } Opnd* IRBuilder::genPrefetch(Opnd *base, Opnd *offset, Opnd *hints) { - Opnd *dst = createOpnd(typeManager.getVoidType()); - appendInst(instFactory.makePrefetch(propagateCopy(base), propagateCopy(offset), + Opnd *dst = createOpnd(typeManager->getVoidType()); + appendInst(instFactory->makePrefetch(propagateCopy(base), propagateCopy(offset), propagateCopy(hints))); return dst; } @@ -1008,7 +1259,7 @@ IRBuilder::genDirectCall(MethodDesc* met Opnd* tauTypesChecked, uint32 numArgs, Opnd* args[], - InlineInfoBuilder* inlineInfoBuilder) // NULL if this call is not inlined + InlineInfoBuilder* inlineInfoBuilder) // NULL if this call is not inlined { if (!tauNullCheckedFirstArg) tauNullCheckedFirstArg = genTauUnsafe(); @@ -1029,7 +1280,7 @@ IRBuilder::genDirectCall(MethodDesc* met args[i] = propagateCopy(args[i]); } Opnd* dst = createOpnd(returnType); - appendInstUpdateInlineInfo(instFactory.makeDirectCall(dst, + appendInstUpdateInlineInfo(instFactory->makeDirectCall(dst, tauNullCheckedFirstArg, tauTypesChecked, numArgs, args, methodDesc), @@ -1048,7 +1299,7 @@ IRBuilder::genTauVirtualCall(MethodDesc* Opnd* tauTypesChecked, uint32 numArgs, Opnd* args[], - InlineInfoBuilder* inlineInfoBuilder) // NULL if this call is not inlined + InlineInfoBuilder* inlineInfoBuilder) // NULL if this call is not inlined { if(!methodDesc->isVirtual()) // Must de-virtualize - no vtable @@ -1075,13 +1326,13 @@ IRBuilder::genTauVirtualCall(MethodDesc* tauTypesChecked = propagateCopy(tauTypesChecked); } if (irBuilderFlags.doSimplify) { - Opnd *dst = simplifier.simplifyTauVirtualCall(methodDesc, - returnType, - tauNullCheckedFirstArg, - tauTypesChecked, - numArgs, - args, - inlineInfoBuilder); + Opnd *dst = simplifier->simplifyTauVirtualCall(methodDesc, + returnType, + tauNullCheckedFirstArg, + tauTypesChecked, + numArgs, + args, + inlineInfoBuilder); if (dst) return dst; } @@ -1096,7 +1347,7 @@ IRBuilder::genTauVirtualCall(MethodDesc* inlineInfoBuilder); } Opnd *dst = createOpnd(returnType); - appendInstUpdateInlineInfo(instFactory.makeTauVirtualCall(dst, + appendInstUpdateInlineInfo(instFactory->makeTauVirtualCall(dst, tauNullCheckedFirstArg, tauTypesChecked, numArgs, args, @@ -1128,7 +1379,7 @@ IRBuilder::genIntrinsicCall(IntrinsicCal tauTypesChecked = propagateCopy(tauTypesChecked); } - appendInst(instFactory.makeIntrinsicCall(dst, intrinsicId, + appendInst(instFactory->makeIntrinsicCall(dst, intrinsicId, tauNullCheckedRefArgs, tauTypesChecked, numArgs, args)); @@ -1144,7 +1395,7 @@ IRBuilder::genJitHelperCall(JitHelperCal args[i] = propagateCopy(args[i]); } Opnd * dst = createOpnd(returnType); - appendInst(instFactory.makeJitHelperCall(dst, helperId, numArgs, args)); + appendInst(instFactory->makeJitHelperCall(dst, helperId, numArgs, args)); return dst; } @@ -1157,7 +1408,7 @@ IRBuilder::genVMHelperCall(VMHelperCallI args[i] = propagateCopy(args[i]); } Opnd * dst = createOpnd(returnType); - appendInst(instFactory.makeVMHelperCall(dst, helperId, numArgs, args)); + appendInst(instFactory->makeVMHelperCall(dst, helperId, numArgs, args)); return dst; } @@ -1170,8 +1421,8 @@ IRBuilder::genTauTypeCompare(Opnd *arg0, // Note that we use the methodDesc's type to obtain the vtable which contains the pointer // to the method. This may be an interface vtable. genLdVTable figures out which. Opnd* vtableThis = genLdVTable(arg0, type); - Opnd* vtableClass = createOpnd(typeManager.getVTablePtrType(type)); - appendInst(instFactory.makeGetVTableAddr(vtableClass, (ObjectType*)type)); + Opnd* vtableClass = createOpnd(typeManager->getVTablePtrType(type)); + appendInst(instFactory->makeGetVTableAddr(vtableClass, (ObjectType*)type)); genBranch(Type::VTablePtr, Cmp_EQ, target, vtableThis, vtableClass); } @@ -1195,11 +1446,11 @@ IRBuilder::genIndirectCall(Type* returnT else tauNullCheckedFirstArg = propagateCopy(tauNullCheckedFirstArg); if (!tauTypesChecked) - tauTypesChecked = genTauUnsafe(); + tauTypesChecked = genTauUnsafe(); else tauTypesChecked = propagateCopy(tauTypesChecked); - appendInstUpdateInlineInfo(instFactory.makeIndirectCall(dst, funAddr, + appendInstUpdateInlineInfo(instFactory->makeIndirectCall(dst, funAddr, tauNullCheckedFirstArg, tauTypesChecked, numArgs, args), @@ -1231,7 +1482,7 @@ IRBuilder::genIndirectMemoryCall(Type* r tauTypesChecked = propagateCopy(tauTypesChecked); Opnd* dst = createOpnd(returnType); - appendInstUpdateInlineInfo(instFactory.makeIndirectMemoryCall(dst, funAddr, + appendInstUpdateInlineInfo(instFactory->makeIndirectMemoryCall(dst, funAddr, tauNullCheckedFirstArg, tauTypesChecked, numArgs, @@ -1244,22 +1495,22 @@ IRBuilder::genIndirectMemoryCall(Type* r void IRBuilder::genReturn(Opnd* src, Type* retType) { src = propagateCopy(src); - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { if (retType != src->getType()) { UNIMPLEMENTED("ret type check"); } } - appendInst(instFactory.makeReturn(src)); + appendInst(instFactory->makeReturn(src)); } void IRBuilder::genReturn() { - appendInst(instFactory.makeReturn()); + appendInst(instFactory->makeReturn()); } void IRBuilder::genRet(Opnd* src) { - appendInst(instFactory.makeRet(src)); + appendInst(instFactory->makeRet(src)); } // Move instruction @@ -1267,7 +1518,7 @@ Opnd* IRBuilder::genCopy(Opnd* src) { src = propagateCopy(src); Opnd* dst = createOpnd(src->getType()); - appendInst(instFactory.makeCopy(dst, src)); + appendInst(instFactory->makeCopy(dst, src)); return dst; } @@ -1282,8 +1533,8 @@ IRBuilder::genArgCoercion(Type* argType, // actual parameter and variable definitions Opnd* IRBuilder::genArgDef(Modifier mod, Type* type) { - Opnd* dst = opndManager.createArgOpnd(type); - appendInst(instFactory.makeDefArg(mod, dst)); + Opnd* dst = opndManager->createArgOpnd(type); + appendInst(instFactory->makeDefArg(mod, dst)); DefArgModifier defMod = mod.getDefArgModifier(); switch (defMod) { case NonNullThisArg: @@ -1307,7 +1558,7 @@ IRBuilder::genArgDef(Modifier mod, Type* VarOpnd* IRBuilder::genVarDef(Type* type, bool isPinned) { - return opndManager.createVarOpnd(type, isPinned); + return opndManager->createVarOpnd(type, isPinned); } // Phi-node instruction @@ -1317,7 +1568,7 @@ IRBuilder::genPhi(uint32 numArgs, Opnd* args[i] = propagateCopy(args[i]); } Opnd* dst = createOpnd(args[0]->getType()); - appendInst(instFactory.makePhi(dst, numArgs, args)); + appendInst(instFactory->makePhi(dst, numArgs, args)); return dst; } @@ -1327,7 +1578,7 @@ IRBuilder::genTauPi(Opnd *src, Opnd *tau src = propagateCopy(src); tau = propagateCopy(tau); PiOpnd* dst = createPiOpnd(src); - appendInst(instFactory.makeTauPi(dst, src, tau, cond)); + appendInst(instFactory->makeTauPi(dst, src, tau, cond)); return dst; } @@ -1338,8 +1589,8 @@ IRBuilder::genLdConstant(int32 val) { uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, (uint32) val); if (dst) return dst; - dst = createOpnd(typeManager.getInt32Type()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getInt32Type()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, (uint32) val, dst->getInst()); return dst; } @@ -1349,8 +1600,8 @@ IRBuilder::genLdConstant(int64 val) { uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, (uint32) (val >> 32), (uint32) (val & 0xffffffff)); if (dst) return dst; - dst = createOpnd(typeManager.getInt64Type()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getInt64Type()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, (uint32) (val >> 32), (uint32) (val & 0xffffffff), dst->getInst()); return dst; } @@ -1363,8 +1614,8 @@ Opnd* IRBuilder::genLdConstant(float val uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, word1, word2); if (dst) return dst; - dst = createOpnd(typeManager.getSingleType()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getSingleType()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, word1, word2, dst->getInst()); return dst; } @@ -1378,8 +1629,8 @@ IRBuilder::genLdConstant(double val) { uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, word1, word2); if (dst) return dst; - dst = createOpnd(typeManager.getDoubleType()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getDoubleType()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, word1, word2, dst->getInst()); return dst; } @@ -1392,7 +1643,7 @@ IRBuilder::genLdConstant(Type *ptrtype, Opnd* dst = lookupHash(hashcode, word1, word2); if (dst) return dst; dst = createOpnd(ptrtype); - appendInst(instFactory.makeLdConst(dst, val)); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, word1, word2, dst->getInst()); return dst; } @@ -1406,8 +1657,8 @@ IRBuilder::genLdFloatConstant(double val uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, word1, word2); if (dst) return dst; - dst = createOpnd(typeManager.getFloatType()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getFloatType()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, word1, word2, dst->getInst()); return dst; } @@ -1423,8 +1674,8 @@ IRBuilder::genLdFloatConstant(float val) uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode, word1, word2); if (dst) return dst; - dst = createOpnd(typeManager.getFloatType()); - appendInst(instFactory.makeLdConst(dst, val)); + dst = createOpnd(typeManager->getFloatType()); + appendInst(instFactory->makeLdConst(dst, val)); insertHash(hashcode, word1, word2, dst->getInst()); return dst; } @@ -1434,27 +1685,27 @@ IRBuilder::genLdNull() { uint32 hashcode = operation.encodeForHashing(); Opnd* dst = lookupHash(hashcode); if (dst) return dst; - dst = createOpnd(typeManager.getNullObjectType()); - appendInst(instFactory.makeLdNull(dst)); + dst = createOpnd(typeManager->getNullObjectType()); + appendInst(instFactory->makeLdNull(dst)); insertHash(hashcode, dst->getInst()); return dst; } Opnd* -IRBuilder::genLdString(MethodDesc* enclosingMethod, uint32 stringToken) { +IRBuilder::genLdRef(MethodDesc* enclosingMethod, uint32 stringToken, Type* type) { bool uncompress = irBuilderFlags.compressedReferences; Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; - Opnd* dst = createOpnd(typeManager.getSystemStringType()); + Opnd* dst = createOpnd(type); - appendInst(instFactory.makeLdString(mod, dst, enclosingMethod, stringToken)); + appendInst(instFactory->makeLdRef(mod, dst, enclosingMethod, stringToken)); return dst; } Opnd* IRBuilder::genLdToken(MethodDesc* enclosingMethod, uint32 metadataToken) { - Opnd* dst = createOpnd(typeManager.getSystemObjectType()); - appendInst(instFactory.makeLdToken(dst, enclosingMethod, metadataToken)); + Opnd* dst = createOpnd(typeManager->getSystemObjectType()); + appendInst(instFactory->makeLdToken(dst, enclosingMethod, metadataToken)); return dst; } @@ -1465,12 +1716,12 @@ IRBuilder::genLdVar(Type* dstType, VarOp if (dst) return dst; dst = createOpnd(dstType); - appendInst(instFactory.makeLdVar(dst, var)); + appendInst(instFactory->makeLdVar(dst, var)); insertHash(Op_LdVar, var, dst->getInst()); return dst; } else { Opnd *dst = createOpnd(dstType); - appendInst(instFactory.makeLdVar(dst, var)); + appendInst(instFactory->makeLdVar(dst, var)); return dst; } } @@ -1482,8 +1733,8 @@ IRBuilder::genLdVarAddr(VarOpnd* var) { var->setAddrTaken(); - dst = createOpnd(typeManager.getManagedPtrType(var->getType())); - appendInst(instFactory.makeLdVarAddr(dst, var)); + dst = createOpnd(typeManager->getManagedPtrType(var->getType())); + appendInst(instFactory->makeLdVarAddr(dst, var)); insertHash(Op_LdVarAddr, var, dst->getInst()); return dst; } @@ -1511,17 +1762,17 @@ IRBuilder::genTauLdInd(Modifier mod, Typ tauBaseNonNull = propagateCopy(tauBaseNonNull); tauAddressInRange = propagateCopy(tauAddressInRange); Opnd* dst = createOpnd(type); - appendInst(instFactory.makeTauLdInd(mod, ldType, dst, ptr, + appendInst(instFactory->makeTauLdInd(mod, ldType, dst, ptr, tauBaseNonNull, tauAddressInRange)); return dst; } Opnd* -IRBuilder::genLdString(Modifier mod, Type* type, - uint32 token, MethodDesc *enclosingMethod) +IRBuilder::genLdRef(Modifier mod, Type* type, + uint32 token, MethodDesc *enclosingMethod) { Opnd* dst = createOpnd(type); - appendInst(instFactory.makeLdString(mod, dst, enclosingMethod, token)); + appendInst(instFactory->makeLdRef(mod, dst, enclosingMethod, token)); return dst; } @@ -1547,7 +1798,7 @@ IRBuilder::genLdField(Type* type, Opnd* } Opnd* dst = createOpnd(type); - appendInst(instFactory.makeTauLdField(mod, type, dst, base, + appendInst(instFactory->makeTauLdField(mod, type, dst, base, tauNullCheck, tauAddressInRange, fieldDesc)); return dst; @@ -1561,7 +1812,7 @@ IRBuilder::genInitType(NamedType* type) if (opnd) return; // no need to re-initialize insertHash(Op_InitType, type->getId(), - appendInst(instFactory.makeInitType(type))); + appendInst(instFactory->makeInitType(type))); } Opnd* @@ -1581,13 +1832,17 @@ IRBuilder::genLdStatic(Type* type, Field } Opnd* dst = createOpnd(type); - appendInst(instFactory.makeLdStatic(mod, type, dst, fieldDesc)); + appendInst(instFactory->makeLdStatic(mod, type, dst, fieldDesc)); return dst; } Opnd* -IRBuilder::genLdElem(Type* type, Opnd* array, Opnd* index) { +IRBuilder::genLdElem(Type* type, Opnd* array, Opnd* index, Opnd* tauNullChecked, Opnd* tauAddressInRange) { + + assert(tauNullChecked); + assert(tauAddressInRange); + array = propagateCopy(array); index = propagateCopy(index); @@ -1598,22 +1853,31 @@ IRBuilder::genLdElem(Type* type, Opnd* a } Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; - Opnd *tauNullCheck = genTauCheckNull(array); - Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullCheck); - Opnd *tauBaseTypeChecked = genTauHasType(array, array->getType()); - Opnd *tauAddressInRange = genTauAnd(tauBoundsChecked, tauBaseTypeChecked); - if (irBuilderFlags.expandMemAddrs) { return genTauLdInd(mod, type, type->tag, genLdElemAddrNoChecks(type, array, index), - tauNullCheck, tauAddressInRange); + tauNullChecked, tauAddressInRange); } Opnd* dst = createOpnd(type); - appendInst(instFactory.makeTauLdElem(mod, type, dst, array, index, - tauNullCheck, tauAddressInRange)); + appendInst(instFactory->makeTauLdElem(mod, type, dst, array, index, + tauNullChecked, tauAddressInRange)); return dst; } +Opnd* +IRBuilder::genLdElem(Type* type, Opnd* array, Opnd* index) { + + array = propagateCopy(array); + index = propagateCopy(index); + + Opnd *tauNullChecked = genTauCheckNull(array); + Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullChecked); + Opnd *tauBaseTypeChecked = genTauHasType(array, array->getType()); + Opnd *tauAddressInRange = genTauAnd(tauBoundsChecked, tauBaseTypeChecked); + + return genLdElem(type,array,index,tauNullChecked,tauAddressInRange); +} + // this is now used just for CLI; the tauNonNull operand is ignored, but the // check should remain even after optimization. Opnd* @@ -1635,18 +1899,18 @@ IRBuilder::genLdFieldAddr(Type* type, Op if (base->getType()->isIntPtr()) { // unmanaged pointer - dst = createOpnd(typeManager.getIntPtrType()); + dst = createOpnd(typeManager->getIntPtrType()); } else if (irBuilderFlags.compressedReferences && type->isObject()) { // until VM type system is upgraded, // fieldDesc type will have uncompressed ref type; // compress it assert(!type->isCompressedReference()); - Type *compressedType = typeManager.compressType(type); - dst = createOpnd(typeManager.getManagedPtrType(compressedType)); + Type *compressedType = typeManager->compressType(type); + dst = createOpnd(typeManager->getManagedPtrType(compressedType)); } else { - dst = createOpnd(typeManager.getManagedPtrType(type)); + dst = createOpnd(typeManager->getManagedPtrType(type)); } - appendInst(instFactory.makeLdFieldAddr(dst, base, fieldDesc)); + appendInst(instFactory->makeLdFieldAddr(dst, base, fieldDesc)); insertHash(Op_LdFieldAddr, base->getId(), fieldDesc->getId(), dst->getInst()); return dst; @@ -1667,18 +1931,18 @@ IRBuilder::genLdFieldAddrNoChecks(Type* if (base->getType()->isIntPtr()) { // unmanaged pointer - dst = createOpnd(typeManager.getIntPtrType()); + dst = createOpnd(typeManager->getIntPtrType()); } else if (irBuilderFlags.compressedReferences && type->isObject()) { // until VM type system is upgraded, // fieldDesc type will have uncompressed ref type; // compress it assert(!type->isCompressedReference()); - Type *compressedType = typeManager.compressType(type); - dst = createOpnd(typeManager.getManagedPtrType(compressedType)); + Type *compressedType = typeManager->compressType(type); + dst = createOpnd(typeManager->getManagedPtrType(compressedType)); } else { - dst = createOpnd(typeManager.getManagedPtrType(type)); + dst = createOpnd(typeManager->getManagedPtrType(type)); } - appendInst(instFactory.makeLdFieldAddr(dst, base, fieldDesc)); + appendInst(instFactory->makeLdFieldAddr(dst, base, fieldDesc)); insertHash(Op_LdFieldAddr, base->getId(), fieldDesc->getId(), dst->getInst()); return dst; @@ -1698,18 +1962,18 @@ IRBuilder::genLdStaticAddrNoChecks(Type* if (fieldDesc->isUnmanagedStatic()) { // can't mark an unmanaged pointer as non-null - dst = createOpnd(typeManager.getIntPtrType()); + dst = createOpnd(typeManager->getIntPtrType()); } else if (irBuilderFlags.compressedReferences && type->isObject()) { // until VM type system is upgraded, // fieldDesc type will have uncompressed ref type; // compress it assert(!type->isCompressedReference()); - Type *compressedType = typeManager.compressType(type); - dst = createOpnd(typeManager.getManagedPtrType(compressedType)); + Type *compressedType = typeManager->compressType(type); + dst = createOpnd(typeManager->getManagedPtrType(compressedType)); } else { - dst = createOpnd(typeManager.getManagedPtrType(type)); + dst = createOpnd(typeManager->getManagedPtrType(type)); } - appendInst(instFactory.makeLdStaticAddr(dst, fieldDesc)); + appendInst(instFactory->makeLdStaticAddr(dst, fieldDesc)); insertHash(Op_LdStaticAddr, fieldDesc->getId(), dst->getInst()); return dst; } @@ -1746,12 +2010,12 @@ IRBuilder::genLdElemAddrNoChecks(Type* e // fieldDesc type will have uncompressed ref type; // compress it assert(!elemType->isCompressedReference()); - Type *compressedType = typeManager.compressType(elemType); - dst = createOpnd(typeManager.getManagedPtrType(compressedType)); + Type *compressedType = typeManager->compressType(elemType); + dst = createOpnd(typeManager->getManagedPtrType(compressedType)); } else { - dst = createOpnd(typeManager.getManagedPtrType(elemType)); + dst = createOpnd(typeManager->getManagedPtrType(elemType)); } - appendInst(instFactory.makeLdElemAddr(elemType, dst, array, index)); + appendInst(instFactory->makeLdElemAddr(elemType, dst, array, index)); insertHash(Op_LdElemAddr, array, index, dst->getInst()); } @@ -1763,8 +2027,8 @@ IRBuilder::genLdFunAddr(MethodDesc* meth Opnd* dst = lookupHash(Op_LdFunAddr, methodDesc->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getMethodPtrType(methodDesc)); - appendInst(instFactory.makeLdFunAddr(dst, methodDesc)); + dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); + appendInst(instFactory->makeLdFunAddr(dst, methodDesc)); insertHash(Op_LdFunAddr, methodDesc->getId(), dst->getInst()); return dst; } @@ -1775,8 +2039,8 @@ IRBuilder::genLdFunAddrSlot(MethodDesc* if (dst) return dst; - dst = createOpnd(typeManager.getMethodPtrType(methodDesc)); - appendInst(instFactory.makeLdFunAddrSlot(dst, methodDesc)); + dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); + appendInst(instFactory->makeLdFunAddrSlot(dst, methodDesc)); insertHash(Op_LdFunAddrSlot, methodDesc->getId(), dst->getInst()); return dst; } @@ -1803,11 +2067,11 @@ IRBuilder::genTauLdVTable(Opnd* base, Op if (irBuilderFlags.useNewTypeSystem) { NamedType* iType = type->asNamedType(); assert(iType); - dst = createOpnd(typeManager.getITablePtrObjType(obj, iType)); + dst = createOpnd(typeManager->getITablePtrObjType(obj, iType)); } else { - dst = createOpnd(typeManager.getVTablePtrType(type)); + dst = createOpnd(typeManager->getVTablePtrType(type)); } - appendInst(instFactory.makeTauLdIntfcVTableAddr(dst, base, tauNullChecked, type)); + appendInst(instFactory->makeTauLdIntfcVTableAddr(dst, base, type)); insertHash(Op_TauLdIntfcVTableAddr, base->getId(), type->getId(), dst->getInst()); } else if (type->isClass()) { @@ -1815,11 +2079,11 @@ IRBuilder::genTauLdVTable(Opnd* base, Op if (dst) return dst; if (irBuilderFlags.useNewTypeSystem) { - dst = createOpnd(typeManager.getVTablePtrObjType(obj)); + dst = createOpnd(typeManager->getVTablePtrObjType(obj)); } else { - dst = createOpnd(typeManager.getVTablePtrType(base->getType())); + dst = createOpnd(typeManager->getVTablePtrType(base->getType())); } - appendInst(instFactory.makeTauLdVTableAddr(dst, base, tauNullChecked)); + appendInst(instFactory->makeTauLdVTableAddr(dst, base, tauNullChecked)); insertHash(Op_TauLdVTableAddr, base, dst->getInst()); } else { assert(0); // shouldn't happen @@ -1833,8 +2097,8 @@ IRBuilder::genGetVTable(ObjectType* type Opnd* dst = lookupHash(Op_GetVTableAddr, type->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getVTablePtrType(type)); - appendInst(instFactory.makeGetVTableAddr(dst, type)); + dst = createOpnd(typeManager->getVTablePtrType(type)); + appendInst(instFactory->makeGetVTableAddr(dst, type)); insertHash(Op_GetVTableAddr, type->getId(), dst->getInst()); return dst; } @@ -1851,8 +2115,8 @@ IRBuilder::genLdVirtFunAddr(Opnd* base, Opnd* vtableOpnd = genTauLdVTable(base, tauNullChecked, methodType); Opnd *tauVtableHasMethod = genTauHasType(base, methodType); - dst = createOpnd(typeManager.getMethodPtrType(methodDesc)); - appendInst(instFactory.makeTauLdVirtFunAddr(dst, vtableOpnd, + dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); + appendInst(instFactory->makeTauLdVirtFunAddr(dst, vtableOpnd, tauVtableHasMethod, methodDesc)); insertHash(Op_TauLdVirtFunAddr, vtableOpnd->getId(), methodDesc->getId(), @@ -1874,11 +2138,11 @@ IRBuilder::genTauLdVirtFunAddrSlot(Opnd* if (irBuilderFlags.useNewTypeSystem) { SsaOpnd* obj = base->asSsaOpnd(); assert(obj); - dst = createOpnd(typeManager.getMethodPtrObjType(obj, methodDesc)); + dst = createOpnd(typeManager->getMethodPtrObjType(obj, methodDesc)); } else { - dst = createOpnd(typeManager.getMethodPtrType(methodDesc)); + dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); } - appendInst(instFactory.makeTauLdVirtFunAddrSlot(dst, vtableOpnd, + appendInst(instFactory->makeTauLdVirtFunAddrSlot(dst, vtableOpnd, tauVtableHasMethod, methodDesc)); insertHash(Op_TauLdVirtFunAddrSlot, vtableOpnd->getId(), @@ -1894,7 +2158,7 @@ IRBuilder::genArrayLen(Type* dstType, Ty if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauArrayLen(dstType, type, array); + dst = simplifier->simplifyTauArrayLen(dstType, type, array); if (dst) return dst; } @@ -1913,12 +2177,12 @@ IRBuilder::genTauArrayLen(Type* dstType, if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauArrayLen(dstType, type, array, tauNullChecked, + dst = simplifier->simplifyTauArrayLen(dstType, type, array, tauNullChecked, tauTypeChecked); if (dst) return dst; } dst = createOpnd(dstType); - appendInst(instFactory.makeTauArrayLen(dst, type, array, tauNullChecked, + appendInst(instFactory->makeTauArrayLen(dst, type, array, tauNullChecked, tauTypeChecked)); insertHash(Op_TauArrayLen, array->getId(), dst->getInst()); @@ -1935,7 +2199,7 @@ IRBuilder::genLdArrayBaseAddr(Type* elem if (irBuilderFlags.useNewTypeSystem) { SsaOpnd* arrayVal = array->asSsaOpnd(); assert(arrayVal); - Type* baseType = typeManager.getArrayBaseType(arrayVal); + Type* baseType = typeManager->getArrayBaseType(arrayVal); dst = createOpnd(baseType); } else { if (irBuilderFlags.compressedReferences && elemType->isObject()) { @@ -1943,13 +2207,13 @@ IRBuilder::genLdArrayBaseAddr(Type* elem // fieldDesc type will have uncompressed ref type; // compress it assert(!elemType->isCompressedReference()); - Type *compressedType = typeManager.compressType(elemType); - dst = createOpnd(typeManager.getManagedPtrType(compressedType)); + Type *compressedType = typeManager->compressType(elemType); + dst = createOpnd(typeManager->getManagedPtrType(compressedType)); } else { - dst = createOpnd(typeManager.getManagedPtrType(elemType)); + dst = createOpnd(typeManager->getManagedPtrType(elemType)); } } - appendInst(instFactory.makeLdArrayBaseAddr(elemType, dst, array)); + appendInst(instFactory->makeLdArrayBaseAddr(elemType, dst, array)); insertHash(Op_LdArrayBaseAddr, array, dst->getInst()); return dst; } @@ -1966,13 +2230,13 @@ IRBuilder::genAddScaledIndex(Opnd* ptr, assert(ptrType); SsaOpnd* indexVar = index->asSsaOpnd(); assert(indexVar); - Type* dstType = typeManager.getArrayIndexType(ptrType->getArrayName(), indexVar); + Type* dstType = typeManager->getArrayIndexType(ptrType->getArrayName(), indexVar); dst = createOpnd(dstType); } else { dst = createOpnd(ptr->getType()); } - appendInst(instFactory.makeAddScaledIndex(dst, ptr, index)); + appendInst(instFactory->makeAddScaledIndex(dst, ptr, index)); insertHash(Op_AddScaledIndex, ptr, index, dst->getInst()); return dst; } @@ -1984,8 +2248,8 @@ IRBuilder::genScaledDiffRef(Opnd* src1, Opnd* dst = lookupHash(Op_ScaledDiffRef, src1, src2); if (dst) return dst; - dst = createOpnd(typeManager.getInt32Type()); - appendInst(instFactory.makeScaledDiffRef(dst, src1, src2)); + dst = createOpnd(typeManager->getInt32Type()); + appendInst(instFactory->makeScaledDiffRef(dst, src1, src2)); insertHash(Op_ScaledDiffRef, src1, src2, dst->getInst()); return dst; } @@ -2000,8 +2264,8 @@ IRBuilder::genUncompressRef(Opnd *compre Type *comprefType = compref->getType(); assert(comprefType->isCompressedReference()); - dst = createOpnd(typeManager.uncompressType(comprefType)); - appendInst(instFactory.makeUncompressRef(dst, compref)); + dst = createOpnd(typeManager->uncompressType(comprefType)); + appendInst(instFactory->makeUncompressRef(dst, compref)); insertHash(Op_UncompressRef, compref, dst->getInst()); return dst; } @@ -2018,8 +2282,8 @@ IRBuilder::genCompressRef(Opnd *uncompre uncomprefType = uncompref->getType(); assert(uncomprefType->isReference() && !uncomprefType->isCompressedReference()); - dst = createOpnd(typeManager.compressType(uncomprefType)); - appendInst(instFactory.makeCompressRef(dst, uncompref)); + dst = createOpnd(typeManager->compressType(uncomprefType)); + appendInst(instFactory->makeCompressRef(dst, uncompref)); insertHash(Op_CompressRef, uncompref, dst->getInst()); return dst; } @@ -2033,8 +2297,8 @@ IRBuilder::genLdFieldOffset(FieldDesc* f if (dst) return dst; - dst = createOpnd(typeManager.getOffsetType()); - appendInst(instFactory.makeLdFieldOffset(dst, fieldDesc)); + dst = createOpnd(typeManager->getOffsetType()); + appendInst(instFactory->makeLdFieldOffset(dst, fieldDesc)); insertHash(Op_LdFieldOffset, fieldDesc->getId(), dst->getInst()); return dst; } @@ -2048,8 +2312,8 @@ IRBuilder::genLdFieldOffsetPlusHeapbase( if (dst) return dst; - dst = createOpnd(typeManager.getOffsetPlusHeapbaseType()); - appendInst(instFactory.makeLdFieldOffsetPlusHeapbase(dst, fieldDesc)); + dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); + appendInst(instFactory->makeLdFieldOffsetPlusHeapbase(dst, fieldDesc)); insertHash(Op_LdFieldOffsetPlusHeapbase, fieldDesc->getId(), dst->getInst()); return dst; } @@ -2060,8 +2324,8 @@ IRBuilder::genLdArrayBaseOffset(Type *el Opnd* dst = lookupHash(Op_LdArrayBaseOffset, elemType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getOffsetType()); - appendInst(instFactory.makeLdArrayBaseOffset(dst, elemType)); + dst = createOpnd(typeManager->getOffsetType()); + appendInst(instFactory->makeLdArrayBaseOffset(dst, elemType)); insertHash(Op_LdArrayBaseOffset, elemType->getId(), dst->getInst()); return dst; } @@ -2072,8 +2336,8 @@ IRBuilder::genLdArrayBaseOffsetPlusHeapb Opnd* dst = lookupHash(Op_LdArrayBaseOffsetPlusHeapbase, elemType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getOffsetPlusHeapbaseType()); - appendInst(instFactory.makeLdArrayBaseOffsetPlusHeapbase(dst, elemType)); + dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); + appendInst(instFactory->makeLdArrayBaseOffsetPlusHeapbase(dst, elemType)); insertHash(Op_LdArrayBaseOffsetPlusHeapbase, elemType->getId(), dst->getInst()); return dst; } @@ -2084,8 +2348,8 @@ IRBuilder::genLdArrayLenOffset(Type *ele Opnd* dst = lookupHash(Op_LdArrayLenOffset, elemType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getOffsetType()); - appendInst(instFactory.makeLdArrayLenOffset(dst, elemType)); + dst = createOpnd(typeManager->getOffsetType()); + appendInst(instFactory->makeLdArrayLenOffset(dst, elemType)); insertHash(Op_LdArrayLenOffset, elemType->getId(), dst->getInst()); return dst; } @@ -2096,8 +2360,8 @@ IRBuilder::genLdArrayLenOffsetPlusHeapba Opnd* dst = lookupHash(Op_LdArrayLenOffsetPlusHeapbase, elemType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getOffsetPlusHeapbaseType()); - appendInst(instFactory.makeLdArrayLenOffsetPlusHeapbase(dst, elemType)); + dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); + appendInst(instFactory->makeLdArrayLenOffsetPlusHeapbase(dst, elemType)); insertHash(Op_LdArrayLenOffsetPlusHeapbase, elemType->getId(), dst->getInst()); return dst; } @@ -2115,7 +2379,7 @@ IRBuilder::genAddOffset(Type *ptrType, O assert(offset->getType()->isOffset()); dst = createOpnd(ptrType); - appendInst(instFactory.makeAddOffset(dst, ref, offset)); + appendInst(instFactory->makeAddOffset(dst, ref, offset)); insertHash(Op_AddOffset, ref, offset, dst->getInst()); return dst; } @@ -2133,7 +2397,7 @@ IRBuilder::genAddOffsetPlusHeapbase(Type assert(offset->getType()->isOffsetPlusHeapbase()); dst = createOpnd(ptrType); - appendInst(instFactory.makeAddOffsetPlusHeapbase(dst, compref, offset)); + appendInst(instFactory->makeAddOffsetPlusHeapbase(dst, compref, offset)); insertHash(Op_AddOffsetPlusHeapbase, compref, offset, dst->getInst()); return dst; } @@ -2142,7 +2406,7 @@ IRBuilder::genAddOffsetPlusHeapbase(Type void IRBuilder::genStVar(VarOpnd* var, Opnd* src) { src = propagateCopy(src); - appendInst(instFactory.makeStVar(var, src)); + appendInst(instFactory->makeStVar(var, src)); if (irBuilderFlags.doCSE) { insertHash(Op_LdVar, var->getId(), src->getInst()); } @@ -2166,12 +2430,12 @@ IRBuilder::genStInd(Type* type, Opnd *tauUnsafe = genTauUnsafe(); if (irBuilderFlags.insertWriteBarriers) { - appendInst(instFactory.makeTauStInd((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStInd((Modifier(Store_WriteBarrier)| compressMod), type->tag, src, ptr, tauUnsafe, tauUnsafe, tauUnsafe)); } else { - appendInst(instFactory.makeTauStInd((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStInd((Modifier(Store_NoWriteBarrier)| compressMod), type->tag, src, ptr, tauUnsafe, tauUnsafe, tauUnsafe)); @@ -2200,12 +2464,12 @@ IRBuilder::genTauStInd(Type* type, : AutoCompress_No); if (irBuilderFlags.insertWriteBarriers) { - appendInst(instFactory.makeTauStInd((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStInd((Modifier(Store_WriteBarrier)| compressMod), type->tag, src, ptr, tauBaseNonNull, tauAddressInRange, tauElemTypeChecked)); } else { - appendInst(instFactory.makeTauStInd((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStInd((Modifier(Store_NoWriteBarrier)| compressMod), type->tag, src, ptr, tauBaseNonNull, tauAddressInRange, tauElemTypeChecked)); @@ -2235,13 +2499,13 @@ IRBuilder::genTauStRef(Type* type, Opnd : AutoCompress_No); if (irBuilderFlags.insertWriteBarriers) { - appendInst(instFactory.makeTauStRef((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStRef((Modifier(Store_WriteBarrier)| compressMod), type->tag, src, objectbase, ptr, tauBaseNonNull, tauAddressInRange, tauElemTypeChecked)); } else { - appendInst(instFactory.makeTauStRef((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStRef((Modifier(Store_NoWriteBarrier)| compressMod), type->tag, src, objectbase, ptr, tauBaseNonNull, tauAddressInRange, @@ -2255,7 +2519,7 @@ IRBuilder::genStField(Type* type, FieldDesc* fieldDesc, Opnd* src) { if (fieldDesc->isStatic()) { - assert(0); + assert(0); genStStatic(type, fieldDesc, src); return; } @@ -2263,9 +2527,9 @@ IRBuilder::genStField(Type* type, src = propagateCopy(src); Opnd *tauBaseNonNull = genTauCheckNull(base); Opnd *tauBaseTypeIsOk = genTauHasType(base, fieldDesc->getParentType()); - Type *fieldType = fieldDesc->getFieldType(); - Opnd *tauStoredTypeIsOk = (fieldType->isObject() - ? genTauHasType(src, fieldType) +// Type *fieldType = fieldDesc->getFieldType(); + Opnd *tauStoredTypeIsOk = (type->isObject() + ? genTauHasType(src, type) : genTauSafe()); // safe, not an object if (irBuilderFlags.expandMemAddrs) { // do not expand ldField of stack values Opnd *ptr = genLdFieldAddr(type, base, fieldDesc); @@ -2283,7 +2547,7 @@ IRBuilder::genStField(Type* type, } else { if (irBuilderFlags.insertWriteBarriers && base->getType()->isValue()==false) { - appendInst(instFactory.makeTauStField((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStField((Modifier(Store_WriteBarrier)| Modifier(AutoCompress_Yes)), type->tag, src, base, tauBaseNonNull, @@ -2291,7 +2555,7 @@ IRBuilder::genStField(Type* type, tauStoredTypeIsOk, fieldDesc)); } else { - appendInst(instFactory.makeTauStField((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStField((Modifier(Store_NoWriteBarrier)| Modifier(AutoCompress_Yes)), type->tag, src, base, tauBaseNonNull, @@ -2307,9 +2571,9 @@ IRBuilder::genStStatic(Type* type, Field src = propagateCopy(src); genInitType(fieldDesc->getParentType()); Opnd *tauOk = genTauSafe(); // address is always ok - Type *fieldType = fieldDesc->getFieldType(); - Opnd *tauTypeIsOk = (fieldType->isObject() - ? genTauHasType(src, fieldType) +// Type *fieldType = fieldDesc->getFieldType(); + Opnd *tauTypeIsOk = (type->isObject() + ? genTauHasType(src, type) : genTauSafe()); // safe, not an object if (irBuilderFlags.expandMemAddrs) { genTauStInd(type, genLdStaticAddr(type, fieldDesc), src, @@ -2320,13 +2584,13 @@ IRBuilder::genStStatic(Type* type, Field return; } if (irBuilderFlags.insertWriteBarriers) { - appendInst(instFactory.makeTauStStatic((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStStatic((Modifier(Store_WriteBarrier)| Modifier(AutoCompress_Yes)), type->tag, src, tauTypeIsOk, fieldDesc)); } else { - appendInst(instFactory.makeTauStStatic((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStStatic((Modifier(Store_NoWriteBarrier)| Modifier(AutoCompress_Yes)), type->tag, src, tauTypeIsOk, @@ -2338,17 +2602,15 @@ void IRBuilder::genStElem(Type* elemType, Opnd* array, Opnd* index, - Opnd* src) { + Opnd* src, + Opnd* tauNullChecked, + Opnd* tauBaseTypeChecked, + Opnd* tauAddressInRange) { array = propagateCopy(array); src = propagateCopy(src); index = propagateCopy(index); - // check elem type - Opnd *tauNullChecked = genTauCheckNull(array); - Opnd *tauBaseTypeChecked = genTauHasType(array, array->getType()); - Opnd *tauElemTypeChecked = 0; - Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullChecked); - Opnd *tauAddressInRange = genTauAnd(tauBaseTypeChecked, - tauBoundsChecked); + + Opnd *tauElemTypeChecked = NULL; if (elemType->isObject()) { tauElemTypeChecked = genTauCheckElemType(array, src, tauNullChecked, tauBaseTypeChecked); @@ -2356,7 +2618,12 @@ IRBuilder::genStElem(Type* elemType, tauElemTypeChecked = genTauSafe(); // src type is ok if non-object } if (irBuilderFlags.expandMemAddrs) { - Opnd *ptr = genLdElemAddr(elemType, array, index); + Opnd *ptr = NULL; + if (tauNullChecked && tauAddressInRange) { + ptr = genLdElemAddrNoChecks(elemType, array, index); + } else { + ptr = genLdElemAddr(elemType, array, index); + } if (irBuilderFlags.insertWriteBarriers) { genTauStRef(elemType, array, ptr, src, tauNullChecked, tauAddressInRange, tauElemTypeChecked); @@ -2366,14 +2633,14 @@ IRBuilder::genStElem(Type* elemType, } } else { if (irBuilderFlags.insertWriteBarriers) { - appendInst(instFactory.makeTauStElem((Modifier(Store_WriteBarrier)| + appendInst(instFactory->makeTauStElem((Modifier(Store_WriteBarrier)| Modifier(AutoCompress_Yes)), elemType->tag, src, array, index, tauNullChecked, tauAddressInRange, tauElemTypeChecked)); } else { - appendInst(instFactory.makeTauStElem((Modifier(Store_NoWriteBarrier)| + appendInst(instFactory->makeTauStElem((Modifier(Store_NoWriteBarrier)| Modifier(AutoCompress_Yes)), elemType->tag, src, array, index, tauNullChecked, @@ -2383,18 +2650,41 @@ IRBuilder::genStElem(Type* elemType, } } +void +IRBuilder::genStElem(Type* elemType, + Opnd* array, + Opnd* index, + Opnd* src) { + + array = propagateCopy(array); + src = propagateCopy(src); + index = propagateCopy(index); + + Opnd *tauNullChecked = NULL; + Opnd *tauAddressInRange = NULL; + Opnd *tauBaseTypeChecked = NULL; + + // prepare checks + tauNullChecked = genTauCheckNull(array); + tauBaseTypeChecked = genTauHasType(array, array->getType()); + Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullChecked); + tauAddressInRange = genTauAnd(tauBaseTypeChecked, tauBoundsChecked); + + genStElem(elemType,array,index,src,tauNullChecked,tauBaseTypeChecked,tauAddressInRange); +} + Opnd* IRBuilder::genNewObj(Type* type) { Opnd* dst = createOpnd(type); - appendInst(instFactory.makeNewObj(dst, type)); + appendInst(instFactory->makeNewObj(dst, type)); return dst; } Opnd* IRBuilder::genNewArray(NamedType* elemType, Opnd* numElems) { numElems = propagateCopy(numElems); - Opnd* dst = createOpnd(typeManager.getArrayType(elemType)); - appendInst(instFactory.makeNewArray(dst, numElems, elemType)); + Opnd* dst = createOpnd(typeManager->getArrayType(elemType)); + appendInst(instFactory->makeNewArray(dst, numElems, elemType)); return dst; } @@ -2408,7 +2698,7 @@ IRBuilder::genMultianewarray(NamedType* elemType = ((ArrayType*)elemType)->getElementType(); } Opnd* dst = createOpnd(arrayType); - appendInst(instFactory.makeNewMultiArray(dst, dimensions, numElems, elemType)); + appendInst(instFactory->makeNewMultiArray(dst, dimensions, numElems, elemType)); return dst; } @@ -2416,14 +2706,14 @@ void IRBuilder::genMonitorEnter(Opnd* src) { src = propagateCopy(src); Opnd *tauNullChecked = genTauCheckNull(src); - appendInst(instFactory.makeTauMonitorEnter(src, tauNullChecked)); + appendInst(instFactory->makeTauMonitorEnter(src, tauNullChecked)); } void IRBuilder::genMonitorExit(Opnd* src) { src = propagateCopy(src); Opnd *tauNullChecked = genTauCheckNull(src); - appendInst(instFactory.makeTauMonitorExit(src, tauNullChecked)); + appendInst(instFactory->makeTauMonitorExit(src, tauNullChecked)); } Opnd* @@ -2433,7 +2723,7 @@ IRBuilder::genLdLockAddr(Type* dstType, if (dst) return dst; dst = createOpnd(dstType); - appendInst(instFactory.makeLdLockAddr(dst, obj)); + appendInst(instFactory->makeLdLockAddr(dst, obj)); insertHash(Op_LdLockAddr, obj, dst->getInst()); return dst; } @@ -2442,7 +2732,7 @@ void IRBuilder::genIncRecCount(Opnd* obj, Opnd *oldLock) { obj = propagateCopy(obj); oldLock = propagateCopy(oldLock); - appendInst(instFactory.makeLdLockAddr(obj, oldLock)); + appendInst(instFactory->makeLdLockAddr(obj, oldLock)); } @@ -2462,7 +2752,7 @@ IRBuilder::genTauBalancedMonitorEnter(Ty src = propagateCopy(src); lockAddr = propagateCopy(lockAddr); Opnd *dst = createOpnd(dstType); - appendInst(instFactory.makeTauBalancedMonitorEnter(dst, src, lockAddr, + appendInst(instFactory->makeTauBalancedMonitorEnter(dst, src, lockAddr, tauNullChecked)); return dst; } @@ -2471,7 +2761,7 @@ void IRBuilder::genBalancedMonitorExit(Opnd* src, Opnd *lockAddr, Opnd *oldValue) { // src should already have been checked for null src = propagateCopy(src); - appendInst(instFactory.makeBalancedMonitorExit(src, lockAddr, oldValue)); + appendInst(instFactory->makeBalancedMonitorExit(src, lockAddr, oldValue)); } Opnd* @@ -2482,7 +2772,7 @@ IRBuilder::genTauOptimisticBalancedMonit src = propagateCopy(src); lockAddr = propagateCopy(lockAddr); Opnd *dst = createOpnd(dstType); - appendInst(instFactory.makeTauOptimisticBalancedMonitorEnter(dst, src, + appendInst(instFactory->makeTauOptimisticBalancedMonitorEnter(dst, src, lockAddr, tauNullChecked)); return dst; @@ -2491,23 +2781,23 @@ IRBuilder::genTauOptimisticBalancedMonit void IRBuilder::genMonitorEnterFence(Opnd* src) { src = propagateCopy(src); - appendInst(instFactory.makeMonitorEnterFence(src)); + appendInst(instFactory->makeMonitorEnterFence(src)); } void IRBuilder::genMonitorExitFence(Opnd* src) { src = propagateCopy(src); - appendInst(instFactory.makeMonitorExitFence(src)); + appendInst(instFactory->makeMonitorExitFence(src)); } void IRBuilder::genTypeMonitorEnter(Type* type) { - appendInst(instFactory.makeTypeMonitorEnter(type)); + appendInst(instFactory->makeTypeMonitorEnter(type)); } void IRBuilder::genTypeMonitorExit(Type* type) { - appendInst(instFactory.makeTypeMonitorExit(type)); + appendInst(instFactory->makeTypeMonitorExit(type)); } @@ -2543,14 +2833,14 @@ IRBuilder::genTauCheckCast(Opnd* src, Op if (irBuilderFlags.doSimplify) { bool alwaysThrows = false; - dst = simplifier.simplifyTauCheckCast(src, tauNullChecked, castType, alwaysThrows); + dst = simplifier->simplifyTauCheckCast(src, tauNullChecked, castType, alwaysThrows); if (dst) { return dst; } } - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauCheckCast(dst, src, tauNullChecked, castType)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauCheckCast(dst, src, tauNullChecked, castType)); insertHash(Op_TauCheckCast, src->getId(), castType->getId(), dst->getInst()); return dst; } @@ -2559,7 +2849,7 @@ IRBuilder::genTauCheckCast(Opnd* src, Op Opnd* IRBuilder::genAsType(Opnd* src, Type* type) { if (type->isUserValue()) { - assert(0); + assert(0); } src = propagateCopy(src); @@ -2569,11 +2859,11 @@ IRBuilder::genAsType(Opnd* src, Type* ty if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauAsType(src, tauCheckedNull, type); + dst = simplifier->simplifyTauAsType(src, tauCheckedNull, type); if (dst) return dst; } dst = createOpnd(type); - appendInst(instFactory.makeTauAsType(dst, src, tauCheckedNull, type)); + appendInst(instFactory->makeTauAsType(dst, src, tauCheckedNull, type)); insertHash(Op_TauAsType, src->getId(), tauCheckedNull->getId(), type->getId(), dst->getInst()); return dst; } @@ -2589,12 +2879,12 @@ IRBuilder::genInstanceOf(Opnd* src, Type if (dst) return dst; if (irBuilderFlags.doSimplify) { - dst = simplifier.simplifyTauInstanceOf(src, tauNullChecked, type); + dst = simplifier->simplifyTauInstanceOf(src, tauNullChecked, type); if (dst) return dst; } - dst = createOpnd(typeManager.getInt32Type()); - appendInst(instFactory.makeTauInstanceOf(dst, src, tauNullChecked, type)); + dst = createOpnd(typeManager->getInt32Type()); + appendInst(instFactory->makeTauInstanceOf(dst, src, tauNullChecked, type)); insertHash(Op_TauInstanceOf, src->getId(), type->getId(), tauNullChecked->getId(), dst->getInst()); return dst; @@ -2602,8 +2892,8 @@ IRBuilder::genInstanceOf(Opnd* src, Type Opnd* IRBuilder::genSizeOf(Type* type) { - Opnd* dst = createOpnd(typeManager.getUInt32Type()); - appendInst(instFactory.makeSizeof(dst, type)); + Opnd* dst = createOpnd(typeManager->getUInt32Type()); + appendInst(instFactory->makeSizeof(dst, type)); return dst; } @@ -2612,9 +2902,9 @@ IRBuilder::genUnbox(Type* type, Opnd* ob assert(type->isValue()); Opnd *src = propagateCopy(obj); genTauCheckNull(obj); - Opnd *two = genCast(src, typeManager.getObjectType(((NamedType*)type)->getVMTypeHandle())); - Opnd* dst = createOpnd(typeManager.getManagedPtrType(type)); - appendInst(instFactory.makeUnbox(dst, two, type)); + Opnd *two = genCast(src, typeManager->getObjectType(((NamedType*)type)->getVMTypeHandle())); + Opnd* dst = createOpnd(typeManager->getManagedPtrType(type)); + appendInst(instFactory->makeUnbox(dst, two, type)); return dst; } @@ -2622,31 +2912,31 @@ Opnd* IRBuilder::genBox(Type* type, Opnd* val) { assert(type->isValue()); val = propagateCopy(val); - Opnd* dst = createOpnd(typeManager.getObjectType(((NamedType*)type)->getVMTypeHandle())); - appendInst(instFactory.makeBox(dst, val, type)); + Opnd* dst = createOpnd(typeManager->getObjectType(((NamedType*)type)->getVMTypeHandle())); + appendInst(instFactory->makeBox(dst, val, type)); return dst; } void IRBuilder::genCopyObj(Type* type, Opnd* dstValPtr, Opnd* srcValPtr) { - appendInst(instFactory.makeCopyObj(dstValPtr, srcValPtr, type)); + appendInst(instFactory->makeCopyObj(dstValPtr, srcValPtr, type)); } void IRBuilder::genInitObj(Type* type, Opnd* valPtr) { - appendInst(instFactory.makeInitObj(valPtr, type)); + appendInst(instFactory->makeInitObj(valPtr, type)); } Opnd* IRBuilder::genLdObj(Type* type, Opnd* addrOfValObj) { Opnd* dst = createOpnd(type); - appendInst(instFactory.makeLdObj(dst, addrOfValObj, type)); + appendInst(instFactory->makeLdObj(dst, addrOfValObj, type)); return dst; } void IRBuilder::genStObj(Opnd* addrOfDstVal, Opnd* srcVal, Type* type) { - appendInst(instFactory.makeStObj(addrOfDstVal, srcVal, type)); + appendInst(instFactory->makeStObj(addrOfDstVal, srcVal, type)); } void @@ -2696,17 +2986,17 @@ IRBuilder::genRefAnyVal(Type* type, Opnd //----------------------------------------------------------------------------- Opnd* IRBuilder::propagateCopy(Opnd* opnd) { - return simplifier.propagateCopy(opnd); + return simplifier->propagateCopy(opnd); } Opnd* IRBuilder::createOpnd(Type* type) { if (type->tag == Type::Void) return OpndManager::getNullOpnd(); - return opndManager.createSsaTmpOpnd(type); + return opndManager->createSsaTmpOpnd(type); } PiOpnd* IRBuilder::createPiOpnd(Opnd *org) { - return opndManager.createPiOpnd(org); + return opndManager->createPiOpnd(org); } Opnd* IRBuilder::genTauCheckNull(Opnd* base) { @@ -2722,10 +3012,10 @@ Opnd* IRBuilder::genTauCheckNull(Opnd* b // Not advisable to turn off simplification of checknull because // IRBuilder calls genTauCheckNull redundantly many times bool alwaysThrows = false; - res = simplifier.simplifyTauCheckNull(base, alwaysThrows); + res = simplifier->simplifyTauCheckNull(base, alwaysThrows); if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; - Opnd* dst = createOpnd(typeManager.getTauType()); - Inst *inst = appendInst(instFactory.makeTauCheckNull(dst, base)); + Opnd* dst = createOpnd(typeManager->getTauType()); + Inst *inst = appendInst(instFactory->makeTauCheckNull(dst, base)); insertHash(Op_TauCheckNull, base, inst); // We can make the type init for the base object available here @@ -2742,11 +3032,11 @@ Opnd* IRBuilder::genTauCheckZero(Opnd* s if (res) return res; bool alwaysThrows = false; - res = simplifier.simplifyTauCheckZero(src, alwaysThrows); + res = simplifier->simplifyTauCheckZero(src, alwaysThrows); if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; - Opnd* dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauCheckZero(dst, src)); + Opnd* dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauCheckZero(dst, src)); insertHash(Op_TauCheckZero, src, dst->getInst()); return dst; } @@ -2760,11 +3050,11 @@ Opnd *IRBuilder::genTauCheckDivOpnds(Opn if (res) return res; bool alwaysThrows = false; - res = simplifier.simplifyTauCheckDivOpnds(src1, src2, alwaysThrows); + res = simplifier->simplifyTauCheckDivOpnds(src1, src2, alwaysThrows); if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; - Opnd* dst = createOpnd(typeManager.getTauType()); - Inst *inst = appendInst(instFactory.makeTauCheckDivOpnds(dst, src1, src2)); + Opnd* dst = createOpnd(typeManager->getTauType()); + Inst *inst = appendInst(instFactory->makeTauCheckDivOpnds(dst, src1, src2)); insertHash(Op_TauCheckDivOpnds, src1, src2, inst); return dst; } @@ -2783,7 +3073,7 @@ Opnd *IRBuilder::genTauCheckBounds(Opnd* if (res) return res; Opnd *tauArrayTypeChecked = genTauHasType(array, array->getType()); - Opnd* arrayLen = genTauArrayLen(typeManager.getInt32Type(), Type::Int32, array, + Opnd* arrayLen = genTauArrayLen(typeManager->getInt32Type(), Type::Int32, array, tauNullChecked, tauArrayTypeChecked); Opnd* dst = genTauCheckBounds(arrayLen, index); @@ -2805,11 +3095,11 @@ IRBuilder::genTauCheckElemType(Opnd* arr if (irBuilderFlags.doSimplify) { bool alwaysThrows = false; - res = simplifier.simplifyTauCheckElemType(array, src, alwaysThrows); + res = simplifier->simplifyTauCheckElemType(array, src, alwaysThrows); if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; } - Opnd* dst = createOpnd(typeManager.getTauType()); - Inst* inst = appendInst(instFactory.makeTauCheckElemType(dst, array, src, + Opnd* dst = createOpnd(typeManager->getTauType()); + Inst* inst = appendInst(instFactory->makeTauCheckElemType(dst, array, src, tauNullChecked, tauIsArray)); insertHash(Op_TauCheckElemType, array, src, inst); @@ -2826,13 +3116,13 @@ IRBuilder::genTauCheckBounds(Opnd* ub, O if (irBuilderFlags.doSimplify) { bool alwaysThrows = false; - dst = simplifier.simplifyTauCheckBounds(ub, index, alwaysThrows); + dst = simplifier->simplifyTauCheckBounds(ub, index, alwaysThrows); } if (!(dst && (dst->getInst()->getOpcode() != Op_TauUnsafe))) { // need to create one - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauCheckBounds(dst, ub, index)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauCheckBounds(dst, ub, index)); } insertHash(Op_TauCheckBounds, ub, index, dst->getInst()); return dst; @@ -2853,12 +3143,12 @@ IRBuilder::genTauCheckFinite(Opnd* src) if (irBuilderFlags.doSimplify) { bool alwaysThrows = false; - dst = simplifier.simplifyTauCheckFinite(src, alwaysThrows); + dst = simplifier->simplifyTauCheckFinite(src, alwaysThrows); if (dst && (dst->getInst()->getOpcode() != Op_TauUnsafe)) return dst; } - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauCheckFinite(dst, src)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauCheckFinite(dst, src)); insertHash(Op_TauCheckFinite, src, dst->getInst()); return dst; } @@ -2871,7 +3161,7 @@ IRBuilder::genTauCheckFinite(Opnd* src) Opnd* IRBuilder::lookupHash(uint32 opc) { if (! irBuilderFlags.doCSE) return NULL; - Inst* inst = cseHashTable.lookup(opc); + Inst* inst = cseHashTable->lookup(opc); if (inst) return inst->getDst(); else @@ -2881,7 +3171,7 @@ Opnd* IRBuilder::lookupHash(uint32 opc) Opnd* IRBuilder::lookupHash(uint32 opc, uint32 op) { if (! irBuilderFlags.doCSE) return NULL; - Inst* inst = cseHashTable.lookup(opc, op); + Inst* inst = cseHashTable->lookup(opc, op); if (inst) return inst->getDst(); else @@ -2891,7 +3181,7 @@ Opnd* IRBuilder::lookupHash(uint32 opc, Opnd* IRBuilder::lookupHash(uint32 opc, uint32 op1, uint32 op2) { if (! irBuilderFlags.doCSE) return NULL; - Inst* inst = cseHashTable.lookup(opc, op1, op2); + Inst* inst = cseHashTable->lookup(opc, op1, op2); if (inst) return inst->getDst(); else @@ -2901,7 +3191,7 @@ Opnd* IRBuilder::lookupHash(uint32 opc, Opnd* IRBuilder::lookupHash(uint32 opc, uint32 op1, uint32 op2, uint32 op3) { if (! irBuilderFlags.doCSE) return NULL; - Inst* inst = cseHashTable.lookup(opc, op1, op2, op3); + Inst* inst = cseHashTable->lookup(opc, op1, op2, op3); if (inst) return inst->getDst(); else @@ -2911,26 +3201,26 @@ Opnd* IRBuilder::lookupHash(uint32 opc, void IRBuilder::insertHash(uint32 opc, Inst* inst) { if (! irBuilderFlags.doCSE) return; - cseHashTable.insert(opc, inst); + cseHashTable->insert(opc, inst); } void IRBuilder::insertHash(uint32 opc, uint32 op1, Inst* inst) { if (! irBuilderFlags.doCSE) return; - cseHashTable.insert(opc, op1, inst); + cseHashTable->insert(opc, op1, inst); } void IRBuilder::insertHash(uint32 opc, uint32 op1, uint32 op2, Inst* inst) { if (! irBuilderFlags.doCSE) return; - cseHashTable.insert(opc, op1, op2, inst); + cseHashTable->insert(opc, op1, op2, inst); } void IRBuilder::insertHash(uint32 opc, uint32 op1, uint32 op2, uint32 op3, Inst* inst) { if (! irBuilderFlags.doCSE) return; - cseHashTable.insert(opc, op1, op2, op3, inst); + cseHashTable->insert(opc, op1, op2, op3, inst); } // tau instructions @@ -2939,8 +3229,8 @@ IRBuilder::genTauSafe() { Opnd* dst = lookupHash(Op_TauSafe); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauSafe(dst)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauSafe(dst)); insertHash(Op_TauSafe, dst->getInst()); return dst; @@ -2952,18 +3242,18 @@ IRBuilder::genTauMethodSafe() { Opnd* dst = tauMethodSafeOpnd; if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - Inst *inst = instFactory.makeTauPoint(dst); + dst = createOpnd(typeManager->getTauType()); + Inst *inst = instFactory->makeTauPoint(dst); - CFGNode *head = getFlowGraph().getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = flowGraph->getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *where = entryLabel->next(); - while (where != entryLabel) { + Inst *where = entryLabel->getNextInst(); + while (where != NULL) { if (where->getOpcode() != Op_DefArg) { break; } - where = where->next(); + where = where->getNextInst(); } // insert before where inst->insertBefore(where); @@ -2978,8 +3268,8 @@ IRBuilder::genTauUnsafe() { Opnd* dst = lookupHash(Op_TauUnsafe); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauUnsafe(dst)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauUnsafe(dst)); insertHash(Op_TauUnsafe, dst->getInst()); return dst; @@ -2993,7 +3283,7 @@ IRBuilder::genTauStaticCast(Opnd *src, O if (dst) return dst; dst = createOpnd(castType); - appendInst(instFactory.makeTauStaticCast(dst, src, tauCheckedCast, castType)); + appendInst(instFactory->makeTauStaticCast(dst, src, tauCheckedCast, castType)); insertHash(hashcode, src->getId(), tauCheckedCast->getId(), castType->getId(), dst->getInst()); Operation hasTypeOperation(Op_TauHasType, castType->tag, Modifier()); @@ -3010,8 +3300,8 @@ IRBuilder::genTauHasType(Opnd *src, Type Opnd* dst = lookupHash(hashcode, src->getId(), castType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauHasType(dst, src, castType)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauHasType(dst, src, castType)); insertHash(hashcode, src->getId(), castType->getId(), dst->getInst()); return dst; @@ -3024,8 +3314,8 @@ IRBuilder::genTauHasExactType(Opnd *src, Opnd* dst = lookupHash(hashcode, src->getId(), castType->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauHasExactType(dst, src, castType)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauHasExactType(dst, src, castType)); insertHash(hashcode, src->getId(), castType->getId(), dst->getInst()); return dst; @@ -3037,8 +3327,8 @@ IRBuilder::genTauIsNonNull(Opnd *src) { Opnd* dst = lookupHash(hashcode, src->getId()); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); - appendInst(instFactory.makeTauIsNonNull(dst, src)); + dst = createOpnd(typeManager->getTauType()); + appendInst(instFactory->makeTauIsNonNull(dst, src)); insertHash(hashcode, src->getId(), dst->getInst()); @@ -3060,9 +3350,9 @@ IRBuilder::genTauAnd(Opnd *src1, Opnd *s Opnd* dst = lookupHash(Op_TauAnd, src1, src2); if (dst) return dst; - dst = createOpnd(typeManager.getTauType()); + dst = createOpnd(typeManager->getTauType()); Opnd* srcs[2] = { src1, src2 }; - appendInst(instFactory.makeTauAnd(dst, 2, srcs)); + appendInst(instFactory->makeTauAnd(dst, 2, srcs)); insertHash(Op_TauAnd, src1->getId(), src2->getId(), dst->getInst()); return dst; @@ -3074,13 +3364,14 @@ IRBuilder::appendInstUpdateInlineInfo(In assert(inst->getCallInstInlineInfoPtr()); if ( builder ) { - builder->buildInlineInfoForInst(inst, target_md); + offset = builder->buildInlineInfoForInst(inst, offset, target_md); } + appendInst(inst); } Inst* IRBuilder::getLastGeneratedInst() { - return currentLabel->prev(); + return (Inst*)currentLabel->getNode()->getLastInst(); } } //namespace Jitrino diff --git vm/jitrino/src/optimizer/IRBuilder.h vm/jitrino/src/optimizer/IRBuilder.h index a70c53a..82226a8 100644 --- vm/jitrino/src/optimizer/IRBuilder.h +++ vm/jitrino/src/optimizer/IRBuilder.h @@ -23,75 +23,55 @@ #ifndef _IRBUILDER_H_ #define _IRBUILDER_H_ -#include <iostream> #include "MemoryManager.h" #include "Opcode.h" #include "Inst.h" #include "CSEHash.h" #include "simplifier.h" #include "InlineInfo.h" +#include "IRBuilderFlags.h" +#include "PMFAction.h" + + +#include <iostream> namespace Jitrino { -class JitrinoParameterTable; class PiCondition; class VectorHandler; class MapHandler; class CompilationContext; +class SessionAction; +struct TranslatorFlags; - // - // flags that control how the IRBuilder expands and optimizes IR instructions - // -struct IRBuilderFlags { - IRBuilderFlags () { - expandMemAddrs = expandNullChecks = false; - expandCallAddrs = expandVirtualCallAddrs = false; - expandElemAddrs = expandElemTypeChecks = false; - doSimplify = doCSE = false; - insertMethodLabels = insertWriteBarriers = false; - suppressCheckBounds = false; - compressedReferences = false; - genMinMaxAbs = false; - genFMinMaxAbs = false; - useNewTypeSystem = false; - isBCMapinfoRequired = false; - } - /* expansion flags */ - bool expandMemAddrs : 1; // expand field/array element accesses - bool expandElemAddrs : 1; // expand array elem address computation - bool expandCallAddrs : 1; // expand fun address computation for direct calls - bool expandVirtualCallAddrs : 1; // expand fun address computation for virtual calls - bool expandNullChecks : 1; // explicit null checks - bool expandElemTypeChecks: 1; // explicit array elem type checks for stores - /* optimization flags */ - bool doCSE : 1; // common subexpression elimination - bool doSimplify : 1; // simplification - /* label & debug insertion */ - bool insertMethodLabels : 1; // insert method entry/exit labels - bool insertWriteBarriers : 1; // insert write barriers to mem stores - bool suppressCheckBounds : 1; - bool compressedReferences: 1; // are refs in heap compressed? - bool genMinMaxAbs : 1; - bool genFMinMaxAbs : 1; - // LBS Project flags - bool useNewTypeSystem : 1; // Use the new LBS type system rather than the old one - bool isBCMapinfoRequired : 1; // Produce HIR bc map info - }; - -class IRBuilder { + +#define IRBUILDER_ACTION_NAME "irbuilder" + +class IRBuilderAction : public Action { public: - static void readFlagsFromCommandLine(CompilationContext* cs); - static void showFlagsFromCommandLine(); - // - // constructor - // - IRBuilder(IRManager& irm); + void init(); + const IRBuilderFlags& getFlags() const {return irBuilderFlags;} +private: + void readFlags(); + + IRBuilderFlags irBuilderFlags; +}; + + +class IRBuilder : public SessionAction { +public: + IRBuilder(); + void init(IRManager* irm, TranslatorFlags* traFlags, MemoryManager& tmpMM); + + //this session can't be placed into PMF path + void run(){assert(0);} - IRManager& getIRManager() {return irManager;} - InstFactory& getInstFactory() {return instFactory;} - TypeManager& getTypeManager() {return typeManager;} - OpndManager& getOpndManager() {return opndManager;} - FlowGraph& getFlowGraph() {return flowGraph;} + IRManager* getIRManager() const { return irManager;} + InstFactory* getInstFactory() const {return instFactory;} + TypeManager* getTypeManager() const {return typeManager;} + OpndManager* getOpndManager() const {return opndManager;} + ControlFlowGraph* getFlowGraph() const {return flowGraph;} + TranslatorFlags* getTranslatorFlags() const {return translatorFlags;} // // used to map bytecode offsets to instructions by JavaByteCodeTranslator @@ -203,13 +183,15 @@ public: Opnd* genLdFloatConstant(double val);//TR Opnd* genLdNull();//TR - Opnd* genLdString(MethodDesc* enclosingMethod, uint32 stringToken);//TR + Opnd* genLdRef(MethodDesc* enclosingMethod, uint32 stringToken, Type* type);//TR Opnd* genLdVar(Type* dstType, VarOpnd* var);//TR Opnd* genLdVarAddr(VarOpnd* var);//TR Opnd* genLdInd(Type*, Opnd* ptr); // for use by front-ends, but not simplifier//TR Opnd* genLdField(Type*, Opnd* base, FieldDesc* fieldDesc); //TR Opnd* genLdStatic(Type*, FieldDesc* fieldDesc);//TR Opnd* genLdElem(Type* elemType, Opnd* array, Opnd* index); //TR + Opnd* genLdElem(Type* elemType, Opnd* array, Opnd* index, + Opnd* tauNullCheck, Opnd* tauAddressInRange); Opnd* genLdFieldAddr(Type* fieldType, Opnd* base, FieldDesc* fieldDesc); //TR Opnd* genLdStaticAddr(Type* fieldType, FieldDesc* fieldDesc);//TR Opnd* genLdElemAddr(Type* elemType, Opnd* array, Opnd* index);//TR @@ -221,6 +203,8 @@ public: void genStField(Type*, Opnd* base, FieldDesc* fieldDesc, Opnd* src);//TR void genStStatic(Type*, FieldDesc* fieldDesc, Opnd* src);//TR void genStElem(Type*, Opnd* array, Opnd* index, Opnd* src);//TR + void genStElem(Type*, Opnd* array, Opnd* index, Opnd* src, + Opnd* tauNullCheck, Opnd* tauBaseTypeCheck, Opnd* tauAddressInRange); void genStInd(Type*, Opnd* ptr, Opnd* src);//TR // checks Opnd* genTauCheckNull(Opnd* base); @@ -255,8 +239,8 @@ public: // method entry/exit LabelInst* genMethodEntryLabel(MethodDesc* methodDesc);//TR void genMethodEntryMarker(MethodDesc* methodDesc);//TR - void genMethodEndMarker(MethodDesc* methodDesc, Opnd *obj);//TR - void genMethodEndMarker(MethodDesc* methodDesc);//TR + void genMethodEndMarker(MethodDesc* methodDesc, Opnd *obj, Opnd *retOpnd);//TR + void genMethodEndMarker(MethodDesc* methodDesc, Opnd *retOpnd);//TR // value object instructions Opnd* genLdObj(Type* type, Opnd* addrOfValObj);//TR void genStObj(Opnd* addrOfDstVal, Opnd* srcVal, Type* type);//TR @@ -301,7 +285,7 @@ public: Opnd* genShladd(Type* dstType, Opnd* value, Opnd* shiftAmount, Opnd* addto); //SI // Control flow // load, store & move - Opnd* genLdString(Modifier mod, Type *dstType,//TR //SI + Opnd* genLdRef(Modifier mod, Type *dstType,//TR //SI uint32 token, MethodDesc *enclosingMethod); // for simplifier use Opnd* genTauLdInd(Modifier mod, Type *dstType, Type::Tag ldType, Opnd *ptr, //SI Opnd *tauNonNullBase, Opnd *tauAddressInRange); // for simplifier use @@ -385,6 +369,9 @@ protected: void appendInstUpdateInlineInfo(Inst* inst, InlineInfoBuilder* builder, MethodDesc* target_md); private: + + void readFlagsFromCommandLine(SessionAction* argSource, const char* argPrefix); + // RECURSIVE GEN // additional gen methods used only recursively Opnd* genPredCmp(Type *dstType, Type::Tag instType, ComparisonModifier mod, @@ -416,259 +403,32 @@ private: void insertHash(uint32 opc, Opnd* op1, Opnd* op2, Opnd* op3, Inst*i) { insertHash(opc, op1->getId(), op2->getId(), op3->getId(), i); }; void invalid(); // called when the builder detects invalid IR void setBcOffset(uint32 bcOffset) { offset = bcOffset; }; + uint32 getBcOffset() { return offset; }; - friend class JavaByteCodeTranslator; - // - // private classes - // - class _Simplifier : public Simplifier { - public: - _Simplifier(IRManager &irm, IRBuilder* irb) - : Simplifier(irm, false, 0), irBuilder(*irb) - { - } - protected: - // numeric - virtual Inst* - genAdd(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ - return irBuilder.genAdd(type, mod, src1, src2)->getInst(); - } - virtual Inst* - genSub(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { - return irBuilder.genSub(type, mod, src1, src2)->getInst(); - } - virtual Inst* - genNeg(Type* type, Opnd* src) { - return irBuilder.genNeg(type, src)->getInst(); - } - virtual Inst* - genMul(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ - return irBuilder.genMul(type, mod, src1, src2)->getInst(); - } - virtual Inst* - genMulHi(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ - return irBuilder.genMulHi(type, mod, src1, src2)->getInst(); - } - virtual Inst* - genMin(Type* type, Opnd* src1, Opnd* src2){ - return irBuilder.genMin(type, src1, src2)->getInst(); - } - virtual Inst* - genMax(Type* type, Opnd* src1, Opnd* src2){ - return irBuilder.genMax(type, src1, src2)->getInst(); - } - virtual Inst* - genAbs(Type* type, Opnd* src1){ - return irBuilder.genAbs(type, src1)->getInst(); - } - // bitwise - virtual Inst* - genAnd(Type* type, Opnd* src1, Opnd* src2){ - return irBuilder.genAnd(type, src1, src2)->getInst(); - } - virtual Inst* - genOr(Type* type, Opnd* src1, Opnd* src2){ - return irBuilder.genOr(type, src1, src2)->getInst(); - } - virtual Inst* - genXor(Type* type, Opnd* src1, Opnd* src2){ - return irBuilder.genXor(type, src1, src2)->getInst(); - } - virtual Inst* - genNot(Type* type, Opnd* src1){ - return irBuilder.genNot(type, src1)->getInst(); - } - virtual Inst* - genSelect(Type* type, - Opnd* src1, Opnd* src2, Opnd* src3){ - return irBuilder.genSelect(type, src1, src2, src3)->getInst(); - } - // conversion - virtual Inst* - genConv(Type* dstType, Type::Tag toType, Modifier ovfMod, Opnd* src){ - return irBuilder.genConv(dstType, toType, ovfMod, src)->getInst(); - } - // shifts - virtual Inst* - genShladd(Type* type, - Opnd* src1, Opnd* src2, Opnd *src3){ - return irBuilder.genShladd(type, src1, src2, src3)->getInst(); - } - virtual Inst* - genShl(Type* type, Modifier smmod, - Opnd* src1, Opnd* src2){ - return irBuilder.genShl(type, smmod, src1, src2)->getInst(); - } - virtual Inst* - genShr(Type* type, Modifier mods, - Opnd* src1, Opnd* src2){ - return irBuilder.genShr(type, mods, src1, src2)->getInst(); - } - // comparison - virtual Inst* - genCmp(Type* type, Type::Tag insttype, - ComparisonModifier mod, Opnd* src1, Opnd* src2){ - return irBuilder.genCmp(type, insttype, mod, src1, src2)->getInst(); - } - // control flow - virtual void - genJump(LabelInst* label) { - irBuilder.genJump(label); - } - virtual void - genBranch(Type::Tag instType, ComparisonModifier mod, - LabelInst* label, Opnd* src1, Opnd* src2) { - irBuilder.genBranch(instType, mod, label, src1, src2); - } - virtual void - genBranch(Type::Tag instType, ComparisonModifier mod, - LabelInst* label, Opnd* src1) { - irBuilder.genBranch(instType, mod, label, src1); - } - virtual Inst* - genDirectCall(MethodDesc* methodDesc, - Type* returnType, - Opnd* tauNullCheckedFirstArg, - Opnd* tauTypesChecked, - uint32 numArgs, - Opnd* args[], - InlineInfoBuilder* inlineBuilder) - { - irBuilder.genDirectCall(methodDesc, returnType, - tauNullCheckedFirstArg, tauTypesChecked, - numArgs, args, inlineBuilder); - return irBuilder.getCurrentLabel()->prev(); - } - // load, store & mov - virtual Inst* - genLdConstant(int32 val) { - return irBuilder.genLdConstant(val)->getInst(); - } - virtual Inst* - genLdConstant(int64 val) { - return irBuilder.genLdConstant(val)->getInst(); - } - virtual Inst* - genLdConstant(float val) { - return irBuilder.genLdConstant(val)->getInst(); - } - virtual Inst* - genLdConstant(double val) { - return irBuilder.genLdConstant(val)->getInst(); - } - virtual Inst* - genLdConstant(Type *type, ConstInst::ConstValue val) { - return irBuilder.genLdConstant(type, val)->getInst(); - } - virtual Inst* - genTauLdInd(Modifier mod, Type* dstType, Type::Tag ldType, Opnd* src, - Opnd *tauNonNullBase, Opnd *tauAddressInRange) { - return irBuilder.genTauLdInd(mod, dstType, ldType, src, - tauNonNullBase, tauAddressInRange)->getInst(); - } - virtual Inst* - genLdString(Modifier mod, Type* dstType, - uint32 token, MethodDesc *enclosingMethod) { - return irBuilder.genLdString(mod, dstType, - token, enclosingMethod)->getInst(); - } - virtual Inst* - genLdFunAddrSlot(MethodDesc* methodDesc) { - return irBuilder.genLdFunAddrSlot(methodDesc)->getInst(); - } - virtual Inst* - genGetVTableAddr(ObjectType* type) { - return irBuilder.genGetVTable(type)->getInst(); - } - // compressed references - virtual Inst* genCompressRef(Opnd *uncompref){ - return irBuilder.genCompressRef(uncompref)->getInst(); - } - virtual Inst* genUncompressRef(Opnd *compref){ - return irBuilder.genUncompressRef(compref)->getInst(); - } - virtual Inst *genLdFieldOffsetPlusHeapbase(FieldDesc* fd) { - return irBuilder.genLdFieldOffsetPlusHeapbase(fd)->getInst(); - } - virtual Inst *genLdArrayBaseOffsetPlusHeapbase(Type *elemType) { - return irBuilder.genLdArrayBaseOffsetPlusHeapbase(elemType)->getInst(); - } - virtual Inst *genLdArrayLenOffsetPlusHeapbase(Type *elemType) { - return irBuilder.genLdArrayLenOffsetPlusHeapbase(elemType)->getInst(); - } - virtual Inst *genAddOffsetPlusHeapbase(Type *ptrType, Opnd *compRef, - Opnd *offsetPlusHeapbase) { - return irBuilder.genAddOffsetPlusHeapbase(ptrType, compRef, - offsetPlusHeapbase)->getInst(); - } - virtual Inst *genTauSafe() { - return irBuilder.genTauSafe()->getInst(); - } - virtual Inst *genTauMethodSafe() { - return irBuilder.genTauMethodSafe()->getInst(); - } - virtual Inst *genTauUnsafe() { - return irBuilder.genTauUnsafe()->getInst(); - } - virtual Inst* genTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) { - return irBuilder.genTauStaticCast(src, tauCheckedCast, castType)->getInst(); - } - virtual Inst* genTauHasType(Opnd *src, Type *castType) { - return irBuilder.genTauHasType(src, castType)->getInst(); - } - virtual Inst* genTauHasExactType(Opnd *src, Type *castType) { - return irBuilder.genTauHasExactType(src, castType)->getInst(); - } - virtual Inst* genTauIsNonNull(Opnd *src) { - return irBuilder.genTauIsNonNull(src)->getInst(); - } - // helper for store simplification, builds/finds simpler src, possibly - // modifies typetag or store modifier. - virtual Opnd* - simplifyStoreSrc(Opnd *src, Type::Tag &typetag, Modifier &mod, - bool compressRef) { - return 0; - } - - virtual void - foldBranch(BranchInst* br, bool isTaken) { - assert(0); - } - virtual void - foldSwitch(SwitchInst* sw, uint32 index) { - assert(0); - } - virtual void - eliminateCheck(Inst* checkInst, bool alwaysThrows) { - assert(0); - } - virtual void genThrowSystemException(CompilationInterface::SystemExceptionId id) { - irBuilder.genThrowSystemException(id); - } - private: - IRBuilder& irBuilder; - }; + friend class JavaByteCodeTranslator; + // // private fields // // references to other translation objects // - IRManager& irManager; - OpndManager& opndManager; // generates operands - TypeManager& typeManager; // generates types - InstFactory& instFactory; // generates instructions - FlowGraph& flowGraph; // generates blocks - IRBuilderFlags& irBuilderFlags; // flags that control translation + IRManager* irManager; + OpndManager* opndManager; // generates operands + TypeManager* typeManager; // generates types + InstFactory* instFactory; // generates instructions + ControlFlowGraph* flowGraph; // generates blocks + IRBuilderFlags irBuilderFlags; // flags that control translation + TranslatorFlags* translatorFlags; // // translation state // - MemoryManager tempMemoryManager; // for use ONLY by IRBuilder LabelInst* currentLabel; // current header label - CSEHashTable cseHashTable; // hash table for CSE + CSEHashTable* cseHashTable; // hash table for CSE + // // simplifier to fold constants etc. // - _Simplifier simplifier; + Simplifier* simplifier; // // method-safe operand Opnd* tauMethodSafeOpnd; diff --git vm/jitrino/src/optimizer/IRBuilderFlags.h vm/jitrino/src/optimizer/IRBuilderFlags.h new file mode 100644 index 0000000..17362e1 --- /dev/null +++ vm/jitrino/src/optimizer/IRBuilderFlags.h @@ -0,0 +1,69 @@ +/* +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @author Intel, Pavel A. Ozhdikhin +* @version $ +* +*/ + +#ifndef _IRBUILDERFLAGS_H_ +#define _IRBUILDERFLAGS_H_ + +namespace Jitrino { +// +// flags that control how the IRBuilder expands and optimizes IR instructions +// +struct IRBuilderFlags { + IRBuilderFlags () { + expandMemAddrs = expandNullChecks = false; + expandCallAddrs = expandVirtualCallAddrs = false; + expandElemAddrs = expandElemTypeChecks = false; + doSimplify = doCSE = false; + insertMethodLabels = insertWriteBarriers = false; + suppressCheckBounds = false; + compressedReferences = false; + genMinMaxAbs = false; + genFMinMaxAbs = false; + useNewTypeSystem = false; + isBCMapinfoRequired = false; + } + /* expansion flags */ + bool expandMemAddrs : 1; // expand field/array element accesses + bool expandElemAddrs : 1; // expand array elem address computation + bool expandCallAddrs : 1; // expand fun address computation for direct calls + bool expandVirtualCallAddrs : 1; // expand fun address computation for virtual calls + bool expandNullChecks : 1; // explicit null checks + bool expandElemTypeChecks: 1; // explicit array elem type checks for stores + /* optimization flags */ + bool doCSE : 1; // common subexpression elimination + bool doSimplify : 1; // simplification + /* label & debug insertion */ + bool insertMethodLabels : 1; // insert method entry/exit labels + bool insertWriteBarriers : 1; // insert write barriers to mem stores + bool suppressCheckBounds : 1; + bool compressedReferences: 1; // are refs in heap compressed? + bool genMinMaxAbs : 1; + bool genFMinMaxAbs : 1; + // LBS Project flags + bool useNewTypeSystem : 1; // Use the new LBS type system rather than the old one + bool isBCMapinfoRequired : 1; // Produce HIR bc map info + bool fullBcMap : 1; // Produce HIR bc map info for all intructions +}; + +} //namespace + +#endif // _IRBUILDERFLAGS_H_ diff --git vm/jitrino/src/optimizer/Inst.cpp vm/jitrino/src/optimizer/Inst.cpp index 7f13f03..45207c3 100644 --- vm/jitrino/src/optimizer/Inst.cpp +++ vm/jitrino/src/optimizer/Inst.cpp @@ -25,7 +25,7 @@ #include <stdio.h> #include "Inst.h" #include "Type.h" #include "IRBuilder.h" -#include "FlowGraph.h" + namespace Jitrino { @@ -34,13 +34,13 @@ namespace Jitrino { //----------------------------------------------------------------------------- Inst::Inst(Opcode opcode, Modifier mod, Type::Tag type, Opnd* dst_) - : operation(opcode, type, mod), numSrcs(0), dst(0), id((uint32)-1), node(0) + : operation(opcode, type, mod), numSrcs(0), dst(0) { setDst(dst_); } Inst::Inst(Opcode opcode, Modifier mod, Type::Tag type, Opnd* dst_, Opnd* src) - : operation(opcode, type, mod), numSrcs(1), dst(0), id((uint32)-1), node(0) + : operation(opcode, type, mod), numSrcs(1), dst(0) { setDst(dst_); srcs[0] = src; @@ -48,7 +48,7 @@ Inst::Inst(Opcode opcode, Modifier mod, Inst::Inst(Opcode opcode, Modifier mod, Type::Tag type, Opnd* dst_, Opnd* src1, Opnd* src2) - : operation(opcode, type, mod), numSrcs(2), dst(0), id((uint32)-1), node(0) + : operation(opcode, type, mod), numSrcs(2), dst(0) { setDst(dst_); srcs[0] = src1; @@ -56,7 +56,7 @@ Inst::Inst(Opcode opcode, Modifier mod, } Inst::Inst(Opcode opcode, Modifier mod, Type::Tag type, Opnd* dst_, uint32 nSrcs) - : operation(opcode, type, mod), numSrcs(nSrcs), dst(0), id((uint32)-1), node(0) + : operation(opcode, type, mod), numSrcs(nSrcs), dst(0) { setDst(dst_); } @@ -67,16 +67,49 @@ Opnd* Inst::getSrcExtended(uint32 srcInd } bool Inst::isThrow() const { - return ((getOpcode() == Op_Throw) || (getOpcode() == Op_ThrowLazy) || - (getOpcode() == Op_ThrowSystemException) || (getOpcode() == Op_ThrowLinkingException) || + return ((getOpcode() == Op_Throw) || (getOpcode() == Op_ThrowSystemException) || + (getOpcode() == Op_ThrowLinkingException) || ( (getOpcode() == Op_VMHelperCall) ? (asVMHelperCallInst()->isThrowLazy()) : false ) ); } + +Edge::Kind Inst::getEdgeKind(const Edge* edge) const { +#ifdef _DEBUG + Node* node = edge->getSourceNode(); + Node* succ = edge->getTargetNode(); + assert(node->isBlockNode()); + assert(succ->isBlockNode()); + assert(node->getLastInst() == this); + assert(node->getOutDegree() <= 2); //uncond + exception +#endif + return Edge::Kind_Unconditional;// jump +} + +void Inst::removeRedundantBranch() { + if (getOpcode() == Op_Branch || isSwitch()) { + unlink(); + } +} + + //----------------------------------------------------------------------------- // BranchInst utilities //----------------------------------------------------------------------------- +void BranchInst::updateControlTransferInst(Node *oldTarget, Node* newTarget ) { + assert(oldTarget->getKind() == newTarget->getKind()); + + LabelInst* oldLabel = (LabelInst*)oldTarget->getFirstInst(); + LabelInst* newLabel = (LabelInst*)newTarget->getFirstInst(); + + // Update source nodes branch instruction + if(getTargetLabel() == oldLabel) { + assert(newTarget->isBlockNode()); + replaceTargetLabel(newLabel); + } +} + // the following utility for conditional branches will make the fallthrough the target and // the target the fallthrough, changing the branch condition in the process @@ -106,34 +139,45 @@ void BranchInst::swapTargets(LabelInst replaceTargetLabel(target); } +Edge::Kind BranchInst::getEdgeKind(const Edge* edge) const { + Node* succ = edge->getTargetNode(); +#ifdef _DEBUG + Node* node = edge->getSourceNode(); + assert(node->isBlockNode()); + assert(succ->isBlockNode()); + assert(node->getLastInst() == this); + assert(node->getOutDegree() == 2 || (node->getOutDegree() == 3 && node->getExceptionEdge()!=NULL)); +#endif + Edge::Kind kind = getTargetLabel() == succ->getFirstInst() ? Edge::Kind_True : Edge::Kind_False; + return kind; +} + // the following utility for conditional branches will return the taken edge based on the // incoming condition. This will ignore exception edges -CFGEdge* BranchInst::getTakenEdge(uint32 result) { +Edge* BranchInst::getTakenEdge(uint32 result) { // find the node for this branch instruction - Inst *label = this->next(); - assert(label->isLabel()); - CFGNode *node = ((LabelInst*)label)->getCFGNode(); + Node *node = getNode(); + assert(node->getFirstInst()->isLabel()); LabelInst *targetLabel = getTargetLabel(); - CFGEdge* edge = NULL; - const CFGEdgeDeque& edges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { + Edge* edge = NULL; + const Edges& edges = node->getOutEdges(); + for(Edges::const_iterator eiter = edges.begin(); eiter != edges.end(); ++eiter) { edge = *eiter; - CFGNode * tar = edge->getTargetNode(); + Node * tar = edge->getTargetNode(); if (!tar->isDispatchNode() && ((result == 0) && (tar->getFirstInst() != targetLabel)) || ((result == 1) && (tar->getFirstInst() == targetLabel)) ) { break; } } - if (edge == NULL) { - ::std::cout << "WARNING, useless branch\n"; - if(node->getOutEdges().empty()) - return NULL; - else - return node->getOutEdges().front(); - } + assert(edge != NULL); + // was: + // std::cout << "WARNING, useless branch\n"; + // if(node->getOutEdges().empty()) + // return NULL; + // else + // return node->getOutEdges().front(); return edge; } @@ -147,7 +191,7 @@ void Inst::print(::std::ostream& os) con InlineInfo* ii = getCallInstInlineInfoPtr(); if ( ii && !ii->isEmpty() ) { os << " has II: "; - ii->printLevels(Log::cat_opt_inline()->ir); + ii->printLevels(Log::out()); } } @@ -409,6 +453,10 @@ void JitHelperCallInst::handlePrintEscap os << "InitializeArray"; break; case PseudoCanThrow: os << "PseudoCanThrow"; break; + case SaveThisState: + os << "SaveThisState"; break; + case ReadThisState: + os << "ReadThisState"; break; default: assert(0); break; } @@ -448,6 +496,37 @@ void TypeInst::handlePrintEscape(::std:: } } +void SwitchInst::updateControlTransferInst(Node *oldTarget, Node* newTarget ) { + assert(oldTarget->getKind() == newTarget->getKind()); + + LabelInst* oldLabel = (LabelInst*)oldTarget->getFirstInst(); + LabelInst* newLabel = (LabelInst*)newTarget->getFirstInst(); + + if (getDefaultTarget() == oldLabel) { + assert(newTarget->isBlockNode()); + replaceDefaultTargetLabel(newLabel); + } + uint32 n = getNumTargets(); + for (uint32 i = 0; i < n; i++) { + if (getTarget(i) == oldLabel) { + assert(newTarget->isBlockNode()); + replaceTargetLabel(i, newLabel); + } + } +} + +Edge::Kind SwitchInst::getEdgeKind(const Edge* edge) const { + Node* succ = edge->getTargetNode(); +#ifdef _DEBUG + Node* node = edge->getSourceNode(); + assert(node->isBlockNode()); + assert(succ->isBlockNode()); + assert(node->getLastInst() == this); +#endif + Edge::Kind kind = getDefaultTarget() == succ->getFirstInst()? Edge::Kind_False : Edge::Kind_True; + return kind; +} + void SwitchInst::handlePrintEscape(::std::ostream& os, char code) const { switch (code) { case 'l': // target labels @@ -1205,9 +1284,18 @@ InstFactory::makeMethodEntryInst(uint32 MethodMarkerInst* InstFactory::makeMethodMarkerInst(MethodMarkerInst::Kind k, MethodDesc* md, - Opnd *obj) { + Opnd *obj, Opnd *retOpnd) { assert(obj && !obj->isNull()); - MethodMarkerInst* inst = new (memManager) MethodMarkerInst(k, md, obj); + MethodMarkerInst* inst = new (memManager) MethodMarkerInst(k, md, obj, retOpnd); + inst->id = numInsts++; + inst->methodId = numMethodInsts++; + return inst; +} + +MethodMarkerInst* +InstFactory::makeMethodMarkerInst(MethodMarkerInst::Kind k, MethodDesc* md, + Opnd *retOpnd) { + MethodMarkerInst* inst = new (memManager) MethodMarkerInst(k, md, retOpnd); inst->id = numInsts++; inst->methodId = numMethodInsts++; return inst; @@ -1381,7 +1469,8 @@ InstFactory::makeTypeInst(Opcode op, Mod TypeInst* InstFactory::makeTypeInst(Opcode op, Modifier mod, Type::Tag ty, Opnd* dst, Opnd* src1, Opnd* src2, Opnd* src3, Type* td) { - Opnd* srcs[3] = { src1, src2, src3 }; + Opnd* srcs_local[3] = { src1, src2, src3 }; + Opnd** srcs = copyOpnds(srcs_local, 3); TypeInst* inst = new (memManager) TypeInst(op, mod, ty, dst, 3, srcs, td); inst->id = numInsts++; inst->methodId = numMethodInsts++; @@ -1390,7 +1479,8 @@ InstFactory::makeTypeInst(Opcode op, Mod TypeInst* InstFactory::makeTypeInst(Opcode op, Modifier mod, Type::Tag ty, Opnd* dst, Opnd* src1, Opnd* src2, Opnd* src3, Opnd* src4, Type* td) { - Opnd* srcs[4] = { src1, src2, src3, src4 }; + Opnd* srcs_local[4] = { src1, src2, src3, src4 }; + Opnd** srcs = copyOpnds(srcs_local, 4); TypeInst* inst = new (memManager) TypeInst(op, mod, ty, dst, 4, srcs, td); inst->id = numInsts++; inst->methodId = numMethodInsts++; @@ -1565,11 +1655,13 @@ InstFactory::makeVMHelperCallInst(Opcode Opnd* dst, uint32 nArgs, Opnd** args_, - VMHelperCallId id) { + VMHelperCallId id, + InlineInfo* inlInfo) { VMHelperCallInst * inst = new (memManager) VMHelperCallInst(op, mod, type, dst, nArgs, args_, id); inst->id = numInsts++; inst->methodId = numMethodInsts++; + inst->inlInfo = inlInfo; return inst; } @@ -1670,9 +1762,17 @@ InstFactory::makeMethodEntryLabel(Method Inst* InstFactory::makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc, - Opnd *obj) { + Opnd *obj, Opnd *retOpnd) { assert(obj && !obj->isNull()); - return makeMethodMarkerInst(kind, methodDesc, obj); + return makeMethodMarkerInst(kind, methodDesc, obj, + retOpnd != NULL ? retOpnd : OpndManager::getNullOpnd()); +} + +Inst* +InstFactory::makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc, + Opnd *retOpnd) { + return makeMethodMarkerInst(kind, methodDesc, + retOpnd != NULL ? retOpnd : OpndManager::getNullOpnd()); } Inst* @@ -1861,10 +1961,6 @@ Inst* InstFactory::makeThrow(ThrowModifi return makeInst(Op_Throw, Modifier(mod), Type::Void, OpndManager::getNullOpnd(), exceptionObj); } -Inst* InstFactory::makeThrowLazy(ThrowModifier mod, uint32 numArgs, Opnd **args, MethodDesc *constructor) { - return makeMethodInst(Op_ThrowLazy, mod, Type::Void, OpndManager::getNullOpnd(), numArgs, args, constructor); -} - Inst* InstFactory::makeThrowSystemException(CompilationInterface::SystemExceptionId exceptionId) { MethodDesc* enclosingMethod = 0; return makeTokenInst(Op_ThrowSystemException, Modifier(), Type::Void, @@ -1987,11 +2083,12 @@ InstFactory::makeJitHelperCall(Opnd* dst } Inst* -InstFactory::makeVMHelperCall(Opnd* dst, VMHelperCallId id, uint32 numArgs, Opnd** args) { +InstFactory::makeVMHelperCall(Opnd* dst, VMHelperCallId id, uint32 numArgs, + Opnd** args, InlineInfo* inlInfo) { Type::Tag returnType = dst->isNull()? Type::Void : dst->getType()->tag; args = copyOpnds(args, numArgs); return makeVMHelperCallInst(Op_VMHelperCall, Modifier(Exception_Sometimes), - returnType, dst, numArgs, args, id); + returnType, dst, numArgs, args, id, inlInfo); } // load, store, & move @@ -2136,11 +2233,9 @@ Inst* InstFactory::makeTauLdVirtFunAddrS } Inst* InstFactory::makeTauLdIntfcVTableAddr(Opnd* dst, Opnd* base, - Opnd *tauVtableHasIntfc, Type* vtableType) { - assert(tauVtableHasIntfc->getType()->tag == Type::Tau); return makeTypeInst(Op_TauLdIntfcVTableAddr, Modifier(), dst->getType()->tag, dst, base, - tauVtableHasIntfc, vtableType); + vtableType); } Inst* InstFactory::makeTauLdVTableAddr(Opnd* dst, Opnd* base, @@ -2417,8 +2512,8 @@ Inst* InstFactory::makeLdToken(Opnd* dst return makeTokenInst(Op_LdToken, Modifier(), Type::Object, dst, metadataToken, enclosingMethod); } -Inst* InstFactory::makeLdString(Modifier mod, Opnd* dst, MethodDesc* enclosingMethod, uint32 stringToken) { - return makeTokenInst(Op_LdString, mod, Type::SystemString, dst, stringToken, enclosingMethod); +Inst* InstFactory::makeLdRef(Modifier mod, Opnd* dst, MethodDesc* enclosingMethod, uint32 token) { + return makeTokenInst(Op_LdRef, mod, dst->getType()->tag, dst, token, enclosingMethod); } // type checking @@ -2661,7 +2756,6 @@ InstOptimizer::dispatch(Inst* inst) { case Op_Return: return caseReturn(inst); case Op_Catch: return caseCatch(inst); case Op_Throw: return caseThrow(inst); - case Op_ThrowLazy: return caseThrowLazy(inst); case Op_ThrowSystemException: return caseThrowSystemException(inst); case Op_ThrowLinkingException: return caseThrowLinkingException(inst); case Op_Leave: return caseLeave(inst); @@ -2674,7 +2768,7 @@ InstOptimizer::dispatch(Inst* inst) { case Op_Copy: return caseCopy(inst); case Op_DefArg: return caseDefArg(inst); case Op_LdConstant: return caseLdConstant(inst->asConstInst()); - case Op_LdString: return caseLdString(inst->asTokenInst()); + case Op_LdRef: return caseLdRef(inst->asTokenInst()); case Op_LdVar: return caseLdVar(inst); case Op_LdVarAddr: return caseLdVarAddr(inst); case Op_TauLdInd: return caseTauLdInd(inst); @@ -2794,22 +2888,41 @@ Inst::getCallInstInlineInfoPtr() const return ii; } -void -InlineInfoBuilder::buildInlineInfoForInst(Inst* inst, MethodDesc* target_md) +uint32 +InlineInfoBuilder::buildInlineInfoForInst(Inst* inst, uint32 currOffset, MethodDesc* target_md) { InlineInfo* ii = inst->getCallInstInlineInfoPtr(); if ( ii ) { - buildInlineInfo(ii); - if ( Log::cat_opt_inline()->isDebugEnabled() ) { - Log::cat_opt_inline()->ir << "InlineInfoBuiler: inlined call to "; + //buildInlineInfo(ii, currOffset); + InlineInfoBuilder* parBuilder = parent; + uint32 parOffset = getCurrentBcOffset(); + ii->prependLevel(getCurrentMd(), currOffset); + while (parBuilder) { + ii->prependLevel(parBuilder->getCurrentMd(), parOffset); + parOffset = parBuilder->getCurrentBcOffset(); + parBuilder = parBuilder->parent; + } + if ( Log::isEnabled() ) { + Log::out() << "InlineInfoBuiler: inlined call to "; if ( target_md ) { - Log::cat_opt_inline()->ir << target_md->getName(); + Log::out() << target_md->getName(); }else{ - Log::cat_opt_inline()->ir << "[some method]"; + Log::out() << "[some method]"; } - Log::cat_opt_inline()->ir << ", chain: "; - ii->printLevels(Log::cat_opt_inline()->ir); + Log::out() << ", chain: "; + ii->printLevels(Log::out()); } + return parOffset; + } + return currOffset; +} +void +InlineInfoBuilder::buildInlineInfo(InlineInfo* ii, uint32 offset) // ii must be non-NULL +{ + if ( parent ) { + parent->buildInlineInfo(ii, offset); + } else { + addCurrentLevel(ii, getCurrentBcOffset()); } } diff --git vm/jitrino/src/optimizer/Inst.h vm/jitrino/src/optimizer/Inst.h index ef3e3af..75a774d 100644 --- vm/jitrino/src/optimizer/Inst.h +++ vm/jitrino/src/optimizer/Inst.h @@ -24,10 +24,6 @@ #ifndef _INST_H_ #define _INST_H_ -#include <assert.h> -#include <stdio.h> -#include <iostream> -#include "open/types.h" #include "MemoryManager.h" #include "Stl.h" #include "VMInterface.h" @@ -37,14 +33,18 @@ #include "Opcode.h" #include "Opnd.h" #include "Log.h" #include "InlineInfo.h" +#include "ControlFlowGraph.h" + +#include "open/types.h" + +#include <assert.h> +#include <stdio.h> +#include <iostream> namespace Jitrino { -class CFGNode; class OpndRenameTable; class IRBuilder; -class FlowGraph; -class CFGEdge; class IRManager; class InstFactory; class PiCondition; @@ -111,58 +111,49 @@ public: // #define MAX_INST_SRCS 2 -class Inst : private Dlink { +class Inst : public CFGInst { public: virtual ~Inst() {} - // modified Dlink methods - void unlink() { - Dlink::unlink(); - node = 0; - } - void insertAfter(Inst *prev_inst) { - Dlink::insertAfter(prev_inst); - node = prev_inst->node; - } - void insertBefore(Inst *next_inst) { - Dlink::insertBefore(next_inst); - node = next_inst->node; - } - void moveTo(Inst *head) { - Inst *otheri = next(); - CFGNode *newnode = head->node; - while (otheri != this) { - otheri->node = newnode; - otheri = otheri->next(); - } - Dlink::moveTo(head); - } - void moveTailTo(Inst *oldhead, Inst* newhead) { - Dlink::moveTailTo(oldhead, newhead); - } -public: + + Inst* getNextInst() const {return (Inst*)next();} + Inst* getPrevInst() const {return (Inst*)prev();} + + bool isHeaderCriticalInst() const {return getOpcode() == Op_Catch || isLabel();} + Type::Tag getType() const { return operation.getType(); } + Opcode getOpcode() const { return operation.getOpcode(); } + Modifier getModifier() const { return operation.getModifier(); } + Operation getOperation() const {return operation;} + uint32 getId() const {return id;} + uint64 getMethodId() const {return methodId; } + void setMethodId(uint64 id) {methodId = id; } + PersistentInstructionId getPersistentInstructionId() const {return pid; } + void setPersistentInstructionId(PersistentInstructionId id) {pid = id; } + Opnd* getDst() const {return dst;} void setType(Type::Tag newType) { operation.setType(newType); } + void setModifier(Modifier newMod) { operation.setModifier(newMod); } + void setDst(Opnd* newDst) { if (dst && dst->isNull() == false && dst->isVarOpnd() == false && (dst->getInst() == this)) dst->setInst(0); @@ -170,13 +161,16 @@ public: if (dst && dst->isNull() == false && dst->isVarOpnd() == false) dst->setInst(this); } + uint32 getNumSrcOperands() const {return numSrcs;} + Opnd* getSrc(uint32 srcIndex) const { assert(srcIndex < numSrcs); if (srcIndex >= MAX_INST_SRCS) return getSrcExtended(srcIndex); return srcs[srcIndex]; } + void setSrc(uint32 srcIndex, Opnd* src) { assert(srcIndex < numSrcs); if (srcIndex >= MAX_INST_SRCS) @@ -258,14 +252,6 @@ public: bool isSigned() const { return operation.isSigned(); } - // - CFGNode *getNode() { return node; }; - CFGNode *getNodeFwd() { return node; }; - void setNode(CFGNode *n) { node = n; }; - // - // - Inst* prev() {return (Inst*)_prev;} - Inst* next() {return (Inst*)_next;} virtual bool isBranch() const { return false; }; virtual bool isCall() const { return false; }; @@ -276,7 +262,6 @@ public: virtual bool isIntrinsicCallInst() const { return false; }; virtual bool isJitHelperCallInst() const { return false; }; virtual bool isVMHelperCallInst() const { return false; }; - virtual bool isLabel() const { return false; }; virtual bool isMethodCall() const { return false; }; virtual bool isMethodEntry() const { return false; }; virtual bool isMethod() const { return false; }; @@ -403,7 +388,13 @@ protected: uint64 methodId; PersistentInstructionId pid; uint32 id; - CFGNode *node; + + + // called from CFG to detect BB->BB block edges + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + + virtual void removeRedundantBranch(); + // // protected accessor methods that deriving classes should override // @@ -422,15 +413,6 @@ public: bool isLabel() const {return true;} virtual bool isDispatchLabel() const {return false;} virtual bool isCatchLabel() const {return false;} - void setCFGNode(CFGNode* n) { - node = n; - Inst *i = next(); - while (i != this) { - i->setNode(n); - i = i->next(); - }; - } - CFGNode *getCFGNode() { return node; }; void setState(void *stat) {state = stat;} void * getState() {return state;} void visit(InstFormatVisitor& visitor) {visitor.accept(this);} @@ -447,7 +429,7 @@ private: friend class InstFactory; uint32 labelId; - void* state; + void* state; }; class DispatchLabelInst: public LabelInst { @@ -501,19 +483,31 @@ public: void removeOpnd() { setSrc(0, OpndManager::getNullOpnd()); - numSrcs = 0; + if (numSrcs) numSrcs--; } + protected: virtual void handlePrintEscape(::std::ostream&, char code) const; private: friend class InstFactory; + MethodMarkerInst(Kind k, MethodDesc* md) : - Inst(k==Entry? Op_MethodEntry : Op_MethodEnd, Modifier(), Type::Void, OpndManager::getNullOpnd()), kind(k), methodDesc(md) {} - MethodMarkerInst(Kind k, MethodDesc* md, Opnd *obj) : + Inst(k==Entry? Op_MethodEntry : Op_MethodEnd, Modifier(), Type::Void, + OpndManager::getNullOpnd()), kind(k), methodDesc(md), retOpnd(NULL) {} + + MethodMarkerInst(Kind k, MethodDesc* md, Opnd *resOpnd) : + Inst(k==Entry? Op_MethodEntry : Op_MethodEnd, Modifier(), Type::Void, + OpndManager::getNullOpnd()), kind(k), methodDesc(md), retOpnd(resOpnd) {} + + MethodMarkerInst(Kind k, MethodDesc* md, Opnd *obj, Opnd *resOpnd) : Inst(k==Entry? Op_MethodEntry : Op_MethodEnd, Modifier(), Type::Void, OpndManager::getNullOpnd(), - obj), kind(k), methodDesc(md) { assert(obj && !obj->isNull()); } + obj), kind(k), methodDesc(md), retOpnd(resOpnd) { + assert(obj && !obj->isNull()); + + } Kind kind; MethodDesc* methodDesc; + Opnd* retOpnd; }; // @@ -526,11 +520,13 @@ public: void visit(InstFormatVisitor& visitor) {visitor.accept(this);} void replaceTargetLabel(LabelInst* target) {targetLabel = target;} - LabelInst* getTargetLabel() {return targetLabel;} + LabelInst* getTargetLabel() const {return targetLabel;} void swapTargets(LabelInst *target); - CFGEdge *getTakenEdge(uint32 condition); + Edge *getTakenEdge(uint32 condition); protected: virtual void handlePrintEscape(::std::ostream&, char code) const; + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); private: friend class InstFactory; BranchInst(Opcode op, LabelInst* target) @@ -563,7 +559,7 @@ public: LabelInst** getTargets() { return targetInsts; } void visit(InstFormatVisitor& visitor) {visitor.accept(this);} bool isSwitch() const {return true;} - LabelInst* getDefaultTarget() {return defaultTargetInst;} + LabelInst* getDefaultTarget() const {return defaultTargetInst;} uint32 getNumTargets() {return numTargets;} void replaceTargetLabel(uint32 i, LabelInst* target) { assert(i < numTargets); @@ -573,6 +569,8 @@ public: protected: virtual void handlePrintEscape(::std::ostream&, char code) const; + virtual Edge::Kind getEdgeKind(const Edge* edge) const; + virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); private: friend class InstFactory; SwitchInst(Opnd* src, LabelInst** targets, uint32 nTargets, LabelInst* defTarget) @@ -1034,6 +1032,7 @@ public: return NULL; } bool isThrowLazy() const {return vmHelperId == ThrowLazy;} +InlineInfo* getInlineInfoPtr() { return inlInfo; } private: virtual void handlePrintEscape(::std::ostream&, char code) const; friend class InstFactory; @@ -1044,7 +1043,7 @@ private: uint32 nArgs, Opnd** args_, VMHelperCallId id) : Inst(op, mod, type, dst, nArgs), - vmHelperId(id) { + vmHelperId(id), inlInfo(NULL) { args = args_; switch (nArgs) { default: @@ -1061,6 +1060,7 @@ private: } Opnd** args; VMHelperCallId vmHelperId; + InlineInfo* inlInfo; }; // phi instructions @@ -1075,6 +1075,7 @@ private: : MultiSrcInst(Op_Phi, Modifier(), type, dst, nArgs, args_) { } + bool isHeaderCriticalInst() const {return true;} }; // pi instructions @@ -1151,17 +1152,14 @@ public: Opnd* tauNullChecked, Opnd* tauTypesChecked, uint32 numArgs, Opnd** args); Inst* makeJitHelperCall(Opnd* dst, JitHelperCallId id, uint32 numArgs, Opnd** args); - Inst* makeVMHelperCall(Opnd* dst, VMHelperCallId id, uint32 numArgs, Opnd** args); + Inst* makeVMHelperCall(Opnd* dst, VMHelperCallId id, uint32 numArgs, + Opnd** args, InlineInfo* inlInfo = NULL); Inst* makeReturn(Opnd* src); Inst* makeReturn(); // void return type Inst* makeCatch(Opnd* dst); Inst* makeCatchLabel(uint32 labelId, uint32 exceptionOrder, Type* exceptionType); CatchLabelInst* makeCatchLabel(uint32 exceptionOrder, Type* exceptionType); Inst* makeThrow(ThrowModifier mod, Opnd* exceptionObj); - Inst* makeThrowLazy(ThrowModifier mod, - uint32 numArgs, - Opnd **args, - MethodDesc *constructor); Inst* makeThrowSystemException(CompilationInterface::SystemExceptionId exceptionId); Inst* makeThrowLinkingException(Class_Handle encClass, uint32 CPIndex, uint32 operation); Inst* makeLeave(LabelInst* labelInst); @@ -1180,7 +1178,7 @@ public: Inst* makeLdConst(Opnd* dst, double val); Inst* makeLdConst(Opnd* dst, ConstInst::ConstValue val); Inst* makeLdNull(Opnd* dst); - Inst* makeLdString(Modifier mod, Opnd* dst, MethodDesc* enclosingMethod, uint32 stringToken); + Inst* makeLdRef(Modifier mod, Opnd* dst, MethodDesc* enclosingMethod, uint32 token); Inst* makeLdVar(Opnd* dst, VarOpnd* var); Inst* makeLdVar(Opnd* dst, SsaVarOpnd* var); Inst* makeLdVarAddr(Opnd* dst, VarOpnd* var); @@ -1196,9 +1194,7 @@ public: Inst* makeLdStaticAddr(Opnd* dst, FieldDesc*); Inst* makeLdElemAddr(Type* type, Opnd* dst, Opnd* array, Opnd* index); Inst* makeTauLdVTableAddr(Opnd* dst, Opnd* base, Opnd *tauBaseNonNull); - Inst* makeTauLdIntfcVTableAddr(Opnd* dst, Opnd* base, - Opnd *tauBaseHasInterface, - Type* vtableType); + Inst* makeTauLdIntfcVTableAddr(Opnd* dst, Opnd* base, Type* vtableType); Inst* makeTauLdVirtFunAddr(Opnd* dst, Opnd* vtable, Opnd *tauVtableHasDesc, MethodDesc*); @@ -1268,7 +1264,9 @@ public: LabelInst* makeLabel(); // method entry/exit LabelInst* makeMethodEntryLabel(MethodDesc* methodDesc); - Inst* makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc, Opnd *obj); + Inst* makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc, + Opnd *obj, Opnd *retOpnd); + Inst* makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc, Opnd *retOpnd); Inst* makeMethodMarker(MethodMarkerInst::Kind kind, MethodDesc* methodDesc); @@ -1393,7 +1391,9 @@ private: uint32 ord, Type *exceptionType); MethodEntryInst* makeMethodEntryInst(uint32 labelId, MethodDesc*) ; - MethodMarkerInst* makeMethodMarkerInst(MethodMarkerInst::Kind, MethodDesc*, Opnd *obj); + MethodMarkerInst* makeMethodMarkerInst(MethodMarkerInst::Kind, MethodDesc*, + Opnd *obj, Opnd *retOpnd); + MethodMarkerInst* makeMethodMarkerInst(MethodMarkerInst::Kind, MethodDesc*, Opnd *retOpnd); MethodMarkerInst* makeMethodMarkerInst(MethodMarkerInst::Kind, MethodDesc*); BranchInst* makeBranchInst(Opcode, LabelInst* target); @@ -1537,7 +1537,8 @@ private: Opnd* dst, uint32 nArgs, Opnd** args_, - VMHelperCallId id); + VMHelperCallId id, + InlineInfo* inlInfo = NULL); PhiInst* makePhiInst(Type::Tag type, Opnd* dst, uint32 nArgs, Opnd** args_); @@ -1680,9 +1681,6 @@ public: virtual Inst* caseThrow(Inst* inst)=0;// {return caseDefault(inst);} - virtual Inst* - caseThrowLazy(Inst* inst)=0;// {return caseDefault(inst);} - virtual Inst* caseThrowSystemException(Inst* inst)=0;// {return caseDefault(inst);} @@ -1724,7 +1722,7 @@ public: caseLdNull(ConstInst* inst)=0;// {return caseDefault(inst);} virtual Inst* - caseLdString(TokenInst* inst)=0;// {return caseDefault(inst);} + caseLdRef(TokenInst* inst)=0;// {return caseDefault(inst);} virtual Inst* caseLdVar(Inst* inst)=0;// {return caseDefault(inst);} diff --git vm/jitrino/src/optimizer/Loop.cpp vm/jitrino/src/optimizer/Loop.cpp index 3e7c5f8..6d3fb46 100644 --- vm/jitrino/src/optimizer/Loop.cpp +++ vm/jitrino/src/optimizer/Loop.cpp @@ -20,121 +20,98 @@ * */ -#include <algorithm> + +#include "escapeanalyzer.h" #include "Log.h" -#include "FlowGraph.h" #include "Inst.h" #include "Dominator.h" #include "Loop.h" #include "globalopndanalyzer.h" #include "optimizer.h" -#include "escapeanalyzer.h" +#include "FlowGraph.h" + +#include <algorithm> namespace Jitrino { -DEFINE_OPTPASS_IMPL(LoopPeelingPass, peel, "Loop Peeling") +DEFINE_SESSION_ACTION(LoopPeelingPass, peel, "Loop Peeling") void LoopPeelingPass::_run(IRManager& irm) { computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); assert(dominatorTree->isValid()); - LoopBuilder lb(irm.getNestedMemoryManager(), - irm, *dominatorTree, irm.getFlowGraph().hasEdgeProfile()); - LoopTree* loopTree = lb.computeAndNormalizeLoops(true); - if (lb.needSsaFixup()) { - fixupSsa(irm); - } - irm.setLoopTree(loopTree); - smoothProfile(irm); + LoopBuilder lb(irm.getNestedMemoryManager(), irm, *dominatorTree, irm.getFlowGraph().hasEdgeProfile()); + lb.computeLoops(true); + lb.peelLoops(); } LoopBuilder::LoopBuilder(MemoryManager& mm, IRManager& irm, DominatorTree& d, bool useProfile) : loopMemManager(mm), dom(d), irManager(irm), instFactory(irm.getInstFactory()), fg(irm.getFlowGraph()), info(NULL), root(NULL), - useProfile(useProfile), needsSsaFixup(false) + useProfile(useProfile), needsSsaFixup(false), flags(*irm.getOptimizerFlags().loopBuilderFlags) { - JitrinoParameterTable& params = irManager.getParameterTable(); - flags.hoist_loads = params.lookupBool("opt::loop::hoist_loads", false); - flags.invert = params.lookupBool("opt::loop::invert", false); - flags.peel = params.lookupBool("opt::loop::peel", true); - flags.insideout_peeling = params.lookupBool("opt::loop::insideout_peeling", false); - flags.old_static_peeling = params.lookupBool("opt::loop::old_static_peeling", false); - flags.aggressive_peeling = params.lookupBool("opt::loop::aggressive_peeling", true); - flags.peel_upto_branch = params.lookupBool("opt::loop::peel_upto_branch", true); - flags.peeling_threshold = params.lookupUint("opt::loop::peeling_threshold", 2); - flags.fullpeel = params.lookupBool("opt::loop::fullpeel", false); - flags.fullpeel_max_inst = params.lookupUint("opt::loop::fullpeel_max_inst", 40); - flags.unroll = params.lookupBool("opt::loop::unroll", false); - flags.unroll_count = params.lookupUint("opt::loop::unroll_count", 4); - flags.unroll_threshold = params.lookupUint("opt::loop::unroll_threshold", 10); - flags.eliminate_critical_back_edge = params.lookupBool("opt::loop::eliminate_critical_back_edge", false); - flags.peel_upto_branch_no_instanceof = params.lookupBool("opt::loop::peel_upto_branch::no_instanceof", true); } -void LoopBuilder::showFlagsFromCommandLine() -{ - Log::out() << " opt::loop::hoist_loads[={on|OFF}] = peel assuming load hoisting" << ::std::endl; - Log::out() << " opt::loop::invert[={on|OFF}] = try to invert loops to reduce branches" << ::std::endl; - Log::out() << " opt::loop::peel[={ON|off}] = do peeling" << ::std::endl; - Log::out() << " opt::loop::insideout_peeling[={on|OFF}] = ?" << ::std::endl; - Log::out() << " opt::loop::aggressive_peeling[={ON|off}] = be aggressive about peeling" << ::std::endl; - Log::out() << " opt::loop::peel_upto_branch[={on|OFF}] = peel only up to a branch" << ::std::endl; - Log::out() << " opt::loop::old_static_peeling[={on|OFF}] = use old-style peeling for static runs" << ::std::endl; - Log::out() << " opt::loop::peeling_threshold[=int] = ? (default 2)" << ::std::endl; - Log::out() << " opt::loop::unroll[={on|OFF}] = ?" << ::std::endl; - Log::out() << " opt::loop::unroll_count[=int] = ? (default 4)" << ::std::endl; - Log::out() << " opt::loop::unroll_threshold[=int] = ? (default 10)" << ::std::endl; - Log::out() << " opt::loop::eliminate_critical_back_edge[={on|OFF}] = ?" << ::std::endl; - Log::out() << " opt::loop::peel_upto_branch::no_instanceof[={on|OFF}] = with peel_upto_branch, peel only up to a branch or instanceof" << ::std::endl; -} +void LoopBuilder::readFlags(Action* argSource, LoopBuilderFlags* flags) { + IAction::HPipeline p = NULL; //default pipeline for argSource + flags->hoist_loads = argSource->getBoolArg(p, "loop.hoist_loads", false); + flags->invert = argSource->getBoolArg(p, "loop.invert", false); + flags->peel = argSource->getBoolArg(p, "loop.peel", true); + flags->insideout_peeling = argSource->getBoolArg(p, "loop.insideout_peeling", false); + flags->old_static_peeling = argSource->getBoolArg(p, "loop.old_static_peeling", false); + flags->aggressive_peeling = argSource->getBoolArg(p, "loop.aggressive_peeling", true); + flags->peel_upto_branch = argSource->getBoolArg(p, "loop.peel_upto_branch", true); + flags->peeling_threshold = argSource->getIntArg(p, "loop.peeling_threshold", 2); + flags->fullpeel = argSource->getBoolArg(p, "loop.fullpeel", false); + flags->fullpeel_max_inst = argSource->getIntArg(p, "loop.fullpeel_max_inst", 40); + flags->unroll = argSource->getBoolArg(p, "loop.unroll", false); + flags->unroll_count = argSource->getIntArg(p, "loop.unroll_count", 4); + flags->unroll_threshold = argSource->getIntArg(p, "loop.unroll_threshold", 10); + flags->peel_upto_branch_no_instanceof = argSource->getBoolArg(p, "loop.peel_upto_branch_no_instanceof", true); -// -// If loop A is contained in loop B, then B's header must dominate -// A's header. We sort loop edges based on headers' dfn so as to -// construct loops from the outermost to the innermost -// -void LoopBuilder::formLoopHierarchy(StlVector<CFGEdge*>& edges, - uint32 numLoops) { - if (numLoops == 0) - return; - - // new blocks are created, recompute df num - uint32 numBlocks = fg.getNodeCount(); - - // create a root loop containing all loops within the method - createLoop(NULL,NULL,numBlocks); - - fg.getNodeCount(); - - // create loops in df num order - for (uint32 j = 0; j < numLoops; j++) - createLoop(edges[j]->getTargetNode(), edges[j]->getSourceNode(), numBlocks); +} +void LoopBuilder::showFlags(std::ostream& os) { + os << " loop builder flags:"<<std::endl; + os << " loop.hoist_loads[={on|OFF}] - peel assuming load hoisting" << std::endl; + os << " loop.invert[={on|OFF}] - try to invert loops to reduce branches" << std::endl; + os << " loop.peel[={ON|off}] - do peeling" << std::endl; + os << " loop.insideout_peeling[={on|OFF}]" << std::endl; + os << " loop.aggressive_peeling[={ON|off}] - be aggressive about peeling" << std::endl; + os << " loop.peel_upto_branch[={on|OFF}] - peel only up to a branch" << std::endl; + os << " loop.old_static_peeling[={on|OFF}] - use old-style peeling for static runs" << std::endl; + os << " loop.peeling_threshold[=int] - (default 2)" << std::endl; + os << " loop.unroll[={on|OFF}]" << std::endl; + os << " loop.unroll_count[=int] - (default 4)" << std::endl; + os << " loop.unroll_threshold[=int] - (default 10)" << std::endl; + os << " loop.peel_upto_branch_no_instanceof[={on|OFF}] - with peel_upto_branch, peel only up to a branch or instanceof" << std::endl; } template <class IDFun> class LoopMarker { public: - static uint32 markNodesOfLoop(StlBitVector& nodesInLoop, CFGNode* header, CFGNode* tail); + static uint32 markNodesOfLoop(StlBitVector& nodesInLoop, Node* header, Node* tail); private: - static uint32 backwardMarkNode(StlBitVector& nodesInLoop, CFGNode* node, StlBitVector& visited); - static uint32 countInsts(CFGNode* node); + static uint32 backwardMarkNode(StlBitVector& nodesInLoop, Node* node, StlBitVector& visited); + static uint32 countInsts(Node* node); }; template <class IDFun> -uint32 LoopMarker<IDFun>::countInsts(CFGNode* node) { +uint32 LoopMarker<IDFun>::countInsts(Node* node) { uint32 count = 0; - Inst* first = node->getFirstInst(); - for(Inst* inst = first->next(); inst != first; inst = inst->next()) - ++count; + Inst* first = (Inst*)node->getFirstInst(); + if (first != NULL) { + for(Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) + ++count; + } return count; } template <class IDFun> uint32 LoopMarker<IDFun>::backwardMarkNode(StlBitVector& nodesInLoop, - CFGNode* node, + Node* node, StlBitVector& visited) { static IDFun getId; if(visited.setBit(node->getId())) @@ -143,10 +120,10 @@ uint32 LoopMarker<IDFun>::backwardMarkNo uint32 count = countInsts(node); nodesInLoop.setBit(getId(node)); - const CFGEdgeDeque& inEdges = node->getInEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& inEdges = node->getInEdges(); + Edges::const_iterator eiter; for(eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { - CFGEdge* e = *eiter; + Edge* e = *eiter; count += backwardMarkNode(nodesInLoop, e->getSourceNode(), visited); } return count; @@ -157,8 +134,8 @@ uint32 LoopMarker<IDFun>::backwardMarkNo // template <class IDFun> uint32 LoopMarker<IDFun>::markNodesOfLoop(StlBitVector& nodesInLoop, - CFGNode* header, - CFGNode* tail) { + Node* header, + Node* tail) { static IDFun getId; uint32 maxSize = ::std::max(getId(header), getId(tail)); MemoryManager tmm(maxSize >> 3, "LoopBuilder::markNodesOfLoop.tmm"); @@ -173,11 +150,6 @@ uint32 LoopMarker<IDFun>::markNodesOfLoo return count + backwardMarkNode(nodesInLoop, tail, visited); } -uint32 LoopBuilder::markNodesOfLoop(StlBitVector& nodesInLoop, - CFGNode* header, - CFGNode* tail) { - return LoopMarker<IdentifyByDFN>::markNodesOfLoop(nodesInLoop, header, tail); -} // @@ -185,7 +157,7 @@ uint32 LoopBuilder::markNodesOfLoop(StlB // we traverse descendants to find who contains the header and return the // descendant loop // -LoopNode* LoopBuilder::findEnclosingLoop(LoopNode* loop, CFGNode* header) { +LoopNode* LoopBuilder::findEnclosingLoop(LoopNode* loop, Node* header) { for (LoopNode* l = loop->getChild(); l != NULL; l = l->getSiblings()) if (l->inLoop(header)) return findEnclosingLoop(l, header); @@ -194,157 +166,15 @@ LoopNode* LoopBuilder::findEnclosingLoop return loop; } -void LoopBuilder::createLoop(CFGNode* header, - CFGNode* tail, - uint32 numBlocks) { - if (header == NULL) // root loop - root = new (loopMemManager) LoopNode(NULL, NULL); - else { - // walk up the hierarchy to find which loop contains it - StlBitVector* nodesInLoop = new (loopMemManager) StlBitVector(loopMemManager,numBlocks); - LoopNode* loop = new (loopMemManager) LoopNode(header, nodesInLoop); - findEnclosingLoop((LoopNode*) root, header)->addChild(loop); - - // make blocks within the loop using backward depth first - // search starting from tail - markNodesOfLoop(*nodesInLoop, header, tail); - } -} - -// numLoopEdges loops share the same header -// create a new block that sinks all loop edges (the edges are no longer -// loop edges). create a new loop edge <block,header>. -// return the newly created block. -// -CFGEdge* LoopBuilder::coalesceEdges(StlVector<CFGEdge*>& edges, - uint32 numEdges) { - CFGNode* header = edges.back()->getTargetNode(); - - // create a new block and re-target all loop edges to the block - CFGNode* block = fg.createBlock(instFactory.makeLabel()); - - for (uint32 nE=numEdges; nE != 0; nE--) { - // remove edge <pred,header> - CFGEdge* e = edges.back(); - edges.pop_back(); - assert(e->getTargetNode() == header); // must share the same header - - fg.replaceEdgeTarget(e, block); - block->setFreq(block->getFreq()+e->getSourceNode()->getFreq()*e->getEdgeProb()); - } - if (numEdges > 1) { - // copy any phi nodes from successor - Inst* phi = header->getFirstInst()->next(); - for (; phi->isPhi(); phi = phi->next()) { - Opnd *orgDst = phi->getDst(); - SsaVarOpnd *ssaOrgDst = orgDst->asSsaVarOpnd(); - assert(ssaOrgDst); - VarOpnd *theVar = ssaOrgDst->getVar(); - assert(theVar); - SsaVarOpnd* newDst = irManager.getOpndManager().createSsaVarOpnd(theVar); - Inst *newInst = instFactory.makePhi(newDst, 0, 0); - PhiInst *newPhiInst = newInst->asPhiInst(); - assert(newPhiInst); - uint32 n = phi->getNumSrcOperands(); - for (uint32 i=0; i<n; i++) { - instFactory.appendSrc(newPhiInst, phi->getSrc(i)); - } - PhiInst *phiInst = phi->asPhiInst(); - assert(phiInst); - instFactory.appendSrc(phiInst, newDst); - block->prependAfterCriticalInst(newInst); - needsSsaFixup = true; - } - } - // create factored edge <block,header> - CFGEdge* edge = fg.addEdge(block,header); - edge->setEdgeProb(1.0); - return edge; -} -// -// check each header to see if multiple loops share the head -// if found, coalesce those loop edges. -// return number of found loops -uint32 LoopBuilder::findLoopEdges(MemoryManager& mm, - StlVector<CFGNode*>& headers, // in - StlVector<CFGEdge*>& loopEdges) { // out - uint32 numLoops = 0; - while (!headers.empty()) { - MemoryManager tmm(16*sizeof(CFGEdge*)*2,"LoopBuilder::findLoopEdges.tmm"); - StlVector<CFGEdge*> entryEdges(tmm); - - CFGNode* head = headers.back(); - headers.pop_back(); - - uint32 numLoopEdges = 0; - uint32 numEntryEdges = 0; - // if n dominates its predecessor, then the edge is an loop back edge - const CFGEdgeDeque& inEdges = head->getInEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { - CFGNode* pred = (*eiter)->getSourceNode(); - if (dom.dominates(head, pred)) { - loopEdges.push_back(*eiter); - numLoopEdges++; - } else { - entryEdges.push_back(*eiter); - numEntryEdges++; - } - } - assert(numLoopEdges != 0 && numEntryEdges != 0); - numLoops++; - - if (head->isBasicBlock()) { - // Create unique preheader if - // a) more than one entry edge or - // b) the one entry edge is a critical edge - if ((numEntryEdges > 1) || (entryEdges.front()->getSourceNode()->getOutDegree() > 1)) { - coalesceEdges(entryEdges, numEntryEdges); - } - // Create unique tail if - // a) more than one back edge or - // b) the one back edge is a critical edge - if ((numLoopEdges > 1) || (flags.eliminate_critical_back_edge && (loopEdges.front()->getSourceNode()->getOutDegree() > 1))) { - CFGEdge* backEdge = coalesceEdges(loopEdges, numLoopEdges); - loopEdges.push_back(backEdge); - } - } - } - return numLoops; -} - -// -// we find loop headers and then find loop edges because coalesceLoops -// introduces new blocks and edges into the flow graph. dom does not -// dominator information for the newly created blocks. -// -void LoopBuilder::findLoopHeaders(StlVector<CFGNode*>& headers) { // out - const CFGNodeDeque& nodes = fg.getNodes(); - CFGNodeDeque::const_iterator niter; - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* n = *niter; - // if n dominates its predecessor, then the edge is an loop back edge - const CFGEdgeDeque& edges = n->getInEdges(); - CFGEdgeDeque::const_iterator eiter; - for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { - CFGNode* pred = (*eiter)->getSourceNode(); - if (pred->isBlockNode() && dom.dominates(n, pred)) { - headers.push_back(n); - break; - } - } - } -} - -bool noStoreOrSynch(FlowGraph& fg) { - const CFGNodeDeque& nodes = fg.getNodes(); - CFGNodeDeque::const_iterator niter; +bool noStoreOrSynch(ControlFlowGraph& fg) { + const Nodes& nodes = fg.getNodes(); + Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* n = *niter; - Inst* first = n->getFirstInst(); - for(Inst* inst = first->next(); inst != first; inst = inst->next()) { + Node* n = *niter; + Inst* first = (Inst*)n->getFirstInst(); + for(Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (inst->getOperation().isStoreOrSync()) { return false; } @@ -375,7 +205,7 @@ bool LoopBuilder::isVariantInst(Inst* in Opcode op = operation.getOpcode(); bool isfinalload = false; - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.cse_final) { switch (inst->getOpcode()) { case Op_TauLdInd: @@ -471,7 +301,7 @@ bool LoopBuilder::isVariantInst(Inst* in return false; } -void LoopBuilder::hoistHeaderInvariants(CFGNode* preheader, CFGNode* header, StlVector<Inst*>& invariantInsts) { +void LoopBuilder::hoistHeaderInvariants(Node* preheader, Node* header, StlVector<Inst*>& invariantInsts) { assert(preheader->getOutDegree() == 1 && preheader->getOutEdges().front()->getTargetNode() == header); StlVector<Inst*>::iterator iiter; @@ -482,26 +312,27 @@ void LoopBuilder::hoistHeaderInvariants( break; } inst->unlink(); - preheader->append(inst); + preheader->appendInst(inst); } } -bool LoopBuilder::isInversionCandidate(CFGNode* originalHeader, CFGNode* header, StlBitVector& nodesInLoop, CFGNode*& next, CFGNode*& exit) { - if(Log::cat_opt_loop()->isDebugEnabled()) { +bool LoopBuilder::isInversionCandidate(Node* originalHeader, Node* header, StlBitVector& nodesInLoop, Node*& next, Node*& exit) { + if(Log::isEnabled()) { Log::out() << "Consider rotating "; - header->printLabel(Log::out()); - Log::out() << " df = (" << (int) header->getDfNum() << ")" << ::std::endl; + FlowGraph::printLabel(Log::out(), header); + Log::out() << " df = (" << (int) header->getDfNum() << ")" << std::endl; } assert(nodesInLoop.getBit(header->getId())); if (flags.aggressive_peeling) { if (header->getOutDegree() == 1) { next = header->getOutEdges().front()->getTargetNode(); - if(next->getInDegree() > 1 && next != originalHeader - ) { + if(next->getInDegree() > 1 && next != originalHeader) { // A pre-header for an inner loop - do not peel. - Log::cat_opt_loop()->debug << "Stop peeling node at L" << (int) header->getLabelId() << ": preheader for inner loop. " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Stop peeling node at ";FlowGraph::printLabel(Log::out(), header); Log::out()<<": preheader for inner loop. " << std::endl; + } return false; } exit = NULL; @@ -510,12 +341,14 @@ bool LoopBuilder::isInversionCandidate(C } if (header->getOutDegree() != 2) { - Log::cat_opt_loop()->debug << "Stop peeling node at L" << (int) header->getLabelId() << ": no exit. " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Stop peeling node at L"; FlowGraph::printLabel(Log::out(), header); Log::out() << ": no exit. " << std::endl; + } return false; } - CFGNode* succ1 = header->getOutEdges().front()->getTargetNode(); - CFGNode* succ2 = header->getOutEdges().back()->getTargetNode(); + Node* succ1 = header->getOutEdges().front()->getTargetNode(); + Node* succ2 = header->getOutEdges().back()->getTargetNode(); // Check if either succ is an exit. if(nodesInLoop.getBit(succ1->getId())) { @@ -524,7 +357,9 @@ bool LoopBuilder::isInversionCandidate(C exit = succ2; } else { // Both succ's are in loop, no inversion. - Log::cat_opt_loop()->debug << "Stop peeling node at L" << (int) header->getLabelId() << ": no exit. " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Stop peeling node at L"; FlowGraph::printLabel(Log::out(), header); Log::out()<< ": no exit. " << std::endl; + } return false; } } else { @@ -534,11 +369,12 @@ bool LoopBuilder::isInversionCandidate(C exit = succ1; } - if(next->getInDegree() > 1 && next != originalHeader - ) { + if(next->getInDegree() > 1 && next != originalHeader ) { // If next has more than one in edge, it must be the header // of an inner loop. Do not peel its preheader. - Log::cat_opt_loop()->debug << "Stop peeling node at L" << (int) header->getLabelId() << ": preheader for inner loop. " << ::std::endl; + if (Log::isEnabled()) { + Log::out()<< "Stop peeling node at L" ; FlowGraph::printLabel(Log::out(), header); Log::out() << ": preheader for inner loop. " << std::endl; + } return false; } @@ -546,7 +382,7 @@ bool LoopBuilder::isInversionCandidate(C } // Perform loop inversion for each recorded loop. -void LoopBuilder::peelLoops(StlVector<CFGEdge*>& loopEdgesIn) { +void LoopBuilder::peelLoops(StlVector<Edge*>& loopEdgesIn) { // Mark the temporaries that are local to a given basic block GlobalOpndAnalyzer globalOpndAnalyzer(irManager); globalOpndAnalyzer.doAnalysis(); @@ -562,35 +398,35 @@ void LoopBuilder::peelLoops(StlVector<CF // Threshold at which a block is considered hot double heatThreshold = irManager.getHeatThreshold(); - StlVector<CFGEdge*> loopEdges(peelmem); + StlVector<Edge*> loopEdges(peelmem); if(flags.insideout_peeling) { - StlVector<CFGEdge*>::reverse_iterator i = loopEdgesIn.rbegin(); while (i != loopEdgesIn.rend()) { + StlVector<Edge*>::reverse_iterator i = loopEdgesIn.rbegin(); while (i != loopEdgesIn.rend()) { loopEdges.insert(loopEdges.end(), *i); i++; } } else { - StlVector<CFGEdge*>::iterator i = loopEdgesIn.begin(); + StlVector<Edge*>::iterator i = loopEdgesIn.begin(); while (i != loopEdgesIn.end()) { loopEdges.insert(loopEdges.end(), *i); i++; } } - StlVector<CFGEdge*>::iterator i; + StlVector<Edge*>::iterator i; for(i = loopEdges.begin(); i != loopEdges.end(); ++i) { // The current back-edge - CFGEdge* backEdge = *i; + Edge* backEdge = *i; // The initial header - CFGNode* header = backEdge->getTargetNode(); + Node* header = backEdge->getTargetNode(); assert(header->getInDegree() == 2); - CFGNode* originalInvertedHeader = header; + Node* originalInvertedHeader = header; // The initial loop end - CFGNode* tail = backEdge->getSourceNode(); + Node* tail = backEdge->getSourceNode(); // The initial preheader - CFGNode* preheader = header->getInEdges().front()->getSourceNode(); + Node* preheader = header->getInEdges().front()->getSourceNode(); if (preheader == tail) preheader = header->getInEdges().back()->getSourceNode(); @@ -607,34 +443,34 @@ void LoopBuilder::peelLoops(StlVector<CF // Perform loop inversion until header has no exit condition or // until one iteration is peeled. - CFGNode* next; - CFGNode* exit; + Node* next; + Node* exit; if (useProfile || !flags.old_static_peeling) { // // Only peel hot loops // if(useProfile) { - double preheaderFreq = preheader->getFreq(); - if(header->getFreq() < heatThreshold || header->getFreq() < preheaderFreq*flags.peeling_threshold || header->getFreq() == 0) + double preheaderFreq = preheader->getExecCount(); + if(header->getExecCount() < heatThreshold || header->getExecCount() < preheaderFreq*flags.peeling_threshold || header->getExecCount() == 0) continue; } // // Rotate loop one more time if the tail is not a branch (off by default) // - Opcode op1 = tail->getLastInst()->getOpcode(); - Opcode op2 = header->getLastInst()->getOpcode(); + Opcode op1 = ((Inst*)tail->getLastInst())->getOpcode(); + Opcode op2 = ((Inst*)header->getLastInst())->getOpcode(); if(flags.invert && (op1 != Op_Branch) && (op1 != Op_PredBranch) && (op2 != Op_Branch) && (op2 != Op_PredBranch)) { if(isInversionCandidate(originalInvertedHeader, header, nodesInLoop, next, exit)) { - preheader = fg.tailDuplicate(preheader, header, defUses); + preheader = FlowGraph::tailDuplicate(irManager, preheader, header, defUses); tail = header; header = next; - assert(tail->findTarget(header) != NULL && preheader->findTarget(header) != NULL); - if(tail->findTarget(header) == NULL) { - tail = (CFGNode*) tail->getUnconditionalEdge()->getTargetNode(); - assert(tail != NULL && tail->findTarget(header) != NULL); + assert(tail->findTargetEdge(header) != NULL && preheader->findTargetEdge(header) != NULL); + if(tail->findTargetEdge(header) == NULL) { + tail = tail->getUnconditionalEdge()->getTargetNode(); + assert(tail != NULL && tail->findTargetEdge(header) != NULL); } originalInvertedHeader = header; } @@ -643,8 +479,8 @@ void LoopBuilder::peelLoops(StlVector<CF // // Compute blocks to peel // - CFGNode* newHeader = header; - CFGNode* newTail = NULL; + Node* newHeader = header; + Node* newTail = NULL; StlBitVector nodesToPeel(tmm, maxSize); if(flags.fullpeel) { if(loopSize <= flags.fullpeel_max_inst) { @@ -653,16 +489,16 @@ void LoopBuilder::peelLoops(StlVector<CF } } else { while(isInversionCandidate(originalInvertedHeader, newHeader, nodesInLoop, next, exit)) { - if(Log::cat_opt_loop()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Peel "; - newHeader->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), newHeader); + Log::out() << std::endl; } newTail = newHeader; nodesToPeel.setBit(newHeader->getId()); newHeader = next; if(newHeader == originalInvertedHeader) { - Log::cat_opt_loop()->debug << "One iteration peeled" << ::std::endl; + Log::out() << "One iteration peeled" << std::endl; break; } } @@ -674,29 +510,28 @@ void LoopBuilder::peelLoops(StlVector<CF // Break final header at branch to peel more instructions // if(header != originalInvertedHeader) { - Inst* last = header->getLastInst(); + Inst* last = (Inst*)header->getLastInst(); if(header->getOutDegree() > 1) - last = last->prev(); + last = last->getPrevInst(); if (flags.peel_upto_branch_no_instanceof) { - Inst *first = header->getFirstInst(); - while ((first != last) && - (first->getOpcode() != Op_TauInstanceOf)) { - first = first->next(); + Inst *first = (Inst*)header->getFirstInst(); + while ((first != last) && (first->getOpcode() != Op_TauInstanceOf)) { + first = first->getNextInst(); } last = first; } - CFGNode* sinkNode = fg.splitNodeAtInstruction(last); + Node* sinkNode = fg.splitNodeAtInstruction(last, true, false, instFactory.makeLabel()); newTail = header; nodesToPeel.resize(sinkNode->getId()+1); nodesToPeel.setBit(header->getId()); - if(Log::cat_opt_loop()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Sink Node = "; - sinkNode->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), sinkNode); Log::out() << ", Header = "; - header->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), header); Log::out() << ", Original Header = "; - originalInvertedHeader->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), originalInvertedHeader); + Log::out() << std::endl; } header = sinkNode; } @@ -706,17 +541,17 @@ void LoopBuilder::peelLoops(StlVector<CF // Peel the nodes // if(newTail != NULL) { - CFGEdge* entryEdge = (CFGEdge*) preheader->findTarget(originalInvertedHeader); - double peeledFreq = preheader->getFreq() * entryEdge->getEdgeProb(); - CFGNode* peeled = fg.duplicateRegion(originalInvertedHeader, nodesToPeel, defUses, peeledFreq); + Edge* entryEdge = preheader->findTargetEdge(originalInvertedHeader); + double peeledFreq = preheader->getExecCount() * entryEdge->getEdgeProb(); + Node* peeled = FlowGraph::duplicateRegion(irManager, originalInvertedHeader, nodesToPeel, defUses, peeledFreq); fg.replaceEdgeTarget(entryEdge, peeled); - if(newTail->findTarget(header) == NULL) { + if(newTail->findTargetEdge(header) == NULL) { // // An intervening stVar block was added to promote a temp to a var // in the duplicated block. The new tail should be the stVar block. // - tail = (CFGNode*) newTail->getUnconditionalEdge()->getTargetNode(); - assert(tail != NULL && tail->findTarget(header) != NULL); + tail = newTail->getUnconditionalEdge()->getTargetNode(); + assert(tail != NULL && tail->findTargetEdge(header) != NULL); } else { tail = newTail; } @@ -727,19 +562,19 @@ void LoopBuilder::peelLoops(StlVector<CF } } - if(flags.unroll && newHeader == originalInvertedHeader && newTail != NULL && header->getFreq() >= heatThreshold && (header->getFreq() >= flags.unroll_threshold * preheader->getFreq())) { + if(flags.unroll && newHeader == originalInvertedHeader && newTail != NULL && header->getExecCount() >= heatThreshold && (header->getExecCount() >= flags.unroll_threshold * preheader->getExecCount())) { header = newHeader; // n is the number of times to unroll the loop - uint32 n = ::std::min(flags.unroll_count, (uint32) (header->getFreq() / preheader->getFreq())); - double headerFreq = header->getFreq(); - CFGNode* backTarget = header; - CFGEdge* backEdge = (CFGEdge*) tail->findTarget(header); - double noEarlyExitProb = (tail->getFreq() * backEdge->getEdgeProb()) / header->getFreq(); + uint32 n = ::std::min(flags.unroll_count, (uint32) (header->getExecCount() / preheader->getExecCount())); + double headerFreq = header->getExecCount(); + Node* backTarget = header; + Edge* backEdge = tail->findTargetEdge(header); + double noEarlyExitProb = (tail->getExecCount() * backEdge->getEdgeProb()) / header->getExecCount(); if(!(noEarlyExitProb > 0 && noEarlyExitProb <= 1)) { - Log::cat_opt_loop()->fail << "headerFreq=" << headerFreq << ::std::endl; - Log::cat_opt_loop()->fail << "tailFreq=" << tail->getFreq() << ::std::endl; - Log::cat_opt_loop()->fail << "backProb=" << backEdge->getEdgeProb() << ::std::endl; - Log::cat_opt_loop()->fail << "noEarlyExit=" << noEarlyExitProb << ::std::endl; + Log::out() << "headerFreq=" << headerFreq << std::endl; + Log::out() << "tailFreq=" << tail->getExecCount() << std::endl; + Log::out() << "backProb=" << backEdge->getEdgeProb() << std::endl; + Log::out() << "noEarlyExit=" << noEarlyExitProb << std::endl; assert(0); } @@ -752,17 +587,17 @@ void LoopBuilder::peelLoops(StlVector<CF sum += scale; } for(k = 0; k < (n-1); ++k) { - CFGNode* unrolled = fg.duplicateRegion(header, nodesToPeel, defUses, headerFreq * scale / sum); + Node* unrolled = FlowGraph::duplicateRegion(irManager, header, nodesToPeel, defUses, headerFreq * scale / sum); scale /= noEarlyExitProb; - backEdge = (CFGEdge*) tail->findTarget(backTarget); + backEdge = tail->findTargetEdge(backTarget); if(backEdge == NULL) { // // An intervening stVar block was added to promote a temp to a var // in the duplicated block. The new tail should be the stVar block. // - tail = (CFGNode*) tail->getUnconditionalEdge()->getTargetNode(); + tail = tail->getUnconditionalEdge()->getTargetNode(); assert(tail != NULL); - CFGEdge* backEdge = (CFGEdge*) tail->findTarget(backTarget); + Edge* backEdge = tail->findTargetEdge(backTarget); if( !(backEdge != NULL) ) assert(0); } fg.replaceEdgeTarget(backEdge, unrolled); @@ -774,40 +609,42 @@ void LoopBuilder::peelLoops(StlVector<CF tail = header->getInEdges().back()->getSourceNode(); } if(preheader->getOutDegree() > 1) { - CFGEdge* edge = (CFGEdge*) preheader->findTarget(header); + Edge* edge = preheader->findTargetEdge(header); assert(edge != NULL); - preheader = fg.spliceBlockOnEdge(edge); + preheader = fg.spliceBlockOnEdge(edge, instFactory.makeLabel()); } } else { while(isInversionCandidate(header, header, nodesInLoop, next, exit)) { - Log::cat_opt_loop()->debug << "Consider peeling node at L" << (int) header->getLabelId() << ::std::endl; + if(Log::isEnabled()) { + Log::out() << "Consider peeling node at L"; FlowGraph::printLabel(Log::out(), header); Log::out() << std::endl; + } assert(header->isBlockNode()); assert(header->getInDegree() == 2); - assert(header->findSource(preheader) != NULL); - assert(header->findSource(tail) != NULL); + assert(header->findSourceEdge(preheader) != NULL); + assert(header->findSourceEdge(tail) != NULL); // Find variant instructions. Invariant instructions need not be duplicated. StlVector<Inst*> variantInsts(tmm); StlHashSet<Opnd*> variantOpnds(tmm); StlVector<Inst*> invariantInsts(tmm); - Inst* first = header->getFirstInst(); + Inst* first = (Inst*)header->getFirstInst(); Inst* inst; - for(inst = first->next(); inst != first; inst = inst->next()) { + for(inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (isVariantInst(inst, variantOpnds)) { - if (Log::cat_opt_loop()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inst "; inst->print(Log::out()); - Log::out() << " is variant" << ::std::endl; + Log::out() << " is variant" << std::endl; } variantInsts.push_back(inst); Opnd* dst = inst->getDst(); variantOpnds.insert(dst); } else { - if (Log::cat_opt_loop()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inst "; inst->print(Log::out()); - Log::out() << " is invariant" << ::std::endl; + Log::out() << " is invariant" << std::endl; } invariantInsts.push_back(inst); } @@ -815,17 +652,17 @@ void LoopBuilder::peelLoops(StlVector<CF // Heuristic #0: If no invariant in header, don't peel. if (invariantInsts.empty()) { - Log::cat_opt_loop()->debug << "Peeling heuristic #0, no invariant" << ::std::endl; + Log::out() << "Peeling heuristic #0, no invariant" << std::endl; break; } // Heuristic #1: If the last instruction is a variant check, stop peeling. - Inst* last = header->getLastInst(); + Inst* last = (Inst*)header->getLastInst(); if (last->getOperation().isCheck() && !variantInsts.empty() && last == variantInsts.back() && !(last->getDst()->isNull() || (last->getDst()->getType()->tag == Type::Tau))) { hoistHeaderInvariants(preheader, header, invariantInsts); - Log::cat_opt_loop()->debug << "Peeling heuristic #1, last inst is variant check" << ::std::endl; + Log::out() << "Peeling heuristic #1, last inst is variant check" << std::endl; break; } // Heuristic #2: If a defined tmp may be live on exit, don't peel this node. @@ -833,7 +670,7 @@ void LoopBuilder::peelLoops(StlVector<CF StlVector<Inst*> globalInsts(tmm); Opnd* unhandledGlobal = NULL; bool hasExit = exit != NULL; - bool exitIsUnwind = hasExit && (exit == fg.getUnwind()); + bool exitIsUnwind = hasExit && (exit == fg.getUnwindNode()); bool exitIsNotDominated = !hasExit || dom.hasDomInfo(header) && dom.hasDomInfo(exit) && !dom.dominates(header, exit); StlVector<Inst*>::iterator iiter; @@ -851,64 +688,69 @@ void LoopBuilder::peelLoops(StlVector<CF } } if (unhandledGlobal != NULL) { - if (Log::cat_opt_loop()->isDebugEnabled()) { - Log::out() << "Stop peeling node at L" << (int) header->getLabelId() << ": unhandled global operand. "; + if (Log::isEnabled()) { + Log::out() << "Stop peeling node at " ; FlowGraph::printLabel(Log::out(), header); Log::out() << ": unhandled global operand. "; unhandledGlobal->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } hoistHeaderInvariants(preheader, header, invariantInsts); break; } // Duplicate instructions - CFGNode* peeled = fg.createBlockNode(); - Log::cat_opt_loop()->debug << "Peeling node L" << (int) header->getLabelId() << " as L" << (int) peeled->getLabelId() << ::std::endl; + Node* peeled = fg.createBlockNode(instFactory.makeLabel()); + if (Log::isEnabled()) { + Log::out() << "Peeling node "; FlowGraph::printLabel(Log::out(), header); Log::out() << " as "; FlowGraph::printLabel(Log::out(), peeled); Log::out() << std::endl; + } Inst* nextInst; // Peel instructions to peeled block. Leave clones of variant insts. - for(inst = first->next(), iiter = variantInsts.begin(); inst != first; inst = nextInst) { - nextInst = inst->next(); + for(inst = first->getNextInst(), iiter = variantInsts.begin(); inst != NULL; inst = nextInst) { + nextInst = inst->getNextInst(); if (iiter != variantInsts.end() && inst == *iiter) { // Make clone in place. ++iiter; Inst* clone = instFactory.clone(inst, opndManager, duplicateTable); clone->insertBefore(nextInst); inst->unlink(); - if (Log::cat_opt_loop()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Peeling: copying "; inst->print(Log::out()); Log::out() << " to "; clone->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } else { if(inst->getOperation().canThrow()) - fg.eliminateCheck(header, inst, false); + FlowGraph::eliminateCheck(fg, header, inst, false); else inst->unlink(); - if (Log::cat_opt_loop()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Peeling: not copying "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } - peeled->append(inst); + peeled->appendInst(inst); } assert(iiter == variantInsts.end()); - fg.replaceEdgeTarget(preheader->findTarget(header), peeled); - if (hasExit) + fg.replaceEdgeTarget(preheader->findTargetEdge(header), peeled); + if (hasExit) { fg.addEdge(peeled, exit); + } fg.addEdge(peeled, next); if (!globalInsts.empty()) { OpndRenameTable* patchTable = new (tmm) OpndRenameTable(tmm); // Need to patch global defs. Create store blocks and merge at next - Log::cat_opt_loop()->debug << "Merging global temps in node L" << (int) header->getLabelId() << " and L" << (int) peeled->getLabelId() << ::std::endl; - CFGNode* newpreheaderSt = fg.createBlockNode(); - CFGNode* newtailSt = fg.createBlockNode(); - fg.replaceEdgeTarget(peeled->findTarget(next), newpreheaderSt); + if (Log::isEnabled()) { + Log::out() << "Merging global temps in node ";FlowGraph::printLabel(Log::out(), header); Log::out()<<" and ";FlowGraph::printLabel(Log::out(), peeled);Log::out()<<std::endl; + } + Node* newpreheaderSt = fg.createBlockNode(instFactory.makeLabel()); + Node* newtailSt = fg.createBlockNode(instFactory.makeLabel()); + fg.replaceEdgeTarget(peeled->findTargetEdge(next), newpreheaderSt); fg.addEdge(newpreheaderSt, next); - fg.replaceEdgeTarget(header->findTarget(next), newtailSt); + fg.replaceEdgeTarget(header->findTargetEdge(next), newtailSt); fg.addEdge(newtailSt, next); StlVector<Inst*>::iterator i; @@ -928,17 +770,17 @@ void LoopBuilder::peelLoops(StlVector<CF // Create a new var and initialize it the original and duplicated blocks. dstVar = opndManager.createVarOpnd(dst->getType(), false); Inst* stPreheader = instFactory.makeStVar(dstVar, dstPreheader); - newpreheaderSt->append(stPreheader); + newpreheaderSt->appendInst(stPreheader); Inst* stTail = instFactory.makeStVar(dstVar, dstTail); - newtailSt->append(stTail); + newtailSt->appendInst(stTail); } Inst* ldVar = instFactory.makeLdVar(dst, dstVar); - next->prepend(ldVar); + next->prependInst(ldVar); patchTable->setMapping(dst, dstPreheader); } - fg.renameOperandsInNode(peeled, patchTable); + FlowGraph::renameOperandsInNode(peeled, patchTable); // Rotate preheader = newpreheaderSt; @@ -946,8 +788,8 @@ void LoopBuilder::peelLoops(StlVector<CF } else { if (peeled->getOutDegree() > 1) { // Remove critical edge - preheader = fg.createBlockNode(); - fg.replaceEdgeTarget(peeled->findTarget(next), preheader); + preheader = fg.createBlockNode(instFactory.makeLabel()); + fg.replaceEdgeTarget(peeled->findTargetEdge(next), preheader); fg.addEdge(preheader, next); } else { preheader = peeled; @@ -959,7 +801,9 @@ void LoopBuilder::peelLoops(StlVector<CF header = next; if (flags.aggressive_peeling) { if (header == originalInvertedHeader) { - Log::cat_opt_loop()->debug << "Stop peeling node at L" << (int) header->getLabelId() << ": peeled one iteration" << ::std::endl; + if (Log::isEnabled()) { + Log::out()<<"Stop peeling node at ";FlowGraph::printLabel(Log::out(), header); Log::out() << ": peeled one iteration" << std::endl; + } break; } } else { @@ -968,20 +812,20 @@ void LoopBuilder::peelLoops(StlVector<CF } } assert(header->getInDegree() == 2); - backEdge = (CFGEdge*) header->findSource(tail); + backEdge = header->findSourceEdge(tail); assert(backEdge != NULL); *i = backEdge; } loopEdgesIn.clear(); if(flags.insideout_peeling) { - StlVector<CFGEdge*>::reverse_iterator i = loopEdges.rbegin(); + StlVector<Edge*>::reverse_iterator i = loopEdges.rbegin(); while (i != loopEdges.rend()) { loopEdgesIn.insert(loopEdgesIn.end(), *i); i++; } } else { - StlVector<CFGEdge*>::iterator i = loopEdges.begin(); + StlVector<Edge*>::iterator i = loopEdges.begin(); while (i != loopEdges.end()) { loopEdgesIn.insert(loopEdgesIn.end(), *i); i++; @@ -989,34 +833,88 @@ void LoopBuilder::peelLoops(StlVector<CF } } -LoopTree* LoopBuilder::computeAndNormalizeLoops(bool doPeelLoops) { - // find all loop headers - MemoryManager tmm(16*sizeof(CFGNode*)*2,"LoopBuilder::computeAndNormalizeLoops.tmm"); - StlVector<CFGNode*> headers(tmm); - findLoopHeaders(headers); - assert(dom.isValid()); - - StlVector<CFGEdge*> loopEdges(tmm); - uint32 numLoops = findLoopEdges(tmm, headers, loopEdges); - // - // build loop hierarchy - // - // sort loop edges based on their depth first number - ::std::sort(loopEdges.begin(), loopEdges.end(), CompareDFN()); - - if (doPeelLoops) { - peelLoops(loopEdges); - if (Log::cat_opt_loop()->isDebugEnabled()) - fg.printInsts(Log::out(), irManager.getMethodDesc()); +class EdgeCoalescerCallbackImpl : public EdgeCoalescerCallback { +friend class LoopBuilder; +public: + EdgeCoalescerCallbackImpl(IRManager& _irm) : ssaAffected(false), irm(_irm){} + + virtual void coalesce(Node* header, Node* newPreHeader, uint32 numEdges) { + InstFactory& instFactory = irm.getInstFactory(); + OpndManager& opndManager = irm.getOpndManager(); + Inst* labelInst = (Inst*)header->getFirstInst(); + assert(labelInst->isLabel() && !labelInst->isCatchLabel()); + newPreHeader->appendInst(instFactory.makeLabel()); + if (numEdges > 1 ) { + for (Inst* phi = labelInst->getNextInst();phi!=NULL && phi->isPhi(); phi = phi->getNextInst()) { + Opnd *orgDst = phi->getDst(); + SsaVarOpnd *ssaOrgDst = orgDst->asSsaVarOpnd(); + assert(ssaOrgDst); + VarOpnd *theVar = ssaOrgDst->getVar(); + assert(theVar); + SsaVarOpnd* newDst = opndManager.createSsaVarOpnd(theVar); + Inst *newInst = instFactory.makePhi(newDst, 0, 0); + PhiInst *newPhiInst = newInst->asPhiInst(); + assert(newPhiInst); + uint32 n = phi->getNumSrcOperands(); + for (uint32 i=0; i<n; i++) { + instFactory.appendSrc(newPhiInst, phi->getSrc(i)); + } + PhiInst *phiInst = phi->asPhiInst(); + assert(phiInst); + instFactory.appendSrc(phiInst, newDst); + newPreHeader->appendInst(newInst); + ssaAffected = true; + } + } } - if (!fg.hasValidOrdering()) - fg.orderNodes(); - formLoopHierarchy(loopEdges, numLoops); - info = new (loopMemManager) LoopTree(loopMemManager, &fg); - info->process((LoopNode*) root); - return info; +private: + bool ssaAffected; + IRManager& irm; +}; + +void LoopBuilder::computeLoops(bool normalize) { + // find all loop headers + LoopTree* lt = irManager.getLoopTree(); + if (lt == NULL) { + MemoryManager& mm = irManager.getMemoryManager(); + EdgeCoalescerCallbackImpl* c = new (mm) EdgeCoalescerCallbackImpl(irManager); + lt = new LoopTree(irManager.getMemoryManager(), &irManager.getFlowGraph(),c); + irManager.setLoopTree(lt); + } + EdgeCoalescerCallbackImpl* callback = (EdgeCoalescerCallbackImpl*)lt->getCoalesceCallback(); + callback->ssaAffected = false; + lt->rebuild(normalize); + needsSsaFixup = callback->ssaAffected; } +void LoopBuilder::peelLoops() { + LoopTree*lt = irManager.getLoopTree(); + if (!lt->hasLoops()) { + return; + } + + MemoryManager tmm(1024,"LoopBuilder::peelLoops"); + Edges loopEdges(tmm); + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + const Edges& edges = node->getOutEdges(); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (lt->isBackEdge(edge)) { + loopEdges.push_back(edge); + } + } + } + peelLoops(loopEdges); + if (Log::isEnabled()) + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); + -} //namespace Jitrino + if (needSsaFixup()) { + OptPass::fixupSsa(irManager); + } + OptPass::smoothProfile(irManager); +} +}//namespace Jitrino diff --git vm/jitrino/src/optimizer/Loop.h vm/jitrino/src/optimizer/Loop.h index c0cc399..6bc06fa 100644 --- vm/jitrino/src/optimizer/Loop.h +++ vm/jitrino/src/optimizer/Loop.h @@ -27,240 +27,74 @@ #include "BitSet.h" #include "Stl.h" #include "Tree.h" #include "irmanager.h" -#include "PropertyTable.h" -#include "optpass.h" +#include "LoopTree.h" namespace Jitrino { -DEFINE_OPTPASS(LoopPeelingPass) -class LoopNode : public TreeNode { -public: - LoopNode* getChild() {return (LoopNode*)child;} - LoopNode* getSiblings() {return (LoopNode*)siblings;} - LoopNode* getParent() {return (LoopNode*)parent;} - - bool inLoop(CFGNode* node) {return nodesInLoop2->getBit(node->getDfNum());} - - virtual void print(::std::ostream& cout) { - if (parent == NULL) - cout << "root"; - else - header->printLabel(cout); - } - - void printNodesInLoop(::std::ostream& cout) { - if (nodesInLoop2 == NULL) - return; - for (uint32 i = 0; i < nodesInLoop2->size(); i++) - if (nodesInLoop2->getBit(i)) - cout << (int)i << " "; - } - - /**** for Dot files *****/ - virtual void printDotNodesInTreeNode(::std::ostream& os) { - os << " | {nodes: "; - printNodesInLoop(os); - os << "}"; - } - - CFGNode* getHeader() const { return header; } -private: - friend class LoopTree; - friend class LoopBuilder; - - LoopNode(CFGNode* hd, StlBitVector* bv) - : nodesInLoop2(bv), header(hd) {} - - void markNode(CFGNode* node) {nodesInLoop2->setBit(node->getDfNum(),true);} - const StlBitVector* getNodesInLoop() const { return nodesInLoop2; } - - StlBitVector* nodesInLoop2; - CFGNode* header; // loop entry point +struct LoopBuilderFlags { + bool hoist_loads; + bool invert; + bool peel; + bool insideout_peeling; + bool old_static_peeling; + bool aggressive_peeling; + bool peel_upto_branch; + uint32 peeling_threshold; + bool fullpeel; + uint32 fullpeel_max_inst; + bool unroll; + uint32 unroll_count; + uint32 unroll_threshold; + bool peel_upto_branch_no_instanceof; }; -class LoopTree : public Tree, public CFGNode::Annotator -{ -public: - LoopTree(MemoryManager& mm, FlowGraph* f) : - mm(mm), flowgraph(f), size((uint32) f->getNodeCount()), - traversalNum(0), loopNodeMap(mm), - containingHeaderMap(mm) { - loopNodeMap.reserve(size); - containingHeaderMap.reserve(size); - } - - - uint32 getNodeCount() const { return size; } - - bool isLoopHeader(CFGNode* node) const { return (loopNodeMap[node->getDfNum()] != NULL); } - bool hasContainingLoopHeader(CFGNode* node) const { return (containingHeaderMap[node->getDfNum()] != NULL); } - CFGNode* getContainingLoopHeader(CFGNode* node) const { return containingHeaderMap[node->getDfNum()]->getHeader(); } - LoopNode* getLoopNode(CFGNode* node) const { return loopNodeMap[node->getDfNum()]; } - - uint32 getLoopDepth(CFGNode* node) const { - uint32 base = isLoopHeader(node) ? 1 : 0; - return hasContainingLoopHeader(node) ? (base + getLoopDepth(getContainingLoopHeader(node))) - : base; - } - - bool loopContains(CFGNode* header, CFGNode *node) const { - LoopNode *loopNode = loopNodeMap[header->getDfNum()]; - assert(loopNode); - return (loopNode->inLoop(node)); - }; - - void process(LoopNode* r) { - root = r; - // Clear data structures - loopNodeMap.clear(); - loopNodeMap.insert(loopNodeMap.begin(), size, NULL); - containingHeaderMap.clear(); - containingHeaderMap.insert(containingHeaderMap.begin(), size, NULL); - if(r != NULL) - visit(r->getChild()); - traversalNum = flowgraph->getTraversalNum(); - } - - // True if the graph was not modified since the dominator was computed. - bool isValid() { - return traversalNum > flowgraph->getModificationTraversalNum(); - } - uint32 getTraversalNum() { return traversalNum; } - - void annotateNode(::std::ostream& os, ControlFlowNode* node) { - if(isValid()) { - CFGNode* n = (CFGNode*) node; - bool isHeader = isLoopHeader(n); - CFGNode* myHeader = hasContainingLoopHeader(n) ? getContainingLoopHeader(n) : NULL; - uint32 depth = getLoopDepth(n); - os << "[Loop Depth=" << (int) depth; - if(isHeader) - os << ", IsNewHeader"; - if(myHeader != NULL) { - os << ", LoopHeader="; - myHeader->printLabel(os); - } - os << "]"; - } - } +class LoopBuilder { -private: - class NodeVisitor { - public: - NodeVisitor(LoopNode* node, StlVector<LoopNode*>& headerMap) : headerNode(node), headerMap(headerMap) {} - - void visit(uint32 elem) { - if((elem != headerNode->getHeader()->getDfNum()) && (headerMap[elem] == NULL)) - headerMap[elem] = headerNode; - } - - private: - LoopNode* headerNode; - StlVector<LoopNode*>& headerMap; - }; - - void visit(LoopNode* node) { - if(node == NULL) - return; - - // Visit children first - visit(node->getChild()); - - // Visit header - uint32 headerNum = node->getHeader()->getDfNum(); - loopNodeMap[headerNum] = node; - NodeVisitor visitor(node, containingHeaderMap); - const StlBitVector* nodesInLoop = node->getNodesInLoop(); - for(uint32 i = 0; i < nodesInLoop->size(); ++i) - if(nodesInLoop->at(i)) - visitor.visit(i); - - // Visit siblings (remaining children of parent) - visit(node->getSiblings()); - } - - MemoryManager& mm; - FlowGraph* flowgraph; - uint32 size; - uint32 traversalNum; - - StlVector<LoopNode*> loopNodeMap; - StlVector<LoopNode*> containingHeaderMap; -}; - -class LoopBuilder { - struct Flags { - bool hoist_loads; - bool invert; - bool peel; - bool insideout_peeling; - bool old_static_peeling; - bool aggressive_peeling; - bool peel_upto_branch; - uint32 peeling_threshold; - bool fullpeel; - uint32 fullpeel_max_inst; - bool unroll; - uint32 unroll_count; - uint32 unroll_threshold; - bool eliminate_critical_back_edge; - bool peel_upto_branch_no_instanceof; - }; -private: - Flags flags; public: - static void showFlagsFromCommandLine(); + static void showFlags(std::ostream& os); + static void readFlags(Action* argSource, LoopBuilderFlags* flags); public: LoopBuilder(MemoryManager& mm, IRManager& irm, DominatorTree& d, bool useProfile); - LoopTree* computeAndNormalizeLoops(bool doPeelLoops=false); + void computeLoops(bool normalize); bool needSsaFixup() { return needsSsaFixup; }; void didSsaFixup() { needsSsaFixup = false; }; + void peelLoops(); private: - // - // private functions - // - class CompareDFN { - public: - bool operator() (CFGEdge* h1, CFGEdge* h2) { return h1->getTargetNode()->getDfNum() < h2->getTargetNode()->getDfNum(); } - }; + class IdentifyByID { public: - uint32 operator() (CFGNode* node) { return node->getId(); } + uint32 operator() (Node* node) { return node->getId(); } }; class IdentifyByDFN { public: - uint32 operator() (CFGNode* node) { return node->getDfNum(); } + uint32 operator() (Node* node) { return node->getDfNum(); } }; - void findLoopHeaders(StlVector<CFGNode*>& headers); - void peelLoops(StlVector<CFGEdge*>& backEdges); - void hoistHeaderInvariants(CFGNode* preheader, CFGNode* header, StlVector<Inst*>& invariantInsts); + void peelLoops(StlVector<Edge*>& backEdges); + void hoistHeaderInvariants(Node* preheader, Node* header, StlVector<Inst*>& invariantInsts); bool isVariantInst(Inst* inst, StlHashSet<Opnd*>& variantOpnds); bool isVariantOperation(Operation operation); - bool isInversionCandidate(CFGNode* currentHeader, CFGNode* proposedHeader, StlBitVector& nodesInLoop, CFGNode*& next, CFGNode*& exit); - uint32 findLoopEdges(MemoryManager& mm,StlVector<CFGNode*>& headers,StlVector<CFGEdge*>& loopEdges); - CFGEdge* coalesceEdges(StlVector<CFGEdge*>& edges,uint32 numEdges); - void formLoopHierarchy(StlVector<CFGEdge*>& loopEdges,uint32 numLoops); - void createLoop(CFGNode* header,CFGNode* tail,uint32 numBlocks); - uint32 markNodesOfLoop(StlBitVector& nodesInLoop,CFGNode* header,CFGNode* tail); - LoopNode* findEnclosingLoop(LoopNode* loop, CFGNode* header); + bool isInversionCandidate(Node* currentHeader, Node* proposedHeader, StlBitVector& nodesInLoop, Node*& next, Node*& exit); + uint32 markNodesOfLoop(StlBitVector& nodesInLoop,Node* header,Node* tail); + LoopNode* findEnclosingLoop(LoopNode* loop, Node* header); MemoryManager& loopMemManager; // for creating loop hierarchy DominatorTree& dom; // dominator information IRManager& irManager; InstFactory& instFactory; // create new label inst for blocks - FlowGraph& fg; + ControlFlowGraph& fg; LoopTree* info; LoopNode* root; bool useProfile; bool canHoistLoads; bool needsSsaFixup; bool invert; + const LoopBuilderFlags& flags; }; } //namespace Jitrino diff --git vm/jitrino/src/optimizer/Opcode.cpp vm/jitrino/src/optimizer/Opcode.cpp index ae63632..3ddd1af 100644 --- vm/jitrino/src/optimizer/Opcode.cpp +++ vm/jitrino/src/optimizer/Opcode.cpp @@ -104,12 +104,11 @@ static OpcodeInfo opcodeTable[] = { { Op_IndirectCall, true, MB::Call, MK::Exception, "calli", "calli [%0](%a) ((%1,%2)) -) %l", }, { Op_IndirectMemoryCall, true, MB::Call, MK::Exception, "callimem", "callimem [%0](%a) ((%1,%2)) -) %l", }, { Op_IntrinsicCall, true, MB::Call, MK::Exception, "callintr", "callintr %d(%p) ((%0,%1)) -) %l", }, - { Op_JitHelperCall, true, MB::Call, MK::Exception, "callhelper", "callhelper %d(%p) ((%0,%1)) -) %l", }, + { Op_JitHelperCall, true, MB::Call, MK::Exception, "callhelper", "callhelper %d(%s) -) %l", }, { Op_VMHelperCall, true, MB::Call, MK::Exception, "callvmhelper", "callvmhelper %d(%s) -) %l", }, { Op_Return, true, MB::ControlFlow, MK::None, "return", "return %s", }, { Op_Catch, true, MB::ControlFlow, MK::None, "catch", "catch -) %l", }, { Op_Throw, true, MB::Exception, MK::Throw, "throw ", "throw %0", }, - { Op_ThrowLazy, true, MB::Exception, MK::None, "throwlazy ", "throwlazy %d (%s)", }, { Op_ThrowSystemException, true, MB::Exception, MK::None, "throwsys ", "throwsys %d", }, { Op_ThrowLinkingException, true, MB::Exception, MK::None, "throwLink ", "throwLink", }, { Op_Leave, true, MB::ControlFlow, MK::None, "leave ", "leave %l", }, // CLI only -- DELETE @@ -124,7 +123,7 @@ static OpcodeInfo opcodeTable[] = { { Op_DefArg, true, MB::None, MK::DefArg, "defarg", "defarg%m -) %l", }, // Load instructions { Op_LdConstant, false, MB::Movable, MK::None, "ldc ", "ldc%t #%c -) %l", }, - { Op_LdString, false, MB::Movable, MK::AutoCompress, "ldstr ", "ldstr%m (%d) -) %l", }, + { Op_LdRef, false, MB::Movable, MK::AutoCompress, "ldref ", "ldref%m (%d) -) %l", }, { Op_LdVar, false, MB::None, MK::None, "ldvar ", "ldvar %0 -) %l", }, { Op_LdVarAddr, false, MB::Movable, MK::None, "ldvara", "ldvara %0 -) %l", }, { Op_TauLdInd, false, MB::Load, MK::AutoCompress_Speculative, "ldind", "ldind%m:%t [%0] ((%1,%2)) -) %l", }, @@ -135,7 +134,7 @@ static OpcodeInfo opcodeTable[] = { { Op_LdStaticAddr, false, MB::Movable, MK::None, "ldsflda", "ldsflda [%d] -) %l", }, { Op_LdElemAddr, false, MB::Movable, MK::None, "ldelema", "ldelema [%0[%1]] -) %l", }, { Op_TauLdVTableAddr, false, MB::Movable, MK::None, "ldvtable", "ldvtable %0 ((%1)) -) %l", }, - { Op_TauLdIntfcVTableAddr, false, MB::Movable, MK::None, "ldintfcvt", "ldintfcvt %0,%d ((%1)) -) %l", }, + { Op_TauLdIntfcVTableAddr, false, MB::Movable, MK::None, "ldintfcvt", "ldintfcvt %0,%d -) %l", }, { Op_TauLdVirtFunAddr, false, MB::CSEable, MK::None, "ldvfn ", "ldvfn [%0.%d] ((%1)) -) %l", }, { Op_TauLdVirtFunAddrSlot, false, MB::CSEable, MK::None, "ldvfnslot", "ldvfnslot [%0.%d] ((%1)) -) %l", }, { Op_LdFunAddr, false, MB::CSEable, MK::None, "ldfn ", "ldfn [%d] -) %l", }, @@ -180,7 +179,7 @@ static OpcodeInfo opcodeTable[] = { { Op_TauInstanceOf, false, MB::Movable, MK::None, "instanceof", "instanceof %0,%d ((%1)) -) %l", }, // returns true if argument is an instance of type T, tau opnd isNonNull { Op_InitType, true, MB::CSEable, MK::None, "inittype", "inittype %d", }, // REVIEW: can this throw an exception? { Op_Label, true, MB::None, MK::None, "label ", "%l:", }, // special label instructions for branch labels, finally, catch - { Op_MethodEntry, true, MB::None, MK::None, "methodentry", "--- %d: (%s)", }, // method entry label + { Op_MethodEntry, true, MB::None, MK::None, "methodentry", "--- MethodEntry(%d): (%s)", }, // method entry label { Op_MethodEnd, true, MB::None, MK::None, "methodend", "+++ MethodEnd(%d) (%s)", }, // end of a method { Op_SourceLineNumber, true, MB::None, MK::None, "lineno", "???", }, // change to source position { Op_LdObj, false, MB::Load, MK::None, "ldobj ", "ldobj [%0] -) %l", }, // load a value type to the stack @@ -264,7 +263,7 @@ unsigned short Modifier::encode(Opcode o assert(bitsused <= numbits); unsigned short usencoded = (unsigned short) encoded; assert(encoded == (uint32) usencoded); - if (0 && Log::cat_opt()->isDebugEnabled()) { + if (0 && Log::isEnabled()) { Log::out() << ::std::endl << "Modifier " << ::std::hex << (int) value << " and Opcode " << (int) opcode << " encoded as " << (int) usencoded << ::std::dec << ::std::endl; } @@ -293,7 +292,7 @@ Modifier::Modifier(Opcode opcode, uint32 assert(bitsused <= OPERATION_MODIFIER_BITS); - if (0 && Log::cat_opt()->isDebugEnabled()) { + if (0 && Log::isEnabled()) { Log::out() << ::std::endl << "Opcode " << ::std::hex << (int) opcode << " and bits " << (int) encoding << " decoded to Modifier " << (int) value << ::std::dec << ::std::endl; } @@ -559,13 +558,13 @@ Operation::getModifierString() const { switch(smod) { case Speculative_Yes: return ".s"; case Speculative_No: return ""; - default: assert(false); + default: assert(false); } case AutoCompress_No: switch(smod) { case Speculative_Yes: return ".s.unc"; case Speculative_No: return ".unc"; - default: assert(false); + default: assert(false); } default: assert(0); } @@ -661,9 +660,8 @@ bool Operation::canThrow() const return true; } -// if (!optimizerFlags.brm_debug) { - if (opcode == Op_InitType) return true; -// } + if (opcode == Op_InitType) return true; + Modifier mod = getModifier(); if (mod.hasExceptionModifier()) { enum ExceptionModifier emod = mod.getExceptionModifier(); @@ -729,7 +727,7 @@ bool Operation::isStoreOrSync() const { case MB::StoreOrSync: return true; default: - break; + break; } return false; } @@ -803,7 +801,7 @@ bool Operation::isConstant() const { switch (opcode) { case Op_LdConstant: - case Op_LdString: + case Op_LdRef: case Op_LdVarAddr: case Op_GetVTableAddr: case Op_LdFieldOffset: diff --git vm/jitrino/src/optimizer/Opcode.h vm/jitrino/src/optimizer/Opcode.h index 662dc31..aa31dfb 100644 --- vm/jitrino/src/optimizer/Opcode.h +++ vm/jitrino/src/optimizer/Opcode.h @@ -120,7 +120,7 @@ inline bool isComparisonModifierSigned(e case Cmp_EQ: case Cmp_GT: case Cmp_GTE: return true; case Cmp_NE_Un: case Cmp_GT_Un: case Cmp_GTE_Un: return false; default: - break; + break; } assert(((int)SignedOp <= (int)mod) && ((int)mod <= (int)UnsignedOp)); return ((int)mod != (int)UnsignedOp); @@ -194,7 +194,7 @@ enum StoreModifier { }; enum ExceptionModifier { - Exception_Sometimes = 0x1 << 17, // the default + Exception_Sometimes = 0x1 << 17, // the default Exception_Always = 0x2 << 17, Exception_Never = 0x3 << 17, Exception_Mask = 0x3 << 17, @@ -268,7 +268,9 @@ enum IntrinsicCallId { enum JitHelperCallId { InitializeArray, - PseudoCanThrow + PseudoCanThrow, + SaveThisState, + ReadThisState }; enum VMHelperCallId { @@ -313,7 +315,6 @@ enum Opcode { // Exception processing Op_Catch, Op_Throw, - Op_ThrowLazy, // generate a call to special VM helper which constructs exc. object only if necessary Op_ThrowSystemException, // takes a CompilationInterface::SystemExceptionId parameter Op_ThrowLinkingException, // generate a call to Helper_Throw_LinkingException Op_Leave, @@ -331,7 +332,7 @@ enum Opcode { Op_DefArg, // DefArgModifier // Load instructions Op_LdConstant, - Op_LdString, + Op_LdRef, // String or reference Op_LdVar, Op_LdVarAddr, Op_TauLdInd, diff --git vm/jitrino/src/optimizer/Opnd.cpp vm/jitrino/src/optimizer/Opnd.cpp index b5190e0..a104c87 100644 --- vm/jitrino/src/optimizer/Opnd.cpp +++ vm/jitrino/src/optimizer/Opnd.cpp @@ -88,7 +88,7 @@ void OpndManager::deleteVar(VarOpnd *va while (inst != NULL) { VarOpnd *instVar = inst->getBaseVar(); if (!instVar || (instVar == var)) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Removing inst "; inst->print(Log::out()); Log::out() << " for deleted var "; @@ -97,7 +97,7 @@ void OpndManager::deleteVar(VarOpnd *va } inst->unlink(); } else { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found misfiled varAccessInst "; inst->print(Log::out()); Log::out() << " for deleted var "; @@ -108,7 +108,7 @@ void OpndManager::deleteVar(VarOpnd *va if (instVar->isDeadFlag) { // looks already deleted; inst->unlink(); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Correct var looks already deleted, so removing inst anyway." << ::std::endl; } @@ -151,10 +151,12 @@ OpndManager::getOpndTypeFromLdType(Type* case Type::Float: return typeManager.getFloatType(); // object types - case Type::CompressedSystemObject: case Type::CompressedSystemString: + case Type::CompressedSystemObject: + case Type::CompressedSystemClass: + case Type::CompressedSystemString: case Type::CompressedArray: case Type::CompressedObject: case Type::CompressedNullObject: - case Type::SystemObject: case Type::SystemString: + case Type::SystemObject: case Type::SystemClass: case Type::SystemString: case Type::Array: case Type::Object: case Type::NullObject: case Type::Offset: case Type::OffsetPlusHeapbase: diff --git vm/jitrino/src/optimizer/Opnd.h vm/jitrino/src/optimizer/Opnd.h index 5413b71..302d66c 100644 --- vm/jitrino/src/optimizer/Opnd.h +++ vm/jitrino/src/optimizer/Opnd.h @@ -82,8 +82,8 @@ public: // // for debug only // - virtual void print(::std::ostream&) const {} - virtual void printWithType(::std::ostream& os) const; + virtual void print(::std::ostream&) const {} + virtual void printWithType(::std::ostream& os) const; protected: // // Constructor @@ -114,7 +114,7 @@ public: Inst* getInst() const {assert(!isVarOpnd()); return inst;} void setInst(Inst* i) {assert(!isVarOpnd()); inst = i;} public: - virtual void print(::std::ostream&) const; + virtual void print(::std::ostream&) const; protected: friend class OpndManager; Opnd(Type* t,uint32 i) : OpndBase(t,i), isGlobalFlag(false), inst(NULL) {} @@ -133,7 +133,7 @@ public: protected: friend class OpndManager; SsaOpnd(Type* t,uint32 i) : Opnd(t,i) - {} + {} }; @@ -153,7 +153,7 @@ public: virtual bool isPiOpnd() const {return true;}; const Opnd *getOrg() const { return orgOpnd; }; Opnd *getOrg() { return orgOpnd; }; - virtual void print(::std::ostream&) const; + virtual void print(::std::ostream&) const; private: friend class OpndManager; PiOpnd(Opnd *orgOpnd0, uint32 i) : @@ -312,8 +312,9 @@ class OpndRenameTable : public HashTable public: OpndRenameTable(MemoryManager& mm, uint32 size = 16, bool renameSSA = false): HashTable<Opnd,Opnd>(mm,size) {renameSsaOpnd = renameSSA;} - virtual ~OpndRenameTable() {} + virtual ~OpndRenameTable() {} + Opnd *getMapping(Opnd *from) {return lookup(from); } void setMapping(Opnd *from, Opnd *to) { insert(from,to); diff --git vm/jitrino/src/optimizer/abcd/abcd.cpp vm/jitrino/src/optimizer/abcd/abcd.cpp index f6d1ced..623d300 100644 --- vm/jitrino/src/optimizer/abcd/abcd.cpp +++ vm/jitrino/src/optimizer/abcd/abcd.cpp @@ -20,82 +20,106 @@ * */ -#include <assert.h> -#include <iostream> -#include <algorithm> -#include "Stl.h" -#include "Log.h" -#include "PropertyTable.h" -#include "open/types.h" -#include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" #include "constantfolder.h" #include "abcd.h" #include "abcdbounds.h" #include "abcdsolver.h" #include "opndmap.h" + +#include "Stl.h" +#include "Log.h" +#include "open/types.h" +#include "Inst.h" #include "walkers.h" +#include "PMFAction.h" + +#include <assert.h> +#include <iostream> +#include <algorithm> namespace Jitrino { -DEFINE_OPTPASS_IMPL(ABCDPass, abcd, "Array Bounds Check Elimination") +//Array Bounds Check Elimination +class ABCDPass: public SessionAction { +public: + void run(); +}; + +ActionFactory<ABCDPass> _abcd("abcd"); void -ABCDPass::_run(IRManager& irm) { - splitCriticalEdges(irm); - computeDominators(irm); +ABCDPass::run() { + IRManager& irm = *getCompilationContext()->getHIRManager(); + OptPass::splitCriticalEdges(irm); + OptPass::computeDominators(irm); Abcd abcd(irm, irm.getNestedMemoryManager(), *irm.getDominatorTree()); abcd.runPass(); } -Abcd::Flags *Abcd::defaultFlags = 0; - void -Abcd::readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params) -{ - if (!defaultFlags) - defaultFlags = new Flags; - defaultFlags->partial = params->lookupBool("opt::abcd::partial", false); - defaultFlags->dryRun = params->lookupBool("opt::abcd::dry_run", false); - defaultFlags->useAliases = params->lookupBool("opt::abcd::use_aliases", true); - defaultFlags->useConv = params->lookupBool("opt::abcd::use_conv", true); - defaultFlags->remConv = params->lookupBool("opt::abcd::rem_conv", true); - defaultFlags->useShr = params->lookupBool("opt::abcd::use_shr", true); - defaultFlags->unmaskShifts = params->lookupBool("opt::abcd::unmask_shifts", true); - defaultFlags->remBr = params->lookupBool("opt::abcd::rem_br", true); - defaultFlags->remCmp = params->lookupBool("opt::abcd::rem_cmp", true); - defaultFlags->remOneBound = params->lookupBool("opt::abcd::rem_one_bound", true); - defaultFlags->remOverflow = params->lookupBool("opt::abcd::rem_overflow", false); - defaultFlags->checkOverflow = params->lookupBool("opt::abcd::check_overflow", false); - defaultFlags->useReasons = params->lookupBool("opt::abcd::use_reasons", false); +Abcd::readFlags(Action* argSource, AbcdFlags* flags ) { + IAction::HPipeline p = NULL; //default pipeline for argSource + flags->partial = argSource->getBoolArg(p, "abcd.partial", false); + flags->dryRun = argSource->getBoolArg(p, "abcd.dry_run", false); + flags->useAliases = argSource->getBoolArg(p, "abcd.use_aliases", true); + flags->useConv = argSource->getBoolArg(p, "abcd.use_conv", true); + flags->remConv = argSource->getBoolArg(p, "abcd.rem_conv", true); + flags->useShr = argSource->getBoolArg(p, "abcd.use_shr", true); + flags->unmaskShifts = argSource->getBoolArg(p, "abcd.unmask_shifts", true); + flags->remBr = argSource->getBoolArg(p, "abcd.rem_br", true); + flags->remCmp = argSource->getBoolArg(p, "abcd.rem_cmp", true); + flags->remOneBound = argSource->getBoolArg(p, "abcd.rem_one_bound", true); + flags->remOverflow = argSource->getBoolArg(p, "abcd.rem_overflow", false); + flags->checkOverflow = argSource->getBoolArg(p, "abcd.check_overflow", false); + flags->useReasons = argSource->getBoolArg(p, "abcd.use_reasons", false); } -void Abcd::showFlagsFromCommandLine() -{ - Log::out() << " opt::abcd::partial[={on|OFF}] = try to eliminate partial ABCs" << ::std::endl; - Log::out() << " opt::abcd::dry_run[={ON|off}] = don't really eliminate checks" << ::std::endl; - Log::out() << " opt::abcd::use_aliases[={ON|off}] = try to use ld/stvar induced aliases" << ::std::endl; - Log::out() << " opt::abcd::use_conv[={ON|off}] = make use of conv info" << ::std::endl; - Log::out() << " opt::abcd::rem_conv[={ON|off}] = remove conv ops in abcd" << ::std::endl; - Log::out() << " opt::abcd::use_shr={ON|off}] = use shr info" << ::std::endl; - Log::out() << " opt::abcd::unmask_shifts={ON|off}] = try to unmask shifts" << ::std::endl; - Log::out() << " opt::abcd::rem_br[={ON|off}] = try to remove branches in abcd" << ::std::endl; - Log::out() << " opt::abcd::rem_cmp[={ON|off}] = try to fold cmps in abcd" << ::std::endl; - Log::out() << " opt::abcd::rem_one_bound[={ON|off}] = eliminate even just upper or lower bound check" << ::std::endl; - Log::out() << " opt::abcd::rem_overflow[={on|OFF}] = try to mark overflow impossible in 32-bit int add/sub"; - Log::out() << " opt::abcd::check_overflow[={on|OFF}] = try to mark overflow impossible in checkbounds"; - Log::out() << " opt::abcd::use_reasons[={ON|off}] = build more precise taus for eliminated instructions"; +void Abcd::showFlags(std::ostream& os) { + os << " abcd flags:"<<std::endl; + os << " abcd.partial[={on|OFF}] - try to eliminate partial ABCs" << std::endl; + os << " abcd.dry_run[={ON|off}] - don't really eliminate checks" << std::endl; + os << " abcd.use_aliases[={ON|off}] - try to use ld/stvar induced aliases" << std::endl; + os << " abcd.use_conv[={ON|off}] - make use of conv info" << std::endl; + os << " abcd.rem_conv[={ON|off}] - remove conv ops in abcd" << std::endl; + os << " abcd.use_shr={ON|off}] - use shr info" << std::endl; + os << " abcd.unmask_shifts={ON|off}] - try to unmask shifts" << std::endl; + os << " abcd.rem_br[={ON|off}] - try to remove branches in abcd" << std::endl; + os << " abcd.rem_cmp[={ON|off}] - try to fold cmps in abcd" << std::endl; + os << " abcd.rem_one_bound[={ON|off}] - eliminate even just upper or lower bound check" << std::endl; + os << " abcd.rem_overflow[={on|OFF}] - try to mark overflow impossible in 32-bit int add/sub"; + os << " abcd.check_overflow[={on|OFF}] - try to mark overflow impossible in checkbounds"; + os << " abcd.use_reasons[={ON|off}] - build more precise taus for eliminated instructions"; } +Abcd::Abcd(IRManager &irManager0, MemoryManager& memManager, DominatorTree& dom0) +: irManager(irManager0), +mm(memManager), +ineqGraph(0), +dominators(dom0), +piMap(0), +nextPiOpndId(0), +solver(0), +canEliminate(memManager), +canEliminateUB(memManager), +canEliminateLB(memManager), +tauUnsafe(0), +tauSafe(0), +blockTauPoint(0), +lastTauPointBlock(0), +blockTauEdge(0), +lastTauEdgeBlock(0), +flags(*irManager.getOptimizerFlags().abcdFlags) +{ +}; + void Abcd::runPass() { - if (Log::cat_opt()->isDebugEnabled() || Log::cat_opt_abcd()->isIR2Enabled()) { - Log::out() << "IR before ABCD pass" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); - irManager.getFlowGraph().printDotFile(irManager.getMethodDesc(), "beforeabcd", &dominators); + if (Log::isEnabled() || Log::isEnabled()) { + Log::out() << "IR before ABCD pass" << std::endl; + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); + FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "beforeabcd"); dominators.printDotFile(irManager.getMethodDesc(), "beforeabcd.dom"); } @@ -105,25 +129,22 @@ void Abcd::runPass() // WARNING: Pi var live ranges may overlap the original // var live ranges here - if (Log::cat_opt_abcd()->isIR2Enabled()) { - Log::out() << "IR after Pi insertion" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); - irManager.getFlowGraph().printDotFile(irManager.getMethodDesc(), "withpi", &dominators); + if (Log::isEnabled()) { + Log::out() << "IR after Pi insertion" << std::endl; + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); + FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "withpi"); } removeRedundantBoundsChecks(); - if (Log::cat_opt()->isDebugEnabled() || Log::cat_opt_abcd()->isIR2Enabled()) { - Log::out() << "IR after removeRedundantBoundsChecks" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); + if (Log::isEnabled() || Log::isEnabled()) { + Log::out() << "IR after removeRedundantBoundsChecks" << std::endl; + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } removePiNodes(); - if (Log::cat_opt_abcd()->isDebugEnabled()) { - Log::out() << "IR after ABCD pass" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); + if (Log::isEnabled()) { + Log::out() << "IR after ABCD pass" << std::endl; + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } } @@ -151,7 +172,7 @@ void Abcd::insertPiNodes() DomTreeWalk<true, InsertPiWalker>(dominators, insertPiWalker, mm); // pre-order } -PiOpnd *Abcd::getNewDestOpnd(CFGNode *block, +PiOpnd *Abcd::getNewDestOpnd(Node *block, Opnd *org) { PiOpnd *tmpOp = irManager.getOpndManager().createPiOpnd(org); @@ -196,67 +217,72 @@ void Abcd::renamePiVariables() } -void Abcd::insertPiNodeForOpnd(CFGNode *block, +void Abcd::insertPiNodeForOpnd(Node *block, Opnd *org, const PiCondition &cond, Opnd *tauOpnd) { if (ConstantFolder::isConstant(org)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Skipping Pi Node for opnd "; org->print(Log::out()); Log::out() << " under condition "; cond.print(Log::out()); - Log::out() << " since it is constant" << ::std::endl; + Log::out() << " since it is constant" << std::endl; } } else { PiOpnd *piOpnd = irManager.getOpndManager().createPiOpnd(org); - Inst *headInst = block->getFirstInst(); - PiCondition *condPtr = - new (irManager.getMemoryManager()) PiCondition(cond); + Inst *headInst = (Inst*)block->getFirstInst(); + PiCondition *condPtr = new (irManager.getMemoryManager()) PiCondition(cond); if (tauOpnd == 0) tauOpnd = getBlockTauEdge(block); Inst *newInst = irManager.getInstFactory().makeTauPi(piOpnd, org, tauOpnd, condPtr); - Inst *place = headInst->next(); - while (place != headInst) { + Inst *place = headInst->getNextInst(); + while (place != NULL) { Opcode opc = place->getOpcode(); if ((opc != Op_Phi) && (opc != Op_TauPoint) && (opc != Op_TauEdge)) break; - place = place->next(); + place = place->getNextInst(); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting Pi Node for opnd "; org->print(Log::out()); Log::out() << " under condition "; cond.print(Log::out()); - Log::out() << " just before inst "; - place->print(Log::out()); - Log::out() << ::std::endl; + if (place!=NULL) { + Log::out() << " just before inst "; + place->print(Log::out()); + } + Log::out() << std::endl; + } + if (place != NULL) { + newInst->insertBefore(place); + } else { + block->appendInst(newInst); } - newInst->insertBefore(place); } } -void Abcd::insertPiNodeForOpndAndAliases(CFGNode *block, +void Abcd::insertPiNodeForOpndAndAliases(Node *block, Opnd *org, const PiCondition &cond, Opnd *tauOpnd) { if (flags.useAliases) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting Pi Node for opnd "; org->print(Log::out()); Log::out() << " and its aliases"; Log::out() << " under condition "; cond.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } AbcdAliases aliases(mm); // check for aliases insertPiNodeForOpnd(block, org, cond, tauOpnd); if (getAliases(org, &aliases, 0)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Has aliases "; AbcdAliasesSet::iterator iter = aliases.theSet.begin(); AbcdAliasesSet::iterator end = aliases.theSet.end(); @@ -265,7 +291,7 @@ void Abcd::insertPiNodeForOpndAndAliases alias.print(Log::out()); Log::out() << " "; } - Log::out() << ::std::endl; + Log::out() << std::endl; } AbcdAliasesSet::iterator iter = aliases.theSet.begin(); AbcdAliasesSet::iterator end = aliases.theSet.end(); @@ -331,14 +357,14 @@ unsignType(Type::Tag typetag) } } -void Abcd::insertPiNodesForComparison(CFGNode *block, +void Abcd::insertPiNodesForComparison(Node *block, ComparisonModifier mod, const PiCondition &bounds, Opnd *op, bool swap_operands, bool negate_comparison) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(..., "; Log::out() << printableComparison(mod); Log::out() << ", "; @@ -348,7 +374,7 @@ void Abcd::insertPiNodesForComparison(CF Log::out() << ", "; Log::out() << (swap_operands ? "true" : "false"); Log::out() << (negate_comparison ? "true" : "false"); - Log::out() << ::std::endl; + Log::out() << std::endl; } PiCondition bounds0 = bounds; @@ -356,10 +382,10 @@ void Abcd::insertPiNodesForComparison(CF if (negate_comparison) { mod = negateComparison(mod); swap_operands = !swap_operands; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison: negating comparison to " ; Log::out() << printableComparison(mod); - Log::out() << ::std::endl; + Log::out() << std::endl; } } switch (mod) { @@ -367,8 +393,8 @@ void Abcd::insertPiNodesForComparison(CF if (negate_comparison) insertPiNodeForOpndAndAliases(block, op, bounds0); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { - Log::out() << "insertPiNodesForComparison: cannot represent ! Cmp_EQ" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "insertPiNodesForComparison: cannot represent ! Cmp_EQ" << std::endl; } } // we can't represent the other case @@ -377,8 +403,8 @@ void Abcd::insertPiNodesForComparison(CF if (!negate_comparison) insertPiNodeForOpndAndAliases(block, op, bounds0); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { - Log::out() << "insertPiNodesForComparison: cannot represent Cmp_NE_Un" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "insertPiNodesForComparison: cannot represent Cmp_NE_Un" << std::endl; } } // we can't represent the other case @@ -400,7 +426,7 @@ void Abcd::insertPiNodesForComparison(CF if (! bounds1.getLb().isUnknown()) insertPiNodeForOpndAndAliases(block, op, bounds1); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; @@ -409,7 +435,7 @@ void Abcd::insertPiNodesForComparison(CF bounds1a.print(Log::out()); Log::out() << "\n\tbounds1 is "; bounds1.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -422,14 +448,14 @@ void Abcd::insertPiNodesForComparison(CF if (! bounds1.getUb().isUnknown()) insertPiNodeForOpndAndAliases(block, op, bounds1); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); Log::out() << "\n\tbounds1 is "; bounds1.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } else { @@ -445,14 +471,14 @@ void Abcd::insertPiNodesForComparison(CF (ubConst >= 0)))) { insertPiNodeForOpndAndAliases(block, op, bounds1); } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); Log::out() << "\n\tbounds1 is "; bounds1.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -466,7 +492,7 @@ void Abcd::insertPiNodesForComparison(CF if (! bounds1.getLb().isUnknown()) insertPiNodeForOpndAndAliases(block, op, bounds1); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; @@ -475,7 +501,7 @@ void Abcd::insertPiNodesForComparison(CF bounds1a.print(Log::out()); Log::out() << "\n\tbounds1 is "; bounds1.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } else { // bounds > op, only an upper bound on op @@ -483,14 +509,14 @@ void Abcd::insertPiNodesForComparison(CF if (! bounds1.getUb().isUnknown()) insertPiNodeForOpndAndAliases(block, op, bounds1); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); Log::out() << "\n\tbounds1 is "; bounds1.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -511,12 +537,12 @@ void Abcd::insertPiNodesForComparison(CF insertPiNodeForOpndAndAliases(block, op, bounds0.only_lower_bound()); } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -529,12 +555,12 @@ void Abcd::insertPiNodesForComparison(CF insertPiNodeForOpndAndAliases(block, op, bounds0.only_upper_bound()); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } else { @@ -549,12 +575,12 @@ void Abcd::insertPiNodesForComparison(CF (ubConst >= 0)))) { insertPiNodeForOpndAndAliases(block, op, bounds0); } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(2): bounds0 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -567,12 +593,12 @@ void Abcd::insertPiNodesForComparison(CF insertPiNodeForOpndAndAliases(block, op, bounds0.only_lower_bound()); } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } else { // bounds >= op, only upper bound on op @@ -580,12 +606,12 @@ void Abcd::insertPiNodesForComparison(CF insertPiNodeForOpndAndAliases(block, op, bounds0.only_upper_bound()); else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "insertPiNodesForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; bounds.print(Log::out()); Log::out() << "\n\tbounds0 is "; bounds0.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -596,8 +622,8 @@ void Abcd::insertPiNodesForComparison(CF assert(0); break; default: - assert(false); - break; + assert(false); + break; } } @@ -613,8 +639,8 @@ void Abcd::insertPiNodesForComparison(CF // // We also must add the new Pi variable to our map. // -void Abcd::insertPiNodesForBranch(CFGNode *block, BranchInst *branchi, - CFGEdge::Kind kind) // True or False only +void Abcd::insertPiNodesForBranch(Node *block, BranchInst *branchi, + Edge::Kind kind) // True or False only { Type::Tag instTypeTag = branchi->getType(); if (!Type::isInteger(instTypeTag)) @@ -631,7 +657,7 @@ void Abcd::insertPiNodesForBranch(CFGNod zeroBounds, op0, false, - (kind == CFGEdge::False)); // negate if false edge + (kind == Edge::Kind_False)); // negate if false edge break; case Cmp_NonZero: insertPiNodesForComparison(block, @@ -639,10 +665,10 @@ void Abcd::insertPiNodesForBranch(CFGNod zeroBounds, op0, false, - (kind == CFGEdge::True)); // but negate if true edge + (kind == Edge::Kind_True)); // but negate if true edge break; - default: - break; + default: + break; } } else { Opnd *op0 = branchi->getSrc(0); @@ -656,7 +682,7 @@ void Abcd::insertPiNodesForBranch(CFGNod bounds0, op1, false, - (kind == CFGEdge::False)); // negate for false edge + (kind == Edge::Kind_False)); // negate for false edge } if (!bounds1.isUnknown()) { insertPiNodesForComparison(block, @@ -664,16 +690,16 @@ void Abcd::insertPiNodesForBranch(CFGNod bounds1, op0, true, - (kind == CFGEdge::False)); // negate for false edge + (kind == Edge::Kind_False)); // negate for false edge } } } -SsaTmpOpnd* Abcd::getBlockTauPoint(CFGNode *block) { +SsaTmpOpnd* Abcd::getBlockTauPoint(Node *block) { if ((lastTauPointBlock == block) && blockTauPoint) return blockTauPoint; - Inst *firstInst = block->getFirstInst(); - Inst *inst = firstInst->next(); - for (; inst != firstInst; inst = inst->next()) { + Inst *firstInst = (Inst*)block->getFirstInst(); + Inst *inst = (Inst*)firstInst->getNextInst(); + for (; inst != NULL; inst = inst->getNextInst()) { if (inst->getOpcode() == Op_TauPoint) { blockTauPoint = inst->getDst()->asSsaTmpOpnd(); assert(blockTauPoint); @@ -681,7 +707,7 @@ SsaTmpOpnd* Abcd::getBlockTauPoint(CFGNo return blockTauPoint; } } - for (inst = firstInst->next(); inst != firstInst; inst = inst->next()) { + for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (inst->getOpcode() != Op_Phi) { break; // insert before inst. } @@ -690,24 +716,30 @@ SsaTmpOpnd* Abcd::getBlockTauPoint(CFGNo TypeManager &tm = irManager.getTypeManager(); SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst* tauPoint = irManager.getInstFactory().makeTauPoint(tauOpnd); - if(Log::cat_opt_abcd()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauPoint inst "; tauPoint->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); - Log::out() << ::std::endl; + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } + Log::out() << std::endl; + } + if (inst!=NULL) { + tauPoint->insertBefore(inst); + } else { + block->appendInst(tauPoint); } - tauPoint->insertBefore(inst); blockTauPoint = tauOpnd; lastTauPointBlock = block; return tauOpnd; } -SsaTmpOpnd* Abcd::getBlockTauEdge(CFGNode *block) { +SsaTmpOpnd* Abcd::getBlockTauEdge(Node *block) { if ((lastTauEdgeBlock == block) && blockTauEdge) return blockTauEdge; - Inst *firstInst = block->getFirstInst(); - Inst *inst = firstInst->next(); - for (; inst != firstInst; inst = inst->next()) { + Inst *firstInst = (Inst*)block->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + for (; inst != NULL; inst = inst->getNextInst()) { if (inst->getOpcode() == Op_TauEdge) { blockTauEdge = inst->getDst()->asSsaTmpOpnd(); assert(blockTauEdge); @@ -715,7 +747,7 @@ SsaTmpOpnd* Abcd::getBlockTauEdge(CFGNod return blockTauEdge; } } - for (inst = firstInst->next(); inst != firstInst; inst = inst->next()) { + for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if ((inst->getOpcode() != Op_Phi) && (inst->getOpcode() != Op_TauPoint)) { break; // insert before inst. } @@ -724,14 +756,20 @@ SsaTmpOpnd* Abcd::getBlockTauEdge(CFGNod TypeManager &tm = irManager.getTypeManager(); SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst* tauEdge = irManager.getInstFactory().makeTauEdge(tauOpnd); - if(Log::cat_opt_abcd()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauEdge inst "; tauEdge->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); - Log::out() << ::std::endl; + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } + Log::out() << std::endl; + } + if (inst != NULL) { + tauEdge->insertBefore(inst); + } else { + block->appendInst(tauEdge); } - tauEdge->insertBefore(inst); blockTauEdge = tauOpnd; lastTauEdgeBlock = block; return tauOpnd; @@ -739,39 +777,45 @@ SsaTmpOpnd* Abcd::getBlockTauEdge(CFGNod SsaTmpOpnd* Abcd::getTauUnsafe() { if (!tauUnsafe) { - CFGNode *head = irManager.getFlowGraph().getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = irManager.getFlowGraph().getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *inst = entryLabel->next(); - while (inst != entryLabel) { + Inst *inst = entryLabel->getNextInst(); + while (inst != NULL) { if (inst->getOpcode() == Op_TauUnsafe) { tauUnsafe = inst->getDst()->asSsaTmpOpnd(); assert(tauUnsafe); return tauUnsafe; } - inst = inst->next(); + inst = inst->getNextInst(); } // need to insert one TypeManager &tm = irManager.getTypeManager(); SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst *tauUnsafeInst = irManager.getInstFactory().makeTauUnsafe(tauOpnd); // place after label and Phi instructions - inst = entryLabel->next(); - while (inst != entryLabel) { + inst = entryLabel->getNextInst(); + while (inst != NULL) { Opcode opc = inst->getOpcode(); if ((opc != Op_Phi) && (opc != Op_TauPi) && (opc != Op_TauPoint)) { break; } - inst = inst->next(); + inst = inst->getNextInst(); } - if(Log::cat_opt_abcd()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauUnsafe inst "; tauUnsafeInst->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); - Log::out() << ::std::endl; + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } + Log::out() << std::endl; + } + if (inst!=NULL) { + tauUnsafeInst->insertBefore(inst); + } else { + head->appendInst(tauUnsafeInst); } - tauUnsafeInst->insertBefore(inst); tauUnsafe = tauOpnd; } return tauUnsafe; @@ -779,45 +823,51 @@ SsaTmpOpnd* Abcd::getTauUnsafe() { SsaTmpOpnd* Abcd::getTauSafe() { if (!tauSafe) { - CFGNode *head = irManager.getFlowGraph().getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = irManager.getFlowGraph().getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *inst = entryLabel->next(); - while (inst != entryLabel) { + Inst *inst = entryLabel->getNextInst(); + while (inst != NULL) { if (inst->getOpcode() == Op_TauSafe) { tauSafe = inst->getDst()->asSsaTmpOpnd(); assert(tauSafe); return tauSafe; } - inst = inst->next(); + inst = inst->getNextInst(); } // need to insert one TypeManager &tm = irManager.getTypeManager(); SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst *tauSafeInst = irManager.getInstFactory().makeTauSafe(tauOpnd); // place after label and Phi instructions - inst = entryLabel->next(); - while (inst != entryLabel) { + inst = entryLabel->getNextInst(); + while (inst != NULL) { Opcode opc = inst->getOpcode(); if ((opc != Op_Phi) && (opc != Op_TauPi) && (opc != Op_TauPoint)) { break; } - inst = inst->next(); + inst = inst->getNextInst(); } - if(Log::cat_opt_abcd()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauSafe inst "; tauSafeInst->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); - Log::out() << ::std::endl; + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } + Log::out() << std::endl; + } + if (inst!=NULL) { + tauSafeInst->insertBefore(inst); + } else { + head->appendInst(tauSafeInst); } - tauSafeInst->insertBefore(inst); tauSafe = tauOpnd; } return tauSafe; }; -void Abcd::insertPiNodesForUnexceptionalPEI(CFGNode *block, Inst *lasti) +void Abcd::insertPiNodesForUnexceptionalPEI(Node *block, Inst *lasti) { switch (lasti->getOpcode()) { case Op_TauCheckBounds: @@ -827,10 +877,10 @@ void Abcd::insertPiNodesForUnexceptional Opnd *idxOp = lasti->getSrc(1); Opnd *boundsOp = lasti->getSrc(0); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Adding info about CheckBounds instruction "; lasti->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Type::Tag typetag = idxOp->getType()->tag; PiBound lb(typetag, int64(0)); @@ -849,10 +899,10 @@ void Abcd::insertPiNodesForUnexceptional // the number of newarray elements must be in [0, MAXINT32] assert(lasti->getNumSrcOperands() == 1); Opnd *numElemOpnd = lasti->getSrc(0); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Adding info about NewArray instruction "; lasti->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Opnd *tauOpnd = getBlockTauEdge(block); // need to use a TauEdge PiCondition bounds0(PiBound(numElemOpnd->getType()->tag, int64(0)), @@ -866,10 +916,10 @@ void Abcd::insertPiNodesForUnexceptional uint32 numOpnds = lasti->getNumSrcOperands(); assert(numOpnds >= 1); StlSet<Opnd *> done(mm); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Adding info about NewMultiArray instruction "; lasti->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Opnd *tauOpnd = 0; // the number of newarray elements must be in [0, MAXINT32] @@ -893,9 +943,9 @@ void Abcd::insertPiNodesForUnexceptional // Add a Pi node in the node if it is after // a test which tells something about a variable. // For now, don't bother with Exception edges. -void Abcd::insertPiNodes(CFGNode *block) +void Abcd::insertPiNodes(Node *block) { - CFGEdge *domEdge = 0; + Edge *domEdge = 0; // see if there is a predecessor block idom such that // (1) idom dominates this one @@ -904,16 +954,16 @@ void Abcd::insertPiNodes(CFGNode *block) // (4) idom has only 1 edge to this node // (1a) if a predecessor dominates it must be idom - CFGNode *idom = dominators.getIdom(block); + Node *idom = dominators.getIdom(block); // (3) must exist and have multiple out-edges if ((idom == NULL) || (idom->hasOnlyOneSuccEdge())) { return; } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking block " << (int)block->getId() << " with idom " - << (int) idom->getId() << ::std::endl; + << (int) idom->getId() << std::endl; } if (block->hasOnlyOnePredEdge()) { @@ -922,12 +972,12 @@ void Abcd::insertPiNodes(CFGNode *block) domEdge = *(block->getInEdges().begin()); } else { // check (1b) and (2) - const CFGEdgeDeque &inedges = block->getInEdges(); - typedef CFGEdgeDeque::const_iterator EdgeIter; + const Edges &inedges = block->getInEdges(); + typedef Edges::const_iterator EdgeIter; EdgeIter eLast = inedges.end(); for (EdgeIter eIter = inedges.begin(); eIter != eLast; eIter++) { - CFGEdge *inEdge = *eIter; - CFGNode *predBlock = inEdge->getSourceNode(); + Edge *inEdge = *eIter; + Node *predBlock = inEdge->getSourceNode(); if (predBlock == idom) { // (1b) found idom if (domEdge) { @@ -943,19 +993,19 @@ void Abcd::insertPiNodes(CFGNode *block) } if (domEdge) { - CFGEdge *inEdge = domEdge; - CFGNode *predBlock = idom; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + Edge *inEdge = domEdge; + Node *predBlock = idom; + if (Log::isEnabled()) { Log::out() << "Checking branch for " << (int)block->getId() << " with idom " - << (int) idom->getId() << ::std::endl; + << (int) idom->getId() << std::endl; } if (!predBlock->hasOnlyOneSuccEdge()) { - CFGEdge::Kind kind = inEdge->getEdgeType(); + Edge::Kind kind = inEdge->getKind(); switch (kind) { - case CFGEdge::True: - case CFGEdge::False: + case Edge::Kind_True: + case Edge::Kind_False: { - Inst* branchi1 = predBlock->getLastInst(); + Inst* branchi1 = (Inst*)predBlock->getLastInst(); assert(branchi1 != NULL); BranchInst* branchi = branchi1->asBranchInst(); if (branchi && branchi->isConditionalBranch()) { @@ -966,15 +1016,15 @@ void Abcd::insertPiNodes(CFGNode *block) } break; - case CFGEdge::Exception: + case Edge::Kind_Dispatch: return; - case CFGEdge::Unconditional: + case Edge::Kind_Unconditional: // Previous block must have a PEI // since it had multiple out-edges. // This is the unexceptional condition. { - Inst* lasti = predBlock->getLastInst(); + Inst* lasti = (Inst*)predBlock->getLastInst(); assert(lasti != NULL); insertPiNodesForUnexceptionalPEI(block, lasti); } @@ -984,18 +1034,16 @@ void Abcd::insertPiNodes(CFGNode *block) // they imply a Pi-like action. break; - case CFGEdge::Catch: - case CFGEdge::Switch: - case CFGEdge::Unknown: + case Edge::Kind_Catch: break; - default: - break; + default: + break; }; } } } -void Abcd::renamePiVariables(CFGNode *block) +void Abcd::renamePiVariables(Node *block) { // For each variable use in the block, check for a Pi version in // the piTable. Since we are visiting in preorder over dominator @@ -1005,13 +1053,12 @@ void Abcd::renamePiVariables(CFGNode *bl // we are past the Pi instructions // first process any pi nodes, just the RHSs - Inst* headInst = block->getFirstInst(); + Inst* headInst = (Inst*)block->getFirstInst(); for (int phase=0; phase < 2; ++phase) { // phase 0: remap just Pi node source operands // phase 1: add Pi remappings, remap source operands of other instructions - for (Inst* inst = headInst->next(); - inst != headInst; inst = inst->next()) { + for (Inst* inst = headInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (inst->getOpcode() == Op_TauPi) { if (phase == 1) { @@ -1026,12 +1073,12 @@ void Abcd::renamePiVariables(CFGNode *bl } } piMap->insert(orgOpnd, dstOpnd); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding remap for Pi of "; orgOpnd->print(Log::out()); Log::out() << " to "; inst->getDst()->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } continue; // don't remap Pi sources; @@ -1057,31 +1104,31 @@ void Abcd::renamePiVariables(CFGNode *bl if (inst->getOpcode() == Op_TauPi) { // for a Pi, remap variables appearing in the condition as well - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "remapping condition in "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } TauPiInst *thePiInst = inst->asTauPiInst(); assert(thePiInst); PiCondition *cond = thePiInst->cond; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " original condition is "; cond->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Opnd *lbRemap = cond->getLb().getVar().the_var; if (lbRemap) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " has lbRemap="; lbRemap->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } if (lbRemap->isPiOpnd()) lbRemap = lbRemap->asPiOpnd()->getOrg(); Opnd *lbRemapTo = piMap->lookup(lbRemap); if (lbRemapTo) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding remap of lbRemap="; lbRemap->print(Log::out()); Log::out() << " to lbRemapTo="; @@ -1090,30 +1137,30 @@ void Abcd::renamePiVariables(CFGNode *bl cond->print(Log::out()); } PiCondition remapped(*cond, lbRemap, lbRemapTo); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " YIELDS1 "; remapped.print(Log::out()); } *cond = remapped; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " YIELDS "; cond->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } Opnd *ubRemap = cond->getUb().getVar().the_var; if (ubRemap && (lbRemap != ubRemap)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " has ubRemap="; ubRemap->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } if (ubRemap->isPiOpnd()) ubRemap = ubRemap->asPiOpnd()->getOrg(); Opnd *ubRemapTo = piMap->lookup(ubRemap); if (ubRemapTo) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding remap of ubRemap="; ubRemap->print(Log::out()); Log::out() << " to ubRemapTo="; @@ -1122,15 +1169,15 @@ void Abcd::renamePiVariables(CFGNode *bl cond->print(Log::out()); } PiCondition remapped(*cond, ubRemap, ubRemapTo); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " YIELDS1 "; remapped.print(Log::out()); } *cond = remapped; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " YIELDS "; cond->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -1166,7 +1213,7 @@ void Abcd::removeRedundantBoundsChecks() // a ScopedDomNodeInstWalker, forward/preorder class RemovePiWalker { Abcd *thePass; - CFGNode *block; + Node *block; public: void startNode(DominatorNode *domNode) { block = domNode->getNode(); }; void applyToInst(Inst *i) { thePass->removePiNodes(block, i); }; @@ -1193,7 +1240,7 @@ void Abcd::removePiNodes() mm); } -void Abcd::removePiNodes(CFGNode *block, Inst *inst) +void Abcd::removePiNodes(Node *block, Inst *inst) { AbcdReasons *why; if (inst->getOpcode() == Op_TauPi) { @@ -1208,7 +1255,7 @@ void Abcd::removePiNodes(CFGNode *block, inst->setDst(OpndManager::getNullOpnd()); Inst* copy = irManager.getInstFactory().makeCopy(dstOpnd,srcOpnd); copy->insertBefore(inst); - irManager.getFlowGraph().eliminateCheck(block, inst, false); + FlowGraph::eliminateCheck(irManager.getFlowGraph(),block, inst, false); } else { uint32 numOpnds = inst->getNumSrcOperands(); for (uint32 i=0; i<numOpnds; i++) { @@ -1274,12 +1321,12 @@ void Abcd::removePiNodes(CFGNode *block, if (inst->getOverflowModifier() == Overflow_None) { new_check->setOverflowModifier(Overflow_None); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " inserting "; new_check->print(Log::out()); Log::out() << " in place of "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } new_check->insertBefore(inst); inst->unlink(); @@ -1303,14 +1350,14 @@ void Abcd::removePiNodes(CFGNode *block, if (inst->getOverflowModifier() == Overflow_None) { new_check->setOverflowModifier(Overflow_None); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " inserting "; ldcInst->print(Log::out()); Log::out() << ";"; new_check->print(Log::out()); Log::out() << "; in place of "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } new_check->insertBefore(inst); ldcInst->insertBefore(new_check); @@ -1322,9 +1369,9 @@ void Abcd::removePiNodes(CFGNode *block, void Abcd::markInstToEliminate(Inst *i) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate instruction "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminate.begin(); @@ -1337,9 +1384,9 @@ void Abcd::markInstToEliminate(Inst *i) void Abcd::markInstToEliminateAndWhy(Inst *i, AbcdReasons *why) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate instruction "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminate.begin(); @@ -1349,7 +1396,7 @@ void Abcd::markInstToEliminateAndWhy(Ins canEliminate.insert(lb, InstReasonPair(i, why)); } AbcdReasons *why2; - bool ism2e = isMarkedToEliminate(i, why2); + bool ism2e = isMarkedToEliminate(i, why2); if( !(ism2e && (why == why2)) ) assert(0); } @@ -1379,9 +1426,9 @@ bool Abcd::isMarkedToEliminate(Inst *i, void Abcd::markInstToEliminateLB(Inst *i) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate LB check in instruction "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminateLB.begin(); @@ -1394,11 +1441,11 @@ void Abcd::markInstToEliminateLB(Inst *i void Abcd::markInstToEliminateLBAndWhy(Inst *i, AbcdReasons *why) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate LB check in instruction "; i->print(Log::out()); Log::out() << " for why=" << ::std::hex << (void *) why << ::std::dec << "="; why->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminateLB.begin(); @@ -1408,7 +1455,7 @@ void Abcd::markInstToEliminateLBAndWhy(I canEliminateLB.insert(lb, InstReasonPair(i, why)); } AbcdReasons *why2; - bool ism2eLB = isMarkedToEliminateLB(i, why2); + bool ism2eLB = isMarkedToEliminateLB(i, why2); if( !(ism2eLB && (why == why2)) ) assert(0); } @@ -1438,9 +1485,9 @@ bool Abcd::isMarkedToEliminateLB(Inst *i void Abcd::markInstToEliminateUB(Inst *i) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate UB of instruction "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminateUB.begin(); @@ -1453,9 +1500,9 @@ void Abcd::markInstToEliminateUB(Inst *i void Abcd::markInstToEliminateUBAndWhy(Inst *i, AbcdReasons *why) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Can eliminate UB of instruction "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } typedef StlVector<InstReasonPair>::iterator itertype; itertype start = canEliminateUB.begin(); @@ -1465,7 +1512,7 @@ void Abcd::markInstToEliminateUBAndWhy(I canEliminateUB.insert(lb, InstReasonPair(i, why)); } AbcdReasons *why2; - bool ism2eUB = isMarkedToEliminateUB(i, why2); + bool ism2eUB = isMarkedToEliminateUB(i, why2); if( !(ism2eUB && (why == why2)) ) assert(0); } @@ -1587,33 +1634,32 @@ bool Abcd::getAliases(Opnd *opnd, AbcdAl } template <class inst_fun_type> -struct NodeInst2NodeFun : ::std::unary_function<CFGNode *, void> +struct NodeInst2NodeFun : ::std::unary_function<Node *, void> { inst_fun_type underlying_fun; NodeInst2NodeFun(const inst_fun_type &theFun) : underlying_fun(theFun) {}; - void operator()(CFGNode *theNode) { - Inst *first = theNode->getFirstInst(); - Inst *thisinst = first; + void operator()(Node *theNode) { + Inst *thisinst = (Inst*)theNode->getFirstInst(); assert(thisinst); do { underlying_fun(theNode, thisinst); - thisinst = thisinst->next(); - } while (thisinst != first); + thisinst = thisinst->getNextInst(); + } while (thisinst != NULL); } }; -struct SsaCheckingFun : public ::std::binary_function<CFGNode *, Inst *, void> { - void operator()(CFGNode *node, Inst *i) { +struct SsaCheckingFun : public ::std::binary_function<Node *, Inst *, void> { + void operator()(Node *node, Inst *i) { if (i->getOpcode() == Op_Phi) { - const CFGEdgeDeque& edges2 = node->getInEdges(); + const Edges& edges2 = node->getInEdges(); uint32 numEdges = (uint32) edges2.size(); uint32 numOps = i->getNumSrcOperands(); - if( !(numOps == numEdges) ) assert(0); + if( !(numOps == numEdges) ) assert(0); } } }; -void checkSSA(FlowGraph *flowgraph) +void checkSSA(ControlFlowGraph* flowgraph) { SsaCheckingFun checkInst; NodeInst2NodeFun<SsaCheckingFun> checkNode(checkInst); @@ -1731,12 +1777,12 @@ SsaTmpOpnd *Abcd::getReasonTau(AbcdReaso SsaTmpOpnd *tauDst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); Inst *tauAndInst = instFactory.makeTauAnd(tauDst, numReasons, newAndOpnds); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting tauAndInst=("; tauAndInst->print(Log::out()); Log::out() << ") before useSite= "; useSite->print(Log::out()); - Log::out() << ")" << ::std::endl; + Log::out() << ")" << std::endl; } tauAndInst->insertBefore(useSite); @@ -1772,9 +1818,9 @@ SsaTmpOpnd *Abcd::makeReasonPhi(Opnd *de if (stVarLoc->getOpcode() != Op_StVar) { assert(stVarLoc->getOpcode() == Op_Phi); // make sure we place stvar in a legal location - Inst *nextInst = stVarLoc->next(); + Inst *nextInst = stVarLoc->getNextInst(); while ((nextInst->getOpcode() == Op_Phi) && (nextInst->getOpcode() == Op_TauPi)) { - nextInst = nextInst->next(); + nextInst = nextInst->getNextInst(); } stVarLoc = nextInst; } @@ -1785,12 +1831,12 @@ SsaTmpOpnd *Abcd::makeReasonPhi(Opnd *de assert(varToStTo); Inst *tauStVarInst = instFactory.makeStVar(varToStTo, tauToStVar); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting tauStVarInst=("; tauStVarInst->print(Log::out()); Log::out() << ") after stVarLoc= "; stVarLoc->print(Log::out()); - Log::out() << ")" << ::std::endl; + Log::out() << ")" << std::endl; } tauStVarInst->insertAfter(stVarLoc); } @@ -1799,26 +1845,26 @@ SsaTmpOpnd *Abcd::makeReasonPhi(Opnd *de Inst *derefVarInst = derefVar->getInst(); assert(derefVarInst->getOpcode() == Op_Phi); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting tauPhiInst=("; tauPhiInst->print(Log::out()); Log::out() << ") before derefVarInst= "; derefVarInst->print(Log::out()); - Log::out() << ")" << ::std::endl; + Log::out() << ")" << std::endl; } tauPhiInst->insertBefore(derefVarInst); Inst *tauLdVarInst = instFactory.makeLdVar(tauResOpnd, tauPhiDstOpnd); - Inst *ldVarLoc = tauPhiInst->next(); - while ((ldVarLoc->getOpcode() == Op_Phi) || (ldVarLoc->getOpcode() == Op_TauPi)) { - ldVarLoc = ldVarLoc->next(); + Inst *ldVarLoc = tauPhiInst->getNextInst(); + while (ldVarLoc!=NULL && (ldVarLoc->getOpcode() == Op_Phi) || (ldVarLoc->getOpcode() == Op_TauPi)) { + ldVarLoc = ldVarLoc->getNextInst(); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting tauLdVarInst=("; tauLdVarInst->print(Log::out()); Log::out() << ") before ldVarLoc= "; ldVarLoc->print(Log::out()); - Log::out() << ")" << ::std::endl; + Log::out() << ")" << std::endl; } tauLdVarInst->insertBefore(ldVarLoc); return tauResOpnd; diff --git vm/jitrino/src/optimizer/abcd/abcd.h vm/jitrino/src/optimizer/abcd/abcd.h index dceb61e..3ac2048 100644 --- vm/jitrino/src/optimizer/abcd/abcd.h +++ vm/jitrino/src/optimizer/abcd/abcd.h @@ -38,15 +38,13 @@ class DominatorNode; class Dominator; class SparseOpndMap; class PiCondition; -class JitrinoParameterTable; -class CFGNode; +class Node; class Opnd; class BranchInst; class AbcdSolver; class AbcdAliases; class AbcdReasons; -DEFINE_OPTPASS(ABCDPass) typedef ::std::pair<Inst *, AbcdReasons *> InstReasonPair; @@ -54,6 +52,22 @@ inline bool operator <(const InstReasonP return (pair1.first < pair2.first); } +struct AbcdFlags { + bool partial; + bool dryRun; + bool useAliases; + bool useConv; + bool remConv; + bool useShr; + bool unmaskShifts; + bool remBr; + bool remCmp; + bool remOneBound; + bool remOverflow; + bool checkOverflow; + bool useReasons; +}; + class Abcd { IRManager& irManager; MemoryManager &mm; @@ -69,54 +83,16 @@ class Abcd { SsaTmpOpnd *tauUnsafe; SsaTmpOpnd *tauSafe; SsaTmpOpnd *blockTauPoint; - CFGNode *lastTauPointBlock; + Node *lastTauPointBlock; SsaTmpOpnd *blockTauEdge; - CFGNode *lastTauEdgeBlock; -public: - struct Flags { - bool partial; - bool dryRun; - bool useAliases; - bool useConv; - bool remConv; - bool useShr; - bool unmaskShifts; - bool remBr; - bool remCmp; - bool remOneBound; - bool remOverflow; - bool checkOverflow; - bool useReasons; - }; -private: - static Flags *defaultFlags; - Flags flags; + Node *lastTauEdgeBlock; + + AbcdFlags& flags; public: - static void readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params); - static void showFlagsFromCommandLine(); + static void readFlags(Action* argSource, AbcdFlags* flags); + static void showFlags(std::ostream& os); - Abcd(IRManager &irManager0, - MemoryManager& memManager, - DominatorTree& dom0) - : irManager(irManager0), - mm(memManager), - ineqGraph(0), - dominators(dom0), - piMap(0), - nextPiOpndId(0), - solver(0), - canEliminate(memManager), - canEliminateUB(memManager), - canEliminateLB(memManager), - tauUnsafe(0), - tauSafe(0), - blockTauPoint(0), - lastTauPointBlock(0), - blockTauEdge(0), - lastTauEdgeBlock(0), - flags(*defaultFlags) - { - }; + Abcd(IRManager &irManager0, MemoryManager& memManager, DominatorTree& dom0); ~Abcd() { }; @@ -125,32 +101,32 @@ public: private: void insertPiNodes(); // insert and rename over whole tree; void insertPiNodes(DominatorNode *domBlock); // for each dominator - void insertPiNodes(CFGNode *block); // for each dominator - void insertPiNodesForUnexceptionalPEI(CFGNode *block, Inst *pei); - void insertPiNodesForBranch(CFGNode *block, BranchInst *branchi, - CFGEdge::Kind kind); - void insertPiNodesForComparison(CFGNode *block, + void insertPiNodes(Node *block); // for each dominator + void insertPiNodesForUnexceptionalPEI(Node *block, Inst *pei); + void insertPiNodesForBranch(Node *block, BranchInst *branchi, + Edge::Kind kind); + void insertPiNodesForComparison(Node *block, ComparisonModifier mod, const PiCondition &bounds, Opnd *op, bool swap_operands, bool negate_comparison); - void insertPiNodeForOpnd(CFGNode *block, Opnd *org, + void insertPiNodeForOpnd(Node *block, Opnd *org, const PiCondition &cond, Opnd *tauOpnd = 0); // checks for aliases of opnd, inserts them. - void insertPiNodeForOpndAndAliases(CFGNode *block, Opnd *org, + void insertPiNodeForOpndAndAliases(Node *block, Opnd *org, const PiCondition &cond, Opnd *tauOpnd = 0); - PiOpnd *getNewDestOpnd(CFGNode *block, Opnd *org); + PiOpnd *getNewDestOpnd(Node *block, Opnd *org); Opnd *getConstantOpnd(Opnd *opnd); // dereferencing through Pis, 0 if not constant. void renamePiVariables(); - void renamePiVariables(CFGNode *block); + void renamePiVariables(Node *block); void renamePiVariables(DominatorNode *block); void removePiNodes(); - void removePiNodes(CFGNode *block, Inst *i); + void removePiNodes(Node *block, Inst *i); void updateSsaForm(); void buildInequalityGraph(); @@ -174,8 +150,8 @@ private: void markInstToEliminateUBAndWhy(Inst *, AbcdReasons *); bool isMarkedToEliminateUB(Inst *, AbcdReasons *&why); - SsaTmpOpnd *getBlockTauPoint(CFGNode *block); - SsaTmpOpnd *getBlockTauEdge(CFGNode *block); + SsaTmpOpnd *getBlockTauPoint(Node *block); + SsaTmpOpnd *getBlockTauEdge(Node *block); SsaTmpOpnd *getTauUnsafe(); SsaTmpOpnd *getTauSafe(); SsaTmpOpnd *getReasonTau(AbcdReasons *reason, diff --git vm/jitrino/src/optimizer/abcd/abcdbounds.cpp vm/jitrino/src/optimizer/abcd/abcdbounds.cpp index 8ddb7ba..253039b 100644 --- vm/jitrino/src/optimizer/abcd/abcdbounds.cpp +++ vm/jitrino/src/optimizer/abcd/abcdbounds.cpp @@ -414,7 +414,7 @@ VarBound::isConvexFunction() const { assert(mod.hasSignedModifier()); if ((mod.getSignedModifier() == SignedOp) && ConstantFolder::isConstant(the_inst->getSrc(1)) ) { return true; - } + } } return false; } @@ -447,48 +447,48 @@ VarBound::getConvexInputBound(bool isLB, // must be signed switch (typetag) { case Type::Int32: - { - int32 bound = outputBound.getInt32(); - if (the_inst->getShiftMaskModifier() == ShiftMask_Masked) - shiftBy = shiftBy & 31; - int32 input = bound << shiftBy; - if (!isLB) { - if (shiftBy < 31) { - input = input + ((int32(1) << shiftBy) - 1); - } else { - input = 0xffffffff; - } - } - if (bound < 0) { - input = input | 0x80000000; - } else { - input = input & 0x7fffffff; - } - inputVar = VarBound(inputOpnd); - return ConstBound(input); - } + { + int32 bound = outputBound.getInt32(); + if (the_inst->getShiftMaskModifier() == ShiftMask_Masked) + shiftBy = shiftBy & 31; + int32 input = bound << shiftBy; + if (!isLB) { + if (shiftBy < 31) { + input = input + ((int32(1) << shiftBy) - 1); + } else { + input = 0xffffffff; + } + } + if (bound < 0) { + input = input | 0x80000000; + } else { + input = input & 0x7fffffff; + } + inputVar = VarBound(inputOpnd); + return ConstBound(input); + } case Type::Int64: - { - int64 bound = outputBound.getInt64(); - if (the_inst->getShiftMaskModifier() == ShiftMask_Masked) - shiftBy = shiftBy & 63; - int64 input = bound << shiftBy; - if (!isLB) { - if (shiftBy < 64) { - input = input + ((int64(1) << shiftBy) - 1); - } else { - input = __INT64_C(0xffffffffffffffff); - } - } - if (bound < 0) { - input = input | __INT64_C(0x8000000000000000); - } else { - input = input & __INT64_C(0x7fffffffffffffff); - } - inputVar = VarBound(inputOpnd); - return ConstBound(input); - } + { + int64 bound = outputBound.getInt64(); + if (the_inst->getShiftMaskModifier() == ShiftMask_Masked) + shiftBy = shiftBy & 63; + int64 input = bound << shiftBy; + if (!isLB) { + if (shiftBy < 64) { + input = input + ((int64(1) << shiftBy) - 1); + } else { + input = __INT64_C(0xffffffffffffffff); + } + } + if (bound < 0) { + input = input | __INT64_C(0x8000000000000000); + } else { + input = input & __INT64_C(0x7fffffffffffffff); + } + inputVar = VarBound(inputOpnd); + return ConstBound(input); + } default: break; @@ -677,7 +677,7 @@ void PiBoundIter::setCurrent() #ifndef NDEBUG Opnd *op0 = instr->getSrc(0); #endif - Opnd *op1 = constOpnd; + Opnd *op1 = constOpnd; // now op1 should be constant // I assume we've done folding first assert(!getConstantOpnd(op0)); diff --git vm/jitrino/src/optimizer/abcd/abcdbounds.h vm/jitrino/src/optimizer/abcd/abcdbounds.h index a334675..6203ba8 100644 --- vm/jitrino/src/optimizer/abcd/abcdbounds.h +++ vm/jitrino/src/optimizer/abcd/abcdbounds.h @@ -223,9 +223,9 @@ public: return ConstBound(false); // MinusInfinity; case Const_MinusInfinity: return ConstBound(true); // PlusInfinity - default: - assert(0); - break; + default: + assert(0); + break; } return *this; } @@ -379,13 +379,13 @@ public: bool isLessEq(const PiBound &other) const; // Return x such that [x, infinity] includes the union of // the intervals [this, infinity] and [other, infinity]. - PiBound min(const PiBound &other) const; +// PiBound min(const PiBound &other) const; // Does the range [-infinity, this] include [-infinity, other]? bool isGreaterEq(const PiBound &other) const; // Return x such that [-infinity, x] includes the union of // the intervals [-infinity, this] and [-infinity, other]. - PiBound max(const PiBound &other) const; +// PiBound max(const PiBound &other) const; PiBound invert(VarBound vb) const { if (isUnknown() || isUndefined()) return *this; diff --git vm/jitrino/src/optimizer/abcd/abcdsolver.cpp vm/jitrino/src/optimizer/abcd/abcdsolver.cpp index e4b8b9c..b8cc946 100644 --- vm/jitrino/src/optimizer/abcd/abcdsolver.cpp +++ vm/jitrino/src/optimizer/abcd/abcdsolver.cpp @@ -67,7 +67,7 @@ ProofLattice AbcdSolver::prove(bool prov pushindent saveindent(this); if (prove_lower_bound) { ConstBound negC = -c; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Trying to prove "; var2.print(Log::out()); Log::out() << " - "; @@ -90,7 +90,7 @@ ProofLattice AbcdSolver::prove(bool prov } else { MemoizedBounds &mb = cache[::std::make_pair(var2, var1)]; // bounds on (var2-var1) - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Trying to prove "; var2.print(Log::out()); Log::out() << " - "; @@ -100,7 +100,7 @@ ProofLattice AbcdSolver::prove(bool prov Log::out() << " : "; } if (mb.leastTrueUB <= c) { // already proved a lower UB. - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 1: mb.leastTrueUB =="; mb.leastTrueUB.print(Log::out()); Log::out() << " => TRUE" << ::std::endl; @@ -113,14 +113,14 @@ ProofLattice AbcdSolver::prove(bool prov } return ProofLattice::ProvenTrue; } else if (mb.greatestFalseUB >= c) { // already disproved a higher UB - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 2: mb.greatestFalseUB =="; mb.greatestFalseUB.print(Log::out()); Log::out() << " => FALSE" << ::std::endl; } return ProofLattice::ProvenFalse; } else if (mb.leastReducedUB <= c) { // has cycle with lower UB - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 3: mb.leastReducedUB =="; mb.leastReducedUB.print(Log::out()); Log::out() << " => REDUCED" << ::std::endl; @@ -134,7 +134,7 @@ ProofLattice AbcdSolver::prove(bool prov return ProofLattice::ProvenReduced; } else if ((var1 == var2) && (c >= ConstBound(int32(0)))) { // reached source: - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 4: => TRUE" << ::std::endl; } // don't need a reason, it's self-evident @@ -145,11 +145,11 @@ ProofLattice AbcdSolver::prove(bool prov ConstBound &active_var = active[::std::make_pair(var1,var2)]; if (!active_var.isNull()) { // a cycle - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 5" << ::std::endl; } if (c < active_var) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Case 5a : active["; var1.print(Log::out()); Log::out() << ", "; @@ -161,7 +161,7 @@ ProofLattice AbcdSolver::prove(bool prov // skip memorization step below by returning immediately return ProofLattice::ProvenFalse; // a reducing cycle for lb } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Case 5b : active["; var1.print(Log::out()); Log::out() << ", "; @@ -174,12 +174,12 @@ ProofLattice AbcdSolver::prove(bool prov return ProofLattice::ProvenReduced; } } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Case 5c: => ..." << ::std::endl; } } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " Setting active["; var1.print(Log::out()); Log::out() << ", "; @@ -222,7 +222,7 @@ ProofLattice AbcdSolver::prove(bool prov // // Note that we are safe from infinite recursion since we // don't move to var2 until var1 is blocked. - // + // bool ignore; result = proveForPredecessors(var1, var2, @@ -235,7 +235,7 @@ ProofLattice AbcdSolver::prove(bool prov } active_var.setNull(); // reset it to Null - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Finished trying to prove "; var2.print(Log::out()); Log::out() << " - "; @@ -246,7 +246,7 @@ ProofLattice AbcdSolver::prove(bool prov } switch (result.value) { case ProofLattice::ProvenTrue: - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " TRUE " << ::std::endl; } if (c < mb.leastTrueUB) { @@ -262,14 +262,14 @@ ProofLattice AbcdSolver::prove(bool prov mb.leastTrueUB = c; break; } case ProofLattice::ProvenFalse: - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " FALSE " << ::std::endl; } if (c > mb.greatestFalseUB) { mb.greatestFalseUB = c; break; } case ProofLattice::ProvenReduced: - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " REDUCED " << ::std::endl; } if (c < mb.leastReducedUB) { @@ -298,7 +298,7 @@ void AbcdSolver::tryToEliminate(Inst *th Opnd *arrayOp = theInst->getSrc(0); Opnd *idxOp = theInst->getSrc(1); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking checkbounds instruction "; theInst->print(Log::out()); Log::out() << " for redundancy" << ::std::endl; @@ -315,7 +315,7 @@ void AbcdSolver::tryToEliminate(Inst *th VarBound(idxOp), // may want upper bound of range -1, why)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "We can eliminate UB check of "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -325,7 +325,7 @@ void AbcdSolver::tryToEliminate(Inst *th Log::out() << ::std::endl; } } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "We cannot eliminate UB check of "; theInst->print(Log::out()); Log::out() << ::std::endl; @@ -340,7 +340,7 @@ void AbcdSolver::tryToEliminate(Inst *th VarBound(), // upper bound of 0 0, why)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "We can eliminate LB check of "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -350,7 +350,7 @@ void AbcdSolver::tryToEliminate(Inst *th Log::out() << ::std::endl; } } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "We cannot eliminate LB check of "; theInst->print(Log::out()); Log::out() << ::std::endl; @@ -359,7 +359,7 @@ void AbcdSolver::tryToEliminate(Inst *th } if (successUB) { if (successLB) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "!!! We can eliminate boundscheck of "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -375,7 +375,7 @@ void AbcdSolver::tryToEliminate(Inst *th else thePass->markCheckToEliminate(theInst); } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "!!! We can eliminate UB check of "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -393,7 +393,7 @@ void AbcdSolver::tryToEliminate(Inst *th } } else { if (successLB) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "!!! We can eliminate LB check of "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -444,14 +444,14 @@ void AbcdSolver::tryToEliminate(Inst *th (srcOp->getType()->tag == dstOp->getType()->tag) && !thePass->isMarkedToEliminate(theInst, ignore)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking conv instruction "; theInst->print(Log::out()); Log::out() << " for redundancy" << ::std::endl; } if (Abcd::convPassesSource(dstOp)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "We can trivially remove conv instruction "; theInst->print(Log::out()); Log::out() << ::std::endl; @@ -497,7 +497,7 @@ void AbcdSolver::tryToEliminate(Inst *th if (res1 != ProofLattice::ProvenFalse) { // note that though these are constant bounds, // they can result in reduced proofs - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "!!! We can eliminate conversion: "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -523,7 +523,7 @@ void AbcdSolver::tryToEliminate(Inst *th AbcdReasons *ignore; if (Abcd::hasCheckableType(shiftByOp) && !thePass->isMarkedToEliminate(theInst, ignore)) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking shift instruction "; theInst->print(Log::out()); Log::out() << " to eliminate mask" << ::std::endl; @@ -557,7 +557,7 @@ void AbcdSolver::tryToEliminate(Inst *th if (res2 != ProofLattice::ProvenFalse) { // note that though these are constant bounds, // they can result in reduced proofs - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "!!! We can eliminate shift mask: "; theInst->print(Log::out()); if (thePass->flags.useReasons) { @@ -627,7 +627,7 @@ void AbcdSolver::tryToEliminate(Inst *th #ifndef NDEBUG Type::Tag constInstType = constInst->getType(); #endif - assert(isSigned ? + assert(isSigned ? ((constInstType == Type::Int8)||(constInstType == Type::Int16)|| (constInstType == Type::Int32)) : ((constInstType == Type::UInt8)|| @@ -717,13 +717,13 @@ #endif } else { newmod.setOverflowModifier(Overflow_Unsigned); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Disproved overflow of add/sub instruction "; theInst->print(Log::out()); Log::out() << " so marking it overflow but exception-free" << ::std::endl; } } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Disproved overflow of add/sub instruction "; theInst->print(Log::out()); Log::out() << " so marking it exception-free" << ::std::endl; @@ -777,7 +777,7 @@ #ifndef NDEBUG ((constInstType == Type::UInt8)|| (constInstType == Type::UInt16)||(constInstType == Type::UInt32))); #endif - ConstInst::ConstValue constValue = constInst->getValue(); + ConstInst::ConstValue constValue = constInst->getValue(); int32 constValue32 = constValue.i4; int64 varlb, varub; if (isSigned) { @@ -864,13 +864,13 @@ #endif } else { newmod.setOverflowModifier(Overflow_Unsigned); } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Disproved overflow of mul instruction "; theInst->print(Log::out()); Log::out() << " so marking it overflow but exception-free" << ::std::endl; } } else { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Disproved overflow of mul instruction "; theInst->print(Log::out()); Log::out() << " so marking it exception-free" << ::std::endl; @@ -900,7 +900,7 @@ ProofLattice AbcdSolver::proveForSpecial const VarBound &otherVar = (checkVar1 ? var2 : var1); ProofLattice result = ProofLattice::ProvenFalse; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Checking special cases for: "; theVar.print(Log::out()); Log::out() << ::std::endl; @@ -915,7 +915,7 @@ ProofLattice AbcdSolver::proveForSpecial assert(theVar.the_var != 0); Inst *the_inst = theVar.the_var->getInst(); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "ConvexFunction: "; the_inst->print(Log::out()); Log::out() << ::std::endl; @@ -989,7 +989,7 @@ ProofLattice AbcdSolver::proveForSpecial assert(theVar.the_var != 0); Inst *the_inst = theVar.the_var->getInst(); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Have conv : "; the_inst->print(Log::out()); Log::out() << ::std::endl; @@ -999,14 +999,14 @@ ProofLattice AbcdSolver::proveForSpecial AbcdReasons *markedWhy = 0; bool alreadyMarked = thePass->isMarkedToEliminate(the_inst, markedWhy); if (passesSource) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Passes Source: "; the_inst->print(Log::out()); Log::out() << ::std::endl; } }; if (alreadyMarked) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Already marked : "; the_inst->print(Log::out()); Log::out() << ::std::endl; @@ -1047,7 +1047,7 @@ ProofLattice AbcdSolver::proveForSpecial // check whether source is in range PiCondition convBounds = PiCondition::convBounds(theVar); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Checking for source in range : "; the_inst->print(Log::out()); Log::out() << ::std::endl; @@ -1083,7 +1083,7 @@ ProofLattice AbcdSolver::proveForSpecial } if (res1 != ProofLattice::ProvenFalse) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Source is in range, passing constraint: "; the_inst->print(Log::out()); if (thePass->flags.useReasons) { @@ -1112,7 +1112,7 @@ ProofLattice AbcdSolver::proveForSpecial c, subWhy); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "Special case conv result = "; result.print(Log::out()); Log::out() << ::std::endl; @@ -1129,7 +1129,7 @@ ProofLattice AbcdSolver::proveForSpecial } } noneApply = true; - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << "NoneApply, special case conv result = "; result.print(Log::out()); Log::out() << ::std::endl; @@ -1159,7 +1159,7 @@ ProofLattice AbcdSolver::proveForPredece VarBound derefVar = (derefVar1 ? var1 : var2); bool boundDirection = derefVar1; // preds are lower bounds, MIN acts like PHI if (preds.isEmpty()) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " Predecessors of "; if (derefVar1) { Log::out() << "var1="; @@ -1173,7 +1173,7 @@ ProofLattice AbcdSolver::proveForPredece predsAreEmpty = true; } else { if (derefVar.isPhiVar()) { - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " Case 5c : Phi function" << ::std::endl; } @@ -1256,7 +1256,7 @@ ProofLattice AbcdSolver::proveForPredece = ((andConditions && thePass->flags.useReasons) ? new (thePass->mm) StlVector<AbcdReasons *>(thePass->mm) : 0); - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " Case 5d : non-Phi" << ::std::endl; } @@ -1337,7 +1337,7 @@ ProofLattice AbcdSolver::proveForPredece } } } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " returning "; result.print(Log::out()); @@ -1360,7 +1360,7 @@ ProofLattice AbcdSolver::proveForPredece return result; } } - if (Log::cat_opt_abcd()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << indent.c_str() << " returning FALSE"; Log::out() << ::std::endl; diff --git vm/jitrino/src/optimizer/abcd/abcdsolver.h vm/jitrino/src/optimizer/abcd/abcdsolver.h index 4ec4c76..480fca2 100644 --- vm/jitrino/src/optimizer/abcd/abcdsolver.h +++ vm/jitrino/src/optimizer/abcd/abcdsolver.h @@ -192,11 +192,11 @@ public: // if (!checkVar1), var2 should have been fully dereferenced // and checked first.; sets noneApply=true if none apply ProofLattice proveForSpecialCases(const VarBound &var1, - const VarBound &var2, - ConstBound c, - bool checkVar1, - bool &noneApply, - AbcdReasons *why); // if non-null and proven true, reasons why + const VarBound &var2, + ConstBound c, + bool checkVar1, + bool &noneApply, + AbcdReasons *why); // if non-null and proven true, reasons why void tryToEliminate(Inst *); // solve for an instruction; void tryToFoldBranch(Inst *); void tryToFoldCompare(Inst *); diff --git vm/jitrino/src/optimizer/aliasanalyzer.h vm/jitrino/src/optimizer/aliasanalyzer.h index e1c9c9a..47e9f65 100644 --- vm/jitrino/src/optimizer/aliasanalyzer.h +++ vm/jitrino/src/optimizer/aliasanalyzer.h @@ -34,7 +34,9 @@ class Type; class AliasAnalyzer { public: + virtual ~AliasAnalyzer() {} + /** * Return false if op1 and op2 cannot point to same location in memory. * Both op1 and op2 must be reference or pointer typed. The method will @@ -54,12 +56,13 @@ class TypeAliasAnalyzer : public AliasAn { public: virtual ~TypeAliasAnalyzer() {} + bool mayAlias(Opnd* op1, Opnd* op2); bool mayAlias(Type* t1, Type* t2); private: - + MemoryAttributeManager _mam; }; diff --git vm/jitrino/src/optimizer/codelowerer.cpp vm/jitrino/src/optimizer/codelowerer.cpp index 0a40883..e909afe 100644 --- vm/jitrino/src/optimizer/codelowerer.cpp +++ vm/jitrino/src/optimizer/codelowerer.cpp @@ -26,13 +26,14 @@ #include "globalopndanalyzer.h" #include "constantfolder.h" #include "optimizer.h" #include "Log.h" +#include "FlowGraph.h" +#include "PMFAction.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(CodeLoweringPass, lower, "Code Lowering / Fast Path Inlining") +DEFINE_SESSION_ACTION(CodeLoweringPass, lower, "Code Lowering / Fast Path Inlining"); -void -CodeLoweringPass::_run(IRManager& irm) { +void CodeLoweringPass::_run(IRManager& irm){ CodeLowerer lowerer(irm); lowerer.doLower(); } @@ -46,34 +47,31 @@ CodeLowerer::doLower() { MemoryManager mm(1000, "CodeLowerer.doLower"); - CFGVector nodes(mm); + Nodes nodes(mm); _irm.getFlowGraph().getNodesPostOrder(nodes); - CFGVector::ReverseIterator i; - - for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode *_currentBlock = *i; + + for(Nodes::reverse_iterator i = nodes.rbegin(); i != nodes.rend(); ++i) { + Node *_currentBlock = *i; if(_currentBlock->isBlockNode()) lowerBlock(_currentBlock); } } void -CodeLowerer::lowerBlock(CFGNode *block) { +CodeLowerer::lowerBlock(Node *block) { assert(block->isBlockNode()); - - Inst* first = block->getFirstInst(); - - for(Inst* inst = first->next(); inst != first; inst = inst->next()) { + for(Inst* inst = (Inst*)block->getFirstInst(); inst != NULL; inst = inst->getNextInst()) { inst = optimizeInst(inst); - if(inst == NULL) + if (inst == NULL) { break; + } } } Inst* CodeLowerer::caseTauCast(TypeInst* inst) { - CFGNode* block = inst->getNode(); + Node* block = inst->getNode(); // // Perform null and vtable checks to avoid an expensive vm call. // The vtable check often succeeds in practice. @@ -103,16 +101,16 @@ CodeLowerer::caseTauCast(TypeInst* inst) // // Target is _succ_ if cast succeeds and _fail_ if cast fails. // - CFGNode* succ = (CFGNode*) block->getUnconditionalEdge()->getTargetNode(); - CFGNode* fail = (CFGNode*) block->getExceptionEdge()->getTargetNode(); + Node* succ = block->getUnconditionalEdge()->getTargetNode(); + Node* fail = block->getExceptionEdge()->getTargetNode(); assert(succ->isBlockNode() && fail->isDispatchNode()); - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); InstFactory& instFactory = _irm.getInstFactory(); OpndManager& opndManager = _irm.getOpndManager(); TypeManager& typeManager = _irm.getTypeManager(); - Inst* succInst = succ->getFirstInst()->next(); + Inst* succInst = (Inst*)succ->getSecondInst(); if(succInst->getOpcode() == Op_TauCheckNull) { // // We have @@ -126,7 +124,7 @@ CodeLowerer::caseTauCast(TypeInst* inst) // dst = cast src, castType, tauDst2 ---> fail // succ2: assert(succInst == succ->getLastInst()); - CFGNode* fail2 = (CFGNode*) succ->getExceptionEdge()->getTargetNode(); + Node* fail2 = succ->getExceptionEdge()->getTargetNode(); Opnd* src2 = succInst->getSrc(0); if(succ->getInDegree() == 1 && fail2 == fail && src2 == dst) { // Reorder checknull and checkcast. @@ -138,8 +136,8 @@ CodeLowerer::caseTauCast(TypeInst* inst) inst->unlink(); succInst->unlink(); - block->append(succInst); - succ->append(inst); + block->appendInst(succInst); + succ->appendInst(inst); succInst->setSrc(0, src); return succInst; @@ -187,13 +185,13 @@ CodeLowerer::caseTauCast(TypeInst* inst) // succ: // ... - CFGNode* b1 = fg.createBlockNode(); - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); - CFGNode* b3a = fg.createBlockNode(); - CFGNode* b3b = fg.createBlockNode(); - CFGNode* b3c = 0; - + Node* b1 = fg.createBlockNode(instFactory.makeLabel()); + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3a = fg.createBlockNode(instFactory.makeLabel()); + Node* b3b = fg.createBlockNode(instFactory.makeLabel()); + Node* b3c = 0; + // // Add null check to _block_. // @@ -202,15 +200,14 @@ CodeLowerer::caseTauCast(TypeInst* inst) inst->unlink(); Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, - b3b->getLabel()); - block->append(test1); + (LabelInst*)b3b->getFirstInst()); + block->appendInst(test1); fg.addEdge(block, b1); fg.addEdge(block, b3b); // create a new tau for null-checked - tauNullChecked = - opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1->append(instFactory.makeTauEdge(tauNullChecked)); + tauNullChecked = opndManager.createSsaTmpOpnd(typeManager.getTauType()); + b1->appendInst(instFactory.makeTauEdge(tauNullChecked)); // // Test direct vtable equality in _b1_ if cast target type is concrete. @@ -221,10 +218,10 @@ CodeLowerer::caseTauCast(TypeInst* inst) ObjectType* srcType = (ObjectType*) src->getType(); Opnd* vt1 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(srcType)); Opnd* vt2 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); - b1->append(instFactory.makeTauLdVTableAddr(vt1, src, tauNullChecked)); - b1->append(instFactory.makeGetVTableAddr(vt2, castType)); - b3c = fg.createBlockNode(); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, b3c->getLabel())); + b1->appendInst(instFactory.makeTauLdVTableAddr(vt1, src, tauNullChecked)); + b1->appendInst(instFactory.makeGetVTableAddr(vt2, castType)); + b3c = fg.createBlockNode(instFactory.makeLabel()); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, (LabelInst*)b3c->getFirstInst())); fg.addEdge(b1, b3c); } fg.addEdge(b1, b2); @@ -233,7 +230,7 @@ CodeLowerer::caseTauCast(TypeInst* inst) // Fall throw to cast call in _b2_. // Opnd* tauCheckedCast = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b2->append(instFactory.makeTauCheckCast(tauCheckedCast, src, + b2->appendInst(instFactory.makeTauCheckCast(tauCheckedCast, src, tauNullChecked, type)); fg.addEdge(b2, b3a); @@ -252,26 +249,26 @@ CodeLowerer::caseTauCast(TypeInst* inst) SsaVarOpnd *tauvar4 = opndManager.createSsaVarOpnd(tauHasTypeVar); // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3b - b3b->append(instFactory.makeTauEdge(tau3)); - b3b->append(instFactory.makeStVar(tauvar2, tau3)); + b3b->appendInst(instFactory.makeTauEdge(tau3)); + b3b->appendInst(instFactory.makeStVar(tauvar2, tau3)); if (b3c) { // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar3, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar3, tau4)); // b3 Opnd* phiOpnds[3] = { tauvar1, tauvar2, tauvar3 }; - b3->append(instFactory.makePhi(tauvar4, 3, phiOpnds)); - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makePhi(tauvar4, 3, phiOpnds)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } else { // b3 Opnd* phiOpnds[3] = { tauvar1, tauvar2 }; - b3->append(instFactory.makePhi(tauvar4, 2, phiOpnds)); - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makePhi(tauvar4, 2, phiOpnds)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } } else { // not SSA @@ -282,27 +279,27 @@ CodeLowerer::caseTauCast(TypeInst* inst) VarOpnd *tauvar4 = tauHasTypeVar; // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3b - b3b->append(instFactory.makeTauEdge(tau3)); - b3b->append(instFactory.makeStVar(tauvar2, tau3)); + b3b->appendInst(instFactory.makeTauEdge(tau3)); + b3b->appendInst(instFactory.makeStVar(tauvar2, tau3)); if (b3c) { // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar4, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar4, tau4)); } // b3 - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } fg.addEdge(b3a, b3); fg.addEdge(b3b, b3); if (b3c) fg.addEdge(b3c, b3); - b3->append(instFactory.makeTauStaticCast(dst, src, tau2, type)); + b3->appendInst(instFactory.makeTauStaticCast(dst, src, tau2, type)); fg.addEdge(b3, succ); return test1; @@ -311,7 +308,7 @@ CodeLowerer::caseTauCast(TypeInst* inst) Inst* CodeLowerer::caseTauCheckCast(TypeInst* inst) { - CFGNode* block = inst->getNode(); + Node* block = inst->getNode(); // // Perform null and vtable checks to avoid an expensive VM call. // The vtable check often succeeds in practice. @@ -334,28 +331,27 @@ CodeLowerer::caseTauCheckCast(TypeInst* // // Target is _succ_ if cast succeeds and _fail_ if cast fails. // - CFGNode* succ = (CFGNode*) block->getUnconditionalEdge()->getTargetNode(); - CFGNode* fail = (CFGNode*) block->getExceptionEdge()->getTargetNode(); + Node* succ = block->getUnconditionalEdge()->getTargetNode(); + Node* fail = block->getExceptionEdge()->getTargetNode(); assert(succ->isBlockNode() && fail->isDispatchNode()); - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); InstFactory& instFactory = _irm.getInstFactory(); OpndManager& opndManager = _irm.getOpndManager(); TypeManager& typeManager = _irm.getTypeManager(); - Inst* succInst = succ->getFirstInst()->next(); + Inst* succInst = (Inst*)succ->getSecondInst(); Inst* succInst2 = 0; Opnd* checkNullSrc = 0; - if ((succInst->getOpcode() == Op_TauStaticCast) && - (succInst->getSrc(0) == src)) { + if (succInst!=NULL && (succInst->getOpcode() == Op_TauStaticCast) && (succInst->getSrc(0) == src)) { // if succInst is a static cast, find following inst checkNullSrc = succInst->getDst(); succInst2 = succInst; - succInst = succInst->next(); + succInst = succInst->getNextInst(); } - if(succInst->getOpcode() == Op_TauCheckNull) { + if(succInst!=NULL && succInst->getOpcode() == Op_TauCheckNull) { assert(succInst == succ->getLastInst()); - CFGNode* fail2 = (CFGNode*) succ->getExceptionEdge()->getTargetNode(); + Node* fail2 = succ->getExceptionEdgeTarget(); if(succ->getInDegree() == 1 && fail2 == fail && ((succInst->getSrc(0) == src) || (succInst->getSrc(0) == checkNullSrc))) { @@ -380,7 +376,7 @@ CodeLowerer::caseTauCheckCast(TypeInst* Inst *copyInst = instFactory.makeCopy(tauDst2, tauNullChecked); copyInst->insertBefore(succInst); - fg.eliminateCheck(succ, succInst, false); + FlowGraph::eliminateCheck(fg, succ, succInst, false); } else { // // We have @@ -398,7 +394,7 @@ CodeLowerer::caseTauCheckCast(TypeInst* // Reorder checknull and checkcast. Opnd* tauDst2 = succInst->getDst(); - CFGNode* succ2 = (CFGNode*) succ->getUnconditionalEdge()->getTargetNode(); + Node* succ2 = succ->getUnconditionalEdge()->getTargetNode(); assert(inst->getSrc(1)->getType()->tag == Type::Tau); inst->setSrc(1, tauDst2); @@ -406,27 +402,29 @@ CodeLowerer::caseTauCheckCast(TypeInst* inst->unlink(); succInst->unlink(); - block->append(succInst); - succ->append(inst); + block->appendInst(succInst); + succ->appendInst(inst); succInst->setSrc(0, src); // if it had a static cast if (succInst2) { // we had a static cast, insert it in succ2 succInst2->unlink(); - Inst *succ2HeadInst = succ2->getFirstInst(); - Inst *insertBeforeInst = succ2HeadInst->next(); - while ((insertBeforeInst->getOpcode() == Op_Phi) || - (insertBeforeInst->getOpcode() == Op_TauPi)) { - insertBeforeInst = insertBeforeInst->next(); + Inst *succ2HeadInst = (Inst*)succ2->getFirstInst(); + Inst *insertBeforeInst = succ2HeadInst->getNextInst(); + while (insertBeforeInst!=NULL + && (insertBeforeInst->getOpcode() == Op_Phi) + || (insertBeforeInst->getOpcode() == Op_TauPi)) + { + insertBeforeInst = insertBeforeInst->getNextInst(); } succInst2->insertBefore(insertBeforeInst); } // update our local state so we can apply the next rule block = succ; - succ = (CFGNode*) block->getUnconditionalEdge()->getTargetNode(); - fail = (CFGNode*) block->getExceptionEdge()->getTargetNode(); + succ = block->getUnconditionalEdge()->getTargetNode(); + fail = block->getExceptionEdge()->getTargetNode(); tauNullChecked = tauDst2; nullWasChecked = true; } @@ -474,12 +472,12 @@ CodeLowerer::caseTauCheckCast(TypeInst* // succ: // ... - CFGNode* b1 = fg.createBlockNode(); - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); - CFGNode* b3a = fg.createBlockNode(); - CFGNode* b3b = fg.createBlockNode(); - CFGNode* b3c = 0; + Node* b1 = fg.createBlockNode(instFactory.makeLabel()); + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3a = fg.createBlockNode(instFactory.makeLabel()); + Node* b3b = fg.createBlockNode(instFactory.makeLabel()); + Node* b3c = 0; // // Add null check to _block_. @@ -489,15 +487,15 @@ CodeLowerer::caseTauCheckCast(TypeInst* inst->unlink(); Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, - b3b->getLabel()); - block->append(test1); + (LabelInst*)b3b->getFirstInst()); + block->appendInst(test1); fg.addEdge(block, b1); fg.addEdge(block, b3b); // create a new tau for nullchecked tauNullChecked = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1->append(instFactory.makeTauEdge(tauNullChecked)); + b1->appendInst(instFactory.makeTauEdge(tauNullChecked)); // // Test direct vtable equality in _b1_ if cast target type is concrete. @@ -508,10 +506,10 @@ CodeLowerer::caseTauCheckCast(TypeInst* ObjectType* srcType = (ObjectType*) src->getType(); Opnd* vt1 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(srcType)); Opnd* vt2 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); - b1->append(instFactory.makeTauLdVTableAddr(vt1, src, tauNullChecked)); - b1->append(instFactory.makeGetVTableAddr(vt2, castType)); - b3c = fg.createBlockNode(); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, b3c->getLabel())); + b1->appendInst(instFactory.makeTauLdVTableAddr(vt1, src, tauNullChecked)); + b1->appendInst(instFactory.makeGetVTableAddr(vt2, castType)); + b3c = fg.createBlockNode(instFactory.makeLabel()); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, (LabelInst*)b3c->getFirstInst())); fg.addEdge(b1, b3c); } fg.addEdge(b1, b2); @@ -523,7 +521,7 @@ CodeLowerer::caseTauCheckCast(TypeInst* // reuse inst inst->setDst(tauCheckedCast); inst->setSrc(1, tauNullChecked); - b2->append(inst); + b2->appendInst(inst); fg.addEdge(b2, b3a); fg.addEdge(b2, fail); @@ -540,26 +538,26 @@ CodeLowerer::caseTauCheckCast(TypeInst* SsaVarOpnd *tauvar4 = opndManager.createSsaVarOpnd(tauHasTypeVar); // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3b - b3b->append(instFactory.makeTauEdge(tau3)); - b3b->append(instFactory.makeStVar(tauvar2, tau3)); + b3b->appendInst(instFactory.makeTauEdge(tau3)); + b3b->appendInst(instFactory.makeStVar(tauvar2, tau3)); if (b3c) { // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar3, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar3, tau4)); // b3 Opnd* phiOpnds[3] = { tauvar1, tauvar2, tauvar3 }; - b3->append(instFactory.makePhi(tauvar4, 3, phiOpnds)); - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makePhi(tauvar4, 3, phiOpnds)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } else { // b3 Opnd* phiOpnds[3] = { tauvar1, tauvar2 }; - b3->append(instFactory.makePhi(tauvar4, 2, phiOpnds)); - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makePhi(tauvar4, 2, phiOpnds)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } } else { // not SSA @@ -570,20 +568,20 @@ CodeLowerer::caseTauCheckCast(TypeInst* VarOpnd *tauvar4 = tauHasTypeVar; // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3b - b3b->append(instFactory.makeTauEdge(tau3)); - b3b->append(instFactory.makeStVar(tauvar2, tau3)); + b3b->appendInst(instFactory.makeTauEdge(tau3)); + b3b->appendInst(instFactory.makeStVar(tauvar2, tau3)); if (b3c) { // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar4, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar4, tau4)); } // b3 - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } fg.addEdge(b3a, b3); @@ -629,11 +627,11 @@ CodeLowerer::caseTauCheckCast(TypeInst* return 0; } - CFGNode* b1 = block; - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); - CFGNode* b3a = fg.createBlockNode(); - CFGNode* b3c = fg.createBlockNode(); + Node* b1 = block; + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3a = fg.createBlockNode(instFactory.makeLabel()); + Node* b3c = fg.createBlockNode(instFactory.makeLabel()); // remove test at the end of block inst->unlink(); @@ -649,9 +647,9 @@ CodeLowerer::caseTauCheckCast(TypeInst* Opnd* vt1 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(srcType)); Opnd* vt2 = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); Inst* nextInst = instFactory.makeTauLdVTableAddr(vt1, src, tauNullChecked); - b1->append(nextInst); - b1->append(instFactory.makeGetVTableAddr(vt2, castType)); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, b3c->getLabel())); + b1->appendInst(nextInst); + b1->appendInst(instFactory.makeGetVTableAddr(vt2, castType)); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, vt1, vt2, (LabelInst*)b3c->getFirstInst())); fg.addEdge(b1, b3c); fg.addEdge(b1, b2); @@ -662,7 +660,7 @@ CodeLowerer::caseTauCheckCast(TypeInst* // reuse inst inst->setDst(tauCheckedCast); inst->setSrc(1, tauNullChecked); - b2->append(inst); + b2->appendInst(inst); fg.addEdge(b2, b3a); fg.addEdge(b2, fail); @@ -678,16 +676,16 @@ CodeLowerer::caseTauCheckCast(TypeInst* SsaVarOpnd *tauvar4 = opndManager.createSsaVarOpnd(tauHasTypeVar); // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar3, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar3, tau4)); // b3 Opnd* phiOpnds[2] = { tauvar1, tauvar3 }; - b3->append(instFactory.makePhi(tauvar4, 2, phiOpnds)); - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makePhi(tauvar4, 2, phiOpnds)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } else { // not SSA @@ -696,14 +694,14 @@ CodeLowerer::caseTauCheckCast(TypeInst* VarOpnd *tauvar4 = tauHasTypeVar; // b3a - b3a->append(instFactory.makeStVar(tauvar1, tauCheckedCast)); + b3a->appendInst(instFactory.makeStVar(tauvar1, tauCheckedCast)); // b3c - b3c->append(instFactory.makeTauEdge(tau4)); - b3c->append(instFactory.makeStVar(tauvar4, tau4)); + b3c->appendInst(instFactory.makeTauEdge(tau4)); + b3c->appendInst(instFactory.makeStVar(tauvar4, tau4)); // b3 - b3->append(instFactory.makeLdVar(tau2, tauvar4)); + b3->appendInst(instFactory.makeLdVar(tau2, tauvar4)); } fg.addEdge(b3a, b3); @@ -716,9 +714,9 @@ CodeLowerer::caseTauCheckCast(TypeInst* Inst* CodeLowerer::caseTauAsType(TypeInst* inst) { - FlowGraph& fg = _irm.getFlowGraph(); - CFGNode* block = inst->getNode(); - CFGNode* succ = fg.splitNodeAtInstruction(inst); + ControlFlowGraph& fg = _irm.getFlowGraph(); + Node* block = inst->getNode(); + Node* succ = fg.splitNodeAtInstruction(inst, true, false, _irm.getInstFactory().makeLabel()); // Replace: // block: @@ -763,28 +761,28 @@ CodeLowerer::caseTauAsType(TypeInst* ins Opnd* dst = inst->getDst(); Type* castType = inst->getTypeInfo(); - CFGNode* b1 = fg.createBlockNode(); - CFGNode* b2 = fg.createBlockNode(); + Node* b1 = fg.createBlockNode(instFactory.makeLabel()); + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); VarOpnd* var = opndManager.createVarOpnd(castType, false); if (tauNullChecked->getInst()->getOpcode() == Op_TauUnsafe) { - CFGNode* b0 = fg.createBlockNode(); + Node* b0 = fg.createBlockNode(instFactory.makeLabel()); // Block - block->append(instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, b2->getLabel())); + block->appendInst(instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, (LabelInst*)b2->getFirstInst())); fg.addEdge(block, b0); fg.addEdge(block, b2); // b0 tauNullChecked = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b0->append(instFactory.makeTauEdge(tauNullChecked)); + b0->appendInst(instFactory.makeTauEdge(tauNullChecked)); block = b0; } SsaTmpOpnd* t1 = opndManager.createSsaTmpOpnd(typeManager.getBooleanType()); Inst *instanceOf = instFactory.makeTauInstanceOf(t1, src, tauNullChecked, castType); - block->append(instanceOf); - block->append(instFactory.makeBranch(Cmp_Zero, t1->getType()->tag, t1, b2->getLabel())); + block->appendInst(instanceOf); + block->appendInst(instFactory.makeBranch(Cmp_Zero, t1->getType()->tag, t1, (LabelInst*)b2->getFirstInst())); fg.addEdge(block, b2); fg.addEdge(block, b1); @@ -793,39 +791,39 @@ CodeLowerer::caseTauAsType(TypeInst* ins SsaTmpOpnd* t2 = opndManager.createSsaTmpOpnd(castType); SsaTmpOpnd* tau1 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); SsaVarOpnd *var1 = opndManager.createSsaVarOpnd(var); - b1->append(instFactory.makeTauEdge(tau1)); - b1->append(instFactory.makeTauStaticCast(t2, src, tau1, castType)); - b1->append(instFactory.makeStVar(var1, t2)); + b1->appendInst(instFactory.makeTauEdge(tau1)); + b1->appendInst(instFactory.makeTauStaticCast(t2, src, tau1, castType)); + b1->appendInst(instFactory.makeStVar(var1, t2)); // B2 SsaTmpOpnd* t3 = opndManager.createSsaTmpOpnd(castType); SsaVarOpnd *var2 = opndManager.createSsaVarOpnd(var); - b2->append(instFactory.makeLdNull(t3)); - b2->append(instFactory.makeStVar(var2, t3)); + b2->appendInst(instFactory.makeLdNull(t3)); + b2->appendInst(instFactory.makeStVar(var2, t3)); // succ SsaVarOpnd *var3 = opndManager.createSsaVarOpnd(var); Opnd* phiOpnds[2] = { var1, var2 }; Inst* phiInst = instFactory.makePhi(var3, 2, phiOpnds); Inst* ldVar = instFactory.makeLdVar(dst, var); - succ->prependAfterCriticalInst(ldVar); - succ->prepend(phiInst); + succ->prependInst(ldVar); + succ->prependInst(phiInst); } else { // B1 SsaTmpOpnd* t2 = opndManager.createSsaTmpOpnd(castType); SsaTmpOpnd* tau1 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1->append(instFactory.makeTauEdge(tau1)); - b1->append(instFactory.makeTauStaticCast(t2, src, tau1, castType)); - b1->append(instFactory.makeStVar(var, t2)); + b1->appendInst(instFactory.makeTauEdge(tau1)); + b1->appendInst(instFactory.makeTauStaticCast(t2, src, tau1, castType)); + b1->appendInst(instFactory.makeStVar(var, t2)); // B2 SsaTmpOpnd* t3 = opndManager.createSsaTmpOpnd(castType); - b2->append(instFactory.makeLdNull(t3)); - b2->append(instFactory.makeStVar(var, t3)); + b2->appendInst(instFactory.makeLdNull(t3)); + b2->appendInst(instFactory.makeStVar(var, t3)); // succ Inst* ldVar = instFactory.makeLdVar(dst, var); - succ->prepend(ldVar); + succ->prependInst(ldVar); } fg.addEdge(b1, succ); @@ -838,7 +836,7 @@ CodeLowerer::caseTauAsType(TypeInst* ins Inst* CodeLowerer::caseTauInstanceOf(TypeInst* inst) { - CFGNode* block = inst->getNode(); + Node* block = inst->getNode(); // // Perform null and vtable checks to avoid an expensive vm call. // The vtable check often succeeds in practice. @@ -862,7 +860,7 @@ CodeLowerer::caseTauInstanceOf(TypeInst* assert(tauCheckedNull->getType()->tag == Type::Tau); Opnd* dst = inst->getDst(); - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); InstFactory& instFactory = _irm.getInstFactory(); OpndManager& opndManager = _irm.getOpndManager(); TypeManager& typeManager = _irm.getTypeManager(); @@ -878,10 +876,9 @@ CodeLowerer::caseTauInstanceOf(TypeInst* // Ensure that dst is only used within a following branch. If so, // dst can be folded. Else, give up. // - Inst* label = block->getFirstInst(); Inst* i; - for(i = inst->next(); i != label; i = i->next()) { - if(i->getNumSrcOperands() > 0) + for(i = (Inst*)block->getFirstInst(); i != NULL; i = i->getNextInst()) { + if (i->getNumSrcOperands() > 0) break; } @@ -926,14 +923,14 @@ CodeLowerer::caseTauInstanceOf(TypeInst* } if(src0 == dst) { - CFGNode* taken = (CFGNode*) block->getTrueEdge()->getTargetNode(); - CFGNode* nottaken = (CFGNode*) block->getFalseEdge()->getTargetNode(); + Node* taken = block->getTrueEdge()->getTargetNode(); + Node* nottaken = block->getFalseEdge()->getTargetNode(); // // Determine the targets when instanceOf is true (succ) and false (fail). // - CFGNode* succ = eq ? nottaken : taken; - CFGNode* fail = eq ? taken : nottaken; + Node* succ = eq ? nottaken : taken; + Node* fail = eq ? taken : nottaken; // Lower when we can fold into the following branch and eliminate dst. // @@ -976,19 +973,19 @@ CodeLowerer::caseTauInstanceOf(TypeInst* branch->unlink(); fg.removeEdge(block, succ); - CFGNode* b1 = 0; - CFGNode* b2 = fg.createBlockNode(); + Node* b1 = 0; + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); Opnd *tau1 = 0; if (tauCheckedNull->getInst()->getOpcode() == Op_TauUnsafe) { - b1 = fg.createBlockNode(); + b1 = fg.createBlockNode(instFactory.makeLabel()); // block: ... if src == NULL - Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, fail->getLabel()); - block->append(test1); + Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, (LabelInst*)fail->getFirstInst()); + block->appendInst(test1); fg.addEdge(block, b1); tau1 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1->append(instFactory.makeTauEdge(tau1)); + b1->appendInst(instFactory.makeTauEdge(tau1)); inst->setSrc(1, tau1); } else { // remove the other edge; we add new ones @@ -1003,15 +1000,15 @@ CodeLowerer::caseTauInstanceOf(TypeInst* ObjectType* srcType = (ObjectType*) src->getType(); Opnd* dynamicVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(srcType)); Opnd* staticVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); - b1->append(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, src, tau1)); - b1->append(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, succ->getLabel())); + b1->appendInst(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, src, tau1)); + b1->appendInst(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, (LabelInst*)succ->getFirstInst())); fg.addEdge(b1, succ); fg.addEdge(b1, b2); // b2: var = src instanceOf type - b2->append(inst); - b2->append(branch); + b2->appendInst(inst); + b2->appendInst(branch); fg.addEdge(b2, succ); fg.addEdge(b2, fail); @@ -1023,7 +1020,7 @@ CodeLowerer::caseTauInstanceOf(TypeInst* // otherwise, just lower instanceOf, although we don't have a branch // to fold it into. { - CFGNode* succ = fg.splitNodeAtInstruction(inst); + Node* succ = fg.splitNodeAtInstruction(inst, true, false, instFactory.makeLabel()); fg.removeEdge(block, succ); inst->unlink(); @@ -1053,8 +1050,8 @@ CodeLowerer::caseTauInstanceOf(TypeInst* // v1.3 = phi(v1.1, v1.2) // dst = ldvar v1.3 - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); // block: if src.vtable == type.vtable assert(src->getType()->isObject()); @@ -1063,21 +1060,21 @@ CodeLowerer::caseTauInstanceOf(TypeInst* Opnd* staticVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); Inst * ldVTableAddrInst = instFactory.makeTauLdVTableAddr(dynamicVTableAddr, src, tauCheckedNull); - block->append(ldVTableAddrInst); - block->append(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); - block->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, b3->getLabel())); + block->appendInst(ldVTableAddrInst); + block->appendInst(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); + block->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, (LabelInst*)b3->getFirstInst())); fg.addEdge(block, b3); fg.addEdge(block, b2); // b2: newDst = instanceOf src, tauCheckedNull, type Opnd* newDst = opndManager.createSsaTmpOpnd(dst->getType()); inst->setDst(newDst); - b2->append(inst); + b2->appendInst(inst); fg.addEdge(b2, succ); // b3: var = 1 Opnd* one = opndManager.createSsaTmpOpnd(dst->getType()); - b3->append(instFactory.makeLdConst(one, (int32) 1)); + b3->appendInst(instFactory.makeLdConst(one, (int32) 1)); fg.addEdge(b3, succ); VarOpnd* dstVar = opndManager.createVarOpnd(dst->getType(), false); @@ -1090,25 +1087,25 @@ CodeLowerer::caseTauInstanceOf(TypeInst* Opnd* dstSsaVars[3] = { var1, var2 }; // Patch b2 - b2->append(instFactory.makeStVar(var1, newDst)); + b2->appendInst(instFactory.makeStVar(var1, newDst)); // Patch b3 - b3->append(instFactory.makeStVar(var2, one)); + b3->appendInst(instFactory.makeStVar(var2, one)); // succ: dst = var ... - succ->prependAfterCriticalInst(instFactory.makeLdVar(dst, phiSsaVar)); - succ->prepend(instFactory.makePhi(phiSsaVar, 2, dstSsaVars)); + succ->prependInst(instFactory.makeLdVar(dst, phiSsaVar)); + succ->prependInst(instFactory.makePhi(phiSsaVar, 2, dstSsaVars)); } else { // no SSA // Patch b2 - b2->append(instFactory.makeStVar(dstVar, newDst)); + b2->appendInst(instFactory.makeStVar(dstVar, newDst)); // Patch b3 - b3->append(instFactory.makeStVar(dstVar, one)); + b3->appendInst(instFactory.makeStVar(dstVar, one)); // succ: dst = var ... - succ->prependAfterCriticalInst(instFactory.makeLdVar(dst, dstVar)); + succ->prependInst(instFactory.makeLdVar(dst, dstVar)); } lowerBlock(succ); @@ -1148,14 +1145,14 @@ CodeLowerer::caseTauInstanceOf(TypeInst* // dst = ldvar v1.4 // ... - CFGNode* b1 = fg.createBlockNode(); - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); - CFGNode* b4 = fg.createBlockNode(); + Node* b1 = fg.createBlockNode(instFactory.makeLabel()); + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); + Node* b4 = fg.createBlockNode(instFactory.makeLabel()); // block: ... if src == NULL - Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, b4->getLabel()); - block->append(test1); + Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, (LabelInst*)b4->getFirstInst()); + block->appendInst(test1); fg.addEdge(block, b4); fg.addEdge(block, b1); @@ -1165,27 +1162,27 @@ CodeLowerer::caseTauInstanceOf(TypeInst* Opnd* dynamicVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(srcType)); Opnd* staticVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(castType)); Opnd* tauNonNull = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1->append(instFactory.makeTauEdge(tauNonNull)); - b1->append(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, src, tauNonNull)); - b1->append(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, b3->getLabel())); + b1->appendInst(instFactory.makeTauEdge(tauNonNull)); + b1->appendInst(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, src, tauNonNull)); + b1->appendInst(instFactory.makeGetVTableAddr(staticVTableAddr, castType)); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, (LabelInst*)b3->getFirstInst())); fg.addEdge(b1, b3); fg.addEdge(b1, b2); // b2: var = src instanceOf type Opnd* newDst = opndManager.createSsaTmpOpnd(dst->getType()); inst->setDst(newDst); - b2->append(inst); + b2->appendInst(inst); fg.addEdge(b2, succ); // b3: var = 1 Opnd* one = opndManager.createSsaTmpOpnd(dst->getType()); - b3->append(instFactory.makeLdConst(one, (int32) 1)); + b3->appendInst(instFactory.makeLdConst(one, (int32) 1)); fg.addEdge(b3, succ); // b4: var = 0 Opnd* zero = opndManager.createSsaTmpOpnd(dst->getType()); - b4->append(instFactory.makeLdConst(zero, (int32) 0)); + b4->appendInst(instFactory.makeLdConst(zero, (int32) 0)); fg.addEdge(b4, succ); VarOpnd* dstVar = opndManager.createVarOpnd(dst->getType(), false); @@ -1199,31 +1196,31 @@ CodeLowerer::caseTauInstanceOf(TypeInst* Opnd* dstSsaVars[3] = { var1, var2, var3 }; // Patch b2 - b2->append(instFactory.makeStVar(var1, newDst)); + b2->appendInst(instFactory.makeStVar(var1, newDst)); // Patch b3 - b3->append(instFactory.makeStVar(var2, one)); + b3->appendInst(instFactory.makeStVar(var2, one)); // Patch b4 - b4->append(instFactory.makeStVar(var3, zero)); + b4->appendInst(instFactory.makeStVar(var3, zero)); // succ: dst = var ... - succ->prependAfterCriticalInst(instFactory.makeLdVar(dst, var4)); - succ->prepend(instFactory.makePhi(var4, 3, dstSsaVars)); + succ->prependInst(instFactory.makeLdVar(dst, var4)); + succ->prependInst(instFactory.makePhi(var4, 3, dstSsaVars)); } else { // no SSA // Patch b2 - b2->append(instFactory.makeStVar(dstVar, newDst)); + b2->appendInst(instFactory.makeStVar(dstVar, newDst)); // Patch b3 - b3->append(instFactory.makeStVar(dstVar, one)); + b3->appendInst(instFactory.makeStVar(dstVar, one)); // Patch b4 - b4->append(instFactory.makeStVar(dstVar, zero)); + b4->appendInst(instFactory.makeStVar(dstVar, zero)); // succ: dst = var ... - succ->prependAfterCriticalInst(instFactory.makeLdVar(dst, dstVar)); + succ->prependInst(instFactory.makeLdVar(dst, dstVar)); } lowerBlock(succ); @@ -1235,7 +1232,7 @@ CodeLowerer::caseTauInstanceOf(TypeInst* Inst* CodeLowerer::caseTauCheckElemType(Inst* inst) { - CFGNode* block = inst->getNode(); + Node* block = inst->getNode(); // // Perform null and vtable checks to avoid an expensive vm call. // The vtable check often succeeds in practice. @@ -1260,8 +1257,8 @@ CodeLowerer::caseTauCheckElemType(Inst* // // Target is _succ_ if check succeeds and _fail_ if cast fails. // - CFGNode* succ = (CFGNode*) block->getUnconditionalEdge()->getTargetNode(); - CFGNode* fail = (CFGNode*) block->getExceptionEdge()->getTargetNode(); + Node* succ = block->getUnconditionalEdge()->getTargetNode(); + Node* fail = block->getExceptionEdge()->getTargetNode(); assert(succ->isBlockNode() && fail->isDispatchNode()); if (tauCheckedNull->getInst()->getOpcode() == Op_TauUnsafe) { @@ -1273,7 +1270,7 @@ CodeLowerer::caseTauCheckElemType(Inst* return 0; } - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Reducing checkelemtype: "; inst->print(Log::out()); Log::out() << "block has id " << (int) block->getId() << ::std::endl; @@ -1319,17 +1316,17 @@ CodeLowerer::caseTauCheckElemType(Inst* // tauResult = ldvar tauvar // succ: - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); InstFactory& instFactory = _irm.getInstFactory(); OpndManager& opndManager = _irm.getOpndManager(); TypeManager& typeManager = _irm.getTypeManager(); - CFGNode* b1 = 0; - CFGNode* b1a = 0; - CFGNode* b2 = fg.createBlockNode(); - CFGNode* b2a = fg.createBlockNode(); - CFGNode* b3 = fg.createBlockNode(); - CFGNode* b0 = fg.createBlockNode(); + Node* b1 = 0; + Node* b1a = 0; + Node* b2 = fg.createBlockNode(instFactory.makeLabel()); + Node* b2a = fg.createBlockNode(instFactory.makeLabel()); + Node* b3 = fg.createBlockNode(instFactory.makeLabel()); + Node* b0 = fg.createBlockNode(instFactory.makeLabel()); fg.removeEdge(block, fail); fg.removeEdge(block, succ); @@ -1349,8 +1346,8 @@ CodeLowerer::caseTauCheckElemType(Inst* inst->unlink(); Inst* test1 = instFactory.makeBranch(Cmp_Zero, src->getType()->tag, src, - b3->getLabel()); - block->append(test1); + (LabelInst*)b3->getFirstInst()); + block->appendInst(test1); assert(array->getType()->isObject()); ObjectType* arrayType = (ObjectType*) array->getType(); @@ -1358,15 +1355,15 @@ CodeLowerer::caseTauCheckElemType(Inst* ObjectType* arrayOfObjectType = typeManager.getArrayType(systemObjectType); if(arrayType == arrayOfObjectType) { // Check if it's an exact match at runtime. If so, we can avoid the more expensive elemType check. - b1 = fg.createBlockNode(); - b1a = fg.createBlockNode(); + b1 = fg.createBlockNode(instFactory.makeLabel()); + b1a = fg.createBlockNode(instFactory.makeLabel()); opndManager.createSsaTmpOpnd(typeManager.getTauType()); Opnd* dynamicVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(arrayType)); Opnd* staticVTableAddr = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(arrayOfObjectType)); - b1->append(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, array, tauCheckedNull)); - b1->append(instFactory.makeGetVTableAddr(staticVTableAddr, arrayOfObjectType)); - b1->append(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, b1a->getLabel())); + b1->appendInst(instFactory.makeTauLdVTableAddr(dynamicVTableAddr, array, tauCheckedNull)); + b1->appendInst(instFactory.makeGetVTableAddr(staticVTableAddr, arrayOfObjectType)); + b1->appendInst(instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, (LabelInst*)b1a->getFirstInst())); fg.addEdge(block, b1); fg.addEdge(b1, b1a); @@ -1383,7 +1380,7 @@ CodeLowerer::caseTauCheckElemType(Inst* // Opnd *tau2 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); inst->setDst(tau2); - b2->append(inst); + b2->appendInst(inst); VarOpnd* tauHasTypeVar = opndManager.createVarOpnd(typeManager.getTauType(), false); @@ -1393,51 +1390,51 @@ CodeLowerer::caseTauCheckElemType(Inst* SsaVarOpnd *tauvar3 = opndManager.createSsaVarOpnd(tauHasTypeVar); // b2a - b2a->append(instFactory.makeStVar(tauvar2, tau2)); + b2a->appendInst(instFactory.makeStVar(tauvar2, tau2)); // b3 Opnd *tau3 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b3->append(instFactory.makeTauEdge(tau3)); - b3->append(instFactory.makeStVar(tauvar3, tau3)); + b3->appendInst(instFactory.makeTauEdge(tau3)); + b3->appendInst(instFactory.makeStVar(tauvar3, tau3)); if (b1a) { // b1a SsaVarOpnd *tauvar1 = opndManager.createSsaVarOpnd(tauHasTypeVar); Opnd *tau1 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1a->append(instFactory.makeTauEdge(tau1)); - b1a->append(instFactory.makeStVar(tauvar1, tau1)); + b1a->appendInst(instFactory.makeTauEdge(tau1)); + b1a->appendInst(instFactory.makeStVar(tauvar1, tau1)); // b0 Opnd* phiOpnds[3] = { tauvar1, tauvar2, tauvar3 }; - b0->prependAfterCriticalInst(instFactory.makeLdVar(tauResult, tauvar0)); - b0->prepend(instFactory.makePhi(tauvar0, 3, phiOpnds)); + b0->prependInst(instFactory.makeLdVar(tauResult, tauvar0)); + b0->prependInst(instFactory.makePhi(tauvar0, 3, phiOpnds)); } else { // b0 Opnd* phiOpnds[2] = { tauvar2, tauvar3 }; - b0->prependAfterCriticalInst(instFactory.makeLdVar(tauResult, tauvar0)); - b0->prepend(instFactory.makePhi(tauvar0, 2, phiOpnds)); + b0->prependInst(instFactory.makeLdVar(tauResult, tauvar0)); + b0->prependInst(instFactory.makePhi(tauvar0, 2, phiOpnds)); } } else { // b2a - b2a->append(instFactory.makeStVar(tauHasTypeVar, tau2)); + b2a->appendInst(instFactory.makeStVar(tauHasTypeVar, tau2)); // b3 Opnd *tau3 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b3->append(instFactory.makeTauEdge(tau3)); - b3->append(instFactory.makeStVar(tauHasTypeVar, tau3)); + b3->appendInst(instFactory.makeTauEdge(tau3)); + b3->appendInst(instFactory.makeStVar(tauHasTypeVar, tau3)); if (b1a) { // b1a Opnd *tau1 = opndManager.createSsaTmpOpnd(typeManager.getTauType()); - b1a->append(instFactory.makeTauEdge(tau1)); - b1a->append(instFactory.makeStVar(tauHasTypeVar, tau1)); + b1a->appendInst(instFactory.makeTauEdge(tau1)); + b1a->appendInst(instFactory.makeStVar(tauHasTypeVar, tau1)); } // b0 - b0->prependAfterCriticalInst(instFactory.makeLdVar(tauResult, tauHasTypeVar)); + b0->prependInst(instFactory.makeLdVar(tauResult, tauHasTypeVar)); } - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Reducing checkelemtype: "; inst->print(Log::out()); if (b1) { @@ -1484,7 +1481,7 @@ CodeLowerer::caseLdStaticAddr(FieldAcces Inst* CodeLowerer::caseLdFieldAddr(FieldAccessInst *inst) { - OptimizerFlags& optimizerFlags = *_irm.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = _irm.getOptimizerFlags(); if (optimizerFlags.reduce_compref) { // reduce this to addoffset(base, ldfieldoffset) @@ -1514,7 +1511,7 @@ #endif Inst* CodeLowerer::caseLdElemAddr(TypeInst *inst) { - OptimizerFlags& optimizerFlags = *_irm.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = _irm.getOptimizerFlags(); if (optimizerFlags.reduce_compref) { // reduce this to addoffset(base, ldelemoffset) TypeInst *tinst = inst->asTypeInst(); @@ -1550,7 +1547,7 @@ CodeLowerer::caseLdElemAddr(TypeInst *in Inst* CodeLowerer::caseLdArrayBaseAddr(Inst *inst) { - OptimizerFlags& optimizerFlags = *_irm.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = _irm.getOptimizerFlags(); if (optimizerFlags.reduce_compref) { // reduce this to addoffset(base, ldelemoffset) TypeInst *tinst = inst->asTypeInst(); @@ -1582,7 +1579,7 @@ CodeLowerer::caseLdArrayBaseAddr(Inst *i Inst* CodeLowerer::caseTauArrayLen(Inst *inst) { - OptimizerFlags& optimizerFlags = *_irm.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = _irm.getOptimizerFlags(); if (optimizerFlags.reduce_compref) { // reduce this to addoffset(base, ldelemoffset) @@ -1629,7 +1626,7 @@ CodeLowerer::caseTauLdInd(Inst *inst) } Inst* -CodeLowerer::caseLdString(TokenInst *inst) +CodeLowerer::caseLdRef(TokenInst *inst) { // handled in simplifier for now. return inst; diff --git vm/jitrino/src/optimizer/codelowerer.h vm/jitrino/src/optimizer/codelowerer.h index 52a916f..2aa6e6f 100644 --- vm/jitrino/src/optimizer/codelowerer.h +++ vm/jitrino/src/optimizer/codelowerer.h @@ -29,11 +29,10 @@ #include "optpass.h" namespace Jitrino { class IRManager; class FlowGraph; -class CFGNode; +class Node; class Inst; class TypeInst; -DEFINE_OPTPASS(CodeLoweringPass) class CodeLowerer : public InstOptimizer { public: @@ -42,7 +41,7 @@ public: void doLower(); private: - void lowerBlock(CFGNode *node); + void lowerBlock(Node *node); Inst* caseDefault(Inst* inst) {return inst;} @@ -64,7 +63,7 @@ private: Inst* caseTauArrayLen(Inst *inst); Inst* caseTauLdInd(Inst *inst); - Inst* caseLdString(TokenInst *inst); + Inst* caseLdRef(TokenInst *inst); Inst* caseLdNull(ConstInst* inst); // Numeric compute @@ -140,9 +139,7 @@ private: Inst* caseCatch(Inst* inst) {return caseDefault(inst);} - Inst* caseThrow(Inst* inst) {return caseDefault(inst);} - - Inst* caseThrowLazy(Inst* inst) {return caseDefault(inst);} + Inst* caseThrow(Inst* inst) {return caseDefault(inst);} Inst* caseThrowSystemException(Inst* inst) {return caseDefault(inst);} diff --git vm/jitrino/src/optimizer/constantfolder.cpp vm/jitrino/src/optimizer/constantfolder.cpp index 4caae38..4a03e0d 100644 --- vm/jitrino/src/optimizer/constantfolder.cpp +++ vm/jitrino/src/optimizer/constantfolder.cpp @@ -43,11 +43,11 @@ inline int isFinite(double s) { } inline float _chgsign(float f) { - return copysignf(f, signbit(f) ? (float)1.0 : (float)-1.0 ); + return copysignf(f, signbit(f) ? (float)1.0 : (float)-1.0 ); } inline double _chgsign(double d) { - return copysign(d, signbit(d) ? 1.0 : -1.0 ); + return copysign(d, signbit(d) ? 1.0 : -1.0 ); } // isnan(double s) is declared in float.h @@ -189,7 +189,7 @@ ConstantFolder::isConstantZero(Opnd* opn case Type::Object: return value.i == 0; default: - return false; + return false; } } @@ -205,7 +205,7 @@ ConstantFolder::isConstantOne(Opnd* opnd case Type::Int64: return value.i8 == 1; default: - return false; + return false; } } @@ -221,7 +221,7 @@ ConstantFolder::isConstantAllOnes(Opnd* case Type::Int64: return value.i8 == (int64) -1; default: - return false; + return false; } } @@ -298,7 +298,7 @@ ConstantFolder::fold8(Opcode opc, int8 c case Op_Max: result = ::std::max(c1,c2); return true; default: - return true; + return true; } } bool @@ -339,7 +339,7 @@ ConstantFolder::fold16(Opcode opc, int16 case Op_Max: result = ::std::max(c1,c2); return true; default: - return true; + return true; } } @@ -363,10 +363,10 @@ ConstantFolder::fold32(Opcode opc, int32 case Op_TauDiv: if (c2 == (int32)0) return false; if (is_signed) { - if ((c1 == (int32)0x80000000) && (c2 == -1)) { - result = c1; - return true; - } + if ((c1 == (int32)0x80000000) && (c2 == -1)) { + result = c1; + return true; + } result = c1 / c2; return true; } else { @@ -375,10 +375,10 @@ ConstantFolder::fold32(Opcode opc, int32 case Op_TauRem: if (c2 == (int32)0) return false; if (is_signed) { - if ((c1 == (int32)0x80000000) && (c2 == -1)) { - result = 0; - return true; - } + if ((c1 == (int32)0x80000000) && (c2 == -1)) { + result = 0; + return true; + } result = c1 % c2; return true; } else { @@ -419,6 +419,11 @@ ConstantFolder::fold64(Opcode opc, int64 // for div and rem, be careful c2 not be 0 case Op_TauDiv: if (c2 == (int64)0) return false; + // LONG.MIN_VALUE / -1 == LONG.MIN_VALUE + if ((c2 == (int64)-1) && (c1 == ((int64)1<<63))) { + result = c1; + return true; + } if (is_signed) { result = c1 / c2; } else { @@ -427,6 +432,11 @@ ConstantFolder::fold64(Opcode opc, int64 return true; case Op_TauRem: if (c2 == (int64)0) return false; + // LONG.MIN_VALUE % -1 == 0 + if ((c2 == (int64)-1) && (c1 == ((int64)1<<63))) { + result = 0; + return true; + } if (is_signed) { result = c1 % c2; } else { @@ -531,8 +541,8 @@ ConstantFolder::fold64(Opcode opc, int64 bool ConstantFolder::foldSingle(Opcode opc, float c, float& result) { if( Op_Neg == opc) { - result = (float)_chgsign(c); - return true; + result = (float)_chgsign(c); + return true; } return false; } @@ -540,8 +550,8 @@ ConstantFolder::foldSingle(Opcode opc, f bool ConstantFolder::foldDouble(Opcode opc, double c, double& result) { if( Op_Neg == opc) { - result = _chgsign(c); - return true; + result = _chgsign(c); + return true; } return false; } @@ -553,7 +563,7 @@ bool ConstantFolder::foldConv(Type::Tag bool ovfm = (mod.getOverflowModifier()!=Overflow_None); switch (toType) { case Type::Int32: - switch (fromType) { + switch (fromType) { case Type::Int32: res.i4 = src.i4; return true; case Type::UInt32: @@ -896,7 +906,7 @@ ConstantFolder::foldConstant(Type::Tag t case Type::UInt64: return fold64(opc, val1.i8, val2.i8, result.i8, is_signed); case Type::IntPtr: case Type::UIntPtr: { - int psi = sizeof(POINTER_SIZE_INT); + int psi = sizeof(POINTER_SIZE_INT); switch (psi) { case 1: return fold8(opc, (int8)val1.i4, (int8)val2.i4, result.i4, is_signed); case 2: return fold16(opc, (int16)val1.i4, (int16)val2.i4, result.i4, is_signed); diff --git vm/jitrino/src/optimizer/dataflow.h vm/jitrino/src/optimizer/dataflow.h index 6d208df..df762c6 100644 --- vm/jitrino/src/optimizer/dataflow.h +++ vm/jitrino/src/optimizer/dataflow.h @@ -27,7 +27,6 @@ #include "MemoryManager.h" #include "BitSet.h" #include "Log.h" #include "Stl.h" -#include "FlowGraph.h" namespace Jitrino { @@ -48,17 +47,17 @@ class DataflowInstance { public: virtual ~DataflowInstance() {} typedef DataflowValue ValueType; - virtual DataflowTF<DataflowValue> *getNodeBehavior(CFGNode *node) = 0; + virtual DataflowTF<DataflowValue> *getNodeBehavior(Node *node) = 0; virtual DataflowValue getEntryValue() = 0; }; template <typename DataflowValue> void -solve(FlowGraph *fg, DataflowInstance<DataflowValue> &instance, bool forwards, +solve(ControlFlowGraph*fg, DataflowInstance<DataflowValue> &instance, bool forwards, MemoryManager &mm, DataflowValue *&solutionBeforeNode, DataflowValue *&solutionAfterNode, - Category *logCategory, bool ignoreExceptionEdges) + bool ignoreExceptionEdges) { - StlVector<CFGNode *> nodes(mm); + StlVector<Node *> nodes(mm); fg->getNodesPostOrder(nodes, forwards); uint32 numNodes = fg->getMaxNodeId(); DataflowValue *beforeNode = new (mm) DataflowValue[numNodes]; @@ -70,38 +69,38 @@ solve(FlowGraph *fg, DataflowInstance<Da solutionBeforeNode = beforeNode; solutionAfterNode = afterNode; - StlDeque<CFGNode *> queue(mm); + StlDeque<Node *> queue(mm); BitSet inQueue(mm, numNodes); DataflowTF<DataflowValue> **nodeTFs= new (mm) DataflowTF<DataflowValue>*[numNodes]; // compute TFs and initialize queue - StlVector<CFGNode *>::reverse_iterator + StlVector<Node *>::reverse_iterator riter = nodes.rbegin(), rend = nodes.rend(); for ( ; riter != rend; ++riter) { - CFGNode *node = *riter; + Node *node = *riter; uint32 nodeId = node->getId(); nodeTFs[nodeId] = instance.getNodeBehavior(node); queue.push_back(node); inQueue.setBit(nodeId); } - CFGNode *entryNode = fg->getEntry(); - CFGNode *exitNode = fg->getExit(); + Node *entryNode = fg->getEntryNode(); + Node *exitNode = fg->getExitNode(); uint32 inId = forwards ? entryNode->getId() : exitNode->getId(); - uint32 firstId = queue[0]->getId(); + uint32 firstId = queue[0]->getId(); if( !(firstId == inId) ) assert(0); beforeNode[firstId] = instance.getEntryValue(); while (!queue.empty()) { - CFGNode *node = queue.front(); + Node *node = queue.front(); queue.pop_front(); inQueue.setBit(false); uint32 nodeId = node->getId(); DataflowTF<DataflowValue> *nodeTF = nodeTFs[nodeId]; - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "solve: visiting node " << (int) nodeId << ::std::endl; } - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " in was: "; beforeNode[nodeId].print(Log::out()); Log::out() << ::std::endl << " out was: "; afterNode[nodeId].print(Log::out()); @@ -109,23 +108,23 @@ solve(FlowGraph *fg, DataflowInstance<Da } if (nodeTF->apply(beforeNode[nodeId], afterNode[nodeId])) { // check whether to update successors - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " node changed" << ::std::endl; Log::out() << " in became: "; beforeNode[nodeId].print(Log::out()); Log::out() << ::std::endl << " out became: "; afterNode[nodeId].print(Log::out()); Log::out() << ::std::endl; } - const CFGEdgeDeque &outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = node->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (ignoreExceptionEdges && target->isDispatchNode()) continue; uint32 targetId = target->getId(); - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " (checking successor " << (int) targetId << ", was "; beforeNode[targetId].print(Log::out()); @@ -133,7 +132,7 @@ solve(FlowGraph *fg, DataflowInstance<Da } if (beforeNode[targetId].meetWith(afterNode[nodeId])) { // value at successor has changed - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " (changed successor " << (int) targetId << ", now "; beforeNode[targetId].print(Log::out()); @@ -141,14 +140,14 @@ solve(FlowGraph *fg, DataflowInstance<Da } if (!inQueue.getBit(targetId)) { // if so, add it to queue - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " (queuing " << (int) targetId << ")" << ::std::endl; } queue.push_back(target); inQueue.setBit(targetId); } else { - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " (already in queue: " << (int) targetId << ")" << ::std::endl; } @@ -156,7 +155,7 @@ solve(FlowGraph *fg, DataflowInstance<Da } } } else { - if (logCategory->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " no change:" << ::std::endl; } } diff --git vm/jitrino/src/optimizer/deadcodeeliminator.cpp vm/jitrino/src/optimizer/deadcodeeliminator.cpp index 6d92d77..0de66f8 100644 --- vm/jitrino/src/optimizer/deadcodeeliminator.cpp +++ vm/jitrino/src/optimizer/deadcodeeliminator.cpp @@ -21,9 +21,7 @@ */ #include "deadcodeeliminator.h" -#include "FlowGraph.h" #include "irmanager.h" -#include "PropertyTable.h" #include "Inst.h" #include "Stl.h" #include "BitSet.h" @@ -31,47 +29,48 @@ #include "MemoryManager.h" #include "Log.h" #include "constantfolder.h" #include "optimizer.h" -#include "Timer.h" +#include "XTimer.h" +#include "PMFAction.h" namespace Jitrino { // Timer.h includes windows.h, which has a broken #def of min: #undef min -DEFINE_OPTPASS_IMPL(DeadCodeEliminationPass, dce, "Dead Code Elimination") +DEFINE_SESSION_ACTION(DeadCodeEliminationPass, dce, "Dead Code Elimination") void -DeadCodeEliminationPass::_run(IRManager& irm) { +DeadCodeEliminationPass::_run(IRManager& irm){ DeadCodeEliminator dce(irm); { - static Timer* justDceTimer = NULL; - PhaseTimer t(justDceTimer, "opt::dce::justDce"); dce.eliminateDeadCode(false); } } -DEFINE_OPTPASS_IMPL(UnreachableCodeEliminationPass, uce, "Unreachable Code Elimination") +DEFINE_SESSION_ACTION(UnreachableCodeEliminationPass, uce, "Unreachable Code Elimination"); -void +void UnreachableCodeEliminationPass::_run(IRManager& irm) { DeadCodeEliminator dce(irm); { - static Timer* justUceTimer = NULL; - PhaseTimer t(justUceTimer, "opt::dce::justUce"); dce.eliminateUnreachableCode(); } - bool fixup_ssa = irm.getParameterTable().lookupBool("opt::fixup_ssa", true); + bool fixup_ssa = irm.getOptimizerFlags().fixup_ssa; if (irm.getInSsa() && fixup_ssa) { - static Timer* edcFixupTimer = NULL; - PhaseTimer t(edcFixupTimer, "opt::dce::edcFixup"); - fixupSsa(irm); + OptPass::fixupSsa(irm); } } -DEFINE_OPTPASS_IMPL(PurgeEmptyNodesPass, purge, "Empty Node Removal") +//Empty Node Removal +class PurgeEmptyNodesPass: public SessionAction { +public: + void run(); +}; +ActionFactory<PurgeEmptyNodesPass> _purge("purge"); void -PurgeEmptyNodesPass::_run(IRManager& irm) { +PurgeEmptyNodesPass::run() { + IRManager& irm = *getCompilationContext()->getHIRManager(); irm.getFlowGraph().purgeEmptyNodes(false); } @@ -243,16 +242,17 @@ usesBitsOfOpnd(uint8 dst_bits, Inst* ins return res1; } -DeadCodeEliminator::DeadCodeEliminator(IRManager& irm) - : irManager(irm), flowGraph(irm.getFlowGraph()), returnOpnd(irm.getReturnOpnd()) { - preserveCriticalEdges = irManager.getParameterTable().lookupBool("opt::dce::preserve_critical_edges", true); +DeadCodeEliminator::DeadCodeEliminator(IRManager& irm) +: irManager(irm), flowGraph(irm.getFlowGraph()), returnOpnd(irm.getReturnOpnd()) +{ + preserveCriticalEdges = irManager.getOptimizerFlags().preserve_critical_edges; } Opnd* DeadCodeEliminator::findDefiningTemp(Opnd* var) { SsaVarOpnd* ssaVarOpnd = var->asSsaVarOpnd(); if(ssaVarOpnd == NULL) { - Log::cat_opt_dc()->debug << "Nothing found: Not SSA" << ::std::endl; + Log::out() << "Nothing found: Not SSA" << ::std::endl; return NULL; // not an SsaVarOpnd } Inst* inst = ssaVarOpnd->getInst(); @@ -260,7 +260,7 @@ DeadCodeEliminator::findDefiningTemp(Opn if(inst->getOpcode() == Op_StVar) { // propagate src of copy recursively copyPropagate(inst); - if(Log::cat_opt_dc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Found: "; Inst* def = inst->getSrc(0)->getInst(); if(def != NULL) { @@ -296,7 +296,7 @@ DeadCodeEliminator::findDefiningTemp(Opn return tmp; } - Log::cat_opt_dc()->debug << "Nothing found: Not stVar or phi instruction" << ::std::endl; + Log::out() << "Nothing found: Not stVar or phi instruction" << ::std::endl; return NULL; } @@ -360,7 +360,7 @@ markLiveInst1(Inst* inst, uint8 dstWidth = 255; - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found dstwidth of " << (int) dstWidth << " for inst "; inst->print(Log::out()); @@ -386,7 +386,7 @@ markLiveInst1(Inst* inst, // was already marked as live, check old width. uint8 oldOpndWidth = 255; - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found dstwidth of " << (int) oldOpndWidth << " for inst "; def->print(Log::out()); @@ -394,7 +394,7 @@ markLiveInst1(Inst* inst, } if (opndWidth > oldOpndWidth) { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Setting dstwidth to " << (int) opndWidth << " for inst "; def->print(Log::out()); @@ -403,7 +403,7 @@ markLiveInst1(Inst* inst, workSet.pushFront(def); } } else { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Setting dstwidth to " << (int) opndWidth << " for inst "; def->print(Log::out()); @@ -432,7 +432,7 @@ markLiveInst1(Inst* inst, // Deletes instructions that are not marked as useful // void -DeadCodeEliminator::sweepInst1(CFGNode* node, +DeadCodeEliminator::sweepInst1(Node* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, @@ -458,14 +458,17 @@ DeadCodeEliminator::sweepInst1(CFGNode* (srcId < maxInstId) && (usefulInstSet.getBit(srcId-minInstId) == false)) { MethodMarkerInst *mmi = inst->asMethodMarkerInst(); + // Method marker could contain retOpnd + if (!mmi->getMethodDesc()->isStatic()) { mmi->removeOpnd(); } } } + } } else if ((minInstId <= instId) && (instId < maxInstId) && usefulInstSet.getBit(instId-minInstId) == false) { // inst is a useless instruction - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Useless inst found, removing: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -495,7 +498,7 @@ DeadCodeEliminator::sweepInst1(CFGNode* // // store to a useless variable // - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Removing store to useless var: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -527,7 +530,7 @@ markLiveInst(Inst* inst, assert((instId >= minInstId) && (instId < maxInstId)); uint8 dstWidth = usedInstWidth[instId-minInstId]; - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found dstwidth of " << (int) dstWidth << " for inst "; inst->print(Log::out()); @@ -553,7 +556,7 @@ markLiveInst(Inst* inst, if (!((minInstId <= defId) && (defId < maxInstId))) { // this instruction is out of the region, skip it. - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Skipping outside-region inst "; def->print(Log::out()); Log::out() << ::std::endl; @@ -562,7 +565,7 @@ markLiveInst(Inst* inst, // was already marked as live, check old width. uint8 oldOpndWidth = usedInstWidth[defId-minInstId]; - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found dstwidth of " << (int) oldOpndWidth << " for inst "; def->print(Log::out()); @@ -570,7 +573,7 @@ markLiveInst(Inst* inst, } if (opndWidth > oldOpndWidth) { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Setting dstwidth to " << (int) opndWidth << " for inst "; def->print(Log::out()); @@ -580,7 +583,7 @@ markLiveInst(Inst* inst, workSet.pushFront(def); } } else { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Setting dstwidth to " << (int) opndWidth << " for inst "; def->print(Log::out()); @@ -610,7 +613,7 @@ markLiveInst(Inst* inst, // Deletes instructions that are not marked as useful // void -DeadCodeEliminator::sweepInst(CFGNode* node, +DeadCodeEliminator::sweepInst(Node* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, @@ -637,14 +640,17 @@ DeadCodeEliminator::sweepInst(CFGNode* n if ((minInstId <= srcId) && (srcId < maxInstId) && (usefulInstSet.getBit(srcId-minInstId) == false)) { MethodMarkerInst *mmi = inst->asMethodMarkerInst(); + // Method marker could contain retOpnd which should be preserved + if (!mmi->getMethodDesc()->isStatic()) { mmi->removeOpnd(); } } } + } } else if ((minInstId <= instId) && (instId < maxInstId) && usefulInstSet.getBit(instId-minInstId) == false) { // inst is a useless instruction - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Useless inst found, removing: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -689,7 +695,7 @@ DeadCodeEliminator::sweepInst(CFGNode* n assert((minInstId <= instId) && (instId < maxInstId)); uint8 usedDstSize = usedInstWidth[instId-minInstId]; - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Found dstwidth of " << (int) usedDstSize << " for inst "; inst->print(Log::out()); @@ -699,19 +705,18 @@ DeadCodeEliminator::sweepInst(CFGNode* n if ((srcSize >= convSize) && (usedDstSize <= convSize)) { // convert to a copy. - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Eliminating redundant conv "; inst->print(Log::out()); Log::out() << ::std::endl; } InstFactory &factory = irManager.getInstFactory(); - Inst *copyInst = - factory.makeCopy(inst->getDst(), inst->getSrc(0)); + Inst *copyInst = factory.makeCopy(inst->getDst(), inst->getSrc(0)); copyInst->insertAfter(inst); inst->unlink(); // copyInst doesn't appear in bitmaps, but we won't walk // over it, so it is only tested for a MethodMarker Inst - // operand above, and we are careful there + // operand above, and we are careful there } } break; @@ -730,7 +735,7 @@ DeadCodeEliminator::sweepInst(CFGNode* n // // store to a useless variable // - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Removing store to useless var: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -749,8 +754,8 @@ DeadCodeEliminator::eliminateUnreachable MemoryManager memManager(1000,"DeadCodeEliminator::eliminateUnreachableCode"); // Purge unreachable nodes from CFG. - StlVector<CFGNode*> unreachableNodes(memManager); - flowGraph.purgeUnreachableNodes((StlVector<ControlFlowNode*>&) unreachableNodes); + Nodes unreachableNodes(memManager); + irManager.getFlowGraph().purgeUnreachableNodes(unreachableNodes); // If no unreachable nodes, return if(unreachableNodes.empty()) @@ -759,15 +764,15 @@ DeadCodeEliminator::eliminateUnreachable // Clear the set of unreachable definitions. StlHashSet<uint32> unreachableDefSet(memManager); - StlVector<CFGNode*>::iterator niter; + StlVector<Node*>::iterator niter; for(niter = unreachableNodes.begin(); niter != unreachableNodes.end(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; // Find unreachable defs. Note, only SsaVarOpnds can be used // in later reachable nodes. - Inst* headInst = node->getFirstInst(); + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { assert(inst->getNode()); SsaVarOpnd* dst = inst->getDst()->asSsaVarOpnd(); if(dst != NULL) { @@ -783,20 +788,20 @@ DeadCodeEliminator::eliminateUnreachable // Cleanup up phi instructions. - const CFGNodeDeque& nodes = flowGraph.getNodes(); - CFGNodeDeque::const_iterator niter2; + const Nodes& nodes = flowGraph.getNodes(); + Nodes::const_iterator niter2; for(niter2 = nodes.begin(); niter2 != nodes.end(); ++niter2) { - CFGNode* node = *niter2; - Inst* headInst = node->getFirstInst(); + Node* node = *niter2; + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { assert(inst->getNode()); if(inst->getOpcode() == Op_Phi) { #ifndef NDEBUG SsaVarOpnd* dst = inst->getDst()->asSsaVarOpnd(); assert(dst!=NULL); #endif - uint32 numSrc = inst->getNumSrcOperands(); + uint32 numSrc = inst->getNumSrcOperands(); uint32 numKill = 0; for(uint32 i = 0; i < numSrc; ++i) { SsaVarOpnd* src = inst->getSrc(i)->asSsaVarOpnd(); @@ -819,12 +824,12 @@ #endif return true; } -static Timer *dcePhase1Timer = 0; // not thread-safe -static Timer *dcePhase2Timer = 0; // not thread-safe -static Timer *dcePhase3Timer = 0; // not thread-safe -static Timer *dcePhase4Timer = 0; // not thread-safe -static Timer *dcePhase5Timer = 0; // not thread-safe -static Timer *dcePhase6Timer = 0; // not thread-safe +static CountTime dcePhase1Timer("opt::dce::phase1"); +static CountTime dcePhase2Timer("opt::dce::phase2"); +static CountTime dcePhase3Timer("opt::dce::phase3"); +static CountTime dcePhase4Timer("opt::dce::phase4"); +static CountTime dcePhase5Timer("opt::dce::phase5"); +static CountTime dcePhase6Timer("opt::dce::phase6"); // // Performs dead code elimination @@ -840,18 +845,18 @@ DeadCodeEliminator::eliminateDeadCode(bo MemoryManager memManager(numInsts*20, "DeadCodeEliminator::eliminateDeadCode"); InstDeque workSet(memManager); - CFGVector nodes(memManager,flowGraph.getMaxNodeId()); + Nodes nodes(memManager); flowGraph.getNodesPostOrder(nodes); - CFGVector::ReverseIterator niter; + Nodes::reverse_iterator niter; // set of useful instructions & variables; initially everything is useless BitSet usefulInstSet(memManager,numInsts+1); BitSet usefulVarSet(memManager,numOpnds+1); - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); uint8 *usedInstWidth = optimizerFlags.dce2 ? new (memManager) uint8[numInsts] : 0; { - PhaseTimer t(dcePhase1Timer, "opt::dce::phase1"); + AutoTimer t(dcePhase1Timer); // // first propagate copies and initialize the work list with @@ -859,10 +864,10 @@ DeadCodeEliminator::eliminateDeadCode(bo // if (usedInstWidth) { for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - Inst* headInst = node->getFirstInst(); + Node* node = *niter; + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { assert(inst->getNode()); // copy propagate all sources of this instruction copyPropagate(inst); @@ -878,7 +883,7 @@ DeadCodeEliminator::eliminateDeadCode(bo usefulInstSet.setBit(instId-minInstId, true); if (usedInstWidth) { uint8 usedWidth = getBitWidth(inst->getType()); - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Setting dstwidth to " << (int) usedWidth << " for inst "; inst->print(Log::out()); @@ -892,10 +897,10 @@ DeadCodeEliminator::eliminateDeadCode(bo } } else { for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - Inst* headInst = node->getFirstInst(); + Node* node = *niter; + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { assert(inst->getNode()); // copy propagate all sources of this instruction copyPropagate(inst); @@ -916,7 +921,7 @@ DeadCodeEliminator::eliminateDeadCode(bo } { - PhaseTimer t(dcePhase2Timer, "opt::dce::phase2"); + AutoTimer t(dcePhase2Timer); // // Iteratively mark all useful instructions by computing slices @@ -936,30 +941,30 @@ DeadCodeEliminator::eliminateDeadCode(bo { const bool canRemoveStVars = (irManager.getParent() == NULL); // we can remove a useless var - PhaseTimer t(dcePhase3Timer, "opt::dce::phase3"); + AutoTimer t(dcePhase3Timer); // // Now cleanup all the dead code // if (usedInstWidth) { for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - Inst* headInst = node->getFirstInst(); + Node* node = *niter; + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next(); inst != headInst; ) { + for (Inst* inst = headInst->getNextInst(); inst != NULL; ) { assert(inst->getNode()); - Inst *nextInst = inst->next(); + Inst *nextInst = inst->getNextInst(); sweepInst(node, inst,usefulInstSet,usefulVarSet,usedInstWidth,minInstId,maxInstId,canRemoveStVars); inst = nextInst; } } } else { for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - Inst* headInst = node->getFirstInst(); + Node* node = *niter; + Inst* headInst = (Inst*)node->getFirstInst(); assert(headInst->getNode()); - for (Inst* inst = headInst->next(); inst != headInst; ) { + for (Inst* inst = headInst->getNextInst(); inst != NULL; ) { assert(inst->getNode()); - Inst *nextInst = inst->next(); + Inst *nextInst = inst->getNextInst(); sweepInst1(node, inst,usefulInstSet,usefulVarSet,minInstId,maxInstId,canRemoveStVars); inst = nextInst; } @@ -970,7 +975,7 @@ DeadCodeEliminator::eliminateDeadCode(bo { const bool canUnlink = (irManager.getParent() == NULL); // we can unlink an unused var - PhaseTimer t(dcePhase4Timer, "opt::dce::phase4"); + AutoTimer t(dcePhase4Timer); // // delete dead variables // @@ -990,7 +995,7 @@ DeadCodeEliminator::eliminateDeadCode(bo varOpnd->setDeadFlag(true); // mark as dead if (canUnlink) { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "removing dead VarOpnd "; varOpnd->print(Log::out()); Log::out() << ::std::endl; @@ -1017,7 +1022,7 @@ DeadCodeEliminator::eliminateDeadCode(bo varOpnd->setDeadFlag(true); // mark as dead if (canUnlink) { - if (Log::cat_opt_dc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "removing dead VarOpnd "; varOpnd->print(Log::out()); Log::out() << ::std::endl; @@ -1032,12 +1037,11 @@ DeadCodeEliminator::eliminateDeadCode(bo } { - PhaseTimer t(dcePhase6Timer, "opt::dce::phase6"); - + AutoTimer t(dcePhase6Timer); flowGraph.mergeAdjacentNodes(); } { - PhaseTimer t(dcePhase5Timer, "opt::dce::phase5"); + AutoTimer t(dcePhase5Timer); if (!keepEmptyNodes) { // // Purge empty nodes. diff --git vm/jitrino/src/optimizer/deadcodeeliminator.h vm/jitrino/src/optimizer/deadcodeeliminator.h index 97f383e..5f8c7bd 100644 --- vm/jitrino/src/optimizer/deadcodeeliminator.h +++ vm/jitrino/src/optimizer/deadcodeeliminator.h @@ -31,16 +31,10 @@ namespace Jitrino { class IRManager; class Inst; class Opnd; -class FlowGraph; -class CFGNode; +class ControlFlowGraph; +class Node; class BitSet; -DEFINE_OPTPASS(DeadCodeEliminationPass) - -DEFINE_OPTPASS(UnreachableCodeEliminationPass) - -DEFINE_OPTPASS(PurgeEmptyNodesPass) - class DeadCodeEliminator { public: DeadCodeEliminator(IRManager& irm); @@ -49,14 +43,14 @@ public: static Opnd* copyPropagate(Opnd*); bool eliminateUnreachableCode(); // returns true if any node is eliminated private: - void sweepInst(CFGNode* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, uint8 *usedInstWidth, uint32 minInstId, uint32 maxInstId, bool canRemoveStvars); - void sweepInst1(CFGNode* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, + void sweepInst(Node* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, uint8 *usedInstWidth, uint32 minInstId, uint32 maxInstId, bool canRemoveStvars); + void sweepInst1(Node* node, Inst* inst, BitSet& usefulInstSet, BitSet& usefulVarSet, uint32 minInstId, uint32 maxInstId, bool canRemoveStvars); // if we're skipping instWidth static Opnd* findDefiningTemp(Opnd* var); IRManager& irManager; - FlowGraph& flowGraph; + ControlFlowGraph& flowGraph; Opnd* returnOpnd; bool preserveCriticalEdges; }; diff --git vm/jitrino/src/optimizer/devirtualizer.cpp vm/jitrino/src/optimizer/devirtualizer.cpp index 8eabc10..eb24a03 100644 --- vm/jitrino/src/optimizer/devirtualizer.cpp +++ vm/jitrino/src/optimizer/devirtualizer.cpp @@ -22,13 +22,12 @@ #include "devirtualizer.h" #include "Log.h" -#include "PropertyTable.h" #include "Dominator.h" #include "inliner.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(GuardedDevirtualizationPass, devirt, "Guarded Devirtualization of Virtual Calls") +DEFINE_SESSION_ACTION(GuardedDevirtualizationPass, devirt, "Guarded Devirtualization of Virtual Calls") void GuardedDevirtualizationPass::_run(IRManager& irm) { @@ -38,7 +37,7 @@ GuardedDevirtualizationPass::_run(IRMana pass.guardCallsInRegion(irm, dominatorTree); } -DEFINE_OPTPASS_IMPL(GuardRemovalPass, unguard, "Removal of Cold Guards") +DEFINE_SESSION_ACTION(GuardRemovalPass, unguard, "Removal of Cold Guards") void GuardRemovalPass::_run(IRManager& irm) { @@ -50,14 +49,12 @@ Devirtualizer::Devirtualizer(IRManager& : _hasProfileInfo(irm.getFlowGraph().hasEdgeProfile()), _typeManager(irm.getTypeManager()), _instFactory(irm.getInstFactory()), _opndManager (irm.getOpndManager()) { - JitrinoParameterTable& propertyTable = irm.getParameterTable(); - bool doProfileOnly = OptPass::inDPGOMode(irm); - _skipColdTargets = propertyTable.lookupBool("opt::devirt::skip_cold", true); - _doAggressiveGuardedDevirtualization = !doProfileOnly || propertyTable.lookupBool("opt::devirt::aggressive", true); - _doProfileOnlyGuardedDevirtualization = !_doAggressiveGuardedDevirtualization; - _devirtUseCHA = propertyTable.lookupBool("opt::devirt::useCHA", false); - _devirtSkipExceptionPath = propertyTable.lookupBool("opt::devirt::skip_exception_path", true); + const OptimizerFlags& optFlags = irm.getOptimizerFlags(); + _skipColdTargets = optFlags.devirt_skip_cold_targets; + _doAggressiveGuardedDevirtualization = !_hasProfileInfo || optFlags.devirt_do_aggressive_guarded_devirtualization; + _devirtUseCHA = optFlags.devirt_devirt_use_cha; + _devirtSkipExceptionPath = optFlags.devirt_devirt_skip_exception_path; } bool @@ -135,7 +132,7 @@ Devirtualizer::guardCallsInRegion(IRMana StlDeque<DominatorNode *> dom_stack(regionIRM.getMemoryManager()); dom_stack.push_back(dtree->getDominatorRoot()); - CFGNode* node = NULL; + Node* node = NULL; DominatorNode *domNode = NULL; while (!dom_stack.empty()) { @@ -164,20 +161,20 @@ Devirtualizer::guardCallsInRegion(IRMana void -Devirtualizer::genGuardedDirectCall(IRManager ®ionIRM, CFGNode* node, Inst* call, MethodDesc* methodDesc, Opnd *tauNullChecked, Opnd *tauTypesChecked, uint32 argOffset) { - FlowGraph ®ionFG = regionIRM.getFlowGraph(); +Devirtualizer::genGuardedDirectCall(IRManager ®ionIRM, Node* node, Inst* call, MethodDesc* methodDesc, Opnd *tauNullChecked, Opnd *tauTypesChecked, uint32 argOffset) { + ControlFlowGraph ®ionFG = regionIRM.getFlowGraph(); assert(!methodDesc->isStatic()); assert(call == node->getLastInst()); - Log::cat_opt_inline()->ir << "Generating guarded direct call to " << methodDesc->getParentType()->getName() + Log::out() << "Generating guarded direct call to " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; - Log::cat_opt_inline()->debug << "Guarded call bytecode size=" << (int) methodDesc->getByteCodeSize() << ::std::endl; + Log::out() << "Guarded call bytecode size=" << (int) methodDesc->getByteCodeSize() << ::std::endl; // // Compute successors of call site // - CFGNode* next = (CFGNode*) node->getUnconditionalEdge()->getTargetNode(); - CFGNode* dispatch = (CFGNode*) node->getExceptionEdge()->getTargetNode(); + Node* next = node->getUnconditionalEdge()->getTargetNode(); + Node* dispatch = node->getExceptionEdge()->getTargetNode(); // // Disconnect edges from call. @@ -189,10 +186,10 @@ Devirtualizer::genGuardedDirectCall(IRMa // // Create nodes for guard, direct call, virtual call, and merge. // - CFGNode* guard = node; - CFGNode* directCallBlock = regionFG.createBlockNode(); - CFGNode* virtualCallBlock = regionFG.createBlockNode(); - CFGNode* merge = next; + Node* guard = node; + Node* directCallBlock = regionFG.createBlockNode(_instFactory.makeLabel()); + Node* virtualCallBlock = regionFG.createBlockNode(_instFactory.makeLabel()); + Node* merge = next; // // Reconnect graph with new nodes. Connect to merge point later. @@ -201,7 +198,7 @@ Devirtualizer::genGuardedDirectCall(IRMa regionFG.addEdge(guard, virtualCallBlock); regionFG.addEdge(directCallBlock, dispatch); regionFG.addEdge(virtualCallBlock, dispatch); - directCallBlock->setFreq(guard->getFreq()); + directCallBlock->setExecCount(guard->getExecCount()); // // Create direct call instruction @@ -225,7 +222,7 @@ Devirtualizer::genGuardedDirectCall(IRMa assert(call_ii && new_ii); new_ii->getInlineChainFrom(*call_ii); - directCallBlock->append(directCall); + directCallBlock->appendInst(directCall); // // Create virtual call @@ -246,10 +243,10 @@ Devirtualizer::genGuardedDirectCall(IRMa Inst* ldSlot2 = _instFactory.makeTauLdVirtFunAddrSlot(funPtr2, vtable, tauVtableHasDesc, ldSlot->getMethodDesc()); - virtualCallBlock->append(ldSlot2); + virtualCallBlock->appendInst(ldSlot2); icall->setSrc(0, funPtr2); } - virtualCallBlock->append(virtualCall); + virtualCallBlock->appendInst(virtualCall); // // Promote a return operand (if one exists) of the call from a ssa temp to a var. @@ -262,16 +259,16 @@ Devirtualizer::genGuardedDirectCall(IRMa VarOpnd* returnVar = _opndManager.createVarOpnd(dst->getType(), false); - CFGNode* directStVarBlock = regionFG.createBlockNode(); - directStVarBlock->setFreq(directCallBlock->getFreq()); + Node* directStVarBlock = regionFG.createBlockNode(_instFactory.makeLabel()); + directStVarBlock->setExecCount(directCallBlock->getExecCount()); regionFG.addEdge(directCallBlock, directStVarBlock)->setEdgeProb(1.0); Inst* stVar1 = _instFactory.makeStVar(returnVar, ssaTmp1); - directStVarBlock->append(stVar1); + directStVarBlock->appendInst(stVar1); - CFGNode* virtualStVarBlock = regionFG.createBlockNode(); + Node* virtualStVarBlock = regionFG.createBlockNode(_instFactory.makeLabel()); regionFG.addEdge(virtualCallBlock, virtualStVarBlock); Inst* stVar2 = _instFactory.makeStVar(returnVar, ssaTmp2); - virtualStVarBlock->append(stVar2); + virtualStVarBlock->appendInst(stVar2); Inst* ldVar = _instFactory.makeLdVar(dst, returnVar); Inst* phi = NULL; @@ -292,7 +289,7 @@ Devirtualizer::genGuardedDirectCall(IRMa // bool needPhiBlock = (merge->getInDegree() > 0); if (needPhiBlock) { - CFGNode* phiBlock = regionFG.createBlockNode(); + Node* phiBlock = regionFG.createBlockNode(_instFactory.makeLabel()); regionFG.addEdge(phiBlock, merge); regionFG.addEdge(directStVarBlock, phiBlock)->setEdgeProb(1.0); regionFG.addEdge(virtualStVarBlock, phiBlock); @@ -302,9 +299,9 @@ Devirtualizer::genGuardedDirectCall(IRMa regionFG.addEdge(virtualStVarBlock, merge); } - merge->prepend(ldVar); + merge->prependInst(ldVar); if(phi != NULL) - merge->prepend(phi); + merge->prependInst(phi); } else{ // Connect calls directly to merge. regionFG.addEdge(directCallBlock, merge)->setEdgeProb(1.0); @@ -319,18 +316,17 @@ Devirtualizer::genGuardedDirectCall(IRMa ObjectType* baseType = (ObjectType*) base->getType(); Opnd* dynamicVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(baseType)); Opnd* staticVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(baseType)); - guard->append(_instFactory.makeTauLdVTableAddr(dynamicVTableAddr, base, + guard->appendInst(_instFactory.makeTauLdVTableAddr(dynamicVTableAddr, base, tauNullChecked)); - guard->append(_instFactory.makeGetVTableAddr(staticVTableAddr, baseType)); - guard->append(_instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, directCallBlock->getLabel())); + guard->appendInst(_instFactory.makeGetVTableAddr(staticVTableAddr, baseType)); + guard->appendInst(_instFactory.makeBranch(Cmp_EQ, Type::VTablePtr, dynamicVTableAddr, staticVTableAddr, (LabelInst*)directCallBlock->getFirstInst())); } bool -Devirtualizer::doGuard(IRManager& irm, CFGNode* node, MethodDesc& methodDesc) { - double methodCount = Inliner::getProfileMethodCount(irm.getCompilationInterface(), methodDesc); - double blockCount = node->getFreq(); +Devirtualizer::doGuard(IRManager& irm, Node* node, MethodDesc& methodDesc) { + - if(_skipColdTargets && _hasProfileInfo && methodCount == 0) + if(_skipColdTargets && _hasProfileInfo && irm.getFlowGraph().getEntryNode()->getExecCount() == 0) return false; // @@ -344,8 +340,6 @@ Devirtualizer::doGuard(IRManager& irm, C return true; } - - // // Only de-virtualize if there's profile information for this // node and the apparent target. @@ -353,18 +347,19 @@ Devirtualizer::doGuard(IRManager& irm, C if(!_hasProfileInfo) return false; - - return (blockCount <= methodCount); + double methodCount = irm.getFlowGraph().getEntryNode()->getExecCount(); + double blockCount = node->getExecCount(); + return (blockCount >= methodCount / 10.0); } void -Devirtualizer::guardCallsInBlock(IRManager& regionIRM, CFGNode* node) { +Devirtualizer::guardCallsInBlock(IRManager& regionIRM, Node* node) { // // Search node for guardian call // if(node->isBlockNode()) { - Inst* last = node->getLastInst(); + Inst* last = (Inst*)node->getLastInst(); MethodInst* methodInst = 0; Opnd* base = 0; Opnd* tauNullChecked = 0; @@ -389,14 +384,14 @@ Devirtualizer::guardCallsInBlock(IRManag if(!iterator->hasNext()) { // No candidate - Log::cat_opt_inline()->fail << "CHA no candidate " << baseType->getName() << "::" << methodDesc->getName() << methodDesc->getSignatureString() << ::std::endl; + Log::out() << "CHA no candidate " << baseType->getName() << "::" << methodDesc->getName() << methodDesc->getSignatureString() << ::std::endl; jitrino_assert(regionIRM.getCompilationInterface(),0); } MethodDesc* newMethodDesc = iterator->getNext(); if(!iterator->hasNext()) { // Only one candidate - Log::cat_opt_inline()->debug << "CHA devirtualize " << baseType->getName() << "::" << methodDesc->getName() << methodDesc->getSignatureString() << ::std::endl; + Log::out() << "CHA devirtualize " << baseType->getName() << "::" << methodDesc->getName() << methodDesc->getSignatureString() << ::std::endl; if(!baseType->isNullObject() && (!baseType->isAbstract() || baseType->isArray()) && !baseType->isInterface()) { assert(newMethodDesc == methodDesc); } @@ -423,7 +418,7 @@ Devirtualizer::guardCallsInBlock(IRManag new_ii->getInlineChainFrom(*call_ii); last->unlink(); - node->append(directCall); + node->appendInst(directCall); done = true; } } @@ -447,12 +442,12 @@ Devirtualizer::guardCallsInBlock(IRManag // Try to guard this call // if(doGuard(regionIRM, node, *methodDesc)) { - Log::cat_opt_inline()->debug << "Guard call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; + Log::out() << "Guard call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; genGuardedDirectCall(regionIRM, node, last, methodDesc, tauNullChecked, tauTypesChecked, argOffset); - Log::cat_opt_inline()->debug << "Done guarding call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; + Log::out() << "Done guarding call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; } else { - Log::cat_opt_inline()->debug << "Don't guard call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; + Log::out() << "Don't guard call to " << baseType->getName() << "::" << methodDesc->getName() << ::std::endl; } } } @@ -485,28 +480,28 @@ Devirtualizer::isPreexisting(Opnd* obj) void Devirtualizer::unguardCallsInRegion(IRManager& regionIRM, uint32 safetyLevel) { - FlowGraph ®ionFG = regionIRM.getFlowGraph(); + ControlFlowGraph ®ionFG = regionIRM.getFlowGraph(); if(!regionFG.hasEdgeProfile()) return; // // Search for previously guarded virtual calls // - MemoryManager mm(regionFG.getMaxNodeId()*sizeof(CFGNode*), "Devirtualizer::unguardCallsInRegion.mm"); - StlVector<CFGNode*> nodes(mm); + MemoryManager mm(regionFG.getMaxNodeId()*sizeof(Node*), "Devirtualizer::unguardCallsInRegion.mm"); + Nodes nodes(mm); regionFG.getNodesPostOrder(nodes); - StlVector<CFGNode*>::reverse_iterator i; + StlVector<Node*>::reverse_iterator i; for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - Inst* last = node->getLastInst(); + Node* node = *i; + Inst* last = (Inst*)node->getLastInst(); if(last->isBranch()) { // // Check if branch is a guard // assert(last->getOpcode() == Op_Branch); BranchInst* branch = last->asBranchInst(); - CFGNode* dCallNode = (CFGNode*) node->getTrueEdge()->getTargetNode(); - CFGNode* vCallNode = (CFGNode*) node->getFalseEdge()->getTargetNode(); + Node* dCallNode = node->getTrueEdge()->getTargetNode(); + Node* vCallNode = node->getFalseEdge()->getTargetNode(); if(branch->getComparisonModifier() != Cmp_EQ) continue; @@ -519,8 +514,8 @@ Devirtualizer::unguardCallsInRegion(IRMa if(src0->getInst()->getOpcode() != Op_TauLdVTableAddr || src1->getInst()->getOpcode() != Op_GetVTableAddr) continue; - Inst* ldvfnslot = vCallNode->getFirstInst()->next(); - Inst* callimem = ldvfnslot->next(); + Inst* ldvfnslot = (Inst*)vCallNode->getSecondInst(); + Inst* callimem = ldvfnslot->getNextInst(); if(ldvfnslot->getOpcode() != Op_TauLdVirtFunAddrSlot || callimem->getOpcode() != Op_IndirectMemoryCall) continue; @@ -529,10 +524,10 @@ Devirtualizer::unguardCallsInRegion(IRMa // bool fold = false; bool foldDirect = false; - if(node->getFreq() == 0) { + if(node->getExecCount() == 0) { fold = true; foldDirect = false; - } else if(vCallNode->getFreq() == 0) { + } else if(vCallNode->getExecCount() == 0) { if(safetyLevel == 0) { fold = false; } else if(safetyLevel == 1) { @@ -543,7 +538,7 @@ Devirtualizer::unguardCallsInRegion(IRMa fold = true; } foldDirect = true; - } else if(dCallNode->getFreq() == 0) { + } else if(dCallNode->getExecCount() == 0) { fold = true; foldDirect = false; } diff --git vm/jitrino/src/optimizer/devirtualizer.h vm/jitrino/src/optimizer/devirtualizer.h index 0dc2b5e..750c701 100644 --- vm/jitrino/src/optimizer/devirtualizer.h +++ vm/jitrino/src/optimizer/devirtualizer.h @@ -28,9 +28,6 @@ #include "irmanager.h" namespace Jitrino { -DEFINE_OPTPASS(GuardedDevirtualizationPass) -DEFINE_OPTPASS(GuardRemovalPass) - class Devirtualizer { public: Devirtualizer(IRManager& irm); @@ -40,12 +37,12 @@ public: void unguardCallsInRegion(IRManager& irm, uint32 safetyLevel=0); private: - void guardCallsInBlock(IRManager& irm, CFGNode* node); - void genGuardedDirectCall(IRManager& irm, CFGNode* node, Inst* call, MethodDesc* methodDesc, Opnd *tauNullChecked, Opnd *tauTypesChecked, uint32 argOffset); + void guardCallsInBlock(IRManager& irm, Node* node); + void genGuardedDirectCall(IRManager& irm, Node* node, Inst* call, MethodDesc* methodDesc, Opnd *tauNullChecked, Opnd *tauTypesChecked, uint32 argOffset); bool isGuardableVirtualCall(Inst* inst, MethodInst*& methodInst, Opnd*& base, Opnd* & tauNullChecked, Opnd*&tauTypesChecked, uint32 &argOffset); - bool doGuard(IRManager& irm, CFGNode* node, MethodDesc& methodDesc); + bool doGuard(IRManager& irm, Node* node, MethodDesc& methodDesc); bool isPreexisting(Opnd* obj); bool _hasProfileInfo; diff --git vm/jitrino/src/optimizer/escanalyzer.cpp vm/jitrino/src/optimizer/escanalyzer.cpp new file mode 100644 index 0000000..532c068 --- /dev/null +++ vm/jitrino/src/optimizer/escanalyzer.cpp @@ -0,0 +1,4232 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Natalya V. Golovleva + * @version $Revision$ + * + */ + +#include "escanalyzer.h" +#include "FlowGraph.h" +#include "Inst.h" +#include "Stl.h" +#include "BitSet.h" +#include "Dominator.h" +#include "Loop.h" +#include "Log.h" +#include "Type.h" +#include "ssa/SSA.h" +#include "optpass.h" +#include "devirtualizer.h" +#include "DrlVMInterface.h" + +namespace Jitrino { + + +DEFINE_SESSION_ACTION(EscapeAnalysisPass, escape, "Escape Analysis") + +struct ComObjStat { + ComObjStat() :_n0(0), _n_ge(0), _n_ae(0), _n_ne(0), _n_lo(0) {}; + uint32 _n0; + uint32 _n_ge; + uint32 _n_ae; + uint32 _n_ne; + uint32 _n_lo; +}; +static ComObjStat comObjStat; +EscAnalyzer::CalledMethodInfos* EscAnalyzer::calledMethodInfos=NULL; +Mutex EscAnalyzer::calledMethodInfosLock; + + +void +EscapeAnalysisPass::_run(IRManager& irm) { + + MemoryManager escMemManager(1024, "EscapeAnalyzer:tmp_mm"); + EscAnalyzer ea(escMemManager, this, irm); + + if (Log::isEnabled() && (ea.allProps!=0)) { + Log::out() << "E s c a p e A n a l y s i s " << std::endl; + } + + //if (Log::isEnabled()) { + // const char* i1=Log::getDotFileDirName(); + // if (strlen(i1)!=0) { + // ControlFlowGraph& flowGraph = irm.getFlowGraph(); + // FlowGraph::printDotFile(flowGraph, irm.getMethodDesc(), "ea1"); + // } + //} + ea.doAnalysis(); + //if (Log::isEnabled()) { + // const char* i1=Log::getDotFileDirName(); + // if (strlen(i1)!=0) { + // ControlFlowGraph& flowGraph = irm.getFlowGraph(); + // FlowGraph::printDotFile(flowGraph, irm.getMethodDesc(), "ea2"); + // } + //} +} // run(IRManager& irm) + + +EscAnalyzer::EscAnalyzer(MemoryManager& mm, SessionAction* argSource, IRManager& irm) +: eaMemManager(mm), irManager(irm), mh(irm.getMethodDesc()) +{ + maxMethodExamLevel = (uint32)argSource->getIntArg("max_level",maxMethodExamLevel_default); + allProps = (uint32)argSource->getIntArg("d_prop",0); + debug_method = argSource->getStringArg("d_method", NULL); + method_ea_level = 0; // determines level of method scan + + const char* translatorName = argSource->getStringArg("translatorActionName", "translator"); + translatorAction = (TranslatorAction*)PMF::getAction(argSource->getPipeline(), translatorName); + assert(translatorAction); + + init(); +} + +EscAnalyzer::EscAnalyzer(EscAnalyzer* parent, IRManager& irm) +: eaMemManager(parent->eaMemManager), irManager(irm), mh(irm.getMethodDesc()) +{ + maxMethodExamLevel = parent->maxMethodExamLevel; + allProps = parent->allProps; + debug_method = parent->debug_method; + translatorAction = parent->translatorAction; + method_ea_level = parent->method_ea_level + 1; + + init(); +} + +void EscAnalyzer::init() { + i32_0 = NULL; + i32_1 = NULL; + + initNodeType = 0; // type of initial scanned node + + scannedObjs = new (eaMemManager) ObjIds(eaMemManager); + scannedInsts = new (eaMemManager) ObjIds(eaMemManager); + scannedSucNodes = new (eaMemManager) ObjIds(eaMemManager); + monitorInstUnits = new (eaMemManager) MonInstUnits(eaMemManager); + + _cfgirun=0; + _instrInfo=0; + _instrInfo2=0; + _cngnodes=0; + _cngedges=0; + _scanMtds=0; + _setState=0; + _printstat=0; + _eainfo=0; + _seinfo=0; + std::fill(prsArr, prsArr + prsNum, 0); + + + int pr = allProps; + int prsBound[] = {1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1}; + if (pr-prsBound[0]-prsBound[0]<0 && pr!= 0) { + for (int i=0; i<prsNum; i++) { + if (pr >= prsBound[i] && pr-prsBound[i] >= 0) { + prsArr[i] = 1; + pr -= prsBound[i]; + } + } + + _eainfo = prsArr[8]; + _seinfo = prsArr[9]; + if (debug_method==NULL || strcmp(debug_method,"all")==0) { + _cfgirun = prsArr[0]; + _instrInfo = prsArr[1]; + _instrInfo2 = prsArr[2]; + _cngnodes = prsArr[3]; + _cngedges = prsArr[4]; + _scanMtds = prsArr[5]; + _setState = prsArr[6]; + _printstat = prsArr[7]; + } + } +} + +void +EscAnalyzer::doAnalysis() { + const char* mn = mh.getName(); + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + ControlFlowGraph& fg = irManager.getFlowGraph(); + uint32 nodeNum = nodes.size(); + uint32 num2 = fg.getNodeCount(); + uint32 num3 = fg.getMaxNodeId(); + Nodes::const_iterator niter; + + lastCnGNodeId = 0; // initialization of private field + defArgNumber = -1; // initialization of private field + + if (Log::isEnabled() && debug_method!=NULL) { + if (strcmp(mn,debug_method)==0) { + _cfgirun = prsArr[0]; + _instrInfo = prsArr[1]; + _instrInfo2 = prsArr[2]; + _cngnodes = prsArr[3]; + _cngedges = prsArr[4]; + _scanMtds = prsArr[5]; + _setState = prsArr[6]; + _printstat = prsArr[7]; + Log::out() << "_cfgirun " << _cfgirun << std::endl; + Log::out() << "_instrInfo " << _instrInfo << std::endl; + Log::out() << "_instrInfo2 " << _instrInfo2 << std::endl; + Log::out() << "_cngnodes " << _cngnodes << std::endl; + Log::out() << "_cngedges " << _cngedges << std::endl; + Log::out() << "_scanMtds " << _scanMtds << std::endl; + Log::out() << "_setState " << _setState << std::endl; + Log::out() << "_printstat " << _printstat << std::endl; + Log::out() << "_eainfo " << _eainfo << std::endl; + Log::out() << "_seinfo " << _seinfo << std::endl; + } + } + if (_eainfo || _seinfo) { + Log::out()<<"====== doAnalysis ====== "<<mn<<" level: "; + Log::out()<<method_ea_level<<" "; + if (mh.isSynchronized()) + Log::out()<<"sync "; + if (mh.isStatic()) + Log::out()<<"stat "; + Log::out()<<nodeNum<<" "<<num2<<" "<<num3<< " "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out()<< std::endl; + } + cfgNode* pr_n = new (eaMemManager)cfgNode[nodeNum]; // passed nodes + int maxInd = 0; + int cur = -1; + Node* node; + cngNodes=new (eaMemManager) CnGNodes(eaMemManager); // Common part of connection graph (nodes) + + for(niter = nodes.begin(); niter != nodes.end(); ++niter) { + node = *niter; + cur = maxInd++; + (pr_n[cur]).nodeId = node->getId(); + (pr_n[cur]).fgNode = node; + (pr_n[cur]).instructions = NULL; + +// exam instructions + +#ifdef _DEBUG + if (_cfgirun) { + Log::out() <<std::endl; + Log::out() <<"pr_n["<<cur<<"] nId "<<(pr_n[cur]).nodeId; + Log::out() <<" Node "<<(pr_n[cur]).fgNode->getId(); + Log::out() <<std::endl; + } +#endif + + instrExam(&pr_n[cur]); + + }; + +#ifdef _DEBUG + if (_cngnodes) { + Log::out() <<"printCnGNodes: "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + printCnGNodes("First run result: nodes",Log::out()); + } +#endif + + cngEdges=new (eaMemManager) CnGEdges(eaMemManager); // Common part of connection graph (edges) + for (int i=0; i<maxInd; i++) { + instrExam2(&pr_n[i]); + } + +#ifdef _DEBUG + if (_cngedges) { + Log::out() <<"printCnGEdges: "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + printCnGEdges("resulting OUT CnGEdges",Log::out()); + } +#endif + + + setCreatedObjectStates(); + +#ifdef _DEBUG + if (_eainfo) { + if (Log::isEnabled()) + printCreatedObjectsInfo(Log::out()); + } +#endif + + saveScannedMethodInfo(); //??? to save states of contained obj, if needed + +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "++++++++++++++ printRefInfo() "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + printRefInfo(Log::out()); + Log::out() << "++++++++++++++ end "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + } +#endif + + if (method_ea_level == 0) { // mark inst that may be optimized +#ifdef _DEBUG + if (_cngedges) + Log::out() <<"+++++++++++++++++ markNotEscInsts()"<< std::endl; +#endif + markNotEscInsts(); + } + +#ifdef _DEBUG + if (_cngnodes) { + Log::out() <<"printCnGNodes: "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + printCnGNodes("Marked nodes",Log::out()); + } +#endif + + if (method_ea_level == 0) { + createdObjectInfo(); // prints if _printstat==1 + } + + if (method_ea_level == 0) { + scanSyncInsts(); + +#ifdef _DEBUG + if (_seinfo && Log::isEnabled()) { + printCreatedObjectsInfo(Log::out()); + Log::out() << "================ this agrument of sync method" + << std::endl; + CnGNodes::iterator it; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + CnGNode* n = (*it); + if (n->nodeType==NT_ACTARG && n->argNumber==0 && + ((MethodDesc*)(n->refObj))->isSynchronized()) { + ((MethodDesc*)(n->refObj))->printFullName(Log::out()); + Log::out()<<std::endl; + printCnGNodeRefs(n, " ", Log::out()); + } + } + + scannedObjs->clear(); + Log::out() << "================ Return Values 2" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_EXITVAL) { + printCnGNodeRefs(*it, "", Log::out()); + } + } + scannedObjs->clear(); + + } +#endif + } + + if (_eainfo || _seinfo) { + Log::out()<<"====== doAnalysis ====== "<<mn<<" level: "; + Log::out()<<method_ea_level<<" end "; + if (mh.isSynchronized()) + Log::out()<<"sync "; + if (mh.isStatic()) + Log::out()<<"stat "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out()<< std::endl; + } + + if (Log::isEnabled() && debug_method!=NULL) { + if (strcmp(mn,debug_method)==0) { + _cfgirun = 0; + _instrInfo = 0; + _instrInfo2 = 0; + _cngnodes = 0; + _cngedges = 0; + _scanMtds = 0; + _setState = 0; + _printstat = 0; + } + } + + return; +} // doAnalysis() + + +void +EscAnalyzer::scanSyncInsts() { + MonInstUnits::iterator it; + Insts::iterator it1; + Insts* syncInsts; + CnGNode* node; + uint32 checkedState = 0; + uint32 nState = 0; + bool to_fix_ssa = false; + + if (monitorInstUnits == NULL) + return; + +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "Synchronized units: " << std::endl; + } +#endif + for (it = monitorInstUnits->begin( ); it != monitorInstUnits->end( ); it++ ) { + node = findCnGNode_op((*it)->opndId); + checkedState = 0; + nState = getEscState(node); + if (node->nodeType == NT_OBJECT || nState == GLOBAL_ESCAPE) + checkedState = nState; + if (nState != GLOBAL_ESCAPE && (node->nodeType != NT_OBJECT)) { + checkedState = checkState(node->nInst,nState); + scannedObjs->clear(); + if (checkedState != nState && checkedState != 0) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanSyncInsts 1: node " + <<node->cngNodeId<<" opndId "<<node->opndId + <<" state "; + if (Log::isEnabled()) + printState(node); + Log::out()<<" to esc.state "<< checkedState << std::endl; + } +#endif + setEscState(node,checkedState); + } + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() <<"--sync: state "; + Log::out() << checkedState << " "; + if (checkedState != nState) + Log::out() << "initState " << nState << " "; + Log::out() << node->cngNodeId << " - " << node->opndId << " "; + if (Log::isEnabled()) + printCnGNode(node,Log::out()); + Log::out() << std::endl; + } +#endif + if ((node->nodeType&NT_OBJECT)==0 && (getEscState(node) != GLOBAL_ESCAPE)) { + findObject(node->nInst); + scannedObjs->clear(); + } + syncInsts = (*it)->monInsts; +#ifdef _DEBUG + if (_seinfo) { + for (it1 = syncInsts->begin( ); it1 != syncInsts->end( ); it1++ ) { + Log::out() << " -"; + if (Log::isEnabled()) + (*it1)->print(Log::out()); + Log::out() << " // node " + << (*it1)->getNode()->getId() << std::endl; + } + } +#endif + if (getEscState(node) == GLOBAL_ESCAPE) + setSencEscState(node,syncInsts); + if (getVirtualCall(node)!=0) { + if (checkedState > GLOBAL_ESCAPE) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- vc loc.esc." << std::endl; + findObject(node->nInst); + scannedObjs->clear(); + } +#endif + if (node->nodeType==NT_OBJECT) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- vc to optimize object" << std::endl; + } +#endif + fixMonitorInstsVCalls(*it); + } + if (node->nodeType==NT_RETVAL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- vc to optimize retval" << std::endl; + } +#endif + fixMonitorInstsVCalls(*it); + } + if (!to_fix_ssa) + to_fix_ssa = true; + } else { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- vc gl.esc." << std::endl; + findObject(node->nInst); + scannedObjs->clear(); + } +#endif + } + } else { + if (node->nodeType==NT_OBJECT && getEscState(node) != GLOBAL_ESCAPE) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ to optimize (remove) object" << std::endl; + } +#endif + removeMonitorInsts(syncInsts); + } + + if (node->nodeType==NT_DEFARG && getEscState(node) != GLOBAL_ESCAPE + && node->nInst->getDefArgModifier()==NonNullThisArg && mh.isSynchronized()) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ to optimize (fix) defarg.ths" << std::endl; + } +#endif +#ifndef PLATFORM_POSIX + fixSyncMethodMonitorInsts(syncInsts); +#endif + } +// if (opndInst->getOpcode()==Op_DefArg && opndInst->getDefArgModifier()==NonNullThisArg) { + + } + } +#ifndef PLATFORM_POSIX + checkCallSyncMethod(); +#endif + // to fix var operand inserted by fixMonitorInstsVCalls method + if (to_fix_ssa) { + OptPass::fixupSsa(irManager); + } + return; +} // scanSyncInsts() + + +void +EscAnalyzer::fixSyncMethodMonitorInsts(Insts* syncInsts) { + SsaTmpOpnd* stThis = (SsaTmpOpnd*)insertReadJitHelperCall(); + insertFlagCheck(syncInsts,stThis); +} // fixSyncMethodMonitorInsts(Insts* syncInsts) + + +void +EscAnalyzer::checkCallSyncMethod() { + CnGNodes::iterator it; + CnGRefs::iterator it2; + CnGNode* node; + CnGNode* aanode; + MethodDesc* md; + CalledMethodInfo* mtdInfo; + uint32 callee_state; + + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + node = (*it); + if (node->nodeType == NT_ACTARG && node->argNumber == 0) { + md = (MethodDesc*)(node->refObj); + if (md->isSynchronized() && node->nInst->getOpcode()==Op_DirectCall) { + const char* ch1 = md->getParentType()->getName(); + const char* ch2 = md->getName(); + const char* ch3 = md->getSignatureString(); + mtdInfo = getMethodInfo(ch1,ch2,ch3); + if (mtdInfo==NULL) { + callee_state = 0; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- Methodinfo is NULL"; + Log::out() << std::endl; + } +#endif + } else { + callee_state = getMethodParamState(mtdInfo,0); + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "---- checkCallSyncMethod:" << std::endl; + if (Log::isEnabled()) + node->nInst->print(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + printCnGNode(node,Log::out()); + Log::out() << std::endl; + if (node->outEdges != NULL) { + for (it2 = node->outEdges->begin(); it2 != node->outEdges->end(); it2++ ) { + Log::out() << " ccsm: "; + if (Log::isEnabled()) + printState(callee_state); + Log::out() << " "; + if (Log::isEnabled()) + printCnGNode((*it2)->cngNodeTo,Log::out()); + Log::out() << std::endl; + } + } + Log::out() << "++++ checkCallSyncMethod: "; + Log::out() << " instance: " << md->isInstance() << + " initializer: " << md->isInstanceInitializer() << " end" << std::endl; + } +#endif + if (callee_state == 0) + callee_state = GLOBAL_ESCAPE; + if (!isGlobalState(callee_state)) { + if (node->outEdges != NULL) { + for (it2 = node->outEdges->begin(); it2 != node->outEdges->end(); it2++ ) { + aanode = (*it2)->cngNodeTo; + if (!isGlobalState(aanode->state)&& + (aanode->nodeType==NT_OBJECT||aanode->nodeType==NT_RETVAL)) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() + << "=-=- sm this.agr.saving" << std::endl; + } +#endif + insertSaveJitHelperCall(node); +#ifdef _DEBUG + if (_seinfo) { + Log::out() + << " checkCSM: this was saved" + << std::endl; + } + } else { + if (_seinfo) { + Log::out() + << " checkCSM: this wasn't saved" + << std::endl; + } +#endif + } + } + } + } + } + } + } +} // checkCallSyncMethod() + + +/* +* Inserts ldc0, if it was not inserted previously, +* jit helper call to save this arg of direct call method. +* Parameter: +* CnGNode corresponding to this arg of direct call sync method. +*/ +void +EscAnalyzer::insertSaveJitHelperCall(CnGNode* node) { + SsaTmpOpnd* stVal; + Inst* inst_before = node->nInst; + Node* oldBlock = inst_before->getNode(); + ControlFlowGraph& fg = irManager.getFlowGraph(); + +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ insertSJHC: before" << std::endl; + if (Log::isEnabled()) { + printNode(fg.getEntryNode(),Log::out()); + printNode(oldBlock,Log::out()); + } + Log::out() << "++++ insertSJHC: before end" << std::endl; + } +#endif + stVal = insertLdConst(0); + // insert jit helper call + Opnd* args[1] = {stVal}; + InstFactory& instfactory = irManager.getInstFactory(); + Inst* jhcinst = instfactory.makeJitHelperCall( + OpndManager::getNullOpnd(), SaveThisState, 1, args); + // add jit helper + jhcinst->insertBefore(inst_before); + Node* newBlock = fg.splitNodeAtInstruction(jhcinst, true, false, instfactory.makeLabel()); + // add dispatch edge to oldBlock + fg.addEdge(oldBlock,newBlock->getExceptionEdgeTarget()); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ insertSJHC: after" << std::endl; + if (Log::isEnabled()) { + printNode(fg.getEntryNode(),Log::out()); + printNode(oldBlock,Log::out()); + printNode(newBlock,Log::out()); + } + Log::out() << "++++ insertSJHC: after end" << std::endl; + } +#endif +} // insertSaveJitHelperCall(CnGNode* node) + + +/* +* Inserts ldc0, if it was not inserted previously, +* jit helper call to read this arg of the method. +* Parameter: +* CnGNode corresponding to this arg of direct call sync method. +* Returns: +* Opnd* stored_value +* 0 - this argument is thread local, 1 - this argument is thread global +*/ +Opnd* +EscAnalyzer::insertReadJitHelperCall() { + ControlFlowGraph& fg = irManager.getFlowGraph(); + Node* oldBlock = fg.getEntryNode(); + Inst* inst_after = (Inst*)oldBlock->getFirstInst(); + TypeManager& _typeManager = irManager.getTypeManager(); + Type* typeInt32 = _typeManager.getInt32Type(); + OpndManager& _opndManager = irManager.getOpndManager(); + SsaTmpOpnd* stThis = _opndManager.createSsaTmpOpnd(typeInt32); + +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ insertRJHC: before" << std::endl; + if (Log::isEnabled()) + printNode(oldBlock,Log::out()); + Log::out() << "++++ insertRJHC: before end" << std::endl; + } +#endif + insertLdConst(0); + // insert jit helper call + Opnd** args = NULL; + InstFactory& instfactory = irManager.getInstFactory(); + Inst* jhcinst = instfactory.makeJitHelperCall( + stThis, ReadThisState, 0, args); + jhcinst->insertAfter(inst_after); + fg.splitNodeAtInstruction(jhcinst,true, false,instfactory.makeLabel()); + fg.addEdge(oldBlock,fg.getUnwindNode()); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "++++ insertRJHC: after" << std::endl; + if (Log::isEnabled()) { + printNode(oldBlock,Log::out()); + } + Log::out() << "++++ insertRJHC: after end" << std::endl; + } +#endif + return stThis; +} // insertReadJitHelperCall() + + +/* +* Checks, that method contains monitor instructions with parameter +* which is this or subobject of this. +* Returns: true, if such monitors exist, false overwise. +*/ +bool +EscAnalyzer::checkMonitorsOnThis() { + MonInstUnits::iterator it; + Insts::iterator it1; + CnGNode* node; + + if (monitorInstUnits==NULL) + return false; + for (it = monitorInstUnits->begin( ); it != monitorInstUnits->end( ); it++ ) { //540 + node = findCnGNode_op((*it)->opndId); + + Inst* opndInst = node->nInst; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " checkMOT: "; + if (Log::isEnabled()) + opndInst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (opndInst->getOpcode()==Op_DefArg && opndInst->getDefArgModifier()==NonNullThisArg) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " checkMOT: "; + Log::out() << (int)(opndInst->getDefArgModifier()) << " " << + (opndInst->getDefArgModifier()==DefArgNoModifier) << " " << + (opndInst->getDefArgModifier()==NonNullThisArg) << " " << + (opndInst->getDefArgModifier()==DefArgBothModifiers) << " state: "; + if (Log::isEnabled()) + printState(node,Log::out()); + Log::out() << std::endl; + if (getEscState(node) != GLOBAL_ESCAPE) { + Log::out() << " defarg.ths isn't global "<< std::endl; + } + } +#endif + return true; + } + } + return false; +} // checkMonitorsOnThis() + + +void +EscAnalyzer::setSencEscState(CnGNode* node,Insts* syncInsts) { + CnGEdges::iterator it; + Insts::iterator it1; + CnGRefs::iterator it2; + Inst* einst; + bool pLocalObj = true; + bool pLocalCurObj = false; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- to node " << node->cngNodeId + << std::endl; + } +#endif + scannedSucNodes->clear(); // prepared for successor collection + for (it = cngEdges->begin( ); it != cngEdges->end( ); it++ ) { + for (it2 = (*it)->refList->begin( ); it2 != (*it)->refList->end( ); it2++ ) { + if ((*it2)->cngNodeTo == node) { + pLocalCurObj = false; + einst = (*it2)->edgeInst; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- "; + Log::out() << einst->getNode()->getId() + << " "; + if (Log::isEnabled()) + einst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (einst->getOpcode() == Op_DirectCall) { + MethodDesc* md=einst->asMethodInst()->getMethodDesc(); + const char* ch1 = md->getParentType()->getName(); + const char* ch2 = md->getName(); + const char* ch3 = md->getSignatureString(); + CalledMethodInfo* mtdInfo = getMethodInfo(ch1,ch2,ch3); + if (mtdInfo==NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- Methodinfo is NULL"; + Log::out() << std::endl; + } +#endif + } else { + uint32 st = getMethodParamState(mtdInfo,(*it)->cngNodeFrom->argNumber); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- Method param " + << (*it)->cngNodeFrom->argNumber << " state is "; + if (Log::isEnabled()) + printState(st); + Log::out() << std::endl; + } +#endif + if ((st&ESC_MASK)>GLOBAL_ESCAPE) { + pLocalCurObj = true; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- Method param " + << (*it)->cngNodeFrom->argNumber << " state is "; + if (Log::isEnabled()) + printState(st); + Log::out() << std::endl; + } +#endif + } else { +#ifdef _DEBUG + if (_seinfo) { + if (Log::isEnabled()) + printMethodInfo(mtdInfo); + } +#endif + } + } + } + findObject1(einst); + collectSuccessors(einst->getNode()); + } + } + for (it1 = syncInsts->begin(); it1 != syncInsts->end( ); it1++ ) { + if (scannedSucNodes->size()!=0) { + if (checkScannedSucNodes((*it1)->getNode()->getId())!=0) { +#ifdef _DEBUG + if (_seinfo) { + if (pLocalCurObj) + Log::out() << " "; + Log::out() << "=- contains " + << (*it1)->getNode()->getId() + << std::endl; + } +#endif + if (!pLocalCurObj) + pLocalObj = false; + } + } + } + scannedSucNodes->clear(); + } + if (pLocalObj) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- may be optimized" + << std::endl; + } +#endif + } +} // setSencEscState(CnGNode* node,Insts* syncInsts) + + +/* +* Collect all reachable from specified node nodes in FlowGraph. +* scannedSucNodes - result of collection. +*/ +void +EscAnalyzer::collectSuccessors(Node* node) { + Node* n; + Edges::const_iterator eit; + const Edges& out_edges = node->getOutEdges(); + if (scannedSucNodes->size()!=0) { + if (checkScannedSucNodes(node->getId())!=0) { + return; + } + } + scannedSucNodes->push_back(node->getId()); + for (eit = out_edges.begin(); eit != out_edges.end(); ++eit) { + n = (*eit)->getTargetNode(); + collectSuccessors(n); + } +} // collectSuccessors(Node* node) + + +void +EscAnalyzer::collectGlobalNodeSuccessors(CnGNode* node) { + CnGEdges::iterator it; + CnGRefs::iterator it2; + Inst* einst; + bool pGlobalObj = false; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=- to node " << node->cngNodeId + << std::endl; + } +#endif + scannedSucNodes->clear(); // prepared for successor collection + for (it = cngEdges->begin( ); it != cngEdges->end( ); it++ ) { + for (it2 = (*it)->refList->begin( ); it2 != (*it)->refList->end( ); it2++ ) { + if ((*it2)->cngNodeTo == node) { + pGlobalObj = false; + einst = (*it2)->edgeInst; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-ggns "; + Log::out() << einst->getNode()->getId() + << " "; + if (Log::isEnabled()) + einst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (einst->getOpcode() == Op_DirectCall) { + MethodDesc* md=einst->asMethodInst()->getMethodDesc(); + const char* ch1 = md->getParentType()->getName(); + const char* ch2 = md->getName(); + const char* ch3 = md->getSignatureString(); + CalledMethodInfo* mtdInfo = getMethodInfo(ch1,ch2,ch3); + if (mtdInfo==NULL) { + pGlobalObj = true; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "ggns=- Methodinfo is NULL"; + Log::out() << std::endl; + } +#endif + } else { + uint32 st = getMethodParamState(mtdInfo,(*it)->cngNodeFrom->argNumber); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "ggns=-=- Method param " + << (*it)->cngNodeFrom->argNumber << " state is "; + if (Log::isEnabled()) + printState(st); + Log::out() << std::endl; + } +#endif + if ((st&ESC_MASK)<=GLOBAL_ESCAPE) { + pGlobalObj = true; +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "ggns=- Method param " + << (*it)->cngNodeFrom->argNumber << " state is "; + if (Log::isEnabled()) + printState(st); + Log::out() << std::endl; + } +#endif + } + } + } + if (einst->getOpcode() == Op_IndirectMemoryCall) + pGlobalObj = true; + if (einst->getOpcode() == Op_TauStInd) { + Inst* i1 = einst->getSrc(0)->getInst(); + if (i1->getOpcode()==Op_LdStaticAddr) + pGlobalObj = true; + uint32 st = getContainingObjState(i1); + if ((st&ESC_MASK)<=GLOBAL_ESCAPE) { + pGlobalObj = true; + } + } + findObject1(einst); + if (pGlobalObj) + collectSuccessors(einst->getNode()); + } + } + } +} // collectGlobalNodeSuccessors(CnGNode* node) + + +uint32 +EscAnalyzer::getContainingObjState(Inst* linst) { + Opnd* cop = NULL; + if (linst->getOpcode()==Op_LdStaticAddr) + return GLOBAL_ESCAPE; + if (linst->getOpcode()==Op_LdFieldAddr || linst->getOpcode()==Op_LdArrayBaseAddr) + cop = linst->getSrc(0); + if (linst->getOpcode()==Op_AddScaledIndex) + cop = linst->getSrc(0)->getInst()->getSrc(0); + else + return GLOBAL_ESCAPE; + CnGNode* n = findCnGNode_op(cop->getId()); + return n->state; +} // getContainingObjState(Inst* linst) + + +void +EscAnalyzer::removeMonitorInsts(Insts* syncInsts) { + ControlFlowGraph& fg = irManager.getFlowGraph(); + Insts::iterator it1; + Edge* excedge = NULL; + Node* targetnode = NULL; + Inst* reminst; +#ifdef _DEBUG + bool canthrow = false; +#endif + + for (it1 = syncInsts->begin( ); it1 != syncInsts->end( ); it1++ ) { + reminst = *it1; + if (reminst->getOperation().canThrow()==true) { + excedge = (Edge*)reminst->getNode()->getExceptionEdge(); + if (excedge != NULL) + targetnode = excedge->getTargetNode(); + else + targetnode = NULL; + } else { + excedge = NULL; + targetnode = NULL; + } +#ifdef _DEBUG + if (_seinfo) { + canthrow = reminst->getOperation().canThrow(); + Log::out() << " "; + if (Log::isEnabled()) + reminst->print(Log::out()); + Log::out() << std::endl; + Log::out() << " canThrow "<< canthrow; + Log::out() << std::endl; + if (excedge==NULL) { + Log::out() << " exception edge is NULL " << std::endl; + } else { + Log::out() << " target node is " + << targetnode->getId() << std::endl; + } + if (canthrow && (excedge==NULL)) { + const Edges& out_edges = reminst->getNode()->getOutEdges(); + Edges::const_iterator eit; + Node* n; + for (eit = out_edges.begin(); eit != out_edges.end(); ++eit) { + n = (*eit)->getTargetNode(); + Log::out() << " edge to node " + << n->getId() << " kind " << (*eit)->getKind() << std::endl; + } + } + } +#endif + + reminst->unlink(); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " unlinked: "; + if (Log::isEnabled()) + reminst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (targetnode != NULL) { + if (targetnode->getInEdges().size() > 1) { + fg.removeEdge(excedge); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " removed edge: " + << excedge->getSourceNode()->getId() << " -> " + << excedge->getTargetNode()->getId() << " kind " << excedge->getKind(); + Log::out() << std::endl; + } +#endif + } else { + scannedObjs->clear(); + removeNode(targetnode); + scannedObjs->clear(); + } + } + + } + +} // removeMonitorInsts(Insts* syncInsts) + + +void +EscAnalyzer::removeNode(Node* node) { + const Edges& out_edges = node->getOutEdges(); + Edges::const_iterator eit; + Node* n; + +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " to remove node " + << node->getId() << std::endl; + } +#endif + if (scannedObjs->size()!=0) { + if (checkScannedObjs(node->getId())) { + return; + } + } + scannedObjs->push_back(node->getId()); + Nodes nodes2delete(irManager.getMemoryManager()); + for (eit = out_edges.begin(); eit != out_edges.end(); ++eit) { + n = (*eit)->getTargetNode(); + if (n->getInEdges().size() == 1) { + nodes2delete.push_back(n); + } + } + Nodes::iterator iter = nodes2delete.begin(), end = nodes2delete.end(); + for (; iter != end; ++iter) { + n = (*iter); + removeNode(n); + } + irManager.getFlowGraph().removeNode(node); + scannedObjs->pop_back(); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << " removed node " + << node->getId() << std::endl; + } +#endif +} // removeNode(Node* node) + + +/* +* Creates i32_0 or i32_1 SsaTmpOpnd (in accordance with value: 0 or 1) +* if it was'n created before. +* Inserts ldc0 or ldc1 instruction after first instruction in entry Node, +* if SsaTmpOpnd was created. +* Returns: +* i32_0, if value = 0 +* i32_1, if value = 1 +*/ +SsaTmpOpnd* +EscAnalyzer::insertLdConst(uint32 value) { + TypeManager& _typeManager = irManager.getTypeManager(); + Type* typeInt32 = _typeManager.getInt32Type(); + OpndManager& _opndManager = irManager.getOpndManager(); + InstFactory& _instFactory = irManager.getInstFactory(); + Inst* ildc = NULL; + if (value == 0) + if (i32_0 == NULL) { + i32_0 = _opndManager.createSsaTmpOpnd(typeInt32); + ildc = _instFactory.makeLdConst(i32_0, 0); + } + if (value == 1) + if (i32_1 == NULL) { + i32_1 = _opndManager.createSsaTmpOpnd(typeInt32); + ildc = _instFactory.makeLdConst(i32_1, 1); + } + if (ildc != NULL) { + ildc->insertAfter(irManager.getFlowGraph().getEntryNode()->getFirstInst()); + } + if (value == 0) + return i32_0; + return i32_1; +} // insertLdConst(uint32 value) + + +void +EscAnalyzer::fixMonitorInstsVCalls(MonUnit* mu) { + Inst* opi = findCnGNode_op(mu->opndId)->nInst; + OpndManager& _opndManager = irManager.getOpndManager(); + InstFactory& _instFactory = irManager.getInstFactory(); + TypeManager& _typeManager = irManager.getTypeManager(); + Type* typeInt32 = _typeManager.getInt32Type(); + VarOpnd* muflag = _opndManager.createVarOpnd(typeInt32, false); + Inst* stvar0; // = _instFactory.makeStVar(muflag, i32_0); + Inst* stvar1; + Insts::iterator inst_it; + Insts* vcInsts = mu->icallInsts;; + Insts* syncInsts = mu->monInsts; +#ifdef _DEBUG + ControlFlowGraph& fg = irManager.getFlowGraph(); + Node* entry_node = fg.getEntryNode(); + Node* muo_node = opi->getNode(); + Node* node; +#endif + + // values 0 and 1 to set flag variable +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w0 Before " << std::endl; + if (Log::isEnabled()) + printNode(entry_node,Log::out()); + } +#endif + insertLdConst(1); + insertLdConst(0); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w0 After " << std::endl; + if (Log::isEnabled()) + printNode(entry_node,Log::out()); + } +#endif + + // insert flag=0 after monitor instruction opnd creation instruction +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w1 Before " << std::endl; + if (Log::isEnabled()) + printNode(muo_node,Log::out()); + } +#endif + stvar0 = _instFactory.makeStVar(muflag, i32_0); + stvar0->insertAfter(opi); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w1 After " << std::endl; + if (Log::isEnabled()) + printNode(muo_node,Log::out()); + } +#endif + + // insert flag=1 before virtual call instructions +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=-=-=- Start w2" << std::endl; + } +#endif + for (inst_it = vcInsts->begin( ); inst_it != vcInsts->end( ); inst_it++ ) { +#ifdef _DEBUG + node = (*inst_it)->getNode(); + if (_seinfo) { + Log::out() << "=-=- w2 Before " << std::endl; + if (Log::isEnabled()) + printNode(node,Log::out()); + } +#endif + stvar1 = _instFactory.makeStVar(muflag, i32_1); + stvar1->insertBefore(*inst_it); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w2 After " << std::endl; + if (Log::isEnabled()) + printNode(node,Log::out()); + } +#endif + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=-=-=- Finish w2" << std::endl; + } +#endif + + insertFlagCheck(syncInsts,muflag); + +} // fixMonitorInstsVCalls(MonUnit* mu) + + +/* +* Insers flag check before monitor instruction. +* If flag = 0 monitor instruction isn't executed. +* Operand flag may be VarOpnd* or SsaTmpOpnd* type. +*/ +void +EscAnalyzer::insertFlagCheck(Insts* syncInsts, Opnd* muflag) { + Insts::iterator inst_it; + OpndManager& _opndManager = irManager.getOpndManager(); + InstFactory& _instFactory = irManager.getInstFactory(); + ControlFlowGraph& fg = irManager.getFlowGraph(); + TypeManager& _typeManager = irManager.getTypeManager(); + Type* typeInt32 = _typeManager.getInt32Type(); + + // check flag before monitor instructions + assert(muflag->isVarOpnd()||muflag->isSsaTmpOpnd()); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=-=-=- Start w3" << std::endl; + } +#endif + for (inst_it = syncInsts->begin( ); inst_it != syncInsts->end( ); inst_it++ ) { + Inst* curMonInst = (*inst_it); + Node* oldnode = curMonInst->getNode(); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w3 Before " << std::endl; + if (Log::isEnabled()) + printNode(oldnode,Log::out()); + } +#endif + Node* afterMonInstBlock = NULL; + Node* tiInstBlock = NULL; + if ((*inst_it)->getNextInst()!=NULL) { + // monitor inst isn'n last + tiInstBlock = fg.splitNodeAtInstruction(curMonInst, true, false, _instFactory.makeLabel()); + afterMonInstBlock = tiInstBlock; + } else { + // monitor inst is last + afterMonInstBlock = (Node*)(oldnode->getUnconditionalEdge()->getTargetNode()); + } + SsaTmpOpnd* i32_flag; + if (muflag->isVarOpnd()) { + i32_flag = _opndManager.createSsaTmpOpnd(typeInt32); + _instFactory.makeLdVar(i32_flag,(VarOpnd*)muflag)->insertBefore(curMonInst); + } else + i32_flag = (SsaTmpOpnd*)muflag; + Inst* branch_inst = _instFactory.makeBranch(Cmp_EQ, Type::Int32, + i32_flag, i32_0, (LabelInst*)(afterMonInstBlock->getFirstInst())); + // insert flag check + branch_inst->insertBefore(curMonInst); +#ifdef _DEBUG + Node* monInstBlock = +#endif + fg.splitNodeAtInstruction(branch_inst,true, false, _instFactory.makeLabel()); + fg.addEdge(oldnode,afterMonInstBlock); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=- w3 After " << std::endl; + if (Log::isEnabled()) { + printNode(oldnode,Log::out()); + printNode(monInstBlock,Log::out()); + if (tiInstBlock != NULL) { + printNode(tiInstBlock,Log::out()); + } + } + } +#endif + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "=-=-=-=- Finish w3" << std::endl; + } +#endif +} // insertFlagCheck(Insts* syncInsts, VarOpnd* muflag) + + +void +EscAnalyzer::printNode(Node* n,::std::ostream& os) { + const Edges& ie = n->getInEdges(); + const Edges& oe = n->getOutEdges(); + Edges::const_iterator i; + os << "=- Node Id." << n->getId() << std::endl; + FlowGraph::printInsts(os,n,2); + os << "=- pred: "; + for(i = ie.begin(); i != ie.end(); ++i) { + os << (*i)->getSourceNode()->getId() << " "; + } + os << std::endl; + os << "=- succ: "; + for(i = oe.begin(); i != oe.end(); ++i) { + os << (*i)->getTargetNode()->getId() << " "; + } + os << std::endl; +} // printNode(Node* n,::std::ostream& os) + + +/* +* Checks state for NT_LDOBJ nodes. +* Returns +* GLOBAL_ESCAPE - for global escaped NT_OBJECT, NT_RETVAL, NT_DEFARG +* node state - for not global escaped NT_OBJECT +* 0 - for not global escaped ?NT_RETVAL, NT_DEFARG +*/ +uint32 +EscAnalyzer::checkState(Inst* inst,uint32 st) { + uint32 st1; + Inst* inst1; + Opnd* opnd1; + uint32 nsrc=inst->getNumSrcOperands(); + + if (st <= GLOBAL_ESCAPE) + return st; + if (scannedObjs->size()!=0) { + if (checkScannedObjs(inst->getId())) { + return st; + } + } + if (inst->getOpcode()==Op_DirectCall || inst->getOpcode()==Op_IndirectMemoryCall) { + Opnd *returnOpnd = inst->getDst(); + if (returnOpnd != NULL) { + CnGNode* n = findCnGNode_op(returnOpnd->getId()); + if (n != NULL) { + st1 = getEscState(n); + if (st > st1) + st=st1; + } + } + return st; + } + if (st <= GLOBAL_ESCAPE) + return st; + if (inst->getOpcode()==Op_TauLdInd || inst->getOpcode()==Op_LdVar) { // ldind, ldvar + Opnd *dst = inst->getDst(); + CnGNode* n = findCnGNode_op(dst->getId()); + if (n != NULL) { + st1 = getEscState(n); + if (st > st1) + st=st1; + } + } + if (st <= GLOBAL_ESCAPE) + return st; + switch (inst->getOpcode()) { + case Op_LdRef: // ldstr + case Op_NewObj: // newobj + case Op_NewArray: // newarray + case Op_NewMultiArray: // newmultiarray + case Op_DefArg: // defarg + { + CnGNode* n = findCnGNode_in(inst->getId()); + if (n != NULL) { + st1 = getEscState(n); + if (st > st1) + st=st1; + } + break; + } + default: + break; + } + if (st <= GLOBAL_ESCAPE) + return st; + scannedObjs->push_back(inst->getId()); + for (uint32 i=0; i<nsrc; i++) { + opnd1 = inst->getSrc(i); + if (opnd1->isVarOpnd()) { + inst1 = opnd1->asVarOpnd()->getVarAccessInsts(); + } else { + inst1 = opnd1->getInst(); + } + st1 = checkState(inst1,st); + if (st > st1) + st=st1; + if (st<=GLOBAL_ESCAPE) + break; + } + scannedObjs->pop_back(); + return st; +} // checkState(Inst* inst,uint32 st) + + +void +EscAnalyzer::findObject(Inst* inst,std::string text) { + Inst* inst1 = NULL; + uint32 nsrc=inst->getNumSrcOperands(); + + if (scannedObjs->size()!=0) { + if (checkScannedObjs(inst->getId())) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "instId " << inst->getId() + << " . . . " << std::endl; + } +#endif + return; + } + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() << text; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (inst->getOpcode()==Op_DirectCall || inst->getOpcode()==Op_IndirectMemoryCall) { + Opnd *returnOpnd = inst->getDst(); + if (returnOpnd != NULL) { + CnGNode* n = findCnGNode_op(returnOpnd->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out()<< text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out()); + Log::out()<< std::endl; + } +#endif + } + } + if (inst->getOpcode()==Op_IndirectMemoryCall) { +#ifdef _DEBUG + MethodDesc* md = inst->getSrc(0)->getInst()->asMethodInst()->getMethodDesc(); + if (_seinfo) { + Log::out() << text << " "; + if (Log::isEnabled()) + md->printFullName(Log::out() ); + Log::out() << std::endl; + } +#endif + } + return; + } + if (inst->getOpcode()==Op_TauLdInd || inst->getOpcode()==Op_LdVar) { // ldind,ldvar + Opnd *dst = inst->getDst(); + CnGNode* n = findCnGNode_op(dst->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out()<< text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out()); + Log::out()<< std::endl; + } +#endif + } + } + switch (inst->getOpcode()) { + case Op_LdRef: // ldstr + case Op_NewObj: // newobj + case Op_NewArray: // newarray + case Op_NewMultiArray: // newmultiarray + case Op_DefArg: // defarg + { + CnGNode* n = findCnGNode_in(inst->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out() ); + Log::out() << std::endl; + // if (getEscState(n) == GLOBAL_ESCAPE) + // return; + } +#endif + } + break; + } + default: + break; + } + scannedObjs->push_back(inst->getId()); + for (uint32 i=0; i<nsrc; i++) { + inst1 = inst->getSrc(i)->getInst(); + findObject(inst1,text+" "); + } + scannedObjs->pop_back(); +} // findObject(Inst* inst,std::string text) + + +/* +* Finds (prints) origin objects of monitor instruction operand. +*/ +void +EscAnalyzer::findObject1(Inst* inst,std::string text) { + Inst* inst1; + uint32 nsrc=inst->getNumSrcOperands(); + + if (scannedObjs->size()!=0) { + if (checkScannedObjs(inst->getId())) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "instId " << inst->getId() + << " . . . " << std::endl; + } +#endif + return; + } + } +#ifdef _DEBUG + if (_seinfo) { + Log::out() << text; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (inst->getOpcode()==Op_DirectCall || inst->getOpcode()==Op_IndirectMemoryCall) { + Opnd *returnOpnd = inst->getDst(); + if (returnOpnd != NULL) { + CnGNode* n = findCnGNode_op(returnOpnd->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out()<< text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out()); + Log::out()<< std::endl; + } +#endif + } + } + if (inst->getOpcode()==Op_IndirectMemoryCall) { +#ifdef _DEBUG + MethodDesc* md = inst->getSrc(0)->getInst()->asMethodInst()->getMethodDesc(); + if (_seinfo) { + Log::out() << text << " "; + if (Log::isEnabled()) + md->printFullName(Log::out() ); + Log::out() << std::endl; + } +#endif + } + return; + } + if (inst->getOpcode()==Op_TauLdInd || inst->getOpcode()==Op_LdVar) { // ldind,ldvar + Opnd *dst = inst->getDst(); + CnGNode* n = findCnGNode_op(dst->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out()<< text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out()); + Log::out()<< std::endl; + } +#endif + } + } + switch (inst->getOpcode()) { + case Op_LdRef: // ldstr + case Op_NewObj: // newobj + case Op_NewArray: // newarray + case Op_NewMultiArray: // newmultiarray + case Op_DefArg: // defarg + { + CnGNode* n = findCnGNode_in(inst->getId()); + if (n != NULL) { +#ifdef _DEBUG + if (_seinfo) { + Log::out() << text << " "; + if (Log::isEnabled()) + printCnGNode(n,Log::out() ); + Log::out() << std::endl; + } +#endif + } + break; + } + default: + break; + } + scannedObjs->push_back(inst->getId()); + switch (inst->getOpcode()) { + case Op_TauLdInd: // ldind + case Op_AddScaledIndex: // addindex + inst1 = inst->getSrc(0)->getInst(); + findObject1(inst1,text+" "); + break; + case Op_TauStInd: // stind + for (uint32 i=0; i<2; i++) { + inst1 = inst->getSrc(i)->getInst(); + findObject1(inst1,text+" "); + } + break; + default: + for (uint32 i=0; i<nsrc; i++) { + inst1 = inst->getSrc(i)->getInst(); + findObject1(inst1,text+" "); + } + } + scannedObjs->pop_back(); +} // findObject1(Inst* inst,std::string text) + + +void +EscAnalyzer::markNotEscInsts() { + CnGNodes::iterator it; + bool p2 = false; + StlMap<uint32, uint32> nonEscInsts(eaMemManager); + typedef ::std::pair <uint32,uint32> intPair; + + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType == NT_OBJECT && getEscState(*it) > GLOBAL_ESCAPE) { + nonEscInsts.insert(intPair((*it)->instrId,getFullState(*it))); + } + } + if (p2 && Log::isEnabled()) { + Log::out() << "================ > "; + irManager.getMethodDesc().printFullName(Log::out()); + Log::out() << std::endl; + } +} // markNotEscInsts() + + +/* +* Summarizes common number of objects with the same state. +* Prints statictics if required. +*/ +void +EscAnalyzer::createdObjectInfo() { + CnGNodes::iterator it; + int n0 = 0; + int n_ge = 0; + int n_ae = 0; + int n_ne = 0; + uint32 state = 0; + + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType == NT_OBJECT) { + n0++; + state = getEscState(*it); + if (state == GLOBAL_ESCAPE) + n_ge++; + if (state == ARG_ESCAPE) + n_ae++; + if (state == NO_ESCAPE) + n_ne++; + } + } + if (_printstat==1) { + Log::out() << "************** Created object info: "; + if (Log::isEnabled()) + mh.printFullName(Log::out()); + Log::out() << std::endl; + Log::out() << " Number of created objects: " << n0 << std::endl; + if (n0>0) { + Log::out() << " Global escaped objects: " << n_ge << std::endl; + Log::out() << " Arg. escaped objects: " << n_ae << std::endl; + Log::out() << " Non escaped objects: " << n_ne << std::endl; + } + Log::out() << "************** " << std::endl; + } + + comObjStat._n0+=n0; + comObjStat._n_ge+=n_ge; + comObjStat._n_ae+=n_ae; + comObjStat._n_ne+=n_ne; + + if (_printstat==1) { + Log::out() << "************** Common created object info " << std::endl; + Log::out() << " Number of created objects: " << comObjStat._n0 << std::endl; + Log::out() << " Global escaped objects: " << comObjStat._n_ge << std::endl; + Log::out() << " Arg. escaped objects: " << comObjStat._n_ae << std::endl; + Log::out() << " Non escaped objects: " << comObjStat._n_ne << std::endl; + Log::out() << " Objects in loop: " << comObjStat._n_lo << std::endl; + Log::out() << "************** " << std::endl; + } +} // createdObjectInfo() + + +void +EscAnalyzer::saveScannedMethodInfo() { + CnGNodes::iterator it; + MethodDesc* mdesc = &irManager.getMethodDesc(); + MemoryManager& globalMM = irManager.getCurrentJITContext()->getGlobalMemoryManager(); + const char* ch1 = mdesc->getParentType()->getName(); + const char* ch2 = mdesc->getName(); + const char* ch3 = mdesc->getSignatureString(); + if (calledMethodInfos==NULL) { + calledMethodInfosLock.lock(); + if (calledMethodInfos==NULL) + calledMethodInfos = new (globalMM) CalledMethodInfos(globalMM); + calledMethodInfosLock.unlock(); + } else { + CalledMethodInfo* mtdInfo = getMethodInfo(ch1,ch2,ch3); + if (mtdInfo!=NULL) + return; // already saved for global analyzed method + } + if (getMethodInfo(ch1,ch2,ch3)!=NULL) // info was saved by another jit + return; + + calledMethodInfosLock.lock(); // Lock to save method info in common memory + + if (getMethodInfo(ch1,ch2,ch3)!=NULL) { // already saved by another jit + calledMethodInfosLock.unlock(); // Unlock + return; + } + + CalledMethodInfo* minfo = new (globalMM) CalledMethodInfo; + char* mpname=new (globalMM) char[strlen(ch1)+1]; + strcpy(mpname,ch1); + char* mname=new (globalMM) char[strlen(ch2)+1]; + strcpy(mname,ch2); + char* msig=new (globalMM) char[strlen(ch3)+1]; + strcpy(msig,ch3); + MemberIdent* mident = new (globalMM) MemberIdent; + mident->parentName=mpname; + mident->name=mname; + mident->signature=msig; + minfo->methodIdent=mident; + uint32 numpar = mdesc->getMethodSig()->getNumParams(); + minfo->numberOfArgs=numpar; + ParamInfos* prminfos = new (globalMM) ParamInfos(globalMM); + minfo->paramInfos=prminfos; + minfo->retValueState=0; + if (mdesc->getMethodSig()->getReturnType()->isReference()) { + uint32 escstate = 3, bitstate = 0; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++) { + if ((*it)->nodeType==NT_EXITVAL) { + bitstate = bitstate|getCalleeEscaped(*it); + if (escstate > getEscState(*it)) + escstate=getEscState(*it); + } + } + minfo->retValueState=escstate|bitstate; + } + bool pmt = checkMonitorsOnThis(); + minfo->mon_on_this = pmt; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++) { + if ((*it)->nodeType==NT_DEFARG) { + ParamInfo* prminfo = new (globalMM) ParamInfo; + prminfo->state=getFullState(*it); + prminfo->paramNumber=(*it)->argNumber; + prminfos->push_back(prminfo); + } + } + calledMethodInfos->push_back(minfo); + + calledMethodInfosLock.unlock(); // Unlock + +#ifdef _DEBUG + if (_scanMtds==1) { + ParamInfos::iterator it2; + Log::out() << "==== ===== calledMethodInfo " << std::endl; + Log::out() << minfo->methodIdent->parentName << " "; + Log::out() << minfo->methodIdent->name << " "; + Log::out() << minfo->methodIdent->signature << " "; + Log::out() << minfo->numberOfArgs<< " " << std::endl; + for (it2 = minfo->paramInfos->begin( ); it2 != minfo->paramInfos->end( ); it2++) { + Log::out() << (*it2)->paramNumber << " st." + << (*it2)->state << std::endl; + } + Log::out() << "==== end ===== calledMethodInfo " << std::endl; + } +#endif +} // saveScannedMethodInfo(MemoryManager& mm) + + +void +EscAnalyzer::printMethodInfos() { + CalledMethodInfos::iterator it1; + ParamInfos::iterator it2; + Log::out() << "==== debug ===== calledMethodInfos; " << std::endl; + if (calledMethodInfos==NULL) + Log::out() << " calledMethodInfos is NULL " << std::endl; + if (calledMethodInfos!=NULL) + for (it1 = calledMethodInfos->begin( ); it1 != calledMethodInfos->end( ); it1++) { + Log::out() << (*it1)->methodIdent->parentName << " "; + Log::out() << (*it1)->methodIdent->name << " "; + Log::out() << (*it1)->methodIdent->signature << " "; + Log::out() << (*it1)->numberOfArgs<< " " << std::endl; + for (it2 = (*it1)->paramInfos->begin( ); + it2 != (*it1)->paramInfos->end( ); it2++) { + Log::out() << (*it2)->paramNumber << " st." + << (*it2)->state << std::endl; + } + } + Log::out() << "==== end ===== calledMethodInfos; " << std::endl; +} // printMethodInfos() + + +void +EscAnalyzer::printMethodInfo(CalledMethodInfo* mi) { + ParamInfos::iterator it2; + Log::out() << "==== debug ===== calledMethodInfo " << std::endl; + if (mi==NULL) + Log::out() << " calledMethodInfo is NULL " << std::endl; + else { + Log::out() << mi->methodIdent->parentName << " "; + Log::out() << mi->methodIdent->name << " "; + Log::out() << mi->methodIdent->signature << " "; + Log::out() << "Number of parameters: " << mi->numberOfArgs<< " " << std::endl; + for (it2 = mi->paramInfos->begin( ); it2 != mi->paramInfos->end( ); it2++) { + Log::out() << (*it2)->paramNumber << " st."; + if (Log::isEnabled()) + printState((*it2)->state); + Log::out() << std::endl; + } + Log::out() << "Return value state: "; + printState(mi->retValueState); + Log::out() << " " << std::endl; + } + Log::out() << "==== end ===== calledMethodInfo " << std::endl; +} // printMethodInfos(CalledMethodInfo* mi) + + +void +EscAnalyzer::scanCalleeMethod(Inst* call) { + MethodDesc* methodDesc = 0; + +#ifdef _DEBUG + if (_scanMtds==1) { + Log::out() << "=="; + if (Log::isEnabled()) + call->print(Log::out()); + Log::out() << std::endl; + } +#endif + if (call == NULL) { // scanned Op_DirectCall, not scanned Op_IndirectMemoryCall + Log::out() << "scanMethod: NULL" << std::endl; + return; + } + methodDesc = call->asMethodCallInst()->getMethodDesc(); + +#ifdef _DEBUG + if (_scanMtds==1) { + Log::out() << std::endl; + Log::out() << "scanMethod: " << methodDesc->getParentType()->getName() + << "." << methodDesc->getName() << methodDesc->getSignatureString() + << " " << methodDesc << std::endl; + Log::out() << " NumParams: " + << methodDesc->getMethodSig()->getNumParams()<< std::endl; + Log::out() << " isNative: " << methodDesc->isNative() << std::endl; + Log::out() << " isStatic: " << methodDesc->isStatic() << std::endl; + Log::out() << " isInstance: " << methodDesc->isInstance() << std::endl; + Log::out() << " isFinal: " << methodDesc->isFinal() << std::endl; + Log::out() << " isVirtual: " << methodDesc->isVirtual() << std::endl; + Log::out() << " isAbstract: " << methodDesc->isAbstract() << std::endl; + Log::out() << " isInstanceInitializer: " + << methodDesc->isInstanceInitializer() << std::endl; + Log::out() << " isOverridden: " << methodDesc->isOverridden() << std::endl; + Log::out() << " isJavaByteCodes: " << methodDesc->isJavaByteCodes() << std::endl; + } +#endif + + OpndManager& _opndManager(irManager.getOpndManager()); + Opnd *returnOpnd = 0; + if(call->getDst()->isNull()) + returnOpnd = _opndManager.getNullOpnd(); + else + returnOpnd = _opndManager.createSsaTmpOpnd(call->getDst()->getType()); + + IRManager* inlinedIRM = new (eaMemManager) IRManager(irManager.getMemoryManager(), irManager, *methodDesc, returnOpnd); + DrlVMCompilationInterface& ci= (DrlVMCompilationInterface&)inlinedIRM->getCompilationInterface(); + bool cibcmap = ci.isBCMapInfoRequired(); + if (cibcmap) { + ci.setBCMapInfoRequired(false); + } + + CompilationContext inlineCC(irManager.getMemoryManager(), &ci, ci.getCompilationContext()->getCurrentJITContext()); + inlineCC.setHIRManager(inlinedIRM); + runTranslatorSession(inlineCC); + + optimizeTranslatedCode(*inlinedIRM); + + if (cibcmap) { + ci.setBCMapInfoRequired(true); + } + + EscAnalyzer ea1(this, *inlinedIRM); + ea1.doAnalysis(); + +} // scanCalleeMethod(Inst* call, MemoryManager& mm) + +void EscAnalyzer::runTranslatorSession(CompilationContext& inlineCC) { + TranslatorSession* traSession = (TranslatorSession*)translatorAction->createSession(inlineCC.getCompilationLevelMemoryManager()); + traSession->setCompilationContext(&inlineCC); + inlineCC.setCurrentSessionAction(traSession); + traSession->run(); + inlineCC.setCurrentSessionAction(NULL); +} + + +void +EscAnalyzer::optimizeTranslatedCode(IRManager& irm) { + // run ssa pass + OptPass::computeDominators(irm); + DominatorTree* dominatorTree = irm.getDominatorTree(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); + + DomFrontier frontier(irm.getNestedMemoryManager(),*dominatorTree,&flowGraph); + SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, + irm.getOptimizerFlags()); + ssaBuilder.convertSSA(irm.getMethodDesc()); + irm.setInSsa(true); + irm.setSsaUpdated(); + + // run devirt pass + Devirtualizer pass(irm); + pass.guardCallsInRegion(irm, dominatorTree); + +} // optimizeTranslatedCode(IRManager& irManager) + + +void +EscAnalyzer::setCreatedObjectStates() { + CnGNodes::iterator it; + NodeMDs::iterator it1; + + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_STFLD) { + initNodeType = NT_STFLD; +#ifdef _DEBUG + if (_setState) { + Log::out() <<"-- before scanGE: node " + <<(*it)->cngNodeId<<" opnd "<<(*it)->opndId<<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() << std::endl; + } +#endif + scanCnGNodeRefsGE(*it); + } + } + scannedObjs->clear(); + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType&NT_EXITVAL) { // returned, thrown +#ifdef _DEBUG + if (_setState) { + Log::out() <<"-- before scanEV: node " + <<(*it)->cngNodeId<<" opnd "<<(*it)->opndId<<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() << std::endl; + } +#endif + initNodeType = (*it)->nodeType; + scanCnGNodeRefsGE(*it); + } + } + scannedObjs->clear(); + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_DEFARG) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"-- before scanDA: node " + <<(*it)->cngNodeId<<" opnd "<<(*it)->opndId<<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() << std::endl; + } +#endif + initNodeType = NT_DEFARG; + scanCnGNodeRefsGE(*it); + scannedObjs->clear(); // temporary + } + } + scannedObjs->clear(); + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_ACTARG) { + curMDNode=(*it)->cngNodeId; +#ifdef _DEBUG + if (_setState) { + Log::out() <<"-- before scanAE: node " + <<(*it)->cngNodeId<<" opnd "<<(*it)->opndId<<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() << std::endl; + } +#endif + initNodeType = NT_ACTARG; + scanCnGNodeRefsAE(*it); + } + } + scannedObjs->clear(); + if (method_ea_level==0) { + DominatorTree* dominatorTree = irManager.getDominatorTree(); + if (!(dominatorTree && dominatorTree->isValid())) { + OptPass::computeDominators(irManager); + dominatorTree = irManager.getDominatorTree(); + } + if (dominatorTree && dominatorTree->isValid()) { + OptPass::computeLoops(irManager); + LoopTree* ltree = irManager.getLoopTree(); + if (ltree->isValid()) + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ( (*it)->nodeType==NT_OBJECT) { + if (ltree->getLoopHeader((*it)->fgNode,false)) { + if ((*it)->state > GLOBAL_ESCAPE) { +#ifdef _DEBUG + if (_setState) { + Log::out() + <<"--setSt loop: node " + <<(*it)->cngNodeId<<" opndId " + <<(*it)->opndId<<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() + <<" to set loop" << std::endl; + } +#endif + setLoopCreated(*it); + comObjStat._n_lo++; + } + } + } + } + } else { +#ifdef _DEBUG + mh.printFullName(Log::out()); Log::out() << std::endl; + Log::out() << "DominatorTree isn't valid " << std::endl; +#endif + } + } + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + uint32 nt = (*it)->nodeType; + if ((nt&NT_OBJECT || nt==NT_LDOBJ) && (getEscState(*it)==ARG_ESCAPE)) { + for (it1 = (*it)->nodeMDs->begin(); it1 != (*it)->nodeMDs->end(); + it1++) { + CnGNode* n=findCnGNode_id(*it1); // method argument node + assert(n!=NULL); + MethodDesc* mdesc = (MethodDesc*)n->refObj; + Inst* callInst = n->nInst; + if (mdesc->isNative()) { // not scanned native methods + if (strcmp(mdesc->getParentType()->getName(),"java/lang/VMMemoryManager")==0 + &&strcmp(mdesc->getName(),"arrayCopy")==0) { + break; // objects don't escape java/lang/VMMemoryManager::arrayCopy + } + if (strcmp(mdesc->getParentType()->getName(),"java/lang/VMClassRegistry")==0 + &&strcmp(mdesc->getName(),"getName")==0) { + break; // objects don't escape java/lang/VMClassRegistry::getName + } + if (strcmp(mdesc->getParentType()->getName(),"java/lang/VMThreadManager")==0 + &&strcmp(mdesc->getName(),"notify")==0) { + break; // objects don't escape java/lang/VMThreadManager::notify + } + setEscState(*it,GLOBAL_ESCAPE); +#ifdef _DEBUG + if (_scanMtds==1) { + if (Log::isEnabled()) + mdesc->printFullName(Log::out()); + Log::out() << std::endl; + Log::out() << " isNative: " + << mdesc->isNative() << std::endl; + } + if (_setState) { + Log::out() <<"--setSt 1: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId + <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out()<<" to gl.esc."<< std::endl; + } +#endif + break; + } + if (callInst->getOpcode()!=Op_DirectCall) { // not direct call + if (method_ea_level == 0) { + MonUnit* mu = NULL; + if (monitorInstUnits!=NULL) + mu = findMonUnit((*it)->opndId); + if (mu != NULL) { + setVirtualCall(*it); + addMonUnitVCall(mu,callInst); +#ifdef _DEBUG + if (Log::isEnabled()) { + Log::out() << "=-=-=-=- callimem for this "; + Log::out() << std::endl; + Log::out() << "=-=- "; + printCnGNode(*it,Log::out()); + Log::out() << std::endl; + printCnGNode(n,Log::out()); + Log::out() << std::endl; + callInst->print(Log::out()); + Log::out() << std::endl; + mdesc->printFullName(Log::out()); + Log::out() << std::endl; + Log::out() << "=-=-=-=- end " << std::endl; + } +#endif + continue; + } + } + + setEscState(*it,GLOBAL_ESCAPE); +#ifdef _DEBUG + if (_scanMtds==1) { + if (Log::isEnabled()) { + callInst->print(Log::out()); + Log::out() << std::endl; + mdesc->printFullName(Log::out()); + } + Log::out() << std::endl; + Log::out() << " isStatic: " + << mdesc->isStatic() << std::endl; + Log::out() << " isFinal: " + << mdesc->isFinal() << std::endl; + + Log::out() << "---------------" << std::endl; + Log::out() << " NumParams: " + << mdesc->getMethodSig()->getNumParams()<< std::endl; + Log::out() << " isNative: " + << mdesc->isNative() << std::endl; + Log::out() << " isStatic: " + << mdesc->isStatic() << std::endl; + Log::out() << " isInstance: " + << mdesc->isInstance() << std::endl; + Log::out() << " isFinal: " + << mdesc->isFinal() << std::endl; + Log::out() << " isVirtual: " + << mdesc->isVirtual() << std::endl; + Log::out() << " isAbstract: " + << mdesc->isAbstract() << std::endl; + Log::out() << " isInstanceInitializer: " + << mdesc->isInstanceInitializer() << std::endl; + Log::out() << " isOverridden: " + << mdesc->isOverridden() << std::endl; + Log::out() << " isJavaByteCodes: " + << mdesc->isJavaByteCodes() << std::endl; + + } + if (_setState) { + Log::out() <<"--setSt 2: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId + <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc." + << std::endl; + } +#endif + break; + } + + CalledMethodInfo* mtdInfo = findMethodInfo(mdesc,callInst); + if (mtdInfo == NULL) { // no info about called method + setEscState(*it,GLOBAL_ESCAPE); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setSt 3: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId + <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc." + << std::endl; + } +#endif + break; + } else { // to use info about scanned method + uint32 narg = n->argNumber; + ParamInfos::iterator it2; + uint32 state = 0; +#ifdef _DEBUG + if (_setState) { + Log::out() << "--setSt cmi: method " + << mtdInfo->methodIdent->parentName << "::" + << mtdInfo->methodIdent->name << " " + << mtdInfo->methodIdent->signature << std::endl; + } +#endif + for (it2 = mtdInfo->paramInfos->begin( ); + it2 != mtdInfo->paramInfos->end( ); it2++) { +#ifdef _DEBUG + if (_setState) { + Log::out() + <<(*it2)->paramNumber<<" == "<<narg<<" state " + <<(*it2)->state <<" < "<< getEscState(*it)<<" "; + if (Log::isEnabled()) + printState(*it); + Log::out() << std::endl; + } +#endif + if ((*it2)->paramNumber == narg) { //???to add scanning of contained obj + if ((state=(*it2)->state&ESC_MASK) < getEscState(*it)) { +#ifdef _DEBUG + if (_setState) { + Log::out()<<"--setSt cmi1: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId + <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to state " + <<state<< std::endl; + } +#endif + setEscState(*it,state); + } + } + } + } + } + if (getEscState(*it)==GLOBAL_ESCAPE) { // to set gl.escape for contained objects + scanCnGNodeRefsGE(*it); //??? to set initNodeType? + scannedObjs->clear(); + } + } + } + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + uint32 nt = (*it)->nodeType; + if ((nt&NT_RETVAL) && getEscState(*it)>GLOBAL_ESCAPE) { + if (nt==NT_CATCHVAL || ((*it)->nInst->getOpcode())==Op_IndirectMemoryCall) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 1: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc."<< std::endl; + } +#endif + setEscState(*it,GLOBAL_ESCAPE); + continue; + } + MethodDesc* mdesc = (*it)->nInst->asMethodInst()->getMethodDesc(); + if (mdesc->isNative()) { // not scanned native methods +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 2: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc."<< std::endl; + } +#endif + setEscState(*it,GLOBAL_ESCAPE); + continue; + } + if (((*it)->nInst->getOpcode())!=Op_DirectCall) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 3: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc."<< std::endl; + } +#endif + setEscState(*it,GLOBAL_ESCAPE); + continue; + } + CalledMethodInfo* mthInfo = findMethodInfo(mdesc,(*it)->nInst); + if (mthInfo == NULL) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 4: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to gl.esc."<< std::endl; + } +#endif + setEscState(*it,GLOBAL_ESCAPE); + } else { + if (getEscState(*it)>((mthInfo->retValueState)&ESC_MASK)) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 5: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to "<< mthInfo->retValueState<< std::endl; + } +#endif + setEscState(*it,(mthInfo->retValueState)&ESC_MASK); + } + } + } + } + + uint32 rs = NO_ESCAPE; + CnGRefs::iterator it2; + CnGNode* cgn; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++) { + if ((*it)->nodeType==NT_EXITVAL) { + if ((*it)->outEdges ==NULL) + continue; + for (it2 = (*it)->outEdges->begin( ); it2 != (*it)->outEdges->end( ); it2++ ) { + cgn = (*it2)->cngNodeTo; + rs = getSubobjectStates(cgn); + if (getEscState(cgn)<=(rs&ESC_MASK)) + rs = getFullState(cgn); + } +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--setCOS 6: node " + <<(*it)->cngNodeId<<" opndId "<<(*it)->opndId <<" state "; + if (Log::isEnabled()) + printState(*it); + Log::out() <<" to "<< rs << std::endl; + } +#endif + setFullState(*it,rs); + + } + scannedObjs->clear(); + } + + +} // setCreatedObjectStates(MemoryManager& mm) + + +uint32 +EscAnalyzer::getSubobjectStates(CnGNode* node) { + uint32 st = NO_ESCAPE, rs; + CnGRefs::iterator it; + CnGNode* cgn; + + if (scannedObjs->size()!=0) { + if (checkScannedObjs(node->cngNodeId)) + return st; + } + if (node->outEdges==NULL) + return st; + for (it = node->outEdges->begin( ); it != node->outEdges->end( ); it++ ) { + cgn = (*it)->cngNodeTo; +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--getSOS : node " + <<cgn->cngNodeId<<" opndId "<<cgn->opndId <<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() << std::endl; + } +#endif + if (st > getEscState(cgn)) + st = getEscState(cgn); + if (st == GLOBAL_ESCAPE) + return st; + scannedObjs->push_back(node->cngNodeId); + rs = getSubobjectStates(cgn); + scannedObjs->pop_back(); + if (st > rs) + st = rs; + if (st == GLOBAL_ESCAPE) + return st; + } + return st; +} + + +EscAnalyzer::CalledMethodInfo* +EscAnalyzer::getMethodInfo(const char* ch1,const char* ch2,const char* ch3) { + CalledMethodInfos::iterator it; + if (calledMethodInfos==NULL) + return NULL; + for (it = calledMethodInfos->begin( ); it != calledMethodInfos->end( ); it++ ) { + const char* c1 = (*it)->methodIdent->parentName; + const char* c2 = (*it)->methodIdent->name; + const char* c3 = (*it)->methodIdent->signature; + if (strcmp(c1,ch1)==0 && strcmp(c2,ch2)==0 && strcmp(c3,ch3)==0) + return (*it); + } + return NULL; +} // getMethodInfo(const char* ch1,const char* ch2,const char* ch3) + + +EscAnalyzer::CalledMethodInfo* +EscAnalyzer::findMethodInfo(MethodDesc* mdesc,Inst* callInst) { + const char* ch1 = mdesc->getParentType()->getName(); + const char* ch2 = mdesc->getName(); + const char* ch3 = mdesc->getSignatureString(); + CalledMethodInfo* mtdInfo = getMethodInfo(ch1,ch2,ch3); + if (mtdInfo == NULL) { +#ifdef _DEBUG + if (_scanMtds==1) { + Log::out() << " = = = = = = = = To scan method " << std::endl; + if (Log::isEnabled()) { + mdesc->printFullName(Log::out()); + Log::out() << std::endl; + callInst->print(Log::out()); + } + Log::out() << std::endl; + } +#endif + if (method_ea_level < maxMethodExamLevel) { + scanCalleeMethod(callInst); + mtdInfo=getMethodInfo(ch1,ch2,ch3); + } + } + return mtdInfo; +} // findMethodInfo(MethodDesc* mdesc) + + +/* +* Finds specified parameter in specified method info. +* Returns: +* state - for existent parameter, +* 0 - for another cases. +*/ +uint32 +EscAnalyzer::getMethodParamState(CalledMethodInfo* mi, uint32 np) { + ParamInfos::iterator it; + uint32 st = 0; + if (mi==NULL) + return 0; + for (it = mi->paramInfos->begin( ); it != mi->paramInfos->end( ); it++) { + if ((*it)->paramNumber == np) { + st = (*it)->state; + return st; + } + } + return st; +} // getMethodParamState(CalledMethodInfo* mi, uint32 np) + + +void +EscAnalyzer::printCreatedObjectsInfo(::std::ostream& os) { + CnGNodes::iterator it; + NodeMDs::iterator it1; + os << "================ Created Object States < "; + irManager.getMethodDesc().printFullName(os); + os << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType & NT_OBJECT || (*it)->nodeType==NT_LDOBJ) { + printCnGNode(*it,os); + ((Opnd*)(*it)->refObj)->printWithType(os); + if (getEscState(*it)==ARG_ESCAPE) { + for (it1 = (*it)->nodeMDs->begin(); it1 != (*it)->nodeMDs->end(); it1++) { + CnGNode* n=findCnGNode_id(*it1); + assert(n!=NULL); + os << std::endl; os <<" "; + printCnGNode(n,os); + os << std::endl; os <<" "; + ((MethodDesc*)n->refObj)->printFullName(os); + } + } + os << std::endl; + os << " =="; ((Opnd*)(*it)->refObj)->getInst()->print(os); + os << std::endl; + } + } + os << "================ > " ; + irManager.getMethodDesc().printFullName(os); + os << std::endl; +} // printCreatedObjectsInfo(::std::ostream& os) + + +void +EscAnalyzer::scanCnGNodeRefsGE(CnGNode* cgn) { +// CnGEdges* cge = cngEdges; + CnGEdges::iterator it; + CnGRefs::iterator it1; + uint32 nscan=0; + if (scannedObjs->size()!=0) { + if (checkScannedObjs(cgn->cngNodeId)) + return; + } +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanGE 1: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" " + << nodeTypeToString(cgn) << cgn->nodeType << std::endl; + } +#endif + if (cgn->nodeType&NT_OBJS) { + if (initNodeType!=NT_EXITVAL && initNodeType!=NT_DEFARG) { // + if (getEscState(cgn) > GLOBAL_ESCAPE) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanGE 2: node " + <<cgn->cngNodeId<<" opndId "<<cgn->opndId <<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" to gl.esc."<< std::endl; + Log::out() <<"--scanGE 2: "<< nodeTypeToString(cgn) + << cgn->nodeType <<" initNode "<<initNodeType<< std::endl; + } +#endif + setEscState(cgn,GLOBAL_ESCAPE); + } + } + if (initNodeType==NT_EXITVAL) { + if (getCalleeEscaped(cgn) == 0) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanGE 3: node " + <<cgn->cngNodeId<<" opndId "<<cgn->opndId <<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" to callee.esc."<< std::endl; + Log::out() <<"--scanGE 3: "<< nodeTypeToString(cgn) + << cgn->nodeType <<" initNode "<<initNodeType<< std::endl; + } +#endif + setCalleeEscaped(cgn); + } + // The objects created in the method are not global escaped through return + } + if (initNodeType==NT_DEFARG) { + if (getCalleeEscaped(cgn) == 0) { +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanGE 5: node " + <<cgn->cngNodeId<<" opndId "<<cgn->opndId <<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" to callee.esc."<< std::endl; + Log::out() <<"--scanGE 5: "<< nodeTypeToString(cgn) + << cgn->nodeType <<" initNode "<<initNodeType<< std::endl; + } +#endif + setCalleeEscaped(cgn); + } + } + } + scannedObjs->push_back(cgn->cngNodeId); + if (cgn->outEdges != NULL) { + for (it1 = cgn->outEdges->begin( ); it1 != cgn->outEdges->end( ); it1++ ) { + scanCnGNodeRefsGE(findCnGNode_id((*it1)->cngNodeTo->cngNodeId)); + if ((*it1)->edgeType!=ET_POINT) + nscan++; + } + } +#ifdef _DEBUG + if (_setState) { + Log::out()<<"--scanGE 6: nscan "<<nscan<<" opndId "<<cgn->opndId<<std::endl; + } +#endif + if (cgn->nodeType==NT_ARRELEM && nscan==0) { + Inst* inst_ldbase= ((Opnd*)(cgn->refObj))->getInst()->getSrc(0)->getInst(); + CnGNode* cgnode=findCnGNode_op(inst_ldbase->getSrc(0)->getId()); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanGE arrElem: "; + if (Log::isEnabled()) + inst_ldbase->print(Log::out()); + Log::out() << std::endl; + Log::out() <<"--scanGE next: " << cgnode->cngNodeId << " - " + << cgnode->opndId << std::endl; + } +#endif + scanCnGNodeRefsGE(cgnode); + } + if (cgn->nodeType==NT_LDOBJ && nscan==0) { + Inst* ldinst =((Opnd*)(cgn->refObj))->getInst(); + if (ldinst->getOpcode()==Op_TauLdInd) { //tttt + Inst* inst_fldaddr= ldinst->getSrc(0)->getInst(); + if (inst_fldaddr->getOpcode()==Op_LdFieldAddr) { + CnGNode* cgnode=findCnGNode_fl(inst_fldaddr,NT_INSTFLD); +#ifdef _DEBUG + if (_setState) { + Log::out() << "TO FIND 1 for opnd " + << cgn->opndId << std::endl; + if (Log::isEnabled()) + ldinst->print(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + inst_fldaddr->print(Log::out()); + Log::out() << std::endl; + Log::out() << cgn->cngNodeId << "-" + << cgn->opndId << " -> "; + Log::out() << cgnode->cngNodeId << "-" + << cgnode->opndId << std::endl; + } +#endif + scanCnGNodeRefsGE(cgnode); + } else { + if (inst_fldaddr->getOpcode()==Op_AddScaledIndex) { + CnGNode* cgnode=findCnGNode_op(ldinst->getSrc(0)->getId()); +#ifdef _DEBUG + if (_setState) { + Log::out() << "TO FIND 2 for opnd " + << cgn->opndId << std::endl; + if (Log::isEnabled()) + ldinst->print(Log::out()); + Log::out() << std::endl; + if (Log::isEnabled()) + inst_fldaddr->print(Log::out()); + Log::out() << std::endl; + Log::out() << cgn->cngNodeId << "-" + << cgn->opndId << " -> "; + Log::out() << cgnode->cngNodeId << "-" + << cgnode->opndId << std::endl; + } +#endif + scanCnGNodeRefsGE(cgnode); + } + } + } + } +} // scanCnGNodeRefsGE(CnGNode* cgn) + + +void +EscAnalyzer::scanCnGNodeRefsEV(CnGNode* cgn) { + CnGRefs::iterator it1; + if (scannedObjs->size()!=0) { + if (checkScannedObjs(cgn->cngNodeId)) + return; + } +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanEV: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId <<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() << " " + << nodeTypeToString(cgn) << cgn->nodeType << std::endl; + } +#endif + if (cgn->nodeType==NT_OBJECT) // object is escaped if it is returned + if (getEscState(cgn) > GLOBAL_ESCAPE) { + setEscState(cgn,GLOBAL_ESCAPE); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanEV: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" to gl.esc."<< std::endl; + } +#endif + } + scannedObjs->push_back(cgn->cngNodeId); + if (cgn->outEdges != NULL) { + for (it1 = cgn->outEdges->begin( ); it1 != cgn->outEdges->end( ); it1++ ) { + scanCnGNodeRefsGE(findCnGNode_id((*it1)->cngNodeTo->cngNodeId)); + } + } +} // scanCnGNodeRefsEV(CnGNode* cgn) + + +void +EscAnalyzer::scanCnGNodeRefsDA(CnGNode* cgn) { + CnGEdges* cge = cngEdges; + CnGEdges::iterator it; + CnGRefs::iterator it1; + uint32 cgntype=cgn->nodeType; + bool first=true; + if (scannedObjs->size()!=0) { + first=false; + if (checkScannedObjs(cgn->cngNodeId)) + return; + } +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanDA: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" "<<nodeTypeToString(cgn)<<cgn->nodeType<< std::endl; + } +#endif + if ((cgntype&NT_OBJECT && !first)||(cgntype==NT_OBJECT && first)) + scannedObjs->push_back(cgn->cngNodeId); + for (it = cge->begin( ); it != cge->end( ); it++ ) { + if ((*it)->cngNodeFrom == cgn) { + for (it1 = (*it)->refList->begin( ); it1 != (*it)->refList->end( ); it1++ ) { + scanCnGNodeRefsGE(findCnGNode_id((*it1)->cngNodeTo->cngNodeId)); + } + } + } +} // scanCnGNodeRefsDA(CnGNode* cgn) + + +void +EscAnalyzer::scanCnGNodeRefsAE(CnGNode* cgn) { + CnGEdges* cge = cngEdges; + CnGEdges::iterator it; + CnGRefs::iterator it1; + uint32 nscan=0; + if (scannedObjs->size()!=0) { + if (checkScannedObjs(cgn->cngNodeId)) + return; + } +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanAE: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" " << nodeTypeToString(cgn) <<cgn->nodeType<< std::endl; + } +#endif + if (cgn->nodeType&NT_OBJS) + if (getEscState(cgn) >= ARG_ESCAPE) { + setEscState(cgn,ARG_ESCAPE); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanAE: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" to arg.esc."<< std::endl; + } +#endif + if (cgn->nodeMDs==NULL) { + Log::out() <<"--scanAE: node "<<cgn->cngNodeId + <<" opndId "<<cgn->opndId<<" state "; + if (Log::isEnabled()) + printState(cgn); + Log::out() <<" " << nodeTypeToString(cgn) + << cgn->nodeType << std::endl; + } + cgn->nodeMDs->push_back(curMDNode); + } + scannedObjs->push_back(cgn->cngNodeId); + for (it = cge->begin( ); it != cge->end( ); it++ ) { + if ((*it)->cngNodeFrom == cgn) { + for (it1 = (*it)->refList->begin( ); it1 != (*it)->refList->end( ); it1++ ) { + if ((*it1)->edgeType==ET_FIELD) // do not scan field edge + continue; + scanCnGNodeRefsAE(findCnGNode_id((*it1)->cngNodeTo->cngNodeId)); + if ((*it1)->edgeType!=ET_POINT) + nscan++; + } + } + } + if (cgn->nodeType==NT_ARRELEM && nscan==0) { + Inst* inst_addindex = ((Opnd*)(cgn->refObj))->getInst(); + Inst* inst_ldbase = inst_addindex->getSrc(0)->getInst(); + if (inst_addindex->getOpcode() == Op_LdArrayBaseAddr) + inst_ldbase = inst_addindex; + CnGNode* cgnode=findCnGNode_op(inst_ldbase->getSrc(0)->getId()); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"--scanAE check1: "; + if (Log::isEnabled()) + inst_ldbase->print(Log::out()); + Log::out() << std::endl; + Log::out() <<"--scanAE check2: "; + if (cgnode==NULL) + Log::out() <<"cngnode==null "<< std::endl; + Inst* inst_addindex= ((Opnd*)(cgn->refObj))->getInst(); + Log::out() <<"--scanAE arrElem: "; + if (Log::isEnabled()) + inst_addindex->print(Log::out()); + Log::out() << std::endl; + Log::out() <<"--scanAE arrElem: "; + if (Log::isEnabled()) + inst_ldbase->print(Log::out()); + Log::out() << std::endl; + Log::out() <<"--scanAE next: " << cgnode->cngNodeId << " - " + << cgnode->opndId << std::endl; + } +#endif + scanCnGNodeRefsAE(cgnode); + } + if (cgn->nodeType==NT_LDOBJ && nscan==0) { + Inst* ldinst =((Opnd*)(cgn->refObj))->getInst(); + if (ldinst->getOpcode()==Op_TauLdInd) { + CnGNode* cgnode=findCnGNode_op(ldinst->getSrc(0)->getId()); +#ifdef _DEBUG + if (_setState) { + Log::out() <<"TO FIND for opnd " + << cgn->opndId << std::endl; + if (Log::isEnabled()) + ldinst->print(Log::out()); + Log::out() << std::endl; + Log::out() << cgn->cngNodeId << "-" + << cgn->opndId << " -> "; + Log::out() << cgnode->cngNodeId << "-" + << cgnode->opndId << std::endl; + } +#endif + scanCnGNodeRefsAE(cgnode); + } + } + if ((cgn->nodeType==NT_INSTFLD) && nscan==0) { //???????? + if (getEscState(cgn) > ARG_ESCAPE) + setEscState(cgn,ARG_ESCAPE); // for instance fields of method parameters & array elements + } + scannedObjs->pop_back(); +} // scanCnGNodeRefsAE(CnGNode* cgn) + + +bool +EscAnalyzer::checkScannedObjs(uint32 id) { + ObjIds::iterator it; + for (it = scannedObjs->begin( ); it != scannedObjs->end( ); it++ ) { + if ((*it)==id) { + return true; + } + } + return false; +} // checkScannedObjs(CnGNode* cgn) + + +bool +EscAnalyzer::checkScannedInsts(uint32 id) { + ObjIds::iterator it; + for (it = scannedInsts->begin( ); it != scannedInsts->end( ); it++ ) { + if ((*it)==id) { + return true; + } + } + return false; +} // checkScannedInsts(CnGNode* cgn) + + +bool +EscAnalyzer::checkScannedSucNodes(uint32 id) { + ObjIds::iterator it; + for (it = scannedSucNodes->begin( ); it != scannedSucNodes->end( ); it++ ) { + if ((*it)==id) { + return true; + } + } + return false; +} // checkScannedSucNodes(CnGNode* cgn) + + +void +EscAnalyzer::printRefInfo(::std::ostream& os) { + CnGNodes::iterator it; + os << "================ Static Fields" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_STFLD) { + printCnGNodeRefs(*it, "", os); + } + } + scannedObjs->clear(); + os << "================ Method Agruments" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_ACTARG) { + printCnGNodeRefs(*it, "", os); + } + } + scannedObjs->clear(); + os << "================ Return Values" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_EXITVAL) { + printCnGNodeRefs(*it, "", os); + } + } + scannedObjs->clear(); + os << "================ Thrown Values" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_THRVAL) { + printCnGNodeRefs(*it, "", os); + } + } + scannedObjs->clear(); + os << "================ Instsnce Fields" << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==NT_INSTFLD) { + printCnGNodeRefs(*it, "", os); + } + } + scannedObjs->clear(); +} // printRefInfo(::std::ostream& os) + + +void +EscAnalyzer::what_inst(Inst* inst,::std::ostream& os) { + if (inst->asCallInst()) + os << " CallInst" << std::endl; + if (inst->asFieldAccessInst()) { + os << " FieldAccessInst" << std::endl; + FieldAccessInst* fai=inst->asFieldAccessInst(); + FieldDesc* fd=fai->getFieldDesc(); + Type* tt=fd->getFieldType(); + os << " isInitOnly " << fd->isInitOnly() << std::endl; + os << " isVolatile " << fd->isVolatile() << std::endl; + os << " isLiteral " << fd->isLiteral() << std::endl; + os << " isUnmanagedStatic " << fd->isUnmanagedStatic() << std::endl; + os << " fldT " << tt->getName() <<" "<< tt->tag<< std::endl; + os << " isObject " << tt->isObject() << std::endl; + os << " isRef " << tt->isReference()<< std::endl; + if (tt->isReference()) { + ref_type_info(tt,os); + } + os << " getName " << fd->getName() << std::endl; + os << " signature " << fd->getSignatureString() << std::endl; + os << " parentType " << fd->getParentType()->getName() << std::endl; + os << " getId " << fd->getId() << std::endl; + os << " isPrivate " << fd->isPrivate() << std::endl; + os << " isStatic " << fd->isStatic() << std::endl; + os << " "; + fd->printFullName(os); + os << std::endl; + } + if (inst->asIntrinsicCallInst()) + os << " IntrinsicCallInst" << std::endl; + if (inst->asMethodCallInst()) + os << " MethodCallInst" << std::endl; + if (inst->asMultiSrcInst()) + os << " MultiSrcInst" << std::endl; + if (inst->asVarAccessInst()) { + os << " VarAccessInst" << std::endl; + if (inst->asVarAccessInst()->getVar()!=NULL) { + os << " Var: "; + inst->asVarAccessInst()->getVar()->print(os);os << std::endl; + os << " "; + inst->asVarAccessInst()->getVar()->printWithType(os);os<< std::endl; + } + if (inst->asVarAccessInst()->getBaseVar()!=NULL) { + os << " BaseVar: "; + inst->asVarAccessInst()->getBaseVar()->print(os);os << std::endl; + os << " "; + inst->asVarAccessInst()->getBaseVar()->printWithType(os);os << std::endl; + } + } + if (inst->asBranchInst()) + os << " BranchInst" << std::endl; + if (inst->asCatchLabelInst()) + os << " CatchLabelInst" << std::endl; + if (inst->asConstInst()) + os << " ConstInst" << std::endl; + if (inst->asDispatchLabelInst()) + os << " DispatchLabelInst" << std::endl; + if (inst->asLabelInst()) + os << " LabelInst" << std::endl; + if (inst->asMethodEntryInst()) + os << " MethodEntryInst" << std::endl; + if (inst->asMethodInst()) { + os << " MethodInst" << std::endl; + MethodDesc* md=inst->asMethodInst()->getMethodDesc(); + os << " isNative " << md->isNative() << std::endl; + os << " isSynchronized " << md->isSynchronized() << std::endl; + os << " isStatic " << md->isStatic() << std::endl; + os << " isInstsnce " << md->isInstance() << std::endl; + os << " isFinal " << md->isFinal() << std::endl; + os << " isVirtual " << md->isVirtual() << std::endl; + os << " isAbstract " << md->isAbstract() << std::endl; + os << " isClassInitializer " << md->isClassInitializer() << std::endl; + os << " isInstanceInitializer " << md->isInstanceInitializer() << std::endl; + os << " isInitLocals " << md->isInitLocals() << std::endl; + os << " isOverridden " << md->isOverridden() << std::endl; + os << " isJavaByteCodes " << md->isJavaByteCodes() << std::endl; + os << " Name " << md->getName() << std::endl; + os << " Signature " << md->getSignatureString() << std::endl; + MethodSignatureDesc* msd = md->getMethodSig(); + uint32 n=msd->getNumParams(); + os << " Params " << n << std::endl; + for (uint32 i = 0; i < n; i++) { + Type* tt = msd->getParamType(i); + os << " << "<<i<<" >> " << tt->getName() <<" "<< tt->tag<< std::endl; + os << " isObject " << tt->isObject(); + os << " isRef " << tt->isReference()<< std::endl; + if (tt->isReference()) { + ref_type_info(tt,os); + } + } + os << " Id " << md->getId() << std::endl; + os << " isPrivate " << md->isPrivate() << std::endl; + os << " ParentName " << md->getParentType()->getName();os << std::endl; + md->printFullName(os);os << std::endl; + } + if (inst->asMethodMarkerInst()) + os << " MethodMarkerInst" << std::endl; + if (inst->asPhiInst()) + os << " PhiInst" << std::endl; + if (inst->asTauPiInst()) + os << " TauPiInst" << std::endl; + if (inst->asSwitchInst()) + os << " SwitchInst" << std::endl; + if (inst->asTokenInst()) + os << " TokenInst" << std::endl; + if (inst->asTypeInst()) { + Type* tt = inst->asTypeInst()->getTypeInfo(); + os << " TypeInst" << std::endl; + os << " "<< tt->getName() <<" "<< tt->tag<< std::endl; + } +} // what_inst(Inst* inst,::std::ostream& os) + + +void +EscAnalyzer::ref_type_info(Type* type,::std::ostream& os) { + NamedType* arreltype; + os << " isArr " << type->isArray(); + if (type->asArrayType()) { + arreltype=type->asArrayType()->getElementType(); + os << " elmT " << arreltype->getName() << " " << arreltype->tag<<" "; + os << " isRef " << arreltype->isReference(); + } + os << " isArrElem " << type->isArrayElement()<< std::endl; +} // ref_type_info(Type* type,::std::ostream& os) + + +void +EscAnalyzer::debug_inst_info(Inst* inst,::std::ostream& os) { + Opnd* dst; + Opnd* src; + uint32 nsrc; + + os << " =="; inst->print(os); os << std::endl; + os << " Inst Info:" << std::endl; + what_inst(inst,os); + os << " Dst & Src Info:" << std::endl; + dst=inst->getDst(); + nsrc=inst->getNumSrcOperands(); + os << " "; + if (!dst->isNull()) + dst->print(os); + else + os << "dst NULL"; + os << " --srcnum " << nsrc << std::endl; + if (!dst->isNull()) { + os << " dst "; + debug_opnd_info(dst, os); + } else + os << std::endl; + if ( nsrc != 0 ) { + os << " sources" << std::endl; + for (uint32 i=0; i<nsrc; i++) { + src=inst->getSrc(i); + os << " <<" <<i<<">> "; + debug_opnd_info(src, os); + } + } +} // debug_inst_info(Inst* inst,::std::ostream& os) + + +void +EscAnalyzer::debug_opnd_info(Opnd* opnd,::std::ostream& os) { + Type* type=opnd->getType(); + + opnd->print(os); + os << " id. " <<opnd->getId(); + os << " type " << type->getName() << " " << type->tag<<" "; + os << " isRef " << type->isReference(); + os << " isObj " << type->isObject() << std::endl; + if (type->isReference()) + ref_type_info(type,os); + os << " "; + opnd->printWithType(os ); + os << std::endl; + os << " prop " << opnd->getProperties(); + os << " isVar " << opnd->isVarOpnd(); + os << " isSsa " << opnd->isSsaOpnd(); + os << " isSsaVar " << opnd->isSsaVarOpnd(); + os << " isSsaTmp " << opnd->isSsaTmpOpnd(); + os << " isPi " << opnd->isPiOpnd() << std::endl; + if (!opnd->isVarOpnd()) { + os << " "; + opnd->getInst()->print(os); + os << std::endl; + what_inst(opnd->getInst(),os); + } +} // debug_opnd_info(Opnd* opnd,::std::ostream& os) + + +EscAnalyzer::CnGNode* +EscAnalyzer::addCnGNode(Inst* inst, Type* type, uint32 ntype) { + CnGNode* cgnode = new (eaMemManager) CnGNode; // new CG node + + cgnode->cngNodeId = ++lastCnGNodeId; + cgnode->fgNode = inst->getNode(); + cgnode->instrId = inst->getId(); + cgnode->nodeType = ntype; + cgnode->lNode = NULL; + cgnode->nInst = inst; + cgnode->outEdges = NULL; + if (cgnode->nodeType==NT_DEFARG) + cgnode->argNumber = defArgNumber; // number of formal parameter + else + cgnode->argNumber = 0; + if ((ntype==NT_STFLD)||ntype==NT_THRVAL) + setFullState(cgnode,GLOBAL_ESCAPE); + else { + if (ntype==NT_ACTARG) + setFullState(cgnode,ARG_ESCAPE); + else + setFullState(cgnode,NO_ESCAPE); + } + if (ntype==NT_EXITVAL) + setCalleeEscaped(cgnode); + if (type->isArray()) { + if (type->asArrayType()->isReference()) { + cgnode->nodeRefType = NR_REFARR; + } else + cgnode->nodeRefType = NR_ARR; + } else + cgnode->nodeRefType = NR_REF; + if (ntype&(NT_OBJECT|NT_RETVAL)||ntype==NT_LDOBJ||ntype==NT_VARVAL||ntype==NT_REF||ntype==NT_ARRELEM) { + cgnode->nodeMDs = new (eaMemManager) NodeMDs(eaMemManager); // to collect methods receiving object + } else + cgnode->nodeMDs = NULL; + cngNodes->push_back(cgnode); + return cgnode; +} // addCnGNode(MemoryManager& mm, Type* type, Inst* inst, uint32 ntype) + + +EscAnalyzer::CnGNode* +EscAnalyzer::addCnGNode_op(Inst* inst, Type* type, uint32 ntype) { + CnGNode* cgnode = addCnGNode(inst, type, ntype); // new CG node + Opnd* opnd = inst->getDst(); + + cgnode->opndId = opnd->getId(); + cgnode->refObj = opnd; + return cgnode; +} // addCnGNode_op(MemoryManager& mm, Inst* inst, Type* type, uint32 ntype) + + +EscAnalyzer::CnGNode* +EscAnalyzer::addCnGNode_mp(Inst* inst, MethodDesc* md, uint32 ntype, uint32 narg) { + Type* type = md->getMethodSig()->getParamType(narg); + CnGNode* cgnode = addCnGNode(inst, type, ntype); // new CG node + + cgnode->opndId = 0; + cgnode->argNumber = narg; + cgnode->refObj = md; + return cgnode; +} // addCnGNode_mp(MemoryManager& mm, Inst* inst, MethodDesc* md, uint32 ntype, uint32 narg) + + +EscAnalyzer::CnGNode* +EscAnalyzer::addCnGNode_ex( Inst* inst, uint32 ntype) { + Type* type = inst->getSrc(0)->getType(); + CnGNode* cgnode = addCnGNode(inst, type, ntype); // new CG node + + cgnode->opndId = 0; + cgnode->refObj = inst->getSrc(0); // returned or thrown operand + return cgnode; +} // addCnGNode_ex(MemoryManager& mm, Inst* inst, uint32 ntype) + + +EscAnalyzer::CnGNode* +EscAnalyzer::addCnGNode_fl(Inst* inst, uint32 ntype) { + Type* type = inst->getDst()->getType(); + CnGNode* cgnode = addCnGNode(inst, type, ntype); // new CG node + + cgnode->opndId = 0; + cgnode->refObj = inst; // returned or thrown operand + return cgnode; +} // addCnGNode_fl(MemoryManager& mm, Inst* inst, uint32 ntype) + + +void +EscAnalyzer::addInst(cfgNode* cfgn, Inst* inst) { + cfgn->instructions->push_back(inst); +} // addInst(cfgNode* cfgn, Inst* inst) + + +void +EscAnalyzer::addMonInst(Inst* inst) { + uint32 monOpndId = inst->getSrc(0)->getId(); + MonUnit* monUnit = NULL; + monUnit = findMonUnit(monOpndId); + if (monUnit == NULL) { + monUnit = new (eaMemManager) MonUnit; // new monitor unit + monUnit->opndId = monOpndId; + monUnit->monInsts = new (eaMemManager) Insts(eaMemManager); + monitorInstUnits->push_back(monUnit); + monUnit->icallInsts = NULL; + } + monUnit->monInsts->push_back(inst); +} // addMonInst(MemoryManager& memManager, Inst* inst) + + +void +EscAnalyzer::addMonUnitVCall(MonUnit* mu, Inst* inst) { + if (mu->icallInsts == NULL) { + mu->icallInsts = new (eaMemManager) Insts(eaMemManager); + } + mu->icallInsts->push_back(inst); +} // addMonUnitVCall(MemoryManager& memManager, MonUnit* mu, Inst* inst) + + +EscAnalyzer::MonUnit* +EscAnalyzer::findMonUnit(uint32 opndId) { + MonInstUnits::iterator it; + assert(monitorInstUnits != NULL); + for (it = monitorInstUnits->begin( ); it != monitorInstUnits->end( ); it++ ) { + if ((*it)->opndId == opndId) + return *it; + } + return NULL; +} + + +void +EscAnalyzer::instrExam(cfgNode* cfgnode) { + Node* node = cfgnode->fgNode; + Inst *headInst = (Inst*)node->getFirstInst(); + int insnum=0; + Type* type; + CnGNode* cgnode; + uint32 ntype=0; + MethodDesc* md; + MethodSignatureDesc* msd; + uint32 n; + bool addinst; + Inst* method_inst; + + cfgnode->instructions=new (eaMemManager) Insts(eaMemManager); + for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { + insnum++; + ntype=0; + if (_instrInfo) { + Log::out() <<"++Node Id."<<node->getId()<<" "<<node->getDfNum()<<std::endl; + Log::out() << "=="; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out() << std::endl; + } + + switch (inst->getOpcode()) { + case Op_LdRef: // ldstr + case Op_NewObj: // newobj + case Op_NewArray: // newarray + case Op_NewMultiArray: // newmultiarray + ntype=NT_OBJECT; // for 4 cases above + case Op_LdConstant: // ldc + if (ntype==0) + ntype=NT_LDOBJ; // loads only ref null + case Op_DefArg: // defarg + if (ntype==0) { + ntype=NT_DEFARG; // for Op_DefArg + defArgNumber++; + } +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getDst()->getType()->isObject()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,ntype); + } + break; + + case Op_LdFieldAddr: // ldflda + ntype=NT_INSTFLD; + case Op_LdStaticAddr: // ldsflda + if (ntype==0) + ntype=NT_STFLD; // for LdStaticAddr +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + FieldAccessInst* fainst; + if ((fainst=inst->asFieldAccessInst())!=NULL) { + type=fainst->getFieldDesc()->getFieldType(); //field type + if (type->isReference()) { + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_REF); + if (findCnGNode_fl(inst,ntype)==NULL) { + CnGNode* n = addCnGNode_fl(inst,ntype); + cgnode->lNode=n; // stick nodes // and if fl node exists ? bug? + } + addInst(cfgnode, inst); + } + } + break; + + case Op_TauLdInd: // ldind +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getDst()->getType()->isObject()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_LDOBJ); + addInst(cfgnode, inst); + } + break; + + case Op_LdArrayBaseAddr: // ldbase + case Op_AddScaledIndex: // addindex +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getDst()->getType()->isReference()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_ARRELEM); + addInst(cfgnode, inst); + } + break; + + case Op_TauStInd: // stind +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getSrc(0)->getType()->isObject()) { + addInst(cfgnode, inst); + } + break; + + case Op_DirectCall: // call +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (!inst->getDst()->isNull()) { + if (inst->getDst()->getType()->isObject()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_RETVAL); + } + } + md=inst->asMethodInst()->getMethodDesc(); + msd = md->getMethodSig(); + n=msd->getNumParams(); + addinst=false; + for (uint32 i = 0; i < n; i++) { + Type* tt = msd->getParamType(i); + if (!tt->isReference()) { + continue; + } + addinst=true; + assert(findCnGNode_mp(inst->getId(),i)==NULL); + cgnode = addCnGNode_mp(inst,md,NT_ACTARG, i); + } + if (addinst) { + addInst(cfgnode, inst); + } +#ifdef _DEBUG + if (_seinfo) { + if (method_ea_level == 0) { + Log::out() <<"iE: call "; + if (md->isSynchronized()) + Log::out() << "sync "; + if (md->isStatic()) + Log::out() << "stat "; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out()<<std::endl; + Log::out() << " "; + if (Log::isEnabled()) + md->printFullName(Log::out()); + Log::out() << std::endl; + } + } +#endif + break; + + case Op_IndirectMemoryCall: //callimem +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (!inst->getDst()->isNull()) { + if (inst->getDst()->getType()->isObject()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_RETVAL); + } + } + method_inst=inst->getSrc(0)->getInst(); + md=method_inst->asMethodInst()->getMethodDesc(); + msd = md->getMethodSig(); + n=msd->getNumParams(); + addinst=false; + for (uint32 i = 0; i < n; i++) { + Type* tt = msd->getParamType(i); + if (!tt->isReference()) { + continue; + } + addinst=true; + assert(findCnGNode_mp(inst->getId(),i)==NULL); + cgnode = addCnGNode_mp(inst,md,NT_ACTARG,i); + } + if (addinst) { + addInst(cfgnode, inst); + } +#ifdef _DEBUG + if (_seinfo) { + if (method_ea_level == 0) { + Log::out() <<"iE: callimem "; + if (md->isSynchronized()) + Log::out() << "sync "; + if (md->isStatic()) + Log::out() << "stat "; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out()<<std::endl; + Log::out() << " "; + if (Log::isEnabled()) + md->printFullName(Log::out()); + Log::out() << std::endl; + } + } +#endif + break; + + case Op_Catch: // catch +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getDst()->getType()->isObject()) { + type=inst->getDst()->getType(); + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_CATCHVAL); + } + break; + + case Op_StVar: // stvar +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + type = inst->getDst()->getType(); + if (type->isObject()) { + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_VARVAL); + addInst(cfgnode, inst); + } + break; + + case Op_Phi: // phi +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + type = inst->getDst()->getType(); + if (type->isReference()) { + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_VARVAL); + addInst(cfgnode, inst); + } + break; + + case Op_LdVar: // ldvar +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + type = inst->getDst()->getType(); + if (type->isReference()) { + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_LDOBJ); + addInst(cfgnode, inst); + } + break; + + case Op_Return: // return + ntype=NT_EXITVAL; + case Op_Throw: // throw + if (ntype==0) + ntype=NT_THRVAL; +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + if (inst->getNumSrcOperands()>0) { + if (inst->getSrc(0)->getType()->isObject()) { + assert(findCnGNode_in(inst->getId())==NULL); + cgnode = addCnGNode_ex(inst,ntype); + addInst(cfgnode, inst); + } + } + break; + + case Op_TauStaticCast: // staticcast + case Op_TauCast: // cast +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + type = inst->getDst()->getType(); + if (type->isObject()) { + assert(findCnGNode_op(inst->getDst()->getId())==NULL); + cgnode = addCnGNode_op(inst,type,NT_LDOBJ); + addInst(cfgnode, inst); + } + break; + + case Op_SaveRet: // saveret +#ifdef _DEBUG + if (_instrInfo) { + Log::out() <<"Node Id."<<node->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + type = inst->getDst()->getType(); + if (type->isIntPtr()) { + cgnode = findCnGNode_op(inst->getDst()->getId()); + if (cgnode == NULL) + cgnode = addCnGNode_op(inst,type,NT_INTPTR); + } + break; + + case Op_TauMonitorEnter: // monenter + case Op_TauMonitorExit: // monexit + addMonInst(inst); +#ifdef _DEBUG + if (_seinfo) { + Log::out() << "iE: monX Node Id." + << node->getId() << " "; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out()<<std::endl; + } +#endif + break; + + case Op_TypeMonitorEnter:// tmonenter + case Op_TypeMonitorExit: // tmonexit + break; + + case Op_TauVirtualCall: // callvirt + case Op_IndirectCall: // calli + case Op_IntrinsicCall: // callintr + + case Op_TauStRef: + case Op_TauStField: + case Op_TauStElem: + case Op_TauStStatic: + case Op_Copy: + + case Op_Box: + + if (_instrInfo) { + Log::out() <<"--Node Id."<<node->getId()<<std::endl; + Log::out() << " =="; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out() << std::endl; + } + break; + + default: + + if (_instrInfo) { + Log::out() <<"~~Node Id."<<node->getId()<<std::endl; + Log::out() << " =="; + if (Log::isEnabled()) + inst->print(Log::out()); + Log::out() << std::endl; + } + } + } + return; +} // instrExam(cfgNode* cfgnode) + + +void +EscAnalyzer::instrExam2(cfgNode* node) { + Insts *instrs = node->instructions; + int insnum=0; + Insts::iterator it; + Inst* inst; + Type* type; + CnGNode* cgnode; + CnGNode* cgn_src; + uint32 ntype=0; + MethodDesc* md; + MethodSignatureDesc* msd; + uint32 n; + Inst* method_inst; + bool not_exam = false; + + for (it = instrs->begin( ); it != instrs->end( ); it++ ) { + inst=*it; + insnum++; + ntype=0; + +#ifdef _DEBUG + if (_instrInfo2) { + Log::out() <<"instrExam2: Node Id."<<node->fgNode->getId()<<std::endl; + if (Log::isEnabled()) + debug_inst_info(inst,Log::out()); + } +#endif + + switch (inst->getOpcode()) { + case Op_LdFieldAddr: // ldflda + ntype=NT_INSTFLD; + case Op_LdStaticAddr: // ldsflda + if (ntype==0) + ntype=NT_STFLD; // for LdStaticAddr + FieldAccessInst* fainst; + if ((fainst=inst->asFieldAccessInst())!=NULL) { + if (fainst->getFieldDesc()->getFieldType()->isReference()) { + cgn_src=findCnGNode_op(inst->getDst()->getId()); // field address node + assert(cgn_src!=NULL); + cgnode=findCnGNode_fl(inst,ntype); // field node + assert(cgnode!=NULL); + // adding edge from fld node to address node + if (ntype == NT_INSTFLD) { + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); // instance node + // adding fld edge for ldflda + addEdge(cgn_src,cgnode,ET_FIELD,inst); + // special for java/lang/String::value + FieldDesc* fd=inst->asFieldAccessInst()->getFieldDesc(); + if (fd->getParentType()->isSystemString()&&strcmp(fd->getName(),"value")==0) { + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + } + } + } + break; + + case Op_TauLdInd: // ldind + if (inst->getDst()->getType()->isObject()) { + cgnode=findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + // ref to loaded object + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + addEdge(cgn_src,cgnode,ET_POINT,inst); + } + break; + + case Op_LdArrayBaseAddr: // ldbase + case Op_AddScaledIndex: // addindex + if (inst->getDst()->getType()->isReference()) { + cgnode=findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + // ref to loaded address + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + if (inst->getOpcode()==Op_LdArrayBaseAddr) { + cgnode->lNode=cgn_src; //stick array object & array base address nodes + } + if (inst->getOpcode()==Op_AddScaledIndex) { + addEdge(cgn_src,cgnode,ET_FIELD,inst); // ref from array object to inner objects + } + } + break; + + case Op_TauStInd: // stind + if (inst->getSrc(0)->getType()->isObject()) { + // ref to loaded address + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + cgnode=findCnGNode_op(inst->getSrc(1)->getId()); + assert(cgnode!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + break; + + case Op_DirectCall: // call + md=inst->asMethodInst()->getMethodDesc(); + msd = md->getMethodSig(); + n=msd->getNumParams(); + for (uint32 i = 0; i < n; i++) { + Type* tt = msd->getParamType(i); + if (!tt->isReference()) + continue; + cgnode=findCnGNode_mp(inst->getId(),i); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(2+i)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + break; + + case Op_IndirectMemoryCall: //callimem + method_inst=inst->getSrc(0)->getInst(); + md=method_inst->asMethodInst()->getMethodDesc(); + msd = md->getMethodSig(); + n=msd->getNumParams(); + for (uint32 i = 0; i < n; i++) { + Type* tt = msd->getParamType(i); + if (!tt->isReference()) + continue; + cgnode = findCnGNode_mp(inst->getId(),i); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(3+i)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + break; + + case Op_StVar: // stvar + if (inst->getDst()->getType()->isObject()) { + cgnode = findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + break; + + case Op_Phi: // phi + if (inst->getDst()->getType()->isObject()) { + uint32 nsrc=inst->getNumSrcOperands(); + cgnode = findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + for (uint32 i=0; i<nsrc; i++) { + cgn_src=findCnGNode_op(inst->getSrc(i)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + } + break; + + case Op_LdVar: // ldvar + type = inst->getDst()->getType(); + if (type->isReference()) { + cgnode = findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + addEdge(cgn_src,cgnode,ET_DEFER,inst); // load ldobj + } + break; + + case Op_Return: // return + ntype=NT_EXITVAL; + case Op_Throw: // throw + if (ntype==0) + ntype=NT_THRVAL; + if (inst->getNumSrcOperands()>0) { + cgnode = findCnGNode_in(inst->getId()); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + } + break; + + case Op_TauStaticCast: // staticcast + case Op_TauCast: // cast + type = inst->getDst()->getType(); + cgnode = findCnGNode_op(inst->getDst()->getId()); + assert(cgnode!=NULL); + cgn_src=findCnGNode_op(inst->getSrc(0)->getId()); + assert(cgn_src!=NULL); + addEdge(cgnode,cgn_src,ET_DEFER,inst); + break; + + case Op_TauMonitorEnter: // monenter + case Op_TauMonitorExit: // monexit + case Op_TypeMonitorEnter:// tmonenter + case Op_TypeMonitorExit: // tmonexit + break; + + default: + if (_instrInfo2) { + not_exam = true; + } + } + if (_instrInfo2) { + if (not_exam) { + Log::out() <<"!!! Not examined."<<std::endl; + not_exam = false; + } + } + } + return; +} // instrExam2(cfgNode* node) + + +void +EscAnalyzer::printCnGNode(CnGNode* cgn,::std::ostream& os) { + std::string t2; + + os << "nodeId "<<cgn->cngNodeId<<" "; + if (cgn->nodeType & NT_OBJS) { //node of object created in the method + os << "opId "<<cgn->opndId<<" "; + } else { + if (cgn->nodeType & NT_ACTARG) { //node of actual method parameter + os << "nArg "<<cgn->argNumber<<" "; + os << "method "<<cgn->refObj<<" "; + } + } + if (cgn->nodeType==NT_DEFARG) + os << " nArg "<<cgn->argNumber<<" "; //Arg number for defarg + os << " inst "<<cgn->instrId<<" ("<<nodeTypeToString(cgn)<<cgn->nodeType<<", "; + switch (cgn->nodeRefType) { + case NR_REF : t2="Ref -"; break; + case NR_ARR : t2="Arr -"; break; + case NR_REFARR : t2="RArr-"; break; + default : t2=" -"; + } + os <<t2<<cgn->nodeRefType<<") "; + if (cgn->lNode) + os << "( " << cgn->lNode->cngNodeId << "-" << cgn->lNode->opndId << " ) "; + os << "st. "; + printState(cgn); os << " "; +} // printCnGNode(CnGNode* cgn,::std::ostream& os) + + +std::string +EscAnalyzer::nodeTypeToString(CnGNode* cgn) { + std::string t1; + switch (cgn->nodeType) { + case NT_OBJECT : t1="Obj -"; break; + case NT_DEFARG : t1="DArg-"; break; + case NT_RETVAL : t1="RVal-"; break; + case NT_CATCHVAL: t1="CVal-"; break; + case NT_STFLD : t1="SFld-"; break; + case NT_INSTFLD : t1="IFld-"; break; + case NT_LDOBJ : t1="LObj-"; break; + case NT_INTPTR : t1="IPtr-"; break; + case NT_VARVAL : t1="VVal-"; break; + case NT_ARRELEM : t1="ArEl-"; break; + case NT_REF : t1="REF -"; break; + case NT_ACTARG : t1="AArg-"; break; + case NT_EXITVAL : t1="EVal-"; break; + case NT_THRVAL : t1="TVal-"; break; + default : t1=" -"; + } + return t1; +} // nodeTypeToString(CnGNode* cgn) + + +std::string +EscAnalyzer::edgeTypeToString(CnGRef* edr) { + std::string t1; + switch (edr->edgeType) { + case ET_POINT : t1="poi-"; break; + case ET_DEFER : t1="ref-"; break; + case ET_FIELD : t1="fld-"; break; + default : t1=" -"; + } + return t1; +} // edgeTypeToString(CnGRef* edr) + + +void +EscAnalyzer::printCnGNodes(char* text,::std::ostream& os) { + CnGNodes::const_iterator it; + FieldDesc* fd; + std::string t1; + std::string t2; + os << " "<< text << std::endl; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + os <<" "; + printCnGNode(*it,os); + os << std::endl; + os << " "; + if ((*it)->nodeType & (NT_OBJS|NT_EXITVAL)) { //node of created or exit object + ((Opnd*)(*it)->refObj)->printWithType(os); + } + if ((*it)->nodeType == NT_RETVAL) { + os << std::endl; os << " "; + Inst* inst = ((Opnd*)(*it)->refObj)->getInst(); + inst->print(os); + if (inst->getOpcode()==Op_IndirectMemoryCall) { + MethodDesc* md = inst->getSrc(0)->getInst()->asMethodInst()->getMethodDesc(); + os << std::endl; os << " "; + md->printFullName(os); + } + } + if ((*it)->nodeType & NT_ACTARG) { //node of actual method parameter + os << ((MethodDesc*)(*it)->refObj)->getParentType()->getName() << "::"; + os << ((MethodDesc*)(*it)->refObj)->getName() << std::endl; + os << " "; + os << ((MethodDesc*)(*it)->refObj)->getMethodSig()->getParamType((*it)->opndId)->getName(); + } + if ((*it)->nodeType & NT_STFLD) { //field node + fd = ((Inst*)(*it)->refObj)->asFieldAccessInst()->getFieldDesc(); + os << fd->getParentType()->getName() << "::"<< fd->getName() << std::endl; + os << " "<<fd->getFieldType()->getName(); + } + os << std::endl; + } +} // printCnGNodes(char* text,::std::ostream& os) + + +void +EscAnalyzer::printCnGNodeRefs(CnGNode* cgn, std::string text,::std::ostream& os) { + CnGNode* node; + CnGRefs::iterator it1; + Inst* inst; + os << text; + if (scannedObjs->size()!=0) { + if (checkScannedObjs(cgn->cngNodeId)) { + os << "nodeId " << cgn->cngNodeId << " . . . " << std::endl; + return; + } + } + printCnGNode(cgn,os); + os << std::endl; + os << text; cgn->nInst->print(os); os << std::endl; + scannedObjs->push_back(cgn->cngNodeId); + if (cgn->outEdges != NULL) + for (it1 = cgn->outEdges->begin( ); it1 != cgn->outEdges->end( ); it1++ ) { + os << text << edgeTypeToString(*it1) << std::endl; + if ((node=findCnGNode_id((*it1)->cngNodeTo->cngNodeId))!=NULL) + printCnGNodeRefs(node,text+" ",os); + } + scannedObjs->pop_back(); + if (cgn->nodeType==NT_RETVAL) { + inst = cgn->nInst; + if (inst->getOpcode()==Op_IndirectMemoryCall) { + MethodDesc* md = inst->getSrc(0)->getInst()->asMethodInst()->getMethodDesc(); + os << text << " "; + md->printFullName(os); os << std::endl; + } + } + if (cgn->nodeType==NT_LDOBJ && getEscState(cgn)!=GLOBAL_ESCAPE) { + inst = cgn->nInst; + lObjectHistory(inst,text,os); + scannedInsts->clear(); + } +} // printCnGNodeRefs(CnGNode* cgn, std::string text,::std::ostream& os) + + +void +EscAnalyzer::lObjectHistory(Inst* inst,std::string text,::std::ostream& os) { + Inst* inst1; + uint32 nsrc=inst->getNumSrcOperands(); + + if (scannedInsts->size()!=0) { + if (checkScannedInsts(inst->getId())) { + os << text << "instId " << inst->getId() << " . . . " << std::endl; + return; + } + } + os << text; inst->print(os); os << std::endl; + if (inst->getOpcode()==Op_DirectCall || inst->getOpcode()==Op_IndirectMemoryCall) { + Opnd *returnOpnd = inst->getDst(); + if (returnOpnd != NULL) { + CnGNode* n = findCnGNode_op(returnOpnd->getId()); + if (n != NULL) { + os<< text << " "; printCnGNode(n,os); os<< std::endl; + } + } + if (inst->getOpcode()==Op_IndirectMemoryCall) { + MethodDesc* md = inst->getSrc(0)->getInst()->asMethodInst()->getMethodDesc(); + os << text << " "; md->printFullName(os); os << std::endl; + } + return; + } + scannedInsts->push_back(inst->getId()); + for (uint32 i=0; i<nsrc; i++) { + inst1 = inst->getSrc(i)->getInst(); + if (!(Type::isTau(inst->getSrc(i)->getType()->tag))) + lObjectHistory(inst1,text+" ",os); + } +} // lObjectHistory(Inst* inst,std::string text,::std::ostream& os) + + +void +EscAnalyzer::printCnGEdges(char* text,::std::ostream& os) { + CnGEdges* cge = cngEdges; + CnGEdges::iterator it; + CnGRefs::iterator it1; + std::string t1; + std::string t2; + os << " "<< text << std::endl; + if (cge==NULL) { + os <<" NULL"<< std::endl; + return; + } + for (it = cge->begin( ); it != cge->end( ); it++ ) { + os << " from "; + printCnGNode((*it)->cngNodeFrom,os); + os << " to " << std::endl; + for (it1 = (*it)->refList->begin( ); it1 != (*it)->refList->end( ); it1++ ) { + os << " "; + os <<(*it1)->cngNodeTo->cngNodeId<<" ("; + switch ((*it1)->edgeType) { + case ET_POINT : t1="poi-"; break; + case ET_DEFER : t1="ref-"; break; + case ET_FIELD : t1="fld-"; break; + default : t1=" -"; + } + os <<t1<<(*it1)->edgeType<<"), "; + printCnGNode(findCnGNode_id((*it1)->cngNodeTo->cngNodeId),os); + os << std::endl; + } + } +} // printCnGEdges(char* text,::std::ostream& os) + + +EscAnalyzer::CnGNode* +EscAnalyzer::findCnGNode_op(uint32 nId) { + CnGNodes::iterator it; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->opndId==nId && ((*it)->nodeType & NT_OBJS)) + return (*it); + } + return(NULL); +} // findCnGNode_op(uint32 nId) + + +EscAnalyzer::CnGNode* +EscAnalyzer::findCnGNode_id(uint32 nId) { + CnGNodes::iterator it; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->cngNodeId==nId) + return (*it); + } + return(NULL); +} // findCnGNode_id(uint32 nId) + + +EscAnalyzer::CnGNode* +EscAnalyzer::findCnGNode_in(uint32 nId) { + CnGNodes::iterator it; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->instrId==nId) + return (*it); + } + return(NULL); +} // findCnGNode_in(uint32 nId) + + +EscAnalyzer::CnGNode* +//EscAnalyzer::findCnGNode_mp(MethodDesc* md, uint32 nId) { +EscAnalyzer::findCnGNode_mp(uint32 iId, uint32 aId) { + CnGNodes::iterator it; + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->instrId==iId && (*it)->argNumber==aId && + (*it)->nodeType == NT_ACTARG) + return (*it); + } + return(NULL); +} // findCnGNode_mp(uint32 iId, uint32 aId) + + +EscAnalyzer::CnGNode* +EscAnalyzer::findCnGNode_fl(Inst* inst, uint32 ntype) { + CnGNodes::iterator it; + FieldDesc* fd1; + FieldDesc* fd2; + uint32 idr = 0; + if (ntype==NT_INSTFLD) + idr=inst->getSrc(0)->getId(); + assert(inst->asFieldAccessInst()!=NULL); + fd1 = inst->asFieldAccessInst()->getFieldDesc(); + for (it = cngNodes->begin( ); it != cngNodes->end( ); it++ ) { + if ((*it)->nodeType==ntype) { + assert(((Inst*)((*it)->refObj))->asFieldAccessInst()!=NULL); + fd2 = ((Inst*)((*it)->refObj))->asFieldAccessInst()->getFieldDesc(); + if ( fd1->getParentType()==fd2->getParentType() && + strcmp(fd1->getName(),fd2->getName())==0) { + if (ntype==NT_INSTFLD) { + uint32 idf=((Inst*)((*it)->refObj))->getSrc(0)->getId(); + if (idr!=idf) { +#ifdef _DEBUG + if (_cngedges) { + Log::out() + << "++++ findCnGNode_fl: required " << idr + << " - found " << idf << " not found" << std::endl; + } +#endif + continue; + } +#ifdef _DEBUG + if (_cngedges) { + Log::out() + << "++++ findCnGNode_fl: required " << idr + << " - found " << idf << std::endl; + } +#endif + } + return (*it); + } + } + } + return(NULL); +} // findCnGNode_fl(Opnd* opnd, uint32 ntype) + + +/* +* Creates edge if it doesn't exist yet. +*/ +void +EscAnalyzer::addEdge(CnGNode* cgnfrom, CnGNode* cgnto, + uint32 etype, Inst* inst) { + CnGEdges::iterator it; + CnGRefs* el; + CnGRef* ref; + CnGNode* cgn1=cgnfrom; + CnGNode* cgn2=cgnto; + bool done = false; + + if (cgnfrom->lNode) { + cgn1=findCnGNode_id(cgnfrom->lNode->cngNodeId); + assert(cgn1!=NULL); + } + + if (cgnto->lNode) { + cgn2=findCnGNode_id(cgnto->lNode->cngNodeId); + assert(cgn2!=NULL); + } +#ifdef _DEBUG + if (_cngedges) { + Log::out() + << "++++ addEdge: " << cgnfrom->cngNodeId << "-" << cgnfrom->opndId + << " ( "<<cgn1->cngNodeId << "-" << cgn1->opndId << " ) to " + << cgnto->cngNodeId << "-" << cgnto->opndId << " ( " + << cgn2->cngNodeId << "-" << cgn2->opndId << " )" << std::endl; + } +#endif + if (cgn1==cgn2) { +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "+++++++ equal " + << cgnfrom->cngNodeId<< "-" << cgnfrom->opndId + << " ( "<<cgn1->cngNodeId << "-" << cgn1->opndId << " ) to " + << cgnto->cngNodeId << "-" << cgnto->opndId << " ( " + << cgn2->cngNodeId << "-" << cgn2->opndId << " )" << std::endl; + } +#endif + return; + } + for ( it = cngEdges->begin( ); it != cngEdges->end( ); it++ ) { + if ((*it)->cngNodeFrom == cgn1) { + CnGRefs::iterator itr; + if (etype==ET_FIELD || cgn1->nodeType==NT_ACTARG) { + for ( itr = (*it)->refList->begin( ); itr != (*it)->refList->end( ); itr++ ) { + if ((*itr)->cngNodeTo == cgn2) { +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "++++ addEdge: ET_FIELD || cgn1-> ==NT_ACTARG && *->cngNodeTo == cgn2" << std::endl; + } +#endif + return; + } + } + } else { + for ( itr = (*it)->refList->begin( ); itr != (*it)->refList->end( ); itr++ ) + if ((*itr)->cngNodeTo == cgn2) { // needed edge exists + done = true; +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "++++ addEdge: needed edge exists" << std::endl; + } +#endif + } + } + if (!done) { + ref = new (eaMemManager) CnGRef; + ref->cngNodeTo=cgn2; + ref->edgeType=etype; + ref->edgeInst=inst; + (*it)->refList->push_back(ref); +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "++++ addEdge: added CnGRef" << std::endl; + } +#endif + } + return; + } + } + ref = new (eaMemManager) CnGRef; + ref->cngNodeTo=cgn2; + ref->edgeType=etype; + ref->edgeInst=inst; + CnGEdge* cgedge=new (eaMemManager) CnGEdge; + el=new CnGRefs(eaMemManager); + cgedge->cngNodeFrom=cgn1; + el->push_back(ref); + cgedge->refList=el; + cngEdges->push_back(cgedge); + cgn1->outEdges=el; +#ifdef _DEBUG + if (_cngedges) { + Log::out() << "++++ addEdge: added edge" << std::endl; + } +#endif + +} // addEdge(CnGNode* cgnfrom, CnGNode* cgnto, uint32 etype, Inst* inst) + +} //namespace Jitrino + diff --git vm/jitrino/src/optimizer/escanalyzer.h vm/jitrino/src/optimizer/escanalyzer.h new file mode 100644 index 0000000..7f25337 --- /dev/null +++ vm/jitrino/src/optimizer/escanalyzer.h @@ -0,0 +1,349 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Natalya V. Golovleva + * @version $Revision$ + * + */ + +#ifndef _ESCANALYSIS_H_ +#define _ESCANALYSIS_H_ + +#include "Stl.h" +#include "optpass.h" +#include "FlowGraph.h" +#include "irmanager.h" +#include "mkernel.h" + +namespace Jitrino { + +// +// Escape analyzer (synchronization removing) +// +class EscAnalyzer { + +public: + EscAnalyzer(MemoryManager& mm, SessionAction* argSource, IRManager& irm); + + void doAnalysis(); + +// CnG node types + static const uint32 NT_OBJECT = 8; // Op_LdRef,Op_NewObj,Op_NewArray,Op_NewMultiArray + static const uint32 NT_DEFARG = NT_OBJECT+1; // formal parameter - Op_DefArg + static const uint32 NT_RETVAL = 16; // Op_DirectCall,Op_IndirectMemoryCall-returned by method + static const uint32 NT_CATCHVAL = NT_RETVAL+1; // catched value + static const uint32 NT_LDOBJ = 32; // Op_LdConstant,Op_TauLdInd,Op_LdVar, + // Op_TauStaticCast,Op_TauCast + static const uint32 NT_INTPTR = NT_LDOBJ+1; // Op_SaveRet + static const uint32 NT_VARVAL = NT_LDOBJ+2; // Op_StVar,Op_Phi + static const uint32 NT_ARRELEM = NT_LDOBJ+3; // Op_LdArrayBaseAddr,Op_AddScaledIndex + static const uint32 NT_REF = NT_LDOBJ+4; // reference value - Op_LdFieldAddr, + // Op_LdStaticAddr + static const uint32 NT_STFLD = 64; // Op_LdStaticAddr + static const uint32 NT_INSTFLD = NT_STFLD+1; // Op_LdFieldAddr + static const uint32 NT_ACTARG = 128; // Op_DirectCall,Op_IndirectMemoryCall + static const uint32 NT_EXITVAL = 256; // returned value - Op_Return + static const uint32 NT_THRVAL = NT_EXITVAL+1; // thrown value - Op_Throw + static const uint32 NT_OBJS = NT_OBJECT|NT_RETVAL|NT_LDOBJ; //for findCnGNode_op +// CnG node reference types + static const uint32 NR_REF = 1; + static const uint32 NR_ARR = 2; + static const uint32 NR_REFARR = 3; +// CnG edge types + static const uint32 ET_POINT = 1; // Op_TauLdInd (loaded value) + static const uint32 ET_DEFER = 2; + static const uint32 ET_FIELD = 3; // Op_LdFieldAddr (object field), Op_AddScaledIndex +// CG node states + static const uint32 GLOBAL_ESCAPE = 1; + static const uint32 ARG_ESCAPE = 2; + static const uint32 NO_ESCAPE = 3; + static const uint32 ESC_MASK = 3; + static const uint32 BIT_MASK = 56; + static const uint32 LOOP_CREATED = 8; + static const uint32 CALLEE_ESCAPED = 16; + static const uint32 VIRTUAL_CALL = 32; + + typedef StlList<uint32> NodeMDs; + + struct CnGNode; + struct CnGRef { + CnGNode* cngNodeTo; + uint32 edgeType; + Inst* edgeInst; + }; + + typedef StlList<CnGRef*> CnGRefs; + typedef StlList<Inst*> Insts; + + struct CnGNode { + uint32 cngNodeId; // CnG node id + uint32 opndId; // opnd id (0 for NT_ACTARG) + void* refObj; // MethodDesc* for NT_ACTARG, Inst* for fields, Opnd* for others + uint32 nodeType; // CnG node types + uint32 nodeRefType; // CnG node reference types + uint32 instrId; + CnGNode* lNode; // ldind from lNode + Node* fgNode; + uint32 state; // escape state + NodeMDs* nodeMDs; // list of NT_ACTARG nodes + Inst* nInst; // ref to inst + uint32 argNumber; // number of arg for NT_DEFARG & NT_ACTARG (0 for others) + CnGRefs* outEdges; // cngNode out edges + }; + + struct MemberIdent { + char* parentName; + char* name; + char* signature; + }; + + struct InstFld; + typedef StlList<InstFld*> InstFlds; + + struct InstFld { + MemberIdent* fldIdent; + uint32 state; + InstFlds* instFlds; // contained instance fields + }; + + struct ParamInfo { + uint32 paramNumber; + uint32 state; + InstFlds* instFlds; // contained instance fields + }; + + typedef StlList<ParamInfo*> ParamInfos; + + struct CalledMethodInfo { + MemberIdent* methodIdent; + uint32 numberOfArgs; + uint32 properties; // native, final, virtual ... + ParamInfos* paramInfos; + uint32 retValueState; + bool mon_on_this; + }; + + typedef StlList<CalledMethodInfo*> CalledMethodInfos; + + struct MonUnit { + uint32 opndId; + Insts* monInsts; + Insts* icallInsts; + }; + + MemoryManager& eaMemManager; + + static CalledMethodInfos* calledMethodInfos; + static Mutex calledMethodInfosLock; + + uint32 allProps; + const char* debug_method; + +private: + static const int maxMethodExamLevel_default = 5; + + struct CnGEdge { + CnGNode* cngNodeFrom; + CnGRefs* refList; + }; + + typedef StlList<CnGNode*> CnGNodes; + typedef StlList<CnGEdge*> CnGEdges; + + struct cfgNode { + uint32 nodeId; + Node* fgNode; + Insts* instructions; + }; + + typedef StlList<uint32> ObjIds; + + typedef StlList<MonUnit*> MonInstUnits; + + EscAnalyzer(EscAnalyzer* parent, IRManager& irm); + + uint32 maxMethodExamLevel; + IRManager& irManager; + MethodDesc& mh; // analyzed method header + CnGNodes* cngNodes; + CnGEdges* cngEdges; + uint32 lastCnGNodeId; + uint32 curMDNode; + int defArgNumber; + uint32 method_ea_level; + ObjIds *scannedObjs; + ObjIds *scannedInsts; + ObjIds *scannedSucNodes; + uint32 initNodeType; // type of initial scanned node + MonInstUnits* monitorInstUnits ; + SsaTmpOpnd* i32_0; + SsaTmpOpnd* i32_1; + TranslatorAction* translatorAction; + + +#ifdef _DEBUG + void prPrN(cfgNode pr_n[],int maxInd) { + Log::out()<<"--------------------"<<std::endl; + Log::out() <<" pr_n contains"<<std::endl; + for (int i=0; i<maxInd; i++) { + Log::out() <<i<<" nId "<<(pr_n[i]).nodeId; + Log::out() <<" Node "<<(pr_n[i]).fgNode->getId(); + Log::out() <<std::endl; + } + Log::out() <<"--------------------"<<std::endl; + } +#endif + //common method for both EscAnalyzer constructors + void init(); + void instrExam(cfgNode* node); + void instrExam2(cfgNode* node); + void addEdge(CnGNode* cgnfrom, CnGNode* cgnto, uint32 etype, Inst* inst); + void printCnGEdges(char* text,::std::ostream& os); + void what_inst(Inst* inst,::std::ostream& os); + void debug_inst_info(Inst* inst,::std::ostream& os); + void debug_opnd_info(Opnd* opnd,::std::ostream& os); + void ref_type_info(Type* type,::std::ostream& os); + CnGNode* addCnGNode(Inst* inst, Type* type, uint32 ntype); + CnGNode* addCnGNode_op(Inst* inst, Type* type, uint32 ntype); + CnGNode* addCnGNode_mp(Inst* inst, MethodDesc* md, uint32 ntype, uint32 narg); + CnGNode* addCnGNode_ex(Inst* inst, uint32 ntype); + CnGNode* addCnGNode_fl(Inst* inst, uint32 ntype); + void printCnGNodes(char* text,::std::ostream& os); + void printCnGNode(CnGNode* cgn,::std::ostream& os); + std::string nodeTypeToString(CnGNode* cgn); + std::string edgeTypeToString(CnGRef* edr); + CnGNode* findCnGNode_id(uint32 nId); + CnGNode* findCnGNode_op(uint32 nId); + CnGNode* findCnGNode_in(uint32 nId); + CnGNode* findCnGNode_mp(uint32 iId, uint32 aId); + CnGNode* findCnGNode_fl(Inst* inst, uint32 ntype); + void printCnGNodeRefs(CnGNode* cgn, std::string text,::std::ostream& os); + void printRefInfo(::std::ostream& os); + void addInst(cfgNode* cfgn, Inst* inst); + void scanCnGNodeRefsGE(CnGNode* cgn); + void scanCnGNodeRefsEV(CnGNode* cgn); + void scanCnGNodeRefsDA(CnGNode* cgn); + void scanCnGNodeRefsAE(CnGNode* cgn); + void scanCalleeMethod(Inst* call); + void optimizeTranslatedCode(IRManager& irManager); + void setCreatedObjectStates(); + void printCreatedObjectsInfo(::std::ostream& os); + void printMethodInfos(); //? + void printMethodInfo(CalledMethodInfo* mi); + CalledMethodInfo* getMethodInfo(const char* ch1,const char* ch2,const char* ch3); + CalledMethodInfo* findMethodInfo(MethodDesc* md,Inst* inst); + void saveScannedMethodInfo(); + uint32 getMethodParamState(CalledMethodInfo* mi, uint32 np); + void markNotEscInsts(); + bool checkScannedObjs(uint32 id); + bool checkScannedInsts(uint32 id); + bool checkScannedSucNodes(uint32 id); + void createdObjectInfo(); + void addMonInst(Inst* inst); + void addMonUnitVCall(MonUnit* mu, Inst* inst); + MonUnit* findMonUnit(uint32 opndId); + void scanSyncInsts(); + void fixSyncMethodMonitorInsts(Insts* syncInsts); + void checkCallSyncMethod(); + void insertSaveJitHelperCall(CnGNode* node); + Opnd* insertReadJitHelperCall(); + bool checkMonitorsOnThis(); + void setSencEscState(CnGNode* node,Insts* syncInsts); + void collectSuccessors(Node* node); + void collectGlobalNodeSuccessors(CnGNode* node); + uint32 getContainingObjState(Inst* linst); + void removeMonitorInsts(Insts* syncInsts); + void removeNode(Node* node); + SsaTmpOpnd* insertLdConst(uint32 value); + void fixMonitorInstsVCalls(MonUnit* mu); + void insertFlagCheck(Insts* syncInsts, Opnd* muflag); + void printNode(Node* n,::std::ostream& os); + uint32 checkState(Inst* inst,uint32 st); + void findObject(Inst* inst,std::string text=" "); + void findObject1(Inst* inst,std::string text=" "); + void lObjectHistory(Inst* inst,std::string text,::std::ostream& os); + uint32 getSubobjectStates(CnGNode* node); + + uint32 getEscState(CnGNode* n) { + return (n->state)&ESC_MASK; + } + void setEscState(CnGNode* n, uint32 st) { + n->state = ((n->state)&BIT_MASK)+st; + } + uint32 getFullState(CnGNode* n) { + return n->state; + } + void setFullState(CnGNode* n, uint32 st) { + n->state = st; + } + uint32 getLoopCreated(CnGNode* n) { + return (n->state)&LOOP_CREATED; + } + void setLoopCreated(CnGNode* n) { + n->state = n->state|LOOP_CREATED; + } + void remLoopCreated(CnGNode* n) { + n->state = (n->state|LOOP_CREATED)^LOOP_CREATED; + } + uint32 getCalleeEscaped(CnGNode* n) { + return (n->state)&CALLEE_ESCAPED; + } + void setCalleeEscaped(CnGNode* n) { + n->state = n->state|CALLEE_ESCAPED; + } + void remCalleeEscaped(CnGNode* n) { + n->state = (n->state|CALLEE_ESCAPED)^CALLEE_ESCAPED; + } + uint32 getVirtualCall(CnGNode* n) { + return (n->state)&VIRTUAL_CALL; + } + void setVirtualCall(CnGNode* n) { + n->state = n->state|VIRTUAL_CALL; + } + void remVirtualCall(CnGNode* n) { + n->state = (n->state|VIRTUAL_CALL)^VIRTUAL_CALL; + } + void printState(CnGNode* n,::std::ostream& os=Log::out()) { + os << getEscState(n) << " (" << (getFullState(n)>>3) << ")"; + } + void printState(uint32 st,::std::ostream& os=Log::out()) { + os << (st&ESC_MASK) << " (" << (st>>3) << ")"; + } + bool isGlobalState(uint32 state) { + if ((state&ESC_MASK)==GLOBAL_ESCAPE||(state&VIRTUAL_CALL)!=0) + return true; + return false; + } + void runTranslatorSession(CompilationContext& inlineCC); + + int _cfgirun; + int _instrInfo; + int _instrInfo2; + int _cngnodes; + int _cngedges; + int _scanMtds; + int _setState; + int _printstat; + int _eainfo; + int _seinfo; +#define prsNum 10 + int prsArr[prsNum]; +}; + +} //namespace Jitrino + +#endif // _ESCANALYSIS_H_ diff --git vm/jitrino/src/optimizer/escapeanalyzer.cpp vm/jitrino/src/optimizer/escapeanalyzer.cpp index bcc0eb1..025fa19 100644 --- vm/jitrino/src/optimizer/escapeanalyzer.cpp +++ vm/jitrino/src/optimizer/escapeanalyzer.cpp @@ -21,7 +21,6 @@ */ #include "escapeanalyzer.h" -#include "FlowGraph.h" #include "irmanager.h" #include "Inst.h" #include "Stl.h" @@ -29,10 +28,10 @@ #include "BitSet.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(EscapeAnalysisPass, escape, "Escape Analysis") +DEFINE_SESSION_ACTION(OldEscapeAnalysisPass, old_escape, "Old Escape Analysis") void -EscapeAnalysisPass::_run(IRManager& irm) { +OldEscapeAnalysisPass::_run(IRManager& irm) { EscapeAnalyzer ea(irm); ea.doAnalysis(); } @@ -42,7 +41,7 @@ isEscapeOptimizationCandidate(Inst* inst switch (inst->getOpcode()) { case Op_Catch: return false; - case Op_LdString: case Op_NewObj: case Op_NewArray: + case Op_LdRef: case Op_NewObj: case Op_NewArray: return true; case Op_NewMultiArray: case Op_Box: @@ -57,7 +56,7 @@ isEscapeOptimizationCandidate(Inst* inst case Op_DefArg: return false; default: - return false; + return false; } // return false; } @@ -72,7 +71,7 @@ isPotentiallyEscapingInst(Inst* inst) { case Op_DirectCall: case Op_TauVirtualCall: case Op_IndirectCall: case Op_IndirectMemoryCall: case Op_IntrinsicCall: - case Op_Return: case Op_Throw: + case Op_Return: case Op_Throw: case Op_TauStInd: case Op_TauStRef: case Op_TauStField: case Op_TauStElem: case Op_TauStStatic: return true; @@ -165,7 +164,7 @@ markEscapingInst(Inst* inst,BitSet& esca // case Op_LdVar: break; - case Op_Catch: case Op_DefArg: case Op_LdString: case Op_LdConstant: + case Op_Catch: case Op_DefArg: case Op_LdRef: case Op_LdConstant: case Op_NewObj: case Op_NewArray: // no src operands to mark break; @@ -211,16 +210,16 @@ EscapeAnalyzer::doAnalysis() { StlDeque<Inst*> candidateSet(memManager); BitSet escapingInsts(memManager,irManager.getInstFactory().getNumInsts()); - const CFGNodeDeque& nodes = irManager.getFlowGraph().getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + Nodes::const_iterator niter; // // Clear all marks on instructions // Collect instructions that are candidate for escape optimizations // for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst* inst=headInst->next();inst!=headInst;inst=inst->next()) { + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { if (isEscapeOptimizationCandidate(inst)) candidateSet.push_back(inst); } @@ -229,9 +228,9 @@ EscapeAnalyzer::doAnalysis() { // Iteratively mark instructions whose results escape the method // for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst* inst=headInst->next();inst!=headInst;inst=inst->next()) { + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { if (isPotentiallyEscapingInst(inst) == false) continue; escapingInsts.setBit(inst->getId(),true); @@ -311,7 +310,7 @@ initialize(Inst* inst, case Op_Phi: break; default: - break; + break; } // // initialize work list according to: @@ -385,8 +384,8 @@ initialize(Inst* inst, workList.push_back(inst->getSrc(0)->getInst()); } break; - default: - break; + default: + break; } } } @@ -416,13 +415,13 @@ EscapeAnalyzer::doAggressiveAnalysis() { // // Initialization step // - const CFGNodeDeque& nodes = irManager.getFlowGraph().getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + Nodes::const_iterator niter; Opnd *returnOpnd = irManager.getReturnOpnd(); for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst* inst=headInst->next();inst!=headInst; inst=inst->next()) { + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst* inst=headInst->getNextInst();inst!=NULL; inst=inst->getNextInst()) { initialize(inst,freeWorkList,defUseBuilder,returnOpnd); } } @@ -437,12 +436,13 @@ EscapeAnalyzer::doAggressiveAnalysis() { } void -DefUseBuilder::initialize(FlowGraph& fg) { - const CFGNodeDeque& nodes = fg.getNodes(); - CFGNodeDeque::const_iterator i; +DefUseBuilder::initialize(ControlFlowGraph& fg) { + const Nodes& nodes = fg.getNodes(); + Nodes::const_iterator i; for(i = nodes.begin(); i != nodes.end(); ++i) { - Inst* label = (*i)->getFirstInst(); - for(Inst* inst = label->next(); inst != label; inst = inst->next()) + Node* node = *i; + Inst* label = (Inst*)node->getFirstInst(); + for(Inst* inst = label->getNextInst(); inst != NULL; inst = inst->getNextInst()) addUses(inst); } } diff --git vm/jitrino/src/optimizer/escapeanalyzer.h vm/jitrino/src/optimizer/escapeanalyzer.h index 7b4c451..1f6a9a1 100644 --- vm/jitrino/src/optimizer/escapeanalyzer.h +++ vm/jitrino/src/optimizer/escapeanalyzer.h @@ -30,11 +30,11 @@ #include "optpass.h" namespace Jitrino { class IRManager; -class FlowGraph; +class ControlFlowGraph; class Inst; -DEFINE_OPTPASS(EscapeAnalysisPass) +//DEFINE_OPTPASS(EscapeAnalysisPass) // // Simple escape analyzer @@ -77,7 +77,7 @@ class DefUseBuilder { public: DefUseBuilder(MemoryManager& mm) : memoryManager(mm), defUseTable(mm) {} - void initialize(FlowGraph& fg); + void initialize(ControlFlowGraph& fg); DefUseLink* getDefUseLinks(Inst* defInst) { return defUseTable[defInst]; diff --git vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.cpp vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.cpp index a287b90..93bfed0 100644 --- vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.cpp +++ vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.cpp @@ -24,11 +24,11 @@ #include "Log.h" #include "gcmanagedpointeranalyzer.h" #include "irmanager.h" #include "deadcodeeliminator.h" -#include "PropertyTable.h" +#include "FlowGraph.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(GCManagedPointerAnalysisPass, gcmap, "GC Managed Pointer to Base Map Construction") +DEFINE_SESSION_ACTION(GCManagedPointerAnalysisPass, opt_gcmap, "GC Managed Pointer to Base Map Construction") void GCManagedPointerAnalysisPass::_run(IRManager& irm) { @@ -44,7 +44,7 @@ _baseMap(*_pBaseMap), _pVarMap(&irManager.getGCBasePointerMap()), _varMap(*_pVarMap), _mapsComputed(false), -_rematerializeMode(!irManager.getParameterTable().lookupBool("opt::gc::build_var_map", true)) +_rematerializeMode(!irManager.getOptimizerFlags().gc_build_var_map) { } @@ -71,13 +71,13 @@ void GCManagedPointerAnalyzer::computeBaseMaps() { assert(_mapsComputed == false); - FlowGraph& fg = _irManager.getFlowGraph(); - MemoryManager mm(fg.getNodeCount()*sizeof(CFGNode*), "GCManagedPointerAnalyzer::computeBaseMaps.mm"); + ControlFlowGraph& fg = _irManager.getFlowGraph(); + MemoryManager mm(fg.getNodes().size()*sizeof(Node*), "GCManagedPointerAnalyzer::computeBaseMaps.mm"); // List of nodes in RPO - StlVector<CFGNode*> nodes(mm); + StlVector<Node*> nodes(mm); fg.getNodesPostOrder(nodes); - StlVector<CFGNode*>::reverse_iterator niter; + StlVector<Node*>::reverse_iterator niter; // List of known static (i.e., non-heap) managed pointers. We can ignore these. StlHashSet<SsaOpnd*> _staticMap(mm); @@ -85,19 +85,19 @@ GCManagedPointerAnalyzer::computeBaseMap #ifndef NDEBUG uint32 iterCount = 0; #endif - bool done = false; + bool done = false; while(!done) { assert(++iterCount <= 2); done = true; for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - if(Log::cat_opt_gc()->isDebugEnabled()) { + Node* node = *niter; + if(Log::isEnabled()) { Log::out() << "Consider block "; - node->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), node); Log::out() << ::std::endl; } - Inst* first = node->getFirstInst(); - for(Inst* inst = first->next(); inst != first; inst = inst->next()) { + Inst* first = (Inst*)node->getFirstInst(); + for(Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { Opnd* dst_ = inst->getDst(); if(!dst_->isNull() && dst_->getType()->isManagedPtr()) { // @@ -141,7 +141,7 @@ #endif } case Op_Phi: { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Consider phi "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -172,7 +172,7 @@ #endif } else { // Not recorded - uninitialized input - need another iteration done = false; - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Undefined arg "; src->print(Log::out()); Log::out() << " - redo" << ::std::endl; @@ -190,9 +190,9 @@ #endif _baseMap[dst] = base; } } // case Op_Phi - break; - default: - break; + break; + default: + break; } // switch(inst->getOpcode()) { } // if(!dst_->isNull() && dst_->getType()->isManagedPtr()) } @@ -210,7 +210,7 @@ GCManagedPointerAnalyzer::addBaseVarDefs BaseMap::iterator i; for(i = _baseMap.begin(); i != _baseMap.end(); ++i) { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Add def for "; i->first->print(Log::out()); Log::out() << ::std::endl; @@ -224,7 +224,7 @@ GCManagedPointerAnalyzer::addBaseVarDefs SsaVarOpnd* GCManagedPointerAnalyzer::insertVarDef(SsaVarOpnd* ptr) { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Insert var def for "; ptr->print(Log::out()); Log::out() << ::std::endl; @@ -288,15 +288,15 @@ GCManagedPointerAnalyzer::analyzeManaged computeBaseMaps(); addBaseVarDefs(); } else { - FlowGraph& fg = _irManager.getFlowGraph(); - MemoryManager mm(fg.getNodeCount()*sizeof(CFGNode*), "GCManagedPointerAnalyzer::analyzeManagedPointers.mm"); + ControlFlowGraph& fg = _irManager.getFlowGraph(); + MemoryManager mm(fg.getNodes().size()*sizeof(Node*), "GCManagedPointerAnalyzer::analyzeManagedPointers.mm"); - StlVector<CFGNode*> nodes(mm); + StlVector<Node*> nodes(mm); fg.getNodesPostOrder(nodes); StlHashSet<SsaOpnd*> _staticMap(mm); - StlVector<CFGNode*>::reverse_iterator niter; + StlVector<Node*>::reverse_iterator niter; #ifndef NDEBUG uint32 k = 0; @@ -306,14 +306,14 @@ #endif assert((++k) <= 3); done = true; for(niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { - CFGNode* node = *niter; - if(Log::cat_opt_gc()->isDebugEnabled()) { + Node* node = *niter; + if(Log::isEnabled()) { Log::out() << "Consider block "; - node->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), node); Log::out() << ::std::endl; } - Inst* first = node->getFirstInst(); - for(Inst* inst = first->next(); inst != first; inst = inst->next()) { + Inst* first = (Inst*)node->getFirstInst(); + for(Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { Opnd* dst_ = inst->getDst(); if(!dst_->isNull() && dst_->getType()->isManagedPtr()) { // @@ -349,7 +349,7 @@ #endif } else { assert(0); if(inst->getOpcode() == Op_AddScaledIndex) { - fg.printDotFile(_irManager.getMethodDesc(), "error", NULL); + FlowGraph::printDotFile(fg, _irManager.getMethodDesc(), "error"); } assert(inst->getOpcode() != Op_AddScaledIndex); } @@ -357,7 +357,7 @@ #endif } case Op_Phi: { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Consider phi "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -379,7 +379,7 @@ #endif } else { if(_staticMap.find(src) == _staticMap.end()) { // Not recorded as a static - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Undefined arg "; src->print(Log::out()); Log::out() << " - redo" << ::std::endl; @@ -394,12 +394,12 @@ #endif if(base != NULL) _baseMap[dst] = base; } else { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Converting " << ::std::endl; - node->print(Log::out()); + FlowGraph::print(Log::out(), node); Log::out() << "Rematerialize for " << ::std::endl; phi->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Opcode opcode = NumOpcodes; FieldDesc* fieldDesc = NULL; @@ -419,7 +419,7 @@ #endif assert(defs.size() == i); defs.push_back(def); Inst* defInst = def->getInst(); - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Process input " << ::std::endl; defInst->print(Log::out()); Log::out() << ::std::endl; @@ -441,7 +441,7 @@ #endif for(uint32 j = 0; j < numArgs; ++j) { SsaTmpOpnd* arg = defInst->getSrc(j)->asSsaTmpOpnd(); assert(arg != NULL); - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Initializing "; arg->print(Log::out()); Log::out() << ::std::endl; @@ -466,13 +466,13 @@ #endif } for(uint32 j = 0; j < numArgs; ++j) { SsaTmpOpnd* arg = defInst->getSrc(j)->asSsaTmpOpnd(); - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Recording "; arg->print(Log::out()); Log::out() << ::std::endl; } if(args[j] != arg) { - Log::cat_opt_gc()->debug << "Must create phi for arg " << (int) j << ::std::endl; + Log::out() << "Must create phi for arg " << (int) j << ::std::endl; args[j] = NULL; argTypes[j] = _irManager.getTypeManager().getCommonType(argTypes[j], arg->getType()); } @@ -485,7 +485,7 @@ #endif for(uint32 j = 0; j < numArgs; ++j) { if(args[j] == NULL) { VarOpnd* var = opndManager.createVarOpnd(argTypes[j], false); - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Creating "; var->print(Log::out()); Log::out() << " for arg " << (int) j << ::std::endl; @@ -505,7 +505,7 @@ #endif _baseMap[ssaVar] = _baseMap[src]; } else { - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Can't find base for "; src->print(Log::out()); Log::out() << " - redo" << ::std::endl; @@ -554,12 +554,12 @@ #endif last = redo; Inst* stVar = instFactory.makeStVar(dst, tmp); stVar->insertAfter(last); - Inst* prev = inst->prev(); + Inst* prev = inst->getPrevInst(); inst->unlink(); inst = prev; - if(Log::cat_opt_gc()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "to " << ::std::endl; - node->print(Log::out()); + FlowGraph::print(Log::out(), node); } } break; diff --git vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.h vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.h index 16865f7..7ab6f10 100644 --- vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.h +++ vm/jitrino/src/optimizer/gcmanagedpointeranalyzer.h @@ -25,7 +25,6 @@ #define _GC_MANAGED_POINTER_ANALYZER_H_ #include "open/types.h" #include "Stl.h" -#include "optpass.h" namespace Jitrino { @@ -37,7 +36,6 @@ class VarOpnd; class SsaVarOpnd; class Type; -DEFINE_OPTPASS(GCManagedPointerAnalysisPass) class GCManagedPointerAnalyzer { public: diff --git vm/jitrino/src/optimizer/globalcodemotion.cpp vm/jitrino/src/optimizer/globalcodemotion.cpp index a204a27..44c4e68 100644 --- vm/jitrino/src/optimizer/globalcodemotion.cpp +++ vm/jitrino/src/optimizer/globalcodemotion.cpp @@ -25,11 +25,9 @@ #include <iostream> #include <algorithm> #include "Stl.h" #include "Log.h" -#include "PropertyTable.h" #include "open/types.h" #include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" #include "Loop.h" #include "globalcodemotion.h" @@ -41,15 +39,20 @@ #include "optimizer.h" #include "hashvaluenumberer.h" #include "aliasanalyzer.h" #include "memoryopt.h" +#include "FlowGraph.h" +#include "optpass.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(GlobalCodeMotionPass, gcm, "Global Code Motion") + static void printLabel(std::ostream& os, DominatorNode* dNode) { + FlowGraph::printLabel(os, dNode->getNode()); + } + +DEFINE_SESSION_ACTION(GlobalCodeMotionPass, gcm, "Global Code Motion") -void -GlobalCodeMotionPass::_run(IRManager& irm) { - splitCriticalEdges(irm); - computeDominatorsAndLoops(irm); +void GlobalCodeMotionPass::_run(IRManager& irm) { + OptPass::splitCriticalEdges(irm); + OptPass::computeDominatorsAndLoops(irm); MemoryManager& memoryManager = irm.getNestedMemoryManager(); DominatorTree* dominatorTree = irm.getDominatorTree(); LoopTree* loopTree = irm.getLoopTree(); @@ -58,17 +61,16 @@ GlobalCodeMotionPass::_run(IRManager& ir gcm.runPass(); } -DEFINE_OPTPASS_IMPL(GlobalValueNumberingPass, gvn, "Global Value Numbering") +DEFINE_SESSION_ACTION(GlobalValueNumberingPass, gvn, "Global Value Numbering") -void -GlobalValueNumberingPass::_run(IRManager& irm) { - computeDominatorsAndLoops(irm); +void GlobalValueNumberingPass::_run(IRManager& irm) { + OptPass::computeDominatorsAndLoops(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); assert(dominatorTree && dominatorTree->isValid()); LoopTree* loopTree = irm.getLoopTree(); assert(loopTree && loopTree->isValid()); MemoryManager& memoryManager = irm.getNestedMemoryManager(); - FlowGraph& flowGraph = irm.getFlowGraph(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); DomFrontier frontier(memoryManager,*dominatorTree,&flowGraph); TypeAliasAnalyzer aliasAnalyzer; @@ -80,7 +82,6 @@ GlobalValueNumberingPass::_run(IRManager } -GlobalCodeMotion::Flags *GlobalCodeMotion::defaultFlags = 0; GlobalCodeMotion::GlobalCodeMotion(IRManager &irManager0, MemoryManager& memManager, @@ -92,13 +93,12 @@ GlobalCodeMotion::GlobalCodeMotion(IRMan mm(memManager), dominators(dom0), loopTree(loopTree0), - flags(*defaultFlags), + flags(*irManager.getOptimizerFlags().gcmFlags), earliest(memManager), latest(memManager), visited(memManager), uses(memManager) { - assert(defaultFlags); } GlobalCodeMotion::~GlobalCodeMotion() @@ -106,42 +106,43 @@ GlobalCodeMotion::~GlobalCodeMotion() } void -GlobalCodeMotion::readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params) -{ - if (!defaultFlags) - defaultFlags = new Flags; - defaultFlags->dry_run = params->lookupBool("opt::gcm::dry_run", false); - defaultFlags->sink_stvars = params->lookupBool("opt::gcm::sink_stvars", false); - defaultFlags->min_cut = params->lookupBool("opt::gcm::min_cut", false); - defaultFlags->sink_constants = params->lookupBool("opt::gcm::sink_constants", true); +GlobalCodeMotion::readFlags(Action* argSource, GcmFlags* flags) { + IAction::HPipeline p = NULL; //default pipeline for argSource + flags->dry_run = argSource->getBoolArg(p, "gcm.dry_run", false); + flags->sink_stvars = argSource->getBoolArg(p, "gcm.sink_stvars", false); + flags->min_cut = argSource->getBoolArg(p, "gcm.min_cut", false); + flags->sink_constants = argSource->getBoolArg(p, "gcm.sink_constants", false); } -void GlobalCodeMotion::showFlagsFromCommandLine() -{ - Log::out() << " opt::gcm::dry_run[={on|OFF}] = don't really move anything" << ::std::endl; - Log::out() << " opt::gcm::sink_stvars[={on|OFF}] = raise ldvar, sink stvar to Phi nodes" - << ::std::endl; - Log::out() << " opt::gcm::min_cut[={on|OFF}] = duplicate placement on mincut between def and uses" << ::std::endl; - Log::out() << " opt::gcm::sink_constants[={ON|off}] = sink constants after placement" << ::std::endl; +void GlobalCodeMotion::showFlags(std::ostream& os) { + os << " global code motion flags:"<<std::endl; + os << " gcm.dry_run[={on|OFF}] - don't really move anything" << std::endl; + os << " gcm.sink_stvars[={on|OFF}] - raise ldvar, sink stvar to Phi nodes" << std::endl; + os << " gcm.min_cut[={on|OFF}] - duplicate placement on mincut between def and uses" << std::endl; + os << " gcm.sink_constants[={ON|off}] - sink constants after placement" << std::endl; } -void GlobalCodeMotion::runPass() -{ - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gcm()->isIR2Enabled()) { - Log::out() << "IR before GCM pass" << ::std::endl; - fg.printInsts(Log::out(), methodDesc); - fg.printDotFile(methodDesc, "beforegcm", &dominators); +void GlobalCodeMotion::runPass() { + if (flags.dry_run && !flags.sink_constants) return; + + if (Log::isEnabled()) { + Log::out() << "IR before GCM pass" << std::endl; + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), methodDesc); + FlowGraph::printDotFile(irManager.getFlowGraph(), methodDesc, "beforegcm"); dominators.printDotFile(methodDesc, "beforegcm.dom"); + dominators.printIndentedTree(Log::out(), "beforegcm.dom"); loopTree->printDotFile(methodDesc, "beforegcm.loop"); } - // schedule instructions early - scheduleAllEarly(); - // now earliest[i] = domNode for earliest placement. + if (!flags.dry_run) { + // schedule instructions early + scheduleAllEarly(); + // now earliest[i] = domNode for earliest placement. - clearVisited(); + clearVisited(); - scheduleAllLate(); + scheduleAllLate(); + } // sink loads of constants, since IPF back-end doesn't re-materialize if (flags.sink_constants) @@ -150,10 +151,10 @@ void GlobalCodeMotion::runPass() // for now, we don't move Phis, Ldvars, or Stvars, so Ssa form is unaffected // fixSsaForm(); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "IR after GCM pass" << ::std::endl; - fg.printInsts(Log::out(), methodDesc); - fg.printDotFile(methodDesc, "aftergcm", &dominators); + if (Log::isEnabled() ) { + Log::out() << "IR after GCM pass" << std::endl; + FlowGraph::printHIR(Log::out(),irManager.getFlowGraph(), methodDesc); + FlowGraph::printDotFile( irManager.getFlowGraph(), methodDesc, "aftergcm"); dominators.printDotFile(methodDesc, "aftergcm.dom"); } } @@ -163,26 +164,26 @@ void GlobalCodeMotion::runPass() // a DomNodeInstWalker, forwards/preorder class GcmScheduleEarlyWalker { GlobalCodeMotion *thePass; - CFGNode *block; + Node *block; DominatorNode *domNode; public: void startNode(DominatorNode *domNode0) { domNode = domNode0; block = domNode->getNode(); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + if (Log::isEnabled() ) { Log::out() << "Begin early scheduling of block "; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; void applyToInst(Inst *i) { thePass->scheduleEarly(domNode, i); }; void finishNode(DominatorNode *domNode) { - CFGNode *block1 = domNode->getNode(); + Node *block1 = domNode->getNode(); if( !(block == block1) ) assert(0); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + if (Log::isEnabled() ) { Log::out() << "Done early scheduling of block "; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; @@ -218,140 +219,148 @@ void GlobalCodeMotion::scheduleEarly(Dom { if (i->isLabel()) return; if (alreadyVisited(i)) { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst is already scheduled early: "; - i->print(Log::out()); - Log::out() << ::std::endl; + /* if (Log::isEnabled() ) { + Log::out() << "= Inst is already scheduled early: "; i->print(Log::out()); + Log::out() << std::endl; } + */ return; - } else { - markAsVisited(i); - - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Beginning early scheduling of inst "; - i->print(Log::out()); - Log::out() << ::std::endl; - } - - if (isPinned(i)) { - // leave it here - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst is pinned" << ::std::endl; - } + } - // We place operands before placing instruction, to get ordering right - // in the block; in normal code, operands should appear first and - // have been already placed, but after GVN we don't have that guarantee. - if (i->getOpcode() != Op_Phi) { // phi operands must also be pinned, skip them. - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst is not a Phi, processing operands" << ::std::endl; - } - // for others, record uses in this instruction - uint32 numSrcs = i->getNumSrcOperands(); - for (uint32 srcNum=0; srcNum < numSrcs; ++srcNum) { - Opnd *srcOpnd = i->getSrc(srcNum); - Inst *srcInst = srcOpnd->getInst(); - scheduleEarly(0, srcInst); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Recording that "; - srcInst->print(Log::out()); - Log::out() << " is used by "; - i->print(Log::out()); - Log::out() << ::std::endl; - } - uses[srcInst].insert(i); - } - } + Node *cfgNode = i->getNode(); + if (domNode==NULL) { + domNode = dominators.getDominatorNode(cfgNode); + } + bool pinned = isPinned(i); + markAsVisited(i); - // now place instruction - if (domNode) { - earliest[i] = domNode; - } else { - CFGNode *cfgNode = i->getNode(); - DominatorNode *domNode1 = dominators.getDominatorNode(cfgNode); - earliest[i] = domNode1; - } + if (Log::isEnabled() ) { + Log::out() << "< Beginning early scheduling of " << (pinned?"":"not"); + Log::out() << " pinned inst "; i->print(Log::out()); + Log::out() << std::endl; + } - if (i->getOperation().canThrow()) { - // as a special case, mark it as being in the normal successor node; - // this will cause dependent instructions to be placed correctly. - CFGNode *peiNode = earliest[i]->getNode(); - - const CFGEdgeDeque &outedges = peiNode->getOutEdges(); - typedef CFGEdgeDeque::const_iterator EdgeIter; - EdgeIter eLast = outedges.end(); - DominatorNode *newDom = 0; - for (EdgeIter eIter = outedges.begin(); eIter != eLast; eIter++) { - CFGEdge *outEdge = *eIter; - CFGEdge::Kind kind = outEdge->getEdgeType(); - if (kind != CFGEdge::Exception) { - CFGNode *succBlock = outEdge->getTargetNode(); - newDom = dominators.getDominatorNode(succBlock); - break; - } - } - if (newDom) { - earliest[i] = newDom; - } + if (pinned) { // leave it here + // We place operands before placing instruction, to get ordering right + // in the block; in normal code, operands should appear first and + // have been already placed, but after GVN we don't have that guarantee. + if (i->getOpcode() != Op_Phi) { // phi operands must also be pinned, skip them. + if (Log::isEnabled() ) { + Log::out() << " Inst is not a Phi, processing operands" << std::endl; } - - } else { - // figure out earliest placement - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst is not pinned:"; - i->print(Log::out()); - Log::out()<< ::std::endl; - } - DominatorNode *currentEarliest = dominators.getDominatorRoot(); + // for others, record uses in this instruction uint32 numSrcs = i->getNumSrcOperands(); for (uint32 srcNum=0; srcNum < numSrcs; ++srcNum) { Opnd *srcOpnd = i->getSrc(srcNum); Inst *srcInst = srcOpnd->getInst(); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst "; - i->print(Log::out()); - Log::out() << " uses "; - srcInst->print(Log::out()); - Log::out()<< ::std::endl; - } scheduleEarly(0, srcInst); - DominatorNode *srcInstEarliest = earliest[srcInst]; - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst "; - i->print(Log::out()); - Log::out() << " uses "; - srcInst->print(Log::out()); - Log::out() << ", which had early placement in "; - srcInstEarliest->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled() ) { + Log::out() << " Recording that "; srcInst->print(Log::out()); + Log::out() << " is used by "; i->print(Log::out()); + Log::out() << std::endl; } - // Note that both currentEarliest and srcInstEarliest dominate this instruction. - // Thus one of them must dominate the other. The dominated one is the earliest place - // we can put this. - if (dominators.isAncestor(currentEarliest, srcInstEarliest)) { - // must move currentEarliest down to have srcOpnd available - currentEarliest = srcInstEarliest; - } - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Recording that "; - srcInst->print(Log::out()); - Log::out() << " is used by "; - i->print(Log::out()); - Log::out() << ::std::endl; + uses[srcInst].insert(i); + } + } + + // now place instruction + earliest[i] = domNode; + + if (i->getOperation().canThrow()) { + // as a special case, mark it as being in the normal successor node; + // this will cause dependent instructions to be placed correctly. + Node *peiNode = earliest[i]->getNode(); + + const Edges &outedges = peiNode->getOutEdges(); + typedef Edges::const_iterator EdgeIter; + EdgeIter eLast = outedges.end(); + DominatorNode *newDom = 0; + for (EdgeIter eIter = outedges.begin(); eIter != eLast; eIter++) { + Edge *outEdge = *eIter; + Edge::Kind kind = outEdge->getKind(); + if (kind != Edge::Kind_Dispatch) { + Node *succBlock = outEdge->getTargetNode(); + newDom = dominators.getDominatorNode(succBlock); + break; } - uses[srcInst].insert(i); // record the use while we're iterating. + } + if (newDom) { + earliest[i] = newDom; } - earliest[i] = currentEarliest; } - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Done earliest placement of "; - i->print(Log::out()); - Log::out() << " is in block "; - earliest[i]->print(Log::out()); - Log::out() << ::std::endl; + } else { + // not pinned, figure out earliest placement + DominatorNode *currentEarliest = dominators.getDominatorRoot(); + DominatorNode *srcInstEarliest = NULL; + uint32 numSrcs = i->getNumSrcOperands(); + for (uint32 srcNum=0; srcNum < numSrcs; ++srcNum) { + Opnd *srcOpnd = i->getSrc(srcNum); + Inst *srcInst = srcOpnd->getInst(); + scheduleEarly(0, srcInst); + srcInstEarliest = earliest[srcInst]; + // Note that both currentEarliest and srcInstEarliest dominate this instruction. + // Thus one of them must dominate the other. + // The dominated one is the earliest place we can put this. + if (currentEarliest->isAncestorOf(srcInstEarliest)) { + // must move currentEarliest down to have srcOpnd available + currentEarliest = srcInstEarliest; + } + if (Log::isEnabled() ) { + Log::out() << " Inst uses "; srcInst->print(Log::out()); + Log::out() << ", which has early placement in "; FlowGraph::printLabel(Log::out(), srcInstEarliest); + Log::out() << std::endl; + } + uses[srcInst].insert(i); // record the use while we're iterating. } - + srcInstEarliest = currentEarliest; // now is the latest placement of src insts + // moving above catch inst may cause problems in code emitter + // check that we do not cross catch boundaries + // find earliest intermediate basic block, starting from the block containing i + DominatorNode *instEarliest = domNode; + for (currentEarliest = domNode; ; currentEarliest = currentEarliest->getParent()) { + Node *candidateNode = currentEarliest->getNode(); + if (Log::isEnabled() ) { + Log::out() << " trying node "; FlowGraph::printLabel(Log::out(), candidateNode); + } + // intermediate basic blocks with catch labels are + // inappropriate to place instructions in + if (candidateNode->isDispatchNode()) { + if (Log::isEnabled() ) { + Log::out() << " ... isDispatchNode"; Log::out() << std::endl; + } + break; + } + LabelInst *first = (LabelInst*)(candidateNode->getFirstInst()); + Inst* next=first->getNextInst(); + if ((next !=NULL) && (next->getOpcode() == Op_Catch)) { + if (Log::isEnabled() ) { + Log::out() << " ... getOpcode() == Op_Catch"; Log::out() << std::endl; + } + instEarliest=currentEarliest; + break; + } + if (first->isCatchLabel()) { + if (Log::isEnabled() ) { + Log::out() << " ... isCatchLabel"; Log::out() << std::endl; + } + break; + } + if (Log::isEnabled() ) { + Log::out() << " ... OK"; Log::out() << std::endl; + } + instEarliest=currentEarliest; + if (currentEarliest==srcInstEarliest) { + break; + } + } // end for + earliest[i] = instEarliest; + } + + if (Log::isEnabled() ) { + Log::out() << "> Done earliest placement of "; i->print(Log::out()); + Log::out() << " is in block "; FlowGraph::printLabel(Log::out(), earliest[i]); + Log::out() << std::endl; } } @@ -360,26 +369,26 @@ void GlobalCodeMotion::scheduleEarly(Dom // a domNodeInstWalker, backwards/postorder class GcmScheduleLateWalker { GlobalCodeMotion *thePass; - CFGNode *block; + Node *block; DominatorNode *domNode; public: void startNode(DominatorNode *domNode0) { domNode = domNode0; block = domNode->getNode(); - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + if (Log::isEnabled() ) { Log::out() << "Begin late scheduling of block "; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; void applyToInst(Inst *i) { thePass->scheduleLate(domNode, 0, i); }; void finishNode(DominatorNode *domNode) { - CFGNode *block1 = domNode->getNode(); + Node *block1 = domNode->getNode(); if( !(block == block1) ) assert(0);; - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + if (Log::isEnabled() ) { Log::out() << "Done late scheduling of block "; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; GcmScheduleLateWalker(GlobalCodeMotion *thePass0) @@ -409,189 +418,180 @@ void GlobalCodeMotion::scheduleAllLate() void GlobalCodeMotion::scheduleLate(DominatorNode *domNode, Inst *basei, Inst *i) { if (i->isLabel()) return; - if (alreadyVisited(i)) { - return; - } else { - markAsVisited(i); + if (alreadyVisited(i)) return; + + if (domNode==NULL) { + domNode = dominators.getDominatorNode(i->getNode()); + } + + markAsVisited(i); + + if (Log::isEnabled() ) { + Log::out() << "< Beginning late scheduling of inst "; + i->print(Log::out()); + Log::out() << std::endl; + } + + bool pinned = isPinned(i); + // figure out where to put it, first scheduling users along the way - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Beginning late scheduling of inst "; - i->print(Log::out()); - Log::out() << ::std::endl; + // schedule users + DominatorNode *lca = 0; + UsesSet &users = uses[i]; + UsesSet::iterator uiter = users.begin(); + UsesSet::iterator uend = users.end(); + + for ( ; uiter != uend; ++uiter) { + Inst *useri = *uiter; + + // schedule use + scheduleLate(domNode, basei, useri); + + if (Log::isEnabled() ) { + Log::out() << "Inst "; i->print(Log::out()); + Log::out() << " is used by inst "; useri->print(Log::out()); + Log::out() << " which is in "; FlowGraph::printLabel(Log::out(), latest[useri]); + Log::out() << std::endl; } - bool pinned = isPinned(i); - // figure out where to put it, first scheduling users along the way - - // schedule users - DominatorNode *lca = 0; - UsesSet &users = uses[i]; - UsesSet::iterator - uiter = users.begin(), - uend = users.end(); - for ( ; uiter != uend; ++uiter) { - Inst *useri = *uiter; - - // schedule use - scheduleLate(domNode, basei, useri); - - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst "; - i->print(Log::out()); - Log::out() << " is used by inst "; - useri->print(Log::out()); - Log::out() << " which is in "; - latest[useri]->print(Log::out()); - Log::out() << ::std::endl; - } - - DominatorNode *usingBlock = latest[useri]; - lca = pinned ? 0 : leastCommonAncestor(lca, usingBlock); - while (lca && (lca->getNode()->isDispatchNode())) { - lca = lca->getParent(); // code can't be placed in dispatch nodes - } + if (pinned) continue; + DominatorNode *usingBlock = latest[useri]; + lca = leastCommonAncestor(lca, usingBlock); + while (lca->getNode()->isDispatchNode()) { + lca = lca->getParent(); // code can't be placed in dispatch nodes } - // if pinned, and following instruction is not already scheduled, + } + + if (pinned) { + // if following instruction is not already scheduled, // then we are scheduling this pinned instruction as a use of some - // other instruction. before scheduling it, we must schedule any + // other instruction. Before scheduling it, we must schedule any // following pinned instruction. - if (pinned) { - Inst *nextInst = i->next(); - while (!nextInst->isLabel() && !alreadyVisited(nextInst)) { - if (isPinned(nextInst)) { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Pinned Inst "; - i->print(Log::out()); - Log::out() << " is followed by unscheduled pinned inst "; - nextInst->print(Log::out()); - Log::out() << ::std::endl; - } - scheduleLate(domNode, basei, nextInst); - // scheduling nextInst should result in scheduling - // any following pinned inst, so break out of loop. - break; - } else { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Pinned Inst "; - i->print(Log::out()); - Log::out() << " is followed by unscheduled unpinned inst "; - nextInst->print(Log::out()); - Log::out() << ::std::endl; - } - nextInst = nextInst->next(); + Inst *nextInst = i->getNextInst(); + while ((nextInst!=NULL) && !alreadyVisited(nextInst)) { + if (isPinned(nextInst)) { + if (Log::isEnabled() ) { + Log::out() << "Pinned Inst "; i->print(Log::out()); + Log::out() << " is followed by unscheduled pinned inst "; + nextInst->print(Log::out()); + Log::out() << std::endl; + } + scheduleLate(domNode, basei, nextInst); + // scheduling nextInst should result in scheduling + // any following pinned inst, so break out of loop. + break; + } else { + if (Log::isEnabled() ) { + Log::out() << "Pinned Inst "; i->print(Log::out()); + Log::out() << " is followed by unscheduled unpinned inst "; + nextInst->print(Log::out()); + Log::out() << std::endl; } + nextInst = nextInst->getNextInst(); } } - - // now, unless pinned, LCA is leastCommonAncestor of all uses + if (Log::isEnabled() ) { + Log::out() << "Inst is pinned, left in place: "; i->print(Log::out()); + Log::out() << std::endl; + } + latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here. + } else if (lca == 0) { // if LCA==0, then there are no uses; i is dead. - - if (pinned) { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst is pinned, left in place: "; - i->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled() ) { + Log::out() << "Inst has no uses, left in place: "; i->print(Log::out()); + Log::out() << std::endl; + } + latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here. + } else { + // now LCA is leastCommonAncestor of all uses + if (i->isLdVar()) { + // moving ldVar late is dangerous: can jump over stVar for the same var + if (domNode->isAncestorOf(lca)) { + lca=domNode; } - latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here. - } else if (lca == 0) { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Inst has no uses, left in place: "; - i->print(Log::out()); - Log::out() << ::std::endl; + } + Node* lcaNode = lca->getNode(); + DominatorNode *best = lca; + Node* bestNode = best->getNode(); + DominatorNode *earliestBlock = earliest[i]; + // code can't be placed in dispatch nodes: + assert(!earliestBlock->getNode()->isDispatchNode()); + if (Log::isEnabled() ) { + Log::out() << " LCA is "; FlowGraph::printLabel(Log::out(), lca); + Log::out() << ", best is "; printLabel(Log::out(), best); + Log::out() << " earliestBlock is "; printLabel(Log::out(), earliestBlock); + Log::out() << std::endl; + } + + while (lca != earliestBlock) { + lca = lca->getParent(); // go up dom tree + lcaNode = lca->getNode(); + assert(lca && lcaNode); + if (lcaNode->isDispatchNode()) { + continue; // code can't be placed in dispatch nodes } - latest[i] = dominators.getDominatorNode(i->getNode()); // leave it here. - } else { - DominatorNode *best = lca; - DominatorNode *earliestBlock = earliest[i]; - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "LCA is "; - lca->print(Log::out()); - Log::out() << ", best is "; - best->print(Log::out()); - Log::out() << " earliestBlock is "; - earliestBlock->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled() ) { + Log::out() << " LCA is "; printLabel(Log::out(), lca); Log::out() << " with depth " << (int)loopTree->getLoopDepth(lcaNode); + Log::out() << ", best is "; printLabel(Log::out(), best); + Log::out() << " with depth " << (int)loopTree->getLoopDepth(bestNode); + Log::out() << std::endl; } - while (lca != earliestBlock) { - assert(lca); - lca = lca->getParent(); // go up dom tree - assert(lca && lca->getNode()); - while (lca->getNode()->isDispatchNode()) { - lca = lca->getParent(); // code can't be placed in dispatch nodes - assert(lca && lca->getNode()); - } - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "LCA is "; - lca->print(Log::out()); - Log::out() << " with depth " - << (int) loopTree->getLoopDepth(lca->getNode()) - << ", best is "; - best->print(Log::out()); - Log::out() << " with depth " - << (int) loopTree->getLoopDepth(best->getNode()); - Log::out() << ::std::endl; + if (loopTree->getLoopDepth(lcaNode) < loopTree->getLoopDepth(bestNode)) { + // find deepest block at shallowest nest + best = lca; + bestNode = lcaNode; + if (Log::isEnabled() ) { + Log::out() << " LCA replaces best" << std::endl; } - - if (loopTree->getLoopDepth(lca->getNode()) < loopTree->getLoopDepth(best->getNode())) { - // find deepest block at shallowest nest - best = lca; - - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "LCA replaces best" << ::std::endl; - } - } - }; - - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Finally, best is "; - best->print(Log::out()); - Log::out() << ::std::endl; } - latest[i] = best; - } + }; - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << "Placing inst "; - i->print(Log::out()); - Log::out() << " in block "; - latest[i]->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled() ) { + Log::out() << " Finally, best is "; printLabel(Log::out(), best); + Log::out() << std::endl; } + latest[i] = best; + } - // now, to actually move the instruction: - - // we always move instructions at the start of the block. - // this looks confusing if we are inserting into the same block - // we are iterating over: we may see the instruction again, but - // this is safe since the instruction is already marked as placed. - - // we do this even for pinned instructions; they will be visited in - // reverse order, so they will be replaced in the block starting at - // the top, so we are ok. - - CFGNode *node = latest[i]->getNode(); - Inst* headInst = node->getFirstInst(); - assert(headInst->isLabel()); - - i->unlink(); - if (i->getOperation().mustEndBlock()) { - // but an instruction which must be at the end must stay there. - // this includes branches. - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << " Placing inst before headinst "; - headInst->print(Log::out()); - Log::out() << ::std::endl; - } - i->insertBefore(headInst); - } else { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { - Log::out() << " Placing inst after headinst "; - headInst->print(Log::out()); - Log::out() << ::std::endl; - } - i->insertAfter(headInst); + if (Log::isEnabled() ) { + Log::out() << " Placing inst "; i->print(Log::out()); + Log::out() << " in block "; printLabel(Log::out(), latest[i]); + Log::out() << std::endl; + } + + // now, to actually move the instruction: + + // we always move instructions at the start of the block. + // this looks confusing if we are inserting into the same block + // we are iterating over: we may see the instruction again, but + // this is safe since the instruction is already marked as placed. + + // we do this even for pinned instructions; they will be visited in + // reverse order, so they will be replaced in the block starting at + // the top, so we are ok. + + Node *node = latest[i]->getNode(); + Inst* headInst = (Inst*)node->getFirstInst(); + assert(headInst->isLabel()); + + i->unlink(); + if (i->getOperation().mustEndBlock()) { + // but an instruction which must be at the end must stay there. + // this includes branches. + if (Log::isEnabled()) { + Log::out() << "> Placing inst before headinst "; + headInst->print(Log::out()); + Log::out() << std::endl; } + node->appendInst(i); + } else { + if (Log::isEnabled()) { + Log::out() << "> Placing inst after headinst "; + headInst->print(Log::out()); + Log::out() << std::endl; + } + node->prependInst(i); } } @@ -615,22 +615,22 @@ DominatorNode *GlobalCodeMotion::leastCo // a NodeInstWalker, forwards/preorder class GcmSinkConstantsWalker { GlobalCodeMotion *thePass; - CFGNode *block; + Node *block; public: - void startNode(CFGNode *cfgNode0) { + void startNode(Node *cfgNode0) { block = cfgNode0; - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + if (Log::isEnabled()) { Log::out() << "Begin sinking constants in block"; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; void applyToInst(Inst *i) { thePass->sinkConstants(i); }; - void finishNode(CFGNode *cfgNode0) { - if (Log::cat_opt_gcm()->isDebugEnabled() || Log::cat_opt_gc()->isIR2Enabled()) { + void finishNode(Node *cfgNode0) { + if (Log::isEnabled() ) { Log::out() << "Done sinking constants in block"; - block->print(Log::out()); - Log::out() << ::std::endl; + FlowGraph::print(Log::out(), block); + Log::out() << std::endl; } }; @@ -678,12 +678,13 @@ bool GlobalCodeMotion::isPinned(Inst *i) { Opcode opcode = i->getOpcode(); // be explicit about SSA ops - if ((opcode == Op_LdVar) || (opcode == Op_StVar) || (opcode == Op_Phi)) +// if ((opcode == Op_LdVar) || (opcode == Op_StVar) || (opcode == Op_Phi)) + if ((opcode == Op_StVar) || (opcode == Op_Phi)) return true; if (i->getOperation().isMovable()) { return false; } - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (0 && optimizerFlags.cse_final) { switch (i->getOpcode()) { case Op_TauLdInd: @@ -740,5 +741,4 @@ void GlobalCodeMotion::clearVisited() visited.clear(); } - } //namespace Jitrino diff --git vm/jitrino/src/optimizer/globalcodemotion.h vm/jitrino/src/optimizer/globalcodemotion.h index c0eaa78..026ff96 100644 --- vm/jitrino/src/optimizer/globalcodemotion.h +++ vm/jitrino/src/optimizer/globalcodemotion.h @@ -26,9 +26,7 @@ #define _GLOBAL_CODE_MOTION_H #include <iostream> #include "open/types.h" #include "Opcode.h" -#include "FlowGraph.h" #include "Stl.h" -#include "optpass.h" #include <utility> namespace Jitrino { @@ -40,42 +38,37 @@ class MemoryManager; class InequalityGraph; class DominatorNode; class Dominator; -class JitrinoParameterTable; -class CFGNode; +class Node; class Opnd; class CSEHashTable; class Type; class LoopTree; +struct GcmFlags { + bool dry_run; + bool sink_stvars; + bool min_cut; + bool sink_constants; +}; + + /* * Implementation of Global Code Motion, * [C.Click. Global Code Motion, Global Value Numbering. PLDI 1995] */ -DEFINE_OPTPASS(GlobalCodeMotionPass) - -DEFINE_OPTPASS(GlobalValueNumberingPass) - class GlobalCodeMotion { IRManager& irManager; - FlowGraph& fg; + ControlFlowGraph& fg; MethodDesc& methodDesc; MemoryManager &mm; DominatorTree& dominators; LoopTree *loopTree; -public: - struct Flags { - bool dry_run; - bool sink_stvars; - bool min_cut; - bool sink_constants; - }; private: - static Flags *defaultFlags; - Flags flags; + GcmFlags& flags; public: - static void readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params); - static void showFlagsFromCommandLine(); + static void readFlags(Action* argSource, GcmFlags* flags); + static void showFlags(std::ostream& os); GlobalCodeMotion(IRManager &irManager0, MemoryManager& memManager, @@ -97,7 +90,7 @@ private: UsesMap uses; void scheduleAllEarly(); - void scheduleBlockEarly(CFGNode *n); + void scheduleBlockEarly(Node *n); void scheduleEarly(DominatorNode *domNode, Inst *i); void scheduleAllLate(); diff --git vm/jitrino/src/optimizer/globalopndanalyzer.cpp vm/jitrino/src/optimizer/globalopndanalyzer.cpp index 651e0d8..66870ab 100644 --- vm/jitrino/src/optimizer/globalopndanalyzer.cpp +++ vm/jitrino/src/optimizer/globalopndanalyzer.cpp @@ -22,44 +22,35 @@ #include "globalopndanalyzer.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" #include "Inst.h" #include "Loop.h" #include "BitSet.h" #include "Log.h" +#include "optpass.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(GlobalOperandAnalysisPass, markglobals, "Basic Block based Global Operand Analysis") +DEFINE_SESSION_ACTION(GlobalOperandAnalysisPass, markglobals, "Basic Block based Global Operand Analysis") void GlobalOperandAnalysisPass::_run(IRManager& irm) { - computeDominators(irm); - computeLoops(irm); + OptPass::computeDominators(irm); + OptPass::computeLoops(irm); AdvancedGlobalOpndAnalyzer globalOpndAnalyzer(irm, *irm.getLoopTree()); globalOpndAnalyzer.doAnalysis(); } // -// Get list of nodes in postorder -// -void -GlobalOpndAnalyzer::getNodesInPostorder() { - nodes.reserve(flowGraph.getMaxNodeId()); - flowGraph.getNodesPostOrder(nodes); -} - -// // Reset global bits // void GlobalOpndAnalyzer::resetGlobalBits() { - ::std::vector<CFGNode*>::iterator niter; + Nodes::iterator niter; for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { // // SsaVarOpnds and VarOpnds are always global; we care only about // SsaTmpOpnds. @@ -86,11 +77,11 @@ GlobalOpndAnalyzer::markGlobals() { uint32 numInsts = irManager.getInstFactory().getNumInsts(); MemoryManager memManager(numInsts/8+4,"GlobalOpndAnalyzer::doAnalysis()"); BitSet markedInstSet(memManager,numInsts); - ::std::vector<CFGNode*>::iterator niter; + Nodes::iterator niter; for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst* headInst = node->getFirstInst(); - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + Node* node = *niter; + Inst* headInst = (Inst*)node->getFirstInst(); + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { // mark as visited markedInstSet.setBit(inst->getId(),true); // check sources to see if any span globally @@ -107,7 +98,7 @@ GlobalOpndAnalyzer::markGlobals() { // if (markedInstSet.getBit(src->getInst()->getId()) == false) { src->setIsGlobal(true); - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "XXX - GlobalOpnd:";src->getInst()->print(Log::out()); Log::out() << ::std::endl; } } @@ -118,23 +109,13 @@ GlobalOpndAnalyzer::markGlobals() { void GlobalOpndAnalyzer::doAnalysis() { - getNodesInPostorder(); + nodes.reserve(flowGraph.getNodeCount()); + flowGraph.getNodesPostOrder(nodes); resetGlobalBits(); // mark temporaries whose live spans basic block boundary as globals markGlobals(); } -bool -AdvancedGlobalOpndAnalyzer::cfgContainsLoops() { - ::std::vector<CFGNode*>::iterator niter; - for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - if (loopInfo.isLoopHeader(node)) - return true; - } - return false; -} - // // Information about a global operand @@ -217,14 +198,13 @@ AdvancedGlobalOpndAnalyzer::markManagedP // // Walk nodes in postorder // - ::std::vector<CFGNode*>::iterator niter; + Nodes::iterator niter; for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; // // Walk instructions in reverse order // - Inst* headInst = node->getFirstInst(); - for (Inst* inst = headInst->prev(); inst!=headInst; inst=inst->prev()) { + for (Inst* inst = (Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()) { Opcode opcode = inst->getOpcode(); // If the managed pointer generated by an instruction is global, its source // should also be marked as global. (Though, technically only if the managed @@ -238,17 +218,17 @@ AdvancedGlobalOpndAnalyzer::markManagedP case Op_LdElemAddr: case Op_LdArrayBaseAddr: case Op_AddScaledIndex: - { + { Opnd* src = inst->getSrc(0); Opnd* dst = inst->getDst(); if(!src->isGlobal() && dst->isGlobal()) { assert(dst->getType()->isManagedPtr()); src->setIsGlobal(true); } - }; + }; break; - default: - break; + default: + break; } } } @@ -263,22 +243,20 @@ AdvancedGlobalOpndAnalyzer::unmarkFalseG // // Walk nodes in postorder // - ::std::vector<CFGNode*>::iterator niter; + Nodes::iterator niter; for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; timeStamp++; // // Figure out the current loop header // - uint32 dfNum = node->getDfNum(); - uint32 currHeader = loopInfo.isLoopHeader(node) ? dfNum - : loopInfo.hasContainingLoopHeader(node) ? loopInfo.getContainingLoopHeader(node)->getDfNum() - : (uint32)-1; + Node* header = loopInfo.getLoopHeader(node, false); + uint32 currHeader = header != NULL ? header->getDfNum() : (uint32)-1; + // // Walk instructions in reverse order // - Inst* headInst = node->getFirstInst(); - for (Inst* inst = headInst->prev(); inst!=headInst; inst=inst->prev()) { + for (Inst* inst = (Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()) { // // Analyze sources // @@ -316,7 +294,7 @@ AdvancedGlobalOpndAnalyzer::unmarkFalseG while (tableIter.getNextElem(opnd,info)) { if (info->isGlobal == false) { opnd->setIsGlobal(false); - if(Log::cat_opt()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "XXX - Not a Global Opnd:"; opnd->print(Log::out()); Log::out() << ::std::endl; @@ -331,7 +309,7 @@ AdvancedGlobalOpndAnalyzer::markGlobals( // // If CFG does not contain any loops there are no global temporaries // - if (!cfgContainsLoops()) + if (!flowGraph.getLoopTree()->hasLoops()) return; // // Mark temporaries whose live spans basic block as globals diff --git vm/jitrino/src/optimizer/globalopndanalyzer.h vm/jitrino/src/optimizer/globalopndanalyzer.h index d3cc946..83f4dcc 100644 --- vm/jitrino/src/optimizer/globalopndanalyzer.h +++ vm/jitrino/src/optimizer/globalopndanalyzer.h @@ -25,38 +25,34 @@ #define _GLOBALOPNDANALYZER_H_ class IRManager; class Dominator; -class CFGNode; +class Node; class Inst; class LoopTree; #include "Stl.h" #include "irmanager.h" -#include "optpass.h" namespace Jitrino { -DEFINE_OPTPASS(GlobalOperandAnalysisPass) - // // Global operand analyzer marks temporaries whose live range spans // a basic block boundary as globals // class GlobalOpndAnalyzer { public: - GlobalOpndAnalyzer(IRManager& irm, FlowGraph* region=NULL) - : irManager(irm), flowGraph((region != NULL) ? *region : irm.getFlowGraph()) + GlobalOpndAnalyzer(IRManager& irm, ControlFlowGraph* region=NULL) + : irManager(irm), flowGraph((region != NULL) ? *region : irm.getFlowGraph()), nodes(irm.getMemoryManager()) { } void doAnalysis(); virtual ~GlobalOpndAnalyzer() {}; protected: - void getNodesInPostorder(); void resetGlobalBits(); virtual void markGlobals(); IRManager& irManager; - FlowGraph& flowGraph; - ::std::vector<CFGNode*> nodes; + ControlFlowGraph& flowGraph; + Nodes nodes; }; // @@ -71,7 +67,6 @@ public: {} virtual ~AdvancedGlobalOpndAnalyzer() {}; private: - bool cfgContainsLoops(); void analyzeInst(Inst* inst, uint32 loopHeader, uint32 timeStamp); void unmarkFalseGlobals(); void markManagedPointerBases(); diff --git vm/jitrino/src/optimizer/hashvaluenumberer.cpp vm/jitrino/src/optimizer/hashvaluenumberer.cpp index eb97934..bab26ff 100644 --- vm/jitrino/src/optimizer/hashvaluenumberer.cpp +++ vm/jitrino/src/optimizer/hashvaluenumberer.cpp @@ -40,7 +40,7 @@ #include "memoryopt.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(HashValueNumberingPass,hvn,"Hash Value Numbering (CSE)") +DEFINE_SESSION_ACTION(HashValueNumberingPass,hvn,"Hash Value Numbering (CSE)") void HashValueNumberingPass::_run(IRManager& irm) { @@ -68,7 +68,7 @@ public: } void enterScope() { - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Entering VN scope" << ::std::endl; } cseHashTable.enter_scope(); @@ -79,7 +79,7 @@ public: if (constantTable) constantTable->exit_scope(); cseHashTable.exit_scope(); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Exiting VN scope" << ::std::endl; } }; @@ -89,12 +89,12 @@ public: DominatorTree &domTree0, MemoryOpt *mopt, bool cse_final0, - FlowGraph &fg0, + ControlFlowGraph &fg0, bool is_scoped) : memoryManager(memoryManager0), cseHashTable(fg0.getNodes().size() * - irm.getCompilationContext()->getOptimizerFlags()->hash_node_tmp_factor, - memoryManager, *irm.getCompilationContext()->getOptimizerFlags()), + irm.getOptimizerFlags().hash_node_tmp_factor, + memoryManager, irm.getOptimizerFlags()), constantTable(0), irManager(irm), tauUnsafe(0), @@ -104,7 +104,7 @@ public: cse_final(cse_final0), fg(fg0) { - OptimizerFlags& optimizerFlags = *irm.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irm.getOptimizerFlags(); if (is_scoped && optimizerFlags.hvn_constants) { constantTable = new (memoryManager) SparseOpndMap(fg0.getNodes().size() * optimizerFlags.hash_node_constant_factor, @@ -169,7 +169,7 @@ public: // control flow Inst* caseBranch(BranchInst* inst) { Inst *res = lookupInst(inst); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "caseBranch "; inst->print(Log::out()); Log::out() << " yields "; @@ -205,9 +205,7 @@ public: Inst* caseCatch(Inst* inst) { return caseDefault(inst); } - Inst* caseThrow(Inst* inst) { return caseDefault(inst); } - - Inst* caseThrowLazy(Inst* inst) { return caseDefault(inst); } + Inst* caseThrow(Inst* inst) { return caseDefault(inst); } Inst* caseThrowSystemException(Inst* inst) { return caseDefault(inst); } @@ -237,9 +235,9 @@ public: caseDefArg(Inst* inst) { return caseDefault(inst); } // load of constants - Inst* caseLdConstant(ConstInst* inst) { return hashInst(inst); } - Inst* caseLdNull(ConstInst* inst) { return hashInst(inst); } - Inst* caseLdString(TokenInst* inst) { return hashInst(inst); } + Inst* caseLdConstant(ConstInst* inst) { return hashInst(inst); } + Inst* caseLdNull(ConstInst* inst) { return hashInst(inst); } + Inst* caseLdRef(TokenInst* inst) { return hashInst(inst); } // variable access Inst* caseLdVar(Inst* inst) { @@ -284,7 +282,7 @@ public: (memOpt && !is_volatile)) { Inst *res = lookupInst(inst); Operation op = inst->getOperation(); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Ldind looking for " << (int) op.encodeForHashing() << ", " @@ -292,7 +290,7 @@ public: << ::std::endl; } if (res != inst) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "found hash" << ::std::endl; } if (res->getOpcode() == Op_TauLdInd) { @@ -310,7 +308,7 @@ public: } // if previous cases fail, { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "not found" << ::std::endl; } Type::Tag tag = inst->getType(); @@ -332,14 +330,14 @@ public: Operation newop = inst->getOperation(); newop.setType(otherTag); CSEHashKey key = getKey(newop, inst->getSrc(0)->getId()); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Ldind looking for changed-sign form " << (int) newop.encodeForHashing() << ::std::endl; } Inst *res = lookupInst(inst, key); if (res != inst) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "found hash" << ::std::endl; } Opnd *dataOpnd = 0; @@ -364,7 +362,7 @@ public: dstType->tag, newDst, dataOpnd); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Ldind replaced by convInst "; convInst->print(Log::out()); Log::out() << ::std::endl; @@ -373,7 +371,7 @@ public: return convInst; } } - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "not found" << ::std::endl; } } @@ -546,7 +544,7 @@ public: Opnd *addrOp = inst->getSrc(1); Type::Tag typetag = inst->getType(); Operation op(Op_TauLdInd, typetag); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Stind hashing Ldind : " << (int) op.encodeForHashing() << ", " @@ -1155,7 +1153,7 @@ private: } Inst* setHashToInst(Inst* inst, const CSEHashKey &key) { if (!key.isNull()) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "setting hash "; key.print(Log::out()); Log::out() << " to inst "; @@ -1170,7 +1168,7 @@ private: if (!key.isNull()) { Inst* newInst = cseHashTable.lookup(key); if (newInst != NULL) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "looking for hash "; key.print(Log::out()); Log::out() << " found inst "; @@ -1179,7 +1177,7 @@ private: } return newInst; } else { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "looking for hash "; key.print(Log::out()); Log::out() << " found NULL" << ::std::endl; @@ -1219,7 +1217,7 @@ private: } Inst* lookupInst(BranchInst* inst) { Inst *res = lookupInst(inst, getKey(inst)); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "lookupInst(Branch "; inst->print(Log::out()); Log::out() << " with hashcode " @@ -1248,9 +1246,9 @@ private: public: void addBranchConditions(DominatorNode* domNode); private: - void addInfoFromBranch(CFGNode* targetNode, BranchInst *branchi, bool isTrueEdge); - void addInfoFromPredBranch(CFGNode* targetNode, BranchInst *branchi, bool isTrueEdge); - void addInfoFromBranchCompare(CFGNode* targetNode, + void addInfoFromBranch(Node* targetNode, BranchInst *branchi, bool isTrueEdge); + void addInfoFromPredBranch(Node* targetNode, BranchInst *branchi, bool isTrueEdge); + void addInfoFromBranchCompare(Node* targetNode, ComparisonModifier mod, Type::Tag comparisonType, bool isTrueEdge, @@ -1268,52 +1266,61 @@ protected: DominatorTree &domTree; MemoryOpt *memOpt; bool cse_final; - FlowGraph &fg; + ControlFlowGraph &fg; public: Inst* getTauUnsafe() { if (!tauUnsafe) { - CFGNode *head = fg.getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = fg.getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *inst = entryLabel->next(); - while (inst != entryLabel) { + Inst *inst = entryLabel->getNextInst(); + while (inst != NULL) { if (inst->getOpcode() == Op_TauUnsafe) { tauUnsafe = inst; return tauUnsafe; } - inst = inst->next(); + inst = inst->getNextInst(); } TypeManager &tm = irManager.getTypeManager(); Opnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); tauUnsafe = irManager.getInstFactory().makeTauUnsafe(tauOpnd); // place after label and Phi instructions - inst = entryLabel->next(); - while (inst != entryLabel) { + inst = entryLabel->getNextInst(); + while (inst != NULL) { Opcode opc = inst->getOpcode(); if ((opc != Op_Phi) && (opc != Op_TauPi) && (opc != Op_TauPoint) && (opc != Op_TauEdge)) break; - inst = inst->next(); + inst = inst->getNextInst(); } - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauUnsafe inst "; tauUnsafe->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } Log::out() << ::std::endl; } - tauUnsafe->insertBefore(inst); + if (inst != NULL) { + tauUnsafe->insertBefore(inst); + } else { + head->appendInst(tauUnsafe); + } + } return tauUnsafe; }; - Opnd* getBlockTauPoint(CFGNode *block) { - Inst *firstInst = block->getFirstInst(); - Inst *inst = firstInst->next(); - for (; inst != firstInst; inst = inst->next()) { - if (inst->getOpcode() == Op_TauPoint) return inst->getDst(); + Opnd* getBlockTauPoint(Node *block) { + Inst *firstInst = (Inst*)block->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + for (; inst != NULL; inst = inst->getNextInst()) { + if (inst->getOpcode() == Op_TauPoint) { + return inst->getDst(); + } } - for (inst = firstInst->next(); inst != firstInst; inst = inst->next()) { + for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (inst->getOpcode() != Op_Phi) { break; // insert before inst. } @@ -1322,25 +1329,32 @@ public: TypeManager &tm = irManager.getTypeManager(); Opnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst* tauPoint = irManager.getInstFactory().makeTauPoint(tauOpnd); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauPoint "; tauPoint->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } Log::out() << ::std::endl; } - tauPoint->insertBefore(inst); + if (inst!=NULL) { + tauPoint->insertBefore(inst); + } else { + block->appendInst(tauPoint); + } return tauOpnd; } - Opnd* getBlockTauEdge(CFGNode *block) { - Inst *firstInst = block->getFirstInst(); - Inst *inst = firstInst->next(); - for (; inst != firstInst; inst = inst->next()) { - if (inst->getOpcode() == Op_TauEdge) return inst->getDst(); + Opnd* getBlockTauEdge(Node *block) { + Inst *firstInst = (Inst*)block->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + for (; inst != NULL; inst = inst->getNextInst()) { + if (inst->getOpcode() == Op_TauEdge) { + return inst->getDst(); + } } - for (inst = firstInst->next(); inst != firstInst; inst = inst->next()) { - if ((inst->getOpcode() != Op_Phi) - && (inst->getOpcode() != Op_TauPoint)) { + for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + if ((inst->getOpcode() != Op_Phi) && (inst->getOpcode() != Op_TauPoint)) { break; // insert before inst. } } @@ -1348,14 +1362,20 @@ public: TypeManager &tm = irManager.getTypeManager(); Opnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); Inst* tauEdge = irManager.getInstFactory().makeTauEdge(tauOpnd); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting tauEdge "; tauEdge->print(Log::out()); - Log::out() << " before inst "; - inst->print(Log::out()); + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } Log::out() << ::std::endl; } - tauEdge->insertBefore(inst); + if (inst != NULL) { + tauEdge->insertBefore(inst); + } else { + block->appendInst(tauEdge); + } return tauOpnd; } bool allowsConstantPropagation(ComparisonModifier mod, Type::Tag comparisonType, @@ -1373,9 +1393,9 @@ InstValueNumberer::addBranchConditions(D if (!parent) return; // first node, no predecessors // check for a dominating edge - CFGNode *block = domNode->getNode(); - CFGNode *idom = parent->getNode(); - CFGEdge *domEdge = 0; + Node *block = domNode->getNode(); + Node *idom = parent->getNode(); + Edge *domEdge = 0; if (idom->hasOnlyOneSuccEdge()) return; // no conditional branch there, no info to obtain @@ -1384,12 +1404,12 @@ InstValueNumberer::addBranchConditions(D } else { // idom must be a predecessor, // and every other predecessor must be dominated by this block - const CFGEdgeDeque &inedges = block->getInEdges(); - typedef CFGEdgeDeque::const_iterator EdgeIter; + const Edges &inedges = block->getInEdges(); + typedef Edges::const_iterator EdgeIter; EdgeIter eLast = inedges.end(); for (EdgeIter eIter = inedges.begin(); eIter != eLast; eIter++) { - CFGEdge *inEdge = *eIter; - CFGNode *predBlock = inEdge->getSourceNode(); + Edge *inEdge = *eIter; + Node *predBlock = inEdge->getSourceNode(); if (predBlock == idom) { if (domEdge) return; // can't deal with more than one dominating edge @@ -1407,22 +1427,22 @@ InstValueNumberer::addBranchConditions(D } if (!domEdge) return; // only take easy info for now. - CFGEdge::Kind kind = domEdge->getEdgeType(); + Edge::Kind kind = domEdge->getKind(); - CFGNode *predBlock = idom; + Node *predBlock = idom; bool taken = false; switch(kind) { - case CFGEdge::True: + case Edge::Kind_True: taken = true; - case CFGEdge::False: + case Edge::Kind_False: { - Inst* branchi1 = predBlock->getLastInst(); + Inst* branchi1 = (Inst*)predBlock->getLastInst(); assert(branchi1 != NULL); BranchInst* branchi = branchi1->asBranchInst(); if (branchi) { if (branchi->getOpcode() == Op_PredBranch) { addInfoFromPredBranch(block, branchi, taken); - } else { + } else if (branchi->getOpcode() != Op_Switch || !taken) { addInfoFromBranch(block, branchi, taken); } } else { @@ -1430,20 +1450,18 @@ InstValueNumberer::addBranchConditions(D } } break; - case CFGEdge::Exception: + case Edge::Kind_Dispatch: taken = true; - case CFGEdge::Unconditional: + case Edge::Kind_Unconditional: // remember the predecessor has multiple out edges, so ut must // be non-exception case of a PEI { - Inst* lasti = predBlock->getLastInst(); + Inst* lasti = (Inst*)predBlock->getLastInst(); assert(lasti != NULL); addInfoFromPEI(lasti, taken); } break; - case CFGEdge::Catch: - case CFGEdge::Switch: - case CFGEdge::Unknown: + case Edge::Kind_Catch: break; default: break; } @@ -1485,11 +1503,12 @@ bool allowsAnyZeroElimination(Comparison case Type::IntPtr: case Type::UIntPtr: case Type::ManagedPtr: case Type::UnmanagedPtr: - case Type::SystemObject: case Type::SystemString: + case Type::SystemObject: case Type::SystemClass: case Type::SystemString: case Type::Array: case Type::Object: case Type::BoxedValue: case Type::MethodPtr: case Type::VTablePtr: case Type::CompressedSystemObject: + case Type::CompressedSystemClass: case Type::CompressedSystemString: case Type::CompressedArray: case Type::CompressedObject: canelim = (notEqual ? (cv.i == 0) : (cv.i != 0)); break; @@ -1577,10 +1596,11 @@ bool allowsAnyZeroElimination(Comparison case Type::IntPtr: case Type::UIntPtr: case Type::ManagedPtr: case Type::UnmanagedPtr: - case Type::SystemObject: case Type::SystemString: + case Type::SystemObject: case Type::SystemClass: case Type::SystemString: case Type::Array: case Type::Object: case Type::BoxedValue: case Type::MethodPtr: case Type::VTablePtr: case Type::CompressedSystemObject: + case Type::CompressedSystemClass: case Type::CompressedSystemString: case Type::CompressedArray: case Type::CompressedObject: canelim = positive ^ isTrueEdge; break; @@ -1760,7 +1780,7 @@ bool allowsCheckCastElimination(Comparis assert(tinst != NULL); *opnd = tinst->getSrc(0); *type = tinst->getTypeInfo(); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "CheckCast Elim: "; (*opnd)->print(Log::out()); Log::out() << ::std::endl; @@ -1823,12 +1843,12 @@ ComparisonModifier negateComparison(Comp return Cmp_EQ; } -void InstValueNumberer::addInfoFromBranch(CFGNode* targetNode, BranchInst *branchi, bool isTrueEdge) +void InstValueNumberer::addInfoFromBranch(Node* targetNode, BranchInst *branchi, bool isTrueEdge) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (!optimizerFlags.elim_checks) return; - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "addInfoFromBranch " << (isTrueEdge ? "taken " : "notTaken "); branchi->print(Log::out()); Log::out() << ::std::endl; @@ -1844,13 +1864,13 @@ void InstValueNumberer::addInfoFromBranc (numSrcs==2 ? branchi->getSrc(1) : 0)); } -void InstValueNumberer::addInfoFromPredBranch(CFGNode* targetNode, BranchInst *branchi, +void InstValueNumberer::addInfoFromPredBranch(Node* targetNode, BranchInst *branchi, bool isTrueEdge) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (!optimizerFlags.elim_checks) return; - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "addInfoFromPredBranch " << (isTrueEdge ? "taken " : "notTaken "); branchi->print(Log::out()); Log::out() << ::std::endl; @@ -1862,7 +1882,7 @@ void InstValueNumberer::addInfoFromPredB return; } - pcmpi->getComparisonModifier(); + pcmpi->getComparisonModifier(); uint32 numSrcs = pcmpi->getNumSrcOperands(); addInfoFromBranchCompare(targetNode, pcmpi->getComparisonModifier(), @@ -1915,7 +1935,7 @@ void InstValueNumberer::recordHasTypeTau } } -void InstValueNumberer::addInfoFromBranchCompare(CFGNode* targetNode, +void InstValueNumberer::addInfoFromBranchCompare(Node* targetNode, ComparisonModifier mod, Type::Tag comparisonType, bool isTrueEdge, @@ -1940,7 +1960,7 @@ void InstValueNumberer::addInfoFromBranc switch (numSrcOperands) { case 1: { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding true comparison: "; switch (modhere) { case Cmp_Zero: Log::out() << "Cmp_Zero "; break; @@ -1964,7 +1984,7 @@ void InstValueNumberer::addInfoFromBranc setHashToInst(tauEdge, getKey(cmpOperation, src0->getId())); setHashToInst(tauEdge, getKey(predCmpOperation, src0->getId())); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding false comparison: "; switch (negModhere) { case Cmp_Zero: Log::out() << "Cmp_Zero "; break; @@ -1996,7 +2016,7 @@ void InstValueNumberer::addInfoFromBranc Opnd *negSrc0 = isTrueEdge ? src1 : src0; Opnd *negSrc1 = isTrueEdge ? src0 : src1; - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding true comparison: "; switch (modhere) { case Cmp_EQ: Log::out() << "Cmp_EQ "; break; @@ -2021,7 +2041,7 @@ void InstValueNumberer::addInfoFromBranc setHashToInst(tauEdge, getKey(predCmpOperation, posSrc0->getId(), posSrc1->getId())); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "adding false comparison: "; switch (negModhere) { case Cmp_EQ: Log::out() << "Cmp_EQ "; break; @@ -2060,7 +2080,7 @@ void InstValueNumberer::addInfoFromBranc if (allowsCheckZeroElimination(mod, comparisonType, src0, src1, isTrueEdge, &opnd)) { assert(opnd); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "can eliminate checkzero of "; opnd->print(Log::out()); Log::out() << ::std::endl; @@ -2079,7 +2099,7 @@ void InstValueNumberer::addInfoFromBranc repeat_it = false; assert(opnd); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "can eliminate checknull of "; opnd->print(Log::out()); Log::out() << ::std::endl; @@ -2107,7 +2127,7 @@ void InstValueNumberer::addInfoFromBranc &opnd, &opnd2)) { assert(opnd); assert(opnd2); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "can eliminate checkbounds of "; opnd->print(Log::out()); Log::out() << ", "; @@ -2127,7 +2147,7 @@ void InstValueNumberer::addInfoFromBranc repeat_it = false; assert(opnd); assert(type); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "can eliminate checkcast of "; opnd->print(Log::out()); Log::out() << ", "; @@ -2138,7 +2158,7 @@ void InstValueNumberer::addInfoFromBranc opnd2 = irManager.getOpndManager().createSsaTmpOpnd(type); Inst* scast = irManager.getInstFactory().makeTauStaticCast(opnd2, opnd, tauEdge->getDst(), type); - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting staticCast inst "; scast->print(Log::out()); Log::out() << " after tauEdge "; @@ -2168,7 +2188,7 @@ void InstValueNumberer::addInfoFromBranc repeat_it = false; assert(opnd); assert(opnd2); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "can eliminate checkelemtype of "; opnd->print(Log::out()); Log::out() << ", "; @@ -2294,10 +2314,10 @@ void InstValueNumberer::addInfoFromPEI(I class ValueNumberingWalker { IRManager &irManager; - FlowGraph &fg; + ControlFlowGraph &fg; InstValueNumberer ivn; DominatorNode *domNode; - CFGNode *block; + Node *block; int depth; bool isScoped; bool useBranches; @@ -2313,17 +2333,17 @@ public: block = domNode->getNode(); if (dispatchDepth <= 0) { if (skipDispatches && block->isDispatchNode()) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Skipping dispatch node "; - block->print(Log::out()); + FlowGraph::print(Log::out(), block); Log::out() << " and dominated nodes"; Log::out() << ::std::endl; } dispatchDepth = 1; } else { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Begin hashvaluenumbering of block"; - block->print(Log::out()); + FlowGraph::print(Log::out(), block); Log::out() << ::std::endl; } if (useBranches) @@ -2332,7 +2352,7 @@ public: } }; void applyToInst(Inst *inst) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN examining instruction "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -2349,7 +2369,7 @@ public: if (ssaOpnd) { Opnd *mapped = opndMap->lookup(ssaOpnd); if (mapped) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN remapped opnd " << (int) i << " of inst " << (int) inst->getId() << " from "; @@ -2366,7 +2386,7 @@ public: if (dispatchDepth > 0) return; Opcode instOpcode = inst->getOpcode(); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN point 1" << ::std::endl; } if (!isScoped) { @@ -2377,12 +2397,12 @@ public: return; } else { } - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN point 2" << ::std::endl; } Inst* optimizedInst = ivn.optimizeInst(inst); Opcode optimizedOpcode = optimizedInst->getOpcode(); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN point 3, optimizedInst = "; if (optimizedInst) { optimizedInst->print(Log::out()); @@ -2394,7 +2414,7 @@ public: if (optimizedInst != inst) { // CSE was found! numInstOptimized++; - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "VN optimized instruction "; inst->print(Log::out()); Log::out() << " to "; @@ -2410,9 +2430,9 @@ public: BranchInst *branchi = inst->asBranchInst(); if (branchi) { if (optimizedOpcode == Op_TauUnsafe) { - fg.foldBranch(block, branchi, false); // not taken + FlowGraph::foldBranch(fg, block, branchi, false); // not taken } else { - fg.foldBranch(block, branchi, true); // taken + FlowGraph::foldBranch(fg, block, branchi, true); // taken } return; } @@ -2439,7 +2459,7 @@ public: copy = irManager.getInstFactory().makeCopy(dstOpnd,srcOpnd); } - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Inserting copy inst "; copy->print(Log::out()); Log::out() << " before inst "; @@ -2460,14 +2480,14 @@ public: // they have corresponding exceptions edges in the control flow // graph. You must remove exception edges when you remove // a potentially exception throwing check instruction. - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Removing redundant check inst "; inst->print(Log::out()); Log::out() << ::std::endl; } - fg.eliminateCheck(block,inst,false); + FlowGraph::eliminateCheck(fg, block,inst,false); } else { - if(Log::cat_opt_vn()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Removing redundant inst "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -2478,7 +2498,7 @@ public: }; void finishNode(DominatorNode *domNode) { if (dispatchDepth > 0) return; - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Done hashvaluenumbering of block"; domNode->print(Log::out()); Log::out() << ::std::endl; @@ -2488,7 +2508,7 @@ public: if ((isScoped && (dispatchDepth == 0)) || (depth == 0)) { ivn.enterScope(); if (opndMap) opndMap->enter_scope(); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Entering scope" << depth << ::std::endl; } } @@ -2501,7 +2521,7 @@ public: } depth -= 1; if ((isScoped && (dispatchDepth == 0)) || (depth == 0)) { - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Exiting scope" << depth << ::std::endl; } ivn.exitScope(); @@ -2510,7 +2530,7 @@ public: if (dispatchDepth == 1) dispatchDepth = 0; }; ValueNumberingWalker(MemoryManager &mm0, IRManager &irm, - FlowGraph &fg0, + ControlFlowGraph &fg0, DominatorTree &domtree, MemoryOpt *mopt, bool isScoped0, @@ -2518,7 +2538,7 @@ public: bool skipDispatches0, bool cacheOpnds0) : irManager(irm), fg(fg0), - ivn(mm0, irm, domtree, mopt, irManager.getCompilationContext()->getOptimizerFlags()->cse_final && isScoped0, + ivn(mm0, irm, domtree, mopt, irManager.getOptimizerFlags().cse_final && isScoped0, fg0, isScoped0), domNode(0), depth(0), isScoped(isScoped0), useBranches(useBranches0), @@ -2527,7 +2547,7 @@ public: opndMap(0), numInstOptimized(0) { if (cacheOpnds) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); opndMap = new (mm0) SparseScopedMap<Opnd *, Opnd *>(fg.getNodes().size() * (optimizerFlags. @@ -2543,10 +2563,10 @@ HashValueNumberer::doGlobalValueNumberin MemoryManager localMM(sizeof(InstValueNumberer)+10000, "HashValueNumberer::doGlobalValueNumbering"); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting unscoped value numbering pass" << ::std::endl; } - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); ValueNumberingWalker walker(localMM, irManager, fg, dominators, mopt, false, false, // un-scoped, no branches !optimizerFlags.gvn_exceptions, @@ -2578,7 +2598,7 @@ HashValueNumberer::doGlobalValueNumberin NodeWalk<ValueNumberingNodeWalker>(fg, nodeWalker); } - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Finished unscoped value numbering pass" << ::std::endl; } } @@ -2589,11 +2609,11 @@ HashValueNumberer::doValueNumbering(Memo MemoryManager localMM(sizeof(InstValueNumberer)+10000, "HashValueNumberer::doValueNumbering"); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting scoped value numbering pass" << ::std::endl; } - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); ValueNumberingWalker walker(localMM, irManager, fg, dominators, mopt, true, true, // scoped, use branches !optimizerFlags.hvn_exceptions, @@ -2609,7 +2629,7 @@ HashValueNumberer::doValueNumbering(Memo DomTreeWalk<true, ValueNumberingDomWalker>(dominators, domWalker, localMM); - if (Log::cat_opt_vn()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Finished scoped value numbering pass" << ::std::endl; } } diff --git vm/jitrino/src/optimizer/hashvaluenumberer.h vm/jitrino/src/optimizer/hashvaluenumberer.h index c1953d4..f16da4e 100644 --- vm/jitrino/src/optimizer/hashvaluenumberer.h +++ vm/jitrino/src/optimizer/hashvaluenumberer.h @@ -24,7 +24,6 @@ #ifndef _HASHVALUENUMBER_H_ #define _HASHVALUENUMBER_H_ #include "irmanager.h" -#include "optpass.h" namespace Jitrino { @@ -34,7 +33,6 @@ class DominatorTree; class MemoryOpt; class FlowGraph; -DEFINE_OPTPASS(HashValueNumberingPass) class HashValueNumberer { public: @@ -51,7 +49,7 @@ public: private: IRManager& irManager; DominatorTree& dominators; - FlowGraph& fg; + ControlFlowGraph& fg; bool useBranches; // do we try to take account of in-edge conditions in a block? }; diff --git vm/jitrino/src/optimizer/inliner.cpp vm/jitrino/src/optimizer/inliner.cpp index a263f29..7364e03 100644 --- vm/jitrino/src/optimizer/inliner.cpp +++ vm/jitrino/src/optimizer/inliner.cpp @@ -21,7 +21,6 @@ */ #include "Log.h" -#include "PropertyTable.h" #include "methodtable.h" #include "inliner.h" #include "irmanager.h" @@ -29,24 +28,27 @@ #include "FlowGraph.h" #include "Inst.h" #include "Dominator.h" #include "Loop.h" -#include "Profiler.h" #include "simplifier.h" #include "JavaByteCodeParser.h" -#include "PropertyTable.h" +#include "EdgeProfiler.h" +#include "StaticProfiler.h" +#include "optimizer.h" namespace Jitrino { -#define MAX_INLINE_GROWTH_FACTOR_PROF 500 -#define MIN_INLINE_STOP_PROF 100 -#define MIN_BENEFIT_THRESHOLD_PROF 100 -#define INLINE_LARGE_THRESHOLD_PROF 150 - #define MAX_INLINE_GROWTH_FACTOR 170 #define MIN_INLINE_STOP 50 #define MIN_BENEFIT_THRESHOLD 200 #define INLINE_LARGE_THRESHOLD 70 +#define MAX_INLINE_GROWTH_FACTOR_PROF 500 +#define MIN_INLINE_STOP_PROF 100 +// no negative profile benefit for nodes with freq >= 1/10 of entry freq +#define MIN_BENEFIT_THRESHOLD_PROF (MIN_BENEFIT_THRESHOLD / 10) +#define INLINE_LARGE_THRESHOLD_PROF 150 + + #define CALL_COST 1 #define INLINE_SMALL_THRESHOLD 12 @@ -62,64 +64,75 @@ #define INLINE_EXACT_ARG_BONUS 0 #define INLINE_EXACT_ALL_BONUS 0 #define INLINE_SKIP_EXCEPTION_PATH true -Inliner::Inliner(MemoryManager& mm, IRManager& irm, bool doProfileOnly) - : _mm(mm), _toplevelIRM(irm), + +DEFINE_SESSION_ACTION(InlinePass, inline, "Method Inlining"); + +Inliner::Inliner(SessionAction* argSource, MemoryManager& mm, IRManager& irm, bool doProfileOnly) + : _tmpMM(mm), _toplevelIRM(irm), _typeManager(irm.getTypeManager()), _instFactory(irm.getInstFactory()), _opndManager(irm.getOpndManager()), _hasProfileInfo(irm.getFlowGraph().hasEdgeProfile()), - _useInliningTranslatorCall(!irm.getFlowGraph().hasEdgeProfile()), _inlineCandidates(mm), _initByteSize(irm.getMethodDesc().getByteCodeSize()), - _currentByteSize(irm.getMethodDesc().getByteCodeSize()), - - _inlineTree(new (mm) InlineNode(irm, 0, 0)) { - JitrinoParameterTable& propertyTable = irm.getParameterTable(); + _inlineTree(new (mm) InlineNode(irm, 0, 0)), + translatorAction(NULL) +{ + if (irm.getCompilationInterface().isBCMapInfoRequired()) { + isBCmapRequired = true; + MethodDesc* meth = irm.getCompilationInterface().getMethodToCompile(); + bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, meth); + } else { + isBCmapRequired = false; + bc2HIRMapHandler = NULL; + } + + const char* translatorName = argSource->getStringArg("translatorActionName", "translator"); + translatorAction = (TranslatorAction*)PMF::getAction(argSource->getPipeline(), translatorName); + assert(translatorAction); + _doProfileOnlyInlining = doProfileOnly; _useInliningTranslator = !doProfileOnly; - _maxInlineGrowthFactor = ((double) propertyTable.lookupInt("opt::inline::growth_factor", doProfileOnly ? MAX_INLINE_GROWTH_FACTOR_PROF : MAX_INLINE_GROWTH_FACTOR)) / 100; - _minInlineStop = propertyTable.lookupUint("opt::inline::min_stop", doProfileOnly ? MIN_INLINE_STOP_PROF : MIN_INLINE_STOP); - _minBenefitThreshold = propertyTable.lookupInt("opt::inline::min_benefit_threshold", - doProfileOnly ? MIN_BENEFIT_THRESHOLD_PROF : MIN_BENEFIT_THRESHOLD); + _maxInlineGrowthFactor = ((double)argSource->getIntArg("growth_factor", doProfileOnly ? MAX_INLINE_GROWTH_FACTOR_PROF : MAX_INLINE_GROWTH_FACTOR)) / 100; + _minInlineStop = argSource->getIntArg("min_stop", doProfileOnly ? MIN_INLINE_STOP_PROF : MIN_INLINE_STOP); + _minBenefitThreshold = argSource->getIntArg("min_benefit_threshold", doProfileOnly ? MIN_BENEFIT_THRESHOLD_PROF : MIN_BENEFIT_THRESHOLD); - _inlineSmallMaxByteSize = propertyTable.lookupUint("opt::inline::small_method_max_size", INLINE_SMALL_THRESHOLD); - _inlineSmallBonus = propertyTable.lookupInt("opt::inline::small_method_bonus", INLINE_SMALL_BONUS); + _inlineSmallMaxByteSize = argSource->getIntArg("inline_small_method_max_size", INLINE_SMALL_THRESHOLD); + _inlineSmallBonus = argSource->getIntArg("inline_small_method_bonus", INLINE_SMALL_BONUS); - _inlineMediumMaxByteSize = propertyTable.lookupUint("opt::inline::medium_method_max_size", INLINE_MEDIUM_THRESHOLD); - _inlineMediumBonus = propertyTable.lookupInt("opt::inline::medium_method_bonus", INLINE_MEDIUM_BONUS); + _inlineMediumMaxByteSize = argSource->getIntArg("medium_method_max_size", INLINE_MEDIUM_THRESHOLD); + _inlineMediumBonus = argSource->getIntArg("medium_method_bonus", INLINE_MEDIUM_BONUS); - _inlineLargeMinByteSize = propertyTable.lookupUint("opt::inline::large_method_min_size", doProfileOnly ? INLINE_LARGE_THRESHOLD_PROF : INLINE_LARGE_THRESHOLD); - _inlineLargePenalty = propertyTable.lookupInt("opt::inline::large_method_penalty", INLINE_LARGE_PENALTY); - - _inlineLoopBonus = propertyTable.lookupInt("opt::inline::loop_bonus", INLINE_LOOP_BONUS); - _inlineLeafBonus = propertyTable.lookupInt("opt::inline::leaf_bonus", INLINE_LEAF_BONUS); - _inlineSynchBonus = propertyTable.lookupInt("opt::inline::synch_bonus", INLINE_SYNCH_BONUS); - _inlineRecursionPenalty = propertyTable.lookupInt("opt::inline::recursion_penalty", INLINE_RECURSION_PENALTY); - _inlineExactArgBonus = propertyTable.lookupInt("opt::inline::exact_single_parameter_bonus", INLINE_EXACT_ARG_BONUS); - _inlineExactAllBonus = propertyTable.lookupInt("opt::inline::exact_all_parameter_bonus", INLINE_EXACT_ALL_BONUS); - - _inlineSkipExceptionPath = propertyTable.lookupBool("opt::inline::skip_exception_path", INLINE_SKIP_EXCEPTION_PATH); - const char* skipMethods = propertyTable.lookup("opt::inline::skip_methods"); + _inlineLargeMinByteSize = argSource->getIntArg("large_method_min_size", doProfileOnly ? INLINE_LARGE_THRESHOLD_PROF : INLINE_LARGE_THRESHOLD); + _inlineLargePenalty = argSource->getIntArg("large_method_penalty", INLINE_LARGE_PENALTY); + + _inlineLoopBonus = argSource->getIntArg("loop_bonus", INLINE_LOOP_BONUS); + _inlineLeafBonus = argSource->getIntArg("leaf_bonus", INLINE_LEAF_BONUS); + _inlineSynchBonus = argSource->getIntArg("synch_bonus", INLINE_SYNCH_BONUS); + _inlineRecursionPenalty = argSource->getIntArg("recursion_penalty", INLINE_RECURSION_PENALTY); + _inlineExactArgBonus = argSource->getIntArg("exact_single_parameter_bonus", INLINE_EXACT_ARG_BONUS); + _inlineExactAllBonus = argSource->getIntArg("exact_all_parameter_bonus", INLINE_EXACT_ALL_BONUS); + + _inlineSkipExceptionPath = argSource->getBoolArg("skip_exception_path", INLINE_SKIP_EXCEPTION_PATH); + const char* skipMethods = argSource->getStringArg("skip_methods", NULL); if(skipMethods == NULL) { _inlineSkipMethodTable = NULL; } else { - ::std::string skipMethodsStr = skipMethods; - _inlineSkipMethodTable = new (_mm) Method_Table(skipMethodsStr.c_str(), "SKIP_METHODS", true); + std::string skipMethodsStr = skipMethods; + _inlineSkipMethodTable = new (_tmpMM) Method_Table(skipMethodsStr.c_str(), "SKIP_METHODS", true); } - _usesOptimisticBalancedSync = (propertyTable.lookupBool("opt::sync::optimistic", false) - ? propertyTable.lookupBool("opt::sync::optcatch", true) - : false); + _usesOptimisticBalancedSync = argSource->getBoolArg("sync_optimistic", false) ? argSource->getBoolArg("sync_optcatch", true) : false; } int32 -Inliner::computeInlineBenefit(CFGNode* node, MethodDesc& methodDesc, InlineNode* parentInlineNode, uint32 loopDepth) +Inliner::computeInlineBenefit(Node* node, MethodDesc& methodDesc, InlineNode* parentInlineNode, uint32 loopDepth) { int32 benefit = 0; - if (Log::cat_opt_inline()->isDebugEnabled()) { - Log::cat_opt_inline()->debug << "Computing Inline benefit for " + if (Log::isEnabled()) { + Log::out() << "Computing Inline benefit for " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl; } @@ -127,28 +140,28 @@ Inliner::computeInlineBenefit(CFGNode* n // Size impact // uint32 size = methodDesc.getByteCodeSize(); - Log::cat_opt_inline()->debug << " size is " << (int) size << ::std::endl; + Log::out() << " size is " << (int) size << ::std::endl; if(size < _inlineSmallMaxByteSize) { // Large bonus for smallest methods benefit += _inlineSmallBonus; - Log::cat_opt_inline()->debug << " isSmall, benefit now = " << benefit << ::std::endl; + Log::out() << " isSmall, benefit now = " << benefit << ::std::endl; } else if(size < _inlineMediumMaxByteSize) { // Small bonus for somewhat small methods benefit += _inlineMediumBonus; - Log::cat_opt_inline()->debug << " isMedium, benefit now = " << benefit << ::std::endl; + Log::out() << " isMedium, benefit now = " << benefit << ::std::endl; } else if(size > _inlineLargeMinByteSize) { // Penalty for large methods benefit -= _inlineLargePenalty * (loopDepth+1); - Log::cat_opt_inline()->debug << " isLarge, benefit now = " << benefit << ::std::endl; + Log::out() << " isLarge, benefit now = " << benefit << ::std::endl; } benefit -= size; - Log::cat_opt_inline()->debug << " Subtracting size, benefit now = " << benefit << ::std::endl; + Log::out() << " Subtracting size, benefit now = " << benefit << ::std::endl; // // Loop depth impact - add bonus for deep call sites // benefit += _inlineLoopBonus*loopDepth; - Log::cat_opt_inline()->debug << " Loop Depth is " << (int) loopDepth + Log::out() << " Loop Depth is " << (int) loopDepth << ", benefit now = " << benefit << ::std::endl; // @@ -156,7 +169,7 @@ Inliner::computeInlineBenefit(CFGNode* n // if(methodDesc.isSynchronized()){ benefit += _inlineSynchBonus; - Log::cat_opt_inline()->debug << " Method is synchronized, benefit now = " << benefit << ::std::endl; + Log::out() << " Method is synchronized, benefit now = " << benefit << ::std::endl; } // // Recursion penalty - discourage recursive inlining @@ -164,7 +177,7 @@ Inliner::computeInlineBenefit(CFGNode* n for(; parentInlineNode != NULL; parentInlineNode = parentInlineNode->getParent()) { if(&methodDesc == &(parentInlineNode->getIRManager().getMethodDesc())) { benefit -= _inlineRecursionPenalty; - Log::cat_opt_inline()->debug << " Subtracted one recursion level, benefit now = " << benefit << ::std::endl; + Log::out() << " Subtracted one recursion level, benefit now = " << benefit << ::std::endl; } } @@ -173,13 +186,13 @@ Inliner::computeInlineBenefit(CFGNode* n // if(isLeafMethod(methodDesc)) { benefit += _inlineLeafBonus; - Log::cat_opt_inline()->debug << " Added leaf bonus, benefit now = " << benefit << ::std::endl; + Log::out() << " Added leaf bonus, benefit now = " << benefit << ::std::endl; } // // Exact argument bonus - may introduce specialization opportunities // - Inst* last = node->getLastInst(); + Inst* last = (Inst*)node->getLastInst(); if(last->getOpcode() == Op_DirectCall) { MethodCallInst* call = last->asMethodCallInst(); assert(call != NULL); @@ -193,21 +206,21 @@ Inliner::computeInlineBenefit(CFGNode* n assert(arg->getType()->tag != Type::Tau); if(arg->getInst()->isConst()) { benefit += _inlineExactArgBonus; - Log::cat_opt_inline()->debug << " Src " << (int) i + Log::out() << " Src " << (int) i << " is const, benefit now = " << benefit << ::std::endl; } else if(arg->getType()->isObject() && Simplifier::isExactType(arg)) { benefit += _inlineExactArgBonus; - Log::cat_opt_inline()->debug << " Src " << (int) i + Log::out() << " Src " << (int) i << " is exacttype, benefit now = " << benefit << ::std::endl; } else { exact = false; - Log::cat_opt_inline()->debug << " Src " << (int) i + Log::out() << " Src " << (int) i << " is inexact, benefit now = " << benefit << ::std::endl; } } if(call->getNumSrcOperands() > 2 && exact) { benefit += _inlineExactAllBonus; - Log::cat_opt_inline()->debug << " Added allexact bonus, benefit now = " << benefit << ::std::endl; + Log::out() << " Added allexact bonus, benefit now = " << benefit << ::std::endl; } } @@ -216,8 +229,8 @@ Inliner::computeInlineBenefit(CFGNode* n // if(_doProfileOnlyInlining && _toplevelIRM.getFlowGraph().hasEdgeProfile()) { double heatThreshold = _toplevelIRM.getHeatThreshold(); - double nodeCount = node->getFreq(); - double scale = nodeCount / heatThreshold; + double nodeCount = node->getExecCount(); + double scale = nodeCount / heatThreshold; if(scale > 100) scale = 100; // Remove any loop bonus as this is already accounted for in block count @@ -225,7 +238,7 @@ Inliner::computeInlineBenefit(CFGNode* n // Scale by call site 'hotness'. benefit = (uint32) ((double) benefit * scale); - Log::cat_opt_inline()->debug << " HeatThreshold=" << heatThreshold + Log::out() << " HeatThreshold=" << heatThreshold << ", nodeCount=" << nodeCount << ", scale=" << scale << "; benefit now = " << benefit @@ -417,7 +430,6 @@ Inliner::reset() { _hasProfileInfo = true; // _irm.getFlowGraph().hasEdgeProfile(); _inlineCandidates.clear(); - _useInliningTranslatorCall = false; } bool @@ -427,7 +439,7 @@ Inliner::canInlineFrom(MethodDesc& metho // Test if calls in this method should be inlined // bool doInline = !methodDesc.isClassInitializer() && !methodDesc.getParentType()->isLikelyExceptionType(); - Log::cat_opt_inline()->debug << "Can inline from " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << " == " << doInline << ::std::endl; + Log::out() << "Can inline from " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << " == " << doInline << ::std::endl; return doInline; } @@ -439,9 +451,9 @@ Inliner::canInlineInto(MethodDesc& metho // bool doSkip = (_inlineSkipMethodTable == NULL) ? false : _inlineSkipMethodTable->accept_this_method(methodDesc); if(doSkip) - Log::cat_opt_inline()->debug << "Skipping inlining of " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl; + Log::out() << "Skipping inlining of " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl; bool doInline = !doSkip && !methodDesc.isNative() && !methodDesc.isNoInlining() && !methodDesc.getParentType()->isLikelyExceptionType(); - Log::cat_opt_inline()->debug << "Can inline this " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << " == " << doInline << ::std::endl; + Log::out() << "Can inline this " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << " == " << doInline << ::std::endl; return doInline; } @@ -451,12 +463,9 @@ Inliner::connectRegion(InlineNode* inlin // This is the top level graph. return; - if(_useInliningTranslatorCall) - // Inlining translator connects the region during translation - return; - + IRManager &inlinedIRM = inlineNode->getIRManager(); - FlowGraph &inlinedFlowGraph = inlinedIRM.getFlowGraph(); + ControlFlowGraph &inlinedFlowGraph = inlinedIRM.getFlowGraph(); Inst *callInst = inlineNode->getCallInst(); MethodDesc &methodDesc = inlinedIRM.getMethodDesc(); @@ -476,11 +485,11 @@ Inliner::connectRegion(InlineNode* inlin &methodDesc, obj) : _instFactory.makeMethodMarker(MethodMarkerInst::Exit, &methodDesc); - CFGNode* entry = inlinedFlowGraph.getEntry(); - entry->prependAfterCriticalInst(entryMarker); - CFGNode* retNode = inlinedFlowGraph.getReturn(); + Node* entry = inlinedFlowGraph.getEntryNode(); + entry->prependInst(entryMarker); + Node* retNode = inlinedFlowGraph.getReturnNode(); if(retNode != NULL) - retNode->append(exitMarker); + retNode->appendInst(exitMarker); // Fuse callsite arguments with incoming parameters uint32 numArgs = callInst->getNumSrcOperands() - 2; // omit taus @@ -488,11 +497,19 @@ Inliner::connectRegion(InlineNode* inlin Opnd *tauTypesChecked = callInst->getSrc(1); assert(tauNullChecked->getType()->tag == Type::Tau); assert(tauTypesChecked->getType()->tag == Type::Tau); - Inst* first = entry->getFirstInst(); + + // Mark tauNullChecked def inst as nonremovable + // tauSafe can be here. this is not our case. + Inst* tauNullCheckInst = tauNullChecked->getInst(); + if(tauNullCheckInst->getOpcode() == Op_TauCheckNull) { + tauNullCheckInst->setDefArgModifier(NonNullThisArg); + } + + Inst* first = (Inst*)entry->getFirstInst(); Inst* inst; Opnd* thisPtr = 0; uint32 j; - for(j = 0, inst = first->next(); j < numArgs && inst != first;) { + for(j = 0, inst = first->getNextInst(); j < numArgs && inst != NULL;) { switch (inst->getOpcode()) { case Op_DefArg: { @@ -544,7 +561,7 @@ Inliner::connectRegion(InlineNode* inlin default: break; } - inst = inst->next(); + inst = inst->getNextInst(); } assert(j == numArgs); @@ -562,11 +579,11 @@ Inliner::connectRegion(InlineNode* inlin bool isSsa = inlinedIRM.getInSsa(); Opnd** phiArgs = isSsa ? new (_toplevelIRM.getMemoryManager()) Opnd*[retNode->getInDegree()] : NULL; uint32 phiCount = 0; - const CFGEdgeDeque& inEdges = retNode->getInEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& inEdges = retNode->getInEdges(); + Edges::const_iterator eiter; for(eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { - CFGNode* retSite = (*eiter)->getSourceNode(); - Inst* ret = retSite->getLastInst(); + Node* retSite = (*eiter)->getSourceNode(); + Inst* ret = (Inst*)retSite->getLastInst(); assert(ret->getOpcode() == Op_Return); if(retVar != NULL) { Opnd* tmp = ret->getSrc(0); @@ -574,24 +591,24 @@ Inliner::connectRegion(InlineNode* inlin if(isSsa) { SsaVarOpnd* ssaVar = _opndManager.createSsaVarOpnd(retVar); phiArgs[phiCount++] = ssaVar; - retSite->append(_instFactory.makeStVar(ssaVar, tmp)); + retSite->appendInst(_instFactory.makeStVar(ssaVar, tmp)); } else { - retSite->append(_instFactory.makeStVar(retVar, tmp)); + retSite->appendInst(_instFactory.makeStVar(retVar, tmp)); } } ret->unlink(); } if(retVar != NULL) { // Insert phi and ldVar after call site - CFGNode* joinNode = inlinedFlowGraph.splitReturnNode(); - joinNode->setFreq(retNode->getFreq()); - ((CFGEdge*) joinNode->findTarget(retNode))->setEdgeProb(1.0); + Node* joinNode = inlinedFlowGraph.splitReturnNode(_instFactory.makeLabel()); + joinNode->setExecCount(retNode->getExecCount()); + joinNode->findTargetEdge(retNode)->setEdgeProb(1.0); if(isSsa) { SsaVarOpnd* ssaVar = _opndManager.createSsaVarOpnd(retVar); - joinNode->append(_instFactory.makePhi(ssaVar, phiCount, phiArgs)); - joinNode->append(_instFactory.makeLdVar(dst, ssaVar)); + joinNode->appendInst(_instFactory.makePhi(ssaVar, phiCount, phiArgs)); + joinNode->appendInst(_instFactory.makeLdVar(dst, ssaVar)); } else { - joinNode->append(_instFactory.makeLdVar(dst, retVar)); + joinNode->appendInst(_instFactory.makeLdVar(dst, retVar)); } // Set return operand. @@ -603,28 +620,26 @@ Inliner::connectRegion(InlineNode* inlin // // Insert explicit catch_all/monitor_exit/rethrow at exception exits for a synchronized inlined region // - if(methodDesc.isSynchronized() && inlinedIRM.getFlowGraph().getUnwind()) { + if(methodDesc.isSynchronized() && inlinedIRM.getFlowGraph().getUnwindNode()) { // Add monitor exit to unwind. - CFGNode* unwind = inlinedFlowGraph.getUnwind(); - const CFGEdgeDeque& unwindEdges = unwind->getInEdges(); - + Node* unwind = inlinedFlowGraph.getUnwindNode(); // Test if an exception exit exists - if(!unwindEdges.empty()) { - CFGNode* dispatch = inlinedFlowGraph.createDispatchNode(); + if(unwind->getInDegree() > 0) { + Node* dispatch = inlinedFlowGraph.createDispatchNode(_instFactory.makeLabel()); // Insert catch all Opnd* ex = _opndManager.createSsaTmpOpnd(_typeManager.getSystemObjectType()); - CFGNode* handler = inlinedFlowGraph.createCatchNode(0, ex->getType()); - handler->append(_instFactory.makeCatch(ex)); + Node* handler = inlinedFlowGraph.createBlockNode(inlinedIRM.getInstFactory().makeCatchLabel(0, ex->getType())); + handler->appendInst(_instFactory.makeCatch(ex)); if(methodDesc.isStatic()) { // Release class monitor - handler->append(_instFactory.makeTypeMonitorExit(methodDesc.getParentType())); + handler->appendInst(_instFactory.makeTypeMonitorExit(methodDesc.getParentType())); } else { // Release object monitor assert(callInst->getNumSrcOperands() > 2); Opnd* obj = callInst->getSrc(2); // object is arg 2; - TranslatorFlags& translatorFlags = *inlinedIRM.getCompilationContext()->getTranslatorFlags(); - if (!translatorFlags.ignoreSync && !translatorFlags.syncAsEnterFence) { + const TranslatorFlags& traFlags = translatorAction->getFlags(); + if (!traFlags.ignoreSync && !traFlags.syncAsEnterFence) { if (_usesOptimisticBalancedSync) { // We may need to insert an optimistically balanced monitorexit. // Note that we shouldn't have an un-optimistic balanced monitorexit, @@ -632,30 +647,30 @@ Inliner::connectRegion(InlineNode* inlin // prevented balancing for a synchronized method, which would have // a missing monitorexit on the exception path. - CFGNode *aRetNode = retNode; + Node *aRetNode = retNode; bool done = false; int count = 0; // We should have an optbalmonexit on a return path while (!done && aRetNode != NULL && !aRetNode->getInEdges().empty()) { - const CFGEdgeDeque& retEdges = aRetNode->getInEdges(); + const Edges& retEdges = aRetNode->getInEdges(); if (!retEdges.empty()) { - CFGEdge *anEdgeToReturn = *retEdges.begin(); - CFGNode *aMonexitNode = anEdgeToReturn->getSourceNode(); - Inst *lastInst = aMonexitNode->getLastInst(); - Inst *firstInst = aMonexitNode->getFirstInst(); + Edge *anEdgeToReturn = *retEdges.begin(); + Node *aMonexitNode = anEdgeToReturn->getSourceNode(); + Inst *lastInst = (Inst*)aMonexitNode->getLastInst(); + Inst *firstInst = (Inst*)aMonexitNode->getFirstInst(); while (lastInst != firstInst) { if (lastInst->getOpcode() == Op_OptimisticBalancedMonitorExit) { Opnd *srcObj = lastInst->getSrc(0); Opnd *lockAddr = lastInst->getSrc(1); Opnd *enterDst = lastInst->getSrc(2); - handler->append(_instFactory.makeOptimisticBalancedMonitorExit(srcObj, + handler->appendInst(_instFactory.makeOptimisticBalancedMonitorExit(srcObj, lockAddr, enterDst)); done = true; break; } - lastInst = lastInst->prev(); + lastInst = lastInst->getPrevInst(); } if (!done) { // we may have empty nodes or something, so try a predecessor. @@ -673,24 +688,21 @@ Inliner::connectRegion(InlineNode* inlin assert(done); } else { Opnd* tauSafe = _opndManager.createSsaTmpOpnd(_typeManager.getTauType()); - handler->append(_instFactory.makeTauSafe(tauSafe)); // monenter success guarantees non-null - handler->append(_instFactory.makeTauMonitorExit(obj, tauSafe)); + handler->appendInst(_instFactory.makeTauSafe(tauSafe)); // monenter success guarantees non-null + handler->appendInst(_instFactory.makeTauMonitorExit(obj, tauSafe)); } } } // Insert rethrow - CFGNode* rethrow = inlinedFlowGraph.createBlockNode(); - rethrow->append(_instFactory.makeThrow(Throw_NoModifier, ex)); + Node* rethrow = inlinedFlowGraph.createBlockNode(_instFactory.makeLabel()); + rethrow->appendInst(_instFactory.makeThrow(Throw_NoModifier, ex)); // Redirect exception exits to monitor_exit - CFGEdgeDeque::const_iterator eiter; - for(eiter = unwindEdges.begin(); eiter != unwindEdges.end(); ) { - CFGEdge* edge = *eiter; - ++eiter; + while (!unwind->getInEdges().empty()) { + Edge* edge = unwind->getInEdges().front(); inlinedFlowGraph.replaceEdgeTarget(edge, dispatch); } - assert(unwindEdges.empty()); inlinedFlowGraph.addEdge(dispatch, handler); inlinedFlowGraph.addEdge(handler, rethrow); inlinedFlowGraph.addEdge(handler, unwind); @@ -703,24 +715,31 @@ Inliner::connectRegion(InlineNode* inlin // if ((methodDesc.isStatic() || methodDesc.isInstanceInitializer()) && methodDesc.getParentType()->needsInitialization()) { - // initialize type for static methods - Inst* initType = _instFactory.makeInitType(methodDesc.getParentType()); - entry->prepend(initType); - inlinedFlowGraph.splitNodeAtInstruction(initType); - inlinedFlowGraph.addEdge(entry, inlinedFlowGraph.getUnwind()); - } + // initialize type for static methods + Inst* initType = _instFactory.makeInitType(methodDesc.getParentType()); + entry->prependInst(initType); + inlinedFlowGraph.splitNodeAtInstruction(initType, true, false, _instFactory.makeLabel()); + Node* unwind = inlinedFlowGraph.getUnwindNode(); + if (unwind == NULL) { + unwind = inlinedFlowGraph.createDispatchNode(_instFactory.makeLabel()); + inlinedFlowGraph.setUnwindNode(unwind); + inlinedFlowGraph.addEdge(unwind, inlinedFlowGraph.getExitNode()); + } + inlinedFlowGraph.addEdge(entry, unwind); + } } void -Inliner::inlineAndProcessRegion(InlineNode* inlineNode, - DominatorTree* dtree, LoopTree* ltree) { +Inliner::inlineAndProcessRegion(InlineNode* inlineNode) { IRManager &inlinedIRM = inlineNode->getIRManager(); - FlowGraph &inlinedFlowGraph = inlinedIRM.getFlowGraph(); - CFGNode *callNode = inlineNode->getCallNode(); + DominatorTree* dtree = inlinedIRM.getDominatorTree(); + LoopTree* ltree = inlinedIRM.getLoopTree(); + ControlFlowGraph &inlinedFlowGraph = inlinedIRM.getFlowGraph(); + Node *callNode = inlineNode->getCallNode(); Inst *callInst = inlineNode->getCallInst(); MethodDesc &methodDesc = inlinedIRM.getMethodDesc(); - if (Log::cat_opt_inline()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "inlineAndProcessRegion " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl; @@ -741,7 +760,7 @@ Inliner::inlineAndProcessRegion(InlineNo // If top level flowgraph // if (inlineNode == _inlineTree.getRoot()) { - Log::cat_opt_inline()->debug << "inlineNode is root" << ::std::endl; + Log::out() << "inlineNode is root" << ::std::endl; return; } @@ -749,10 +768,10 @@ Inliner::inlineAndProcessRegion(InlineNo // Splice region into top level flowgraph at call site // assert(callInst->getOpcode() == Op_DirectCall); - Log::cat_opt_inline()->ir << "Inlining " << methodDesc.getParentType()->getName() + Log::out() << "Inlining " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl; - Log::cat_opt_inline()->ir + Log::out() << "callee = " << methodDesc.getParentType()->getName() << "." << methodDesc.getName() << ::std::endl << "caller = " << inlinedIRM.getParent()->getMethodDesc().getParentType()->getName() << "." @@ -763,22 +782,22 @@ Inliner::inlineAndProcessRegion(InlineNo // update inlining-related information in all 'call' instructions of the inlined method // - const CFGNodeDeque& nodes = inlinedFlowGraph.getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = inlinedFlowGraph.getNodes(); + Nodes::const_iterator niter; uint16 count = 0; assert(callInst->isMethodCall()); InlineInfo& call_ii = *callInst->asMethodCallInst()->getInlineInfoPtr(); - call_ii.printLevels(Log::cat_opt_inline()->ir); - Log::cat_opt_inline()->ir << ::std::endl; + call_ii.printLevels(Log::out()); + Log::out() << ::std::endl; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; - Inst* first = node->getFirstInst(); + Inst* first = (Inst*)node->getFirstInst(); Inst* i; - for(i=first->next(); i != first; i=i->next()) { + for(i=first->getNextInst(); i != NULL; i=i->getNextInst()) { InlineInfo *ii = i->getCallInstInlineInfoPtr(); // ii should be non-null for each call instruction if ( ii ) { @@ -786,12 +805,27 @@ Inliner::inlineAndProcessRegion(InlineNo // InlineInfo order is parent-first // (ii might be non-empty when translation-level inlining is on) // - ii->prependLevel(&methodDesc); + uint32 bcOff = ILLEGAL_VALUE; + + if (isBCmapRequired) { + uint64 callIinstID = (uint64) callInst->getId(); + uint64 iinstID = (uint64) i->getId(); + bcOff = (uint32)bc2HIRMapHandler->getVectorEntry(iinstID); + if (iinstID != callIinstID) { + uint32 inlinedBcOff = ILLEGAL_VALUE; + inlinedBcOff = (uint32)bc2HIRMapHandler->getVectorEntry(callIinstID); + bc2HIRMapHandler->setVectorEntry(iinstID, inlinedBcOff); + } + } + + ii->prependLevel(&methodDesc, bcOff); + // appropriate byte code offset instead of 0 should be propogated here + // to enable correct inline info ii->prependInlineChain(call_ii); // ii->inlineChain remains at the end - Log::cat_opt_inline()->ir << " call No." << count++ << " "; - ii->printLevels(Log::cat_opt_inline()->ir); + Log::out() << " call No." << count++ << " "; + ii->printLevels(Log::out()); } } } @@ -801,17 +835,32 @@ Inliner::inlineAndProcessRegion(InlineNo // IRManager* parent = inlinedIRM.getParent(); assert(parent); - parent->getFlowGraph().spliceFlowGraphInline(callNode, callInst, inlinedFlowGraph); + + Edge* edgeToInlined = callNode->getUnconditionalEdge(); + ControlFlowGraph& parentCFG = parent->getFlowGraph(); + parentCFG.spliceFlowGraphInline(edgeToInlined, inlinedFlowGraph); + parentCFG.removeEdge(callNode->getExceptionEdge()); + callInst->unlink(); + +} + + +void Inliner::runTranslatorSession(CompilationContext& inlineCC) { + TranslatorSession* traSession = (TranslatorSession*)translatorAction->createSession(inlineCC.getCompilationLevelMemoryManager()); + traSession->setCompilationContext(&inlineCC); + inlineCC.setCurrentSessionAction(traSession); + traSession->run(); + inlineCC.setCurrentSessionAction(NULL); } InlineNode* -Inliner::getNextRegionToInline() { +Inliner::getNextRegionToInline(CompilationContext& inlineCC) { // If in DPGO profiling mode, don't inline if profile information is not available. if(_doProfileOnlyInlining && !_toplevelIRM.getFlowGraph().hasEdgeProfile()) { return NULL; } - CFGNode* callNode = 0; + Node* callNode = 0; InlineNode* inlineParentNode = 0; MethodCallInst* call = 0; MethodDesc* methodDesc = 0; @@ -827,7 +876,7 @@ Inliner::getNextRegionToInline() { inlineParentNode = _inlineCandidates.top().inlineNode; _inlineCandidates.pop(); - call = callNode->getLastInst()->asMethodCallInst(); + call = ((Inst*)callNode->getLastInst())->asMethodCallInst(); assert(call != NULL); methodDesc = call->getMethodDesc(); @@ -841,8 +890,8 @@ Inliner::getNextRegionToInline() { || (methodByteSize < _inlineSmallMaxByteSize)) { found = true; } else { - Log::cat_opt_inline()->debug << "Skip inlining " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; - Log::cat_opt_inline()->debug << "methodByteSize=" + Log::out() << "Skip inlining " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; + Log::out() << "methodByteSize=" << (int)methodByteSize << ", newByteSize = " << (int)newByteSize << ", factor=" << factor @@ -853,14 +902,14 @@ Inliner::getNextRegionToInline() { if(!found) { // No more candidates. Done with inlining. assert(_inlineCandidates.empty()); - Log::cat_opt_inline()->debug << "Done inlining " << ::std::endl; + Log::out() << "Done inlining " << ::std::endl; return NULL; } // // Set candidate as current inlined region // - Log::cat_opt_inline()->info2 << "Opt: Inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << + Log::out() << "Opt: Inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << methodDesc->getSignatureString() << ::std::endl; // Generate flowgraph for new region @@ -868,79 +917,24 @@ Inliner::getNextRegionToInline() { uint32 id = methodDesc->getUniqueId(); _instFactory.setMethodId(((uint64)id)<<32); - Opnd *returnOpnd = 0; - if (_useInliningTranslatorCall) { - if(call->getDst()->isNull()) - returnOpnd = _opndManager.getNullOpnd(); - else - returnOpnd = _opndManager.createSsaTmpOpnd(call->getDst()->getType()); - } - IRManager* inlinedIRM = new (_mm) IRManager(_toplevelIRM, *methodDesc, returnOpnd); - FlowGraph* inlinedFG = &inlinedIRM->getFlowGraph(); + + IRManager* inlinedIRM = new (_tmpMM) IRManager(_tmpMM, _toplevelIRM, *methodDesc, NULL); // Augment inline tree - InlineNode *inlineNode = new (_mm) InlineNode(*inlinedIRM, call, callNode); + InlineNode *inlineNode = new (_tmpMM) InlineNode(*inlinedIRM, call, callNode); inlineParentNode->addChild(inlineNode); - if(_useInliningTranslatorCall) { - // Use inlining translator. - - uint32 numArgs = call->getNumSrcOperands() - 2; // pass taus separately - MemoryManager localMemManager(numArgs*sizeof(Opnd*), "FlowGraph::inlineMethod.localMemManager"); -#ifndef NDEBUG - Opnd* tauNullChecked = call->getSrc(0); - assert(tauNullChecked->getType()->tag == Type::Tau); - Opnd* tauTypesChecked = call->getSrc(1); - assert(tauTypesChecked->getType()->tag == Type::Tau); -#endif - Opnd** argOpnds = new (localMemManager) Opnd*[numArgs]; - for(uint32 j = 0; j < numArgs; ++j) { - Opnd *arg = call->getSrc(j+2); // skip taus - assert(arg->getType()->tag != Type::Tau); - argOpnds[j] = arg; - } - - - TranslatorIntfc::translateByteCodesInline(*inlinedIRM, - numArgs, argOpnds, 0); - returnOpnd = inlinedIRM->getReturnOpnd(); - if(returnOpnd && !returnOpnd->isNull()) { - Inst *copyInst = _instFactory.makeCopy(call->getDst(), returnOpnd); - CFGNode *fgReturnNode = inlinedFG->getReturn(); - assert(fgReturnNode != NULL); - if (Log::cat_opt_inline()->isDebugEnabled()) { - Log::out() << "Adding copy instruction: "; - copyInst->print(Log::out()); - Log::out() << ::std::endl << " to block" << ::std::endl; - fgReturnNode->print(Log::out()); - Log::out() << ::std::endl; - } - fgReturnNode->append(copyInst); - inlinedIRM->setReturnOpnd(call->getDst()); - if (Log::cat_opt_inline()->isDebugEnabled()) { - Log::out() << "After block changed: " << ::std::endl; - fgReturnNode->print(Log::out()); - Log::out() << ::std::endl; - } - } - - if ((methodDesc->isStatic() || methodDesc->isInstanceInitializer()) && - methodDesc->getParentType()->needsInitialization()) { - // initialize type for static methods - Inst* initType = _instFactory.makeInitType(methodDesc->getParentType()); - inlinedFG->getEntry()->prepend(initType); - inlinedFG->splitNodeAtInstruction(initType); - inlinedFG->addEdge(inlinedFG->getEntry(), inlinedFG->getUnwind()); - } - } else { - // Call regular translator - this must be used to annotate profile information onto the - // inlined region - TranslatorIntfc::translateByteCodes(*inlinedIRM); + // Call a translator + if (isBCmapRequired) { + uint32 methodByteSize = methodDesc->getByteCodeSize(); + size_t incSize = methodByteSize * ESTIMATED_HIR_SIZE_PER_BYTECODE; + MethodDesc* parentMethod = _toplevelIRM.getCompilationInterface().getMethodToCompile(); + incVectorHandlerSize(bcOffset2HIRHandlerName, parentMethod, incSize); } - // Cleanup - inlinedFG->cleanupPhase(); + inlineCC.setHIRManager(inlinedIRM); + runTranslatorSession(inlineCC); // Save state. _currentByteSize = newByteSize; @@ -956,29 +950,29 @@ Inliner::processDominatorNode(InlineNode // // Process this node for inline candidates // - CFGNode* node = dnode->getNode(); + Node* node = dnode->getNode(); if(node->isBlockNode()) { // Search for call site - Inst* last = node->getLastInst(); + Inst* last =(Inst*)node->getLastInst(); if(last->getOpcode() == Op_DirectCall) { // Process call site MethodCallInst* call = last->asMethodCallInst(); assert(call != NULL); MethodDesc* methodDesc = call->getMethodDesc(); - Log::cat_opt_inline()->debug << "Considering inlining instruction I" + Log::out() << "Considering inlining instruction I" << (int)call->getId() << ::std::endl; if(canInlineInto(*methodDesc)) { uint32 size = methodDesc->getByteCodeSize(); int32 benefit = computeInlineBenefit(node, *methodDesc, inlineNode, ltree->getLoopDepth(node)); assert(size > 0); - Log::cat_opt_inline()->debug << "Inline benefit " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << " == " << (int) benefit << ::std::endl; + Log::out() << "Inline benefit " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << " == " << (int) benefit << ::std::endl; if(0 < size && benefit > _minBenefitThreshold) { // Inline candidate - Log::cat_opt_inline()->debug << "Add to queue" << ::std::endl; + Log::out() << "Add to queue" << ::std::endl; _inlineCandidates.push(CallSite(benefit, node, inlineNode)); } else { - Log::cat_opt_inline()->debug << "Will not inline" << ::std::endl; + Log::out() << "Will not inline" << ::std::endl; } } } @@ -1008,34 +1002,34 @@ Inliner::processRegion(InlineNode* inlin } void -Inliner::scaleBlockCounts(CFGNode* callSite, IRManager& inlinedIRM) { - Log::cat_opt_inline()->debug << "Scaling block counts for callsite in block " +Inliner::scaleBlockCounts(Node* callSite, IRManager& inlinedIRM) { + Log::out() << "Scaling block counts for callsite in block " << (int) callSite->getId() << ::std::endl; if(!_toplevelIRM.getFlowGraph().hasEdgeProfile()) { // No profile information to scale - Log::cat_opt_inline()->debug << "No profile information to scale!" << ::std::endl; + Log::out() << "No profile information to scale!" << ::std::endl; return; } // // Compute scale from call site count and inlined method count // - double callFreq = callSite->getFreq(); - FlowGraph &inlinedRegion = inlinedIRM.getFlowGraph(); - double methodFreq = inlinedRegion.getEntry()->getFreq(); + double callFreq = callSite->getExecCount(); + ControlFlowGraph &inlinedRegion = inlinedIRM.getFlowGraph(); + double methodFreq = inlinedRegion.getEntryNode()->getExecCount(); double scale = callFreq / ((methodFreq != 0.0) ? methodFreq : 1.0); - Log::cat_opt_inline()->debug << "callFreq=" << callFreq + Log::out() << "callFreq=" << callFreq << ", methodFreq=" << methodFreq << ", scale=" << scale << ::std::endl; // // Apply scale to each block in inlined region // - const CFGNodeDeque& nodes = inlinedRegion.getNodes(); - CFGNodeDeque::const_iterator i; + const Nodes& nodes = inlinedRegion.getNodes(); + Nodes::const_iterator i; for(i = nodes.begin(); i != nodes.end(); ++i) { - CFGNode* node = *i; - node->setFreq(node->getFreq()*scale); + Node* node = *i; + node->setExecCount(node->getExecCount()*scale); } } @@ -1045,19 +1039,13 @@ Inliner::getProfileMethodCount(Compilati // // Get the entry count for a given method // - if ( compileIntf.isDynamicProfiling() ) { + CompilationContext* cc = compileIntf.getCompilationContext(); + if ( cc->hasDynamicProfileToUse() ) { // Online - MemoryManager mm(1024, "Inliner::getProfileMethodCount.mm"); - EdgeProfile* profile = new (mm) EdgeProfile(mm, methodDesc); - - return profile->getEntryFreq(); + double res = cc->getProfilingInterface()->getProfileMethodCount(methodDesc); + return res; } else { - // Offline - EdgeProfile* profile = profileCtrl.readProfileFromFile(methodDesc); - if(profile == NULL) - return 0; - - return profile->getEntryFreq(); + return 0; } } @@ -1096,5 +1084,81 @@ #endif return (uint32) sum; } +static void runInlinerPipeline(CompilationContext& inlineCC, const char* pipeName) { + PMF::HPipeline p = inlineCC.getCurrentJITContext()->getPMF().getPipeline(pipeName); + assert(p!=NULL); + PMF::PipelineIterator pit(p); + while (pit.next()) { + SessionAction* sa = pit.getSessionAction(); + sa->setCompilationContext(&inlineCC); + inlineCC.setCurrentSessionAction(sa); + inlineCC.stageId++; + sa->run(); + inlineCC.setCurrentSessionAction(0); + assert(!inlineCC.isCompilationFailed() && !inlineCC.isCompilationFinished()); + } +} + +void InlinePass::_run(IRManager& irm) { + + computeDominatorsAndLoops(irm); + + + CompilationContext* cc = getCompilationContext(); + MemoryManager& mm = cc->getCompilationLevelMemoryManager() ; + CompilationInterface* ci = cc->getVMCompilationInterface(); + JITInstanceContext* jit = cc->getCurrentJITContext(); + + // Set up Inliner + bool connectEarly = getBoolArg("connect_early", true); + const char* pipeName = getStringArg("pipeline", "inliner_pipeline"); + + MemoryManager tmpMM(1024, "Inliner::tmp_mm"); + Inliner inliner(this, tmpMM, irm, irm.getFlowGraph().hasEdgeProfile()); + InlineNode* rootRegionNode = (InlineNode*) inliner.getInlineTree().getRoot(); + inliner.inlineAndProcessRegion(rootRegionNode); + + // Inline calls + do { + CompilationContext inlineCC(mm, ci, jit); + inlineCC.setPipeline(cc->getPipeline()); + InlineNode* regionNode = inliner.getNextRegionToInline(inlineCC); + if (regionNode == NULL) { + break; + } + assert(regionNode != rootRegionNode); + IRManager ®ionManager = regionNode->getIRManager(); + assert(inlineCC.getHIRManager() == ®ionManager); + + // Connect region arguments to top-level flowgraph + if(connectEarly) { + inliner.connectRegion(regionNode); + } + + // Optimize inlined region before splicing + inlineCC.stageId = cc->stageId; + runInlinerPipeline(inlineCC, pipeName); + cc->stageId = inlineCC.stageId; + + // Splice into flow graph and find next region. + if(!connectEarly) { + inliner.connectRegion(regionNode); + } + OptPass::computeDominatorsAndLoops(regionManager); + inliner.inlineAndProcessRegion(regionNode); + } while (true); + const OptimizerFlags& optimizerFlags = irm.getOptimizerFlags(); + // Print the results to logging / dot file + if(optimizerFlags.dumpdot) { + inliner.getInlineTree().printDotFile(irm.getMethodDesc(), "inlinetree"); + } + if(Log::isEnabled()) { + Log::out() << indent(irm) << "Opt: Inline Tree" << ::std::endl; + inliner.getInlineTree().printIndentedTree(Log::out(), " "); + } + Log::out() << "Inline Checksum == " << (int) inliner.getInlineTree().computeCheckSum() << ::std::endl; +} + + } //namespace Jitrino diff --git vm/jitrino/src/optimizer/inliner.h vm/jitrino/src/optimizer/inliner.h index 793e268..af8e89a 100644 --- vm/jitrino/src/optimizer/inliner.h +++ vm/jitrino/src/optimizer/inliner.h @@ -25,6 +25,7 @@ #define _INLINER_H_ #include "StlPriorityQueue.h" #include "Tree.h" +#include "irmanager.h" namespace Jitrino { @@ -33,7 +34,7 @@ class IRManager; class TypeManager; class InstFactory; class OpndManager; -class CFGNode; +class Node; class MethodInst; class Inst; class Opnd; @@ -43,24 +44,23 @@ class MethodDesc; class DominatorTree; class DominatorNode; class LoopTree; -class JitrinoParameterTable; class Method_Table; class InlineNode : public TreeNode { public: - InlineNode(IRManager& irm, Inst *callInst, CFGNode *callNode) : _irm(irm), _callInst(callInst), _callNode(callNode) {} + InlineNode(IRManager& irm, Inst *callInst, Node *callNode) : _irm(irm), _callInst(callInst), _callNode(callNode) {} InlineNode* getChild() {return (InlineNode*) child;} InlineNode* getSiblings() {return (InlineNode*) siblings;} InlineNode* getParent() {return (InlineNode*) parent;} IRManager& getIRManager() { return _irm; } Inst* getCallInst() { return _callInst; } - CFGNode* getCallNode() { return _callNode; } + Node* getCallNode() { return _callNode; } void print(::std::ostream& os); void printTag(::std::ostream& os); private: IRManager& _irm; Inst* _callInst; - CFGNode* _callNode; + Node* _callNode; }; class InlineTree : public Tree { @@ -78,20 +78,19 @@ private: class Inliner { public: - Inliner(MemoryManager& mm, IRManager& irm, - bool doProfileOnly=false); + Inliner(SessionAction* argSource, MemoryManager& mm, IRManager& irm, bool doProfileOnly=false); // Inline this method into the current CFG and process it for further // inline candidates. If the argument is the top level CFG, only processing // occurs. - void inlineAndProcessRegion(InlineNode* inlineNode, DominatorTree* dtree, LoopTree* ltree); + void inlineAndProcessRegion(InlineNode* inlineNode); // Connect input and return operands of the region to the top-level method. Do not yet splice. void connectRegion(InlineNode* inlineNode); // Build the flowgraph for the next inline candidate method. Note, this flowgraph // is not yet connected to the top level CFG. - InlineNode* getNextRegionToInline(); + InlineNode* getNextRegionToInline(CompilationContext& inlineCC); InlineTree& getInlineTree() { return _inlineTree; } @@ -102,10 +101,10 @@ public: private: class CallSite { public: - CallSite(int32 benefit, CFGNode* callNode, InlineNode* inlineNode) : benefit(benefit), callNode(callNode), inlineNode(inlineNode) {} + CallSite(int32 benefit, Node* callNode, InlineNode* inlineNode) : benefit(benefit), callNode(callNode), inlineNode(inlineNode) {} int32 benefit; - CFGNode* callNode; + Node* callNode; InlineNode* inlineNode; }; @@ -114,10 +113,12 @@ private: bool operator()(const CallSite& site1, const CallSite& site2) { return site1.benefit < site2.benefit; } }; - void scaleBlockCounts(CFGNode* callSite, IRManager& inlinedIRM); + void scaleBlockCounts(Node* callSite, IRManager& inlinedIRM); void processRegion(InlineNode *inlineNode, DominatorTree* dtree, LoopTree* ltree); void processDominatorNode(InlineNode *inlineNode, DominatorNode* dtree, LoopTree* ltree); + void runTranslatorSession(CompilationContext& inlineCC); + // True if this method should be processed for further inlining. I.e., // can we inline the calls in this method? bool canInlineFrom(MethodDesc& methodDesc); @@ -127,17 +128,16 @@ private: bool isLeafMethod(MethodDesc& methodDesc); - int32 computeInlineBenefit(CFGNode* node, MethodDesc& methodDesc, InlineNode* parentInlineNode, uint32 loopDepth); + int32 computeInlineBenefit(Node* node, MethodDesc& methodDesc, InlineNode* parentInlineNode, uint32 loopDepth); - MemoryManager& _mm; + MemoryManager& _tmpMM; IRManager& _toplevelIRM; TypeManager& _typeManager; InstFactory& _instFactory; OpndManager& _opndManager; bool _hasProfileInfo; - bool _useInliningTranslatorCall; - + StlPriorityQueue<CallSite, StlVector<CallSite>, CallSiteCompare> _inlineCandidates; uint32 _initByteSize; uint32 _currentByteSize; @@ -173,6 +173,9 @@ private: uint64 oldMethodId; bool _usesOptimisticBalancedSync; + bool isBCmapRequired; + VectorHandler* bc2HIRMapHandler; + TranslatorAction* translatorAction; }; diff --git vm/jitrino/src/optimizer/irmanager.h vm/jitrino/src/optimizer/irmanager.h index 070df2b..8f1af05 100644 --- vm/jitrino/src/optimizer/irmanager.h +++ vm/jitrino/src/optimizer/irmanager.h @@ -23,39 +23,38 @@ #ifndef _IRMANAGER_H_ #define _IRMANAGER_H_ +#include "JavaTranslator.h" #include "CompilationContext.h" #include "MemoryManager.h" #include "MemoryEstimates.h" #include "Opnd.h" #include "Inst.h" -#include "FlowGraph.h" #include "VMInterface.h" #include "CGSupport.h" +#include "JITInstanceContext.h" +#include "ControlFlowGraph.h" +#include "optimizer.h" +#include "PMFAction.h" namespace Jitrino { -class CodeProfiler; class MethodDesc; class TypeManager; -class JitrinoParameterTable; -class CompilationContext; +class ProfilingInterface; +class LoopTree; typedef StlHashMap<VarOpnd*, VarOpnd*> GCBasePointerMap; class IRManager { public: // Top-level IRManager - IRManager(CompilationInterface& compilationInterface, JitrinoParameterTable& parameterTable) + IRManager(MemoryManager& mm, CompilationInterface& compilationInterface, OptimizerFlags& optFlags) : _parent(0), - _memoryManagerBase(compilationInterface.getMethodToCompile()->getByteCodeSize()* - ESTIMATED_MEMORY_PER_BYTECODE, - "IRManager::memoryManager"), - _memoryManager(_memoryManagerBase), + _memoryManagerBase(mm), + _memoryManager(mm), _opndManager(*(new (_memoryManager) OpndManager(compilationInterface.getTypeManager(),_memoryManager))), _instFactory(*(new (_memoryManager) InstFactory(_memoryManager, *compilationInterface.getMethodToCompile()))), - _flowGraph(*(new (_memoryManager) FlowGraph(_memoryManager,_instFactory,_opndManager))), - _dominatorTree(NULL), - _loopTree(NULL), + _flowGraph(*(new (_memoryManager) ControlFlowGraph(_memoryManager))), _inlinedReturnOpnd(0), _inlineOptPath(NULL), _gcBasePointerMap(*(new (_memoryManager) GCBasePointerMap(_memoryManager))), @@ -66,26 +65,21 @@ public: _heatThreshold(0), _abort(false), _compilationInterface(compilationInterface), - _parameterTable(parameterTable), - _codeProfiler(NULL), _typeManager(compilationInterface.getTypeManager()), _methodDesc(*compilationInterface.getMethodToCompile()), - _jsrEntryMap(NULL) + _jsrEntryMap(NULL), + _optFlags(optFlags) { - _flowGraph.setIRManager(this); } - // Nested IRManager for inlined region - IRManager(IRManager& containingIRManager, MethodDesc& regionMethodDesc, - Opnd *returnOpnd) + // Nested IRManager for inlined region. + IRManager(MemoryManager& tmpMM, IRManager& containingIRManager, MethodDesc& regionMethodDesc, Opnd *returnOpnd) : _parent(&containingIRManager), - _memoryManagerBase(0, "IRManager::memoryManagerBase"), + _memoryManagerBase(tmpMM), _memoryManager(containingIRManager.getMemoryManager()), _opndManager(containingIRManager.getOpndManager()), _instFactory(containingIRManager.getInstFactory()), - _flowGraph(*(new (_memoryManagerBase) FlowGraph(_memoryManager, _instFactory, _opndManager))), - _dominatorTree(NULL), - _loopTree(NULL), + _flowGraph(*(new (_memoryManagerBase) ControlFlowGraph(_memoryManager))), _inlinedReturnOpnd(returnOpnd), _inlineOptPath(_parent->getInlineOptPath()), _gcBasePointerMap(_memoryManagerBase), @@ -96,21 +90,17 @@ public: _heatThreshold(containingIRManager.getHeatThreshold()), _abort(_parent->getAbort()), _compilationInterface(containingIRManager.getCompilationInterface()), - _parameterTable(containingIRManager.getParameterTable()), - _codeProfiler(NULL), _typeManager(_compilationInterface.getTypeManager()), _methodDesc(regionMethodDesc), - _jsrEntryMap(NULL) + _jsrEntryMap(NULL), + _optFlags(containingIRManager._optFlags) { - _flowGraph.setIRManager(this); } // The compilation interface to the VM CompilationInterface& getCompilationInterface() {return _compilationInterface;} - // The parameter table for the top-level method - JitrinoParameterTable& getParameterTable() {return _parameterTable;} - + // The memory manager for the top-level HIR MemoryManager& getMemoryManager() {return _memoryManager; } @@ -131,15 +121,15 @@ public: InstFactory& getInstFactory() {return _instFactory;} // The flowgraph for this region - FlowGraph& getFlowGraph() {return _flowGraph;} + ControlFlowGraph& getFlowGraph() {return _flowGraph;} // The dominator tree for this region - may be NULL or invalid - DominatorTree* getDominatorTree() {return _dominatorTree;} - void setDominatorTree(DominatorTree* tree) { _dominatorTree = tree; } + DominatorTree* getDominatorTree() {return getFlowGraph().getDominatorTree();} + void setDominatorTree(DominatorTree* tree) { getFlowGraph().setDominatorTree(tree); } // The loop tree for this region - may be NULL or invalid - LoopTree* getLoopTree() {return _loopTree;} - void setLoopTree(LoopTree* tree) { _loopTree = tree; } + LoopTree* getLoopTree() {return getFlowGraph().getLoopTree();} + void setLoopTree(LoopTree* tree) { getFlowGraph().setLoopTree(tree);} // The return operand for this region Opnd* getReturnOpnd() { return _inlinedReturnOpnd; } @@ -167,10 +157,6 @@ public: // The minimum Instruction Id in this region. uint32 getMinimumInstId() { return _minRegionInstId; } - // The DPGO Code Profile - CodeProfiler* getCodeProfiler() {return _codeProfiler;} - void setCodeProfiler(CodeProfiler* profiler) { _codeProfiler = profiler; } - // The DPGO threshold for hotness - blocks with a execution count // greater than this threshold should be considered hot double getHeatThreshold() {return _heatThreshold;} @@ -190,15 +176,18 @@ public: // The HIR typechecker main entry point enum OptimizerPhase { OP_FrontEnd, OP_Optimizer }; - CompilationContext* getCompilationContext() {return getCompilationInterface().getCompilationContext();} + CompilationContext* getCompilationContext() {return getCompilationInterface().getCompilationContext();} + JITInstanceContext* getCurrentJITContext() {return getCompilationContext()->getCurrentJITContext();} + ProfilingInterface* getProfilingInterface() {return getCurrentJITContext()->getProfilingInterface();} + const OptimizerFlags& getOptimizerFlags() const {return _optFlags;} private: IRManager* _parent; - MemoryManager _memoryManagerBase; + MemoryManager& _memoryManagerBase; MemoryManager& _memoryManager; OpndManager& _opndManager; InstFactory& _instFactory; - FlowGraph& _flowGraph; + ControlFlowGraph& _flowGraph; DominatorTree* _dominatorTree; LoopTree* _loopTree; Opnd* _inlinedReturnOpnd; @@ -212,11 +201,10 @@ private: bool _abort; CompilationInterface& _compilationInterface; - JitrinoParameterTable& _parameterTable; - CodeProfiler* _codeProfiler; TypeManager& _typeManager; MethodDesc& _methodDesc; JsrEntryInstToRetInstMap* _jsrEntryMap; + OptimizerFlags& _optFlags; }; /** MapHandler is auxilary class to eliminate direct usage of map hanlers between HLO and codegenerator */ diff --git vm/jitrino/src/optimizer/lazyexceptionopt.cpp vm/jitrino/src/optimizer/lazyexceptionopt.cpp index 71e20fd..9744fea 100644 --- vm/jitrino/src/optimizer/lazyexceptionopt.cpp +++ vm/jitrino/src/optimizer/lazyexceptionopt.cpp @@ -32,32 +32,11 @@ #include "optimizer.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(LazyExceptionOptPass, lazyexc, "Lazy Exception Throwing Optimization") +DEFINE_SESSION_ACTION(LazyExceptionOptPass, lazyexc, "Lazy Exception Throwing Optimization") void LazyExceptionOptPass::_run(IRManager& irm) { LazyExceptionOpt le(irm, irm.getMemoryManager()); - -#ifdef _DEBUG - const char* i1=Log::getDotFileDirName(); - OptimizerFlags& optimizerFlags = *irm.getCompilationContext()->getOptimizerFlags(); - if (optimizerFlags.dumpdot) { - if (strlen(i1)!=0) { - FlowGraph& flowGraph = irm.getFlowGraph(); - DominatorTree* dominatorTree = irm.getDominatorTree(); - flowGraph.printDotFile(irm.getMethodDesc(), "le1", (dominatorTree && dominatorTree->isValid()) ? dominatorTree : NULL); - } - } -#endif le.doLazyExceptionOpt(); -#ifdef _DEBUG - if (optimizerFlags.dumpdot) { - if (strlen(i1)!=0) { - FlowGraph& flowGraph = irm.getFlowGraph(); - DominatorTree* dominatorTree = irm.getDominatorTree(); - flowGraph.printDotFile(irm.getMethodDesc(), "le2", (dominatorTree && dominatorTree->isValid()) ? dominatorTree : NULL); - } - } -#endif } int LazyExceptionOpt::level=0; @@ -67,6 +46,14 @@ LazyExceptionOpt::LazyExceptionOpt(IRMan leMemManager(1024,"LazyExceptionOpt::doLazyExceptionOpt"), compInterface(ir_manager.getCompilationInterface()),nodeSet(NULL) { + if (compInterface.isBCMapInfoRequired()) { + isBCmapRequired = true; + MethodDesc* meth = compInterface.getMethodToCompile(); + bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, meth); + } else { + isBCmapRequired = false; + bc2HIRMapHandler = NULL; + } } void @@ -74,22 +61,22 @@ LazyExceptionOpt::doLazyExceptionOpt() { MethodDesc &md = irManager.getMethodDesc(); BitSet excOpnds(leMemManager,irManager.getOpndManager().getNumSsaOpnds()); StlDeque<Inst*> candidateSet(leMemManager); - optCandidates = new OptCandidates(leMemManager); + optCandidates = new (leMemManager) OptCandidates(leMemManager); CompilationInterface::MethodSideEffect m_sideEff = compInterface.getMethodHasSideEffect(&md); - const CFGNodeDeque& nodes = irManager.getFlowGraph().getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = irManager.getFlowGraph().getNodes(); + Nodes::const_iterator niter; #ifdef _DEBUG mtdDesc=&md; #endif #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << std::endl; - for (int i=0; i<level; i++) Log::cat_opt_lazyexc()->debug << " "; - Log::cat_opt_lazyexc()->debug << "doLE "; md.printFullName(Log::out()); - Log::cat_opt_lazyexc()->debug << " SideEff " << (int)m_sideEff << std::endl; + for (int i=0; i<level; i++) Log::out() << " "; + Log::out() << "doLE "; md.printFullName(Log::out()); + Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif @@ -104,24 +91,24 @@ #endif m_sideEff = CompilationInterface::MSE_NO; compInterface.setMethodHasSideEffect(&md,m_sideEff); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " core api exc "; md.printFullName(Log::out()); - Log::cat_opt_lazyexc()->debug << " SideEff " << (int)m_sideEff << std::endl; + if (Log::isEnabled()) { + Log::out() << " core api exc "; md.printFullName(Log::out()); + Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst* inst=headInst->next();inst!=headInst;inst=inst->next()) { + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { #ifdef _DEBUG if (inst->getOpcode()==Op_DefArg && isExceptionInit) { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " defarg: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " "; - Log::cat_opt_lazyexc()->debug << (int)(inst->getDefArgModifier()) << " " << + if (Log::isEnabled()) { + Log::out() << " defarg: "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << " "; + Log::out() << (int)(inst->getDefArgModifier()) << " " << (inst->getDefArgModifier()==DefArgNoModifier) << " " << (inst->getDefArgModifier()==NonNullThisArg) << " " << (inst->getDefArgModifier()==SpecializedToExactType) << " " << @@ -136,11 +123,11 @@ #endif excOpnds.setBit(opndId,false); // different exc. edges #ifdef _DEBUG if (excOpnds.getBit(opndId)==1) { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " add opnd: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " add obj: "; - inst->getSrc(0)->getInst()->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " add opnd: "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << " add obj: "; + inst->getSrc(0)->getInst()->print(Log::out()); Log::out() << std::endl; } } #endif @@ -150,9 +137,9 @@ #endif if (instSideEffect(inst)) { m_sideEff=compInterface.MSE_YES; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << "~~~~~~inst sideEff "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << "~~~~~~inst sideEff "; + inst->print(Log::out()); Log::out() << std::endl; } #endif } @@ -162,9 +149,9 @@ #endif if (m_sideEff == CompilationInterface::MSE_UNKNOWN) if (isExceptionInit && isArgCheckNull) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << "~~~~~~init sideEff reset: " << m_sideEff << " 3 "; - md.printFullName(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << "~~~~~~init sideEff reset: " << m_sideEff << " 3 "; + md.printFullName(Log::out()); Log::out() << std::endl; } #endif m_sideEff = CompilationInterface::MSE_NULL_PARAM; @@ -174,10 +161,10 @@ #endif } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); Opnd* opnd; - for (Inst* inst=headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { uint32 nsrc = inst->getNumSrcOperands(); for (uint32 i=0; i<nsrc; i++) { if (!(opnd=inst->getSrc(i))->isSsaOpnd()) // check ssa operands @@ -191,18 +178,18 @@ #endif if (addOptCandidates(opndId,inst)) { excOpnds.setBit(opndId,false); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " - rem opnd " << opnd->getId() << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " - rem opnd " << opnd->getId() << " "; + inst->print(Log::out()); Log::out() << std::endl; } #endif } } else { excOpnds.setBit(opndId,false); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " -- rem opnd " << opnd->getId() << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " -- rem opnd " << opnd->getId() << " "; + inst->print(Log::out()); Log::out() << std::endl; } #endif } @@ -210,9 +197,9 @@ #endif if (inst->getOpcode()!=Op_Throw) { excOpnds.setBit(opndId,false); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " rem opnd " << opnd->getId() << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " rem opnd " << opnd->getId() << " "; + inst->print(Log::out()); Log::out() << std::endl; } #endif } @@ -222,9 +209,9 @@ #endif } if (!excOpnds.isEmpty()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << "------LE: "; - md.printFullName(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << "------LE: "; + md.printFullName(Log::out()); Log::out() << std::endl; } #endif fixOptCandidates(&excOpnds); @@ -232,21 +219,26 @@ #endif level--; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - for (int i=0; i<level; i++) Log::cat_opt_lazyexc()->debug << " "; - Log::cat_opt_lazyexc()->debug << "done "; md.printFullName(Log::out()); - Log::cat_opt_lazyexc()->debug << " SideEff " << (int)m_sideEff << std::endl; + if (Log::isEnabled()) { + for (int i=0; i<level; i++) Log::out() << " "; + Log::out() << "done "; md.printFullName(Log::out()); + Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif }; +/* +* Returns: +* true, if throw cannot be optimized +* false, otherwise +*/ bool LazyExceptionOpt::addOptCandidates(uint32 id, Inst* inst) { OptCandidate* oc = NULL; ThrowInsts* thrinst = NULL; OptCandidates::iterator it; if (optCandidates == NULL) - optCandidates = new OptCandidates(leMemManager); + optCandidates = new (leMemManager) OptCandidates(leMemManager); for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) { if ((*it)->opndId==id) { oc = *it; @@ -254,17 +246,28 @@ LazyExceptionOpt::addOptCandidates(uint3 } } #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " addOptCandidates: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " addOptCandidates: "; + inst->print(Log::out()); Log::out() << std::endl; } #endif if (oc == NULL) { + if (inst->getOpcode()==Op_Throw) { + bool hasFinalize = + ((NamedType*)inst->getSrc(0)->getType())->isFinalizable(); + if (hasFinalize) { +#ifdef _DEBUG + Log::out() << " isFinalizable: " + << hasFinalize << std::endl; +#endif + return true; + } + } oc = new (leMemManager) OptCandidate; oc->opndId = id; oc->objInst = inst->getSrc(0)->getInst(); oc->initInst=NULL; - thrinst = new ThrowInsts(leMemManager); + thrinst = new (leMemManager) ThrowInsts(leMemManager); thrinst->push_back(inst); oc->throwInsts = thrinst; optCandidates->push_back(oc); @@ -280,9 +283,9 @@ #endif assert(oc->initInst==NULL); oc->initInst = inst; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " addOptCandidates: call checkMC "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " addOptCandidates: call checkMC "; + inst->print(Log::out()); Log::out() << std::endl; } #endif uint32 nii_id=inst->getId()+1; @@ -290,9 +293,9 @@ #endif for (it1 = oc->throwInsts->begin(); it1 !=oc->throwInsts->end(); it1++) { if ((*it1)->getId() != nii_id) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << "?? addOptCandidates: throw "; - (*it1)->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << "?? addOptCandidates: throw "; + (*it1)->print(Log::out()); Log::out() << std::endl; } #endif if (checkInSideEff((*it1),inst)) @@ -309,25 +312,25 @@ #endif bool LazyExceptionOpt::checkInSideEff(Inst* throw_inst, Inst* init_inst) { - CFGNode* node = throw_inst->getNode(); - Inst* instfirst = node->getFirstInst();; + Node* node = throw_inst->getNode(); + Inst* instfirst = (Inst*)node->getFirstInst();; Inst* instlast = throw_inst; Inst* inst; bool dofind = true; bool inSE = false; if (throw_inst!=instfirst) - instlast=throw_inst->prev(); + instlast=throw_inst->getPrevInst(); else { node = node->getInEdges().front()->getSourceNode(); - instlast = node->getLastInst(); + instlast = (Inst*)node->getLastInst(); } while (dofind && node!=NULL) { - instfirst = node->getFirstInst(); - for (inst = instlast; inst!=instfirst; inst=inst->prev()) { + instfirst = (Inst*)node->getFirstInst(); + for (inst = instlast; inst!=instfirst; inst=inst->getPrevInst()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkInSE: see "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkInSE: see "; + inst->print(Log::out()); Log::out() << std::endl; } #endif if (inst==init_inst) { @@ -338,9 +341,9 @@ #endif if (instSideEffect(inst)) { inSE=true; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkInSE: sideEff "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkInSE: sideEff "; + inst->print(Log::out()); Log::out() << std::endl; } #endif break; @@ -349,7 +352,7 @@ #endif } if (dofind){ node = node->getInEdges().front()->getSourceNode(); - instlast = node->getLastInst(); + instlast = (Inst*)node->getLastInst(); } } if (dofind) @@ -359,14 +362,14 @@ #endif bool LazyExceptionOpt::isEqualExceptionNodes(Inst* oi, Inst* ti) { - CFGEdge* oedge = (CFGEdge*)oi->getNode()->getExceptionEdge(); - CFGEdge* tedge = (CFGEdge*)ti->getNode()->getExceptionEdge(); + Edge* oedge = oi->getNode()->getExceptionEdge(); + Edge* tedge = ti->getNode()->getExceptionEdge(); if (oedge->getTargetNode()!=tedge->getTargetNode()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " addOptCandidates: diff.exc.edges for obj&throw "; - Log::cat_opt_lazyexc()->debug << oedge->getTargetNode()->getId() << " "; - Log::cat_opt_lazyexc()->debug << tedge->getTargetNode()->getId() << std::endl; + if (Log::isEnabled()) { + Log::out() << " addOptCandidates: diff.exc.edges for obj&throw "; + Log::out() << oedge->getTargetNode()->getId() << " "; + Log::out() << tedge->getTargetNode()->getId() << std::endl; } #endif return false; @@ -435,19 +438,22 @@ LazyExceptionOpt::fixOptCandidates(BitSe oinst = (*it)->objInst; assert(oinst != NULL); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " to remove "; + if (Log::isEnabled()) { + Log::out() << " to remove "; oinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } #endif iinst = (*it)->initInst->asMethodCallInst(); assert(iinst != NULL); + // inline info from constructor should be propogated to lazy + // exception if any + InlineInfo* constrInlineInfo = iinst->getInlineInfoPtr(); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " to remove "; + if (Log::isEnabled()) { + Log::out() << " to remove "; iinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } #endif assert((*it)->throwInsts != NULL); @@ -466,10 +472,10 @@ #endif } Inst* mptinst = irManager.getInstFactory().makeLdFunAddr(mpt,iinst->getMethodDesc()); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " 1st "; + if (Log::isEnabled()) { + Log::out() << " 1st "; mptinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } #endif ThrowInsts::iterator it1; @@ -477,22 +483,33 @@ #endif tinst = *it1; assert(tinst != NULL); tlinst=irManager.getInstFactory().makeVMHelperCall( - OpndManager::getNullOpnd(), ThrowLazy, opcount, opnds); + OpndManager::getNullOpnd(), ThrowLazy, opcount, + opnds, constrInlineInfo); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " 2nd "; + if (Log::isEnabled()) { + Log::out() << " 2nd "; tlinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " to change "; + if (Log::isEnabled()) { + Log::out() << " to change "; tinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } #endif mptinst->insertBefore(tinst); tlinst->insertBefore(tinst); tinst->unlink(); + + if (isBCmapRequired) { + uint64 bcOffset = ILLEGAL_VALUE; + uint64 instID = iinst->getId(); + bcOffset = bc2HIRMapHandler->getVectorEntry(instID); + if (bcOffset != ILLEGAL_VALUE) { + bc2HIRMapHandler->setVectorEntry(mptinst->getId(), bcOffset); + bc2HIRMapHandler->setVectorEntry(tlinst->getId(), bcOffset); + } + } } irManager.getFlowGraph().purgeEmptyNodes(); } @@ -501,21 +518,21 @@ #endif bool LazyExceptionOpt::removeInsts(Inst* oinst,Inst* iinst) { - FlowGraph fg = irManager.getFlowGraph(); - CFGEdge* oedge = (CFGEdge*)oinst->getNode()->getExceptionEdge(); - CFGEdge* iedge = (CFGEdge*)iinst->getNode()->getExceptionEdge(); - CFGNode* otn = oedge->getTargetNode(); - CFGNode* itn = iedge->getTargetNode(); + ControlFlowGraph& fg = irManager.getFlowGraph(); + Edge* oedge = oinst->getNode()->getExceptionEdge(); + Edge* iedge = iinst->getNode()->getExceptionEdge(); + Node* otn = oedge->getTargetNode(); + Node* itn = iedge->getTargetNode(); if (otn!=itn) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " removeInsts: diff.exc.edges for obj&init "; - Log::cat_opt_lazyexc()->debug << otn->getId() << " " << itn->getId() << std::endl; - Log::cat_opt_lazyexc()->debug << " "; oinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " "; iinst->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " removeInsts: diff.exc.edges for obj&init "; + Log::out() << otn->getId() << " " << itn->getId() << std::endl; + Log::out() << " "; oinst->print(Log::out()); + Log::out() << std::endl; + Log::out() << " "; iinst->print(Log::out()); + Log::out() << std::endl; } #endif return false; @@ -534,10 +551,10 @@ #endif } void -LazyExceptionOpt::removeNode(CFGNode* node) { - const CFGEdgeDeque &out_edges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eit; - CFGNode* n; +LazyExceptionOpt::removeNode(Node* node) { + const Edges &out_edges = node->getOutEdges(); + Edges::const_iterator eit; + Node* n; for (eit = out_edges.begin(); eit != out_edges.end(); ++eit) { n = (*eit)->getTargetNode(); if (n->getInEdges().size() == 1) @@ -571,27 +588,27 @@ LazyExceptionOpt::checkMethodCall(Inst* cmd = inst->asCallInst()->getFunPtr()->getType()->asMethodPtrType()->getMethodDesc(); } else { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: no check "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: no check "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return true; } } #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: "; - cmd->printFullName(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: "; + cmd->printFullName(Log::out()); Log::out() << std::endl; } #endif mse=compInterface.getMethodHasSideEffect(cmd); #ifdef _DEBUG if (mse!=CompilationInterface::MSE_UNKNOWN) { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: prev.set sideEff " << mse << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: prev.set sideEff " << mse << " "; + inst->print(Log::out()); Log::out() << std::endl; } } #endif @@ -606,9 +623,9 @@ #endif && strncmp(cmd->getParentType()->getName(),"java/lang/",10) == 0) { compInterface.setMethodHasSideEffect(cmd,CompilationInterface::MSE_NO); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: core api exc "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: core api exc "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return false; @@ -616,9 +633,9 @@ #endif if ( opcode!=Op_DirectCall && !cmd->isFinal() ) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: not DirCall not final "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: not DirCall not final "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return true; @@ -627,12 +644,12 @@ #endif if (!isExceptionInit && !(cmd->isInstanceInitializer()&&cmd->getParentType()->isLikelyExceptionType())) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: no init "; - Log::cat_opt_lazyexc()->debug << isExceptionInit << " "; - Log::cat_opt_lazyexc()->debug << cmd->isInstanceInitializer() << " "; - Log::cat_opt_lazyexc()->debug << cmd->getParentType()->isLikelyExceptionType() << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: no init "; + Log::out() << isExceptionInit << " "; + Log::out() << cmd->isInstanceInitializer() << " "; + Log::out() << cmd->getParentType()->isLikelyExceptionType() << " "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return true; @@ -640,9 +657,9 @@ #endif if (cmd->getParentType()->needsInitialization()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: need cinit "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: need cinit "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return true; // cannot compile <init> before <clinit> (to fix vm) @@ -650,8 +667,8 @@ #endif if (compInterface.compileMethod(cmd)) { mse = compInterface.getMethodHasSideEffect(cmd); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: method was compiled, sideEff " + if (Log::isEnabled()) { + Log::out() << " checkMC: method was compiled, sideEff " << mse << std::endl; } #endif @@ -664,9 +681,9 @@ #endif bool mayBeNull; if (nsrc>3) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: exc.init "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: exc.init "; + inst->print(Log::out()); Log::out() << std::endl; } #endif mayBeNull=false; @@ -681,11 +698,11 @@ #endif return false; #ifdef _DEBUG for (uint32 i=0; i<nsrc; i++) { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " "<<i<<" isRef: "<< + if (Log::isEnabled()) { + Log::out() << " "<<i<<" isRef: "<< inst->getSrc(i)->getType()->isReference()<<" "; inst->getSrc(i)->getInst()->print(Log::out()); - Log::cat_opt_lazyexc()->debug << std::endl; + Log::out() << std::endl; } } #endif @@ -693,8 +710,8 @@ #endif } #ifdef _DEBUG else { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " ?????? MSE_NULL_PARAM & nsrc "<< + if (Log::isEnabled()) { + Log::out() << " ?????? MSE_NULL_PARAM & nsrc "<< nsrc << std::endl; } } @@ -704,8 +721,8 @@ #endif } } else { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkMC: method was not compiled " << std::endl; + if (Log::isEnabled()) { + Log::out() << " checkMC: method was not compiled " << std::endl; } #endif return true; @@ -715,12 +732,12 @@ #endif bool LazyExceptionOpt::mayBeNullArg(Inst* call_inst, Inst* src_inst) { uint32 mnid = irManager.getFlowGraph().getMaxNodeId(); - CFGNode* node = call_inst->getNode(); + Node* node = call_inst->getNode(); bool done = true; if (nodeSet == NULL) { nodeSet = new (leMemManager) NodeSet; - nodeSet->nodes=new BitSet(leMemManager,mnid); + nodeSet->nodes=new (leMemManager) BitSet(leMemManager,mnid); } else { nodeSet->nodes->clear(); } @@ -731,20 +748,20 @@ LazyExceptionOpt::mayBeNullArg(Inst* cal done = checkArg(node); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " mb0 done " << done << " nodes: " << std::endl; + if (Log::isEnabled()) { + Log::out() << " mb0 done " << done << " nodes: " << std::endl; for(uint32 i = 0; i < mnid; i++) { if (nodeSet->nodes->getBit(i)) { - Log::cat_opt_lazyexc()->debug << " " << i; + Log::out() << " " << i; } } - Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " arg node: " << nodeSet->arg_src_inst->getNode()->getId() << std::endl; - Log::cat_opt_lazyexc()->debug << " call node: " << nodeSet->call_inst->getNode()->getId() << std::endl; + Log::out() << std::endl; + Log::out() << " arg node: " << nodeSet->arg_src_inst->getNode()->getId() << std::endl; + Log::out() << " call node: " << nodeSet->call_inst->getNode()->getId() << std::endl; if (nodeSet->check_inst) - Log::cat_opt_lazyexc()->debug << " check node: " << nodeSet->check_inst->getNode()->getId() << std::endl; + Log::out() << " check node: " << nodeSet->check_inst->getNode()->getId() << std::endl; if (nodeSet->reset_inst) - Log::cat_opt_lazyexc()->debug << " reset node: " << nodeSet->reset_inst->getNode()->getId() << std::endl; + Log::out() << " reset node: " << nodeSet->reset_inst->getNode()->getId() << std::endl; } #endif if (!done) @@ -760,18 +777,18 @@ #endif } bool -LazyExceptionOpt::checkArg(CFGNode* nodeS) { - CFGNode* node = nodeS; - Inst* instfirst = node->getFirstInst(); - Inst* instlast = node->getLastInst(); +LazyExceptionOpt::checkArg(Node* nodeS) { + Node* node = nodeS; + Inst* instfirst = (Inst*)node->getFirstInst(); + Inst* instlast = (Inst*)node->getLastInst(); Inst* inst; Opnd* arg_opnd = nodeSet->arg_src_inst->getDst(); bool doneOK = true; bool dofind = true; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkArg: first node " << node->getId() + if (Log::isEnabled()) { + Log::out() << " checkArg: first node " << node->getId() << " inEdges " << node->getInDegree() << " " << std::endl; } #endif @@ -780,32 +797,32 @@ #endif if ( nodeSet->nodes->getBit(node->getId()) ) { if (nodeSet->call_inst->getNode() == node) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " node " << node->getId() + if (Log::isEnabled()) { + Log::out() << " node " << node->getId() << " again in call_inst node " << std::endl; } #endif doneOK = false; } #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " node " << node->getId() + if (Log::isEnabled()) { + Log::out() << " node " << node->getId() << " inEdges " << node->getInDegree() << " was scanned " << std::endl; } #endif break; } #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " node " << node->getId() + if (Log::isEnabled()) { + Log::out() << " node " << node->getId() << " inEdges " << node->getInDegree() << std::endl; } #endif - for (inst = instlast; inst!=instfirst; inst=inst->prev()) { + for (inst = instlast; inst!=instfirst; inst=inst->getPrevInst()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " "; + inst->print(Log::out()); Log::out() << std::endl; } #endif if (inst==nodeSet->arg_src_inst) { @@ -817,8 +834,8 @@ #endif dofind = false; doneOK = false; #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " check_inst is not NULL" << std::endl; + if (Log::isEnabled()) { + Log::out() << " check_inst is not NULL" << std::endl; } #endif } @@ -828,8 +845,8 @@ #endif if (inst->getDst()==arg_opnd) { #ifdef _DEBUG if (nodeSet->reset_inst != NULL) { - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " reset_inst is not NULL" << std::endl; + if (Log::isEnabled()) { + Log::out() << " reset_inst is not NULL" << std::endl; } } #endif @@ -848,11 +865,11 @@ #endif } if (node->getInDegree()==1) { node = node->getInEdges().front()->getSourceNode(); - instfirst = node->getFirstInst(); - instlast = node->getLastInst(); + instfirst = (Inst*)node->getFirstInst(); + instlast = (Inst*)node->getLastInst(); } else { - const CFGEdgeDeque &in_edges = node->getInEdges(); - CFGEdgeDeque::const_iterator eit; + const Edges &in_edges = node->getInEdges(); + Edges::const_iterator eit; for (eit = in_edges.begin(); eit != in_edges.end(); ++eit) { if ( !(checkArg((*eit)->getSourceNode())) ) { doneOK = false; @@ -874,13 +891,13 @@ LazyExceptionOpt::checkField(Inst* inst) Inst* instDef = insOp->getInst(); if (instDef->getOpcode() == Op_DefArg) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checkField: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " checkField: "; - instDef->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " checkField: "; - Log::cat_opt_lazyexc()->debug << (int)(instDef->getDefArgModifier()) << " " << + if (Log::isEnabled()) { + Log::out() << " checkField: "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << " checkField: "; + instDef->print(Log::out()); Log::out() << std::endl; + Log::out() << " checkField: "; + Log::out() << (int)(instDef->getDefArgModifier()) << " " << (instDef->getDefArgModifier()==DefArgNoModifier) << " " << (instDef->getDefArgModifier()==NonNullThisArg) << " " << (instDef->getDefArgModifier()==DefArgBothModifiers) << std::endl; @@ -928,9 +945,9 @@ LazyExceptionOpt::instSideEffect(Inst* i case Op_IndirectCall: case Op_IndirectMemoryCall: #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " instSideEffect: call checkMC "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " instSideEffect: call checkMC "; + inst->print(Log::out()); Log::out() << std::endl; } #endif return checkMethodCall(inst); @@ -942,7 +959,6 @@ #endif case Op_Catch: return false; case Op_Throw: - case Op_ThrowLazy: case Op_ThrowSystemException: case Op_ThrowLinkingException: return true; @@ -959,7 +975,7 @@ #endif return true; case Op_DefArg: case Op_LdConstant: - case Op_LdString: + case Op_LdRef: case Op_LdVar: case Op_LdVarAddr: case Op_TauLdInd: @@ -995,11 +1011,11 @@ #endif { Inst* inst_src1 = inst->getSrc(1)->getInst(); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " stind: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " "; - inst_src1->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " stind: "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << " "; + inst_src1->print(Log::out()); Log::out() << std::endl; } #endif if (inst_src1->getOpcode()==Op_LdFieldAddr ) @@ -1019,11 +1035,11 @@ #endif { Inst* inst_src = inst->getSrc(0)->getInst(); #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << " checknull: "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << " "; - inst_src->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; + if (Log::isEnabled()) { + Log::out() << " checknull: "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << " "; + inst_src->print(Log::out()); Log::out() << std::endl; } #endif if (inst_src->getOpcode()==Op_DefArg && isExceptionInit) { @@ -1043,10 +1059,10 @@ #endif NamedType* nt = inst->getDst()->getType()->asNamedType(); if (strncmp(nt->getName(),"java/lang/",10)==0 && nt->isLikelyExceptionType()) { #ifdef _DEBUG - if (Log::cat_opt_lazyexc()->isDebugEnabled()) { - Log::cat_opt_lazyexc()->debug << "====newobj "; - inst->print(Log::out()); Log::cat_opt_lazyexc()->debug << std::endl; - Log::cat_opt_lazyexc()->debug << "core api exc " << nt->getName() << " " + if (Log::isEnabled()) { + Log::out() << "====newobj "; + inst->print(Log::out()); Log::out() << std::endl; + Log::out() << "core api exc " << nt->getName() << " " << strncmp(nt->getName(),"java/lang/",10) << " excType: " << nt->isLikelyExceptionType() << std::endl; } diff --git vm/jitrino/src/optimizer/lazyexceptionopt.h vm/jitrino/src/optimizer/lazyexceptionopt.h index bc245a1..a57b4e6 100644 --- vm/jitrino/src/optimizer/lazyexceptionopt.h +++ vm/jitrino/src/optimizer/lazyexceptionopt.h @@ -28,10 +28,10 @@ #include "optpass.h" #include "Inst.h" #include "BitSet.h" #include "VMInterface.h" +#include "irmanager.h" namespace Jitrino { -DEFINE_OPTPASS(LazyExceptionOptPass) class LazyExceptionOpt { public: @@ -45,13 +45,13 @@ private: void fixOptCandidates(BitSet* bs); void printOptCandidates(::std::ostream& os); bool checkMethodCall(Inst* inst); - void removeNode(CFGNode* node); + void removeNode(Node* node); bool removeInsts(Inst* oinst,Inst* iinst); bool checkField(Inst* inst); bool isEqualExceptionNodes(Inst* oi, Inst* ti); bool checkInSideEff(Inst* throw_inst, Inst* init_inst); bool mayBeNullArg(Inst* call_inst, Inst* src_inst); - bool checkArg(CFGNode* node); + bool checkArg(Node* node); private: IRManager &irManager; @@ -63,14 +63,14 @@ private: #ifdef _DEBUG MethodDesc* mtdDesc; #endif - typedef StlList<Inst*> ThrowInsts; + typedef StlList<Inst*> ThrowInsts; struct OptCandidate { uint32 opndId; Inst* objInst; Inst* initInst; ThrowInsts* throwInsts; }; - typedef StlList<OptCandidate*> OptCandidates; + typedef StlList<OptCandidate*> OptCandidates; OptCandidates* optCandidates; static int level; struct NodeSet { @@ -81,6 +81,9 @@ #endif Inst* reset_inst; }; NodeSet* nodeSet; + // Byte code map info + bool isBCmapRequired; + VectorHandler* bc2HIRMapHandler; }; } // namespace Jitrino diff --git vm/jitrino/src/optimizer/memoryopt.cpp vm/jitrino/src/optimizer/memoryopt.cpp index 14991cb..efac2fe 100644 --- vm/jitrino/src/optimizer/memoryopt.cpp +++ vm/jitrino/src/optimizer/memoryopt.cpp @@ -25,36 +25,34 @@ #include <iostream> #include <algorithm> #include "Stl.h" #include "Log.h" -#include "PropertyTable.h" #include "open/types.h" #include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" #include "Loop.h" #include "Opcode.h" #include "walkers.h" - +#include "optpass.h" #include "opndmap.h" #include "memoryopt.h" #include "aliasanalyzer.h" #include "memoryoptrep.h" #include "./ssa/SSA.h" -#include "Timer.h" +#include "XTimer.h" #include "hashvaluenumberer.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(MemoryValueNumberingPass, memopt, "Redundant Ld-St Elimination") +DEFINE_SESSION_ACTION(MemoryValueNumberingPass, memopt, "Redundant Ld-St Elimination") void -MemoryValueNumberingPass::_run(IRManager& irm) { +MemoryValueNumberingPass::_run(IRManager& irm) { computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); assert(dominatorTree && dominatorTree->isValid()); LoopTree* loopTree = irm.getLoopTree(); - FlowGraph& flowGraph = irm.getFlowGraph(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); MemoryManager& memoryManager = irm.getNestedMemoryManager(); DomFrontier frontier(memoryManager,*dominatorTree,&flowGraph); @@ -65,14 +63,12 @@ MemoryValueNumberingPass::_run(IRManager HashValueNumberer valueNumberer(irm, *dominatorTree); valueNumberer.doValueNumbering(&mopt); - bool do_redstore = irm.getParameterTable().lookupBool("opt::do_redstore", true); + bool do_redstore = irm.getOptimizerFlags().memOptFlags->do_redstore; if (do_redstore) { mopt.eliminateRedStores(); } } -MemoryOpt::Flags *MemoryOpt::defaultFlags = 0; - MemoryOpt::MemoryOpt(IRManager &irManager0, MemoryManager& memManager, DominatorTree& dom0, @@ -92,9 +88,8 @@ MemoryOpt::MemoryOpt(IRManager &irManage renameMap(0), memUseDefs(memManager), memDefUses(memManager), - flags(*defaultFlags) + flags(*irManager.getOptimizerFlags().memOptFlags) { - assert(defaultFlags); assert(aliasManager); uint32 numNodes = df0.getNumNodes(); @@ -110,67 +105,69 @@ MemoryOpt::~MemoryOpt() } void -MemoryOpt::readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params) +MemoryOpt::readFlags(Action* argSource, MemoptFlags* flags) { - if (!defaultFlags) - defaultFlags = new Flags; - const char *res = params->lookup("opt::mm"); - defaultFlags->model = Model_Default; + IAction::HPipeline p = NULL; //default pipeline for argSource + + const char *res = argSource->getStringArg(p, "memopt.mm", NULL); + flags->model = Model_Default; if (res) { if (strncmp(res,"strict",7)==0) { - defaultFlags->model = Model_Strict; + flags->model = Model_Strict; } else if (strncmp(res,"reads_kill",11)==0) { - defaultFlags->model = Model_ReadsKill; + flags->model = Model_ReadsKill; } else if (strncmp(res,"cse_final",9)==0) { - defaultFlags->model = Model_CseFinal; + flags->model = Model_CseFinal; } } - res = params->lookup("opt::synch"); - defaultFlags->synch = Synch_Default; + res = argSource->getStringArg(p, "memopt.synch", NULL); + flags->synch = Synch_Default; if (res) { if (strncmp(res,"fence", 6)==0) { - defaultFlags->synch = Synch_Fence; + flags->synch = Synch_Fence; } else if (strncmp(res,"moveable", 9)==0) { - defaultFlags->synch = Synch_Moveable; + flags->synch = Synch_Moveable; } else if (strncmp(res,"only_lock", 10)==0) { - defaultFlags->synch = Synch_OnlyLock; + flags->synch = Synch_OnlyLock; } else if (strncmp(res,"one_thread", 11)==0) { - defaultFlags->synch = Synch_OneThread; + flags->synch = Synch_OneThread; } } - defaultFlags->debug = params->lookupBool("opt::mem::debug", false); - defaultFlags->verbose = params->lookupBool("opt::mem::verbose", false); - defaultFlags->redstore = params->lookupBool("opt::mem::redstore", false); - defaultFlags->syncopt = params->lookupBool("opt::mem::syncopt", false); + flags->debug = argSource->getBoolArg(p, "memopt.debug", false); + flags->verbose = argSource->getBoolArg(p, "memopt.verbose", false); + flags->redstore = argSource->getBoolArg(p, "memopt.redstore", false); + flags->syncopt = argSource->getBoolArg(p, "memopt.syncopt", false); + flags->do_redstore = argSource->getBoolArg(p, "memopt.do_redstore", true); + } -void MemoryOpt::showFlagsFromCommandLine() -{ - Log::out() << " opt::mm=strict = no memory optimizations" << ::std::endl; - Log::out() << " opt::mm=reads_kill = reads kill" << ::std::endl; - Log::out() << " opt::mm=cse_final = allow final field CSEing, maybe hoisting" << ::std::endl; - Log::out() << " opt::synch=fence = no memory ops move past lock/unlock" << ::std::endl; - Log::out() << " opt::synch=moveable = load/store movement into locks allowed" << ::std::endl; - Log::out() << " opt::synch=only_lock = eliminable local objects not treated as fence" << ::std::endl; - Log::out() << " opt::synch=one_thread = locks and fences elided freely" << ::std::endl; - Log::out() << " opt::mem::debug[={ON,off}] = debug memory opts" << ::std::endl; - Log::out() << " opt::mem::verbose[={ON,off}] = verbose memory opt output" << ::std::endl; - Log::out() << " opt::mem::redstore[={on,OFF}] = try to eliminate redundant stores" << ::std::endl; - Log::out() << " opt::mem::syncopt[={on,OFF}] = turn exit/enter into fences" << ::std::endl; +void MemoryOpt::showFlags(std::ostream& os) { + os << " memopt flags:"<<std::endl; + os << " memopt.mm=strict - no memory optimizations" << std::endl; + os << " memopt.mm=reads_kill - reads kill" << std::endl; + os << " memopt.mm=cse_final - allow final field CSEing, maybe hoisting" << std::endl; + os << " memopt.synch=fence - no memory ops move past lock/unlock" << std::endl; + os << " memopt.synch=moveable - load/store movement into locks allowed" << std::endl; + os << " memopt.synch=only_lock - eliminable local objects not treated as fence" << std::endl; + os << " memopt.synch=one_thread - locks and fences elided freely" << std::endl; + os << " memopt.debug[={ON,off}] - debug memory opts" << std::endl; + os << " memopt.verbose[={ON,off}] - verbose memory opt output" << std::endl; + os << " memopt.redstore[={on,OFF}] - try to eliminate redundant stores" << std::endl; + os << " memopt.syncopt[={on,OFF}] - turn exit/enter into fences" << std::endl; } -static Timer *memoptPhase1Timer = 0; // not thread-safe -static Timer *memoptPhase2Timer = 0; // not thread-safe -static Timer *memoptPhase3Timer = 0; // not thread-safe +static CountTime memoptPhase1Timer("opt::mem::phase1"); // not thread-safe +static CountTime memoptPhase2Timer("opt::mem::phase2"); // not thread-safe +static CountTime memoptPhase3Timer("opt::mem::phase3"); // not thread-safe void MemoryOpt::runPass() { - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Starting MemoryOpt Pass" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Starting MemoryOpt Pass" << std::endl; } // initialize iDef, iUse for each instr, build initial set of locations { - PhaseTimer t(memoptPhase1Timer, "opt::mem::phase1"); + AutoTimer t(memoptPhase1Timer); initMemoryOperations(); } @@ -194,47 +191,47 @@ void MemoryOpt::runPass() // // if (flags.redstore) { - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Trying redundant store elimination" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Trying redundant store elimination" << std::endl; } - PhaseTimer t(memoptPhase2Timer, "opt::mem::phase2"); + AutoTimer t(memoptPhase2Timer); eliminateRedStores(); } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Finished MemoryOpt Pass" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Finished MemoryOpt Pass" << std::endl; } if (flags.syncopt) { - PhaseTimer t(memoptPhase3Timer, "opt::mem::phase3"); - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Trying synchronization optimization" << ::std::endl; + AutoTimer t(memoptPhase3Timer); + if (Log::isEnabled()) { + Log::out() << "Trying synchronization optimization" << std::endl; } doSyncOpt(); } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Finished synchronization optimization" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Finished synchronization optimization" << std::endl; } } // a NodeInstWalker, backwards over instructions class MemoryOptInitWalker { MemoryOpt *thePass; - CFGNode *n; + Node *n; public: MemoryOptInitWalker(MemoryOpt *thePass0) : thePass(thePass0), n(0) { }; - void startNode(CFGNode *node) { n = node; }; + void startNode(Node *node) { n = node; }; void applyToInst(Inst *inst); - void finishNode(CFGNode *node) {}; + void finishNode(Node *node) {}; }; // Phase 1: for each memory access, get an description of the set of // memory locations which must be considered with it. -static Timer *memoptPhase1bTimer = 0; // not thread-safe -static Timer *memoptPhase1cTimer = 0; // not thread-safe -static Timer *memoptPhase1dTimer = 0; // not thread-safe +static CountTime memoptPhase1bTimer("opt::mem::phase1b"); // not thread-safe +static CountTime memoptPhase1cTimer("opt::mem::phase1c"); // not thread-safe +static CountTime memoptPhase1dTimer("opt::mem::phase1d"); // not thread-safe void MemoryOpt::initMemoryOperations() { @@ -243,37 +240,37 @@ void MemoryOpt::initMemoryOperations() typedef NodeInst2NodeWalker<false, MemoryOptInitWalker> InitNodeWalker; InitNodeWalker initNodeWalker(initWalker); - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << ::std::endl << "Instruction Memory Effects:" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << std::endl << "Instruction Memory Effects:" << std::endl; } { - PhaseTimer t(memoptPhase1bTimer, "opt::mem::phase1b"); + AutoTimer t(memoptPhase1bTimer); // have the first inst, define Any for renaming walk DominatorNode *domRoot = dominators.getDominatorRoot(); - CFGNode *cfgRoot = domRoot->getNode(); - Inst *firstInst = cfgRoot->getFirstInst(); + Node *cfgRoot = domRoot->getNode(); + Inst *firstInst = (Inst*)cfgRoot->getFirstInst(); assert(firstInst->isLabel()); AliasRep escapingMem = aliasManager->getAny(); renameMap->insert(escapingMem, firstInst); } { - PhaseTimer t(memoptPhase1cTimer, "opt::mem::phase1c"); + AutoTimer t(memoptPhase1cTimer); // walk over all instructions, inserting memory effects NodeWalk<InitNodeWalker>(fg, initNodeWalker); - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << ::std::endl << "END of Instruction Memory Effects" << ::std::endl; + if (Log::isEnabled()) { + Log::out() << std::endl << "END of Instruction Memory Effects" << std::endl; } insertMemPhi(); } - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { aliasManager->dumpAliasReps(Log::out()); } { - PhaseTimer t(memoptPhase1dTimer, "opt::mem::phase1d"); + AutoTimer t(memoptPhase1dTimer); createUsesMap(); } } @@ -337,7 +334,7 @@ MemoryOpt::getOrCreateInstEffect(Inst *i } // R/W anything that escapes or is global -void MemoryOpt::effectAnyGlobal(CFGNode *n, Inst *i) +void MemoryOpt::effectAnyGlobal(Node *n, Inst *i) { AliasRep anyGlobal = aliasManager->getAnyGlobal(); addUseToInstruction(n, i, anyGlobal); @@ -345,92 +342,92 @@ void MemoryOpt::effectAnyGlobal(CFGNode } // writes opnd.vptr -void MemoryOpt::effectWriteVtable(CFGNode *n, Inst *i, Opnd *opnd) +void MemoryOpt::effectWriteVtable(Node *n, Inst *i, Opnd *opnd) { AliasRep vtblMemory = aliasManager->getVtableOf(opnd); addDefToInstruction(n, i, vtblMemory); } -void MemoryOpt::effectReadVtable(CFGNode *n, Inst *i, Opnd *opnd) +void MemoryOpt::effectReadVtable(Node *n, Inst *i, Opnd *opnd) { AliasRep vtblMemory = aliasManager->getVtableOf(opnd); addUseToInstruction(n, i, vtblMemory); } -void MemoryOpt::effectReadMethodPtr(CFGNode *n, Inst *i, Opnd *obj, MethodDesc *desc) +void MemoryOpt::effectReadMethodPtr(Node *n, Inst *i, Opnd *obj, MethodDesc *desc) { AliasRep methodPtrMem = aliasManager->getMethodPtr(obj, desc); addUseToInstruction(n, i, methodPtrMem); } -void MemoryOpt::effectReadMethodPtr(CFGNode *n, Inst *i, MethodDesc *desc) +void MemoryOpt::effectReadMethodPtr(Node *n, Inst *i, MethodDesc *desc) { NamedType *theType = desc->getParentType(); AliasRep typeVtable = aliasManager->getVtableOf(theType); addUseToInstruction(n, i, typeVtable); } -void MemoryOpt::effectReadFunPtr(CFGNode *n, Inst *i, Opnd *fnptr) +void MemoryOpt::effectReadFunPtr(Node *n, Inst *i, Opnd *fnptr) { } -void MemoryOpt::effectExit(CFGNode *n, Inst *i) +void MemoryOpt::effectExit(Node *n, Inst *i) { AliasRep escapingMem = aliasManager->getAnyEscaping(); addUseToInstruction(n, i, escapingMem); } -void MemoryOpt::effectInit(CFGNode *n, Inst *i) +void MemoryOpt::effectInit(Node *n, Inst *i) { AliasRep escapingMem = aliasManager->getAny(); addDefToInstruction(n, i, escapingMem); } -void MemoryOpt::effectEntry(CFGNode *n, Inst *i) +void MemoryOpt::effectEntry(Node *n, Inst *i) { AliasRep escapingMem = aliasManager->getAnyEscaping(); addDefToInstruction(n, i, escapingMem); } -void MemoryOpt::effectRead(CFGNode *n, Inst *i, Opnd *addr) +void MemoryOpt::effectRead(Node *n, Inst *i, Opnd *addr) { AliasRep thisMem = aliasManager->getReference(addr); addUseToInstruction(n, i, thisMem); } -void MemoryOpt::effectWrite(CFGNode *n, Inst *i, Opnd *addr) +void MemoryOpt::effectWrite(Node *n, Inst *i, Opnd *addr) { AliasRep thisMem = aliasManager->getReference(addr); addDefToInstruction(n, i, thisMem); } -void MemoryOpt::effectReadClassVtable(CFGNode *n, Inst *i, NamedType *t) +void MemoryOpt::effectReadClassVtable(Node *n, Inst *i, NamedType *t) { AliasRep vtblMemory = aliasManager->getVtableOf(t); addDefToInstruction(n, i, vtblMemory); } -void MemoryOpt::effectWriteArrayLength(CFGNode *n, Inst *i, Opnd *opnd) +void MemoryOpt::effectWriteArrayLength(Node *n, Inst *i, Opnd *opnd) { AliasRep arrayLenMem = aliasManager->getArrayLen(opnd); addDefToInstruction(n, i, arrayLenMem); } -void MemoryOpt::effectReadArrayLength(CFGNode *n, Inst *i, Opnd *opnd) +void MemoryOpt::effectReadArrayLength(Node *n, Inst *i, Opnd *opnd) { AliasRep arrayLenMem = aliasManager->getArrayLen(opnd); addUseToInstruction(n, i, arrayLenMem); } -void MemoryOpt::effectWriteArrayElements(CFGNode *n, Inst *i, Opnd *array, +void MemoryOpt::effectWriteArrayElements(Node *n, Inst *i, Opnd *array, Opnd *offset, Opnd *length) { AliasRep arrayElemMem = aliasManager->getArrayElements(array, offset, length); addDefToInstruction(n, i, arrayElemMem); } -void MemoryOpt::effectReadArrayElements(CFGNode *n, Inst *i, Opnd *array, +void MemoryOpt::effectReadArrayElements(Node *n, Inst *i, Opnd *array, Opnd *offset, Opnd *length) { AliasRep arrayElemMem = aliasManager->getArrayElements(array, offset, length); @@ -439,46 +436,46 @@ void MemoryOpt::effectReadArrayElements( // creates an object/array, returned in opnd: // writes array length, etc. -void MemoryOpt::effectNew(CFGNode *n, Inst *i, Opnd *dstop) +void MemoryOpt::effectNew(Node *n, Inst *i, Opnd *dstop) { AliasRep objInitMem = aliasManager->getObjectNew(dstop); addDefToInstruction(n, i, objInitMem); } // make sure object's vtable are visible to others before publishing this -void MemoryOpt::effectReleaseObject(CFGNode *n, Inst *i, Opnd *obj) +void MemoryOpt::effectReleaseObject(Node *n, Inst *i, Opnd *obj) { addReleaseToInstruction(n, i); } // make sure object's vtable is available to all -void MemoryOpt::effectInitType(CFGNode *n, Inst *i, NamedType *type) +void MemoryOpt::effectInitType(Node *n, Inst *i, NamedType *type) { AliasRep typeInitMem = aliasManager->getTypeNew(type); addDefToInstruction(n, i, typeInitMem); } // make sure object's vtable is available to all -void MemoryOpt::effectFinishObject(CFGNode *n, Inst *i, Opnd *obj) +void MemoryOpt::effectFinishObject(Node *n, Inst *i, Opnd *obj) { AliasRep objFinishMem = aliasManager->getFinishObject(obj); addDefToInstruction(n, i, objFinishMem); } // make sure object's vtable is available to all -void MemoryOpt::effectFinishType(CFGNode *n, Inst *i, NamedType *type) +void MemoryOpt::effectFinishType(Node *n, Inst *i, NamedType *type) { AliasRep typeFinishMem = aliasManager->getFinishType(type); addDefToInstruction(n, i, typeFinishMem); } // can commute with any ops, but not be added/removed: -void MemoryOpt::effectIncCounter(CFGNode *n, Inst *i) +void MemoryOpt::effectIncCounter(Node *n, Inst *i) { } // object may be 0 if lock has been removed -void MemoryOpt::effectIncRecCount(CFGNode *n, Inst *i, Opnd *object) +void MemoryOpt::effectIncRecCount(Node *n, Inst *i, Opnd *object) { if (object) { AliasRep thisMem = aliasManager->getLock(object); @@ -489,7 +486,7 @@ void MemoryOpt::effectIncRecCount(CFGNod } // object may be 0 if lock has been removed -void MemoryOpt::effectMonitorEnter(CFGNode *n, Inst *i, Opnd *object) +void MemoryOpt::effectMonitorEnter(Node *n, Inst *i, Opnd *object) { if (object) { AliasRep thisMem = aliasManager->getLock(object); @@ -500,7 +497,7 @@ void MemoryOpt::effectMonitorEnter(CFGNo addAcquireToInstruction(n, i); } -void MemoryOpt::effectMonitorExit(CFGNode *n, Inst *i, Opnd *object) +void MemoryOpt::effectMonitorExit(Node *n, Inst *i, Opnd *object) { if (object) { AliasRep thisMem = aliasManager->getLock(object); @@ -512,7 +509,7 @@ void MemoryOpt::effectMonitorExit(CFGNod } // object may be 0 if lock has been removed -void MemoryOpt::effectTypeMonitorEnter(CFGNode *n, Inst *i, Type *type) +void MemoryOpt::effectTypeMonitorEnter(Node *n, Inst *i, Type *type) { assert(type); @@ -523,7 +520,7 @@ void MemoryOpt::effectTypeMonitorEnter(C addAcquireToInstruction(n, i); } -void MemoryOpt::effectTypeMonitorExit(CFGNode *n, Inst *i, Type *type) +void MemoryOpt::effectTypeMonitorExit(Node *n, Inst *i, Type *type) { assert(type); @@ -533,17 +530,17 @@ void MemoryOpt::effectTypeMonitorExit(CF addReleaseToInstruction(n, i); } -void MemoryOpt::addDefToInstruction(CFGNode *n, Inst *i, const AliasRep &thisMem) +void MemoryOpt::addDefToInstruction(Node *n, Inst *i, const AliasRep &thisMem) { InstMemBehavior *b = getOrCreateInstEffect(i); b->defs.insert(thisMem); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inserting def for "; thisMem.print(Log::out()); Log::out() << " at node "; - n->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), n); + Log::out() << std::endl; } // if there is already a definition of an ancestor of this one, then it @@ -555,14 +552,14 @@ void MemoryOpt::addDefToInstruction(CFGN for ( ; iter != endIter; ++iter) { AliasRep anc = *iter; if (aliasDefSites->hasAliasDefSite(anc, n)) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Not recording def for "; thisMem.print(Log::out()); Log::out() << " at node "; - n->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), n); Log::out() << " because ancestor "; anc.print(Log::out()); - Log::out() << " has def there" << ::std::endl; + Log::out() << " has def there" << std::endl; } return; } @@ -571,19 +568,19 @@ void MemoryOpt::addDefToInstruction(CFGN aliasDefSites->addAliasDefSite(thisMem, n); } -void MemoryOpt::addUseToInstruction(CFGNode *n, Inst *i, const AliasRep &thisMem) +void MemoryOpt::addUseToInstruction(Node *n, Inst *i, const AliasRep &thisMem) { InstMemBehavior *b = getOrCreateInstEffect(i); b->uses.insert(thisMem); } -void MemoryOpt::addReleaseToInstruction(CFGNode *n, Inst *i) +void MemoryOpt::addReleaseToInstruction(Node *n, Inst *i) { InstMemBehavior *b = getOrCreateInstEffect(i); b->release = true; } -void MemoryOpt::addAcquireToInstruction(CFGNode *n, Inst *i) +void MemoryOpt::addAcquireToInstruction(Node *n, Inst *i) { InstMemBehavior *b = getOrCreateInstEffect(i); b->acquire = true; @@ -626,11 +623,11 @@ MemoryOptInitWalker::applyToInst(Inst *i assert(calli->getNumSrcOperands() == 7); #ifndef NDEBUG Opnd *tauNullChecked = calli->getSrc(0); - assert(tauNullChecked->getType()->tag == Type::Tau); + assert(tauNullChecked->getType()->tag == Type::Tau); Opnd *tauTypesChecked = calli->getSrc(1); assert(tauTypesChecked->getType()->tag == Type::Tau); #endif - Opnd *srcarray = calli->getSrc(2); + Opnd *srcarray = calli->getSrc(2); Opnd *srcoffset = calli->getSrc(3); Opnd *dstarray = calli->getSrc(4); Opnd *dstoffset = calli->getSrc(5); @@ -669,6 +666,8 @@ #endif switch (callId) { case InitializeArray: case PseudoCanThrow: + case SaveThisState: + case ReadThisState: break; default: assert(0); @@ -678,7 +677,6 @@ #endif break; case Op_Return: case Op_Throw: - case Op_ThrowLazy: case Op_ThrowSystemException: case Op_ThrowLinkingException: case Op_Leave: @@ -931,7 +929,7 @@ #endif case Op_Shr: case Op_Cmp: case Op_Cmp3: case Op_Branch: case Op_Jump: case Op_Switch: case Op_LdConstant: - case Op_LdString: // just reads method string pool, no memory effect. + case Op_LdRef: // helper call to load a constant, no memory effect. case Op_Copy: case Op_StVar: @@ -984,9 +982,9 @@ #endif assert(0); break; } - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Inst "; i->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; InstMemBehavior *b = thePass->getInstEffect(i); if (b) { StlVectorSet<AliasRep>::iterator @@ -999,7 +997,7 @@ #endif rep.dump(Log::out()); Log::out() << " "; } - Log::out() << ::std::endl; + Log::out() << std::endl; } StlVectorSet<AliasRep>::iterator iter2 = b->uses.begin(), @@ -1011,7 +1009,7 @@ #endif rep.dump(Log::out()); Log::out() << " "; } - Log::out() << ::std::endl; + Log::out() << std::endl; } } } @@ -1190,12 +1188,12 @@ AliasManager::isDuplicate(const AliasRep void AliasManager::sawDuplicate(const AliasRep &ar, const AliasRep &canon) { - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Saw duplicate of "; - canon.print(Log::out()); - Log::out() << " : "; - ar.print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Saw duplicate of "; + canon.print(Log::out()); + Log::out() << " : "; + ar.print(Log::out()); + Log::out() << std::endl; } StlVectorSet<AliasRep> *theset = canon2others[canon]; if (!theset) { @@ -1273,8 +1271,8 @@ AliasRep AliasManager::getReference(Opnd case Op_AddScaledIndex: { Type *eltType = NULL; - Opnd *thePtr = addri->getSrc(0); - Type *theType = thePtr->getType(); + Opnd *thePtr = addri->getSrc(0); + Type *theType = thePtr->getType(); if (theType->isManagedPtr()) { PtrType *thePtrType = (PtrType *) theType; eltType = thePtrType->getPointedToType(); @@ -1518,7 +1516,7 @@ AliasRep AliasManager::getObjectField(Op void AliasManager::dumpAliasReps(::std::ostream &os) const { - os << "Alias Sets:" << ::std::endl; + os << "Alias Sets:" << std::endl; AliasList::const_iterator iter = allAliasReps.begin(), end = allAliasReps.end(); @@ -1544,9 +1542,9 @@ AliasManager::dumpAliasReps(::std::ostre } else { os << "--null--"; } - os << ::std::endl; + os << std::endl; } - os << "End of Alias Sets" << ::std::endl; + os << "End of Alias Sets" << std::endl; } // yields a list of ancestors in some order @@ -1585,10 +1583,10 @@ AliasManager::computeAncestors(const Ali case AliasRep::ObjectFieldKind: { FieldDesc *field = (FieldDesc *) a.desc; - if (a.opnd) { - result->push_back(getObjectField(0, field)); - } - if (field->isInitOnly()) { + if (a.opnd) { + result->push_back(getObjectField(0, field)); + } + if (field->isInitOnly()) { result->push_back(getFinishObject(a.opnd)); } else { if ((a.opnd == 0) || analyzer->mayEscape(a.opnd)) { @@ -1675,7 +1673,7 @@ void MemoryOpt::insertPhiFor(const Alias StlList<VarDefSites *> &ancestorDefSites) { StlList<VarDefSites *>::iterator ancEnd = ancestorDefSites.end(); - CFGNode* node; + Node* node; while ((node = defSites->removeDefSite()) != NULL) { bool done = false; // if an ancestor has a def there, skip it @@ -1684,36 +1682,36 @@ void MemoryOpt::insertPhiFor(const Alias VarDefSites *ancSites = *ancIter; if (ancSites->isDefSite(node)) { done = true; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Skipping node "; - node->printLabel(Log::out()); - Log::out() << " because ancestor has def there" << ::std::endl; + FlowGraph::printLabel(Log::out(), node); + Log::out() << " because ancestor has def there" << std::endl; } break; } } if (done) continue; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Consider def at node "; - node->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), node); + Log::out() << std::endl; } - List<CFGNode>* dflist = df.getFrontiersOf(node); + List<Node>* dflist = df.getFrontiersOf(node); for (; dflist != NULL; dflist = dflist->getNext()) { // block where phi inst is going to be inserted - CFGNode* insertedLoc = dflist->getElem(); + Node* insertedLoc = dflist->getElem(); // if phi has been inserted, then skip // no need to insert phi inst in the epilog because // there is no var use in the epilog if (!defSites->beenInsertedPhi(insertedLoc) && !insertedLoc->getOutEdges().empty()) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Queuing DF node "; - insertedLoc->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), insertedLoc); + Log::out() << std::endl; } // create a new phi instruction for varOpnd createMemPhiInst(theRep,insertedLoc); @@ -1734,10 +1732,10 @@ void MemoryOpt::insertMemPhi() { VarDefSites* defSites = (*iter).second; if (defSites) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "BEGIN Inserting Phis for "; aliasRep.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } const AliasManager::AliasList *alist = aliasManager->getAncestors(aliasRep); @@ -1755,31 +1753,31 @@ void MemoryOpt::insertMemPhi() { } insertPhiFor(aliasRep, defSites, ancestorDefSites); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "DONE Inserting Phis for "; aliasRep.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } else { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "NO Phis for "; aliasRep.print(Log::out()); - Log::out() << " because it has no defs" << ::std::endl; + Log::out() << " because it has no defs" << std::endl; } } } } -void MemoryOpt::createMemPhiInst(const AliasRep &aliasRep, CFGNode *node) +void MemoryOpt::createMemPhiInst(const AliasRep &aliasRep, Node *node) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Insert MemPhi for "; aliasRep.print(Log::out()); Log::out() << " at node "; - node->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), node); + Log::out() << std::endl; } - Inst *firstInst = node->getFirstInst(); + Inst *firstInst = (Inst*)node->getFirstInst(); assert(firstInst->isLabel()); InstMemBehavior *b = getOrCreateInstEffect(firstInst); @@ -1831,10 +1829,10 @@ void MemoryOpt::addMemUseDef(Inst *use, void MemoryOpt::remMemInst(Inst *theInst) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Eliminating redundant memory instruction: "; theInst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } // get defs used by theInst @@ -1895,21 +1893,21 @@ void MemoryOpt::remMemInst(Inst *theInst } } } - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Finished eliminating redundant memory instruction: "; theInst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } } void MemoryOpt::replaceMemInst(Inst *oldInst, Inst *newInst) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Replacing memory instruction "; oldInst->print(Log::out()); Log::out() << " by "; newInst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } // get defs used by theInst @@ -1972,7 +1970,7 @@ void MemoryOpt::replaceMemInst(Inst *old bool MemoryOpt::hasSameReachingDefs(Inst *i1, Inst *i2) { assert(i1 != i2); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "checking use2defs(" << (int)i1->getId() << ")==use2defs(" << (int)i2->getId() << "): "; } @@ -1989,8 +1987,8 @@ bool MemoryOpt::hasSameReachingDefs(Inst assert(defs1 && defs2); result = (*defs1 == *defs2); } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << (result ? " == > TRUE" : " == > FALSE") << ::std::endl; + if (Log::isEnabled()) { + Log::out() << (result ? " == > TRUE" : " == > FALSE") << std::endl; } return result; } @@ -2022,12 +2020,12 @@ MemoryRenameWalker::addDef(Inst *inst, c void MemoryRenameWalker::addUse(Inst *inst, const AliasRep &rep) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Adding Use of aliasRep "; rep.print(Log::out()); Log::out() << " to inst "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } AliasRenameMap::DefsSet defs(thePass->mm); @@ -2047,10 +2045,10 @@ MemoryRenameWalker::applyToInst(Inst *in { InstMemBehavior *b = thePass->getInstEffect(inst); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "applying renaming to Inst "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } if (b) { // compute uses here @@ -2070,10 +2068,10 @@ MemoryRenameWalker::applyToInst(Inst *in end = b->uses.end(); for ( ; iter != end; ++iter) { AliasRep rep = *iter; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " has use of "; rep.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } addUse(inst, rep); } @@ -2087,10 +2085,10 @@ MemoryRenameWalker::applyToInst(Inst *in end = b->defs.end(); for ( ; iter != end; ++iter) { AliasRep rep = *iter; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " has def of "; rep.print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } addDef(inst, rep); } @@ -2101,23 +2099,23 @@ MemoryRenameWalker::applyToInst(Inst *in void MemoryRenameWalker::finishNode(DominatorNode *domNode) { - CFGNode *node = domNode->getNode(); + Node *node = domNode->getNode(); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "finishing renaming for Node "; - node->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), node); + Log::out() << std::endl; } - const CFGEdgeDeque& edges = node->getOutEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& edges = node->getOutEdges(); + Edges::const_iterator eiter; for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { - CFGEdge* e = *eiter; - CFGNode* succ = e->getTargetNode(); + Edge* e = *eiter; + Node* succ = e->getTargetNode(); const StlVector<AliasRep> *memPhis = thePass->memPhiSites->getMemPhis(succ); if (memPhis) { - Inst *succLabel = succ->getFirstInst(); + Inst *succLabel = (Inst*)succ->getFirstInst(); assert(succLabel->isLabel()); StlVector<AliasRep>::const_iterator @@ -2131,10 +2129,10 @@ MemoryRenameWalker::finishNode(Dominator } } - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "finished renaming for Node "; - node->printLabel(Log::out()); - Log::out() << ::std::endl; + FlowGraph::printLabel(Log::out(), node); + Log::out() << std::endl; } } @@ -2145,15 +2143,15 @@ public: MemoryDebugWalker(MemoryOpt *thePass0) : thePass(thePass0) { }; - void startNode(CFGNode *node) { }; + void startNode(Node *node) { }; void applyToInst(Inst *inst); - void finishNode(CFGNode *node) {}; + void finishNode(Node *node) {}; }; void MemoryDebugWalker::applyToInst(Inst *inst) { inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; MemoryOpt::Use2DefsMap::iterator found = thePass->memUseDefs.find(inst), end = thePass->memUseDefs.end(); @@ -2169,7 +2167,7 @@ void MemoryDebugWalker::applyToInst(Inst thisDep->print(Log::out()); Log::out() << " "; } - Log::out() << ::std::endl; + Log::out() << std::endl; } } @@ -2186,7 +2184,7 @@ void MemoryOpt::createUsesMap() DomTreeWalk<true, MemoryRenameDomWalker>(dominators, domRenameWalker, mm); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { MemoryDebugWalker debugWalker(this); // adapt the forwards NodeInstWalker to a NodeWalker @@ -2218,11 +2216,11 @@ void AliasRenameMap::insert(const AliasR uint32 timeNow = ++timeCount; AliasBinding newBinding(defInst, timeNow); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " adding def of "; rep.print(Log::out()); Log::out() << " at time " << (int) timeNow << " to inst " - << (int) defInst->getId() << ::std::endl; + << (int) defInst->getId() << std::endl; } // first, set this value @@ -2270,16 +2268,16 @@ void AliasRenameMap::lookup(const AliasR { if (!bestInst) { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "aliasRep "; rep.print(Log::out()); - Log::out() << " has no binding" << ::std::endl; + Log::out() << " has no binding" << std::endl; } } else { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "aliasRep "; rep.print(Log::out()); - Log::out() << " has binding at time " << (int) bestWhen << ::std::endl; + Log::out() << " has binding at time " << (int) bestWhen << std::endl; } } @@ -2288,16 +2286,16 @@ void AliasRenameMap::lookup(const AliasR AliasManager::AliasList::const_iterator iter = alist->begin(), end = alist->end(); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { if (iter != end) { - Log::out() << "trying ancestors: " << ::std::endl; + Log::out() << "trying ancestors: " << std::endl; } else { - Log::out() << "has no ancestors" << ::std::endl; + Log::out() << "has no ancestors" << std::endl; } } for ( ; iter != end; ++iter) { AliasRep thisAncestor = *iter; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { thisAncestor.print(Log::out()); Log::out() << " "; } @@ -2305,31 +2303,31 @@ void AliasRenameMap::lookup(const AliasR Inst *thisInst = newFound.inst; if (thisInst) { uint32 thisWhen = newFound.when; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " "; thisAncestor.print(Log::out()); - Log::out() << " has binding at time " << (int) thisWhen << ::std::endl; + Log::out() << " has binding at time " << (int) thisWhen << std::endl; } if (newFound.when > bestWhen) { bestWhen = thisWhen; bestInst = thisInst; - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << ", replaces bestInst"; } } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << ::std::endl; + if (Log::isEnabled()) { + Log::out() << std::endl; } } else { - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " "; thisAncestor.print(Log::out()); - Log::out() << " has no binding " << ::std::endl; + Log::out() << " has no binding " << std::endl; } } } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << ::std::endl; + if (Log::isEnabled()) { + Log::out() << std::endl; } } assert(bestInst); @@ -2432,11 +2430,11 @@ MemoryRedStoreWalker::applyToInst(Inst * FieldDesc *instDesc = finst->getFieldDesc(); FieldDesc *usingDesc = fusing->getFieldDesc(); - usingDesc = instDesc; + usingDesc = instDesc; if ((usingBase == thisBase) && usingDesc && ( getBitWidth(usingInst->getType()) - >= getBitWidth(inst->getType()) )) { + >= getBitWidth(inst->getType()) )) { // eliminate inst; thePass->remMemInst(inst); inst->unlink(); @@ -2450,10 +2448,10 @@ MemoryRedStoreWalker::applyToInst(Inst * FieldDesc *instDesc = finst->getFieldDesc(); FieldDesc *usingDesc = fusing->getFieldDesc(); - usingDesc = instDesc; + usingDesc = instDesc; if (usingDesc && (getBitWidth(usingInst->getType()) - >= getBitWidth(inst->getType()))) { + >= getBitWidth(inst->getType()))) { // eliminate inst; thePass->remMemInst(inst); inst->unlink(); @@ -2497,8 +2495,8 @@ void MemoryOpt::eliminateRedStores() // do the walk over nodes in arbitrary order NodeWalk<MemoryRedStoreNodeWalker>(fg, redStoreNodeWalker); - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "After red store elimination: " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "After red store elimination: " << std::endl; MemoryDebugWalker debugWalker(this); @@ -2542,10 +2540,10 @@ MemorySyncOptWalker::applyToInst(Inst *i newlyInvolved.insert(inst); Opnd *obj = inst->getSrc(0); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking instruction "; inst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } Opnd *enterLockAddrOpnd = 0; @@ -2560,10 +2558,10 @@ MemorySyncOptWalker::applyToInst(Inst *i // don't have it, insert it involved.insert(monitorInst); - if (Log::cat_opt_mem()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Is involved with instruction "; monitorInst->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } if (monitorInst->isLabel()) { // acting as memory phi, match both ways @@ -2718,8 +2716,8 @@ MemorySyncOptWalker::applyToInst(Inst *i // turn them into fences - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Can convert to fence: " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "Can convert to fence: " << std::endl; } InstFactory &instFactory = thePass->irManager.getInstFactory(); @@ -2753,12 +2751,12 @@ MemorySyncOptWalker::applyToInst(Inst *i default: assert(0); } - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "Instruction " << ::std::endl << " "; + if (Log::isEnabled()) { + Log::out() << "Instruction " << std::endl << " "; invInst->print(Log::out()); - Log::out() << ::std::endl << " becomes " << ::std::endl << " "; + Log::out() << std::endl << " becomes " << std::endl << " "; newI->print(Log::out()); - Log::out() << ::std::endl; + Log::out() << std::endl; } newI->insertAfter(invInst); invInst->unlink(); @@ -2778,8 +2776,8 @@ void MemoryOpt::doSyncOpt() // do the walk over nodes in arbitrary order NodeWalk<MemorySyncOptNodeWalker>(fg, memSyncOptNodeWalker); - if (Log::cat_opt_mem()->isDebugEnabled()) { - Log::out() << "After mem syncopt: " << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "After mem syncopt: " << std::endl; MemoryDebugWalker debugWalker(this); diff --git vm/jitrino/src/optimizer/memoryopt.h vm/jitrino/src/optimizer/memoryopt.h index a809b3b..3f84d6e 100644 --- vm/jitrino/src/optimizer/memoryopt.h +++ vm/jitrino/src/optimizer/memoryopt.h @@ -26,10 +26,8 @@ #define _MEMORY_OPT_H #include <iostream> #include "open/types.h" #include "Opcode.h" -#include "FlowGraph.h" #include "Stl.h" #include <utility> -#include "optpass.h" namespace Jitrino { @@ -39,8 +37,7 @@ class InequalityGraph; class DominatorNode; class Dominator; class DomFrontier; -class JitrinoParameterTable; -class CFGNode; +class Node; class Opnd; class CSEHashTable; class Type; @@ -54,12 +51,11 @@ class VarDefSites; class MemPhiSites; class AliasRenameMap; class MemUseMap; - -DEFINE_OPTPASS(MemoryValueNumberingPass) +struct MemoptFlags; class MemoryOpt { IRManager& irManager; - FlowGraph& fg; + ControlFlowGraph& fg; MemoryManager &mm; DominatorTree& dominators; DomFrontier &df; @@ -103,20 +99,12 @@ public: // unsynchronized operations Synch_Default }; - struct Flags { - enum Model model; - enum Synch synch; - bool debug; - bool verbose; - bool redstore; - bool syncopt; - }; + private: - static Flags *defaultFlags; - Flags flags; + MemoptFlags& flags; public: - static void readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params); - static void showFlagsFromCommandLine(); + static void readFlags(Action* argSource, MemoptFlags* flags); + static void showFlags(std::ostream& os); MemoryOpt(IRManager &irManager0, MemoryManager& memManager, @@ -143,7 +131,7 @@ private: void insertMemPhi(); void createUsesMap(); - void createMemPhiInst(const AliasRep &, CFGNode *n); + void createMemPhiInst(const AliasRep &, Node *n); void insertPhiFor(const AliasRep &theRep, VarDefSites* defSites, StlList<VarDefSites *> &ancestorSites); @@ -154,60 +142,60 @@ private: friend class MemorySyncOptWalker; // methods to note memory effects of an instruction - void effectAnyGlobal(CFGNode *n, Inst *i); // R/W anything that escapes or is global - void effectWriteVtable(CFGNode *n, Inst *i, Opnd *opnd); - void effectReadVtable(CFGNode *n, Inst *i, Opnd *opnd); - void effectReadMethodPtr(CFGNode *n, Inst *i, Opnd *obj, MethodDesc *desc); - void effectReadMethodPtr(CFGNode *n, Inst *i, MethodDesc *desc); - void effectReadFunPtr(CFGNode *n, Inst *i, Opnd *funptr); - - void effectInit(CFGNode *n, Inst *i); // initial state, everything defined - void effectExit(CFGNode *n, Inst *i); - void effectEntry(CFGNode *n, Inst *i); // just globals overwritten - void effectRead(CFGNode *n, Inst *i, Opnd *addr); - void effectWrite(CFGNode *n, Inst *i, Opnd *addr); - - void effectReadClassVtable(CFGNode *n, Inst *i, NamedType *t); - void effectWriteArrayLength(CFGNode *n, Inst *i, Opnd *opnd); - void effectReadArrayLength(CFGNode *n, Inst *i, Opnd *opnd); - void effectReadArrayElements(CFGNode *n, Inst *i, Opnd *arrayop, + void effectAnyGlobal(Node *n, Inst *i); // R/W anything that escapes or is global + void effectWriteVtable(Node *n, Inst *i, Opnd *opnd); + void effectReadVtable(Node *n, Inst *i, Opnd *opnd); + void effectReadMethodPtr(Node *n, Inst *i, Opnd *obj, MethodDesc *desc); + void effectReadMethodPtr(Node *n, Inst *i, MethodDesc *desc); + void effectReadFunPtr(Node *n, Inst *i, Opnd *funptr); + + void effectInit(Node *n, Inst *i); // initial state, everything defined + void effectExit(Node *n, Inst *i); + void effectEntry(Node *n, Inst *i); // just globals overwritten + void effectRead(Node *n, Inst *i, Opnd *addr); + void effectWrite(Node *n, Inst *i, Opnd *addr); + + void effectReadClassVtable(Node *n, Inst *i, NamedType *t); + void effectWriteArrayLength(Node *n, Inst *i, Opnd *opnd); + void effectReadArrayLength(Node *n, Inst *i, Opnd *opnd); + void effectReadArrayElements(Node *n, Inst *i, Opnd *arrayop, Opnd *offsetop, Opnd *length); - void effectWriteArrayElements(CFGNode *n, Inst *i, Opnd *arrayop, + void effectWriteArrayElements(Node *n, Inst *i, Opnd *arrayop, Opnd *offsetop, Opnd *length); // creates an object/array, returned in opnd: // writes array length, etc. - void effectNew(CFGNode *n, Inst *i, Opnd *dstop); + void effectNew(Node *n, Inst *i, Opnd *dstop); // make sure object's vtable are visible to others before publishing this - void effectReleaseObject(CFGNode *n, Inst *i, Opnd *obj); + void effectReleaseObject(Node *n, Inst *i, Opnd *obj); // make sure object's vtable is available to all - void effectInitType(CFGNode *n, Inst *i, NamedType *type); + void effectInitType(Node *n, Inst *i, NamedType *type); // mark end of initializer when finalizers should stay constant: - void effectFinishObject(CFGNode *n, Inst *i, Opnd *obj); - void effectFinishType(CFGNode *n, Inst *i, NamedType *type); + void effectFinishObject(Node *n, Inst *i, Opnd *obj); + void effectFinishType(Node *n, Inst *i, NamedType *type); // can commute with any ops, but not be added/removed: - void effectIncCounter(CFGNode *n, Inst *i); + void effectIncCounter(Node *n, Inst *i); // object may be 0 if lock has been removed - void effectMonitorEnter(CFGNode *n, Inst *i, Opnd *object); - void effectMonitorExit(CFGNode *n, Inst *i, Opnd *object); + void effectMonitorEnter(Node *n, Inst *i, Opnd *object); + void effectMonitorExit(Node *n, Inst *i, Opnd *object); // just increments the lock on object, no acq/rel - void effectIncRecCount(CFGNode *n, Inst *i, Opnd *object); + void effectIncRecCount(Node *n, Inst *i, Opnd *object); // lock type methods - void effectTypeMonitorEnter(CFGNode *n, Inst *i, Type *type); - void effectTypeMonitorExit(CFGNode *n, Inst *i, Type *type); + void effectTypeMonitorEnter(Node *n, Inst *i, Type *type); + void effectTypeMonitorExit(Node *n, Inst *i, Type *type); private: // implementation - void addDefToInstruction(CFGNode *n, Inst *i, const AliasRep &thisMem); - void addUseToInstruction(CFGNode *n, Inst *i, const AliasRep &thisMem); - void addReleaseToInstruction(CFGNode *n, Inst *i); - void addAcquireToInstruction(CFGNode *n, Inst *i); + void addDefToInstruction(Node *n, Inst *i, const AliasRep &thisMem); + void addUseToInstruction(Node *n, Inst *i, const AliasRep &thisMem); + void addReleaseToInstruction(Node *n, Inst *i); + void addAcquireToInstruction(Node *n, Inst *i); void addMemUseDef(Inst *use, Inst *def); void addMemUseDefs(Inst *use, DefsSet &defs); @@ -216,6 +204,15 @@ public: void replaceMemInst(Inst *oldI, Inst *newI); // substitute dep info }; +struct MemoptFlags { + enum MemoryOpt::Model model; + enum MemoryOpt::Synch synch; + bool debug; + bool verbose; + bool redstore; + bool syncopt; + bool do_redstore; +}; } //namespace Jitrino #endif // _MEMORY_OPT_H diff --git vm/jitrino/src/optimizer/memoryoptrep.h vm/jitrino/src/optimizer/memoryoptrep.h index 2b65c3e..2069c81 100644 --- vm/jitrino/src/optimizer/memoryoptrep.h +++ vm/jitrino/src/optimizer/memoryoptrep.h @@ -197,7 +197,7 @@ class AliasDefSites : public StlHashMap< public: typedef StlHashMap<AliasRep, VarDefSites *> BaseType; AliasDefSites(MemoryManager &m, uint32 n): BaseType(m), mm(m), numNodes(n) {}; - void addAliasDefSite(const AliasRep &rep, CFGNode* node) { + void addAliasDefSite(const AliasRep &rep, Node* node) { VarDefSites* aliasSites = (*this)[rep]; if (!aliasSites) { aliasSites = new (mm) VarDefSites(mm, numNodes); @@ -205,7 +205,7 @@ public: } aliasSites->addDefSite(node); }; - bool hasAliasDefSite(const AliasRep &rep, CFGNode* node) { + bool hasAliasDefSite(const AliasRep &rep, Node* node) { iterator aliasSitesIter = this->find(rep); if (aliasSitesIter == end()) { return false; @@ -226,7 +226,7 @@ public: nodeArray[i] = 0; } } - void addMemPhi(CFGNode *n, const AliasRep &rep) { + void addMemPhi(Node *n, const AliasRep &rep) { size_t i = n->getDfNum(); StlVector<AliasRep> *a = nodeArray[i]; if (!a) { @@ -235,7 +235,7 @@ public: } a->push_back(rep); } - const StlVector<AliasRep> *getMemPhis(CFGNode *n) const { + const StlVector<AliasRep> *getMemPhis(Node *n) const { size_t i = n->getDfNum(); return nodeArray[i]; } diff --git vm/jitrino/src/optimizer/multiplybyconstant.cpp vm/jitrino/src/optimizer/multiplybyconstant.cpp index 9b947be..1e89ae4 100644 --- vm/jitrino/src/optimizer/multiplybyconstant.cpp +++ vm/jitrino/src/optimizer/multiplybyconstant.cpp @@ -41,7 +41,6 @@ #include "Type.h" #include "Inst.h" #include "IRBuilder.h" #include "BitSet.h" -#include "FlowGraph.h" #include "Log.h" #include "optimizer.h" #include "simplifier.h" @@ -219,7 +218,7 @@ public: if (sp != 1) { ::std::cerr << ::std::endl; ::std::cerr << "sp != 1 after applying: "; - printOps(::std::cerr); ::std::cerr << ::std::endl; + printOps(::std::cerr); ::std::cerr << ::std::endl; assert(0); } if (latency) { *latency = when[0]; } @@ -335,7 +334,7 @@ public: if (sp != 1) { ::std::cerr << ::std::endl; ::std::cerr << "sp != 1 after applying: "; - printOps(::std::cerr); ::std::cerr << ::std::endl; + printOps(::std::cerr); ::std::cerr << ::std::endl; assert(0); } @@ -808,7 +807,7 @@ void planMulCompound(MulMethod &m, intty int rightzeros = ((d & 1)!=0) ? 0 : deltaright+1; #ifndef NDEBUG - int leftzeros = ((d & ((inttype)1<<(width-1))) != 0) ? 0 : deltaleft; + int leftzeros = ((d & ((inttype)1<<(width-1))) != 0) ? 0 : deltaleft; #endif assert((rightzeros == ntz<inttype, width>(d))); assert((leftzeros == nlz<inttype, width>(d))); @@ -1017,10 +1016,10 @@ #else // !STANDALONE_TEST Opnd * Simplifier::planMul32(int32 multiplier, Opnd *opnd) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); MulMethod method(!optimizerFlags.ia32_code_gen); planMul<int32, 32>(method, multiplier, 1); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "in multiply(" << (int) multiplier << ", "; opnd->print(Log::out()); Log::out() << "), method is "; @@ -1032,10 +1031,10 @@ Simplifier::planMul32(int32 multiplier, Opnd * Simplifier::planMul64(int64 multiplier, Opnd *opnd) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); MulMethod method(!optimizerFlags.ia32_code_gen); planMul<int64, 64>(method, multiplier, 1); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "in multiply(" << (int) multiplier << ", "; opnd->print(Log::out()); Log::out() << "), method is "; diff --git vm/jitrino/src/optimizer/optarithmetic.h vm/jitrino/src/optimizer/optarithmetic.h index f5f12a2..d5b0bfb 100644 --- vm/jitrino/src/optimizer/optarithmetic.h +++ vm/jitrino/src/optimizer/optarithmetic.h @@ -110,10 +110,10 @@ getMagic(inttype d, inttype *magicNum, i uinttype anc = t - 1 - (t%ad); // anc = |nc| // initial value, we try values from [width-1, 2*width] - uinttype p = width-1; // power of 2 to divide by + uinttype p = width-1; // power of 2 to divide by // these are maintained incrementally in loop as p is changed - uinttype q1 = hiBitSet / anc; // q1 = 2**p/|nc| + uinttype q1 = hiBitSet / anc; // q1 = 2**p/|nc| uinttype r1 = hiBitSet - q1*anc; // r1 = rem(2**p, |nc|) uinttype q2 = hiBitSet / ad; // q2 = 2**p /|d| uinttype r2 = hiBitSet - q2*ad; // r2 = rem(2**p, |d|) diff --git vm/jitrino/src/optimizer/optimizer.cpp vm/jitrino/src/optimizer/optimizer.cpp index a450abd..1e97380 100644 --- vm/jitrino/src/optimizer/optimizer.cpp +++ vm/jitrino/src/optimizer/optimizer.cpp @@ -26,7 +26,6 @@ #include <iostream> #include "open/types.h" #include "optimizer.h" #include "Inst.h" -#include "FlowGraph.h" #include "irmanager.h" #include "Dominator.h" #include "Loop.h" @@ -36,19 +35,17 @@ #include "ssa/SSA.h" #include "Log.h" #include "deadcodeeliminator.h" #include "hashvaluenumberer.h" -#include "escapeanalyzer.h" +//#include "escapeanalyzer.h" +#include "escanalyzer.h" #include "globalopndanalyzer.h" #include "simplifier.h" #include "inliner.h" #include "devirtualizer.h" -#include "PropertyTable.h" #include "abcd/abcd.h" #include "Jitrino.h" -#include "Profiler.h" #include "codelowerer.h" -#include "Timer.h" #include "globalcodemotion.h" #include "tailduplicator.h" #include "gcmanagedpointeranalyzer.h" @@ -61,1253 +58,156 @@ #include "pidgenerator.h" #include "StaticProfiler.h" #include "lazyexceptionopt.h" #include "CompilationContext.h" +#include "EdgeProfiler.h" +#include "PMFAction.h" namespace Jitrino { -static const char* client_static_path = "ssa,devirt,inline,purge,simplify,uce,dce,dessa,lazyexc,ssa,memopt,simplify,uce,dce,lower,dessa,statprof"; -static const char* client_inline_path = "ssa,devirt"; - -void readOptimizerFlagsFromCommandLine(CompilationContext* compilationContext) -{ - JitrinoParameterTable* params = compilationContext->getThisParameterTable(); - OptimizerFlags& optimizerFlags = *compilationContext->getOptimizerFlags(); - memset( &optimizerFlags, 0, sizeof optimizerFlags ); - optimizerFlags.noopt_path = params->lookup("opt::noopt_path"); - - optimizerFlags.skip = params->lookupBool("opt::skip", true); - optimizerFlags.static_path = params->lookup("opt::static_path"); - optimizerFlags.inline_path = params->lookup("opt::inline_path"); - // - // see TranslatorIntfc.cpp for additional info about the "client" option - // - if ( params->lookupBool("client", false) ) { - optimizerFlags.skip = false; - optimizerFlags.static_path = client_static_path; - optimizerFlags.inline_path = client_inline_path; - } - optimizerFlags.dpgo1_path = params->lookup("opt::dpgo1_path"); - optimizerFlags.dpgo2_path = params->lookup("opt::dpgo2_path"); - - optimizerFlags.meta_optimize = params->lookupBool("opt::meta_optimize", true); - optimizerFlags.dump_paths = params->lookup("opt::dump_paths"); - - optimizerFlags.skip_phase1 = params->lookupBool("opt::skip_phase1", false); - optimizerFlags.fast_phase1 = optimizerFlags.skip_phase1 || params->lookupBool("opt::fast_phase1", false); - optimizerFlags.dumpdot = params->lookupBool("opt::dumpdot", false); - - optimizerFlags.do_ssa = params->lookupBool("opt::do_ssa", false); - optimizerFlags.build_loops= params->lookupBool("opt::build_loops", true); - optimizerFlags.globals_span_loops = params->lookupBool("opt::globals_span_loops", true); - optimizerFlags.do_abcd = params->lookupBool("opt::do_abcd", true); - optimizerFlags.do_inline = params->lookupBool("opt::do_inline", true); - optimizerFlags.inline_n = params->lookupUint("opt::inline_n", 0); - - optimizerFlags.do_guarded_devirtualization = params->lookupBool("opt::do_guarded_devirtualization", true); - optimizerFlags.do_unguard = params->lookupBool("opt::do_unguard", true); - optimizerFlags.do_peeling = params->lookupBool("opt::do_peeling", true); - optimizerFlags.elim_cmp3 = params->lookupBool("opt::elim_cmp3", true); - optimizerFlags.elim_checks = params->lookupBool("opt::elim_checks", true); - optimizerFlags.do_lower = params->lookupBool("opt::do_lower", true); - optimizerFlags.use_profile = params->lookupBool("opt::use_profile", false); - optimizerFlags.do_latesimplify = params->lookupBool("opt::do_latesimplify", true); - optimizerFlags.use_mulhi = params->lookupBool("opt::use_mulhi", false); - optimizerFlags.lower_divconst = params->lookupBool("opt::lower_divconst", true); - optimizerFlags.do_gcm = params->lookupBool("opt::do_gcm", false); - optimizerFlags.do_gvn = params->lookupBool("opt::do_gvn", false); - optimizerFlags.do_tail_duplication = params->lookupBool("opt::do_tail_duplication", true); - optimizerFlags.do_profile_tail_duplication = params->lookupBool("opt::do_profile_tail_duplication", true); - optimizerFlags.do_early_profile_tail_duplication = params->lookupBool("opt::do_early_profile_tail_duplication", false); - optimizerFlags.profile_unguarding_level = params->lookupUint("opt::profile_unguarding_level", 0); - optimizerFlags.do_profile_redundancy_elimination = params->lookupBool("opt::do_profile_redundancy_elimination", true); - optimizerFlags.do_prefetching = params->lookupBool("opt::do_prefetching", true); - optimizerFlags.do_memopt = params->lookupBool("opt::do_memopt", true); - optimizerFlags.profile_threshold = params->lookupUint("opt::profile_threshold", 5000); - optimizerFlags.use_average_threshold = params->lookupBool("opt::use_average_threshold", false); - optimizerFlags.use_minimum_threshold = params->lookupBool("opt::use_minimum_threshold", false); - optimizerFlags.use_fixed_threshold = params->lookupBool("opt::use_fixed_threshold", false); - optimizerFlags.prune_untaken_edges = params->lookupBool("opt::prune_untaken_edges", false); - optimizerFlags.do_lazyexc = params->lookupBool("opt::do_lazyexc", true); - - optimizerFlags.ia32_code_gen = Jitrino::flags.codegen != Jitrino::CG_IPF; - - optimizerFlags.cse_final = params->lookupBool("opt::cse_final", true); - optimizerFlags.no_simplify = params->lookupBool("opt::no_simplify", false); - optimizerFlags.no_hvn = params->lookupBool("opt::no_hvn", false); - optimizerFlags.brm_debug = params->lookupBool("opt::brm_debug", false); - optimizerFlags.fixup_ssa = params->lookupBool("opt::fixup_ssa", true); - optimizerFlags.number_dots = params->lookupBool("opt::number_dots", false); - optimizerFlags.do_sxt = params->lookupBool("opt::do_sxt", true); - optimizerFlags.do_reassoc = params->lookupBool("opt::do_reassoc", true); - optimizerFlags.do_reassoc_depth = params->lookupBool("opt::do_reassoc_depth", true); - optimizerFlags.do_reassoc_depth2 = params->lookupBool("opt::do_reassoc_depth2", true); - optimizerFlags.do_prof_red2 = params->lookupBool("opt::do_prof_red2", false); - optimizerFlags.dce2 = params->lookupBool("opt::dce2", true); - optimizerFlags.do_redstore = params->lookupBool("opt::do_redstore", true); - optimizerFlags.do_syncopt = params->lookupBool("opt::do_syncopt", true); - optimizerFlags.keep_empty_nodes_after_syncopt = params->lookupBool("opt::keep_empty_nodes_after_syncopt", false); - optimizerFlags.do_syncopt2 = params->lookupBool("opt::do_syncopt2", true); - optimizerFlags.do_prof_red2_latesimplify = params->lookupBool("opt::do_prof_red2_latesimplify", false); - optimizerFlags.gc_build_var_map = params->lookupBool("opt::gc::build_var_map", true); - optimizerFlags.reduce_compref = params->lookupBool("opt::reduce_compref", false); - optimizerFlags.split_ssa = params->lookupBool("opt::split_ssa", true); - optimizerFlags.better_ssa_fixup - = params->lookupBool("opt::better_ssa_fixup", false); - optimizerFlags.count_ssa_fixup - = params->lookupBool("opt::count_ssa_fixup", false); - optimizerFlags.hvn_exceptions - = params->lookupBool("opt::hvn_exceptions", true); - optimizerFlags.hash_init_factor - = params->lookupUint("opt::hash_init_factor", 1); - optimizerFlags.hash_resize_factor - = params->lookupUint("opt::hash_resize_factor", 2); - optimizerFlags.hash_resize_to - = params->lookupUint("opt::hash_resize_to", 3); - optimizerFlags.hash_node_var_factor - = params->lookupUint("opt::hash_node_var_factor", 1); - optimizerFlags.hash_node_tmp_factor - = params->lookupUint("opt::hash_node_tmp_factor", 2); - optimizerFlags.hash_node_constant_factor - = params->lookupUint("opt::hash_node_constant_factor", 1); - optimizerFlags.sink_constants - = params->lookupBool("opt::sink_constants", true); - optimizerFlags.sink_constants1 - = params->lookupBool("opt::sink_constants1", false); - optimizerFlags.gvn_exceptions - = params->lookupBool("opt::gvn_exceptions", false); - optimizerFlags.gvn_aggressive - = params->lookupBool("opt::gvn_aggressive", false); - optimizerFlags.do_reassoc_compref - = params->lookupBool("opt::do_reassoc_compref", false); - optimizerFlags.hvn_constants - = params->lookupBool("opt::hvn_constants", true); - optimizerFlags.simplify_taus - = params->lookupBool("opt::simplify_taus", true); - optimizerFlags.early_memopt - = params->lookupBool("opt::early_memopt", true); - optimizerFlags.early_memopt_prof - = params->lookupBool("opt::early_memopt::prof", false); - optimizerFlags.no_peel_inlined - = params->lookupBool("opt::no_peel_inlined", false); - optimizerFlags.hvn_inlined - = params->lookupBool("opt::hvn_inlined", false); - optimizerFlags.memopt_inlined - = params->lookupBool("opt::memopt_inlined", false); - - optimizerFlags.type_check - = params->lookupBool("opt::type_check", false); - - optimizerFlags.use_pattern_table2 - = params->lookupBool("opt::use_pattern_table2", false); - optimizerFlags.use_fixup_vars - = params->lookupBool("opt::use_fixup_vars", false); - - optimizerFlags.pass_profile_to_cg - = params->lookupBool("opt::pass_profile_to_cg", true); - - Abcd::readDefaultFlagsFromCommandLine(params); - GlobalCodeMotion::readDefaultFlagsFromCommandLine(params); - MemoryOpt::readDefaultFlagsFromCommandLine(params); - Reassociate::readDefaultFlagsFromCommandLine(params); - SyncOpt::readDefaultFlagsFromCommandLine(params); -} - -void showOptimizerFlagsFromCommandLine() -{ - Log::out() << " opt::skip[={on|OFF}] = skip all optimization" << ::std::endl; - Log::out() << " opt::dumpdot[={on|OFF}] = dump dotfiles for loops, dominators, etc" << ::std::endl; - Log::out() << " opt::do_ssa[={on|OFF}] = do extra SSA optimizations" << ::std::endl; - Log::out() << " opt::globals_span_loops[={ON|off}] = ?" << ::std::endl; - Log::out() << " opt::do_abcd[={on|OFF}] = run ABCD pass" << ::std::endl; - Log::out() << " opt::do_inline[={ON|off}] = do IR level inlining" << ::std::endl; - Log::out() << " opt::do_guarded_devirtualization[={ON|off}] = convert some virtual calls into guarded direct calls" << ::std::endl; - Log::out() << " opt::do_peeling[={ON|off}] = do loop peeling / inversion" << ::std::endl; - Log::out() << " opt::elim_cmp3[={ON|off}] = eliminate cmp3 tests" << ::std::endl; - Log::out() << " opt::elim_checks[={ON|off}] = try to eliminate some checks using branch conditions" << ::std::endl; - Log::out() << " opt::do_lower[={ON|off}] = lower type checks" << ::std::endl; - Log::out() << " opt::do_lazyexc[={ON|off}] = do lazy exception throwing optimization" << ::std::endl; - Log::out() << " opt::use_profile[={on|OFF}] = use profile information to guide optimizations" << ::std::endl; - Log::out() << " opt::do_latesimplify[={ON|off}] = do late simplification pass to lower mulconst" << ::std::endl; - Log::out() << " opt::use_mulhi{ON|off}] = use MulHi opcode" << ::std::endl; - Log::out() << " opt::lower_divconst[={ON|off}] = lower div by constant to mul" << ::std::endl; - Log::out() << " opt::do_gcm[={on|OFF}] = run global code motion" << ::std::endl; - Log::out() << " opt::do_gvn[={on|OFF}] = run global value numbering" << ::std::endl; - Log::out() << " opt::do_tail_duplication[={ON|off}] = do tail duplication" << ::std::endl; - Log::out() << " opt::do_profile_tail_duplication[={ON|off}] = do profile guided tail duplication" << ::std::endl; - Log::out() << " opt::profile_unguarding_level[={0,1,2}] = do profile guided unguarding?" << ::std::endl; - Log::out() << " opt::do_profile_redundancy_elimination[={ON|off}] = do profile guided redundancy elimination" << ::std::endl; - Log::out() << " opt::do_prefetching[={on|OFF}] = do prefetching pass" << ::std::endl; - Log::out() << " opt::cse_final[={ON|off}] = do cse of final fields " << ::std::endl; - Log::out() << " opt::no_simplify[={on|OFF}] = suppress simplify " << ::std::endl; - Log::out() << " opt::no_hvn[={on|OFF}] = suppress hashvaluenumbering " << ::std::endl; - Log::out() << " opt::do_memopt[={ON|off}] = do memory optimization pass" << ::std::endl; - Log::out() << " opt::fixup_ssa[={on|OFF}] = fixup SSA form after code deletion" << ::std::endl; - Log::out() << " opt::number_dots[={on|OFF}] = use a counter in dot file names to show order" << ::std::endl; - Log::out() << " opt::do_sxt[={ON|off}] = do some sign extension elimination" << ::std::endl; - Log::out() << " opt::do_reassoc[={ON|off}] = do reassociation before code motion" << ::std::endl; - Log::out() << " opt::do_reassoc_depth[={ON|off}] = do depth-reducing reassociation before cgen" << ::std::endl; - Log::out() << " opt::do_reassoc_depth2[={ON|off}] = do depth-reducing reassoc before cgen in DPGO" << ::std::endl; - Log::out() << " opt::do_reassoc_compref[={on|OFF}] = reassoc reduced compref exprs" << ::std::endl; - Log::out() << " opt::do_prof_red2[={on|OFF}] = do redundancy elimination twice for dynopt"; - Log::out() << " opt::do_prof_red2_latesimplify[={on|OFF}] = lower mults in dynopt pass 1"; - Log::out() << " opt::dce2[={ON|off}] = use new version of DCE pass"; - Log::out() << " opt::do_redstore[={ON|off}] = do redstore elim as a separate pass"; - Log::out() << " opt::do_syncopt[={ON|off}] = do monitorenter/exit opts"; - Log::out() << " opt::do_syncopt2[={ON|off}] = do extra monitorenter/exit opts in PGO pass"; - Log::out() << " opt::gc::build_var_map[={ON|off}] = opt builds gc map for vars"; - Log::out() << " opt::reduce_compref[={on|OFF}] = simplify reference un/compression"; - Log::out() << " opt::split_ssa[={ON|off}] = rename nonoverlapping SSA var versions"; - Log::out() << " opt::better_ssa_fixup[={on|OFF}] = defer ssa fixup until graph change"; - Log::out() << " opt::count_ssa_fixup[={on|OFF}] = count invocations of SSA fixup"; - Log::out() << " opt::hvn_exceptions[={ON|off}] = do value-numbering on exception paths" << ::std::endl; - Log::out() << " opt::hvn_constants[={ON|off}] = value-number constants from equality tests" << ::std::endl; - Log::out() << " opt::sink_constants[={ON|off}] = eliminate globals whose values are constant" << ::std::endl; - Log::out() << " opt::sink_constants1[={on|OFF}] = make sink_constants more aggressive" << ::std::endl; - Log::out() << " opt::gvn_exceptions[={on|OFF}] = apply gvn in exception code" << ::std::endl; - Log::out() << " opt::gvn_aggressive[={on|OFF}] = do more aggressive global value numbering" << ::std::endl; - Log::out() << " opt::simplify_taus[={ON|off}] = simplify tau expressions in optimizer" << ::std::endl; - - Log::out() << " opt::early_memopt[={ON|off}] = do some early memory optimizations" << ::std::endl; - Log::out() << " opt::early_memopt::prof[={on|OFF}] = do early memory opts with opt::use_profile" << ::std::endl; - Log::out() << " opt::no_peel_inlined[={on|OFF}] = do not peel a method while inlining it" << ::std::endl; - Log::out() << " opt::hvn_inlined[={on|OFF}] = do some value numbering while inlining" << ::std::endl; - Log::out() << " opt::memopt_inlined[={on|OFF}] = do some memory opts while inlining" << ::std::endl; - - Log::out() << " opt::type_check[={on|OFF}] = type check intermediate results" << ::std::endl; - - Log::out() << " opt::use_pattern_table2[={on|OFF}] = use alternate pattern table" << ::std::endl; - Log::out() << " opt::use_fixup_vars[={on|OFF}] = use pass,fixupVars instead of dessa,pass,fixupvars" << ::std::endl; - Log::out() << " opt::pass_profile_to_cg[={ON|off}] = pass profile information to the code generator" << ::std::endl; - - Abcd::showFlagsFromCommandLine(); - GlobalCodeMotion::showFlagsFromCommandLine(); - MemoryOpt::showFlagsFromCommandLine(); - Reassociate::showFlagsFromCommandLine(); -} - - - -// -// Base optimizer consists of optimizations that do not require -// a self-contained flow graph. In the case of inlining, we have flow graphs -// that refer to operands defined in the calling method's flowgraph. -// These optimizations can operate on inlined regions that -// refer to operands/instructions outside the region. -// -class BaseOptimizer { +class OptInitAction : public Action { public: - BaseOptimizer(MemoryManager& memoryManager, IRManager& irManager0, bool suppressLog) : - memoryManager(memoryManager), - irManager(irManager0), - flowGraph(irManager0.getFlowGraph()), - methodDesc(irManager0.getMethodDesc()), - instFactory(irManager0.getInstFactory()), - opndManager(irManager0.getOpndManager()), - typeManager(irManager0.getTypeManager()), - suppressLog(suppressLog), - optimizerFlags(*irManager0.getCompilationContext()->getOptimizerFlags()) - { - stageId=Log::getNextStageId(); - initMap(); - } - - // Dominators and loops - void computeDominatorsAndLoops(); - - // Printing utilities - void printInstructions(bool condition, char* passName) { - if(condition) { - Log::out() << "Printing HIR " << passName << ::std::endl; - OptPass::printHIR(irManager); - } - } - - void info2(const char* message) { - if(!suppressLog) - Log::cat_opt()->info2 << message << ::std::endl; - } - - void run(const ::std::string& passName); - void runPasses(const ::std::string& passName); - - void addPasses(const ::std::string& passName); - void runCurrentPasses(const char* label); - - void metaOptimize(::std::string& passes); - void metaOptimize(); - void findAndReplace(::std::string& str, const ::std::string& find, const ::std::string& replace); - void trim(::std::string& path) { if(!path.empty() && path[0] == ',') path = path.substr(1); } - - ::std::string& getCurrentPasses(); - void clearCurrentPasses(); - - const char* indent() { return OptPass::indent(irManager); } - - uint32 getStageId(){ return stageId; } -protected: - static void initMap(); - static void registerPass(OptPass* pass); - - - MemoryManager& memoryManager; - IRManager& irManager; - FlowGraph& flowGraph; - MethodDesc& methodDesc; - InstFactory& instFactory; - OpndManager& opndManager; - TypeManager& typeManager; - - bool suppressLog; - std::string passList; - OptimizerFlags optimizerFlags; - - typedef ::std::string StdString; - typedef StlHashMap<StdString, OptPass*> OptMap; - static MemoryManager mapmm; - static OptMap optMap; - - struct PatternMapping { - const char* pattern; - const char* replacement; - }; - - uint32 stageId; - - static PatternMapping patternTable[]; - static PatternMapping patternTable2[]; + void init() {readFlags();} + OptimizerFlags optimizerFlags; +private: + void readFlags(); + void showFlags(); }; -MemoryManager BaseOptimizer::mapmm(1024, "OptimizerMapMemoryManager"); - -BaseOptimizer::OptMap BaseOptimizer::optMap(BaseOptimizer::mapmm); - -DEFINE_OPTPASS(InlinePass) -DEFINE_OPTPASS_IMPL(InlinePass, inline, "Method Inlining") - -void -BaseOptimizer::initMap() { - if(optMap.empty()) { - registerPass(new (mapmm) ABCDPass()); // abcd - registerPass(new (mapmm) CodeLoweringPass()); // lower - registerPass(new (mapmm) DeadCodeEliminationPass()); // dce - registerPass(new (mapmm) UnreachableCodeEliminationPass()); // uce - registerPass(new (mapmm) PurgeEmptyNodesPass()); // purge - registerPass(new (mapmm) EscapeAnalysisPass()); // escape - registerPass(new (mapmm) GCManagedPointerAnalysisPass()); // gcmap - registerPass(new (mapmm) GlobalOperandAnalysisPass()); // markglobals - registerPass(new (mapmm) GlobalCodeMotionPass()); // gcm - registerPass(new (mapmm) GlobalValueNumberingPass()); // gvn - registerPass(new (mapmm) HashValueNumberingPass()); // hvn - registerPass(new (mapmm) LoopPeelingPass()); // peel - registerPass(new (mapmm) MemoryValueNumberingPass()); // memopt - registerPass(new (mapmm) ReassociationPass()); // reassoc - registerPass(new (mapmm) DepthReassociationPass()); // reassocdepth - registerPass(new (mapmm) LateDepthReassociationPass()); // latereassocdepth - registerPass(new (mapmm) SimplificationPass()); // simplify - registerPass(new (mapmm) LateSimplificationPass()); // latesimplify - registerPass(new (mapmm) TauSimplificationPass()); // tausimp - registerPass(new (mapmm) SyncOptPass()); // syncopt - registerPass(new (mapmm) RedundantBranchMergingPass()); // taildup - registerPass(new (mapmm) HotPathSplittingPass()); // hotpath - registerPass(new (mapmm) GuardedDevirtualizationPass()); // devirt - registerPass(new (mapmm) GuardRemovalPass()); // unguard - registerPass(new (mapmm) InlinePass()); // inline - registerPass(new (mapmm) PersistentInstIdGenerationPass()); // pidgen - registerPass(new (mapmm) SSAPass()); // ssa - registerPass(new (mapmm) DeSSAPass()); // dessa - registerPass(new (mapmm) SplitSSAPass()); // splitssa - registerPass(new (mapmm) FixupVarsPass()); // fixupvars - registerPass(new (mapmm) StaticProfilerPass()); // statprof - registerPass(new (mapmm) LazyExceptionOptPass()); // lazyexc - } -} - -void -BaseOptimizer::registerPass(OptPass* pass) { - if (Log::cat_opt()->isInfo2Enabled()){ - Log::cat_opt()->info2 << "Registering [" << pass->getTagName() << "] " << pass->getName() << ::std::endl; - } - optMap[pass->getTagName()] = pass; -} - -void -BaseOptimizer::run(const ::std::string& passName) { - OptMap::iterator iter; - if((iter = optMap.find(passName)) == optMap.end()) { - ::std::cerr << "Cannot find optimization [" << passName << "]" << ::std::endl; - assert(0); - }else{ - iter->second->run(irManager); - } -} - -void -BaseOptimizer::runPasses(const ::std::string& passName) { - size_t len = passName.length(); - size_t pos1 = 0; - size_t pos2 = 0; - while(pos2 < len && !irManager.getAbort()) { - pos2 = passName.find(",", pos1); - run(passName.substr(pos1, (pos2-pos1))); - pos1 = pos2+1; - } -} - -void -BaseOptimizer::addPasses(const ::std::string& passes) { - if(passList.empty()) - passList = passes; - else - passList += "," + passes; -} - -void -BaseOptimizer::runCurrentPasses(const char* label) { - metaOptimize(); - Log::cat_opt()->info2 << indent() << "Opt: Run optimization path: " << passList.c_str() << ::std::endl; - runPasses(passList); - passList = ""; -} - -BaseOptimizer::PatternMapping -BaseOptimizer::patternTable[] = { - { ",dessa,ssa,", "," }, - { ",ssa,dessa,", "," }, - { ",simplify,uce,dce,hvn,uce,dce,simplify,uce,dce,hvn,uce,dce,", ",simplify,uce,dce,hvn,uce,dce," }, - { ",simplify,uce,dce,simplify,uce,dce,", ",simplify,uce,dce," }, - { ",uce,dce,uce,dce,", ",uce,dce,", }, - { NULL, NULL, }, - }; -BaseOptimizer::PatternMapping -BaseOptimizer::patternTable2[] = { - { ",dessa,ssa,", "," }, - { ",ssa,dessa,", "," }, - { ",simplify,uce,dce,hvn,uce,dce,simplify,uce,dce,hvn,uce,dce,", ",simplify,uce,dce,hvn,uce,dce," }, - { ",simplify,uce,dce,simplify,uce,dce,", ",simplify,uce,dce," }, - { ",uce,dce,uce,dce,", ",uce,dce,", }, - { ",uce,dce,simplify,uce,dce,", ",simplify,uce,dce,", }, - { ",uce,dce,dessa,syncopt,uce,dce,", ",uce,dce,dessa,syncopt,", }, - { NULL, NULL, }, - }; - -void -BaseOptimizer::metaOptimize(::std::string& passes) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); - passes = std::string(",") + passes + ","; - - // Suppress hash value numbering (cse) if directed - if(optimizerFlags.no_hvn) - findAndReplace(passes, ",hvn,", ","); - - // Suppress simplification if directed - if(optimizerFlags.no_simplify) { - findAndReplace(passes, ",simplify,uce,dce,", ","); - findAndReplace(passes, ",latesimplify,uce,dce,", ","); - findAndReplace(passes, ",simplify,", ","); - findAndReplace(passes, ",latesimplify,", ","); - } - - if(optimizerFlags.meta_optimize) { - // Replace the optimization patterns in the pattern table above with the provided replacements - if (optimizerFlags.use_pattern_table2) { - for(uint32 i = 0; patternTable2[i].pattern != NULL; ++i) { - assert(patternTable2[i].replacement); - findAndReplace(passes, patternTable2[i].pattern, patternTable2[i].replacement); - } - } else { - for(uint32 i = 0; patternTable[i].pattern != NULL; ++i) { - assert(patternTable[i].replacement); - findAndReplace(passes, patternTable[i].pattern, patternTable[i].replacement); - } - } - } - - passes = passes.substr(1, passes.length() - 2); -} - -void -BaseOptimizer::metaOptimize() { - metaOptimize(passList); -} - -void -BaseOptimizer::findAndReplace(::std::string& str, const ::std::string& find, const ::std::string& replace) { - for(size_t i = str.find(find); i != ::std::string::npos; i = str.find(find)) - str.replace(i, find.length(), replace); - -} - -::std::string& -BaseOptimizer::getCurrentPasses() { - return passList; -} - -void -BaseOptimizer::clearCurrentPasses() { - passList = ""; -} - -void -BaseOptimizer::computeDominatorsAndLoops() { - OptPass::computeDominatorsAndLoops(irManager); -} - -class GlobalOptimizer : public BaseOptimizer { +class OptInitSession : public SessionAction { public: - GlobalOptimizer(MemoryManager& memoryManager, IRManager& irManager, bool suppressLog=false) : - BaseOptimizer(memoryManager, irManager, suppressLog) {} - - - // Build optimization path - void buildStaticAggressivePath(CompilationMode mode, ::std::string& path); - void buildStaticFastPath(::std::string& path); - void buildProfileGuidedPath(CompilationMode mode, ::std::string& path); - void buildInlineOptPath(::std::string& path); - void buildDPGOInlineOptPath(::std::string& path); - - void buildNoOptPath(::std::string& path); - void buildStaticPath(::std::string& path); - void buildDPGO1Path(::std::string& path); - void buildDPGO2Path(::std::string& path); - - // Privatization passes - void doPrivatization(::std::string& path); - - // Redundancy elimination passes - void doRedundancyElimination(::std::string& path); - - // IR lowering - void doSimplifyTaus(::std::string& path); - void doIRLowering(::std::string& path); - void doSyncOpt(::std::string& path); - - - void doTailDuplication(::std::string& path); - void doProfileTailDuplication(::std::string& path); - - void doLazyExceptionOpt(::std::string& path); - - // PGO passes - void generateProfile(); - void annotateProfile(); - void setHeatThreshold(); - - // Mode paths - void doNoOptPath(); - void doStaticPath(); - void doDPGO1Path(bool genProfile=true); - void doDPGO2Path(); - - - // Dot file printing utilities - void printDotFile(bool condition, char* subKind) { - if(condition) { - char dotName[30]="opt."; - sprintf(dotName+4, "%d", (int)stageId); - strcat(dotName, "."); - strcat(dotName, subKind); - OptPass::printDotFile(irManager, dotName); - } - } - void printDominatorTree(bool condition) { - if(condition) { - char dotName[30]="opt."; - sprintf(dotName+4, "%d", (int)stageId); - strcat(dotName, "domtree"); - irManager.getDominatorTree()->printDotFile(methodDesc, "domtree"); - } - } - void printLoopTree(bool condition) { - if(condition) { - char dotName[30]="opt."; - sprintf(dotName+4, "%d", (int)stageId); - strcat(dotName, "looptree"); - irManager.getLoopTree()->printDotFile(methodDesc, "looptree"); - } + virtual void run () { + CompilationContext* cc = getCompilationContext(); + assert(cc->getHIRManager() == NULL); + MemoryManager& mm = cc->getCompilationLevelMemoryManager(); + OptInitAction* myAction = (OptInitAction*)getAction(); + OptimizerFlags& flags = myAction->optimizerFlags; + IRManager* irm = new (mm) IRManager(mm, *cc->getVMCompilationInterface(), flags); + cc->setHIRManager(irm); } - void dumpPathsToFile(); }; -void -GlobalOptimizer::doSimplifyTaus(::std::string& path) { - if (optimizerFlags.simplify_taus) { - path += ",tausimp"; - } -} - -void -GlobalOptimizer::doIRLowering(::std::string& path) { - if (optimizerFlags.do_lower) { - path += ",lower"; - } -} - -void -GlobalOptimizer::doSyncOpt(::std::string& path) { - if (optimizerFlags.do_syncopt) { - if (optimizerFlags.use_fixup_vars) { - path += ",uce,dce,syncopt,uce,dce,fixupvars,uce,dce"; - } else { - path += ",dessa,syncopt,uce,dce,ssa"; - } - } -} -void -GlobalOptimizer::doTailDuplication(::std::string& path) { - if(optimizerFlags.do_tail_duplication) { - path += ",dessa,taildup,ssa,simplify,uce,dce,hvn,uce,dce"; - } -} +static void showFlags(std::ostream& os); -void -GlobalOptimizer::doProfileTailDuplication(::std::string& path) { - if(optimizerFlags.do_profile_tail_duplication || optimizerFlags.do_early_profile_tail_duplication) { - path += ",dessa,hotpath,ssa,simplify,uce,dce,hvn,uce,dce"; - } -} +#define OPT_INIT_NAME "opt_init" -void -GlobalOptimizer::doLazyExceptionOpt(::std::string& path) { - // disable for IPF until CG support is implemented - if (optimizerFlags.do_lazyexc && optimizerFlags.ia32_code_gen) { - path += ",lazyexc"; - } -} +class OptInitFactory : public ActionFactory<OptInitSession, OptInitAction> { +public: + OptInitFactory(const char* name) : ActionFactory<OptInitSession, OptInitAction>(name, NULL){} + virtual void showHelp (std::ostream& os) {showFlags(os);} +}; -void -InlinePass::_run(IRManager& irm) { - computeDominatorsAndLoops(irm); +static OptInitFactory _opt_init(OPT_INIT_NAME); - // Set up Inliner - bool connectEarly = irm.getParameterTable().lookupBool("opt::inline::connect_early", true); - Inliner inliner(irm.getNestedMemoryManager(), irm, inDPGOMode(irm) && getCompilationMode(irm) != CM_DPGO1); - InlineNode *rootRegionNode = (InlineNode*) inliner.getInlineTree().getRoot(); - inliner.inlineAndProcessRegion(rootRegionNode, irm.getDominatorTree(), irm.getLoopTree()); - // Inline calls - InlineNode *regionNode = inliner.getNextRegionToInline(); - while(regionNode != NULL) { - assert(regionNode != rootRegionNode); - IRManager ®ionManager = regionNode->getIRManager(); - GlobalOptimizer regionOptimizer(regionManager.getNestedMemoryManager(), regionManager, - false); +void OptInitAction::readFlags() +{ + MemoryManager& mm = getJITInstanceContext().getGlobalMemoryManager(); + memset( &optimizerFlags, 0, sizeof(OptimizerFlags)); - // If in DPGO mode, redo DPGO1 optimizations on inlined regions. - CompilationMode mode = getCompilationMode(irm); - + optimizerFlags.dumpdot= getBoolArg("dumpdot", false); - // Connect region arguments to top-level flowgraph - if(connectEarly) - inliner.connectRegion(regionNode); + optimizerFlags.cse_final = getBoolArg("cse_final", true); - // Optimize inlined region before splicing - { - PhaseInvertedTimer modeTimer(getModeTimer(mode)); - PhaseInvertedTimer timer(getTimer()); + optimizerFlags.hash_init_factor = getIntArg("hash_init_factor", 1); + optimizerFlags.hash_resize_factor = getIntArg("hash_resize_factor", 2); + optimizerFlags.hash_resize_to = getIntArg("hash_resize_to", 3); + optimizerFlags.hash_node_var_factor = getIntArg("hash_node_var_factor", 1); + optimizerFlags.hash_node_tmp_factor = getIntArg("hash_node_tmp_factor", 2); + optimizerFlags.hash_node_constant_factor = getIntArg("hash_node_constant_factor", 1); - regionOptimizer.addPasses(irm.getInlineOptPath()); - regionOptimizer.runCurrentPasses("Inline Passes"); - } + optimizerFlags.sink_constants = getBoolArg("sink_constants", true); + optimizerFlags.sink_constants1 = getBoolArg("sink_constants1", false); - // Splice into flow graph and find next region. - regionOptimizer.computeDominatorsAndLoops(); - if(!connectEarly) - inliner.connectRegion(regionNode); - inliner.inlineAndProcessRegion(regionNode, regionManager.getDominatorTree(), regionManager.getLoopTree()); - regionNode = inliner.getNextRegionToInline(); - } - OptimizerFlags& optimizerFlags = *irm.getCompilationContext()->getOptimizerFlags(); - // Print the results to logging / dot file - if(optimizerFlags.dumpdot) - inliner.getInlineTree().printDotFile(irm.getMethodDesc(), "inlinetree"); - if(Log::cat_opt_inline()->isInfo2Enabled()) { - Log::cat_opt_inline()->info2 << indent(irm) << "Opt: Inline Tree" << ::std::endl; - inliner.getInlineTree().printIndentedTree(Log::out(), " "); - } - Log::cat_opt_inline()->info << "Inline Checksum == " << (int) inliner.getInlineTree().computeCheckSum() << ::std::endl; -} - - -void -GlobalOptimizer::buildInlineOptPath(::std::string& path) { - if (optimizerFlags.do_peeling && !optimizerFlags.use_profile - && !optimizerFlags.no_peel_inlined) { - - if (optimizerFlags.memopt_inlined || optimizerFlags.hvn_inlined) { - path += ",ssa,simplify,uce,dce,hvn,uce,dce"; - if (optimizerFlags.memopt_inlined) { - path += ",memopt,simplify,uce,dce,hvn,uce,dce"; - } - path += ",dessa"; - } - - path += ",peel"; - } - - path += ",ssa"; - if ((optimizerFlags.memopt_inlined || optimizerFlags.hvn_inlined) - && optimizerFlags.no_peel_inlined) { - path += ",ssa,simplify,uce,dce,hvn,uce,dce"; - if (optimizerFlags.memopt_inlined) { - path += ",memopt,simplify,uce,dce,hvn,uce,dce"; - } - path += ",dessa"; - } - - path += ",simplify,uce,dce"; - - if(optimizerFlags.do_guarded_devirtualization) { - path += ",devirt"; - } - - trim(path); -} - - -void -GlobalOptimizer::buildDPGOInlineOptPath(::std::string& path) { - if(optimizerFlags.do_early_profile_tail_duplication) { - if(optimizerFlags.do_tail_duplication) - path += ",dessa,taildup,ssa,simplify,uce,dce,hvn,uce,dce"; - if(optimizerFlags.do_profile_tail_duplication) - path += ",dessa,hotpath,ssa,simplify,uce,dce,hvn,uce,dce"; - } - - path += ",ssa,simplify,uce,dce"; - - if(optimizerFlags.do_unguard) { - path += ",unguard,simplify,uce,dce"; - } - - trim(path); -} - -void -GlobalOptimizer::doPrivatization(::std::string& path) { - path += ",escape"; - - if (optimizerFlags.do_memopt) { - path += ",memopt"; - } - - if (optimizerFlags.do_reassoc) { - path += ",reassoc,uce,dce,hvn,uce,dce"; - } -} - -void -GlobalOptimizer::doRedundancyElimination(::std::string& path) { - bool needCleanup = false; + //simplifier flags + optimizerFlags.elim_cmp3 = getBoolArg("elim_cmp3", true); + optimizerFlags.use_mulhi = getBoolArg("use_mulhi", false); + optimizerFlags.lower_divconst = getBoolArg("lower_divconst", true); + optimizerFlags.ia32_code_gen = Jitrino::flags.codegen != Jitrino::CG_IPF; + optimizerFlags.do_sxt = getBoolArg("do_sxt", true); + optimizerFlags.reduce_compref = getBoolArg("reduce_compref", false); - if (optimizerFlags.do_memopt) { - path += ",uce,dce"; - path += ",memopt"; - } - if (optimizerFlags.do_reassoc) { - path += ",reassoc,uce,dce,hvn,uce,dce"; - } + //hvn flags + optimizerFlags.elim_checks = getBoolArg("elim_checks", true); + optimizerFlags.gvn_exceptions = getBoolArg("gvn_exceptions", false); + optimizerFlags.gvn_aggressive = getBoolArg("gvn_aggressive", false); + optimizerFlags.hvn_constants = getBoolArg("hvn_constants", true); - if (optimizerFlags.do_abcd) { - // after abcd, cleanup removed conversions and their predecessors - path += ",abcd,uce,dce"; + //profiler flags + optimizerFlags.profile_threshold = getIntArg("profile_threshold", 5000); + optimizerFlags.use_average_threshold = getBoolArg("use_average_threshold", false); + optimizerFlags.use_minimum_threshold = getBoolArg("use_minimum_threshold", false); + optimizerFlags.use_fixed_threshold = getBoolArg("use_fixed_threshold", false); - needCleanup = true; - } - if (optimizerFlags.do_gcm) { - if (optimizerFlags.do_gvn) { - path += ",gvn"; - } + //dce flags + optimizerFlags.fixup_ssa = getBoolArg("fixup_ssa", true); + optimizerFlags.dce2 = getBoolArg("dce2", true); + optimizerFlags.preserve_critical_edges = getBoolArg("preserve_critical_edges", true); - path += ",gcm"; - needCleanup = true; - } + //ssa + optimizerFlags.better_ssa_fixup = getBoolArg("better_ssa_fixup", false); - if (needCleanup) { - // try some cleanup - path += ",simplify,uce,dce,hvn,uce,dce"; - } -} - -void -GlobalOptimizer::buildStaticFastPath(::std::string& path) { - if(!optimizerFlags.skip_phase1) { - path += ",ssa,simplify,uce,dce"; - if(optimizerFlags.do_guarded_devirtualization) - path += ",devirt,uce,dce"; - if(!optimizerFlags.no_hvn) - path += ",hvn,uce,dce"; - path += ",dessa"; - } - path += ",pidgen"; -} - -void -GlobalOptimizer::buildStaticAggressivePath(CompilationMode mode, ::std::string& path) { - assert(mode == CM_STATIC || mode == CM_DPGO1); - path += ",ssa,simplify,uce,dce,hvn,uce,dce"; - if (optimizerFlags.early_memopt && optimizerFlags.do_memopt) { - path += ",memopt,simplify,uce,dce,hvn,uce,dce"; - } - path += ",dessa"; - - buildInlineOptPath(path); - if(optimizerFlags.do_inline && mode == CM_STATIC) - path += ",inline"; - path += ",simplify,uce,dce"; + //statprof + optimizerFlags.statprof_do_loop_heuristics_override = getBoolArg("statprof_do_loop_heuristics_override", true); + optimizerFlags.statprof_heuristics = getStringArg("statprof_heuristics", NULL); - path += ",simplify,uce,dce,hvn,uce,dce"; - doSimplifyTaus(path); - doLazyExceptionOpt(path); - - doPrivatization(path); + //gcmptranalyzer + optimizerFlags.gc_build_var_map = getBoolArg("gc_build_var_map", true); + //devirtualizer flags + optimizerFlags.devirt_skip_cold_targets = getBoolArg("devirt_skip_cold", true); + optimizerFlags.devirt_do_aggressive_guarded_devirtualization = getBoolArg("devirt_aggressive", false); + optimizerFlags.devirt_devirt_use_cha = getBoolArg("devirt_use_cha", false); + optimizerFlags.devirt_devirt_skip_exception_path = getBoolArg("devirt_skip_exception_path", true); - doIRLowering(path); - doSyncOpt(path); + optimizerFlags.abcdFlags = new (mm) AbcdFlags; + memset(optimizerFlags.abcdFlags, sizeof(AbcdFlags), 0); - if (optimizerFlags.use_profile - && optimizerFlags.do_profile_redundancy_elimination) { - - if (optimizerFlags.do_prof_red2) { - doRedundancyElimination(path); - - } - if (optimizerFlags.do_prof_red2_latesimplify) { - path += ",latesimplify,uce,dce,hvn,uce,dce"; - } - } else { // not in a dynopt run, always do redundancy elim - doRedundancyElimination(path); - - if (optimizerFlags.do_latesimplify) { - path += ",latesimplify,uce,dce,hvn,uce,dce"; - } - } - - if (optimizerFlags.do_reassoc_depth) { - path += ",reassocdepth,uce,dce,hvn,uce,dce"; - } - - doTailDuplication(path); - - path += ",purge"; - if(optimizerFlags.split_ssa) - path += ",splitssa"; -#ifdef _IPF_ - path += ",gcmap"; -#endif - - path += ",dessa"; - path += ",pidgen"; - path += ",statprof"; -} - - -void -GlobalOptimizer::buildProfileGuidedPath(CompilationMode mode, ::std::string& path) { - buildDPGOInlineOptPath(path); - if(optimizerFlags.do_inline) - path += ",inline"; - - path += ",simplify,uce,dce,hvn,uce,dce"; - doSimplifyTaus(path); - - if(optimizerFlags.do_profile_tail_duplication) { - doTailDuplication(path); - doProfileTailDuplication(path); - } else { - doTailDuplication(path); - } - - if(optimizerFlags.fast_phase1) { - doPrivatization(path); - doIRLowering(path); - } - if (optimizerFlags.do_syncopt2) { - doSyncOpt(path); - } - if (optimizerFlags.do_peeling && optimizerFlags.use_profile) { - path += ",dessa,peel,ssa"; - } - - path += ",simplify,uce,dce,hvn,uce,dce"; - - if(optimizerFlags.do_profile_redundancy_elimination) { - doRedundancyElimination(path); - - if (optimizerFlags.do_latesimplify) { - path += ",latesimplify,uce,dce,hvn,uce,dce"; - } - } - - if (optimizerFlags.do_reassoc_depth2) { - path += ",reassocdepth,uce,dce,hvn,uce,dce"; - } - - path += ",purge"; - if(optimizerFlags.split_ssa) - path += ",splitssa"; -#ifdef _IPF_ - path += ",gcmap"; -#endif - path += ",dessa"; -} - -void -GlobalOptimizer::generateProfile() { - // - // Profile generation. - // Dynamic profiling has higher priority than off-line profiling. - // - computeDominatorsAndLoops(); - printDotFile(optimizerFlags.dumpdot, "beforepgen"); - - assert(0); + optimizerFlags.gcmFlags = new (mm) GcmFlags; + memset(optimizerFlags.gcmFlags, sizeof(GcmFlags), 0); - printDotFile(optimizerFlags.dumpdot, "afterpgen"); + optimizerFlags.memOptFlags = new (mm) MemoptFlags; + memset(optimizerFlags.memOptFlags, sizeof(MemoptFlags), 0); + + optimizerFlags.syncOptFlags = new (mm) SyncOptFlags; + memset(optimizerFlags.syncOptFlags, sizeof(SyncOptFlags), 0); + + optimizerFlags.loopBuilderFlags = new (mm) LoopBuilderFlags; + memset(optimizerFlags.loopBuilderFlags, sizeof(LoopBuilderFlags), 0); + + Abcd::readFlags(this, optimizerFlags.abcdFlags); + GlobalCodeMotion::readFlags(this, optimizerFlags.gcmFlags); + MemoryOpt::readFlags(this, optimizerFlags.memOptFlags); + SyncOpt::readFlags(this, optimizerFlags.syncOptFlags); + LoopBuilder::readFlags(this, optimizerFlags.loopBuilderFlags); +} + + +void showFlags(std::ostream& os) { + os << "\n"<<OPT_INIT_NAME<<std::endl; + os << " global optimizer flags:"<<std::endl; + os << " elim_cmp3[={ON|off}] - eliminate cmp3 tests" << std::endl; + os << " elim_checks[={ON|off}] - try to eliminate some checks using branch conditions" << std::endl; + os << " use_mulhi{ON|off}] - use MulHi opcode" << std::endl; + os << " lower_divconst[={ON|off}] - lower div by constant to mul" << std::endl; + os << " cse_final[={ON|off}] - do cse of final fields " << std::endl; + os << " fixup_ssa[={on|OFF}] - fixup SSA form after code deletion" << std::endl; + os << " number_dots[={on|OFF}] - use a counter in dot file names to show order" << std::endl; + os << " dce2[={ON|off}] - use new version of DCE pass"; + os << " split_ssa[={ON|off}] - rename nonoverlapping SSA var versions"; + os << " better_ssa_fixup[={on|OFF}] - defer ssa fixup until graph change"; + os << " hvn_exceptions[={ON|off}] - do value-numbering on exception paths" << std::endl; + os << " hvn_constants[={ON|off}] - value-number constants from equality tests" << std::endl; + os << " sink_constants[={ON|off}] - eliminate globals whose values are constant" << std::endl; + os << " sink_constants1[={on|OFF}] - make sink_constants more aggressive" << std::endl; + + Abcd::showFlags(os); + GlobalCodeMotion::showFlags(os); + MemoryOpt::showFlags(os); + SyncOpt::showFlags(os); + LoopBuilder::showFlags(os); } -void -GlobalOptimizer::annotateProfile() { - // - // Profile feedback. - // Dynamic profiling has higher priority than off-line profiling. - // - computeDominatorsAndLoops(); - CompilationInterface& compileIntf = irManager.getCompilationInterface(); - if ( compileIntf.isDynamicProfiling() ) { - // For dynamic profiling controlled by the Profile Manager. - CodeProfiler codeProfiler; - codeProfiler.getOnlineProfile(irManager); - } else if ( profileCtrl.useProf() ) { - // For offline profile generation and feedback as controlled by - // -jitrino PROF="...". - CodeProfiler codeProfiler; - codeProfiler.getOfflineProfile(irManager); - } - - if (flowGraph.hasEdgeProfile()) { - if (Log::cat_opt()->isInfo2Enabled()){ - Log::cat_opt()->info2 << "Jitrino: " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "... HAS dynamic profile" << ::std::endl; - } - if (profileCtrl.getDebugCtrl() > 0) { - ::std::cerr << "Jitrino: " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "... HAS dynamic profile" << ::std::endl; - printInstructions(profileCtrl.getDebugCtrl() > 1, "IR after annotation"); - } - } else { - if (Log::cat_opt()->isInfo2Enabled()){ - Log::cat_opt()->info2 << "Jitrino: " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "... HAS NO dynamic profile" << ::std::endl; - } - if (profileCtrl.getDebugCtrl() > 0) { - ::std::cerr << "Jitrino: " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "... HAS NO dynamic profile" << ::std::endl; - printInstructions(profileCtrl.getDebugCtrl() > 1, "IR after annotation"); - } - } -} - -void -GlobalOptimizer::setHeatThreshold() { - double profile_threshold = optimizerFlags.profile_threshold; - if(optimizerFlags.use_average_threshold) { - // Keep a running average of method counts. - static uint32 count = 0; - static double total = 0.0; - count++; - double methodFreq = flowGraph.getEntry()->getFreq(); - assert(methodFreq > 0); - total += methodFreq; - irManager.setHeatThreshold(total / count); - } else if(optimizerFlags.use_minimum_threshold) { - double methodFreq = flowGraph.getEntry()->getFreq(); - if(methodFreq < profile_threshold) - methodFreq = profile_threshold; - irManager.setHeatThreshold(methodFreq); - } else if(optimizerFlags.use_fixed_threshold) { - irManager.setHeatThreshold(profile_threshold); - } else { - // Use the method entry - irManager.setHeatThreshold(flowGraph.getEntry()->getFreq()); - } - Log::cat_opt()->info2 << "Heat threshold = " << irManager.getHeatThreshold() << ::std::endl; -} - -void -GlobalOptimizer::buildNoOptPath(::std::string& path) { - doIRLowering(path); - doLazyExceptionOpt(path); - if (!irManager.getMethodDesc().isClassInitializer()) { - path+=",statprof"; - } - trim(path); -} - -void -GlobalOptimizer::buildStaticPath(::std::string& path) { - buildStaticAggressivePath(CM_STATIC, path); - trim(path); -} - -void -GlobalOptimizer::buildDPGO1Path(::std::string& path) { - if(!optimizerFlags.fast_phase1) - buildStaticAggressivePath(CM_DPGO1, path); - else - buildStaticFastPath(path); - trim(path); -} - -void -GlobalOptimizer::buildDPGO2Path(::std::string& path) { - buildProfileGuidedPath(CM_DPGO2, path); - trim(path); -} - - - - -void -GlobalOptimizer::doNoOptPath() { - Log::cat_opt()->info2 << indent() << "Opt: Entering No Optimization Path" << ::std::endl; - ::std::string path; - if(optimizerFlags.noopt_path) - path = optimizerFlags.noopt_path; - else - buildNoOptPath(path); - addPasses(path); - runCurrentPasses("Passes"); -} - -void -GlobalOptimizer::doStaticPath() { - Log::cat_opt()->info2 << indent() << "Opt: Entering Static Optimization Path" << ::std::endl; - ::std::string inlinePath; - if(optimizerFlags.inline_path) - inlinePath = optimizerFlags.inline_path; - else - buildInlineOptPath(inlinePath); - - irManager.setInlineOptPath(inlinePath.c_str()); - - ::std::string path; - if(optimizerFlags.static_path) - path = optimizerFlags.static_path; - else - buildStaticPath(path); - addPasses(path); - runCurrentPasses("Passes"); -} - -void -GlobalOptimizer::doDPGO1Path(bool genProfile) { - Log::cat_opt()->info2 << indent() << "Opt: Entering Profile Collection (DPGO1) Path" << ::std::endl; - ::std::string path; - if(optimizerFlags.dpgo1_path) - path = optimizerFlags.dpgo1_path; - else - buildDPGO1Path(path); - addPasses(path); - runCurrentPasses("Passes"); - - if(genProfile) - generateProfile(); -} - -void -GlobalOptimizer::doDPGO2Path() { - // - // Repeat DPGO1 without generating profile - // - doDPGO1Path(false); - annotateProfile(); - setHeatThreshold(); - - // - // Do profile guided optimization - // - Log::cat_opt()->info2 << indent() << "Opt: Entering Profile Guided Optimization (DPGO2) Path" << ::std::endl; - double methodCount = Inliner::getProfileMethodCount(irManager.getCompilationInterface(), methodDesc); - if((!optimizerFlags.check_profile_threshold || - methodCount >= optimizerFlags.profile_threshold) && flowGraph.hasEdgeProfile()) { - Log::cat_opt()->info << "Jitrino: reoptimize " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName(); - Log::cat_opt()->info2 << "... methodCount = " << methodCount; - Log::cat_opt()->info << ::std::endl; - - ::std::string inlinePath; - if(optimizerFlags.inline_path) - inlinePath = optimizerFlags.inline_path; - else - buildDPGOInlineOptPath(inlinePath); - irManager.setInlineOptPath(inlinePath.c_str()); - - ::std::string path; - if(optimizerFlags.dpgo2_path) - path = optimizerFlags.dpgo2_path; - else - buildDPGO2Path(path); - addPasses(path); - runCurrentPasses("Passes"); - } - else { - Log::cat_opt()->info << "Jitrino: do not reoptimize " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "... methodCount = " << methodCount << ::std::endl; - } -} - - - -void -GlobalOptimizer::dumpPathsToFile() { - static bool dumped = false; - if(!dumped && optimizerFlags.dump_paths != NULL) { - ::std::ofstream out(optimizerFlags.dump_paths); - if (!out) { - ::std::cerr << "Unable to open " << optimizerFlags.dump_paths << " for path output.\n"; - exit(1); - }; - - ::std::string path; - - out << "#\n# NOOPT PATH\n#\n"; - out << "opt::noopt_path=\"lower\"\n"; - - if(!OptPass::inDPGOMode(irManager)) { - out << "#\n# STATIC PATH\n#\n"; - buildStaticPath(path); - metaOptimize(path); - out << "opt::static_path=\"" << path.c_str() << "\"\n"; - path = ""; - - out << "#\n# INLINE PATH\n#\n"; - buildInlineOptPath(path); - metaOptimize(path); - out << "opt::inline_path=\"" << path.c_str() << "\"\n"; - path = ""; - } else { - out << "#\n# DPGO1 PATH\n#\n"; - buildDPGO1Path(path); - metaOptimize(path); - out << "opt::dpgo1_path=\"" << path.c_str() << "\"\n"; - path = ""; - - out << "#\n# DPGO2 PATH\n#\n"; - buildDPGO2Path(path); - metaOptimize(path); - out << "opt::dpgo2_path=\"" << path.c_str() << "\"\n"; - path = ""; - out << "#\n# INLINE PATH\n#\n"; - buildDPGOInlineOptPath(path); - metaOptimize(path); - out << "opt::inline_path=\"" << path.c_str() << "\"\n"; - path = ""; - } - dumped = true; - } -} - - -// -// entry point to the optimizer -// -bool -optimize(IRManager& irManager) { - static Timer* timer = NULL; - PhaseTimer phaseTimer(timer, "opt::all"); - CompilationInterface& compileIntf = irManager.getCompilationInterface(); - MethodDesc& methodDesc = irManager.getMethodDesc(); - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); - - optimizerFlags.use_profile = OptPass::inDPGOMode(irManager); - if (optimizerFlags.use_profile) { - optimizerFlags.early_memopt = optimizerFlags.early_memopt_prof; - } - optimizerFlags.check_profile_threshold = irManager.getParameterTable().lookupBool("opt::check_profile_threshold", !compileIntf.isDynamicProfiling()); - - MemoryManager& memManager = irManager.getMemoryManager(); - GlobalOptimizer optimizer(memManager, irManager); - - if (Log::cat_opt()->isInfo2Enabled()){ - Log::cat_opt()->info2 << "Jitrino: optimize " << methodDesc.getParentType()->getName() - << "::" << methodDesc.getName() << "..." << ::std::endl; - } - - uint32 stageId=optimizer.getStageId(); - - if (Log::cat_opt()->isIREnabled()){ - Log::printStageBegin(stageId, "HLO", "High Level Optimizations", "opt"); - - Log::printIRDumpBegin(stageId, "High Level Optimizations", "before"); - optimizer.printInstructions(Log::cat_opt()->isIREnabled(), "before optimization"); - Log::printIRDumpEnd(stageId, "High Level Optimizations", "before"); - - optimizer.printDotFile(optimizerFlags.dumpdot, "before"); - optimizer.dumpPathsToFile(); - } - - - CompilationMode mode = OptPass::getCompilationMode(irManager); - - switch(mode) { - case CM_NO_OPT: - { - static Timer* timer = NULL; - PhaseTimer phaseTimer(timer, "opt::noopt"); - optimizer.doNoOptPath(); - } - break; - case CM_STATIC: - { - static Timer* timer = NULL; - PhaseTimer phaseTimer(timer, "opt::static"); - optimizer.doStaticPath(); - } - break; - case CM_DPGO1: - { - static Timer* timer = NULL; - PhaseTimer phaseTimer(timer, "opt::dpgo1"); - optimizer.doDPGO1Path(); - } - break; - case CM_DPGO2: - { - static Timer* timer = NULL; - PhaseTimer phaseTimer(timer, "opt::dpgo2"); - optimizer.doDPGO2Path(); - } - break; - default: - assert(0); - } - - // - // Prepare for code generation. - // - optimizer.computeDominatorsAndLoops(); - optimizer.run("markglobals"); - - if (Log::cat_opt()->isIREnabled()){ - optimizer.printDominatorTree(optimizerFlags.dumpdot); - optimizer.printLoopTree(optimizerFlags.dumpdot); - - Log::printIRDumpBegin(stageId, "High Level Optimizations", "after"); - optimizer.printInstructions(Log::cat_opt()->isIREnabled(), "IR after Optimization"); - Log::printIRDumpEnd(stageId, "High Level Optimizations", "after"); - - optimizer.printDotFile(optimizerFlags.dumpdot, "after"); - - Log::printStageEnd(stageId, "HLO", "High Level Optimizations", "opt"); - } - - assert(irManager.getAbort() == false); - return true; -} - - } //namespace Jitrino diff --git vm/jitrino/src/optimizer/optimizer.h vm/jitrino/src/optimizer/optimizer.h index e349170..bea336f 100644 --- vm/jitrino/src/optimizer/optimizer.h +++ vm/jitrino/src/optimizer/optimizer.h @@ -27,109 +27,79 @@ #include "TranslatorIntfc.h" namespace Jitrino { -class CompilationInterface; -class CompilationContext; -class IRManager; +struct MemoptFlags; +struct AbcdFlags; +struct GcmFlags; +struct SyncOptFlags; +struct LoopBuilderFlags; -bool optimize(IRManager& irManager); // returns success or failure +struct OptimizerFlags { + + //global optimizer flags + bool dumpdot; -class JitrinoParameterTable; + bool cse_final; -void readOptimizerFlagsFromCommandLine(CompilationContext* compilationContext); -void showOptimizerFlagsFromCommandLine(); + uint32 hash_init_factor; + uint32 hash_resize_factor; + uint32 hash_resize_to; + uint32 hash_node_var_factor; + uint32 hash_node_tmp_factor; + uint32 hash_node_constant_factor; -struct OptimizerFlags { - const char* noopt_path; - const char* static_path; - const char* dpgo1_path; - const char* dpgo2_path; - - const char* inline_path; - bool meta_optimize; - const char* dump_paths; + bool sink_constants; + bool sink_constants1; - bool skip; - bool fast_phase1; - bool skip_phase1; - bool dumpdot; - bool build_loops; - bool do_ssa; - bool globals_span_loops; - bool do_abcd; - bool do_inline; - uint32 inline_n; - bool do_guarded_devirtualization; - bool do_unguard; - bool do_peeling; + //simplifier flags bool elim_cmp3; - bool elim_checks; - bool do_lower; - bool use_profile; - bool do_latesimplify; bool use_mulhi; bool lower_divconst; - bool do_gcm; - bool do_gvn; bool ia32_code_gen; - bool cse_final; - bool no_simplify; - bool no_hvn; - bool do_tail_duplication; - bool do_profile_tail_duplication; - bool do_early_profile_tail_duplication; - bool prune_untaken_edges; - uint32 profile_unguarding_level; + bool do_sxt; + bool reduce_compref; + + + //hvn flag + bool elim_checks; + bool gvn_exceptions; + bool gvn_aggressive; + bool hvn_exceptions; + bool hvn_constants; + + + //profiler flags uint32 profile_threshold; - bool check_profile_threshold; bool use_average_threshold; bool use_minimum_threshold; bool use_fixed_threshold; - bool do_profile_redundancy_elimination; - bool do_prefetching; - bool do_memopt; - bool brm_debug; + + //dce flags bool fixup_ssa; - bool number_dots; - bool do_sxt; - bool do_reassoc; - bool do_reassoc_depth; - bool do_reassoc_depth2; - bool do_prof_red2; bool dce2; - bool do_redstore; - bool do_syncopt; - bool keep_empty_nodes_after_syncopt; - bool do_syncopt2; - bool do_prof_red2_latesimplify; - bool gc_build_var_map; - bool reduce_compref; - bool split_ssa; + bool preserve_critical_edges; + + + //ssa bool better_ssa_fixup; - bool count_ssa_fixup; - bool hvn_exceptions; - bool sink_constants; - bool sink_constants1; - bool gvn_exceptions; - bool gvn_aggressive; - bool do_reassoc_compref; - uint32 hash_init_factor; - uint32 hash_resize_factor; - uint32 hash_resize_to; - uint32 hash_node_var_factor; - uint32 hash_node_tmp_factor; - uint32 hash_node_constant_factor; - bool hvn_constants; - bool simplify_taus; - bool early_memopt; - bool early_memopt_prof; - bool no_peel_inlined; - bool hvn_inlined; - bool memopt_inlined; - bool type_check; - bool use_pattern_table2; - bool use_fixup_vars; - bool pass_profile_to_cg; - bool do_lazyexc; + + //statprof + bool statprof_do_loop_heuristics_override; + const char* statprof_heuristics; + + //gc-mptr-analyzer + bool gc_build_var_map; + + //devirt + bool devirt_skip_cold_targets; + bool devirt_do_aggressive_guarded_devirtualization; + bool devirt_devirt_use_cha; + bool devirt_devirt_skip_exception_path; + + AbcdFlags* abcdFlags; + GcmFlags* gcmFlags; + MemoptFlags* memOptFlags; + SyncOptFlags* syncOptFlags; + LoopBuilderFlags* loopBuilderFlags; }; } //namespace Jitrino diff --git vm/jitrino/src/optimizer/optpass.cpp vm/jitrino/src/optimizer/optpass.cpp index 171802a..c0f66ca 100644 --- vm/jitrino/src/optimizer/optpass.cpp +++ vm/jitrino/src/optimizer/optpass.cpp @@ -23,40 +23,50 @@ #include "Log.h" #include "optpass.h" #include "irmanager.h" -#include "Timer.h" #include "Dominator.h" #include "Loop.h" #include "./ssa/SSA.h" -#include "Profiler.h" -#include "CompilationContext.h" +#include "EMInterface.h" #include "optimizer.h" +#include "FlowGraph.h" +#include "StaticProfiler.h" + +#ifdef _WIN32 + #define snprintf _snprintf +#endif + namespace Jitrino { void -OptPass::run(IRManager& irm) +OptPass::run() { - id=Log::getNextStageId(); + IRManager& irm = *getCompilationContext()->getHIRManager(); + id = Log::getStageId(); + + LogStream& irdump = log(LogStream::IRDUMP); + LogStream& dotdump = log(LogStream::DOTDUMP); - if (Log::cat_opt()->isIREnabled()){ - Log::printStageBegin(id, "HLO", getName(), getTagName()); - } + if (irdump.isEnabled()) { + Log::printStageBegin(irdump.out(), id, "HLO", getName(), getTagName()); + irdump << indent(irm) << "Opt: Running " << getName() << ::std::endl; + printHIR(irm, "before"); + } + + if (dotdump.isEnabled()) { + printDotFile(irm, id, getTagName(), "before"); + } - Log::cat_opt()->info3 << indent(irm) << "Opt: Running " << getName() << ::std::endl; - printHIR(irm, genIRBefore(irm), "before"); - printDotFile(irm, genDotFileBefore(irm), "before"); - { - CompilationMode mode = getCompilationMode(irm); - PhaseTimer modeTimer(getModeTimer(mode), getModeTimerName(mode)); - PhaseTimer timer(getTimer(), getTimerName()); _run(irm); + + if (dotdump.isEnabled()) { + printDotFile(irm, id, getTagName(), "after"); } - printHIR(irm, genIRAfter(irm), "after"); - printDotFile(irm, genDotFileAfter(irm), "after"); - if (Log::cat_opt()->isIREnabled()){ - Log::printStageEnd(id, "HLO", getName(), getTagName()); - } + if (irdump.isEnabled()) { + printHIR(irm, "after"); + Log::printStageEnd(irdump.out(), id, "HLO", getName(), getTagName()); + } } void @@ -66,9 +76,9 @@ OptPass::computeDominators(IRManager& ir // Already valid. return; } - Log::cat_opt()->info3 << indent(irm) << "Opt: Compute Dominators" << ::std::endl; - static Timer *computeDominatorsTimer = 0; // not thread-safe - PhaseTimer t(computeDominatorsTimer, "opt::helper::computeDominators"); + Log::out() << indent(irm) << "Opt: Compute Dominators" << ::std::endl; + static CountTime computeDominatorsTimer("opt::helper::computeDominators"); + AutoTimer tm(computeDominatorsTimer); DominatorBuilder db; dominatorTree = db.computeDominators(irm.getNestedMemoryManager(), &(irm.getFlowGraph()),false,true); irm.setDominatorTree(dominatorTree); @@ -76,47 +86,44 @@ OptPass::computeDominators(IRManager& ir void -OptPass::computeLoops(IRManager& irm) { - LoopTree* loopTree = irm.getLoopTree(); - if(loopTree != NULL && loopTree->isValid()) - // Already valid. +OptPass::computeLoops(IRManager& irm, bool normalize) { + LoopTree* lt = irm.getLoopTree(); + if (lt!=NULL && lt->isValid() && (lt->isNormalized() || !normalize)) { return; - Log::cat_opt()->info3 << indent(irm) << "Opt: Compute Loop Tree" << ::std::endl; - static Timer *computeLoopsTimer = 0; // not thread-safe - PhaseTimer t(computeLoopsTimer, "opt::helper::computeLoops"); - assert(irm.getDominatorTree()->isValid()); - LoopBuilder lb(irm.getNestedMemoryManager(), - irm, *(irm.getDominatorTree()),false); - loopTree = lb.computeAndNormalizeLoops(); + } + Log::out() << indent(irm) << "Opt: Compute Loop Tree" << ::std::endl; + static CountTime computeLoopsTimer("opt::helper::computeLoops"); + AutoTimer tm(computeLoopsTimer); + LoopBuilder lb(irm.getNestedMemoryManager(), irm, *(irm.getDominatorTree()),false); + lb.computeLoops(normalize); if (lb.needSsaFixup()) { fixupSsa(irm); } - irm.setLoopTree(loopTree); } void -OptPass::computeDominatorsAndLoops(IRManager& irm) { +OptPass::computeDominatorsAndLoops(IRManager& irm, bool normalizeLoops) { computeDominators(irm); - computeLoops(irm); + computeLoops(irm, normalizeLoops); computeDominators(irm); } void OptPass::fixupSsa(IRManager& irm) { - static Timer* fixupSsaTimer = 0; + static CountTime fixupSsaTimer("opt::helper::fixupSsa"); static uint32 globalSsaFixupCounter = 0; if(!irm.isSsaUpdated()) { - PhaseTimer t(fixupSsaTimer, "opt::helper::fixupSsa"); - Log::cat_opt()->info3 << indent(irm) << "Opt: SSA Fixup" << ::std::endl; + AutoTimer tm(fixupSsaTimer); + Log::out() << indent(irm) << "Opt: SSA Fixup" << ::std::endl; computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); - FlowGraph& flowGraph = irm.getFlowGraph(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); MemoryManager& memoryManager = irm.getNestedMemoryManager(); DomFrontier frontier(memoryManager,*dominatorTree,&flowGraph); - SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, *irm.getCompilationContext()->getOptimizerFlags()); - bool better_ssa_fixup = irm.getParameterTable().lookupBool("opt::better_ssa_fixup", false); + SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, irm.getOptimizerFlags()); + bool better_ssa_fixup = irm.getOptimizerFlags().better_ssa_fixup; ssaBuilder.fixupSSA(irm.getMethodDesc(), better_ssa_fixup); globalSsaFixupCounter += 1; @@ -128,163 +135,62 @@ OptPass::fixupSsa(IRManager& irm) { void OptPass::splitCriticalEdges(IRManager& irm) { if(!irm.areCriticalEdgesSplit()) { - irm.getFlowGraph().splitCriticalEdges(false); + Nodes newNodes(irm.getMemoryManager()); + irm.getFlowGraph().splitCriticalEdges(false, &newNodes); + for (Nodes::const_iterator it = newNodes.begin(), end = newNodes.end(); it!=end; ++it) { + Node* node = *it; + if(node->isEmpty(false)) { + assert(node->isBlockNode() && !node->isCatchBlock()); + node->appendInst(irm.getInstFactory().makeLabel()); + } + } irm.setCriticalEdgesSplit(); } } -bool -OptPass::inDPGOMode(IRManager& irm) { - return irm.getParameterTable().lookupBool("opt::use_profile", irm.getCompilationInterface().isDynamicProfiling() - || profileCtrl.useProf() || profileCtrl.getInstrumentGen()); -} - -CompilationMode -OptPass::getCompilationMode(IRManager& irm) { - if ( irm.getCompilationContext()->getOptimizerFlags()->skip ) { - return CM_NO_OPT; - } - MethodDesc& md = irm.getMethodDesc(); - - switch(irm.getCompilationInterface().getOptimizationLevel()) { - case 0: - if (md.isClassInitializer()) { - return CM_NO_OPT; - } else { - return CM_STATIC; - } - case 1: - return inDPGOMode(irm) ? (profileCtrl.useProf() ? CM_DPGO2 : CM_DPGO1) : CM_STATIC; - case 2: - return CM_DPGO2; - default: - assert(0); - return CM_NUM_MODES; - } -} - -const char* -OptPass::getCompilationModeName(CompilationMode mode) { - switch(mode) { - case CM_NO_OPT: return "noopt"; - case CM_STATIC: return "static"; - case CM_DPGO1: return "dpgo1"; - case CM_DPGO2: return "dpgo2"; - default: break; - } - assert(0); - return NULL; -} void OptPass::initialize() { - timer = NULL; - timerName = ::std::string("opt::")+getTagName(); - for(uint32 i = 0; i < CM_NUM_MODES; ++i) { - modeTimers[i] = NULL; - modeTimerNames[i] = ::std::string("opt::")+getCompilationModeName((CompilationMode) i)+"::"+getTagName(); - } -} - -const char* -OptPass::getModeTimerName(CompilationMode mode) { - return modeTimerNames[mode].c_str(); -} - -Timer*& -OptPass::getTimer() { - return timer; } -Timer*& -OptPass::getModeTimer(CompilationMode mode) { - return modeTimers[mode]; -} bool OptPass::isProfileConsistent(IRManager& irm) { - char methodStr[MaxMethodStringLength]; - genMethodString(irm.getMethodDesc(), methodStr, MaxMethodStringLength); - return irm.getFlowGraph().isProfileConsistent(methodStr, profileCtrl.getDebugCtrl()>0); + return irm.getFlowGraph().isEdgeProfileConsistent(); } void OptPass::smoothProfile(IRManager& irm) { if (isProfileConsistent(irm) == false) { - if (profileCtrl.getDebugCtrl() > 0) - ::std::cerr << "Optimizer detects profile inconsistency! Ready for smoothing!" << ::std::endl; - irm.getFlowGraph().smoothProfile(irm.getMethodDesc()); + StaticProfiler::fixEdgeProbs(irm); + irm.getFlowGraph().smoothEdgeProfile(); } } -bool OptPass::genIRBefore(IRManager& irm) { - return Log::cat_opt()->isDebugEnabled(); -} -bool OptPass::genIRAfter(IRManager& irm) { - return Log::cat_opt()->isIR2Enabled(); -} -bool OptPass::genDotFileBefore(IRManager& irm) { - return false; -} -bool OptPass::genDotFileAfter(IRManager& irm) { - return false; -} - void OptPass::printHIR(IRManager& irm) { - FlowGraph& flowGraph = irm.getFlowGraph(); - DominatorTree* dominatorTree = irm.getDominatorTree(); - LoopTree* loopTree = irm.getLoopTree(); - - CFGNode::ChainedAnnotator annotator; - CFGNode::ProfileAnnotator profileAnnotator; - if(dominatorTree && dominatorTree->isValid()) - annotator.add(dominatorTree); - if(loopTree && loopTree->isValid()) - annotator.add(loopTree); - if(flowGraph.hasEdgeProfile()) { - annotator.add(&profileAnnotator); - } - flowGraph.printInsts(Log::out(),irm.getMethodDesc(), &annotator); + FlowGraph::printHIR(Log::log(LogStream::IRDUMP).out(), irm.getFlowGraph(), irm.getMethodDesc()); } void -OptPass::printHIR(IRManager& irm, bool condition, const char* when) { - if(condition) { - Log::printIRDumpBegin(id, getName(), when); - printHIR(irm); - Log::printIRDumpEnd(id, getName(), when); - } +OptPass::printHIR(IRManager& irm, const char* when) { + std::ostream& out = Log::log(LogStream::IRDUMP).out(); + Log::printIRDumpBegin(out, id, getName(), when); + printHIR(irm); + Log::printIRDumpEnd(out, id, getName(), when); } void -OptPass::printDotFile(IRManager& irm, const char* name) { - FlowGraph& flowGraph = irm.getFlowGraph(); - DominatorTree* dominatorTree = irm.getDominatorTree(); - flowGraph.printDotFile(irm.getMethodDesc(), name, (dominatorTree && dominatorTree->isValid()) ? dominatorTree : NULL); -} - -void OptPass::composeDotFileName(char * name, const char * suffix) -{ - name[0] = 0; - strcat(name, getTagName()); - strcat(name, "."); - char idString[10]; - sprintf(idString, "%d", (int)id); - strcat(name, idString); - strcat(name, "."); - strcat(name, suffix); +OptPass::printDotFile(IRManager& irm, int id, const char* name, const char* suffix) { + char temp[128]; + snprintf(temp, sizeof(temp), "%.2i.%s.%s", id, name, suffix); + printDotFile(irm, temp); } void -OptPass::printDotFile(IRManager& irm, bool condition, const char* suffix) { - if(condition) { - assert(strlen(getTagName()) < 30); - assert(strlen(suffix) < 30); - char name[128]; - composeDotFileName(name, suffix); - printDotFile(irm, name); - } +OptPass::printDotFile(IRManager& irm, const char* name) { + ControlFlowGraph& flowGraph = irm.getFlowGraph(); + FlowGraph::printDotFile(flowGraph, irm.getMethodDesc(), name); } const char* diff --git vm/jitrino/src/optimizer/optpass.h vm/jitrino/src/optimizer/optpass.h index c442e10..0ac0521 100644 --- vm/jitrino/src/optimizer/optpass.h +++ vm/jitrino/src/optimizer/optpass.h @@ -23,43 +23,19 @@ #ifndef _OPT_PASS_H_ #define _OPT_PASS_H_ + +#include "CompilationContext.h" +#include "PMFAction.h" + #include <string> namespace Jitrino { class IRManager; class MemoryManager; -class Timer; - -// -// Jitrino is always invoked in one of the following modes. -// -enum CompilationMode { - CM_NO_OPT, // Perform no optimizations. Used for class initializers and other cold code. - CM_STATIC, // Perform aggressive static optimizations. No profile information to be collected or used. - CM_DPGO1, // Perform 1st compile in DPGO mode. Compile conservatively and prepare for profile gathering. - CM_DPGO2, // Perform 2nd compile in DPGO mode. Compile aggressively using profile information. - CM_NUM_MODES -}; - -#define DEFINE_OPTPASS(classname) \ -class classname : public OptPass { \ -public: \ - classname(); \ - const char* getName(); \ - const char* getTagName(); \ - const char* getTimerName(); \ -protected: \ - void _run(IRManager& irm); \ -}; -#define DEFINE_OPTPASS_IMPL(classname, tagname, fullname) \ - classname::classname() { initialize(); } \ - const char* classname::getName() { return fullname; } \ - const char* classname::getTagName() { return #tagname; } \ - const char* classname::getTimerName() { return "opt::all::"#tagname; } - -class OptPass { + +class OptPass : public SessionAction { public: // // The name of this optimization pass. E.g., "Partial Redundancy Elimination" @@ -72,79 +48,59 @@ public: virtual const char* getTagName() = 0; // - // Get the compile-time timers. - // - virtual const char* getTimerName() = 0; - Timer*& getTimer(); - const char* getModeTimerName(CompilationMode mode); - Timer*& getModeTimer(CompilationMode mode); - - // // Run the pass. // - void run(IRManager& mm); - - // - // Return true if in DPGO mode. In this mode, do aggressive optimizations only when profile information is available. - // - static bool inDPGOMode(IRManager& irm); - - // - // Get the Jitrino compilation mode - // - static CompilationMode getCompilationMode(IRManager& irm); - static const char* getCompilationModeName(CompilationMode mode); + void run(); + // // Services to compute dominators, loops, ssa if necessary. // These methods only recompute if a change is detected. // static void computeDominators(IRManager& irm); - static void computeLoops(IRManager& irm); - static void computeDominatorsAndLoops(IRManager& irm); + static void computeLoops(IRManager& irm, bool normalize = true); + static void computeDominatorsAndLoops(IRManager& irm, bool normalizeLoops = true); static void fixupSsa(IRManager& irm); static void splitCriticalEdges(IRManager& irm); static bool isProfileConsistent(IRManager& irm); static void smoothProfile(IRManager& irm); static void printHIR(IRManager& irm); + static void printDotFile(IRManager& irm, int id, const char* name, const char* suffix); static void printDotFile(IRManager& irm, const char* suffix); static const char* indent(IRManager& irm); protected: - // - // Virtual dtor - to provide a correct cleanup for derived classes and - // to avoid many compiler's warnings - // - virtual ~OptPass() {}; // - // Callback to subclass to run optimization. + // Virtual dtor - to provide a correct cleanup for derived classes and + // to avoid many compiler's warnings // - virtual void _run(IRManager& irm) = 0; - + virtual ~OptPass() {}; // - // Set options to print IR & dot files + // Callback to subclass to run optimization. // - virtual bool genIRBefore(IRManager& irm); - virtual bool genIRAfter(IRManager& irm); - virtual bool genDotFileBefore(IRManager& irm); - virtual bool genDotFileAfter(IRManager& irm); + virtual void _run(IRManager& irm) = 0; - void composeDotFileName(char * name, const char * suffix); - void printHIR(IRManager& irm, bool condition, const char* when); - void printDotFile(IRManager& irm, bool condition, const char* when); + void composeDotFileName(char * name, const char * suffix); + void printHIR(IRManager& irm, const char* when); void initialize(); private: - Timer* timer; - ::std::string timerName; - Timer* modeTimers[CM_NUM_MODES]; - ::std::string modeTimerNames[CM_NUM_MODES]; - - unsigned id; + unsigned id; }; +#define DEFINE_SESSION_ACTION(classname, tagname, fullname) \ +class classname : public OptPass { \ +protected: \ + void _run(IRManager& irm); \ + const char* classname::getName() { return fullname; } \ + const char* classname::getTagName() { return #tagname; } \ +}; \ +ActionFactory<classname> tagname##_(#tagname); + + } //namespace Jitrino + #endif //_OPT_PASS_H_ diff --git vm/jitrino/src/optimizer/pidgenerator.cpp vm/jitrino/src/optimizer/pidgenerator.cpp index f554d4b..253e812 100644 --- vm/jitrino/src/optimizer/pidgenerator.cpp +++ vm/jitrino/src/optimizer/pidgenerator.cpp @@ -22,11 +22,10 @@ #include "pidgenerator.h" #include "irmanager.h" -#include "FlowGraph.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(PersistentInstIdGenerationPass, pidgen, "Persistent Instruction Id Generation Pass") +DEFINE_SESSION_ACTION(PersistentInstIdGenerationPass, pidgen, "Persistent Instruction Id Generation Pass") void PersistentInstIdGenerationPass::_run(IRManager& irm) { @@ -40,14 +39,14 @@ PersistentInstructionIdGenerator::runPas MethodDesc& methodDesc = irm.getMethodDesc(); - StlVector<CFGNode*> nodes(mm); + StlVector<Node*> nodes(mm); irm.getFlowGraph().getNodesPostOrder(nodes); - StlVector<CFGNode*>::reverse_iterator i; + StlVector<Node*>::reverse_iterator i; for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - Inst* label = node->getFirstInst(); - for(Inst* inst = label->next(); inst != label; inst = inst->next()) + Node* node = *i; + Inst* label = (Inst*)node->getFirstInst(); + for(Inst* inst = label->getNextInst(); inst != NULL; inst = inst->getNextInst()) inst->setPersistentInstructionId(PersistentInstructionId(&methodDesc, inst->getId() - irm.getMinimumInstId())); } } diff --git vm/jitrino/src/optimizer/pidgenerator.h vm/jitrino/src/optimizer/pidgenerator.h index 89794d5..c6f67d1 100644 --- vm/jitrino/src/optimizer/pidgenerator.h +++ vm/jitrino/src/optimizer/pidgenerator.h @@ -27,7 +27,6 @@ #include "optpass.h" namespace Jitrino { -DEFINE_OPTPASS(PersistentInstIdGenerationPass) class PersistentInstructionIdGenerator { public: diff --git vm/jitrino/src/optimizer/reassociate.cpp vm/jitrino/src/optimizer/reassociate.cpp index ea0e5ca..a98ad44 100644 --- vm/jitrino/src/optimizer/reassociate.cpp +++ vm/jitrino/src/optimizer/reassociate.cpp @@ -25,20 +25,19 @@ #include <iostream> #include <algorithm> #include "Stl.h" #include "Log.h" -#include "PropertyTable.h" #include "open/types.h" #include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "reassociate.h" #include "CSEHash.h" #include "Opcode.h" #include "constantfolder.h" #include "simplifier.h" +#include "FlowGraph.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(ReassociationPass, reassoc, "Reassociation") +DEFINE_SESSION_ACTION(ReassociationPass, reassoc, "Reassociation") void ReassociationPass::_run(IRManager& irm) { @@ -46,7 +45,7 @@ ReassociationPass::_run(IRManager& irm) pass.runPass(false); } -DEFINE_OPTPASS_IMPL(DepthReassociationPass, reassocdepth, "Reassociation with Minimum Depth") +DEFINE_SESSION_ACTION(DepthReassociationPass, reassocdepth, "Reassociation with Minimum Depth") void DepthReassociationPass::_run(IRManager& irm) { @@ -54,7 +53,7 @@ DepthReassociationPass::_run(IRManager& pass.runPass(true); } -DEFINE_OPTPASS_IMPL(LateDepthReassociationPass, latereassocdepth, "Reassociation with Minimum Depth + Constant Mul/Div Optimization") +DEFINE_SESSION_ACTION(LateDepthReassociationPass, latereassocdepth, "Reassociation with Minimum Depth + Constant Mul/Div Optimization") void LateDepthReassociationPass::_run(IRManager& irm) { @@ -84,34 +83,20 @@ inline bool operator < (const OpndWithPr return false; } -Reassociate::Flags *Reassociate::defaultFlags = 0; - Reassociate::Reassociate(IRManager &irManager0, - MemoryManager& memManager) + MemoryManager& memManager) : irManager(irManager0), mm(memManager), - flags(*defaultFlags), cfgRpoNum(memManager), priority(memManager), minDepth(false) { - assert(defaultFlags); } Reassociate::~Reassociate() { } -void -Reassociate::readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params) -{ - if (!defaultFlags) - defaultFlags = new Flags; -} - -void Reassociate::showFlagsFromCommandLine() -{ -} uint32 Reassociate::getPriority(Opnd *opnd) { @@ -122,80 +107,80 @@ uint32 Reassociate::getPriority(Opnd *op Opcode opc = operation.getOpcode(); switch (opc) { case Op_LdConstant: - opriority = 0; break; + opriority = 0; break; case Op_Copy: - opriority = getPriority(inst->getSrc(0)); break; + opriority = getPriority(inst->getSrc(0)); break; case Op_LdVar: - { - Opnd *var = inst->getSrc(0); - SsaVarOpnd *ssaVarOpnd = var->asSsaVarOpnd(); - assert(ssaVarOpnd); - opriority = getPriority(ssaVarOpnd); - } - break; + { + Opnd *var = inst->getSrc(0); + SsaVarOpnd *ssaVarOpnd = var->asSsaVarOpnd(); + assert(ssaVarOpnd); + opriority = getPriority(ssaVarOpnd); + } + break; case Op_Add: opriority = computePriority(costOfAdd, getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1))); - break; + break; case Op_Sub: - opriority = computePriority(costOfSub, getPriority(inst->getSrc(0)), + opriority = computePriority(costOfSub, getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1))); - break; + break; case Op_Neg: - opriority = computePriority(costOfNeg, getPriority(inst->getSrc(0))); - break; + opriority = computePriority(costOfNeg, getPriority(inst->getSrc(0))); + break; case Op_Mul: - opriority = computePriority(costOfMul, getPriority(inst->getSrc(0)), + opriority = computePriority(costOfMul, getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1))); - break; + break; case Op_Conv: - opriority = computePriority(costOfConv, getPriority(inst->getSrc(0))); - break; + opriority = computePriority(costOfConv, getPriority(inst->getSrc(0))); + break; case Op_And: case Op_Or: case Op_Xor: - opriority = computePriority(costOfBoolOp, getPriority(inst->getSrc(0)), + opriority = computePriority(costOfBoolOp, getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1))); - break; + break; case Op_Not: - opriority = computePriority(costOfNot, getPriority(inst->getSrc(0))); - break; + opriority = computePriority(costOfNot, getPriority(inst->getSrc(0))); + break; case Op_Shladd: - opriority = computePriority(costOfShladd,getPriority(inst->getSrc(0)), + opriority = computePriority(costOfShladd,getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1)), getPriority(inst->getSrc(2))); - break; + break; case Op_Shr: case Op_Shl: - opriority = computePriority(costOfShift, getPriority(inst->getSrc(0)), + opriority = computePriority(costOfShift, getPriority(inst->getSrc(0)), getPriority(inst->getSrc(1))); - break; + break; default: - if (operation.isMovable()) { - uint32 numOpnds = inst->getNumSrcOperands(); - opriority = 0; + if (operation.isMovable()) { + uint32 numOpnds = inst->getNumSrcOperands(); + opriority = 0; - for (uint32 i = 0; i<numOpnds; i++) { + for (uint32 i = 0; i<numOpnds; i++) { Opnd *opndi = inst->getSrc(i); uint32 argpriority = getPriority(opndi); opriority = ::std::max(opriority, argpriority); - } - opriority = computePriority(costOfMisc, opriority); - } else { - Inst *previ = inst->prev(); - uint32 ipriority = 1; - while (!previ->isLabel()) { - ++ipriority; - previ = previ->prev(); - } - CFGNode *block = previ->asLabelInst()->getCFGNode(); - uint32 bpriority = cfgRpoNum[block]; - opriority = ((bpriority * priorityFactorOfBlock) + } + opriority = computePriority(costOfMisc, opriority); + } else { + Inst *previ = inst->getPrevInst(); + uint32 ipriority = 1; + while (!previ->isLabel()) { + ++ipriority; + previ = previ->getPrevInst(); + } + Node *block = previ->asLabelInst()->getNode(); + uint32 bpriority = cfgRpoNum[block]; + opriority = ((bpriority * priorityFactorOfBlock) + ipriority)*priorityFactorOfPosition; - } - break; } - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + break; + } + if (Log::isEnabled()) { Log::out() << "Priority of "; opnd->print(Log::out()); Log::out() << " computed is " << (int) opriority << ::std::endl; @@ -208,59 +193,57 @@ void Reassociate::runPass(bool minimizeD { minDepth = minimizeDepth; if (minimizeDepth) { - costOfAdd = 1; - costOfSub = 1; - costOfNeg = 1; - costOfMul = 15; - costOfConv = 1; - costOfBoolOp = 1; - costOfNot = 1; - costOfShladd = 1; - costOfShift = 1; - costOfMisc = 1; - priorityFactorOfBlock = 64; - priorityFactorOfPosition = 2; + costOfAdd = 1; + costOfSub = 1; + costOfNeg = 1; + costOfMul = 15; + costOfConv = 1; + costOfBoolOp = 1; + costOfNot = 1; + costOfShladd = 1; + costOfShift = 1; + costOfMisc = 1; + priorityFactorOfBlock = 64; + priorityFactorOfPosition = 2; } else { - costOfAdd = 0; - costOfSub = 0; - costOfNeg = 0; - costOfMul = 0; - costOfConv = 0; - costOfBoolOp = 0; - costOfNot = 0; - costOfShladd = 0; - costOfShift = 0; - costOfMisc = 0; - priorityFactorOfBlock = 64; - priorityFactorOfPosition = 1; - } - - if (Log::cat_opt_reassoc()->isIR2Enabled()) { + costOfAdd = 0; + costOfSub = 0; + costOfNeg = 0; + costOfMul = 0; + costOfConv = 0; + costOfBoolOp = 0; + costOfNot = 0; + costOfShladd = 0; + costOfShift = 0; + costOfMisc = 0; + priorityFactorOfBlock = 64; + priorityFactorOfPosition = 1; + } + + if (Log::isEnabled()) { Log::out() << "IR before Reassociation pass" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); - irManager.getFlowGraph().printDotFile(irManager.getMethodDesc(), - "beforereassoc", 0); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); + FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "beforereassoc"); } // first, assign Reverse-PostOrder numbers to flowGraph nodes - StlVector<CFGNode *> postOrderNodes(mm); - FlowGraph &fg = irManager.getFlowGraph(); + StlVector<Node *> postOrderNodes(mm); + ControlFlowGraph &fg = irManager.getFlowGraph(); fg.getNodesPostOrder(postOrderNodes); - StlVector<CFGNode *>::reverse_iterator - riter = postOrderNodes.rbegin(), - rend = postOrderNodes.rend(); + StlVector<Node *>::reverse_iterator + riter = postOrderNodes.rbegin(), + rend = postOrderNodes.rend(); uint32 i = 0; while (riter != rend) { - CFGNode *node = *riter; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - Log::out() << "RPO["; - node->printLabel(Log::out()); - Log::out() << "] = " << (int) i; - Log::out() << ::std::endl; - } - cfgRpoNum[node] = i++; - ++riter; + Node *node = *riter; + if (Log::isEnabled()) { + Log::out() << "RPO["; + FlowGraph::printLabel(Log::out(), node); + Log::out() << "] = " << (int) i; + Log::out() << ::std::endl; + } + cfgRpoNum[node] = i++; + ++riter; } numBlocks = i; @@ -268,26 +251,24 @@ void Reassociate::runPass(bool minimizeD theSimp = &simplifier; simplifier.simplifyControlFlowGraph(); - if (Log::cat_opt_reassoc()->isIR2Enabled()) { + if (Log::isEnabled()) { Log::out() << "IR after Reassociation pass" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), - irManager.getMethodDesc()); - irManager.getFlowGraph().printDotFile(irManager.getMethodDesc(), - "afterreassoc", 0); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); + FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "afterreassoc"); } } void Reassociate::addAddAssoc(StlDeque<OpndWithPriority> &opnds, bool negated, - Type* type, Opnd* opnd) + Type* type, Opnd* opnd) { Inst *inst = opnd->getInst(); if (inst->getType() == type->tag) { - switch(inst->getOpcode()) { - case Op_Add: - if (inst->getOverflowModifier() != Overflow_None) break; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + switch(inst->getOpcode()) { + case Op_Add: + if (inst->getOverflowModifier() != Overflow_None) break; + if (Log::isEnabled()) { Log::out() << "addAddAssoc of operand "; opnd->print(Log::out()); Log::out() << " is Add("; @@ -296,22 +277,22 @@ Reassociate::addAddAssoc(StlDeque<OpndWi inst->getSrc(1)->print(Log::out()); Log::out() << "), checking opnds" << ::std::endl; } - addAddAssoc(opnds, negated, type, inst->getSrc(0)); - addAddAssoc(opnds, negated, type, inst->getSrc(1)); - return; - case Op_Neg: - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + addAddAssoc(opnds, negated, type, inst->getSrc(0)); + addAddAssoc(opnds, negated, type, inst->getSrc(1)); + return; + case Op_Neg: + if (Log::isEnabled()) { Log::out() << "addAddAssoc of operand "; opnd->print(Log::out()); Log::out() << " is Neg("; inst->getSrc(0)->print(Log::out()); Log::out() << "), checking opnd" << ::std::endl; } - addAddAssoc(opnds, !negated, type, inst->getSrc(0)); - return; - case Op_Sub: - if (inst->getOverflowModifier() != Overflow_None) break; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + addAddAssoc(opnds, !negated, type, inst->getSrc(0)); + return; + case Op_Sub: + if (inst->getOverflowModifier() != Overflow_None) break; + if (Log::isEnabled()) { Log::out() << "addAddAssoc of operand "; opnd->print(Log::out()); Log::out() << " is Sub("; @@ -320,24 +301,24 @@ Reassociate::addAddAssoc(StlDeque<OpndWi inst->getSrc(1)->print(Log::out()); Log::out() << "), checking opnds" << ::std::endl; } - addAddAssoc(opnds, negated, type, inst->getSrc(0)); - addAddAssoc(opnds, !negated, type, inst->getSrc(1)); - return; + addAddAssoc(opnds, negated, type, inst->getSrc(0)); + addAddAssoc(opnds, !negated, type, inst->getSrc(1)); + return; case Op_Copy: - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "addAddAssoc of operand "; opnd->print(Log::out()); Log::out() << " is Copy("; inst->getSrc(0)->print(Log::out()); Log::out() << "), checking opnd" << ::std::endl; } - addAddAssoc(opnds, negated, type, inst->getSrc(0)); - return; - default: - break; - } + addAddAssoc(opnds, negated, type, inst->getSrc(0)); + return; + default: + break; + } } - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "addAddAssoc of operand "; opnd->print(Log::out()); Log::out() << " is terminal, adding" << ::std::endl; @@ -348,22 +329,22 @@ Reassociate::addAddAssoc(StlDeque<OpndWi void Reassociate::addMulAssoc(StlDeque<OpndWithPriority> &opnds, bool negated, - Type* type, Opnd* opnd) + Type* type, Opnd* opnd) { Inst *inst = opnd->getInst(); if (inst->getType() == type->tag) { - switch(inst->getOpcode()) { - case Op_Mul: - if (inst->getOverflowModifier() != Overflow_None) break; - addMulAssoc(opnds, negated, type, inst->getSrc(0)); - addMulAssoc(opnds, negated, type, inst->getSrc(1)); - return; + switch(inst->getOpcode()) { + case Op_Mul: + if (inst->getOverflowModifier() != Overflow_None) break; + addMulAssoc(opnds, negated, type, inst->getSrc(0)); + addMulAssoc(opnds, negated, type, inst->getSrc(1)); + return; case Op_Copy: addAddAssoc(opnds, negated, type, inst->getSrc(0)); - return; - default: - break; - } + return; + default: + break; + } } opnds.push_back(OpndWithPriority(opnd, getPriority(opnd), negated)); } @@ -375,15 +356,15 @@ Reassociate::addAddOffsetAssoc(StlDeque< { Inst *inst = opnd->getInst(); if (inst->getType() == type->tag) { - switch(inst->getOpcode()) { - case Op_AddOffset: - addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(0)); - addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(1)); - return; - case Op_AddOffsetPlusHeapbase: - addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(0)); - addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(1)); - return; + switch(inst->getOpcode()) { + case Op_AddOffset: + addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(0)); + addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(1)); + return; + case Op_AddOffsetPlusHeapbase: + addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(0)); + addAddOffsetAssoc(opnds, compressed, type, inst->getSrc(1)); + return; case Op_UncompressRef: case Op_CompressRef: case Op_Copy: @@ -395,9 +376,9 @@ Reassociate::addAddOffsetAssoc(StlDeque< case Op_AddScaledIndex: case Op_ScaledDiffRef: case Op_TauArrayLen: - default: - break; - } + default: + break; + } } opnds.push_back(OpndWithPriority(opnd, getPriority(opnd), compressed)); } @@ -406,24 +387,24 @@ Reassociate::addAddOffsetAssoc(StlDeque< // maybe this stuff should be in simplifier. Opnd* Reassociate::simplifyReassociatedAdd(Type *type, - StlDeque<OpndWithPriority> &opnds) + StlDeque<OpndWithPriority> &opnds) { typedef StlDeque<OpndWithPriority> VectType; ::std::sort(opnds.begin(), opnds.end()); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - VectType::iterator - iter = opnds.begin(), - end = opnds.end(); - Log::out() << "BEGIN simplifyReassociatedAdd: "; - for ( ; iter != end ; iter++) { - OpndWithPriority &owd = *iter; - Log::out() << (owd.negate ? "-" : "+") << "("; - owd.opnd->print(Log::out()); - Log::out() << ", " << (int)owd.priority << ") "; - } - Log::out() << ::std::endl; + if (Log::isEnabled()) { + VectType::iterator + iter = opnds.begin(), + end = opnds.end(); + Log::out() << "BEGIN simplifyReassociatedAdd: "; + for ( ; iter != end ; iter++) { + OpndWithPriority &owd = *iter; + Log::out() << (owd.negate ? "-" : "+") << "("; + owd.opnd->print(Log::out()); + Log::out() << ", " << (int)owd.priority << ") "; + } + Log::out() << ::std::endl; } // algorithm: @@ -505,7 +486,7 @@ Reassociate::simplifyReassociatedAdd(Typ OpndWithPriority newelt(newOpnd, newPriority, newNegated); opnds.push_front(newelt); size += 1; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " new " << (newNegated ? "-" : "+") << "("; newOpnd->print(Log::out()); Log::out() << ", " << (int) newPriority << ") = " << debug_op << "("; @@ -530,42 +511,42 @@ Reassociate::simplifyReassociatedAdd(Typ assert(opnds[0].negate); // need to neg result Opnd *newres = theSimp->genNeg(type, res)->getDst(); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " negated: "; newres->print(Log::out()); Log::out() << " = neg("; res->print(Log::out()); Log::out() << ")" << ::std::endl; } - res = newres; + res = newres; } else { assert(!opnds[0].negate); } - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - Log::out() << "FINISHED simplifyReassociatedAdd: "; - res->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "FINISHED simplifyReassociatedAdd: "; + res->print(Log::out()); + Log::out() << ::std::endl; } return res; } Opnd* Reassociate::simplifyReassociatedMul(Type *type, - StlDeque<OpndWithPriority> &opnds) + StlDeque<OpndWithPriority> &opnds) { typedef StlDeque<OpndWithPriority> VectType; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - VectType::iterator - iter = opnds.begin(), - end = opnds.end(); - Log::out() << "BEGIN simplifyReassociatedMul: "; - for ( ; iter != end ; iter++) { - OpndWithPriority &owd = *iter; - Log::out() << "("; - owd.opnd->print(Log::out()); - Log::out() << ", " << (int)owd.priority << ") "; - } - Log::out() << ::std::endl; + if (Log::isEnabled()) { + VectType::iterator + iter = opnds.begin(), + end = opnds.end(); + Log::out() << "BEGIN simplifyReassociatedMul: "; + for ( ; iter != end ; iter++) { + OpndWithPriority &owd = *iter; + Log::out() << "("; + owd.opnd->print(Log::out()); + Log::out() << ", " << (int)owd.priority << ") "; + } + Log::out() << ::std::endl; } ::std::sort(opnds.begin(), opnds.end()); @@ -610,7 +591,7 @@ Reassociate::simplifyReassociatedMul(Typ false // negs negate each other ); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " new ("; newOpnd1->print(Log::out()); Log::out() << ", " << (int) priorityNew1 << ") = sqr(mul("; @@ -639,7 +620,7 @@ Reassociate::simplifyReassociatedMul(Typ uint32 priority = computePriority(costOfMul, priority0, priority1); OpndWithPriority newelt(newOpnd, priority, neg0 ^ neg1); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " new ("; newOpnd->print(Log::out()); Log::out() << ", " << (int) priority << ") = mul(("; @@ -660,15 +641,15 @@ Reassociate::simplifyReassociatedMul(Typ break; } } - } } - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - VectType::iterator - iter = opnds.begin(), - end = opnds.end(); - Log::out() << "FINISHED simplifyReassociatedMul: "; - opnds[0].opnd->print(Log::out()); - Log::out() << ::std::endl; + } + if (Log::isEnabled()) { + VectType::iterator + iter = opnds.begin(), + end = opnds.end(); + Log::out() << "FINISHED simplifyReassociatedMul: "; + opnds[0].opnd->print(Log::out()); + Log::out() << ::std::endl; } return opnds[0].opnd; } @@ -681,18 +662,18 @@ Reassociate::simplifyReassociatedAddOffs ::std::sort(opnds.begin(), opnds.end()); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - VectType::iterator - iter = opnds.begin(), - end = opnds.end(); - Log::out() << "BEGIN simplifyReassociatedAddOffset: "; - for ( ; iter != end ; iter++) { - OpndWithPriority &owd = *iter; - Log::out() << (owd.negate ? "-" : "+") << "("; - owd.opnd->print(Log::out()); - Log::out() << ", " << (int)owd.priority << ") "; - } - Log::out() << ::std::endl; + if (Log::isEnabled()) { + VectType::iterator + iter = opnds.begin(), + end = opnds.end(); + Log::out() << "BEGIN simplifyReassociatedAddOffset: "; + for ( ; iter != end ; iter++) { + OpndWithPriority &owd = *iter; + Log::out() << (owd.negate ? "-" : "+") << "("; + owd.opnd->print(Log::out()); + Log::out() << ", " << (int)owd.priority << ") "; + } + Log::out() << ::std::endl; } assert(0); @@ -776,7 +757,7 @@ Reassociate::simplifyReassociatedAddOffs OpndWithPriority newelt(newOpnd, newPriority, newNegated); opnds.push_front(newelt); size += 1; - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " new " << (newNegated ? "-" : "+") << "("; newOpnd->print(Log::out()); Log::out() << ", " << (int) newPriority << ") = " << debug_op << "("; @@ -801,21 +782,21 @@ Reassociate::simplifyReassociatedAddOffs assert(opnds[0].negate); // need to neg result Opnd *newres = theSimp->genNeg(type, res)->getDst(); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " negated: "; newres->print(Log::out()); Log::out() << " = neg("; res->print(Log::out()); Log::out() << ")" << ::std::endl; } - res = newres; + res = newres; } else { assert(!opnds[0].negate); } - if (Log::cat_opt_reassoc()->isDebugEnabled()) { - Log::out() << "FINISHED simplifyReassociatedAdd: "; - res->print(Log::out()); - Log::out() << ::std::endl; + if (Log::isEnabled()) { + Log::out() << "FINISHED simplifyReassociatedAdd: "; + res->print(Log::out()); + Log::out() << ::std::endl; } return res; } @@ -828,7 +809,7 @@ Simplifier::simplifyAddViaReassociation2 assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifyAddViaReassociation2 Add("; src1->print(Log::out()); Log::out() << ", "; @@ -848,7 +829,7 @@ Simplifier::simplifyNegViaReassociation2 assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifyNegViaReassociation2 Neg("; src1->print(Log::out()); Log::out() << "): " << ::std::endl; @@ -865,7 +846,7 @@ Simplifier::simplifySubViaReassociation2 assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifySubViaReassociation2 Sub("; src1->print(Log::out()); Log::out() << ", "; @@ -885,7 +866,7 @@ Simplifier::simplifyMulViaReassociation2 assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifyMulViaReassociation2 Mul("; src1->print(Log::out()); Log::out() << ", "; @@ -906,7 +887,7 @@ Simplifier::simplifyAddOffsetViaReassoci assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifyAddOffsetViaReassociation AddOffset("; uncompBase->print(Log::out()); Log::out() << ", "; @@ -926,7 +907,7 @@ Simplifier::simplifyAddOffsetPlusHeapbas assert(theReassociate); StlDeque<OpndWithPriority> opnds(theReassociate->mm); - if (Log::cat_opt_reassoc()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "simplifyAddViaReassociation2 Add("; compBase->print(Log::out()); Log::out() << ", "; diff --git vm/jitrino/src/optimizer/reassociate.h vm/jitrino/src/optimizer/reassociate.h index da8c9e7..79fae16 100644 --- vm/jitrino/src/optimizer/reassociate.h +++ vm/jitrino/src/optimizer/reassociate.h @@ -26,11 +26,12 @@ #define _REASSOCIATE_H #include <iostream> #include "open/types.h" #include "Opcode.h" -#include "FlowGraph.h" #include "Stl.h" #include "optpass.h" #include <utility> +#include "ControlFlowGraph.h" + namespace Jitrino { class IRManager; @@ -38,8 +39,7 @@ class MemoryManager; class InequalityGraph; class DominatorNode; class Dominator; -class JitrinoParameterTable; -class CFGNode; +class Node; class Opnd; class CSEHashTable; class Type; @@ -55,14 +55,6 @@ struct OpndWithPriority { }; bool operator < (const OpndWithPriority &a, const OpndWithPriority &b); -DEFINE_OPTPASS(ReassociationPass) - -DEFINE_OPTPASS(DepthReassociationPass) - -DEFINE_OPTPASS(LateDepthReassociationPass) - -class Simplifier; - // // Try to re-associate expressions to either // - reduce expression height @@ -72,17 +64,12 @@ class Reassociate { IRManager& irManager; MemoryManager &mm; public: - struct Flags { - }; + private: - static Flags *defaultFlags; - Flags flags; public: - static void readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params); - static void showFlagsFromCommandLine(); - + Reassociate(IRManager &irManager0, - MemoryManager& memManager); + MemoryManager& memManager); ~Reassociate(); @@ -97,18 +84,18 @@ private: void addAddAssoc(StlDeque<OpndWithPriority> &opnds, bool negated, - Type* type, Opnd* opnd); + Type* type, Opnd* opnd); void addMulAssoc(StlDeque<OpndWithPriority> &opnds, bool negated, - Type* type, Opnd* opnd); + Type* type, Opnd* opnd); void addAddOffsetAssoc(StlDeque<OpndWithPriority> &opnds, bool compressed, Type* type, Opnd* opnd); Opnd* simplifyReassociatedAdd(Type *type, - StlDeque<OpndWithPriority> &opnds); + StlDeque<OpndWithPriority> &opnds); Opnd* simplifyReassociatedMul(Type *type, - StlDeque<OpndWithPriority> &opnds); + StlDeque<OpndWithPriority> &opnds); Opnd* simplifyMulViaReassociation2(Type* type, Opnd* src1, Opnd* src2); @@ -120,7 +107,7 @@ private: private: // we compute Reverse-Postorder numbers for CFGnodes: - StlHashMap<CFGNode *, uint32> cfgRpoNum; + StlHashMap<Node *, uint32> cfgRpoNum; StlHashMap<Opnd *, uint32> priority; uint32 getPriority(Opnd *opnd); // computes if not in the hash map @@ -130,8 +117,8 @@ private: uint32 costOfAdd, costOfSub, costOfNeg, costOfMul, costOfConv, costOfBoolOp, - costOfNot, costOfShladd, costOfShift, costOfMisc, - priorityFactorOfBlock, priorityFactorOfPosition; + costOfNot, costOfShladd, costOfShift, costOfMisc, + priorityFactorOfBlock, priorityFactorOfPosition; uint32 numBlocks; bool minDepth; diff --git vm/jitrino/src/optimizer/simplifier.cpp vm/jitrino/src/optimizer/simplifier.cpp index f02f977..c173075 100644 --- vm/jitrino/src/optimizer/simplifier.cpp +++ vm/jitrino/src/optimizer/simplifier.cpp @@ -24,9 +24,7 @@ #include "Opcode.h" #include "Opnd.h" #include "Type.h" #include "Inst.h" -#include "IRBuilder.h" #include "BitSet.h" -#include "FlowGraph.h" #include "Log.h" #include "optimizer.h" #include "simplifier.h" @@ -37,6 +35,8 @@ #include "reassociate.h" #include "irmanager.h" #include "CompilationContext.h" +#include "FlowGraph.h" + #include <float.h> #include <math.h> @@ -63,15 +63,14 @@ inline bool isnan(double s) { #endif -DEFINE_OPTPASS_IMPL(SimplificationPass, simplify, "Simplification") - +DEFINE_SESSION_ACTION(SimplificationPass, simplify, "Perform simplification pass"); void SimplificationPass::_run(IRManager& irm) { SimplifierWithInstFactory simplifier(irm, false); simplifier.simplifyControlFlowGraph(); } -DEFINE_OPTPASS_IMPL(LateSimplificationPass, latesimplify, "Simplification + Constant Mul/Div Optimization") +DEFINE_SESSION_ACTION(LateSimplificationPass, latesimplify, "Simplification + Constant Mul/Div Optimization"); void LateSimplificationPass::_run(IRManager& irm) { @@ -138,10 +137,10 @@ Simplifier::isNonNullObject(Opnd* opnd) Inst* inst = opnd->getInst(); switch (inst->getOpcode()) { case Op_NewObj: case Op_NewArray: case Op_NewMultiArray: - case Op_Box: case Op_LdString: case Op_Catch: + case Op_Box: case Op_LdRef: case Op_Catch: return true; default: - return false; + return false; } } @@ -168,19 +167,19 @@ Simplifier::isExactType(Opnd* opnd) { Inst* inst = opnd->getInst(); switch (inst->getOpcode()) { case Op_NewObj: case Op_NewArray: case Op_NewMultiArray: - case Op_Box: case Op_LdString: + case Op_Box: case Op_LdRef: return true; case Op_DefArg: return (inst->getDefArgModifier() == SpecializedToExactType); default: - return false; + return false; } } //----------------------------------------------------------------------------- // Simplifier class //----------------------------------------------------------------------------- Simplifier::Simplifier(IRManager& irm, bool latePass, - Reassociate *reassociate0) + Reassociate *reassociate0) : irManager(irm), flowGraph(irm.getFlowGraph()), isLate(latePass), theReassociate(reassociate0) { @@ -389,7 +388,7 @@ Simplifier::foldConstMultiplyBySubWithCo #ifndef NDEBUG bool foldres = #endif - ConstantFolder::foldConstant(type->tag, Op_Mul, + ConstantFolder::foldConstant(type->tag, Op_Mul, constInst->getValue(), // c1 otherConstInst->getValue(), // c2 res, @@ -399,7 +398,7 @@ #endif #ifndef NDEBUG foldres = #endif - ConstantFolder::foldConstant(type->tag, Op_Neg, res, negRes); + ConstantFolder::foldConstant(type->tag, Op_Neg, res, negRes); assert(foldres); if (type->tag == Type::Int32) { negFoldedConst = genLdConstant(negRes.i4)->getDst(); @@ -765,9 +764,9 @@ Simplifier::simplifyAdd(Type* type, return opnd; // if (theReassociate) { - opnd = simplifyAddViaReassociation2(type, src1, src2); - if (opnd != NULL) - return opnd; + opnd = simplifyAddViaReassociation2(type, src1, src2); + if (opnd != NULL) + return opnd; } // return NULL; @@ -836,14 +835,14 @@ Simplifier::simplifySub(Type* type, Modi return opnd; if (theReassociate) { - opnd = simplifySubViaReassociation2(type, src1, src2); - if (opnd != NULL) - return opnd; + opnd = simplifySubViaReassociation2(type, src1, src2); + if (opnd != NULL) + return opnd; } opnd = simplifySubViaReassociation(type, src1, src2); if (opnd != NULL) - return opnd; + return opnd; return NULL; @@ -878,9 +877,9 @@ Simplifier::simplifyNeg(Type* type, Opnd } if (theReassociate) { - Opnd *opnd = simplifyNegViaReassociation2(type, src); - if (opnd != NULL) - return opnd; + Opnd *opnd = simplifyNegViaReassociation2(type, src); + if (opnd != NULL) + return opnd; } return NULL; @@ -925,10 +924,10 @@ Simplifier::simplifyAnd(Type* theType, O src2->getInst()->asConstInst(), true); - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); // check for And of 0xff with zxt/sxt:i1, etc. if (optimizerFlags.do_sxt && - (ConstantFolder::isConstant(src1) || ConstantFolder::isConstant(src2))) { + (ConstantFolder::isConstant(src1) || ConstantFolder::isConstant(src2))) { Inst *inst2 = src2->getInst(); Type::Tag typeTag2 = inst2->getType(); Inst *inst1 = src1->getInst(); @@ -940,73 +939,73 @@ Simplifier::simplifyAnd(Type* theType, O (((typeTag2 == Type::Int8) && (((uint64)val64) <= 0xff)) || ((typeTag2 == Type::Int16) && (((uint64)val64) <= 0xffff)) || ((typeTag2 == Type::Int32) && (((uint64)val64) <= 0xffffffff)))) { - Opnd *src2opnd = inst2->getSrc(0); - if (src2opnd->getType() == src2->getType()) { - return genAnd(theType, src1, src2opnd)->getDst(); - } - } else if (ConstantFolder::isConstant(src2->getInst(), val64) && - (inst1->getOpcode() == Op_Conv) && - (((typeTag1 == Type::Int8) && (((uint64)val64) <= 0xff)) || - ((typeTag2 == Type::Int16) && (((uint64)val64) <= 0xffff)) || - ((typeTag2 == Type::Int32) && (((uint64)val64) <= 0xffffffff)))) { - Opnd *src1opnd = inst1->getSrc(0); - if (src1opnd->getType() == src1->getType()) { - return genAnd(theType, src1opnd, src2)->getDst(); - } - } else if (ConstantFolder::isConstant(src1->getInst(), val32) && - (inst2->getOpcode() == Op_Conv) && - (((typeTag2 == Type::Int8) && (((uint32)val32) <= 0xff)) || - ((typeTag2 == Type::Int16) && (((uint32)val32) <= 0xffff)) || - ((typeTag2 == Type::Int32) && (((uint32)val32) <= 0xffffffff)))) { - Opnd *src2opnd = inst2->getSrc(0); - if (src2opnd->getType() == src2->getType()) { - return genAnd(theType, src1, src2opnd)->getDst(); - } - } else if (ConstantFolder::isConstant(src2->getInst(), val32) && - (inst1->getOpcode() == Op_Conv) && - (((typeTag1 == Type::Int8) && (((uint32)val32) <= 0xff)) || - ((typeTag2 == Type::Int16) && (((uint32)val32) <= 0xffff)) || - ((typeTag2 == Type::Int32) && (((uint32)val32) <= 0xffffffff)))) { - Opnd *src1opnd = inst1->getSrc(0); - if (src1opnd->getType() == src1->getType()) { - return genAnd(theType, src1opnd, src2)->getDst(); - } - } - - // check for And of 0xff with ld.u1, etc. + Opnd *src2opnd = inst2->getSrc(0); + if (src2opnd->getType() == src2->getType()) { + return genAnd(theType, src1, src2opnd)->getDst(); + } + } else if (ConstantFolder::isConstant(src2->getInst(), val64) && + (inst1->getOpcode() == Op_Conv) && + (((typeTag1 == Type::Int8) && (((uint64)val64) <= 0xff)) || + ((typeTag2 == Type::Int16) && (((uint64)val64) <= 0xffff)) || + ((typeTag2 == Type::Int32) && (((uint64)val64) <= 0xffffffff)))) { + Opnd *src1opnd = inst1->getSrc(0); + if (src1opnd->getType() == src1->getType()) { + return genAnd(theType, src1opnd, src2)->getDst(); + } + } else if (ConstantFolder::isConstant(src1->getInst(), val32) && + (inst2->getOpcode() == Op_Conv) && + (((typeTag2 == Type::Int8) && (((uint32)val32) <= 0xff)) || + ((typeTag2 == Type::Int16) && (((uint32)val32) <= 0xffff)) || + ((typeTag2 == Type::Int32) && (((uint32)val32) <= 0xffffffff)))) { + Opnd *src2opnd = inst2->getSrc(0); + if (src2opnd->getType() == src2->getType()) { + return genAnd(theType, src1, src2opnd)->getDst(); + } + } else if (ConstantFolder::isConstant(src2->getInst(), val32) && + (inst1->getOpcode() == Op_Conv) && + (((typeTag1 == Type::Int8) && (((uint32)val32) <= 0xff)) || + ((typeTag2 == Type::Int16) && (((uint32)val32) <= 0xffff)) || + ((typeTag2 == Type::Int32) && (((uint32)val32) <= 0xffffffff)))) { + Opnd *src1opnd = inst1->getSrc(0); + if (src1opnd->getType() == src1->getType()) { + return genAnd(theType, src1opnd, src2)->getDst(); + } + } + + // check for And of 0xff with ld.u1, etc. if (ConstantFolder::isConstant(src1->getInst(), val64) && (inst2->getOpcode() == Op_TauLdInd) && (((typeTag2 == Type::UInt8) && (((uint64)val64) == 0xff)) || ((typeTag2 == Type::UInt16) && (((uint64)val64) == 0xffff)) || ((typeTag2 == Type::UInt32) && (((uint64)val64) == 0xffffffff)))) { - if (theType == src2->getType()) { - return src2; - } - } else if (ConstantFolder::isConstant(src2->getInst(), val64) && - (inst1->getOpcode() == Op_TauLdInd) && - (((typeTag1 == Type::UInt8) && (((uint64)val64) == 0xff)) || - ((typeTag2 == Type::UInt16) && (((uint64)val64) == 0xffff)) || - ((typeTag2 == Type::UInt32) && (((uint64)val64) == 0xffffffff)))) { - if (theType == src1->getType()) { - return src1; - } - } else if (ConstantFolder::isConstant(src1->getInst(), val32) && - (inst2->getOpcode() == Op_TauLdInd) && - (((typeTag2 == Type::UInt8) && (((uint32)val32) == 0xff)) || - ((typeTag2 == Type::UInt16) && (((uint32)val32) == 0xffff)) || - ((typeTag2 == Type::UInt32) && (((uint32)val32) == 0xffffffff)))) { - if (theType == src2->getType()) { - return src2; - } - } else if (ConstantFolder::isConstant(src2->getInst(), val32) && - (inst1->getOpcode() == Op_TauLdInd) && - (((typeTag1 == Type::UInt8) && (((uint32)val32) == 0xff)) || - ((typeTag2 == Type::UInt16) && (((uint32)val32) == 0xffff)) || - ((typeTag2 == Type::UInt32) && (((uint32)val32) == 0xffffffff)))) { - if (theType == src1->getType()) { - return src1; - } - } + if (theType == src2->getType()) { + return src2; + } + } else if (ConstantFolder::isConstant(src2->getInst(), val64) && + (inst1->getOpcode() == Op_TauLdInd) && + (((typeTag1 == Type::UInt8) && (((uint64)val64) == 0xff)) || + ((typeTag2 == Type::UInt16) && (((uint64)val64) == 0xffff)) || + ((typeTag2 == Type::UInt32) && (((uint64)val64) == 0xffffffff)))) { + if (theType == src1->getType()) { + return src1; + } + } else if (ConstantFolder::isConstant(src1->getInst(), val32) && + (inst2->getOpcode() == Op_TauLdInd) && + (((typeTag2 == Type::UInt8) && (((uint32)val32) == 0xff)) || + ((typeTag2 == Type::UInt16) && (((uint32)val32) == 0xffff)) || + ((typeTag2 == Type::UInt32) && (((uint32)val32) == 0xffffffff)))) { + if (theType == src2->getType()) { + return src2; + } + } else if (ConstantFolder::isConstant(src2->getInst(), val32) && + (inst1->getOpcode() == Op_TauLdInd) && + (((typeTag1 == Type::UInt8) && (((uint32)val32) == 0xff)) || + ((typeTag2 == Type::UInt16) && (((uint32)val32) == 0xffff)) || + ((typeTag2 == Type::UInt32) && (((uint32)val32) == 0xffffffff)))) { + if (theType == src1->getType()) { + return src1; + } + } } return NULL; } @@ -1020,8 +1019,8 @@ Simplifier::simplifyOr(Type* theType, Op // if (src1 == src2) return src1; - // - // 0 | s2 -> s2 + // + // 0 | s2 -> s2 // if (ConstantFolder::isConstantZero(src1)) return src2; @@ -1208,14 +1207,14 @@ Simplifier::simplifyMul(Type* type, bool t = ConstantFolder::isConstant(src1->getInst(), multiplier); if( !t) assert(0); - Opnd *product = planMul32(multiplier, src2); + Opnd *product = planMul32(multiplier, src2); return product; } else { // src2isConstant int32 multiplier; bool t = ConstantFolder::isConstant(src2->getInst(), multiplier); if( !t) assert(0); - Opnd *product = planMul32(multiplier, src1); + Opnd *product = planMul32(multiplier, src1); return product; } @@ -1226,14 +1225,14 @@ Simplifier::simplifyMul(Type* type, bool t = ConstantFolder::isConstant(src1->getInst(), multiplier); if( !t) assert(0); - Opnd *product = planMul64(multiplier, src2); + Opnd *product = planMul64(multiplier, src2); return product; } else { // src2isConstant int64 multiplier; bool t = ConstantFolder::isConstant(src2->getInst(), multiplier); if( !t) assert(0); - Opnd *product = planMul64(multiplier, src1); + Opnd *product = planMul64(multiplier, src1); return product; } @@ -1267,9 +1266,9 @@ Simplifier::simplifyMul(Type* type, return opnd; // if (theReassociate) { - opnd = simplifyMulViaReassociation2(type, src1, src2); - if (opnd != NULL) - return opnd; + opnd = simplifyMulViaReassociation2(type, src1, src2); + if (opnd != NULL) + return opnd; } // return NULL; @@ -1346,7 +1345,7 @@ Simplifier::simplifyMulHi(Type* type, bool t = ConstantFolder::isConstant(src1->getInst(), multiplier); if( !t) assert(0); - Type *dstType64 = tm.getInt64Type(); + Type *dstType64 = tm.getInt64Type(); Opnd *src2_64 = genConv(dstType64, (isSigned ? Type::Int64 : Type::UInt64), @@ -1365,7 +1364,7 @@ Simplifier::simplifyMulHi(Type* type, int32 multiplier; bool t = ConstantFolder::isConstant(src2->getInst(), multiplier); - if( !t) assert(0); + if( !t) assert(0); TypeManager &tm = irManager.getTypeManager(); Type *dstType64 = tm.getInt64Type(); Opnd *src1_64 = genConv(dstType64, @@ -1458,7 +1457,7 @@ Simplifier::simplifyTauDiv(Type* dstType mod.isSigned()); #ifdef _IPF_ - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); // // further ops only for integers // @@ -1583,7 +1582,7 @@ #ifdef _IPF_ } } #endif - return NULL; + return NULL; } Opnd* @@ -1606,7 +1605,7 @@ Simplifier::simplifyTauRem(Type* dstType src2->getInst()->asConstInst(), mod.isSigned()); #ifdef _IPF_ - // + // // don't simplify floating point further // switch (dstType->tag) { @@ -1724,29 +1723,29 @@ Simplifier::simplifyConv(Type* dstType, return genLdConstant(dstType, res)->getDst(); } } - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.do_sxt && (opndInst->getOpcode() == Op_And)) { assert(opndInst->getNumSrcOperands() == 2); Opnd *src0 = opndInst->getSrc(0); Opnd *src1 = opndInst->getSrc(1); - int64 val64; - // and with 0xff makes Conv(u8) redundant, etc.. - if (ConstantFolder::isConstant(src0->getInst(), val64) && - (((toType == Type::UInt8) - && (((uint64)val64) <= 0xff)) || + int64 val64; + // and with 0xff makes Conv(u8) redundant, etc.. + if (ConstantFolder::isConstant(src0->getInst(), val64) && + (((toType == Type::UInt8) + && (((uint64)val64) <= 0xff)) || ((toType == Type::Int8) && (((uint64)val64) <= 0x7f)) || - ((toType == Type::UInt16) - && (((uint64)val64) <= 0x7fff)) || - ((toType == Type::Int16) - && (((uint64)val64) <= 0xffff)) || - ((toType == Type::UInt32) - && (((uint64)val64) <= 0xffffffff)) || - ((toType == Type::Int32) - && (((uint64)val64) <= 0x7fffffff)))) { - if (dstType == src->getType()) - return src; - } else if (ConstantFolder::isConstant(src1->getInst(), val64) && + ((toType == Type::UInt16) + && (((uint64)val64) <= 0x7fff)) || + ((toType == Type::Int16) + && (((uint64)val64) <= 0xffff)) || + ((toType == Type::UInt32) + && (((uint64)val64) <= 0xffffffff)) || + ((toType == Type::Int32) + && (((uint64)val64) <= 0x7fffffff)))) { + if (dstType == src->getType()) + return src; + } else if (ConstantFolder::isConstant(src1->getInst(), val64) && (((toType == Type::UInt8) && (((uint64)val64) <= 0xff)) || ((toType == Type::Int8) @@ -1759,41 +1758,41 @@ Simplifier::simplifyConv(Type* dstType, && (((uint64)val64) <= 0xffffffff)) || ((toType == Type::Int32) && (((uint64)val64) <= 0x7fffffff)))) { - if (dstType == src->getType()) - return src; - } - int32 val32; - if (ConstantFolder::isConstant(src0->getInst(), val32) && - (((toType == Type::UInt8) - && (((uint32)val32) <= 0xff)) || + if (dstType == src->getType()) + return src; + } + int32 val32; + if (ConstantFolder::isConstant(src0->getInst(), val32) && + (((toType == Type::UInt8) + && (((uint32)val32) <= 0xff)) || ((toType == Type::Int8) - && (((uint32)val32) <= 0x7f)) || - ((toType == Type::UInt16) - && (((uint32)val32) <= 0xffff)) || - ((toType == Type::Int16) - && (((uint32)val32) <= 0x7fff)) || - ((toType == Type::UInt32) - && (((uint32)val32) <= 0xffffffff)) || - ((toType == Type::Int32) - && (((uint32)val32) <= 0x7fffffff)))) { - if (dstType == src->getType()) - return src; - } else if (ConstantFolder::isConstant(src1->getInst(), val32) && - (((toType == Type::UInt8) - && (((uint32)val32) <= 0xff)) || + && (((uint32)val32) <= 0x7f)) || + ((toType == Type::UInt16) + && (((uint32)val32) <= 0xffff)) || + ((toType == Type::Int16) + && (((uint32)val32) <= 0x7fff)) || + ((toType == Type::UInt32) + && (((uint32)val32) <= 0xffffffff)) || + ((toType == Type::Int32) + && (((uint32)val32) <= 0x7fffffff)))) { + if (dstType == src->getType()) + return src; + } else if (ConstantFolder::isConstant(src1->getInst(), val32) && + (((toType == Type::UInt8) + && (((uint32)val32) <= 0xff)) || ((toType == Type::Int8) && (((uint32)val32) <= 0x7f)) || - ((toType == Type::UInt16) - && (((uint32)val32) <= 0xffff)) || - ((toType == Type::Int16) - && (((uint32)val32) <= 0x7fff)) || - ((toType == Type::UInt32) - && (((uint32)val32) <= 0xffffffff)) || - ((toType == Type::Int32) - && (((uint32)val32) <= 0x7fffffff)))) { - if (dstType == src->getType()) - return src; - } + ((toType == Type::UInt16) + && (((uint32)val32) <= 0xffff)) || + ((toType == Type::Int16) + && (((uint32)val32) <= 0x7fff)) || + ((toType == Type::UInt32) + && (((uint32)val32) <= 0xffffffff)) || + ((toType == Type::Int32) + && (((uint32)val32) <= 0x7fffffff)))) { + if (dstType == src->getType()) + return src; + } } @@ -2345,13 +2344,13 @@ Simplifier::simplifyCmpOfCmp3(Type::Tag // 0 != test return simplifyCmp3ByResult(src2, true, false, true, newInstType, newmod, newSrc1, newSrc2); - } else if (((val == 1) && (mod == Cmp_NE_Un)) || - ((val == 0) && (mod == Cmp_GTE))) { - // 1 != test - // 0 >= test + } else if (((val == 1) && (mod == Cmp_NE_Un)) || + ((val == 0) && (mod == Cmp_GTE))) { + // 1 != test + // 0 >= test return simplifyCmp3ByResult(src2, true, true, false, newInstType, newmod, newSrc1, newSrc2); - } + } } } return false; @@ -2625,7 +2624,7 @@ Simplifier::simplifyCmpToCmp(Type::Tag i Opnd* &newSrc2) { ConstInst::ConstValue valC; - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.elim_cmp3 && (instType == Type::Int32) && simplifyCmpOfCmp3(instType, mod, src1, src2, newInstType, newmod, newSrc1, newSrc2)) { @@ -2724,8 +2723,8 @@ Simplifier::canFoldBranch(Type::Tag inst case Cmp_GT_Un: isTaken = false; return true; - default: - break; + default: + break; } } return false; @@ -2841,7 +2840,7 @@ Simplifier::simplifyTauCheckNull(Opnd* o return genTauIsNonNull(opnd)->getDst(); // is safe, but only in method } if (isNullObject(opnd)) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "CheckNull of src "; opnd->print(Log::out()); Log::out() << " always throws" << ::std::endl; @@ -2871,7 +2870,7 @@ Simplifier::simplifyTauCheckBounds(Opnd* return genTauSafe()->getDst(); // is safe by construction } else { // fold to a throwSystemId - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checkbounds of arrayLen "; arrayLen->print(Log::out()); Log::out() << " and index "; @@ -2905,7 +2904,7 @@ Simplifier::simplifyTauCheckLowerBound(O result)) { if (result == 1) { // fold to a throwSystemId - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "CheckLowerBound of lb "; lb->print(Log::out()); Log::out() << " and index "; @@ -2949,7 +2948,7 @@ Simplifier::simplifyTauCheckUpperBound(O return genTauSafe()->getDst(); // check is safe by construction } else { // fold to a throwSystemId - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "CheckUpperBound of idx "; idx->print(Log::out()); Log::out() << " and ub "; @@ -2979,7 +2978,7 @@ Simplifier::simplifyTauCheckZero(Opnd* o if (value != 0) return genTauSafe()->getDst(); // check is safe by construction else { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "CheckZero of opnd "; opnd->print(Log::out()); Log::out()<< " always throws" << ::std::endl; @@ -3229,7 +3228,7 @@ Simplifier::simplifyCompressRef(Opnd* op Opnd* Simplifier::simplifyAddOffset(Type *ptrType, Opnd* uncompBase, Opnd *offset) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.reduce_compref) { Inst *uncompBaseInst = uncompBase->getInst(); if (uncompBaseInst->getOpcode() == Op_UncompressRef) { @@ -3284,7 +3283,7 @@ Opnd* Simplifier::simplifyAddOffsetPlusHeapbase(Type *ptrType, Opnd* compBase, Opnd *offsetPlusHeapbase) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (0 && optimizerFlags.reduce_compref && theReassociate) { Opnd *opnd = simplifyAddOffsetPlusHeapbaseViaReassociation(compBase, offsetPlusHeapbase); @@ -3312,7 +3311,7 @@ SimplifierWithInstFactory::simplifyStore return srcisrc; } - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (compressRef && optimizerFlags.reduce_compref && @@ -3338,7 +3337,7 @@ SimplifierWithInstFactory::simplifyStore void Simplifier::simplifyTauStStatic(Inst *inst) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Trying to simplify TauStStatic: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -3361,7 +3360,7 @@ Simplifier::simplifyTauStStatic(Inst *in void Simplifier::simplifyTauStField(Inst *inst) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Trying to simplify StField: "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -3447,30 +3446,30 @@ Opnd * Simplifier::simplifyTauLdInd(Modifier mod, Type* dstType, Type::Tag type, Opnd *ptr, Opnd *tauBaseNonNull, Opnd *tauAddressInRange) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.do_sxt && !optimizerFlags.ia32_code_gen) { - // simplify signed loads to unsigned - Opnd *newLd = 0; - switch (type) { - case Type::Int8: - newLd = genTauLdInd(mod, dstType, Type::UInt8, ptr, - tauBaseNonNull, tauAddressInRange)->getDst(); - break; - case Type::Int16: - newLd = genTauLdInd(mod, dstType, Type::UInt16, ptr, - tauBaseNonNull, tauAddressInRange)->getDst(); - break; - case Type::Int32: - newLd = genTauLdInd(mod, dstType, Type::UInt32, ptr, - tauBaseNonNull, tauAddressInRange)->getDst(); - break; - default: - break; - } - if (newLd) { - Opnd *extOpnd = genConv(dstType, type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), newLd)->getDst(); - return extOpnd; - } + // simplify signed loads to unsigned + Opnd *newLd = 0; + switch (type) { + case Type::Int8: + newLd = genTauLdInd(mod, dstType, Type::UInt8, ptr, + tauBaseNonNull, tauAddressInRange)->getDst(); + break; + case Type::Int16: + newLd = genTauLdInd(mod, dstType, Type::UInt16, ptr, + tauBaseNonNull, tauAddressInRange)->getDst(); + break; + case Type::Int32: + newLd = genTauLdInd(mod, dstType, Type::UInt32, ptr, + tauBaseNonNull, tauAddressInRange)->getDst(); + break; + default: + break; + } + if (newLd) { + Opnd *extOpnd = genConv(dstType, type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), newLd)->getDst(); + return extOpnd; + } } if (optimizerFlags.reduce_compref && (mod.getAutoCompressModifier() == AutoCompress_Yes)) { @@ -3494,20 +3493,20 @@ Simplifier::simplifyTauLdInd(Modifier mo Opnd * -Simplifier::simplifyLdString(Modifier mod, Type* dstType, - uint32 token, MethodDesc* enclosingMethod) +Simplifier::simplifyLdRef(Modifier mod, Type* dstType, + uint32 token, MethodDesc* enclosingMethod) { - OptimizerFlags& optimizerFlags = *irManager.getCompilationContext()->getOptimizerFlags(); + const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); if (optimizerFlags.reduce_compref && (mod.getAutoCompressModifier() == AutoCompress_Yes)) { assert(dstType->isReference()); assert(!dstType->isCompressedReference()); Type *compressedType = irManager.getTypeManager().compressType(dstType); - Opnd *newLdString = genLdString(AutoCompress_No, compressedType, - token, - enclosingMethod)->getDst(); - Opnd *uncOpnd = genUncompressRef(newLdString)->getDst(); + Opnd *newLdRef = genLdRef(AutoCompress_No, compressedType, + token, + enclosingMethod)->getDst(); + Opnd *uncOpnd = genUncompressRef(newLdRef)->getDst(); return uncOpnd; } return 0; @@ -3562,9 +3561,7 @@ Simplifier::simplifyTauLdVirtFunAddrSlot } Opnd* -Simplifier::simplifyTauLdIntfcVTableAddr(Opnd* base, - Opnd *tauBaseHasInterface, - Type* vtableType) { +Simplifier::simplifyTauLdIntfcVTableAddr(Opnd* base, Type* vtableType) { // Can't really simplify load of an interface vtable return NULL; } @@ -3593,7 +3590,7 @@ Simplifier::simplifyTauVirtualCall(Metho // or if the method is final // if (isExactType(args[0]) || methodDesc->isFinal() || methodDesc->isPrivate()) { - if(isExactType(args[0])) { + if(isExactType(args[0]) && !args[0]->getType()->isInterface()) { methodDesc = irManager.getCompilationInterface().getOverriddenMethod( (NamedType*) args[0]->getType(), methodDesc); } @@ -3729,17 +3726,18 @@ Simplifier::caseBranch(BranchInst* inst) Inst* Simplifier::caseSwitch(SwitchInst* inst) { - uint32 numTarget = inst->getNumTargets(); - LabelInst** targets = inst->getTargets(); - LabelInst* defaultTarget = inst->getDefaultTarget(); Opnd* index = inst->getSrc(0); int32 value; if(ConstantFolder::isConstant(index->getInst(), value)) { foldSwitch(inst, value); return NULL; } else { - if(simplifySwitch(numTarget, targets, defaultTarget, index)) + uint32 numTarget = inst->getNumTargets(); + LabelInst** targets = inst->getTargets(); + LabelInst* defaultTarget = inst->getDefaultTarget(); + if(simplifySwitch(numTarget, targets, defaultTarget, index)) { return NULL; + } } return inst; } @@ -3806,8 +3804,8 @@ Simplifier::propagateCopy(Opnd* opnd) { // Simplifier methods that generate instructions //----------------------------------------------------------------------------- SimplifierWithInstFactory::SimplifierWithInstFactory(IRManager& irm, - bool isLate, - Reassociate *reassociate0) + bool isLate, + Reassociate *reassociate0) : Simplifier(irm, isLate, reassociate0), nextInst(NULL), currentCfgNode(NULL), @@ -3822,23 +3820,23 @@ SimplifierWithInstFactory::SimplifierWit void SimplifierWithInstFactory::foldBranch(BranchInst* br, bool isTaken) { - flowGraph.foldBranch(currentCfgNode,br,isTaken); + FlowGraph::foldBranch(flowGraph, currentCfgNode,br,isTaken); } void SimplifierWithInstFactory::foldSwitch(SwitchInst* switchInst, uint32 index) { - flowGraph.foldSwitch(currentCfgNode,switchInst,index); + FlowGraph::foldSwitch(flowGraph, currentCfgNode,switchInst,index); } void SimplifierWithInstFactory::eliminateCheck(Inst* checkInst, bool alwaysThrows) { - flowGraph.eliminateCheck(currentCfgNode,checkInst,alwaysThrows); + FlowGraph::eliminateCheck(flowGraph, currentCfgNode,checkInst,alwaysThrows); } uint32 SimplifierWithInstFactory::simplifyControlFlowGraph() { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting simplifyControlFlowGraph" << ::std::endl; } @@ -3847,44 +3845,44 @@ SimplifierWithInstFactory::simplifyContr BitSet* reachableNodes = new (memManager) BitSet(memManager,flowGraph.getMaxNodeId()); BitSet* unreachableInsts = new (memManager) BitSet(memManager,irManager.getInstFactory().getNumInsts()); - ::std::vector<CFGNode*> nodes; + StlVector<Node*> nodes(memManager); nodes.reserve(flowGraph.getMaxNodeId()); // // Compute postorder list. // flowGraph.getNodesPostOrder(nodes); // Use reverse iterator to generate nodes in reverse postorder. - ::std::vector<CFGNode*>::reverse_iterator niter = nodes.rbegin(); + StlVector<Node*>::reverse_iterator niter = nodes.rbegin(); // mark first node as reachable reachableNodes->setBit((*niter)->getId(),true); for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { currentCfgNode = *niter; - Inst* headInst = currentCfgNode->getFirstInst(); + Inst* headInst = (Inst*)currentCfgNode->getFirstInst(); if (reachableNodes->getBit(currentCfgNode->getId()) == false) { // unreachable block // mark block's instructions as unreachable - for (Inst* inst = headInst->next();inst!=headInst;inst=inst->next()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { unreachableInsts->setBit(inst->getId(),true); } // skip over unreachable block continue; } - for (Inst* inst = headInst->next();inst!=headInst;) { - Inst* nextInst = inst->next(); - if (Log::cat_opt_sim()->isDebugEnabled()) { + for (Inst* inst = headInst->getNextInst();inst!=NULL;) { + Inst* nextInst = inst->getNextInst(); + if (Log::isEnabled()) { Log::out() << "Trying to simplify Instruction: "; inst->print(Log::out()); Log::out() << ::std::endl; } Inst* optimizedInst = optimizeInst(inst); if (optimizedInst != inst) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "was simplified" << ::std::endl; } // simplification occurred numInstOptimized++; if (optimizedInst != NULL) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "replacing with new instruction "; optimizedInst->print(Log::out()); Log::out() << ::std::endl; @@ -3906,10 +3904,13 @@ SimplifierWithInstFactory::simplifyContr // dstOpnd is null first. // Inst* copy = irManager.getInstFactory().makeCopy(dstOpnd, srcOpnd); - assert(nextInst); - assert(nextInst->getNode()); - copy->insertBefore(nextInst); - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (nextInst) { + assert(nextInst->getNode()); + copy->insertBefore(nextInst); + } else { + currentCfgNode->appendInst(copy); + } + if (Log::isEnabled()) { Log::out() << "inserting copy instruction "; copy->print(Log::out()); Log::out() << ::std::endl; @@ -3921,15 +3922,15 @@ SimplifierWithInstFactory::simplifyContr inst = nextInst; } // mark successor blocks as reachable - CFGEdgeDeque::const_iterator + Edges::const_iterator i = currentCfgNode->getOutEdges().begin(), iend = currentCfgNode->getOutEdges().end(); for (; i != iend; i++) { - CFGNode* succ = (*i)->getTargetNode(); + Node* succ = (*i)->getTargetNode(); reachableNodes->setBit(succ->getId(),true); } } - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Done simplifyControlFlowGraph" << ::std::endl; } return numInstOptimized; @@ -3948,18 +3949,22 @@ SimplifierWithInstFactory::insertInst(In void SimplifierWithInstFactory::insertInstInHeader(Inst* inst) { - CFGNode *head = flowGraph.getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = flowGraph.getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *where = entryLabel->next(); - while (where != entryLabel) { + Inst *where = entryLabel->getNextInst(); + while (where != NULL) { if (where->getOpcode() != Op_DefArg) { break; } - where = where->next(); + where = where->getNextInst(); } // insert before where - inst->insertBefore(where); + if (where!=NULL) { + inst->insertBefore(where); + } else { + head->appendInst(inst); + } } Inst* @@ -4162,7 +4167,8 @@ SimplifierWithInstFactory::genDirectCall numArgs, args, methodDesc); if ( inlineBuilder ) { - inlineBuilder->buildInlineInfoForInst(inst, methodDesc); + uint32 callOffset = ILLEGAL_VALUE; + inlineBuilder->buildInlineInfoForInst(inst, callOffset, methodDesc); } insertInst(inst); @@ -4218,12 +4224,12 @@ SimplifierWithInstFactory::genTauLdInd(M } Inst* -SimplifierWithInstFactory::genLdString(Modifier mod, Type* type, - uint32 token, - MethodDesc *methodDesc) +SimplifierWithInstFactory::genLdRef(Modifier mod, Type* type, + uint32 token, + MethodDesc *methodDesc) { Opnd* dst = opndManager.createSsaTmpOpnd(type); - Inst* inst = instFactory.makeLdString(mod, dst, methodDesc, token); + Inst* inst = instFactory.makeLdRef(mod, dst, methodDesc, token); insertInst(inst); return inst; } @@ -4386,7 +4392,7 @@ Simplifier::simplifyTauCheckCast(Opnd* s } else if (irManager.getTypeManager().isSubClassOf(opndType, castType)) { return genTauHasType(src, castType)->getDst(); } else if (!irManager.getTypeManager().isSubClassOf(castType, opndType)) { - if (Log::cat_opt_sim()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "in simplifyTauCheckCast: castToType "; castType->print(Log::out()); Log::out() << " not subtype of source "; @@ -4404,10 +4410,10 @@ Opnd* Simplifier::simplifyTauHasType(Opnd* src, Type* castType) { // all references have type java/lang/Object - if ((castType == irManager.getTypeManager().getSystemObjectType()) || - (castType == irManager.getTypeManager().getCompressedSystemObjectType())) { - return genTauSafe()->getDst(); - } + if ((castType == irManager.getTypeManager().getSystemObjectType()) || + (castType == irManager.getTypeManager().getCompressedSystemObjectType())) { + return genTauSafe()->getDst(); + } // otherwise, check for constants or casts #ifndef NDEBUG Type *opndType = src->getType(); @@ -4436,10 +4442,10 @@ #endif return tauCastChecked; } // otherwise, first check whether we can be more precise than this cast - DeadCodeEliminator::copyPropagate(staticCastInst); + DeadCodeEliminator::copyPropagate(staticCastInst); Opnd *staticCastSrc = staticCastInst->getSrc(0); tauCastChecked = staticCastInst->getSrc(1); - + Opnd *foundRecurse = simplifyTauHasType(staticCastSrc, castType); if (foundRecurse) { return foundRecurse; diff --git vm/jitrino/src/optimizer/simplifier.h vm/jitrino/src/optimizer/simplifier.h index 76111f0..f02f8c2 100644 --- vm/jitrino/src/optimizer/simplifier.h +++ vm/jitrino/src/optimizer/simplifier.h @@ -36,15 +36,11 @@ class IRManager; class InstFactory; class Reassociate; -DEFINE_OPTPASS(SimplificationPass) - -DEFINE_OPTPASS(LateSimplificationPass) - class Simplifier : public InstOptimizer { public: Simplifier(IRManager& irm, bool latepass=false, - Reassociate *reassociate=0); + Reassociate *reassociate=0); // // returns an Opnd if the add can be simplified // null if the operation cannot be simplified @@ -110,16 +106,16 @@ public: Opnd** args, InlineInfoBuilder* inlineBuilder); // loads - Opnd* simplifyLdString(Modifier mod, Type *dstType, - uint32 token, - MethodDesc* enclosingMethod); + Opnd* simplifyLdRef(Modifier mod, Type *dstType, + uint32 token, + MethodDesc* enclosingMethod); Opnd* simplifyTauLdInd(Modifier mod, Type *dstType, Type::Tag type, Opnd* ptr, Opnd* tauBaseNonNull, Opnd* tauAddressInRange); Opnd* simplifyTauLdVTableAddr(Opnd* base, Opnd *tauBaseNonNull); - Opnd* simplifyTauLdIntfcVTableAddr(Opnd* base, Opnd *tauBaseHasInterface, Type* vtableType); + Opnd* simplifyTauLdIntfcVTableAddr(Opnd* base, Type* vtableType); Opnd* simplifyTauLdVirtFunAddr(Opnd* vtable, Opnd *tauVtableHasDesc, MethodDesc*); Opnd* simplifyTauLdVirtFunAddrSlot(Opnd* vtable, Opnd *tauVtableHasDesc, MethodDesc*); @@ -186,7 +182,7 @@ public: static bool isExactType(Opnd*); protected: IRManager& irManager; - FlowGraph& flowGraph; + ControlFlowGraph& flowGraph; // genOp routines create an instruction, may never return NULL // but may simplify it to some other instruction @@ -240,8 +236,8 @@ protected: virtual Inst* genLdConstant(Type *type, ConstInst::ConstValue val) = 0; virtual Inst* genTauLdInd(Modifier mod, Type *dstType, Type::Tag type, Opnd *ptr, Opnd *tauNonNullBase, Opnd *tauAddressInRange) = 0; - virtual Inst* genLdString(Modifier mod, Type *dstType, - uint32 token, MethodDesc *enclosingMethod) = 0; + virtual Inst* genLdRef(Modifier mod, Type *dstType, + uint32 token, MethodDesc *enclosingMethod) = 0; virtual Inst* genLdFunAddrSlot(MethodDesc*) = 0; virtual Inst* genGetVTableAddr(ObjectType* type) = 0; // compressed references @@ -495,9 +491,7 @@ public: Inst* caseCatch(Inst* inst) {return caseDefault(inst);} - Inst* caseThrow(Inst* inst) {return caseDefault(inst);} - - Inst* caseThrowLazy(Inst* inst) {return caseDefault(inst);} + Inst* caseThrow(Inst* inst) {return caseDefault(inst);} Inst* caseThrowSystemException(Inst* inst) {return caseDefault(inst);} @@ -528,11 +522,11 @@ public: Inst* caseLdNull(ConstInst* inst) {return caseDefault(inst);} Inst* - caseLdString(TokenInst* inst) { - Opnd* opnd = simplifyLdString(inst->getModifier(), - inst->getDst()->getType(), - inst->getToken(), - inst->getEnclosingMethod()); + caseLdRef(TokenInst* inst) { + Opnd* opnd = simplifyLdRef(inst->getModifier(), + inst->getDst()->getType(), + inst->getToken(), + inst->getEnclosingMethod()); if (opnd != NULL) return opnd->getInst(); return inst; @@ -544,15 +538,15 @@ public: Inst* caseTauLdInd(Inst* inst) { - Opnd* opnd = simplifyTauLdInd(inst->getModifier(), + Opnd* opnd = simplifyTauLdInd(inst->getModifier(), inst->getDst()->getType(), inst->getType(), inst->getSrc(0), inst->getSrc(1), inst->getSrc(2)); - if (opnd != NULL) - return opnd->getInst(); - return inst; + if (opnd != NULL) + return opnd->getInst(); + return inst; } Inst* caseTauLdField(FieldAccessInst* inst) {return caseDefault(inst);} @@ -577,7 +571,6 @@ public: } Inst* caseTauLdIntfcVTableAddr(TypeInst* inst) { Opnd* opnd = simplifyTauLdIntfcVTableAddr(inst->getSrc(0), - inst->getSrc(1), inst->getTypeInfo()); if (opnd != NULL) return opnd->getInst(); @@ -1078,26 +1071,19 @@ protected: // re-association machinery friend class Reassociate; - Opnd* - simplifyAddViaReassociation2(Type* type, Opnd* src1, Opnd* src2); - Opnd* - simplifyNegViaReassociation2(Type* type, Opnd* src1); - Opnd* - simplifySubViaReassociation2(Type* type, Opnd* src1, Opnd *src2); - Opnd* - simplifyMulViaReassociation2(Type* type, Opnd* src1, Opnd* src2); - Opnd* - simplifyAddOffsetViaReassociation(Opnd* uncompBase, Opnd *offset); - Opnd* - simplifyAddOffsetPlusHeapbaseViaReassociation(Opnd *compBase, - Opnd *offsetPlusHeapbase); + Opnd* simplifyAddViaReassociation2(Type* type, Opnd* src1, Opnd* src2); + Opnd* simplifyNegViaReassociation2(Type* type, Opnd* src1); + Opnd* simplifySubViaReassociation2(Type* type, Opnd* src1, Opnd *src2); + Opnd* simplifyMulViaReassociation2(Type* type, Opnd* src1, Opnd* src2); + Opnd* simplifyAddOffsetViaReassociation(Opnd* uncompBase, Opnd *offset); + Opnd* simplifyAddOffsetPlusHeapbaseViaReassociation(Opnd *compBase, Opnd *offsetPlusHeapbase); Reassociate *theReassociate; }; class SimplifierWithInstFactory : public Simplifier { public: SimplifierWithInstFactory(IRManager&,bool latePass=false, - Reassociate *reassociate0=0); + Reassociate *reassociate0=0); virtual Inst* optimizeInst(Inst* inst); uint32 simplifyControlFlowGraph(); protected: @@ -1152,8 +1138,8 @@ protected: virtual Inst* genTauLdInd(Modifier mod, Type *dstType, Type::Tag type, Opnd *ptr, Opnd *tauNonNullBase, Opnd *tauAddressInRange); - virtual Inst* genLdString(Modifier mod, Type *dstType, - uint32 token, MethodDesc *enclosingMethod); + virtual Inst* genLdRef(Modifier mod, Type *dstType, + uint32 token, MethodDesc *enclosingMethod); virtual Inst* genLdFunAddrSlot(MethodDesc*); virtual Inst* genGetVTableAddr(ObjectType* type); @@ -1184,7 +1170,7 @@ protected: virtual void eliminateCheck(Inst* checkInst, bool alwaysThrows); private: Inst* nextInst; - CFGNode* currentCfgNode; + Node* currentCfgNode; InstFactory& instFactory; OpndManager& opndManager; TypeManager& typeManager; diff --git vm/jitrino/src/optimizer/simplifytaus.cpp vm/jitrino/src/optimizer/simplifytaus.cpp index 3806fe4..cf71f2c 100644 --- vm/jitrino/src/optimizer/simplifytaus.cpp +++ vm/jitrino/src/optimizer/simplifytaus.cpp @@ -23,13 +23,12 @@ #include "Log.h" #include "simplifytaus.h" #include "irmanager.h" -#include "PropertyTable.h" #include "Stl.h" #include "walkers.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(TauSimplificationPass, tausimp, "Tau Simplification") +DEFINE_SESSION_ACTION(TauSimplificationPass, tausimp, "Tau Simplification") void TauSimplificationPass::_run(IRManager& irm) { @@ -64,12 +63,12 @@ SimplifyTaus::SimplifyTaus(MemoryManager class TauHasTypesMap { typedef ::std::pair<Opnd *, Type *> OpndXType; #ifdef PLATFORM_POSIX - struct OpndXTypeHash : public __gnu_cxx::hash<OpndXType> { + struct OpndXTypeHash : public __gnu_cxx::hash<OpndXType> { #else #if !defined(__SGI_STL_PORT) - struct OpndXTypeHash : public stdext::hash_compare<OpndXType> { + struct OpndXTypeHash : public stdext::hash_compare<OpndXType> { #else - struct OpndXTypeHash : public ext::hash_compare<OpndXType> { + struct OpndXTypeHash : public ext::hash_compare<OpndXType> { #endif #endif size_t operator() (const OpndXType x) const { @@ -257,7 +256,7 @@ public: void SimplifyTaus::runPass() { - FlowGraph &fg = irManager.getFlowGraph(); + ControlFlowGraph &fg = irManager.getFlowGraph(); SsaTmpOpnd *tauSafeOpnd = findTauSafeOpnd(); TauHasTypesMap map(memManager); TauHasTypesMap exactmap(memManager); @@ -301,7 +300,7 @@ SimplifyTaus::runPass() for ( ; iter != end; ++iter) { #ifdef _NDEBUG Inst *remInst = *iter; - assert(remInst->next() == remInst); + assert(remInst->next() == remInst); assert(remInst->prev() == remInst); #endif } @@ -310,7 +309,7 @@ #endif Opnd *TauWalkerState::lookupMapping(Opnd *src, Type *type, bool exactType) { Opnd *found = exactType ? exactMap.lookup(src, type) : map.lookup(src, type); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { if (exactType) Log::out() << "found tau exacttype mapping ("; else @@ -333,7 +332,7 @@ Opnd *TauWalkerState::lookupMapping(Opnd void TauWalkerState::recordMapping(Opnd *mapTo, Opnd *src, Type *type, bool exactType) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "recording tau mapping ("; src->print(Log::out()); Log::out() << ", "; @@ -355,7 +354,7 @@ void TauWalkerState::recordMapping(Opnd void TauWalkerState::recordCopyMapping(Opnd *mapTo, Opnd *mapFrom) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "recording tau CopyMapping: "; mapFrom->print(Log::out()); Log::out() << " -> "; @@ -368,7 +367,7 @@ void TauWalkerState::recordCopyMapping(O Opnd *TauWalkerState::lookupCopyMapping(Opnd *mapFrom) { Opnd *found = copyMap.lookup(mapFrom); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "found CopyMapping: "; mapFrom->print(Log::out()); Log::out() << " -> "; @@ -383,7 +382,7 @@ Opnd *TauWalkerState::lookupCopyMapping( void TauWalkerState::noteInstToRemove(Inst *tauHasTypeInst) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "noting inst to remove: "; tauHasTypeInst->print(Log::out()); Log::out() << ::std::endl; @@ -519,7 +518,7 @@ Opnd *TauWalkerState::findReplacement(Op } case Op_LdConstant: - case Op_LdString: + case Op_LdRef: { return genTauSafe(); } @@ -726,18 +725,18 @@ Opnd *TauWalkerState::findReplacement(Op SsaTmpOpnd *SimplifyTaus::findTauSafeOpnd() { if (!tauSafeOpnd) { - CFGNode *head = irManager.getFlowGraph().getEntry(); - Inst *entryLabel = head->getFirstInst(); + Node *head = irManager.getFlowGraph().getEntryNode(); + Inst *entryLabel = (Inst*)head->getFirstInst(); // first search for one already there - Inst *inst = entryLabel->next(); - while (inst != entryLabel) { + Inst *inst = entryLabel->getNextInst(); + while (inst != NULL) { if (inst->getOpcode() == Op_TauSafe) { tauSafeOpnd = inst->getDst()->asSsaTmpOpnd(); - Inst *prevInst = inst->prev(); // make sure it's before any possible uses + Inst *prevInst = inst->getPrevInst(); // make sure it's before any possible uses if ((prevInst != entryLabel) && (prevInst->getOpcode() != Op_DefArg)) { do { - prevInst = prevInst->prev(); + prevInst = prevInst->getPrevInst(); } while ((prevInst != entryLabel) && (prevInst->getOpcode() != Op_DefArg)); inst->unlink(); @@ -745,7 +744,7 @@ SsaTmpOpnd *SimplifyTaus::findTauSafeOpn } return tauSafeOpnd; } - inst = inst->next(); + inst = inst->getNextInst(); } // need to insert one TypeManager &tm = irManager.getTypeManager(); @@ -895,7 +894,7 @@ VarOpnd *TauWalkerState::getReductionTau if (baseTauVarOpnd) { VarOpnd *baseTauVar = baseTauVarOpnd->asVarOpnd(); assert(baseTauVar); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { if (exactType) Log::out() << "should reduce exact ssaVarOpnd "; else @@ -909,7 +908,7 @@ VarOpnd *TauWalkerState::getReductionTau } return baseTauVar; } else { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { if (exactType) Log::out() << "should not reduce exact ssaVarOpnd "; else @@ -930,7 +929,7 @@ VarOpnd *TauWalkerState::getReductionTau VarOpnd *baseTauVar = baseTauVarOpnd->asVarOpnd(); assert(baseTauVar); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { if (exactType) Log::out() << "should reduce exact VarOpnd "; else @@ -942,7 +941,7 @@ VarOpnd *TauWalkerState::getReductionTau } return baseTauVar; } else { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { if (exactType) Log::out() << "should not reduce exact VarOpnd "; else @@ -970,7 +969,7 @@ Opnd *TauWalkerState::reduceSsaOpnd(Opnd // create one and map it; OpndManager &om = irManager.getOpndManager(); if (opnd->isSsaVarOpnd()) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "creating reducedSsaOpnd for baseVar="; baseVar->print(Log::out()); Log::out() << ::std::endl; @@ -980,7 +979,7 @@ Opnd *TauWalkerState::reduceSsaOpnd(Opnd return baseVar; } else { assert(opnd->isSsaTmpOpnd()); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "creating new tmp for baseVar="; baseVar->print(Log::out()); Log::out() << ::std::endl; @@ -990,7 +989,7 @@ Opnd *TauWalkerState::reduceSsaOpnd(Opnd recordMapping(mappedOpnd, opnd, type, exactType); } } - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reduceSsaOpnd("; opnd->print(Log::out()); Log::out() << ", "; @@ -1025,7 +1024,7 @@ void TauWalkerState::reduceVarTaus(Inst StlVectorSet<Type *> *reduceTypes = shouldReduceSsaOpnd(opnd, exactType); if (reduceTypes) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reducing StVar inst "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -1038,7 +1037,7 @@ void TauWalkerState::reduceVarTaus(Inst Type *type = *iter; VarOpnd *baseTauOpnd = getReductionTauBaseVar(opnd, type, exactType); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reducing StVar inst "; inst->print(Log::out()); if (exactType) @@ -1062,7 +1061,7 @@ void TauWalkerState::reduceVarTaus(Inst assert(newInst->getDst()->getInst() == newInst); assert(newDstSsaVarOpnd->getInst()->getDst() == newDstSsaVarOpnd); newInst->insertAfter(inst); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reduced StVar inst "; inst->print(Log::out()); Log::out() << " to inst "; @@ -1070,7 +1069,7 @@ void TauWalkerState::reduceVarTaus(Inst Log::out() << ::std::endl; } } else { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "tau opnd "; newDstSsaVarOpnd->print(Log::out()); Log::out() << " already has an inst "; @@ -1085,7 +1084,7 @@ void TauWalkerState::reduceVarTaus(Inst Inst *newInst = irManager.getInstFactory().makeStVar(newDstVarOpnd, newSrc); newInst->insertAfter(inst); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reduced StVar inst "; inst->print(Log::out()); Log::out() << " to inst "; @@ -1108,7 +1107,7 @@ void TauWalkerState::reduceVarTaus(Inst StlVectorSet<Type *> *reduceTypes = shouldReduceSsaOpnd(opnd, exactType); if (reduceTypes) { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reducing Phi inst "; inst->print(Log::out()); Log::out() << ::std::endl; @@ -1121,7 +1120,7 @@ void TauWalkerState::reduceVarTaus(Inst Type *type = *iter; VarOpnd *baseTauOpnd = getReductionTauBaseVar(opnd, type, exactType); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reducing Phi inst "; inst->print(Log::out()); if (exactType) @@ -1147,7 +1146,7 @@ void TauWalkerState::reduceVarTaus(Inst Inst *newInst = irManager.getInstFactory().makePhi(newDst, numOpnds, newOpnds); newInst->insertAfter(inst); - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "reduced Phi inst "; inst->print(Log::out()); Log::out() << " to inst "; @@ -1155,7 +1154,7 @@ void TauWalkerState::reduceVarTaus(Inst Log::out() << ::std::endl; } } else { - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "tau opnd "; newDst->print(Log::out()); Log::out() << " already has an inst "; diff --git vm/jitrino/src/optimizer/simplifytaus.h vm/jitrino/src/optimizer/simplifytaus.h index 6efa5b1..50d0f93 100644 --- vm/jitrino/src/optimizer/simplifytaus.h +++ vm/jitrino/src/optimizer/simplifytaus.h @@ -39,7 +39,6 @@ class FlowGraph; class Opnd; class SsaTmpOpnd; -DEFINE_OPTPASS(TauSimplificationPass) class SimplifyTaus { public: diff --git vm/jitrino/src/optimizer/ssa/SSA.cpp vm/jitrino/src/optimizer/ssa/SSA.cpp index 8e47c8a..2470c37 100644 --- vm/jitrino/src/optimizer/ssa/SSA.cpp +++ vm/jitrino/src/optimizer/ssa/SSA.cpp @@ -27,7 +27,6 @@ -#include "FlowGraph.h" #include "Dominator.h" #include "SSA.h" #include "Inst.h" @@ -41,38 +40,38 @@ #include "CompilationContext.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(FixupVarsPass, fixupvars, "Fixup SSA Vars") +DEFINE_SESSION_ACTION(FixupVarsPass, fixupvars, "Fixup SSA Vars") void FixupVarsPass::_run(IRManager& irm) { - computeDominators(irm); + OptPass::computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); - FlowGraph& flowGraph = irm.getFlowGraph(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); DomFrontier frontier(irm.getNestedMemoryManager(),*dominatorTree,&flowGraph); - SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, *irm.getCompilationContext()->getOptimizerFlags()); + SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, irm.getOptimizerFlags()); bool phiInserted = ssaBuilder.fixupVars(&irm.getFlowGraph(), irm.getMethodDesc()); irm.setInSsa(true); if (phiInserted) irm.setSsaUpdated(); } -DEFINE_OPTPASS_IMPL(SSAPass, ssa, "SSA Construction") +DEFINE_SESSION_ACTION(SSAPass, ssa, "SSA Construction") void SSAPass::_run(IRManager& irm) { - computeDominators(irm); + OptPass::computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); - FlowGraph& flowGraph = irm.getFlowGraph(); + ControlFlowGraph& flowGraph = irm.getFlowGraph(); DomFrontier frontier(irm.getNestedMemoryManager(),*dominatorTree,&flowGraph); - SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, *irm.getCompilationContext()->getOptimizerFlags()); + SSABuilder ssaBuilder(irm.getOpndManager(),irm.getInstFactory(),frontier,&flowGraph, irm.getOptimizerFlags()); ssaBuilder.convertSSA(irm.getMethodDesc()); irm.setInSsa(true); irm.setSsaUpdated(); } -DEFINE_OPTPASS_IMPL(DeSSAPass, dessa, "SSA Deconstruction") +DEFINE_SESSION_ACTION(DeSSAPass, dessa, "SSA Deconstruction") void DeSSAPass::_run(IRManager& irm) { @@ -80,21 +79,20 @@ DeSSAPass::_run(IRManager& irm) { irm.setInSsa(false); } -DEFINE_OPTPASS_IMPL(SplitSSAPass, splitssa, "SSA Variable Web Splitting") +DEFINE_SESSION_ACTION(SplitSSAPass, splitssa, "SSA Variable Web Splitting") void -SplitSSAPass::_run(IRManager& irm) -{ +SplitSSAPass::_run(IRManager& irm) { SSABuilder::splitSsaWebs(&irm.getFlowGraph(), irm.getOpndManager()); } -// #define DEBUG_SSA +//#define DEBUG_SSA class RenameStack : public SparseScopedMap<Opnd *, SsaVarOpnd *> { public: typedef SparseScopedMap<Opnd *, SsaVarOpnd *> BaseMap; - RenameStack(MemoryManager& mm, uint32 n, OptimizerFlags& optimizerFlags) + RenameStack(MemoryManager& mm, uint32 n, const OptimizerFlags& optimizerFlags) : BaseMap(n, mm, optimizerFlags.hash_init_factor, optimizerFlags.hash_resize_factor, @@ -108,15 +106,15 @@ public: // find def sites (blocks) of var operand // void SSABuilder::findDefSites(DefSites& allDefSites) { - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = fg->getNodes(); + Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - if (!node->isBasicBlock()) continue; + Node* node = *niter; + if (!node->isBlockNode()) continue; // go over each instruction to find var definition - Inst* first = node->getFirstInst(); - for (Inst* inst = first->next(); inst != first; inst = inst->next()) { + Inst* first = (Inst*)node->getFirstInst(); + for (Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { // look for var definitions if (!inst->isStVar()) continue; @@ -149,11 +147,11 @@ class SsaRenameWalker { RenameStack *rs; uint32 n; const StlVectorSet<VarOpnd *> *whatVars; - OptimizerFlags& optimizerFlags; + const OptimizerFlags& optimizerFlags; public: SsaRenameWalker(SSABuilder *builder0, MemoryManager &localMM, - uint32 num, OptimizerFlags& _optimizerFlags) + uint32 num, const OptimizerFlags& _optimizerFlags) : localMemManager(localMM), ssaBuilder(builder0), rs(0), @@ -187,16 +185,16 @@ void SSABuilder::renameNode(RenameStack const StlVectorSet<VarOpnd *> *whatVars) { if (dt == NULL) return; - CFGNode* node = dt->getNode(); + Node* node = dt->getNode(); - Inst* head = node->getFirstInst(); + Inst* head = (Inst*)node->getFirstInst(); #ifdef DEBUG_SSA - ::std::ostream &cout = Log::out(); - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "renameNode "; node->printLabel(cout); ::std::cout << ::std::endl; + std::ostream &cout = Log::out(); + if (Log::isEnabled()) { + cout << "renameNode "; FlowGraph::printLabel(cout, node); cout << std::endl; } #endif - for (Inst* i = head->next(); i != head; i = i->next()) { + for (Inst* i = head->getNextInst(); i != NULL; i = i->getNextInst()) { if (!i->isPhi()) { // replace src with ssa opnd uint32 nSrcs = i->getNumSrcOperands(); @@ -225,15 +223,15 @@ #endif SsaVarOpnd* ssaDst = opndManager.createSsaVarOpnd((VarOpnd*)dst); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "SSA "; ssaDst->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert((VarOpnd*)dst, ssaDst); i->setDst(ssaDst); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - i->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + i->print(cout); cout << ::std::endl; } #endif // record stVar inst @@ -243,39 +241,39 @@ #endif if (whatVars && !whatVars->has(theVar)) continue; #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "SSA "; ssaDst->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert(ssaDst->getVar(), ssaDst); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - i->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + i->print(cout); cout << ::std::endl; } #endif } } // add var sources to following phi instructions - const CFGEdgeDeque& edges = node->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges& edges = node->getOutEdges(); + Edges::const_iterator eiter = edges.begin(), eend = edges.end(); for(eiter = edges.begin(); eiter != eend; ++eiter) { - CFGEdge* e = *eiter; - CFGNode* succ = e->getTargetNode(); + Edge* e = *eiter; + Node* succ = e->getTargetNode(); // Phi insts are inserted to the beginning of the block // if succ does not have phi insts, then we can skip it - Inst *phi = succ->getFirstInst()->next(); - if (!phi->isPhi()) continue; + Inst *phi = (Inst*)succ->getSecondInst(); + if (phi==NULL || !phi->isPhi()) continue; // node is jth predecessor for succ // replace jth var of phi insts - Inst* nextphi = phi->next(); - for (;phi->isPhi(); phi = nextphi) { - nextphi = phi->next(); + Inst* nextphi = phi->getNextInst(); + for (;phi!=NULL && phi->isPhi(); phi = nextphi) { + nextphi = phi->getNextInst(); // get var Opnd *theopnd = phi->getDst(); VarOpnd *thevar = theopnd->asVarOpnd(); @@ -285,7 +283,7 @@ #endif assert(theSsaVar); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "case 2" << ::std::endl; } #endif @@ -298,19 +296,19 @@ #endif if (ssa != NULL) { #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "redge"; - ::std::cout << (int32)j; - ::std::cout << " with ssa "; ssa->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + cout << "redge"; +// cout << (int32)j; + cout << " with ssa "; ssa->print(cout); cout << ::std::endl; } #endif addPhiSrc((PhiInst*)phi,ssa); } else { #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "no source for phi of var "; + if (Log::isEnabled()) { + cout << "no source for phi of var "; thevar->print(cout); - ::std::cout << ::std::endl; + cout << ::std::endl; } #endif // if ssa is NULL, then the phi must be a dead phi inst @@ -332,16 +330,16 @@ void SSABuilder::insertPhi(DefSites& all if (varOpnd->isAddrTaken()) continue; - CFGNode* node; - CFGNode *returnNode = fg->getReturn(); - CFGNode *unwindNode = fg->getUnwind(); - CFGNode *exitNode = fg->getExit(); + Node* node; + Node *returnNode = fg->getReturnNode(); + Node *unwindNode = fg->getUnwindNode(); + Node *exitNode = fg->getExitNode(); while ((node = defSites->removeDefSite()) != NULL) { - List<CFGNode>* df = frontier.getFrontiersOf(node); + List<Node>* df = frontier.getFrontiersOf(node); for (; df != NULL; df = df->getNext()) { // block where phi inst is going to be inserted - CFGNode* insertedLoc = df->getElem(); + Node* insertedLoc = df->getElem(); // if phi has been inserted, then skip // no need to insert phi inst in the epilog, // return node, or unwind node because @@ -361,11 +359,11 @@ void SSABuilder::insertPhi(DefSites& all } } -void SSABuilder::createPhiInst(VarOpnd* var, CFGNode* insertedLoc) { +void SSABuilder::createPhiInst(VarOpnd* var, Node* insertedLoc) { // create phi instruction Inst* phi = instFactory.makePhi(var,0, 0); // insert to the beginning of insertedLoc - insertedLoc->prepend(phi); + insertedLoc->prependInst(phi); createPhi = true; } @@ -398,7 +396,7 @@ class ClearPhiSrcsWalker { SSABuilder *thePass; const StlVectorSet<VarOpnd *> *whatVars; public: - void applyToCFGNode(CFGNode *node) { thePass->clearPhiSrcs(node, + void applyToCFGNode(Node *node) { thePass->clearPhiSrcs(node, whatVars); }; ClearPhiSrcsWalker(SSABuilder *thePass0) @@ -417,9 +415,9 @@ class ClearPhiSrcsWalker2 { const StlVectorSet<VarOpnd *> *oldVars; // vars of interest StlVector<VarOpnd *> *newVars; // vars which we have changed const StlVectorSet<Opnd *> *removedVars; // vars defined by removed Phis - StlVector<CFGNode *> &tmpNodeList; + StlVector<Node *> &tmpNodeList; public: - void applyToCFGNode(CFGNode *node) { thePass->clearPhiSrcs2(node, + void applyToCFGNode(Node *node) { thePass->clearPhiSrcs2(node, oldVars, newVars, removedVars, @@ -428,7 +426,7 @@ public: const StlVectorSet<VarOpnd *> *oldVars0, StlVector<VarOpnd *> *newVars0, const StlVectorSet<Opnd *> *removedVars0, - StlVector<CFGNode *> &tmpNodeList0) + StlVector<Node *> &tmpNodeList0) : thePass(thePass0), oldVars(oldVars0), newVars(newVars0), removedVars(removedVars0), @@ -446,11 +444,11 @@ public: } }; -void SSABuilder::clearPhiSrcs(CFGNode *node, const StlVectorSet<VarOpnd *> *whatVars) +void SSABuilder::clearPhiSrcs(Node *node, const StlVectorSet<VarOpnd *> *whatVars) { + Inst* phi = (Inst*)node->getSecondInst(); if (whatVars) { - Inst* phi = node->getFirstInst()->next(); - for (;phi->isPhi(); phi = phi->next()) { + for (;phi!=NULL && phi->isPhi(); phi = phi->getNextInst()) { Opnd *dstOp = phi->getDst(); VarOpnd *varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { @@ -465,8 +463,7 @@ void SSABuilder::clearPhiSrcs(CFGNode *n } } } else { - Inst* phi = node->getFirstInst()->next(); - for (;phi->isPhi(); phi = phi->next()) { + for (;phi!=NULL && phi->isPhi(); phi = phi->getNextInst()) { PhiInst *phiInst = phi->asPhiInst(); assert(phiInst); phiInst->setNumSrcs(0); @@ -474,17 +471,17 @@ void SSABuilder::clearPhiSrcs(CFGNode *n } } -void SSABuilder::clearPhiSrcs2(CFGNode *node, +void SSABuilder::clearPhiSrcs2(Node *node, const StlVectorSet<VarOpnd *> *whatVars, StlVector<VarOpnd *> *changedVars, const StlVectorSet<Opnd *> *removedVars, - StlVector<CFGNode *> &scratchNodeList) + StlVector<Node *> &scratchNodeList) { bool needPreds = true; - StlVector<CFGNode *> &preds = scratchNodeList; + StlVector<Node *> &preds = scratchNodeList; - Inst* inst = node->getFirstInst()->next(); - for (;inst->isPhi(); inst = inst->next()) { + Inst* inst = (Inst*)node->getSecondInst(); + for (;inst!=NULL && inst->isPhi(); inst = inst->getNextInst()) { Opnd *dstOp =inst->getDst(); VarOpnd *varOpnd = 0; if (whatVars) { @@ -507,25 +504,25 @@ void SSABuilder::clearPhiSrcs2(CFGNode * if (needPreds) { needPreds = false; - const CFGEdgeDeque& edges2 = node->getInEdges(); + const Edges& edges2 = node->getInEdges(); preds.clear(); preds.reserve(edges2.size()); - CFGEdgeDeque::const_iterator eiter2; + Edges::const_iterator eiter2; for(eiter2 = edges2.begin(); eiter2 != edges2.end(); ++eiter2){ preds.push_back((*eiter2)->getSourceNode()); } } DominatorTree &domTree = frontier.getDominator(); Inst *thisOpndInst = thisOpnd->getInst(); - CFGNode *thisOpndInstNode = thisOpndInst->getNode(); + Node *thisOpndInstNode = thisOpndInst->getNode(); if (thisOpndInstNode) { // the operand's source instruction was not already dead. - StlVector<CFGNode *>::const_iterator + StlVector<Node *>::const_iterator predIter = preds.begin(), predEnd = preds.end(); bool foundDom = false; for ( ; predIter != predEnd; ++predIter) { - CFGNode *predNode = *predIter; + Node *predNode = *predIter; if (domTree.dominates(thisOpndInstNode, predNode)) { // we found it, leave this operand alone. foundDom = true; @@ -570,7 +567,7 @@ class CheckForTrivialPhisWalker { StlVector<VarOpnd *> changedVars; StlVectorSet<VarOpnd *> changedVarsSet; public: - void applyToCFGNode(CFGNode *node) { + void applyToCFGNode(Node *node) { if (thePass->checkForTrivialPhis(node, changedVars)) { removedPhi = true; removedPhiRecently = true; @@ -600,32 +597,31 @@ public: }; }; -bool SSABuilder::checkForTrivialPhis(CFGNode *node, +bool SSABuilder::checkForTrivialPhis(Node *node, StlVector<VarOpnd *> &changedVars) { - Inst* phi = node->getFirstInst()->next(); - Inst *nextphi = phi->next(); + Inst* phi = (Inst*)node->getSecondInst(); bool removedPhi = false; #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking node " << (int)node->getId() << " for trivial phis" << ::std::endl; } #endif - - for (;phi->isPhi(); phi = nextphi) { - nextphi = phi->next(); + Inst* nextphi = NULL; + for (;phi!=NULL && phi->isPhi(); phi = nextphi) { + nextphi = phi->getNextInst(); #ifdef _DEBUG PhiInst *phiInst = phi->asPhiInst(); - assert(phiInst); + assert(phiInst); #endif uint32 nSrcs = phi->getNumSrcOperands(); if (nSrcs <= 1) { // phi must be trivial #ifdef DEBUG_SSA ::std::ostream &cout = Log::out(); - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "removing trivial instruction "; phi->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + cout << "removing trivial instruction "; phi->print(cout); cout << ::std::endl; } #endif Opnd *dstOp = phi->getDst(); @@ -650,7 +646,7 @@ class CheckForTrivialPhisWalker2 { StlVector<VarOpnd *> *changedVars; // note which vars are changed StlVector<Opnd *> *removedVars; // record dst of removed Phis public: - void applyToCFGNode(CFGNode *node) { + void applyToCFGNode(Node *node) { thePass->checkForTrivialPhis2(node, lookatVars, changedVars, removedVars); }; @@ -667,32 +663,32 @@ public: void setChangedVars(StlVector<VarOpnd *> *vars) { changedVars = vars; } }; -void SSABuilder::checkForTrivialPhis2(CFGNode *node, +void SSABuilder::checkForTrivialPhis2(Node *node, const StlVectorSet<VarOpnd *> *lookatVars, StlVector<VarOpnd *> *changedVars, StlVector<Opnd *> *removedVars) { - Inst* phi = node->getFirstInst()->next(); - Inst *nextphi = phi->next(); + Inst* phi = (Inst*)node->getSecondInst(); + Inst *nextphi = NULL; #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Checking node " << (int)node->getId() << " for trivial phis2" << ::std::endl; } #endif for (;phi->isPhi(); phi = nextphi) { - nextphi = phi->next(); + nextphi = phi->getNextInst(); #ifdef _DEBUG PhiInst *phiInst = phi->asPhiInst(); - assert(phiInst); + assert(phiInst); #endif uint32 nSrcs = phi->getNumSrcOperands(); if (nSrcs <= 1) { // phi must be trivial #ifdef DEBUG_SSA ::std::ostream &cout = Log::out(); - if (Log::cat_opt()->isDebugEnabled()) { - ::std::cout << "removing trivial2 instruction "; phi->print(cout); ::std::cout << ::std::endl; + if (Log::isEnabled()) { + cout << "removing trivial2 instruction "; phi->print(cout); cout << ::std::endl; } #endif Opnd *dstOp = phi->getDst(); @@ -717,17 +713,17 @@ bool SSABuilder::fixupSSA(MethodDesc& me "SSABuilder::fixupSSA::memManager"); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting fixupSSA" << ::std::endl; - fg->printDotFile(methodDesc, "midfixup-0", 0); + FlowGraph::printDotFile(*fg, methodDesc, "midfixup-0"); } #endif if (useBetter) { StlVector<VarOpnd *> newChangedVars(localMM); StlVector<Opnd *> removedVars(localMM); - StlVector<CFGNode *> tmpNodeList(localMM); + StlVector<Node *> tmpNodeList(localMM); // first cleanup trivial Phis to avoid mess later CheckForTrivialPhisWalker2 checkTrivialWalker(this, @@ -748,7 +744,7 @@ #endif NodeWalk<ClearPhiSrcsWalker2>(*fg, clearPhisWalker2); if (newChangedVars.empty()) { #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "newChangedVars is empty" << ::std::endl; } #endif @@ -777,7 +773,7 @@ #endif // lather, rinse, repeat #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "beginning iteration" << ::std::endl; } #endif @@ -807,7 +803,7 @@ #endif NodeWalk<CheckForTrivialPhisWalker2>(*fg, checkTrivialWalker); } #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "done iteration" << ::std::endl; } #endif @@ -817,8 +813,8 @@ #endif NodeWalk<ClearPhiSrcsWalker>(*fg, clearPhisWalker); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixup-1", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg, methodDesc, "midfixup-1"); } #endif @@ -830,8 +826,8 @@ #endif localMM); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixup-2", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg, methodDesc, "midfixup-2"); } #endif @@ -839,21 +835,21 @@ #endif NodeWalk<CheckForTrivialPhisWalker>(*fg, checkTrivialWalker); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "before iteration" << ::std::endl; } #endif while (checkTrivialWalker.foundTrivial()) { #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "starting iteration" << ::std::endl; } #endif // we deleted some Phi instruction(s) #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixup-3", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg, methodDesc, "midfixup-3"); } #endif // clear all other Phis for that var(s) @@ -871,14 +867,14 @@ #endif NodeWalk<CheckForTrivialPhisWalker>(*fg, checkTrivialWalker); } #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "done iteration" << ::std::endl; } #endif } #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixup-4", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg, methodDesc, "midfixup-4"); Log::out() << "Finished fixupSSA" << ::std::endl; } @@ -988,17 +984,17 @@ public: // check for new Vars which are not in SSA form; if there are any, fix up all occurrences of // that var, put into SSA form. -bool SSABuilder::fixupVars(FlowGraph *fg, MethodDesc& methodDesc) { +bool SSABuilder::fixupVars(ControlFlowGraph*fg, MethodDesc& methodDesc) { // clear out all Phi args int sizeEstimate = opndManager.getNumVarOpnds()+opndManager.getNumSsaOpnds(); MemoryManager localMM(64*sizeEstimate, "SSABuilder::fixupVars::memManager"); #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting fixupVars" << ::std::endl; - fg->printDotFile(methodDesc, "midfixupvars-0", 0); + FlowGraph::printDotFile(*fg, methodDesc, "midfixupvars-0"); } #endif @@ -1022,8 +1018,8 @@ #endif // now all vars in usedOutOfSsa are not used in SSA form, and have no Phis. #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixupvars-1", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg,methodDesc, "midfixupvars-1"); } #endif @@ -1032,8 +1028,8 @@ #endif } #ifdef DEBUG_SSA - if (Log::cat_opt()->isDebugEnabled()) { - fg->printDotFile(methodDesc, "midfixupvars-3", 0); + if (Log::isEnabled()) { + FlowGraph::printDotFile(*fg, methodDesc, "midfixupvars-3"); Log::out() << "Finished fixupVars" << ::std::endl; } @@ -1054,14 +1050,14 @@ #endif */ -void SSABuilder::deconvertSSA(FlowGraph* fg,OpndManager& opndManager) { - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter; +void SSABuilder::deconvertSSA(ControlFlowGraph* fg,OpndManager& opndManager) { + const Nodes& nodes = fg->getNodes(); + Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst *inst = headInst->next(); inst != headInst; ) { - Inst *nextInst = inst->next(); + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { + Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { inst->unlink(); } else { @@ -1100,19 +1096,19 @@ struct SsaVarClique : private UnionFind // rename vars to make un-overlapping live ranges of a variable into // different variables. -void SSABuilder::splitSsaWebs(FlowGraph* fg,OpndManager& opndManager) { +void SSABuilder::splitSsaWebs(ControlFlowGraph* fg,OpndManager& opndManager) { uint32 numSsaOpnds = opndManager.getNumSsaOpnds(); MemoryManager localMM(16*numSsaOpnds, "SSABuilder::splitSsaWebs::memManager"); SsaVarClique *cliques = new (localMM) SsaVarClique[numSsaOpnds]; - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = fg->getNodes(); + Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst *inst = headInst->next(); inst != headInst; ) { - Inst *nextInst = inst->next(); + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { + Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { // do something VarOpnd *var0 = 0; @@ -1155,10 +1151,10 @@ void SSABuilder::splitSsaWebs(FlowGraph* } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - Inst *headInst = node->getFirstInst(); - for (Inst *inst = headInst->next(); inst != headInst; ) { - Inst *nextInst = inst->next(); + Node* node = *niter; + Inst *headInst = (Inst*)node->getFirstInst(); + for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { + Inst *nextInst = inst->getNextInst(); for (uint32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); diff --git vm/jitrino/src/optimizer/ssa/SSA.h vm/jitrino/src/optimizer/ssa/SSA.h index 8081bfb..a0b9067 100644 --- vm/jitrino/src/optimizer/ssa/SSA.h +++ vm/jitrino/src/optimizer/ssa/SSA.h @@ -25,6 +25,7 @@ #define _SSA_H_ #include "MemoryManager.h" #include "Stack.h" +#include "FlowGraph.h" #include "HashTable.h" #include "Dominator.h" #include "optpass.h" @@ -35,10 +36,6 @@ class DomFrontier; class SparseOpndMap; struct OptimizerFlags; -DEFINE_OPTPASS(SSAPass) -DEFINE_OPTPASS(DeSSAPass) -DEFINE_OPTPASS(SplitSSAPass) -DEFINE_OPTPASS(FixupVarsPass) // // There is a VarDefSites for each var that records all CFG nodes in which @@ -49,26 +46,26 @@ class VarDefSites { public: VarDefSites(MemoryManager& m, uint32 max) : stack(m), alreadyRecorded(m, max), insertedPhi(m, max) {} - void addDefSite(CFGNode* node) { + void addDefSite(Node* node) { // avoid pushing the same node twice onto the stack if (alreadyRecorded.getBit(node->getDfNum())) return; alreadyRecorded.setBit(node->getDfNum(),true); stack.push(node); } - CFGNode* removeDefSite() {return stack.pop();} - void insertPhiSite(CFGNode* node) { + Node* removeDefSite() {return stack.pop();} + void insertPhiSite(Node* node) { insertedPhi.setBit(node->getDfNum(), true); addDefSite(node); } - bool beenInsertedPhi(CFGNode* node) { + bool beenInsertedPhi(Node* node) { return insertedPhi.getBit(node->getDfNum()); } - bool isDefSite(CFGNode* node) { + bool isDefSite(Node* node) { return alreadyRecorded.getBit(node->getDfNum()); } private: - Stack<CFGNode> stack; + Stack<Node> stack; BitSet alreadyRecorded; // def sites (blocks) been recorded BitSet insertedPhi; // blocks that have been inserted phi }; @@ -79,7 +76,7 @@ private: class DefSites { public: DefSites(MemoryManager& m, uint32 n) : table(m,32), mm(m), numNodes(n) {} - void addVarDefSite(VarOpnd* var, CFGNode* node) { + void addVarDefSite(VarOpnd* var, Node* node) { if (var == NULL) return; VarDefSites* varSites = table.lookup(var); @@ -100,29 +97,29 @@ class RenameStack; class SSABuilder { public: - SSABuilder(OpndManager& om, InstFactory& factory, DomFrontier& df, FlowGraph* f, OptimizerFlags& optFlags) + SSABuilder(OpndManager& om, InstFactory& factory, DomFrontier& df, ControlFlowGraph* f, const OptimizerFlags& optFlags) : instFactory(factory), frontier(df), opndManager(om), fg(f), createPhi(false), optimizerFlags(optFlags) {} bool convertSSA(MethodDesc& methodDesc); bool fixupSSA(MethodDesc& methodDesc, bool useBetterAlg); - bool fixupVars(FlowGraph* fg, MethodDesc& methodDesc); - static void deconvertSSA(FlowGraph* fg,OpndManager& opndManager); - static void splitSsaWebs(FlowGraph* fg,OpndManager& opndManager); + bool fixupVars(ControlFlowGraph* fg, MethodDesc& methodDesc); + static void deconvertSSA(ControlFlowGraph* fg,OpndManager& opndManager); + static void splitSsaWebs(ControlFlowGraph* fg,OpndManager& opndManager); private: void findDefSites(DefSites& allDefSites); void insertPhi(DefSites& allDefSites); - void createPhiInst(VarOpnd* var, CFGNode* insertedLoc); + void createPhiInst(VarOpnd* var, Node* insertedLoc); void addPhiSrc(PhiInst* i, SsaVarOpnd* src); void renameNode(RenameStack *rs, DominatorNode* dt, const StlVectorSet<VarOpnd *> *whatVars); - void clearPhiSrcs(CFGNode *, const StlVectorSet<VarOpnd *> *whatVars); - void clearPhiSrcs2(CFGNode *, + void clearPhiSrcs(Node *, const StlVectorSet<VarOpnd *> *whatVars); + void clearPhiSrcs2(Node *, const StlVectorSet<VarOpnd *> *whatVars, StlVector<VarOpnd *> *changedVars, const StlVectorSet<Opnd *> *removedVars, - StlVector<CFGNode *> &scratchNodeList); - bool checkForTrivialPhis(CFGNode *, + StlVector<Node *> &scratchNodeList); + bool checkForTrivialPhis(Node *, StlVector<VarOpnd *> &changedVars); - void checkForTrivialPhis2(CFGNode *node, + void checkForTrivialPhis2(Node *node, const StlVectorSet<VarOpnd *> *lookatVars, StlVector<VarOpnd *> *changedVars, StlVector<Opnd *> *removedVars); @@ -130,9 +127,9 @@ private: InstFactory& instFactory; DomFrontier& frontier; OpndManager& opndManager; - FlowGraph* fg; + ControlFlowGraph* fg; bool createPhi; - OptimizerFlags& optimizerFlags; + const OptimizerFlags& optimizerFlags; friend class ClearPhiSrcsWalker; friend class CheckForTrivialPhisWalker; diff --git vm/jitrino/src/optimizer/syncopt.cpp vm/jitrino/src/optimizer/syncopt.cpp index 12737b5..36212a5 100644 --- vm/jitrino/src/optimizer/syncopt.cpp +++ vm/jitrino/src/optimizer/syncopt.cpp @@ -25,11 +25,9 @@ #include <iostream> #include <algorithm> #include "Stl.h" #include "Log.h" -#include "PropertyTable.h" #include "open/types.h" #include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" #include "Loop.h" #include "Opcode.h" @@ -38,12 +36,14 @@ #include "opndmap.h" #include "dataflow.h" #include "unionfind.h" #include "syncopt.h" +#include "FlowGraph.h" +#include "PMFAction.h" namespace Jitrino { #define EXTRA_DEBUGGING 0 -DEFINE_OPTPASS_IMPL(SyncOptPass, syncopt, "Synchronization Optimization") +DEFINE_SESSION_ACTION(SyncOptPass, syncopt, "Synchronization Optimization") void SyncOptPass::_run(IRManager& irm) { @@ -51,18 +51,16 @@ SyncOptPass::_run(IRManager& irm) { opt.runPass(); } -SyncOpt::Flags *SyncOpt::defaultFlags = 0; SyncOpt::SyncOpt(IRManager &irManager0, MemoryManager& memManager) : irManager(irManager0), mm(memManager), - flags(*defaultFlags), + flags(*irManager.getOptimizerFlags().syncOptFlags), lockType(0), lockAddrType(0), lockVar(memManager) { - assert(defaultFlags); } SyncOpt::~SyncOpt() @@ -70,26 +68,22 @@ SyncOpt::~SyncOpt() } void -SyncOpt::readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params) -{ - if (!defaultFlags) - defaultFlags = new Flags; - - defaultFlags->optimistic = params->lookupBool("opt::sync::optimistic", false); - defaultFlags->use_IncRecCount - = params->lookupBool("opt::sync::use_increccount", false); - defaultFlags->balance = params->lookupBool("opt::sync::balance", true); - defaultFlags->transform = params->lookupBool("opt::sync::transform", true); - defaultFlags->transform2 = params->lookupBool("opt::sync::transform2", true); +SyncOpt::readFlags(Action* argSource, SyncOptFlags* flags) { + IAction::HPipeline p = NULL; //default pipeline for argSource + flags->optimistic = argSource->getBoolArg(p, "sync.optimistic", false); + flags->use_IncRecCount = argSource->getBoolArg(p, "sync.use_increccount", false); + flags->balance = argSource->getBoolArg(p, "sync.balance", true); + flags->transform = argSource->getBoolArg(p, "sync.transform", true); + flags->transform2 = argSource->getBoolArg(p, "sync.transform2", true); } -void SyncOpt::showFlagsFromCommandLine() -{ - Log::out() << " opt::sync::optimistic[={OFF|on}] = convert region with a call to optimistic balanced enter/exit" << ::std::endl; - Log::out() << " opt::sync::use_increccount[={OFF|on}] = use increccount [not working yet]" << ::std::endl; - Log::out() << " opt::sync::balance[={off|ON}] = do balancing" << ::std::endl; - Log::out() << " opt::sync::transform[={off|ON}] = do rewriting that facilitates balancing" << ::std::endl; - Log::out() << " opt::sync::transform2[={OFF|on}] = give dispatch nodes a dispatch succ" << ::std::endl; +void SyncOpt::showFlags(std::ostream& os) { + os << " syncopt flags:"<<std::endl; + os << " sync.optimistic[={OFF|on}] - convert region with a call to optimistic balanced enter/exit" << std::endl; + os << " sync.use_increccount[={OFF|on}] - use increccount [not working yet]" << std::endl; + os << " sync.balance[={off|ON}] - do balancing" << ::std::endl; + os << " sync.transform[={off|ON}] - do rewriting that facilitates balancing" << std::endl; + os << " sync.transform2[={OFF|on}] - give dispatch nodes a dispatch succ" << std::endl; } @@ -99,69 +93,69 @@ protected: SyncOpt *thePass; IRManager &irm; MemoryManager &mm; - FlowGraph &fg; - CFGNode *unwind; + ControlFlowGraph &fg; + Node *unwind; public: FixupSyncEdgesWalker(IRManager &irm0, MemoryManager& mm0) : irm(irm0), mm(mm0), fg(irm0.getFlowGraph()), unwind(0) { - unwind = fg.getUnwind(); + unwind = fg.getUnwindNode(); }; - void applyToCFGNode(CFGNode *node); - bool applyToNode1(CFGNode *node); - bool applyToNode2(CFGNode *node); - bool applyToNode3(CFGNode *node); + void applyToCFGNode(Node *node); + bool applyToNode1(Node *node); + bool applyToNode2(Node *node); + bool applyToNode3(Node *node); - bool isDispatchNode(CFGNode *node) { return node->isDispatchNode(); }; - bool isCatchAll(CFGNode *node, Opnd *&caughtOpnd, CFGNode *&catchInstNode); - bool isMonExit(CFGNode *node, Opnd *&monOpnd, CFGNode *&dispatchNode, - CFGEdge *&dispatchEdge); - bool isCatchAllAndMonExit(CFGNode *node, Opnd *&caughtOpnd, Opnd *&monOpnd, CFGNode *&dispatchNode, - CFGEdge *&dispatchEdge, - CFGNode *&catchInstNode); - bool isJustThrow(CFGNode *node, Opnd *&thrownOpnd, CFGNode *&dispatchNode); - bool isUnwind(CFGNode *node) { return (node == unwind); }; - CFGNode *getFirstCatchNode(CFGNode *dispatchNode); + bool isDispatchNode(Node *node) { return node->isDispatchNode(); }; + bool isCatchAll(Node *node, Opnd *&caughtOpnd, Node *&catchInstNode); + bool isMonExit(Node *node, Opnd *&monOpnd, Node *&dispatchNode, + Edge *&dispatchEdge); + bool isCatchAllAndMonExit(Node *node, Opnd *&caughtOpnd, Opnd *&monOpnd, Node *&dispatchNode, + Edge *&dispatchEdge, + Node *&catchInstNode); + bool isJustThrow(Node *node, Opnd *&thrownOpnd, Node *&dispatchNode); + bool isUnwind(Node *node) { return (node == unwind); }; + Node *getFirstCatchNode(Node *dispatchNode); }; -bool FixupSyncEdgesWalker::isCatchAll(CFGNode *node, Opnd *&caughtOpnd, - CFGNode *&catchInstNode) +bool FixupSyncEdgesWalker::isCatchAll(Node *node, Opnd *&caughtOpnd, + Node *&catchInstNode) { - Inst *firstInst = node->getFirstInst(); + Inst *firstInst = (Inst*)node->getFirstInst(); if (!firstInst->isCatchLabel()) return false; CatchLabelInst *catchLabelInst = firstInst->asCatchLabelInst(); Type *exceptionType = catchLabelInst->getExceptionType(); if (exceptionType != irm.getTypeManager().getSystemObjectType()) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " isCatchAll case 1" << ::std::endl; } return false; } - Inst *nextInst = firstInst->next(); - CFGNode *ciNode = node; + Inst *nextInst = firstInst->getNextInst(); + Node *ciNode = node; int counter = 0; while (nextInst->getOpcode() != Op_Catch) { if (nextInst == firstInst) { if (++counter > 3) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " isCatchAll case 5" << ::std::endl; } // don't think this is possible, but bound the loop just in case. return false; } if (!ciNode->hasOnlyOneSuccEdge()) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " isCatchAll case 4" << ::std::endl; } return false; } - CFGNode *succ = (*(ciNode->getOutEdges().begin()))->getTargetNode(); + Node *succ = (*(ciNode->getOutEdges().begin()))->getTargetNode(); ciNode = succ; - firstInst = succ->getFirstInst(); - nextInst = firstInst->next(); + firstInst = (Inst*)succ->getFirstInst(); + nextInst = firstInst->getNextInst(); } } Opnd *opnd = nextInst->getDst(); @@ -170,38 +164,38 @@ bool FixupSyncEdgesWalker::isCatchAll(CF // yes catchInstNode = ciNode; caughtOpnd = opnd; - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " isCatchAll case 2" << ::std::endl; } return true; } - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " isCatchAll case 3" << ::std::endl; } return false; } -bool FixupSyncEdgesWalker::isMonExit(CFGNode *node, Opnd *&monOpnd, CFGNode *&dispatchNode, - CFGEdge *&dispatchEdge) +bool FixupSyncEdgesWalker::isMonExit(Node *node, Opnd *&monOpnd, Node *&dispatchNode, + Edge *&dispatchEdge) { - Inst *lastInst = node->getLastInst(); + Inst *lastInst = (Inst*)node->getLastInst(); Opcode opcode = lastInst->getOpcode(); if (!((opcode == Op_TauMonitorExit) || (opcode == Op_OptimisticBalancedMonitorExit))) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << "isMonExit opcode is " << (int) opcode << ::std::endl; } return false; } monOpnd = lastInst->getSrc(0); - const CFGEdgeDeque &outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = node->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (target->isDispatchNode()) { dispatchNode = target; dispatchEdge = e; @@ -212,23 +206,23 @@ bool FixupSyncEdgesWalker::isMonExit(CFG return false; } -bool FixupSyncEdgesWalker::isCatchAllAndMonExit(CFGNode *node, Opnd *&caughtOpnd, - Opnd *&monOpnd, CFGNode *&dispatchNode, - CFGEdge *&dispatchEdge, - CFGNode *&catchInstNode) +bool FixupSyncEdgesWalker::isCatchAllAndMonExit(Node *node, Opnd *&caughtOpnd, + Opnd *&monOpnd, Node *&dispatchNode, + Edge *&dispatchEdge, + Node *&catchInstNode) { catchInstNode = 0; if (isCatchAll(node, caughtOpnd, catchInstNode) && isMonExit(catchInstNode, monOpnd, dispatchNode, dispatchEdge)) { // make sure that's all it is assert(catchInstNode); - Inst *labelInst = catchInstNode->getFirstInst(); - Inst *catchInst = labelInst->next(); + Inst *labelInst = (Inst*)catchInstNode->getFirstInst(); + Inst *catchInst = labelInst->getNextInst(); // with DPGO, we may see an incCounter here - Inst *thirdInst = catchInst->next(); // monexit or tausafe or incCounter - Inst *fourthInst = thirdInst->next(); // label or monexit or tausafe or incCounter - Inst *fifthInst = fourthInst->next(); // label or taumonexit(tausafe) - Inst *sixthInst = fifthInst->next(); // .. or label + Inst *thirdInst = catchInst->getNextInst(); // monexit or tausafe or incCounter + Inst *fourthInst = thirdInst->getNextInst(); // label or monexit or tausafe or incCounter + Inst *fifthInst = fourthInst->getNextInst(); // label or taumonexit(tausafe) + Inst *sixthInst = fifthInst->getNextInst(); // .. or label return ((labelInst == fourthInst) || ((labelInst == fifthInst) && ((thirdInst->getOpcode() == Op_TauSafe) || @@ -243,21 +237,21 @@ bool FixupSyncEdgesWalker::isCatchAllAnd return false; } -bool FixupSyncEdgesWalker::isJustThrow(CFGNode *node, Opnd *&thrownOpnd, CFGNode *&dispatchNode) +bool FixupSyncEdgesWalker::isJustThrow(Node *node, Opnd *&thrownOpnd, Node *&dispatchNode) { - Inst *lastInst = node->getLastInst(); + Inst *lastInst = (Inst*)node->getLastInst(); Opcode opcode = lastInst->getOpcode(); if (opcode != Op_Throw) { return false; } - Inst *prevInst = lastInst->prev(); + Inst *prevInst = lastInst->getPrevInst(); if (prevInst->isLabel()) { // check for dispatchNode assert(node->hasOnlyOneSuccEdge()); - const CFGEdgeDeque &outEdges = node->getOutEdges(); + const Edges &outEdges = node->getOutEdges(); assert(outEdges.size() == 1); - CFGEdge *e = *(outEdges.begin()); - CFGNode *target = e->getTargetNode(); + Edge *e = *(outEdges.begin()); + Node *target = e->getTargetNode(); assert((target == unwind) || (target->isDispatchNode())); thrownOpnd = lastInst->getSrc(0); @@ -267,16 +261,16 @@ bool FixupSyncEdgesWalker::isJustThrow(C return false; } -CFGNode *FixupSyncEdgesWalker::getFirstCatchNode(CFGNode *dispatchNode) +Node *FixupSyncEdgesWalker::getFirstCatchNode(Node *dispatchNode) { assert(dispatchNode->isDispatchNode()); - const CFGEdgeDeque &outEdges = dispatchNode->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = dispatchNode->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (!target->isDispatchNode()) { return target; } @@ -294,58 +288,58 @@ CFGNode *FixupSyncEdgesWalker::getFirstC bool -FixupSyncEdgesWalker::applyToNode1(CFGNode *node) +FixupSyncEdgesWalker::applyToNode1(Node *node) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { - Log::out() << "applyToNode1 examining node"; node->print(Log::out()); Log::out() << ::std::endl; + if (EXTRA_DEBUGGING && Log::isEnabled()) { + Log::out() << "applyToNode1 examining node"; FlowGraph::print(Log::out(), node); Log::out() << ::std::endl; } - CFGNode *dispatch1 = 0; - CFGEdge *dispatch1edge = 0; + Node *dispatch1 = 0; + Edge *dispatch1edge = 0; Opnd *monOpnd1 = 0; if (!isMonExit(node, monOpnd1, dispatch1, dispatch1edge)) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 1" << ::std::endl; } return false; } - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 1b" << ::std::endl; } - CFGNode *catchNode = getFirstCatchNode(dispatch1); + Node *catchNode = getFirstCatchNode(dispatch1); Opnd *caughtOpnd = 0; Opnd *monOpnd2 = 0; - CFGNode *dispatchNode2ignore = 0; - CFGEdge *dispatchEdge2ignore = 0; - CFGNode *catchInstNode = 0; + Node *dispatchNode2ignore = 0; + Edge *dispatchEdge2ignore = 0; + Node *catchInstNode = 0; if (!isCatchAllAndMonExit(catchNode, caughtOpnd, monOpnd2, dispatchNode2ignore, dispatchEdge2ignore, catchInstNode)) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 2" << ::std::endl; } return false; } - CFGEdge *outEdge = (CFGEdge *)catchInstNode->getUnconditionalEdge(); + Edge *outEdge = (Edge *)catchInstNode->getUnconditionalEdge(); assert(outEdge); - CFGNode *nextNode = outEdge->getTargetNode(); + Node *nextNode = outEdge->getTargetNode(); Opnd *thrownOpnd = 0; - CFGNode *dispatch2 = 0; + Node *dispatch2 = 0; if (!isJustThrow(nextNode, thrownOpnd, dispatch2)) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 3, nextNode is "; - nextNode->print(Log::out()); + FlowGraph::print(Log::out(), nextNode); Log::out() << ::std::endl; } return false; } if (!((monOpnd1 == monOpnd2) && (caughtOpnd == thrownOpnd))) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 4" << ::std::endl; } return false; @@ -354,13 +348,13 @@ FixupSyncEdgesWalker::applyToNode1(CFGNo // found it if (dispatch1 == dispatch2) { // it's a self-loop - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 5" << ::std::endl; } assert(0); } - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 6" << ::std::endl; } fg.replaceEdgeTarget(dispatch1edge, dispatch2); @@ -369,34 +363,34 @@ FixupSyncEdgesWalker::applyToNode1(CFGNo // check for Dispatch -> catchall, eliminate any exception edge on the dispatch bool -FixupSyncEdgesWalker::applyToNode2(CFGNode *node) +FixupSyncEdgesWalker::applyToNode2(Node *node) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { - Log::out() << "applyToNode2 examining node"; node->print(Log::out()); Log::out() << ::std::endl; + if (EXTRA_DEBUGGING && Log::isEnabled()) { + Log::out() << "applyToNode2 examining node"; FlowGraph::print(Log::out(), node); Log::out() << ::std::endl; } if (node == unwind) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 1" << ::std::endl; } return false; } if (!node->isDispatchNode()) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 2" << ::std::endl; } return false; } - const CFGEdgeDeque &outEdges = node->getOutEdges(); - CFGEdge *dispatchEdge = 0; + const Edges &outEdges = node->getOutEdges(); + Edge *dispatchEdge = 0; - CFGEdgeDeque::const_iterator + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (target->isDispatchNode()) { assert(!dispatchEdge); dispatchEdge = e; @@ -404,35 +398,35 @@ FixupSyncEdgesWalker::applyToNode2(CFGNo } if (!dispatchEdge) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 3" << ::std::endl; } return false; } - CFGEdge *catchEdge = 0; + Edge *catchEdge = 0; for (eiter = outEdges.begin() ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - if (e->getKind() == CFGEdge::Catch) { + Edge *e = *eiter; + if (e->getKind() == Edge::Kind_Catch) { catchEdge = e; - CFGNode *catchNode = catchEdge->getTargetNode(); + Node *catchNode = catchEdge->getTargetNode(); Opnd *scratch; - CFGNode *catchInstNode; + Node *catchInstNode; if (!isCatchAll(catchNode, scratch, catchInstNode)) { continue; } // dispatch node has a catch-all, doesn't need fall-through fg.removeEdge(dispatchEdge); - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 6" << ::std::endl; } return true; } } - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 4" << ::std::endl; } return false; @@ -444,41 +438,41 @@ FixupSyncEdgesWalker::applyToNode2(CFGNo // monexit t1 --> Dispatch2 --> Catch(t2:object); --> L1': goto L1' bool -FixupSyncEdgesWalker::applyToNode3(CFGNode *node) +FixupSyncEdgesWalker::applyToNode3(Node *node) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { - Log::out() << "applyToNode3 examining node"; node->print(Log::out()); Log::out() << ::std::endl; + if (EXTRA_DEBUGGING && Log::isEnabled()) { + Log::out() << "applyToNode3 examining node"; FlowGraph::print(Log::out(), node); Log::out() << ::std::endl; } - CFGNode *catchNode = node; + Node *catchNode = node; Opnd *caughtOpnd = 0; Opnd *monOpnd2 = 0; - CFGNode *dispatchNode1 = 0; - CFGEdge *dispatchEdge1 = 0; - CFGNode *catchInstNode = 0; + Node *dispatchNode1 = 0; + Edge *dispatchEdge1 = 0; + Node *catchInstNode = 0; if (!isCatchAllAndMonExit(catchNode, caughtOpnd, monOpnd2, dispatchNode1, dispatchEdge1, catchInstNode)) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 1" << ::std::endl; } return false; } - Inst *catchNodeFirstInst = catchNode->getFirstInst(); + Inst *catchNodeFirstInst = (Inst*)catchNode->getFirstInst(); CatchLabelInst *catchLabelInst = catchNodeFirstInst->asCatchLabelInst(); assert(catchLabelInst); - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 2" << ::std::endl; } // must be high-priority catch node uint32 order = catchLabelInst->getOrder(); if (order != 0) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 3" << ::std::endl; } return false; @@ -488,41 +482,40 @@ FixupSyncEdgesWalker::applyToNode3(CFGNo // must be only exception edge to this dispatch if (dispatchNode1->getInEdges().size() != 1) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 4" << ::std::endl; } return false; } // find the catch node edge - const CFGEdgeDeque &outEdges = dispatchNode1->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = dispatchNode1->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (target == catchNode) { - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 5" << ::std::endl; } TypeManager &typeManager = irm.getTypeManager(); InstFactory &instFactory = irm.getInstFactory(); OpndManager &opndManager = irm.getOpndManager(); - Opnd* ex = - opndManager.createSsaTmpOpnd(typeManager.getSystemObjectType()); - CFGNode *newCatchNode = fg.createCatchNode(0, ex->getType()); - newCatchNode->append(instFactory.makeCatch(ex)); + Opnd* ex = opndManager.createSsaTmpOpnd(typeManager.getSystemObjectType()); + Node *newCatchNode = fg.createBlockNode(instFactory.makeCatchLabel(0, ex->getType())); + newCatchNode->appendInst(instFactory.makeCatch(ex)); - CFGNode *newLoopNode = fg.createBlockNode(); + Node *newLoopNode = fg.createBlockNode(instFactory.makeLabel()); #ifdef _DEBUG - Inst *newLoopFirstInst = newLoopNode->getFirstInst(); + Inst *newLoopFirstInst = (Inst*)newLoopNode->getFirstInst(); assert(newLoopFirstInst); LabelInst *newLoopLabelInst = newLoopFirstInst->asLabelInst(); #endif - assert(newLoopLabelInst); + assert(newLoopLabelInst); fg.replaceEdgeTarget(e, newCatchNode); fg.addEdge(newCatchNode, newLoopNode); @@ -530,14 +523,14 @@ #endif return true; } } - if (EXTRA_DEBUGGING && Log::cat_opt_sync()->isDebugEnabled()) { + if (EXTRA_DEBUGGING && Log::isEnabled()) { Log::out() << " case 6" << ::std::endl; } return false; } void -FixupSyncEdgesWalker::applyToCFGNode(CFGNode *node) +FixupSyncEdgesWalker::applyToCFGNode(Node *node) { applyToNode1(node); applyToNode2(node); @@ -552,19 +545,19 @@ public: { }; ~FixupSyncEdgesWalker2() {}; - void applyToCFGNode(CFGNode *node); + void applyToCFGNode(Node *node); }; -void FixupSyncEdgesWalker2::applyToCFGNode(CFGNode *node) +void FixupSyncEdgesWalker2::applyToCFGNode(Node *node) { if (node->isDispatchNode() && (node != unwind)) { - const CFGEdgeDeque &outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = node->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); if (target->isDispatchNode()) { return; } @@ -577,22 +570,22 @@ void FixupSyncEdgesWalker2::applyToCFGNo void SyncOpt::runPass() { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Starting SyncOpt Pass" << ::std::endl; Log::out() << " MemManager bytes_allocated= " << (int) mm.bytes_allocated() << ::std::endl; } { - const CFGNodeDeque &nodes = irManager.getFlowGraph().getNodes(); - CFGNodeDeque::const_iterator + const Nodes &nodes = irManager.getFlowGraph().getNodes(); + Nodes::const_iterator iter = nodes.begin(), end = nodes.end(); for (; iter != end; ++iter) { - CFGNode *node = *iter; - Inst *firstInst = node->getFirstInst(); - Inst *inst = firstInst->next(); - while (inst != firstInst) { + Node *node = *iter; + Inst *firstInst = (Inst*)node->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + while (inst != NULL) { Opcode opcode = inst->getOpcode(); switch (opcode) { case Op_TauMonitorEnter: @@ -605,10 +598,10 @@ void SyncOpt::runPass() default: break; } - inst = inst->next(); + inst = inst->getNextInst(); } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "No sync found, skipping SyncOpt Pass" << ::std::endl; Log::out() << " MemManager bytes_allocated= " << (int) mm.bytes_allocated() << ::std::endl; @@ -619,18 +612,18 @@ void SyncOpt::runPass() } if (flags.transform) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Preprocessing graph to reduce monExit->monExit loops" << ::std::endl; Log::out() << "PRINTING LOG: IR before sync exception edge fixup" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } FixupSyncEdgesWalker fixupEdges(irManager, mm); NodeWalk<FixupSyncEdgesWalker>(irManager.getFlowGraph(), fixupEdges); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "PRINTING LOG: IR after sync exception edge fixup" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } } @@ -666,38 +659,38 @@ void SyncOpt::runPass() // BalancedMonitorEnter(). On any path leading from a BalancedMonitorEnter without a // following BalancedMonitorExit, insert an IncRecCount() - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "PRINTING LOG: IR before sync pass 1" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } findBalancedExits(false, false); // not optimistic, no increccount - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "PRINTING LOG: IR after sync pass 1" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } if (flags.optimistic) { Opnd *syncMethodOpnd = 0; - CFGNode *tmpDispatchNode = 0; - CFGNode *tmpCatchNode = 0; - CFGNode *tmpRethrowNode = 0; + Node *tmpDispatchNode = 0; + Node *tmpCatchNode = 0; + Node *tmpRethrowNode = 0; MethodDesc &desc = irManager.getMethodDesc(); if (desc.isSynchronized() && !desc.isStatic()) { // synchronized on first param - FlowGraph &fg = irManager.getFlowGraph(); - CFGNode *entry = fg.getEntry(); - Inst *firstInst = entry->getFirstInst(); - Inst *inst = firstInst->next(); - while (inst != firstInst) { + ControlFlowGraph &fg = irManager.getFlowGraph(); + Node *entry = fg.getEntryNode(); + Inst *firstInst = (Inst*)entry->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + while (inst != NULL) { if (inst->getOpcode() == Op_DefArg) { break; } - inst = inst->next(); + inst = inst->getNextInst(); } - assert((inst != firstInst) && (inst->getOpcode() == Op_DefArg)); + assert((inst != NULL) && (inst->getOpcode() == Op_DefArg)); Opnd *thisOpnd = inst->getDst(); assert(!syncMethodOpnd); @@ -705,7 +698,7 @@ void SyncOpt::runPass() } else { } - bool needToPatchUnwind = syncMethodOpnd && (irManager.getFlowGraph().getUnwind() != NULL); + bool needToPatchUnwind = syncMethodOpnd && (irManager.getFlowGraph().getUnwindNode() != NULL); if (needToPatchUnwind) { insertUnwindMonitorExit(syncMethodOpnd, tmpDispatchNode, tmpCatchNode, tmpRethrowNode); @@ -716,30 +709,30 @@ void SyncOpt::runPass() removeUnwindMonitorExit(syncMethodOpnd, tmpDispatchNode, tmpCatchNode, tmpRethrowNode); } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "PRINTING LOG: IR after sync pass 2" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } } } if (flags.transform2) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Postrocessing graph to add dispatch edges" << ::std::endl; Log::out() << "PRINTING LOG: IR before dispatch edge fixup" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } FixupSyncEdgesWalker2 fixupEdges(irManager, mm); NodeWalk<FixupSyncEdgesWalker2>(irManager.getFlowGraph(), fixupEdges); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "PRINTING LOG: IR after dispatch edge fixup" << ::std::endl; - irManager.getFlowGraph().printInsts(Log::out(), irManager.getMethodDesc()); + FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Finished SyncOpt Pass" << ::std::endl; Log::out() << " MemManager bytes_allocated= " << (int) mm.bytes_allocated() << ::std::endl; @@ -817,7 +810,7 @@ public: } }; void invalidateMonitors(bool optimistic, bool use_IncRecCount) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before invalidateMonitors(): "; print(Log::out()); Log::out() << ::std::endl; @@ -827,14 +820,14 @@ public: } else { state = Bottom; depth = 0; } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after invalidateMonitors(): "; print(Log::out()); Log::out() << ::std::endl; } }; void openMonitor(Inst *monitorEnter, Opnd *obj) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before openMonitor(" << (int) monitorEnter->getId() << "): "; @@ -855,7 +848,7 @@ public: depth = 0; } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after openMonitor(" << (int) monitorEnter->getId() << "): "; @@ -864,7 +857,7 @@ public: } } void closeMonitor(Inst *monitorExit, Opnd *obj) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before closeMonitor("; monitorExit->print(Log::out()); Log::out() << ", "; @@ -879,7 +872,7 @@ public: state = Bottom; } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after closeMonitor("; obj->print(Log::out()); Log::out() << "): "; @@ -890,7 +883,7 @@ public: // applies given inst to this value void apply(Inst *i, MemoryManager &mm, bool optimistic, bool use_IncRecCount) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "SyncOptDfValue visiting instr "; i->print(Log::out()); Log::out() << ::std::endl; @@ -926,11 +919,11 @@ public: class SyncOptTfValue : public DataflowTF<SyncOptDfValue> { MemoryManager &mem; - CFGNode *node; + Node *node; bool optimistic; bool use_IncRecCount; public: - SyncOptTfValue(MemoryManager &mm, CFGNode *theNode, bool optimistic0, + SyncOptTfValue(MemoryManager &mm, Node *theNode, bool optimistic0, bool use_IncRecCount0) : mem(mm), node(theNode), optimistic(optimistic0), @@ -938,16 +931,16 @@ public: // returns true if changed bool apply(const SyncOptDfValue &in, SyncOptDfValue &out) { SyncOptDfValue res = in; - Inst* firstInst = node->getFirstInst(); + Inst* firstInst = (Inst*)node->getFirstInst(); Inst * inst = firstInst; do { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "visiting instr "; inst->print(Log::out()); Log::out() << ::std::endl; } res.apply(inst, mem, optimistic, use_IncRecCount); - inst = inst->next(); - } while (inst != firstInst); + inst = inst->getNextInst(); + } while (inst != NULL); return out.meetWith(res); } @@ -963,7 +956,7 @@ public: {}; typedef SyncOptDfValue ValueType; - DataflowTF<SyncOptDfValue> *getNodeBehavior(CFGNode *node) { + DataflowTF<SyncOptDfValue> *getNodeBehavior(Node *node) { SyncOptTfValue *res = new (mm) SyncOptTfValue(mm, node, optimistic, use_IncRecCount); return res; @@ -1013,7 +1006,7 @@ public: return new (mem) SyncClique(obj); }; void applyToInst(Inst *i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "SyncOptDfValue visiting instr "; i->print(Log::out()); Log::out() << ::std::endl; @@ -1047,7 +1040,7 @@ public: } } void invalidateMonitors(Inst *i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before invalidateMonitors(" << (int) i->getId() << "), depth=" @@ -1068,7 +1061,7 @@ public: } else { for (uint32 i=0; i<currentDepth; ++i) { // invalidate all open monitors - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking01 "; (*currentStack)[i]->print(Log::out()); Log::out() << " to "; @@ -1081,7 +1074,7 @@ public: } } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after invalidateMonitors(" << (int) i->getId() << "), depth=" @@ -1090,7 +1083,7 @@ public: } }; void openMonitor(Inst *monitorEnter, Opnd *obj) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before openMonitor(" << (int) monitorEnter->getId() << ", "; @@ -1107,7 +1100,7 @@ public: (*currentStack)[currentDepth] = clique; currentDepth += 1; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after openMonitor(" << (int) monitorEnter->getId() << ", "; @@ -1118,7 +1111,7 @@ public: } } void closeMonitor(Inst *monitorExit, Opnd *obj) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " before closeMonitor(" << (int) monitorExit->getId() << ", "; @@ -1132,7 +1125,7 @@ public: assert(currentStack); SyncClique *currentMonitor = (*currentStack)[currentDepth-1]; currentMonitor = currentMonitor->find(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " setting monitorCliques[" << (int) monitorExit->getId() << "] = "; @@ -1158,13 +1151,13 @@ public: needRecCount[monitorExit] = openSet; } } else { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " currentDepth is 0 at monitorExit; setting " << " monitorCliques[monitorExit] = bottom" << ::std::endl; } monitorCliques[monitorExit] = bottomClique; } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " after closeMonitor(" << (int) monitorExit->getId() << ", "; @@ -1194,13 +1187,13 @@ SyncOpt::getLockVar(Opnd *obj) Inst *objDef = obj->getInst(); if (objDef->getOperation().mustEndBlock()) { // can't insert right after objectdef - CFGNode *objDefNode = objDef->getNode(); - CFGEdge *outEdge = (CFGEdge*) objDefNode->getUnconditionalEdge(); + Node *objDefNode = objDef->getNode(); + Edge *outEdge = objDefNode->getUnconditionalEdge(); assert(outEdge); - CFGNode *nextNode = outEdge->getTargetNode(); - Inst *nextInst = nextNode->getFirstInst()->next(); - while (nextInst->getOpcode() == Op_Phi) { - nextInst = nextInst->next(); + Node *nextNode = outEdge->getTargetNode(); + Inst *nextInst = (Inst*)nextNode->getSecondInst(); + while (nextInst!=NULL && nextInst->getOpcode() == Op_Phi) { + nextInst = nextInst->getNextInst(); } ldLockInst->insertBefore(nextInst); } else { @@ -1238,11 +1231,10 @@ uint32 SyncOpt::findBalancedExits_Stage1 { SyncOptForwardInstance findBalancedExits(mm, optimistic, use_IncRecCount); - FlowGraph &fg = irManager.getFlowGraph(); + ControlFlowGraph &fg = irManager.getFlowGraph(); solve<SyncOptDfValue>(&fg, findBalancedExits, true, // forwards mm, - entrySolution, exitSolution, - Log::cat_opt_sync(), true); // ignore exception edges + entrySolution, exitSolution, true); // ignore exception edges uint32 numCliques = 0; { for (uint32 i = 0; i<numNodes; i++) { @@ -1263,7 +1255,7 @@ void SyncOpt::linkStacks(uint32 depth1, uint32 mindepth = ::std::min(depth1, depth2); uint32 i = 0; for ( ; i < mindepth; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking02 "; stack2[depth2-1-i].print(Log::out()); Log::out() << " with "; @@ -1273,7 +1265,7 @@ void SyncOpt::linkStacks(uint32 depth1, stack2[depth2-1-i].link(&stack1[depth1-1-i]); } for ( ; i < depth1; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking03 "; stack1[depth1-1-i].print(Log::out()); Log::out() << " with bottom ("; @@ -1283,7 +1275,7 @@ void SyncOpt::linkStacks(uint32 depth1, stack1[depth1-1-i].link(bottomClique); } for ( ; i < depth2; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking04 "; stack2[depth2-1-i].print(Log::out()); Log::out() << " with bottom ("; @@ -1296,7 +1288,7 @@ void SyncOpt::linkStacks(uint32 depth1, // starting with cliques in inStack[0..depthIn-1], walk node with walker // and union result with outStack[0..depthOut-1]. stackspace is available for scratch. -void SyncOpt::findBalancedExits_Stage2a(CFGNode *node, +void SyncOpt::findBalancedExits_Stage2a(Node *node, uint32 depthIn, SyncClique *inStack, uint32 depthOut, @@ -1312,7 +1304,7 @@ void SyncOpt::findBalancedExits_Stage2a( } } assert(&walker.mem == &mm); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " Before walk, depthIn=" << (int) depthIn << ", stack = "; for (uint32 i=0; i<depthIn; i++) { @@ -1331,7 +1323,7 @@ void SyncOpt::findBalancedExits_Stage2a( StlVector<SyncClique *> *currentStack = walker.getStack(); assert(currentStack); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " After walk of node #" << (int) node->getId() << ", currentDepth=" @@ -1345,7 +1337,7 @@ void SyncOpt::findBalancedExits_Stage2a( } uint32 mindepth = ::std::min(currentDepth, depthOut); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " Linking05 with outstack of depth " << (int) depthOut << ", outstack = "; @@ -1358,7 +1350,7 @@ void SyncOpt::findBalancedExits_Stage2a( { uint32 i = 0; for ( ; i < mindepth; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking06 "; (*currentStack)[currentDepth-1-i]->print(Log::out()); Log::out() << " with "; @@ -1368,7 +1360,7 @@ void SyncOpt::findBalancedExits_Stage2a( (*currentStack)[currentDepth-1-i]->link(&outStack[depthOut-1-i]); } for ( ; i < currentDepth; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking07 "; (*currentStack)[currentDepth-1-i]->print(Log::out()); Log::out() << " with bottom ("; @@ -1378,7 +1370,7 @@ void SyncOpt::findBalancedExits_Stage2a( (*currentStack)[currentDepth-1-i]->link(bottomClique); } for ( ; i < depthOut; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking08 "; outStack[depthOut-1-i].print(Log::out()); Log::out() << " with bottom ("; @@ -1407,22 +1399,22 @@ void SyncOpt::findBalancedExits_Stage2(b needRecCount); StlVector<SyncClique *>stackspace(mm, SYNC_STACK_TOP_DEPTH+1, 0); - FlowGraph &fg = irManager.getFlowGraph(); - const CFGNodeDeque &nodes = fg.getNodes(); + ControlFlowGraph &fg = irManager.getFlowGraph(); + const Nodes &nodes = fg.getNodes(); assert(&walker.mem == &mm); - CFGNodeDeque::const_iterator + Nodes::const_iterator iter = nodes.begin(), end = nodes.end(); for (; iter != end; ++iter) { - CFGNode *node = *iter; + Node *node = *iter; uint32 nodeId = node->getId(); uint32 depthIn = entrySolution[nodeId].getDepth(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Considering node " << (int) nodeId << " with depthIn=" << (int) depthIn << ::std::endl; } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { if (!entrySolution[nodeId].isTop()) { Log::out() << "Node solution is not Top" << ::std::endl; } else { @@ -1439,21 +1431,21 @@ void SyncOpt::findBalancedExits_Stage2(b walker, stackspace, bottomClique); // link with every successor except for exception edges from MonitorExit - const CFGEdgeDeque &outEdges = node->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges &outEdges = node->getOutEdges(); + Edges::const_iterator eiter = outEdges.begin(), eend = outEdges.end(); for ( ; eiter != eend; ++eiter) { - CFGEdge *e = *eiter; - CFGNode *target = e->getTargetNode(); + Edge *e = *eiter; + Node *target = e->getTargetNode(); // skip any exception edge from a MonitorExit unless optimistic if (!optimistic && target->isDispatchNode()) { - Inst *lastInst = node->getLastInst(); + Inst *lastInst = (Inst*)node->getLastInst(); if ((lastInst->getOpcode() == Op_TauMonitorExit) || (lastInst->getOpcode() == Op_OptimisticBalancedMonitorExit)) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Skipping monitor exception edge from node #" << (int) nodeId << " to dispatch node #" @@ -1471,7 +1463,7 @@ void SyncOpt::findBalancedExits_Stage2(b SyncClique *targetStack = entryCliques[targetId]; uint32 targetDepth = entrySolution[targetId].getDepth(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Linking09 output of node #" << (int) nodeId << " with input of node #" @@ -1485,12 +1477,12 @@ void SyncOpt::findBalancedExits_Stage2(b } // link any open monitor at the exit node with bottom { - CFGNode *exitNode = fg.getExit(); + Node *exitNode = fg.getExitNode(); uint32 exitId = exitNode->getId(); uint32 depthIn = entrySolution[exitId].getDepth(); SyncClique *exitStack = entryCliques[exitId]; for (uint32 i=0; i< depthIn; ++i) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " for exit node: i=" << (int) i; Log::out() << " linking10 "; @@ -1506,7 +1498,7 @@ void SyncOpt::findBalancedExits_Stage2(b bool SyncOpt::monitorExitIsBad(Inst *monExit, SyncClique *clique, SyncClique *cliqueRoot, SyncClique *bottomCliqueRoot) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Considering monitorExit instruction: "; monExit->print(Log::out()); Log::out() << " with "; @@ -1517,17 +1509,17 @@ bool SyncOpt::monitorExitIsBad(Inst *mon } if (cliqueRoot == bottomCliqueRoot) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " clique == bottom" << ::std::endl; } return true; } else if (!cliqueRoot->opnd) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " cliqueRoot->opnd = NULL" << ::std::endl; } return true; } else if (cliqueRoot->opnd != monExit->getSrc(0)) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " clique->opnd != monitorExit->opnd:" << ::std::endl; Log::out() << " Clique="; if (cliqueRoot->opnd) @@ -1591,7 +1583,7 @@ void SyncOpt::findBalancedExits_Stage3(b StlVector<Inst *> newBadMonitorExits(mm); SyncClique *bottomCliqueRoot = bottomClique->find(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " beginning Stage3" << ::std::endl; } @@ -1599,7 +1591,7 @@ void SyncOpt::findBalancedExits_Stage3(b while (needToCheckAgain) { needToCheckAgain = false; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " beginning Stage3 iteration" << ::std::endl; } @@ -1640,7 +1632,7 @@ void SyncOpt::findBalancedExits_Stage3(b } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " done Stage3a" << ::std::endl; } @@ -1652,7 +1644,7 @@ void SyncOpt::findBalancedExits_Stage3(b Inst *monExit = *monExitIter; SyncClique *clique = monitorCliques[monExit]; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking11 badMonitor "; clique->print(Log::out()); Log::out() << " with bottom ("; @@ -1663,7 +1655,7 @@ void SyncOpt::findBalancedExits_Stage3(b } bottomCliqueRoot = bottomCliqueRoot->find(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " done Stage3b" << ::std::endl; } @@ -1678,7 +1670,7 @@ void SyncOpt::findBalancedExits_Stage3(b if (depMonRoot != bottomCliqueRoot) { foundDependentMonitor = true; // we need to re-iterate - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " linking12 depMonRoot "; depMonRoot->print(Log::out()); Log::out() << " with bottom ("; @@ -1691,7 +1683,7 @@ void SyncOpt::findBalancedExits_Stage3(b } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " done Stage3c" << ::std::endl; } @@ -1704,12 +1696,12 @@ void SyncOpt::findBalancedExits_Stage3(b newBadExitEnd = newBadMonitorExits.end(); for ( ; newBadExitIter != newBadExitEnd; ++newBadExitIter) { Inst *newBadExit = *newBadExitIter; - CFGNode *node = newBadExit->getNode(); + Node *node = newBadExit->getNode(); uint32 nodeId = node->getId(); uint32 nodeDepth = exitSolution[nodeId].getDepth(); - CFGEdge *e = (CFGEdge *)node->getExceptionEdge(); - CFGNode *target = e->getTargetNode(); + Edge *e = (Edge *)node->getExceptionEdge(); + Node *target = e->getTargetNode(); uint32 targetId = target->getId(); uint32 targetDepth = entrySolution[targetId].getDepth(); @@ -1727,7 +1719,7 @@ void SyncOpt::findBalancedExits_Stage3(b } } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Linking13 exception edge from bad monexit at node #" << (int) nodeId << " to dispatch node #" @@ -1740,7 +1732,7 @@ void SyncOpt::findBalancedExits_Stage3(b } } - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " done Stage3d" << ::std::endl; } @@ -1749,7 +1741,7 @@ void SyncOpt::findBalancedExits_Stage3(b needToCheckAgain = differs; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " done Stage3 iteration" << ::std::endl; } } @@ -1761,13 +1753,13 @@ void SyncOpt::findBalancedExits(bool opt OpndManager &opndManager = irManager.getOpndManager(); InstFactory &instFactory = irManager.getInstFactory(); - FlowGraph &fg = irManager.getFlowGraph(); + ControlFlowGraph &fg = irManager.getFlowGraph(); uint32 numNodes = fg.getMaxNodeId(); SyncOptDfValue *entrySolution, *exitSolution; uint32 numCliques = findBalancedExits_Stage1(optimistic, use_IncRecCount, numNodes, entrySolution, exitSolution); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "numNodes is " << (int) numNodes << ::std::endl; Log::out() << "numCliques is " << (int) numCliques << ::std::endl; } @@ -1786,7 +1778,7 @@ void SyncOpt::findBalancedExits(bool opt exitCliques[i] = &cliquesHeap[cliqueHeapIndex]; cliqueHeapIndex += lout; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " node " << (int) i << " has " << (int) lin << " cliques in: [ "; for (uint32 j = 0; j<lin; ++j) { entryCliques[i][j].print(Log::out()); @@ -1805,12 +1797,12 @@ void SyncOpt::findBalancedExits(bool opt } assert(cliqueHeapIndex <= numCliques); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "finished dataflow solution" << ::std::endl; } SyncClique *bottomClique = new (mm) SyncClique(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Bottom clique is "; bottomClique->print(Log::out()); Log::out() << ::std::endl; @@ -1831,7 +1823,7 @@ void SyncOpt::findBalancedExits(bool opt // also, needRecCount[monitorExit]=cliques to be invalidated if monitorExit opnd // doesn't match, or if the monitorExit clique is/was invalidated SyncClique *bottomCliqueRoot = bottomClique->find(); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Bottom clique root is "; bottomCliqueRoot->print(Log::out()); Log::out() << ::std::endl; @@ -1860,7 +1852,7 @@ void SyncOpt::findBalancedExits(bool opt Inst *inst = (*miter).first; SyncClique *clique = (*miter).second; - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Considering balancing instruction: "; inst->print(Log::out()); Log::out() << " with "; @@ -1870,7 +1862,7 @@ void SyncOpt::findBalancedExits(bool opt clique = clique->find(); if ((clique == bottomCliqueRoot)) { - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << " Clique == bottom" << ::std::endl; } continue; @@ -1934,8 +1926,8 @@ void SyncOpt::findBalancedExits(bool opt if (!optimistic) { // remove exception edge - CFGNode *node = inst->getNode(); - CFGEdge* edge = (CFGEdge *)node->getExceptionEdge(); + Node *node = inst->getNode(); + Edge* edge = (Edge *)node->getExceptionEdge(); assert(edge != NULL); fg.removeEdge(edge); } @@ -1943,8 +1935,8 @@ void SyncOpt::findBalancedExits(bool opt inst->unlink(); } break; - default: - break; + default: + break; } } } @@ -1959,7 +1951,7 @@ void SyncOpt::findBalancedExits(bool opt StlVectorSet<SyncClique *> *cliques = (*miter).second; assert(cliques); - if (Log::cat_opt_sync()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Considering increccount for instruction: "; invalidatingInst->print(Log::out()); Log::out() << ::std::endl; @@ -1997,40 +1989,40 @@ void SyncOpt::findBalancedExits(bool opt } void SyncOpt::insertUnwindMonitorExit(Opnd *syncMethodOpnd, - CFGNode *&tmpDispatchNode, CFGNode *&tmpCatchNode, - CFGNode *&tmpRethrowNode) + Node *&tmpDispatchNode, Node *&tmpCatchNode, + Node *&tmpRethrowNode) { assert(flags.optimistic); assert(syncMethodOpnd); InstFactory &instFactory = irManager.getInstFactory(); OpndManager &opndManager = irManager.getOpndManager(); TypeManager &typeManager = irManager.getTypeManager(); - FlowGraph &fg = irManager.getFlowGraph(); - CFGNode *unwind = fg.getUnwind(); + ControlFlowGraph &fg = irManager.getFlowGraph(); + Node *unwind = fg.getUnwindNode(); assert(unwind); // use it if we have an unwind node only - CFGNode *newDispatchNode = fg.createDispatchNode(); + Node *newDispatchNode = fg.createDispatchNode(instFactory.makeLabel()); Opnd* ex = opndManager.createSsaTmpOpnd(typeManager.getSystemObjectType()); - CFGNode *newCatchNode = fg.createCatchNode(0, ex->getType()); - newCatchNode->append(instFactory.makeCatch(ex)); + Node *newCatchNode = fg.createBlockNode(instFactory.makeCatchLabel(0, ex->getType())); + newCatchNode->appendInst(instFactory.makeCatch(ex)); bool insertedMethodExit = false; - CFGNode *rethrowNode = fg.createBlockNode(); - rethrowNode->append(instFactory.makeThrow(Throw_NoModifier, ex)); + Node *rethrowNode = fg.createBlockNode(instFactory.makeLabel()); + rethrowNode->appendInst(instFactory.makeThrow(Throw_NoModifier, ex)); // Redirect exception exits that aren't from a node whose successor's successor // is return, to newDispatchNode - const CFGEdgeDeque& unwindEdges = unwind->getInEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& unwindEdges = unwind->getInEdges(); + Edges::const_iterator eiter; for(eiter = unwindEdges.begin(); eiter != unwindEdges.end(); ) { bool redirectEdge = true; - CFGEdge* edge = *eiter; + Edge* edge = *eiter; ++eiter; - CFGNode *source = edge->getSourceNode(); + Node *source = edge->getSourceNode(); // check whether source is a return-path monitorExit(this) - Inst *sourceLastInst = source->getLastInst(); + Inst *sourceLastInst = (Inst*)source->getLastInst(); if (((sourceLastInst->getOpcode() == Op_TauMonitorExit) || (sourceLastInst->getOpcode() == Op_OptimisticBalancedMonitorExit)) && (sourceLastInst->getSrc(0) == syncMethodOpnd)) { @@ -2041,28 +2033,28 @@ void SyncOpt::insertUnwindMonitorExit(Op if (sourceLastInst->getOpcode() == Op_TauMonitorExit) { Opnd *tauSrcNonNull = sourceLastInst->getSrc(1); assert(tauSrcNonNull->getType()->tag == Type::Tau); - newCatchNode->append(instFactory.makeTauMonitorExit(syncMethodOpnd, tauSrcNonNull)); + newCatchNode->appendInst(instFactory.makeTauMonitorExit(syncMethodOpnd, tauSrcNonNull)); } else { Opnd *lockAddrOpnd = sourceLastInst->getSrc(1); Opnd *oldValueOpnd = sourceLastInst->getSrc(1); - newCatchNode->append(instFactory.makeOptimisticBalancedMonitorExit(syncMethodOpnd, + newCatchNode->appendInst(instFactory.makeOptimisticBalancedMonitorExit(syncMethodOpnd, lockAddrOpnd, oldValueOpnd)); } } // now check whether other successor is a return node - const CFGEdgeDeque& sourceEdges = source->getOutEdges(); - CFGEdgeDeque::const_iterator + const Edges& sourceEdges = source->getOutEdges(); + Edges::const_iterator sourceEdgesIter = sourceEdges.begin(), sourceEdgesEnd = sourceEdges.end(); for(; sourceEdgesIter != sourceEdgesEnd; ++sourceEdgesIter) { - CFGEdge *sourceEdge = *sourceEdgesIter; - CFGNode *target = sourceEdge->getTargetNode(); + Edge *sourceEdge = *sourceEdgesIter; + Node *target = sourceEdge->getTargetNode(); if (target == unwind) continue; // check if it ends in return - Inst *targetLastInst = target->getLastInst(); + Inst *targetLastInst = (Inst*)target->getLastInst(); if (targetLastInst->getOpcode() == Op_Return) { // do not redirect redirectEdge = false; @@ -2090,18 +2082,18 @@ void SyncOpt::insertUnwindMonitorExit(Op } void SyncOpt::removeUnwindMonitorExit(Opnd *syncMethodOpnd, - CFGNode *tmpDispatchNode, CFGNode *tmpCatchNode, - CFGNode *tmpRethrowNode) + Node *tmpDispatchNode, Node *tmpCatchNode, + Node *tmpRethrowNode) { assert(flags.optimistic); assert(syncMethodOpnd); - FlowGraph &fg = irManager.getFlowGraph(); - CFGNode *unwind = fg.getUnwind(); + ControlFlowGraph &fg = irManager.getFlowGraph(); + Node *unwind = fg.getUnwindNode(); - const CFGEdgeDeque& tmpDispatchInEdges = tmpDispatchNode->getInEdges(); - CFGEdgeDeque::const_iterator eiter; + const Edges& tmpDispatchInEdges = tmpDispatchNode->getInEdges(); + Edges::const_iterator eiter; for(eiter = tmpDispatchInEdges.begin(); eiter != tmpDispatchInEdges.end(); ) { - CFGEdge* edge = *eiter; + Edge* edge = *eiter; ++eiter; fg.replaceEdgeTarget(edge, unwind); } diff --git vm/jitrino/src/optimizer/syncopt.h vm/jitrino/src/optimizer/syncopt.h index 9920fbf..98bf406 100644 --- vm/jitrino/src/optimizer/syncopt.h +++ vm/jitrino/src/optimizer/syncopt.h @@ -27,7 +27,6 @@ #include <iostream> #include "open/types.h" #include "optpass.h" #include "Opcode.h" -#include "FlowGraph.h" #include "Stl.h" #include <utility> @@ -39,8 +38,7 @@ class InequalityGraph; class DominatorNode; class Dominator; class DomFrontier; -class JitrinoParameterTable; -class CFGNode; +class Node; class Opnd; class CSEHashTable; class Type; @@ -49,29 +47,26 @@ class SyncClique; class SyncOptDfValue; class BuildSyncCliquesWalker; -DEFINE_OPTPASS(SyncOptPass) +struct SyncOptFlags { + bool debug; + bool verbose; + bool redstore; + bool optimistic; // assume we can balance monitorenter/exit around a call + bool use_IncRecCount; + bool transform; + bool transform2; + bool balance; +}; class SyncOpt { IRManager& irManager; MemoryManager &mm; -public: - struct Flags { - bool debug; - bool verbose; - bool redstore; - bool optimistic; // assume we can balance monitorenter/exit around a call - bool use_IncRecCount; - bool transform; - bool transform2; - bool balance; - }; private: - static Flags *defaultFlags; - Flags flags; + SyncOptFlags flags; public: - static void readDefaultFlagsFromCommandLine(const JitrinoParameterTable *params); - static void showFlagsFromCommandLine(); + static void readFlags(Action* argSource, SyncOptFlags* flags); + static void showFlags(std::ostream& os); SyncOpt(IRManager &irManager0, MemoryManager& memManager); @@ -101,7 +96,7 @@ private: void linkStacks(uint32 depth1, SyncClique *stack1, uint32 depth2, SyncClique *stack2, SyncClique *bottomClique); - void findBalancedExits_Stage2a(CFGNode *node, + void findBalancedExits_Stage2a(Node *node, uint32 depthIn, SyncClique *inStack, uint32 depthOut, @@ -128,11 +123,11 @@ private: SyncClique *cliqueRoot, SyncClique *bottomRoot); void insertUnwindMonitorExit(Opnd *syncMethodOpnd, - CFGNode *&tmpDispatchNode, CFGNode *&tmpCatchNode, - CFGNode *&tmpRethrowNode); + Node *&tmpDispatchNode, Node *&tmpCatchNode, + Node *&tmpRethrowNode); void removeUnwindMonitorExit(Opnd *syncMethodOpnd, - CFGNode *tmpDispatchNode, CFGNode *tmpCatchNode, - CFGNode *tmpRethrowNode); + Node *tmpDispatchNode, Node *tmpCatchNode, + Node *tmpRethrowNode); }; } //namespace Jitrino diff --git vm/jitrino/src/optimizer/tailduplicator.cpp vm/jitrino/src/optimizer/tailduplicator.cpp index bd94f2a..d7ecf3a 100644 --- vm/jitrino/src/optimizer/tailduplicator.cpp +++ vm/jitrino/src/optimizer/tailduplicator.cpp @@ -26,10 +26,11 @@ #include "irmanager.h" #include "Dominator.h" #include "Loop.h" #include "escapeanalyzer.h" +#include "FlowGraph.h" namespace Jitrino { -DEFINE_OPTPASS_IMPL(RedundantBranchMergingPass, taildup, "Redundant Branch Merging/Factoring") +DEFINE_SESSION_ACTION(RedundantBranchMergingPass, taildup, "Redundant Branch Merging/Factoring") void RedundantBranchMergingPass::_run(IRManager& irm) { @@ -40,7 +41,7 @@ RedundantBranchMergingPass::_run(IRManag tm.doTailDuplication(); } -DEFINE_OPTPASS_IMPL(HotPathSplittingPass, hotpath, "Profile Guided Hot Path Splitting") +DEFINE_SESSION_ACTION(HotPathSplittingPass, hotpath, "Profile Guided Hot Path Splitting") void HotPathSplittingPass::_run(IRManager& irm) { @@ -71,32 +72,32 @@ TailDuplicator::process(DefUseBuilder& d process(defUses, child); } - CFGNode* node = dnode->getNode(); - BranchInst* branch = node->getLastInst()->asBranchInst(); + Node* node = dnode->getNode(); + BranchInst* branch = ((Inst*)node->getLastInst())->asBranchInst(); if(branch == NULL) return; // Tail duplicate redundant branches in dominated nodes. for(child = dnode->getChild(); child != NULL; child = child->getSiblings()) { - CFGNode* cnode = child->getNode(); - BranchInst* branch2 = cnode->getLastInst()->asBranchInst(); - if(branch2 != NULL && node->findTarget(cnode) == NULL && isMatchingBranch(branch, branch2)) + Node* cnode = child->getNode(); + BranchInst* branch2 = ((Inst*)cnode->getLastInst())->asBranchInst(); + if(branch2 != NULL && node->findTargetEdge(cnode) == NULL && isMatchingBranch(branch, branch2)) tailDuplicate(defUses, node, cnode); } } void -TailDuplicator::tailDuplicate(DefUseBuilder& defUses, CFGNode* idom, CFGNode* tail) +TailDuplicator::tailDuplicate(DefUseBuilder& defUses, Node* idom, Node* tail) { if(tail->getInDegree() != 2) return; - CFGNode* t1 = (CFGNode*) idom->getTrueEdge()->getTargetNode(); - CFGNode* f1 = (CFGNode*) idom->getFalseEdge()->getTargetNode(); + Node* t1 = idom->getTrueEdge()->getTargetNode(); + Node* f1 = idom->getFalseEdge()->getTargetNode(); - CFGNode* p1 = (CFGNode*) tail->getInEdges().front()->getSourceNode(); - CFGNode* p2 = (CFGNode*) tail->getInEdges().back()->getSourceNode(); + Node* p1 = tail->getInEdges().front()->getSourceNode(); + Node* p2 = tail->getInEdges().back()->getSourceNode(); - CFGNode* t2; + Node* t2; if(_dtree->dominates(t1, p1) && _dtree->dominates(f1, p2)) { t2 = p1; @@ -106,22 +107,22 @@ TailDuplicator::tailDuplicate(DefUseBuil return; } - if(Log::cat_opt_td()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Tail duplicate "; - tail->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), tail); Log::out() << ::std::endl; } - FlowGraph& fg = _irm.getFlowGraph(); - CFGNode* copy = fg.tailDuplicate(t2, tail, defUses); - fg.foldBranch(copy, copy->getLastInst()->asBranchInst(), true); - fg.foldBranch(tail, tail->getLastInst()->asBranchInst(), false); + ControlFlowGraph& fg = _irm.getFlowGraph(); + Node* copy = FlowGraph::tailDuplicate(_irm, t2, tail, defUses); + FlowGraph::foldBranch(fg, copy, ((Inst*)copy->getLastInst())->asBranchInst(), true); + FlowGraph::foldBranch(fg, tail, ((Inst*)tail->getLastInst())->asBranchInst(), false); } void TailDuplicator::doTailDuplication() { MemoryManager mm(0, "TailDuplicator::doTailDuplication.mm"); - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); DefUseBuilder defUses(mm); defUses.initialize(fg); @@ -132,8 +133,8 @@ TailDuplicator::doTailDuplication() { } void -TailDuplicator::profileGuidedTailDuplicate(LoopTree* ltree, DefUseBuilder& defUses, CFGNode* node) { - FlowGraph& fg = _irm.getFlowGraph(); +TailDuplicator::profileGuidedTailDuplicate(LoopTree* ltree, DefUseBuilder& defUses, Node* node) { + ControlFlowGraph& fg = _irm.getFlowGraph(); if(node->getInDegree() < 2) // Nothing to duplicate @@ -141,39 +142,39 @@ TailDuplicator::profileGuidedTailDuplica double heatThreshold = _irm.getHeatThreshold(); - double nodeCount = node->getFreq(); - Log::cat_opt_td()->debug << "Try nodeCount = " << nodeCount << ::std::endl; + double nodeCount = node->getExecCount(); + Log::out() << "Try nodeCount = " << nodeCount << ::std::endl; if(nodeCount < 0.90 * heatThreshold) return; - const CFGEdgeDeque& inEdges = node->getInEdges(); + const Edges& inEdges = node->getInEdges(); - CFGNode* hotPred = NULL; - CFGEdge* hotEdge = NULL; - CFGEdgeDeque::const_iterator j; + Node* hotPred = NULL; + Edge* hotEdge = NULL; + Edges::const_iterator j; for(j = inEdges.begin(); j != inEdges.end(); ++j) { - CFGEdge* edge = *j; - CFGNode* pred = edge->getSourceNode(); - if(!pred->isBasicBlock()) { + Edge* edge = *j; + Node* pred = edge->getSourceNode(); + if(!pred->isBlockNode()) { hotPred = NULL; break; } - if(pred->getFreq() > 0.90 * nodeCount) { + if(pred->getExecCount() > 0.90 * nodeCount) { hotPred = pred; hotEdge = edge; } } if(hotPred != NULL) { - Log::cat_opt_td()->debug << "Duplicate " << ::std::endl; + Log::out() << "Duplicate " << ::std::endl; double hotProb = hotEdge->getEdgeProb(); - double hotFreq = hotPred->getFreq() * hotProb; - if(Log::cat_opt_td()->isDebugEnabled()) { + double hotFreq = hotPred->getExecCount() * hotProb; + if(Log::isEnabled()) { Log::out() << "Hot Pred = "; - hotPred->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), hotPred); Log::out() << ::std::endl; Log::out() << "HotPredProb = " << hotProb << ::std::endl; - Log::out() << "HotPredFreq = " << hotPred->getFreq() << ::std::endl; + Log::out() << "HotPredFreq = " << hotPred->getExecCount() << ::std::endl; Log::out() << "HotFreq = " << hotFreq << ::std::endl; } if(hotFreq > 1.10 * nodeCount) @@ -182,45 +183,45 @@ TailDuplicator::profileGuidedTailDuplica hotFreq = nodeCount; else if(hotFreq < 0.75 * nodeCount) return; - CFGNode* newNode = fg.tailDuplicate(hotPred, node, defUses); - if(Log::cat_opt_td()->isDebugEnabled()) { + Node* newNode = FlowGraph::tailDuplicate(_irm, hotPred, node, defUses); + if(Log::isEnabled()) { Log::out() << "New node = "; - newNode->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), newNode); Log::out() << ::std::endl; } - newNode->setFreq(hotFreq); - CFGEdge* stBlockEdge = (CFGEdge*) newNode->getUnconditionalEdge(); + newNode->setExecCount(hotFreq); + Edge* stBlockEdge = newNode->getUnconditionalEdge(); if(stBlockEdge != NULL) { - CFGNode* stBlock = (CFGNode*) stBlockEdge->getTargetNode(); + Node* stBlock = stBlockEdge->getTargetNode(); if(stBlock->getId() > newNode->getId()) - stBlock->setFreq(newNode->getFreq()); + stBlock->setExecCount(newNode->getExecCount()); } - node->setFreq(nodeCount-hotFreq); - ((CFGEdge*) hotPred->findTarget(newNode))->setEdgeProb(hotProb); + node->setExecCount(nodeCount-hotFreq); + hotPred->findTargetEdge(newNode)->setEdgeProb(hotProb); // Test if node is source of back edge. - CFGNode* loopHeader = NULL; - const CFGEdgeDeque& outEdges = node->getOutEdges(); + Node* loopHeader = NULL; + const Edges& outEdges = node->getOutEdges(); for(j = outEdges.begin(); j != outEdges.end(); ++j) { - CFGEdge* edge = *j; - CFGNode* succ = edge->getTargetNode(); - if(succ->getDfNum() != UINT32_MAX && ltree->isLoopHeader(succ) && succ->getDfNum() < node->getDfNum()) { + Edge* edge = *j; + Node* succ = edge->getTargetNode(); + if(succ->getDfNum() != MAX_UINT32 && ltree->isLoopHeader(succ) && succ->getDfNum() < node->getDfNum()) { loopHeader = succ; } } if(loopHeader != NULL) { // Create new loop header: - CFGNode* newHeader = fg.createBlockNode(); + Node* newHeader = fg.createBlockNode(_irm.getInstFactory().makeLabel()); - const CFGEdgeDeque& loopInEdges = loopHeader->getInEdges(); + const Edges& loopInEdges = loopHeader->getInEdges(); for(j = loopInEdges.begin(); j != loopInEdges.end();) { - CFGEdge* edge = *j; + Edge* edge = *j; ++j; - CFGNode* pred = edge->getSourceNode(); + Node* pred = edge->getSourceNode(); if(pred != newNode) { fg.replaceEdgeTarget(edge, newHeader); - newHeader->setFreq(newHeader->getFreq()+pred->getFreq()*edge->getEdgeProb()); + newHeader->setExecCount(newHeader->getExecCount()+pred->getExecCount()*edge->getEdgeProb()); } } fg.addEdge(newHeader, loopHeader); @@ -231,24 +232,24 @@ TailDuplicator::profileGuidedTailDuplica void TailDuplicator::doProfileGuidedTailDuplication(LoopTree* ltree) { MemoryManager mm(0, "TailDuplicator::doProfileGuidedTailDuplication.mm"); - FlowGraph& fg = _irm.getFlowGraph(); + ControlFlowGraph& fg = _irm.getFlowGraph(); if(!fg.hasEdgeProfile()) return; DefUseBuilder defUses(mm); defUses.initialize(fg); - StlVector<CFGNode*> nodes(mm); + Nodes nodes(mm); fg.getNodesPostOrder(nodes); - StlVector<CFGNode*>::reverse_iterator i; + Nodes::reverse_iterator i; for(i = nodes.rbegin(); i != nodes.rend(); ++i) { - CFGNode* node = *i; - if(Log::cat_opt_td()->isDebugEnabled()) { + Node* node = *i; + if(Log::isEnabled()) { Log::out() << "Consider "; - node->printLabel(Log::out()); + FlowGraph::printLabel(Log::out(), node); Log::out() << ::std::endl; } - if(!node->isBlockNode() || node == fg.getReturn()) + if(!node->isBlockNode() || node == fg.getReturnNode()) continue; if(ltree->isLoopHeader(node)) diff --git vm/jitrino/src/optimizer/tailduplicator.h vm/jitrino/src/optimizer/tailduplicator.h index 6cbb076..fe9c965 100644 --- vm/jitrino/src/optimizer/tailduplicator.h +++ vm/jitrino/src/optimizer/tailduplicator.h @@ -32,12 +32,9 @@ class DominatorTree; class DominatorNode; class LoopTree; class DefUseBuilder; -class CFGNode; +class Node; class BranchInst; -DEFINE_OPTPASS(RedundantBranchMergingPass) - -DEFINE_OPTPASS(HotPathSplittingPass) class TailDuplicator { public: @@ -49,8 +46,8 @@ public: private: bool isMatchingBranch(BranchInst* br1, BranchInst* br2); void process(DefUseBuilder& defUses, DominatorNode* dnode); - void tailDuplicate(DefUseBuilder& defUses, CFGNode* idom, CFGNode* tail); - void profileGuidedTailDuplicate(LoopTree* ltree, DefUseBuilder& defUses, CFGNode* node); + void tailDuplicate(DefUseBuilder& defUses, Node* idom, Node* tail); + void profileGuidedTailDuplicate(LoopTree* ltree, DefUseBuilder& defUses, Node* node); IRManager& _irm; DominatorTree* _dtree; diff --git vm/jitrino/src/optimizer/walkers.cpp vm/jitrino/src/optimizer/walkers.cpp index 69046e1..2cad984 100644 --- vm/jitrino/src/optimizer/walkers.cpp +++ vm/jitrino/src/optimizer/walkers.cpp @@ -20,7 +20,6 @@ */ #include "Log.h" -#include "PropertyTable.h" #include "open/types.h" #include "walkers.h" diff --git vm/jitrino/src/optimizer/walkers.h vm/jitrino/src/optimizer/walkers.h index 8467b85..76761ab 100644 --- vm/jitrino/src/optimizer/walkers.h +++ vm/jitrino/src/optimizer/walkers.h @@ -32,13 +32,12 @@ #include "MemoryManager.h" #include "Inst.h" #include "irmanager.h" -#include "FlowGraph.h" #include "Dominator.h" namespace Jitrino { class DominatorNode; -class CFGNode; +class Node; class DominatorTree; /* example DomWalker @@ -64,7 +63,7 @@ void DomTreeWalk(DominatorTree &dTree, D if (domNode) { walker.enterScope(); - // scope is associated with this node and its children + // scope is associated with this node and its children if (preorder) { walker.applyToDominatorNode(domNode); // process node @@ -76,7 +75,7 @@ void DomTreeWalk(DominatorTree &dTree, D // but first deal with this node's children dom_stack.push_back(domNode); // push parent dom_stack.push_back(domNode->getChild()); - // scope will be exited if no children left + // scope will be exited if no children left } else { dom_stack.pop_back(); // no children left, exit scope if (!dom_stack.empty()) { @@ -100,19 +99,14 @@ private: // walker can modify/insert/unlink anything before i->next() (if forward) // or anything after i->prev() (if !forward) template <bool forward, class InstWalker> -void WalkInstsInBlock(CFGNode *node, InstWalker &walker) +void WalkInstsInBlock(Node *node, InstWalker &walker) { - Inst* headInst = node->getFirstInst(); - Inst* firstInst = forward ? headInst : (headInst->prev()); - Inst* lastInst = forward ? headInst->prev() : headInst; - Inst* inst = firstInst; - Inst *justDid = 0; - do { - Inst *next = forward ? inst->next() : inst->prev(); + Inst* inst = (Inst*)(forward ? node->getFirstInst() : node->getLastInst()); + while(inst!=NULL) { + Inst *next = forward ? inst->getNextInst() : inst->getPrevInst(); walker.applyToInst(inst); - justDid = inst; inst = next; - } while (justDid != lastInst); + } } /* @@ -173,12 +167,12 @@ public: /* example NodeWalker class NodeWalker { - void applyToCFGNode(CFGNode *node); + void applyToCFGNode(Node *node); }; class NodeInstWalker { void applyToInst(Inst *inst); void startNode(CFGNOde *node); - void finishNode(CFGNode *node); + void finishNode(Node *node); }; */ @@ -186,7 +180,7 @@ template <bool forward, class NodeInstWa class NodeInst2NodeWalker { NodeInstWalker &instWalker; public: - void applyToCFGNode(CFGNode *node) { + void applyToCFGNode(Node *node) { instWalker.startNode(node); WalkInstsInBlock<forward, NodeInstWalker>(node, instWalker); instWalker.finishNode(node); @@ -199,7 +193,7 @@ template <bool forward, class InstWalker class Inst2NodeWalker { InstWalker &instWalker; public: - void applyToCFGNode(CFGNode *node) { + void applyToCFGNode(Node *node) { WalkInstsInBlock<forward, InstWalker>(node, instWalker); } Inst2NodeWalker(InstWalker &instWalker0) : @@ -207,9 +201,9 @@ public: }; template <class NodeWalker> -struct NodeWalkDelegate : public ::std::unary_function<CFGNode *, void > { +struct NodeWalkDelegate : public ::std::unary_function<Node *, void > { NodeWalker &realWalker; - void operator()(CFGNode *n) { + void operator()(Node *n) { realWalker.applyToCFGNode(n); }; NodeWalkDelegate(NodeWalker &w) : realWalker(w) {}; @@ -217,19 +211,19 @@ struct NodeWalkDelegate : public ::std:: // walk over flowgraph nodes in any order template <class NodeWalker> -void NodeWalk(FlowGraph &fg, NodeWalker &walker) +void NodeWalk(ControlFlowGraph &fg, NodeWalker &walker) { NodeWalkDelegate<NodeWalker> delegate(walker); - const CFGNodeDeque &nodes = fg.getNodes(); + const Nodes &nodes = fg.getNodes(); ::std::for_each(nodes.begin(), nodes.end(), delegate); } template <class inst_fun_type> -struct Inst2NodeFun : public ::std::unary_function<CFGNode *, void> +struct Inst2NodeFun : public ::std::unary_function<Node *, void> { inst_fun_type underlying_fun; Inst2NodeFun(const inst_fun_type &theFun) : underlying_fun(theFun) {}; - void operator()(CFGNode *theNode) { + void operator()(Node *theNode) { Inst *first = theNode->getFirstInst(); Inst *thisinst = first; assert(thisinst); @@ -241,12 +235,12 @@ struct Inst2NodeFun : public ::std::unar }; template <class node_fun_type> -struct Node2FlowgraphFun : public ::std::unary_function<FlowGraph &, void> +struct Node2FlowgraphFun : public ::std::unary_function<ControlFlowGraph &, void> { node_fun_type underlying_fun; Node2FlowgraphFun(const node_fun_type &theFun) : underlying_fun(theFun) {}; - void operator()(FlowGraph &fg) { - const CFGNodeDeque &nodes = fg.getNodes(); + void operator()(ControlFlowGraph &fg) { + const Nodes &nodes = fg.getNodes(); ::std::for_each(nodes.begin(), nodes.end(), underlying_fun); } }; diff --git vm/jitrino/src/shared/Arena.h vm/jitrino/src/shared/Arena.h index cd64d31..baef906 100644 --- vm/jitrino/src/shared/Arena.h +++ vm/jitrino/src/shared/Arena.h @@ -34,7 +34,7 @@ namespace Jitrino { typedef struct Arena { struct Arena *next_arena; // next arena char *next_byte; // next byte available in arena - char *last_byte; // end of arena space + char *last_byte; // end of arena space char bytes[1]; // start of arena space } Arena; diff --git vm/jitrino/src/shared/BitSet.cpp vm/jitrino/src/shared/BitSet.cpp index 2782bb8..f7e8317 100644 --- vm/jitrino/src/shared/BitSet.cpp +++ vm/jitrino/src/shared/BitSet.cpp @@ -24,7 +24,7 @@ #include "BitSet.h" namespace Jitrino { - + // use 64-bit words if compiled for IPF #define WORD_SHIFT_AMOUNT 5 @@ -35,13 +35,13 @@ #define WORD_MASK (WORD_NBITS-1) //0x000 // returns the word containing bitNumber // static inline uint32 getWordIndex(uint32 bitNumber) { - return (bitNumber >> WORD_SHIFT_AMOUNT); + return (bitNumber >> WORD_SHIFT_AMOUNT); } // // returns a mask for bitNumber masking // static inline uint32 getBitMask(uint32 bitNumber) { - return (0x0001 << (bitNumber & WORD_MASK)); + return (0x0001 << (bitNumber & WORD_MASK)); } static uint32 getNumWords(uint32 setSize) { @@ -61,65 +61,65 @@ static uint32 getNumBytes(uint32 setSize BitSet::BitSet(MemoryManager& memManager, uint32 size) :words(0), setSize(0), wordsCapacity(0), mm(memManager) { - if (size != 0) - { - alloc(size); - clear(); - } + if (size != 0) + { + alloc(size); + clear(); + } } BitSet::BitSet(MemoryManager& memManager, const BitSet& set) :mm(memManager) { - assert(set.words != 0); - alloc(set.setSize); - copy(set.words); + assert(set.words != 0); + alloc(set.setSize); + copy(set.words); } BitSet::BitSet(const BitSet& set) :mm(set.mm) { - assert(set.words != 0); - alloc(set.setSize); - copy(set.words); + assert(set.words != 0); + alloc(set.setSize); + copy(set.words); } BitSet::BitSet(MemoryManager& memManager, const BitSet& set, uint32 size) :mm(memManager) { - alloc(size); + alloc(size); copyFromSmallerSet(set); } BitSet& BitSet::operator = (const BitSet& set) { - if (this != &set) - { - assert(set.words != 0); - if (wordsCapacity < getNumWords(set.setSize)) - alloc(set.setSize); - setSize = set.setSize; - copy(set.words); - } - return *this; + if (this != &set) + { + assert(set.words != 0); + if (wordsCapacity < getNumWords(set.setSize)) + alloc(set.setSize); + setSize = set.setSize; + copy(set.words); + } + return *this; } void BitSet::alloc(uint32 size) { - assert(size != 0); - words = new (mm) uint32[wordsCapacity = getNumWords(setSize = size)]; + assert(size != 0); + words = new (mm) uint32[wordsCapacity = getNumWords(setSize = size)]; } void BitSet::copy(uint32* src) { - for (int i = getNumWords(setSize); --i >= 0;) - words[i] = src[i]; + for (int i = getNumWords(setSize); --i >= 0;) + words[i] = src[i]; clearTrailingBits(); } @@ -137,7 +137,7 @@ void BitSet::resize(uint32 newSetSize) { clearTrailingBits(); setSize = newSetSize; } else if (newSetSize < setSize) { - assert(newSetSize != 0); + assert(newSetSize != 0); setSize = newSetSize; clearTrailingBits(); } @@ -146,90 +146,90 @@ void BitSet::resize(uint32 newSetSize) { void BitSet::clearTrailingBits() { - uint32 mk = getBitMask(setSize) - 1; - for (uint32 i = getWordIndex(setSize); i < wordsCapacity; ++i) { - words[i] &= mk; - mk = 0; - } + uint32 mk = getBitMask(setSize) - 1; + for (uint32 i = getWordIndex(setSize); i < wordsCapacity; ++i) { + words[i] &= mk; + mk = 0; + } } void BitSet::resizeClear(uint32 newSetSize) { - uint32 newWordsCapacity = getNumWords(newSetSize); + uint32 newWordsCapacity = getNumWords(newSetSize); if (newWordsCapacity > wordsCapacity) - words = new (mm) uint32[wordsCapacity = newWordsCapacity]; + words = new (mm) uint32[wordsCapacity = newWordsCapacity]; - for (uint32 i=0; i<wordsCapacity; i++) - words[i] = 0; + for (uint32 i=0; i<wordsCapacity; i++) + words[i] = 0; setSize = newSetSize; } // -// Sets all bits to false +// Sets all bits to false // void BitSet::clear() { - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] = 0; + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] = 0; } // -// Sets all bits to true +// Sets all bits to true // void BitSet::setAll() { - assert(words != 0); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] = ~((uint32)0); - clearTrailingBits(); + assert(words != 0); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] = ~((uint32)0); + clearTrailingBits(); } // -// Checks if set has any bits set to true +// Checks if set has any bits set to true // bool BitSet::isEmpty() const { - assert(words != 0); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) if (words[i] != 0) return false; - return true; + assert(words != 0); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) if (words[i] != 0) return false; + return true; } // -// Sets 32 bits to values indicated by a bit mask and returns old values +// Sets 32 bits to values indicated by a bit mask and returns old values // uint32 BitSet::set32Bits(uint32 firstBitNumber, uint32 value) { - assert(words != 0 && firstBitNumber < setSize || firstBitNumber % 32 == 0); - uint32 wordIndex = getWordIndex(firstBitNumber); - uint32 oldValue = words[wordIndex]; - words[wordIndex] = value; - return oldValue; + assert(words != 0 && firstBitNumber < setSize || firstBitNumber % 32 == 0); + uint32 wordIndex = getWordIndex(firstBitNumber); + uint32 oldValue = words[wordIndex]; + words[wordIndex] = value; + return oldValue; } // -// Returns values of 32 bits encoded as a bit mask +// Returns values of 32 bits encoded as a bit mask // uint32 BitSet::get32Bits(uint32 firstBitNumber) { - assert(words != 0 && firstBitNumber < setSize || firstBitNumber % 32 == 0); - return words[getWordIndex(firstBitNumber)]; + assert(words != 0 && firstBitNumber < setSize || firstBitNumber % 32 == 0); + return words[getWordIndex(firstBitNumber)]; } // -// Copies another set +// Copies another set // void BitSet::copyFrom(const BitSet& set) { - assert(set.words != 0); - if (this != &set) { - if (words == 0) - alloc(set.setSize); - assert(setSize == set.setSize); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] = set.words[i]; - } + assert(set.words != 0); + if (this != &set) { + if (words == 0) + alloc(set.setSize); + assert(setSize == set.setSize); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] = set.words[i]; + } } // -// Copies from a smaller set to another set +// Copies from a smaller set to another set // void BitSet::copyFromSmallerSet(const BitSet& set) { - assert(set.words != 0); - assert(this != &set); - if (words == 0) - alloc(set.setSize); - assert(setSize >= set.setSize); - uint32 numWords1 = getNumWords(setSize); + assert(set.words != 0); + assert(this != &set); + if (words == 0) + alloc(set.setSize); + assert(setSize >= set.setSize); + uint32 numWords1 = getNumWords(setSize); uint32 numWords2 = getNumWords(set.setSize); assert(numWords1 >= numWords2); uint32 i; @@ -237,120 +237,120 @@ void BitSet::copyFromSmallerSet(const Bi for (i=numWords2; i<numWords1; i++) words[i] = 0; } // -// Unions with another set +// Unions with another set // void BitSet::unionWith(const BitSet& set) { - assert(words != 0 && set.words != 0 && setSize == set.setSize); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] |= set.words[i]; + assert(words != 0 && set.words != 0 && setSize == set.setSize); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] |= set.words[i]; } // -// Intersects with another set +// Intersects with another set // void BitSet::intersectWith(const BitSet& set) { - assert(words != 0 && set.words != 0 && setSize == set.setSize); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] &= set.words[i]; + assert(words != 0 && set.words != 0 && setSize == set.setSize); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] &= set.words[i]; } // -// Subtracts another set +// Subtracts another set // void BitSet::subtract(const BitSet& set) { - assert(words != 0 && set.words != 0 && setSize == set.setSize); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) words[i] &= ~(set.words[i]); + assert(words != 0 && set.words != 0 && setSize == set.setSize); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) words[i] &= ~(set.words[i]); } // -// Checks if this set is equal to another one +// Checks if this set is equal to another one // bool BitSet::isEqual(const BitSet& set) { - assert(words != 0 && set.words != 0); - if (setSize != set.setSize) return false; - uint32 numWords = getNumWords(setSize); + assert(words != 0 && set.words != 0); + if (setSize != set.setSize) return false; + uint32 numWords = getNumWords(setSize); for (uint32 i=0; i<numWords; i++) { if (words[i] != set.words[i]) return false; } - return true; + return true; } // -// Checks if set is disjoint from another set +// Checks if set is disjoint from another set // bool BitSet::isDisjoint(const BitSet& set) { - assert(words != 0 && set.words != 0 && setSize == set.setSize); - uint32 numWords = getNumWords(setSize); + assert(words != 0 && set.words != 0 && setSize == set.setSize); + uint32 numWords = getNumWords(setSize); for (uint32 i=0; i<numWords; i++) { - if ((words[i] & set.words[i]) != 0) return false; + if ((words[i] & set.words[i]) != 0) return false; } - return true; + return true; } // -// Checks if every bit in a set is less than or equal to every bit in another set (where false < true). +// Checks if every bit in a set is less than or equal to every bit in another set (where false < true). // bool BitSet::isLessOrEqual(const BitSet& set) { - assert(words != 0 && set.words != 0 && setSize == set.setSize); - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) { - if ((words[i] & (~set.words[i])) != 0) return false; + assert(words != 0 && set.words != 0 && setSize == set.setSize); + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) { + if ((words[i] & (~set.words[i])) != 0) return false; } - return true; + return true; } void BitSet::visitElems(Visitor& visitor) const { - assert(words != 0); - uint32 bitNumber = 0; - uint32 numWords = getNumWords(setSize); - for (uint32 i=0; i<numWords; i++) { - uint32 word = words[i]; - for (uint32 mask = 0x0001; mask != 0; mask = mask << 1) { - if ((word & mask) != 0) - visitor.visit(bitNumber); - bitNumber++; - } - } + assert(words != 0); + uint32 bitNumber = 0; + uint32 numWords = getNumWords(setSize); + for (uint32 i=0; i<numWords; i++) { + uint32 word = words[i]; + for (uint32 mask = 0x0001; mask != 0; mask = mask << 1) { + if ((word & mask) != 0) + visitor.visit(bitNumber); + bitNumber++; + } + } } void BitSet::print(::std::ostream& os) { Printer printer(os); os << " SetElems ["; visitElems(printer); - os << " ] " << ::std::endl; + os << " ] " << ::std::endl; } -BitSet::IterB::IterB (const BitSet& set) +BitSet::IterB::IterB (const BitSet& set) { - init(set); + init(set); } -void BitSet::IterB::init (const BitSet& set) +void BitSet::IterB::init (const BitSet& set) { - ptr = set.words - 1; - end = set.words + getNumWords(set.setSize); - idx = -1; + ptr = set.words - 1; + end = set.words + getNumWords(set.setSize); + idx = -1; } int BitSet::IterB::getNext () { - if ((idx & 31) == 31) - mask = 0; - else - mask >>= 1, ++idx; - - while (mask == 0) - { - if (++ptr == end) - return -1; - - mask = *ptr; - (idx &= ~31) += 32; - } + if ((idx & 31) == 31) + mask = 0; + else + mask >>= 1, ++idx; + + while (mask == 0) + { + if (++ptr == end) + return -1; + + mask = *ptr; + (idx &= ~31) += 32; + } - while ((mask & 1) == 0) - mask >>= 1, ++idx; + while ((mask & 1) == 0) + mask >>= 1, ++idx; - return idx; + return idx; } diff --git vm/jitrino/src/shared/BitSet.h vm/jitrino/src/shared/BitSet.h index 00e1c5d..a9ed7cd 100644 --- vm/jitrino/src/shared/BitSet.h +++ vm/jitrino/src/shared/BitSet.h @@ -31,174 +31,174 @@ #include <iostream> namespace Jitrino { - + class BitSet { public: - // - // Constructors - // - BitSet(MemoryManager&, uint32 size); - // - // copy constructors - // - BitSet(MemoryManager&, const BitSet&); - BitSet(const BitSet&); + // + // Constructors + // + BitSet(MemoryManager&, uint32 size); + // + // copy constructors + // + BitSet(MemoryManager&, const BitSet&); + BitSet(const BitSet&); // // This constructor is useful when a bit set needs to be expanded into a larger one // BitSet(MemoryManager&, const BitSet&, uint32 size); - // - // assignment operator (resizes the set if necessary) - // - BitSet& operator = (const BitSet&); - // + // + // assignment operator (resizes the set if necessary) + // + BitSet& operator = (const BitSet&); + // // resizes BitSet. Sets new bits to FALSE - // + // void resize(uint32 newSetSize); - // + // // resizes BitSet. Sets all bits to FALSE - // + // void resizeClear(uint32 newSetSize); - // - // returns the size of the set - // - uint32 getSetSize() const {return setSize;} - // - // returns the value of the bit - // - bool getBit(uint32 bitNumber) const - { - assert(words != 0 && bitNumber < setSize); - return (reinterpret_cast<char*>(words)[bitNumber >> 3] & (1 << (bitNumber & 7))) != 0; - } - // - // sets a bit to the given value and returns old value of bit - // - bool setBit(uint32 bitNumber, bool value = true) - { - assert(words != 0 && bitNumber < setSize); - char& wd = reinterpret_cast<char*>(words)[bitNumber >> 3]; - char mk = (char)(1 << (bitNumber & 7)); - - bool old = (wd & mk) != 0; - if (value) - wd |= mk; - else - wd &= ~mk; - - return old; - } - // - // Sets all bits to false - // - void clear(); - // - // Sets all bits to true - // - void setAll(); - // - // Checks if set has any bits set to true - // - bool isEmpty() const; - // - // Sets 32 bits to values indicated by a bit mask and returns old values - // - uint32 set32Bits(uint32 firstBitNumber, uint32 value); - // - // Returns values of 32 bits encoded as a bit mask - // - uint32 get32Bits(uint32 firstBitNumber); - // - // Copies another set - // - void copyFrom(const BitSet& set); - // - // Copies from a smaller set to another set - // - void copyFromSmallerSet(const BitSet& set); - // - // Unions with another set - // - void unionWith(const BitSet& set); - // - // Intersects with another set - // - void intersectWith(const BitSet& set); - // - // Subtracts another set - // - void subtract(const BitSet& set); - // - // Checks if set is equal to another set - // - bool isEqual(const BitSet& set); - // - // Checks if set is disjoint from another set - // - bool isDisjoint(const BitSet& set); - // - // Checks if every bit in a set is less than or equal to every bit in another set (where false < true). - // - bool isLessOrEqual(const BitSet& set); - - - class Visitor; - - void visitElems(Visitor& visitor) const; + // + // returns the size of the set + // + uint32 getSetSize() const {return setSize;} + // + // returns the value of the bit + // + bool getBit(uint32 bitNumber) const + { + assert(words != 0 && bitNumber < setSize); + return (reinterpret_cast<char*>(words)[bitNumber >> 3] & (1 << (bitNumber & 7))) != 0; + } + // + // sets a bit to the given value and returns old value of bit + // + bool setBit(uint32 bitNumber, bool value = true) + { + assert(words != 0 && bitNumber < setSize); + char& wd = reinterpret_cast<char*>(words)[bitNumber >> 3]; + char mk = (char)(1 << (bitNumber & 7)); + + bool old = (wd & mk) != 0; + if (value) + wd |= mk; + else + wd &= ~mk; + + return old; + } + // + // Sets all bits to false + // + void clear(); + // + // Sets all bits to true + // + void setAll(); + // + // Checks if set has any bits set to true + // + bool isEmpty() const; + // + // Sets 32 bits to values indicated by a bit mask and returns old values + // + uint32 set32Bits(uint32 firstBitNumber, uint32 value); + // + // Returns values of 32 bits encoded as a bit mask + // + uint32 get32Bits(uint32 firstBitNumber); + // + // Copies another set + // + void copyFrom(const BitSet& set); + // + // Copies from a smaller set to another set + // + void copyFromSmallerSet(const BitSet& set); + // + // Unions with another set + // + void unionWith(const BitSet& set); + // + // Intersects with another set + // + void intersectWith(const BitSet& set); + // + // Subtracts another set + // + void subtract(const BitSet& set); + // + // Checks if set is equal to another set + // + bool isEqual(const BitSet& set); + // + // Checks if set is disjoint from another set + // + bool isDisjoint(const BitSet& set); + // + // Checks if every bit in a set is less than or equal to every bit in another set (where false < true). + // + bool isLessOrEqual(const BitSet& set); + + + class Visitor; + + void visitElems(Visitor& visitor) const; class Printer; - void print(::std::ostream& os); + void print(::std::ostream& os); - class IterB; + class IterB; private: - // - // makes initial allocation - // - void alloc(uint32 size); - void copy (uint32* src); - // + // + // makes initial allocation + // + void alloc(uint32 size); + void copy (uint32* src); + // // zero bits that out of setSize - // + // void clearTrailingBits(); - // - // words containing the set's bits; - // - uint32* words; - // - // size of set (in bits) - // - uint32 setSize; - // + // + // words containing the set's bits; + // + uint32* words; + // + // size of set (in bits) + // + uint32 setSize; + // // number of words reserved - // + // uint32 wordsCapacity; - // - // mem manager used to resize the set - // + // + // mem manager used to resize the set + // MemoryManager& mm; }; class BitSet::Visitor { public: - virtual ~Visitor() {} - virtual void visit(uint32 elem) = 0; + virtual ~Visitor() {} + virtual void visit(uint32 elem) = 0; }; class BitSet::Printer : public BitSet::Visitor { public: - Printer(::std::ostream & _os) : os(_os) {} - virtual ~Printer() {} - void visit(uint32 i) { os << " " << (int) i;} + Printer(::std::ostream & _os) : os(_os) {} + virtual ~Printer() {} + void visit(uint32 i) { os << " " << (int) i;} private: - ::std::ostream & os; + ::std::ostream & os; }; @@ -206,16 +206,16 @@ class BitSet::IterB { public: - IterB (const BitSet& set); + IterB (const BitSet& set); - void init (const BitSet& set); - int getNext (); + void init (const BitSet& set); + int getNext (); protected: - uint32 * ptr, * end; - uint32 mask; - int idx; + uint32 * ptr, * end; + uint32 mask; + int idx; }; diff --git vm/jitrino/src/shared/CGSupport.cpp vm/jitrino/src/shared/CGSupport.cpp index 04eee8a..2838ae5 100644 --- vm/jitrino/src/shared/CGSupport.cpp +++ vm/jitrino/src/shared/CGSupport.cpp @@ -24,7 +24,7 @@ #include "Stl.h" #include <string> #include <functional> #include "Type.h" -#include "Timer.h" +//#include "Timer.h" #define QUAL_NAME_LENGTH 1024 @@ -179,6 +179,26 @@ uint64 getMapHandlerSize(const char* nam return (uint64)mapHandler->size(); } +void incVectorHandlerSize(const char* name, MethodDesc* meth, size_t incSize) { + StlHashMap< POINTER_SIZE_INT, void* >* handleMap; + handleMap = (StlHashMap< POINTER_SIZE_INT, void* >*) meth->getHandleMap(); + POINTER_SIZE_INT keyVal = (POINTER_SIZE_INT) name; + //KeyPair keyVal((POINTER_SIZE_INT)name, (POINTER_SIZE_INT) meth); + + assert(handleMap->find(keyVal) != handleMap->end()); + StlVector<uint64>* vector = (StlVector<uint64>*)handleMap->find(keyVal)->second; + vector->resize(vector->size() + incSize, ILLEGAL_VALUE); +} +uint64 getVectorSize(const char* name, MethodDesc* meth) { + StlHashMap< POINTER_SIZE_INT, void* >* handleMap; + handleMap = (StlHashMap< POINTER_SIZE_INT, void* >*) meth->getHandleMap(); + POINTER_SIZE_INT keyVal = (POINTER_SIZE_INT) name; + //KeyPair keyVal((POINTER_SIZE_INT)name, (POINTER_SIZE_INT) meth); + + assert(handleMap->find(keyVal) != handleMap->end()); + StlVector<uint64>* vector = (StlVector<uint64>*)handleMap->find(keyVal)->second; + return (uint64)vector->size(); +} void enumerateHandlMap(MethodDesc* meth) { StlHashMap< POINTER_SIZE_INT, void* >* handleMap; handleMap = (StlHashMap< POINTER_SIZE_INT, void* >*) meth->getHandleMap(); @@ -239,6 +259,7 @@ void removeVectorEntry(void* vectorHandl StlVector<uint64>* theVector = (StlVector<uint64>*) vectorHandler; (*theVector)[(size_t)key] = (uint64)ILLEGAL_VALUE; } + /************************************************************************/ //void addMapHandler(void* mapHandler, const char* name) { // assert(handlMap->find(name) == handlMap->end()); diff --git vm/jitrino/src/shared/CGSupport.h vm/jitrino/src/shared/CGSupport.h index e1b727d..c6cbf0b 100644 --- vm/jitrino/src/shared/CGSupport.h +++ vm/jitrino/src/shared/CGSupport.h @@ -34,7 +34,7 @@ #else #endif #define ESTIMATED_LIR_SIZE_PER_HIR 0x3 -#define ESTIMATED_HIR_SIZE_PER_BYTECODE 0x6 +#define ESTIMATED_HIR_SIZE_PER_BYTECODE 0x8 namespace Jitrino { @@ -59,6 +59,9 @@ void removeContainerHandler(const char* void* getContainerHandler(const char* name, MethodDesc* meth); bool isContainerHandlerExist(const char* name, MethodDesc* meth); +void incVectorHandlerSize(const char* name, MethodDesc* meth, size_t incSize); +uint64 getVectorSize(const char* name, MethodDesc* meth); + uint64 getMapHandlerSize(const char* name, MethodDesc* meth); uint64 getMapEntry(void* mapHandler, uint64 key); diff --git vm/jitrino/src/shared/Category.cpp vm/jitrino/src/shared/Category.cpp deleted file mode 100644 index 29dd8d7..0000000 --- vm/jitrino/src/shared/Category.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.13.24.4 $ - * - */ - -#include "Category.h" - -namespace Jitrino { - -::std::ostream* Category::_glob_outp = &::std::cout; - -void -Category::initialize() -{ - debug.setCategory(this); - debug2.setCategory(this); - ir.setCategory(this); - ir2.setCategory(this); - info.setCategory(this); - info2.setCategory(this); - info3.setCategory(this); - warn.setCategory(this); - error.setCategory(this); - fail.setCategory(this); -} - -Category::Category(const ::std::string& _name, LogLevel threshold) : - doLogging(true), name(_name), _outp(NULL), - dynamicThreshold(threshold), parent(NULL), parentOverride(true) -{ - initialize(); -} - -Category* -Category::createCategory(const ::std::string& subname, LogLevel threshold) -{ - ::std::string full_subname = subname; - - if(name != "") { - full_subname = name + "." + subname; - } - Category *res = new Category(full_subname, threshold); - res->setParentOverride(true); - res->parent = this; - categoryMap[subname] = res; - return res; -} - -Category::~Category() { - categoryMap.clear(); -} - -// Get a category. -Category* -Category::getCategory(const ::std::string& name) -{ - ::std::string subcat_name = name; - int ind = name.find('.'); - bool dot_found = ind != (int)::std::string::npos; - - if (dot_found) { - assert(ind > 0); - subcat_name = name.substr(0, ind); // not including the '.' - } - Category* subcat = NULL; - CategoryMap::const_iterator i = categoryMap.find(subcat_name); - - if (i != categoryMap.end()) { - subcat = categoryMap[subcat_name]; - } - if (subcat == NULL) { - return NULL; - } - if (dot_found) { - ::std::string tail = name.substr(ind + 1, name.length()-ind-1); - subcat = subcat->getCategory(tail); - } - return subcat; -} - -void Category::removeCategory(Category* child) { - CategoryMap::const_iterator i; - ::std::string name = ""; - - for (i = categoryMap.begin(); i != categoryMap.end(); i++) { - if (i->second == child) { - name = i->first; - break; - } - } - if (name != "") { - categoryMap.erase(name); - } -} - -void Category::reset(bool parentOverrides) { - dynamicThreshold = LogDefaultThreshold; - parentOverride = parentOverrides; -}; - -void Category::setThreshold(LogLevel level, bool check_parent_override) { - dynamicThreshold = level; -} - -// Set minimum logging threshold -void -Category::setThreshold(const ::std::string& str, bool check_parent_override) -{ - LogLevel level = LogNone; - - if(str == "all") - level = LogAll; - else if(str == "debug") - level = LogDebug; - else if(str == "debug2") - level = LogDebug2; - else if(str == "ir") - level = LogIR; - else if(str == "ir2") - level = LogIR2; - else if(str == "info") - level = LogInfo; - else if(str == "info2") - level = LogInfo2; - else if(str == "info3") - level = LogInfo3; - else if(str == "warn") - level = LogWarn; - else if(str == "error") - level = LogError; - else if(str == "fail") - level = LogFail; - else if(str == "none") - level = LogNone; - - setThreshold(level, check_parent_override); -} - -bool Category::doesParentOverride() const { - return parentOverride; -} - -void Category::setParentOverride(bool override) { - parentOverride = override; -} - -::std::ostream& Category::out() { - return _outp == NULL ? global_out() : *_outp; -} - -/** - * Turn on/off logging for this category and recursively for all - * child categories. - */ -void Category::setLogging(bool on, bool check_parent_override) { - if (on == true) { - doLogging = on; - } - for (CategoryMap::iterator i = categoryMap.begin(); i != categoryMap.end(); i++) { - Category *child = (*i).second; - - if (!check_parent_override || child->doesParentOverride()) { - child->setLogging(on, check_parent_override); - } - } - doLogging = on; -} - -/** - * Set new output for this category and recursively for all - * child categories. - */ -void Category::set_out(::std::ostream *new_outp, bool check_parent_override) { - for (CategoryMap::iterator i = categoryMap.begin(); i != categoryMap.end(); i++) { - Category *child = (*i).second; - - if (!check_parent_override || child->doesParentOverride()) { - child->set_out(new_outp); - } - } - _outp = new_outp; -} - -bool Category::is_out_set() { - return _outp != NULL; -} - -::std::ostream& Category::global_out() { - assert(_glob_outp != NULL); - return *_glob_outp; -} - -void Category::set_global_out(::std::ostream *new_outp) { - _glob_outp = new_outp; -} - -void Category::dump() { - ::std::cerr << "Category " << name.c_str() << " : " << (int) dynamicThreshold << ::std::endl; -} - -bool Category::isLogDynamicEnabled(LogLevel level) { - bool level_ok = level >= dynamicThreshold; - bool parent_ok = parent != NULL && parent->isLogDynamicEnabled(level); - - return doLogging && (level_ok || (parentOverride && parent_ok)); -} - -bool Category::isLogEnabled(LogLevel level) { - bool res = (level >= LogStaticThreshold) && isLogDynamicEnabled(level); - return res; -} - -Category* Category::getRoot() { - return (parent == NULL ? this : parent->getRoot()); -} - -void Category::logf(LogLevel level, const char* format, ...) { - if(isLogEnabled(level)) { - va_list va; - va_start(va, format); - outf(format, va); - va_end(va); - } -} - -// Format output C style -void -Category::outf(const char* format, ...) -{ - const int SIZE = 1000; - char buffer[SIZE]; - assert((int)strlen(format) < SIZE); - va_list va; - va_start(va, format); - vsprintf(buffer, format, va); - va_end(va); - out() << buffer; -} - -} //namespace Jitrino diff --git vm/jitrino/src/shared/Category.h vm/jitrino/src/shared/Category.h deleted file mode 100644 index 0a25d34..0000000 --- vm/jitrino/src/shared/Category.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.12.24.4 $ - * - */ - -#ifndef _CATEGORY_H_ -#define _CATEGORY_H_ - -#include <assert.h> -#include <iostream> -#include <stdarg.h> - -//#include "Stl.h" -#include <string> -#include <map> - -namespace Jitrino { - -// Logging levels -enum LogLevel { - LogAll = 0, - LogDebug2 = 5, - LogDebug = 10, - LogIR2 = 12, - LogIR = 15, - LogInfo3 = 17, - LogInfo2 = 18, - LogInfo = 20, - LogWarn = 30, - LogError = 40, - LogFail = 50, - LogNone = 60, -}; - -// Set the static threshold. Any operation below this threshold should be removed. -#ifdef _DEBUG -// Log everything -const LogLevel -LogStaticThreshold = LogAll; -#else -// Log nothing -#ifndef PRUNED_BINARY -const LogLevel -LogStaticThreshold = LogAll; // change back to LogNone for maximal speed -#else -const LogLevel -LogStaticThreshold = LogNone; -#endif -#endif - -const LogLevel -LogDefaultThreshold = LogNone; - -class Category; - -/** - * A stream-like class for logging output. - **/ -template<LogLevel level> -class CategoryStream { - friend class Category; -public: - template <class T> - inline CategoryStream<level>& operator<<(const T& value); - inline CategoryStream& operator << (::std::ostream& (*f)(::std::ostream&)); - -private: - CategoryStream() {} - CategoryStream(const CategoryStream& os); - void operator=(const CategoryStream& os); - - void setCategory(Category* c) { cat = c; } - Category* cat; -}; - -#define DEFINE_LEVEL(level, name) \ - /* Is logging enabled for this level.*/ \ - bool is##name##Enabled() { return isLogEnabled(Log##name); } \ - \ - /* C++ style output guarded by this level.*/ \ - CategoryStream<Log##name> level; - -/** - * A log4j style logging facility. - */ -class Category { -private: - // GCC doesn't understand empty namespace in template - typedef ::std::string StdString; - typedef ::std::map<StdString, Category*> CategoryMap; -public: - Category(const ::std::string& name, LogLevel threshold = LogDefaultThreshold); - Category(Category *parent, const ::std::string& name, LogLevel threshold = LogDefaultThreshold); - ~Category(); - - // Get the root category. - Category* getRoot(); - - // Get a child category with given name. - Category* getCategory(const ::std::string& name); - - // Create a new child category. - Category* createCategory(const ::std::string& name, LogLevel threshold = LogNone); - - // Remove child category - void removeCategory(Category* child); - - // Reset to default values - void reset(bool parentOverrides); - - // Set minimum logging threshold. - void setThreshold(LogLevel level, bool check_parent_override = true); - - void setThreshold(const ::std::string& str, bool check_parent_override = true); - - // Does the parent category's threshold override this category's threshold. - bool doesParentOverride() const; - - void setParentOverride(bool override); - - DEFINE_LEVEL(debug, Debug) - DEFINE_LEVEL(debug2, Debug2) - DEFINE_LEVEL(ir, IR) - DEFINE_LEVEL(ir2, IR2) - DEFINE_LEVEL(info, Info) - DEFINE_LEVEL(info2, Info2) - DEFINE_LEVEL(info3, Info3) - DEFINE_LEVEL(warn, Warn) - DEFINE_LEVEL(error, Error) - DEFINE_LEVEL(fail, Fail) - - ::std::ostream& out(); - - void setLogging(bool on, bool check_parent_override = true); - void set_out(::std::ostream *new_outp, bool check_parent_override = true); - bool is_out_set(); - static ::std::ostream& global_out(); - static void set_global_out(::std::ostream *new_outp); - void dump(); - - bool isLogDynamicEnabled(LogLevel level); - bool isLogEnabled(LogLevel level); - -private: - Category(const Category& cat) { assert(0); } - void operator=(const Category& cat) { assert(0); } - - void initialize(); - - void logf(LogLevel level, const char* format, ...); - - void outf(const char* format, ...); - - static ::std::ostream* _glob_outp; - - // Per instance data - - /** On/off switch */ - bool doLogging; - - /** category name */ - ::std::string name; - - /** category output stream */ - ::std::ostream* _outp; - - /** map of child categories */ - CategoryMap categoryMap; - - /** current logging level for this category */ - LogLevel dynamicThreshold; - - /** parent category */ - Category* parent; - - /** whether parent settings (such as logging level) override this category's ones */ - bool parentOverride; - -}; - - -template <LogLevel level> -template <class T> -CategoryStream<level>& -CategoryStream<level>::operator<<(const T& value) { - // Should be compile-time NOP if first test fails. - if(level >= LogStaticThreshold) { - if(cat->isLogDynamicEnabled(level)) { - cat->out() << value; - } - } - return *this; -} - -template <LogLevel level> -CategoryStream<level>& -CategoryStream<level>::operator << (::std::ostream& (*f)(::std::ostream&)) { - // Should be compile-time NOP if first test fails. - if(level >= LogStaticThreshold) { - if(cat->isLogDynamicEnabled(level)) { - f(cat->out()); - } - } - return *this; -} - -} //namespace Jitrino - -#endif // _CATEGORY_H_ diff --git vm/jitrino/src/shared/ControlFlowGraph.cpp vm/jitrino/src/shared/ControlFlowGraph.cpp index fccf1aa..4f4f0fd 100644 --- vm/jitrino/src/shared/ControlFlowGraph.cpp +++ vm/jitrino/src/shared/ControlFlowGraph.cpp @@ -21,498 +21,972 @@ */ #include "ControlFlowGraph.h" +#include "LoopTree.h" //required for edge profile smoothing #include <algorithm> namespace Jitrino { -void -ControlFlowGraph::addNode(ControlFlowGraph::Node* node) -{ - addNode(_nodes.end(), node); +////////////////////////////////////////////////////////////////////////// +// ControlFlowGraphFactory methods +Node* ControlFlowGraphFactory::createNode(MemoryManager& mm, Node::Kind kind) { + return new (mm) Node(mm, kind); +} + +Edge* ControlFlowGraphFactory::createEdge(MemoryManager& mm, Node::Kind srcKind, Node::Kind dstKind) { + return new (mm) Edge(); } -void -ControlFlowGraph::addNode(ControlFlowGraph::NodeList::iterator pos, ControlFlowGraph::Node* node) + +////////////////////////////////////////////////////////////////////////// +// Edge methods + +Edge::Kind Edge::getKind() const { + Edge::Kind kind = Edge::Kind_Unconditional; + if (source->isBlockNode()) { + if (target->isBlockNode()) { + if (source->getOutDegree() > 1) { + CFGInst* inst = source->getLastInst(); + if (inst!=NULL) { + kind = inst->getEdgeKind(this); + } else { //empty node with dispatch and unconditional edges. B->B edge is unconditional +#ifdef _DEBUG //do some checks + assert(source->getOutDegree() == 2); + const Edges& outEdges = source->getOutEdges(); + Edge* secondEdge = outEdges.front() == this ? outEdges.back() : outEdges.front(); + assert(secondEdge->getTargetNode()->isDispatchNode()); +#endif + //edge kind stays unconditional + } + } + } else if (target->isDispatchNode()) { + kind = Edge::Kind_Dispatch; + } else { + assert(target->isExitNode());//kind is unconditional + } + } else { + assert(source->isDispatchNode()); + if (target->isDispatchNode() || target->isExitNode()) { + kind = Edge::Kind_Dispatch; + } else { + assert(target->isBlockNode()); + kind = Edge::Kind_Catch; + } + } + return kind; +} + +////////////////////////////////////////////////////////////////////////// +// Node methods + +class HeadInst : public CFGInst { +public: + HeadInst(Node* _node) {node = _node;} + // must never be called on head inst + virtual Edge::Kind getEdgeKind(const Edge* edge) const {assert(false); return Edge::Kind_Unconditional;} +}; + +Node::Node(MemoryManager& mm, Kind _kind) +: id(MAX_UINT32), dfNumber(0), preNumber(0), postNumber(0), traversalNumber(0), +kind(_kind), inEdges(mm), outEdges(mm), instsHead(NULL), execCount(0) { - // Set ID - node->setId(_nodeIDGenerator); - _nodeIDGenerator++; + instsHead = new (mm) HeadInst(this); +} - // Add node - _nodes.insert(pos, node); +Edge* Node::getOutEdge(Edge::Kind edgeKind) const { + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (edge->getKind() == edgeKind) { + return edge; + } + } + return NULL; +} - // Reset node traversal number - node->_traversalNumber = 0; - // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; +Edge* Node::findEdge(bool isForward, const Node* node) const { + const Edges& edges = getEdges(isForward); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (edge->getNode(isForward) == node) { + return edge; + } + } + return NULL; } -void -ControlFlowGraph::removeNode(ControlFlowGraph::Node* node) -{ - removeNode(::std::find(_nodes.begin(), _nodes.end(), node)); + +// appends inst to the end of node list. +void Node::appendInst(CFGInst* newInst, CFGInst* instAfter) { + if (instAfter==NULL) { + newInst->insertBefore(instsHead); + } else { + assert(instAfter->getNode() == this); + newInst->insertAfter(instAfter); + } + } -void -ControlFlowGraph::removeNode(ControlFlowGraph::NodeList::iterator pos) +// appends inst to the beginning of node list. Checks "block header critical inst" property +void Node::prependInst(CFGInst* newInst, CFGInst* instBefore) { + if (instBefore==NULL) { + instBefore = instsHead; + for (CFGInst* inst = getFirstInst(); inst!=NULL; inst = inst->next()) { + if (inst->isLabel()) { + continue; + } + if (newInst->isHeaderCriticalInst() || !inst->isHeaderCriticalInst()) { + instBefore = inst; + break; + } + } + } + assert(instBefore->getNode() == this); + newInst->insertBefore(instBefore); +} + +void Node::insertInst(CFGInst* prev, CFGInst* newInst) { +#ifdef _DEBUG + assert(newInst->getNode() == NULL); + if (newInst->isHeaderCriticalInst()) { //check prev inst is also critical + if (prev != instsHead) { //check only if newInst will not be the first + CFGInst* prevInst = (CFGInst*)prev; + assert(prevInst->isHeaderCriticalInst()); + assert(!newInst->isLabel()); //label must be the first + } + } else { //check next inst is not critical + Dlink* nextLink = prev->getNext(); + if (nextLink!=instsHead) {//check only if newInst will not be the last + CFGInst* nextInst = (CFGInst*)nextLink; + assert(!nextInst->isHeaderCriticalInst()); + } + } +#endif + ((Dlink*)newInst)->insertAfter(prev); + newInst->node = this; +} + + +uint32 Node::getInstCount(bool ignoreLabels) const { + uint32 count = 0; + CFGInst* first = getFirstInst(); + while (ignoreLabels && first!=NULL && first->isLabel()) { + first = first->next(); + } + for (CFGInst* inst = first; inst!=NULL; inst = inst->next()) { + count++; + } + return count; +} + +Edge* Node::findEdgeTo(bool isForward, Node* node) const { + const Edges& edges = getEdges(isForward); + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + if (edge->getNode(isForward) == node) { + return edge; + } + } + return NULL; + +} + +////////////////////////////////////////////////////////////////////////// +// CFG methods + +ControlFlowGraph::ControlFlowGraph(MemoryManager& _mm, ControlFlowGraphFactory* _factory) +: mm (_mm), factory(_factory), entryNode (NULL), returnNode(NULL), exitNode(NULL), unwindNode(NULL), +nodes(_mm), postOrderCache(_mm), nodeIDGenerator(0), edgeIDGenerator(0), nodeCount(0), +traversalNumber(0), lastModifiedTraversalNumber(0), lastOrderingTraversalNumber(0), +lastEdgeRemovalTraversalNumber(0), lastProfileUpdateTraversalNumber(0), currentPreNumber(0), currentPostNumber(0), +annotatedWithEdgeProfile(false), domTree(NULL), postDomTree(NULL), loopTree(NULL) { - Node* node = *pos; + if (factory == NULL) { //use default factory + factory = new (mm) ControlFlowGraphFactory(); + } +} - // Remove incident edges - EdgeList::const_iterator eiter; - for(eiter = node->_inEdges.begin(); eiter != node->_inEdges.end();) - removeEdge(*(eiter++)); - for(eiter = node->_outEdges.begin(); eiter != node->_outEdges.end();) - removeEdge(*(eiter++)); +Node* ControlFlowGraph::createNode(Node::Kind kind, CFGInst* inst) { + Node* node = factory->createNode(mm, kind); + addNode(node); + if (inst!=NULL) { + node->appendInst(inst); + } + return node; +} - // Erase the node itself - _nodes.erase(pos); +void ControlFlowGraph::removeNode(Node* node) { + removeNode(std::find(nodes.begin(), nodes.end(), node), true); +} + +void ControlFlowGraph::removeNode(Nodes::iterator pos, bool erase) { + Node* node = *pos; + + assert(node!=entryNode); + if (node == returnNode) { + returnNode = NULL; + } else if(node == unwindNode) { + unwindNode = NULL; + } else if (node == exitNode) { + assert(0); + exitNode = NULL; + } + + // Remove incident edges + while (!node->inEdges.empty()) { + Edge* edge = node->inEdges.front(); + removeEdge(edge); + } + + while (!node->outEdges.empty()) { + Edge* edge = node->outEdges.front(); + removeEdge(edge); + } + // Erase the node itself + if (erase) { + *pos = *nodes.rbegin(); + nodes.pop_back(); + } else { + *pos = NULL; + } // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; + lastModifiedTraversalNumber = traversalNumber; } -void -ControlFlowGraph::addEdge(ControlFlowGraph::Node* source, ControlFlowGraph::Node* target, - ControlFlowGraph::Edge* edge) -{ +Edge* ControlFlowGraph::addEdge(Node* source, Node* target, double edgeProb) { + assert(target!=entryNode); + assert(source!=exitNode); + assert (source->findTargetEdge(target) == NULL); + Edge* edge = factory->createEdge(mm, source->getKind(), target->getKind()); + addEdge(source, target, edge, edgeProb); + return edge; +} + +void ControlFlowGraph::addEdge(Node* source, Node* target, Edge* edge, double edgeProb) { // Set ID - edge->setId(_edgeIDGenerator); - _edgeIDGenerator++; + edge->setId(edgeIDGenerator); + edgeIDGenerator++; // Out edge for source node - edge->_source = source; - source->_outEdges.push_back(edge); - + edge->source = source; + source->outEdges.push_back(edge); + // In edge for target node - edge->_target = target; - target->_inEdges.push_back(edge); + edge->target = target; + target->inEdges.push_back(edge); + + edge->setEdgeProb(edgeProb); // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; + lastModifiedTraversalNumber = traversalNumber; } -void -ControlFlowGraph::removeEdge(ControlFlowGraph::Edge* edge) -{ + +void ControlFlowGraph::removeEdge(Edge* edge) { // Remove out edge from source node Node* source = edge->getSourceNode(); - EdgeList& outEdges = source->_outEdges; - outEdges.remove(edge); + Edges& outEdges = source->outEdges; + outEdges.erase(std::remove(outEdges.begin(), outEdges.end(), edge)); // Remove in edge from target node Node* target = edge->getTargetNode(); - EdgeList& inEdges = target->_inEdges; - inEdges.remove(edge); + Edges& inEdges = target->inEdges; + inEdges.erase(std::remove(inEdges.begin(), inEdges.end(), edge)); // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; - _lastEdgeRemovalTraversalNumber = _traversalNumber; -} - -void -ControlFlowGraph::removeEdge(ControlFlowGraph::Node* source, ControlFlowGraph::Node* target) -{ - const EdgeList& edges = source->getOutEdges(); - EdgeList::const_iterator eiter = edges.begin(); - while(eiter != edges.end()) { - Edge* edge = *eiter; - ++eiter; - if(edge->getTargetNode() == target) - removeEdge(edge); - } + lastModifiedTraversalNumber = traversalNumber; + lastEdgeRemovalTraversalNumber = traversalNumber; } -ControlFlowGraph::Edge* -ControlFlowGraph::replaceEdgeTarget(Edge* edge, ControlFlowGraph::Node* newTarget) -{ +Edge* ControlFlowGraph::replaceEdgeTarget(Edge* edge, Node* newTarget) { Node* source = edge->getSourceNode(); Node* oldTarget = edge->getTargetNode(); - + CFGInst* lastInst = source->getLastInst(); + removeEdge(edge); - Edge* newEdge = createEdge(source, newTarget); - _updateBranchInstruction(source, oldTarget, newTarget); + Edge* newEdge = addEdge(source, newTarget); + if (lastInst!=NULL) { + lastInst->updateControlTransferInst(oldTarget, newTarget); + } return newEdge; } + + +#define PROFILE_ERROR_ALLOWED 0.000000001 +#define ABS(a) (((a) > (0)) ? (a) : -(a)) + + +// Check the profile consistency of the CFG. +// Return true if the profile is consistent. Otherwise, return false. +bool ControlFlowGraph::isEdgeProfileConsistent(bool checkEdgeProbs, bool checkExecCounts, bool doAssertForClient) { + assert(hasEdgeProfile()); + bool profileIsUptodate= lastProfileUpdateTraversalNumber > getModificationTraversalNum(); +#ifndef _DEBUG + if (profileIsUptodate) { + return true; + } +#else + //do self test in debug version + bool doAssert = profileIsUptodate || doAssertForClient; +#endif + + const Nodes& postOrdered = getNodesPostOrder(); + for (Nodes::const_iterator it = postOrdered.begin(), end = postOrdered.end(); it!=end; ++it) { + Node* node = *it; + if (checkEdgeProbs) { + const Edges& outEdges = node->getOutEdges(); + if (!outEdges.empty()) { + double probSum = 0; + for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + double prob = edge->getEdgeProb(); + if (prob <= 0 || prob > 1) { + assert(doAssert?false:true); + return false; + } + probSum+=prob; + } + if (ABS(probSum-1) > PROFILE_ERROR_ALLOWED) { + assert(doAssert?false:true); + return false; + } + } + } + if (checkExecCounts) { + const Edges& inEdges = node->getInEdges(); + bool hasInfiniteLoops = false; + if (!inEdges.empty()) { + double freqSum = 0; + for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node* sourceNode = edge->getSourceNode(); + double freq = edge->getEdgeProb() * sourceNode->getExecCount(); + if (sourceNode->getTraversalNum()!=node->getTraversalNum()) { + freq = 0; + } + if (freq <=0) { + assert(doAssert?false:true); + return false; + } + freqSum+=freq; + } + if (freqSum <=0 ) { + assert(doAssert?false:true); + return false; + } + double nodeFreq = node->getExecCount(); + if (nodeFreq > 1/PROFILE_ERROR_ALLOWED) { + hasInfiniteLoops = true; + } else if (ABS(nodeFreq / freqSum - 1) >= PROFILE_ERROR_ALLOWED) { + assert(doAssert?false:true); + return false; + } + } + if (!hasInfiniteLoops && exitNode!=NULL) { + double exitFreq = exitNode->getExecCount(); + double entryFreq = entryNode->getExecCount(); + bool ok = ABS(exitFreq - entryFreq) < PROFILE_ERROR_ALLOWED * entryFreq; + if (!ok) { + assert(doAssert ? false : true); + return false; + } + } + } + } + if (!profileIsUptodate && checkEdgeProbs && checkExecCounts) { + lastProfileUpdateTraversalNumber = getTraversalNum(); + } + return true; +} + +// this utility splits a node at a particular instruction, leaving the instruction in the +// same node and moving all insts (before inst : splitAfter=false/after inst : splitAfter=true +// to the newly created note +// returns the new node created +Node* ControlFlowGraph::splitNodeAtInstruction(CFGInst *inst, bool splitAfter, bool keepDispatch, CFGInst* labelInst) { + Node *node = inst->getNode(); + Node* dispatchNode = keepDispatch ? node->getExceptionEdgeTarget() : NULL; + Node* nextNode = splitNode(node, splitAfter, labelInst); + if (inst == node->getLastInst()) { + assert(!splitAfter || (node->getOutDegree() == 1 && node->getUnconditionalEdge()!=NULL) + || (node->getOutDegree()==2 && node->getExceptionEdgeTarget()!=NULL)); + } -ControlFlowGraph::Edge* -ControlFlowGraph::Node::findSource(ControlFlowGraph::Node* source) -{ - EdgeList::const_iterator - i = _inEdges.begin(), - iend = _inEdges.end(); - for(; i != iend; ++i) { - if((*i)->getSourceNode() == source) - return *i; + //keeping dispatch node is useful for extended basis blocks + if (keepDispatch && dispatchNode!=NULL) { + assert(node->getExceptionEdgeTarget() == NULL); + addEdge(node, dispatchNode, 0); } - return NULL; + + // now move the instructions + for (CFGInst *ins = splitAfter ? inst->next() : inst; ins != NULL; ) { + CFGInst *nextins = ins->next(); + ins->unlink(); + nextNode->appendInst(ins); + ins = nextins; + } + nextNode->setExecCount(node->getExecCount()); + node->findTargetEdge(nextNode)->setEdgeProb(1.0); + return nextNode; } -ControlFlowGraph::Edge* -ControlFlowGraph::Node::findTarget(ControlFlowGraph::Node* target) -{ - EdgeList::const_iterator - i = _outEdges.begin(), - iend = _outEdges.end(); - for(; i != iend; ++i) { - if((*i)->getTargetNode() == target) - return *i; - } - return NULL; +// Splice a new empty block on the CFG edge. +Node* ControlFlowGraph::spliceBlockOnEdge(Edge* edge, CFGInst* inst) { + Node* source = edge->getSourceNode(); + double edgeProb = edge->getEdgeProb(); + double edgeFreq = source->getExecCount()*edgeProb; + + // Split the edge + Node* split = splitEdge(edge, inst); + split->setExecCount(edgeFreq); + + // Set the incoming edge probability + assert(split->getInDegree() == 1); + split->getInEdges().front()->setEdgeProb(edgeProb); + + // Set the outgoing edge probability + assert(split->getOutDegree() == 1); + split->getOutEdges().front()->setEdgeProb(1.0); + + return split; } -void -ControlFlowGraph::resetInEdges(ControlFlowGraph::Node* node) -{ - EdgeList::iterator - i = node->_inEdges.begin(), - iend = node->_inEdges.end(); - for(; i != iend;) { - Edge* edge = *i; - ++i; - // The old successor; node is the new successor - Node* old = edge->getTargetNode(); - if(old != node) { - Node* pred = edge->getSourceNode(); - // Check if another edge already goes to node. . - bool redundant = (pred->findTarget(node) != NULL); - // Set this edge to point to node. Note, we do this even if the - // edge is to be deleted. removeEdge only works if the edge - // is well-formed. - edge->setTargetNode(node); - // Update branch instruction in source. - if(pred->isBlockNode()) _updateBranchInstruction(pred, old, node); - if(redundant) { - // Edge is redundant - eliminate. - if(pred->getOutDegree() == 2) { - // Pred already has edge to node and succ, and no other successors. - // We can eliminate the branch and the edge to succ. - if(pred->isBlockNode()) _removeBranchInstruction(pred); +void ControlFlowGraph::splitCriticalEdges(bool includeExceptionEdges, Nodes* newNodes) { + // go backwards through collection so appending won't hurt us. + Nodes::reverse_iterator iter = nodes.rbegin(), end = nodes.rend(); + for (int idx = (int)nodes.size(); --idx<=0;) { + Node* target = nodes[idx]; + // exception edges go to a dispatch node. + // only look at nodes with multiple in edges. + if (target->isDispatchNode() || includeExceptionEdges) { +restart: + if (target->getInDegree() > 1) { + Edges& inEdges = target->inEdges; + Edges::iterator iterEdge = inEdges.begin(), endEdge = inEdges.end(); + for (; iterEdge != endEdge; ++iterEdge) { + Edge* thisEdge = *iterEdge; + Node* source = thisEdge->getSourceNode(); + if ((source->getOutDegree() > 1) && (includeExceptionEdges || !source->isDispatchNode())) { + // it's a critical edge, split it + Node* newNode = splitEdge(thisEdge, NULL); + if (newNodes) { + newNodes->push_back(newNode); + } + goto restart; + } } - - removeEdge(edge); } } - } + } } -void -ControlFlowGraph::resetOutEdges(ControlFlowGraph::Node* node) -{ - EdgeList::iterator - i = node->_outEdges.begin(), - iend = node->_outEdges.end(); - for(; i != iend;) { - Edge* edge = *i; - ++i; - // The old predecessor; node is the new predecessor - Node* old = edge->getSourceNode(); - if(old != node) { - Node* succ = edge->getTargetNode(); - // Check if another edge already comes from node. - bool redundant = (succ->findSource(node) != NULL); - // Set this edge to point to node. Note, we do this even if the - // edge is to be deleted. removeEdge only works if the edge - // is well-formed. - edge->setSourceNode(node); - if(redundant) { - // Edge is redundant - eliminate. - removeEdge(edge); - } - } +bool ControlFlowGraph::isBlockMergeAllowed(Node* source, Node* target, bool allowMergeDispatch) const { + assert(source->isBlockNode() && target->isBlockNode()); + if (target == returnNode) { + return false; + } + if (source->getUnconditionalEdgeTarget()!=target) { + return false; + } + if (target->getInDegree()!=1 || source->getOutDegree() > 2) { + return false; } -} -ControlFlowGraph::Edge* -ControlFlowGraph::Node::getOutEdge(ControlFlowGraph::Edge::Kind kind) -{ - EdgeList::const_iterator - i = _outEdges.begin(), - iend = _outEdges.end(); - for(; i != iend; ++i) { - Edge* edge = *i; - if(edge->getKind() == kind) - return edge; + Node* sourceDispatch = source->getExceptionEdgeTarget(); + Node* targetDispatch = target->getExceptionEdgeTarget(); + + if (source->getOutDegree() == 2 && sourceDispatch == 0) { + return false; // 2 uncond edges, e.g. indirect jumps } - return NULL; + + if (!allowMergeDispatch) { + return sourceDispatch==NULL && targetDispatch==NULL; + } + + bool allowMergeByDispatch = sourceDispatch == targetDispatch + || (sourceDispatch == unwindNode && targetDispatch == NULL) + || (sourceDispatch == NULL && targetDispatch == unwindNode); + + return allowMergeByDispatch; } -void -ControlFlowGraph::mergeNodes(Node* source, Node* target, bool keepFirst) -{ - assert(source->isBlockNode() && target->isBlockNode()); - assert(target->getInDegree() == 1); - assert(source->getOutDegree() == 1); - Edge* edge = *(target->_inEdges.begin()); + +void ControlFlowGraph::mergeBlocks(Node* source, Node* target, bool keepFirst) { + assert(isBlockMergeAllowed(source, target, true)); + + Edge* edge = target->inEdges.front(); assert(edge->getSourceNode() == source); removeEdge(edge); if(keepFirst) { // Merge second block into first - _moveInstructions(target, source, false); + moveInstructions(target, source, false); moveOutEdges(target, source); removeNode(target); } else { // Merge first block into second - _moveInstructions(source, target, true); + moveInstructions(source, target, true); moveInEdges(source, target); removeNode(source); } } -ControlFlowGraph::Node* -ControlFlowGraph::splitNode(Node* node, bool newBlockAtEnd) -{ - assert(node->isBlockNode()); - Node* newNode = createBlockNode(); - - if(newBlockAtEnd) { - // move edges - moveOutEdges(node, newNode); - createEdge(node, newNode); - } else { // new block at beginning - // move edges - moveInEdges(node, newNode); - createEdge(newNode, node); - } - return newNode; -} - -// WARNING: depends on the derived class's _createNode() always -// inserting the created nodes at the end of the node list. -// This is the case for FlowGraph currently, but you never know. -void -ControlFlowGraph::splitCriticalEdges(bool includeExceptionEdges) -{ - // go backwards through list so appending won't hurt us. - - NodeList::reverse_iterator - iter = _nodes.rbegin(), - end = _nodes.rend(); - for (; iter != end; ++iter) { - Node* target = *iter; - // exception edges go to a dispatch node. - // only look at nodes with multiple in edges. - if (target->isDispatchNode() ? includeExceptionEdges : true) { - restart: - if (target->getInDegree() > 1) { - EdgeList& inEdges = target->_inEdges; - EdgeList::iterator - iterEdge = inEdges.begin(), - endEdge = inEdges.end(); - for (; iterEdge != endEdge; ++iterEdge) { - Edge* thisEdge = *iterEdge; - Node* source = thisEdge->getSourceNode(); - if ((source->getOutDegree() > 1) && - (includeExceptionEdges || - !source->isDispatchNode())) { - // it's a critical edge, split it - splitEdge(thisEdge); - goto restart; - } +void ControlFlowGraph::mergeAdjacentNodes(bool skipEntry, bool mergeByDispatch) { + for(uint32 idx = 0; idx < nodes.size(); idx++) { + Node* node = nodes[idx]; + if (node->isBlockNode() && (!skipEntry || node!=entryNode)) { + Node* succ = node->getUnconditionalEdgeTarget(); + if (succ!=NULL && succ->getInDegree() == 1 && !succ->isExitNode()) { + if (isBlockMergeAllowed(node, succ, mergeByDispatch)){ + mergeBlocks(node, succ); + idx--; + } + } + } else if (node->isDispatchNode()) { + if (node->getOutDegree() == 1) { + Node* succ = node->getOutEdges().front()->getTargetNode(); + if (succ->isDispatchNode()) { + // This dispatch has no handlers. + // Forward edges to this dispatch node to the successor. + moveInstructions(node, succ, true); + moveInEdges(node, succ); + removeNode(nodes.begin() + idx, true); + idx--; } } } - } + } } -ControlFlowGraph::Node* -ControlFlowGraph::splitEdge(Edge *edge) -{ - Node* source = edge->getSourceNode(); - Node* target = edge->getTargetNode(); - Node* newNode = createBlockNode(); - removeEdge(edge); - addEdge(source, newNode, edge); - _updateBranchInstruction(source, target, newNode); - createEdge(newNode, target); - return newNode; -} - -void -ControlFlowGraph::purgeEmptyNodes(bool preserveCriticalEdges) { - NodeList::iterator - iter = _nodes.begin(), - end = _nodes.end(); - for(; iter != end;) { - NodeList::iterator current = iter; - Node* node = *iter; - ++iter; +void ControlFlowGraph::purgeEmptyNodes(bool preserveCriticalEdges, bool removeEmptyCatchBlocks) { + for(Nodes::iterator it = nodes.begin(),end = nodes.end(); it != end; ++it) { + Node* node = *it; if(node->isBlockNode() && node->isEmpty()) { - // Preserve entry and return nodes - if(node == getEntry() || node == getReturn()) + // Preserve entry node + if(node == getEntryNode() || node == getReturnNode() || (!removeEmptyCatchBlocks && node->isCatchBlock())) { continue; - // Preserve catch nodes. These nodes contain exception type information. - if(/*(node->getInDegree() == 1) &&*/ - (node->getInEdges().front()->getSourceNode()->isDispatchNode())) - continue; + } // Node must have one unconditional successor if it is empty. - assert(node->getOutDegree() == 1); - Node* succ = node->getOutEdges().front()->getTargetNode(); - assert(succ->isBlockNode()); - if(succ == node) + assert(node->getOutDegree() == 1 || (node->getOutDegree()==2 && node->getExceptionEdge()!=NULL)); + Node* succ = node->getUnconditionalEdgeTarget(); + assert(succ->isBlockNode() || (succ->isExitNode() && getReturnNode() == NULL)); //cfg without special support for return node... + if(succ == node) { // This is an empty infinite loop. continue; + } // Preserve this node if it breaks a critical edge if requested. bool preserve = false; if(preserveCriticalEdges && succ->getInDegree() > 1) { // Preserve this block if any predecessors have multiple out edges. - EdgeList::const_iterator eiter; + Edges::const_iterator eiter; for(eiter = node->getInEdges().begin(); !preserve && eiter != node->getInEdges().end(); ++eiter) { if((*eiter)->getSourceNode()->getOutDegree() > 1) // This node breaks a critical edge. preserve = true; } - - if(preserve) { - if(node->getInDegree() == 1) { - Node* pred = node->getInEdges().front()->getSourceNode(); - assert(pred->getOutDegree() > 1); - if(pred->getOutDegree() <= succ->getInDegree()) { - preserve = false; - for(eiter = pred->getOutEdges().begin(); !preserve && eiter != pred->getOutEdges().end(); ++eiter) { - Node* node2 = (*eiter)->getTargetNode(); - if(node2 != succ && (!node2->isEmpty() || node2->getOutEdges().front()->getTargetNode() != succ)) - preserve = true; - } - } - } - } } if(!preserve) { moveInEdges(node, succ); - removeNode(current); + removeNode(it, false); } } } + nodes.erase(std::remove(nodes.begin(), nodes.end(), (Node*)NULL), nodes.end()); } -void -ControlFlowGraph::mergeAdjacentNodes() { - NodeList::iterator - iter = _nodes.begin(), - end = _nodes.end(); - for(; iter != end;) { - NodeList::iterator current = iter; - Node* node = *iter; - ++iter; - if(node->getOutDegree() == 1) { - Node* succ = node->getOutEdges().front()->getTargetNode(); - Node::Kind kind = node->getKind(); - if(kind == succ->getKind()) { - if(kind == Node::Block) { - if(succ != getReturn() && succ->getInDegree() == 1) { - // Merge block nodes. - if(iter != end && *iter == succ) - ++iter; - mergeNodes(node, succ); - } - } else if(kind == Node::Dispatch) { - // This dispatch has no handlers. - // Forward edges to this dispatch node to the successor. - _moveInstructions(node, succ, true); - moveInEdges(node, succ); - removeNode(current); - } +void ControlFlowGraph::addNode(Node* node) { + // Set ID + node->setId(nodeIDGenerator); + nodeIDGenerator++; + + // Add node + nodes.push_back(node); + + // Reset node traversal number + node->traversalNumber = 0; + + // Mark the graph modified. + lastModifiedTraversalNumber = traversalNumber; +} + + +// Splice inlineFG into this CFG. +void ControlFlowGraph::spliceFlowGraphInline(Edge* edge, ControlFlowGraph& inlineFG) { + assert(!edge->isDispatchEdge() && !edge->isCatchEdge()); + + Node* nodeBeforeEntry = edge->getSourceNode(); + Node* nodeAfterReturn = edge->getTargetNode(); + Node* dispatchNode = nodeBeforeEntry->getExceptionEdgeTarget(); + + Node* inlineEntryNode = inlineFG.getEntryNode(); + Node* inlineReturnNode = inlineFG.getReturnNode(); + Node* inlineUnwindNode = inlineFG.getUnwindNode(); + Node* inlineExitNode = inlineFG.getExitNode(); + + bool returnSeen = false; + bool unwindSeen = false; + + + // Add nodes to CFG + assert(&getMemoryManager() == &inlineFG.getMemoryManager()); + const Nodes& inlineNodes = inlineFG.getNodes(); + for(Nodes::const_iterator i = inlineNodes.begin(), end = inlineNodes.end(); i != end; ++i) { + Node* n = *i; + if (n != inlineExitNode) { + addNode(n); + const Edges& oEdges = n->getOutEdges(); + Edges::const_iterator e; + for(e = oEdges.begin(); e != oEdges.end(); ++e) { + setNewEdgeId(*e); + } + if (n == inlineReturnNode) { + returnSeen = true; + } else if (n == inlineUnwindNode) { + unwindSeen = true; } } + + } + + // Connect nodes. + replaceEdgeTarget(edge, inlineEntryNode); + if(returnSeen) { + removeEdge(inlineReturnNode, inlineExitNode); + addEdge(inlineReturnNode, nodeAfterReturn, 1); + } + if(unwindSeen) { + removeEdge(inlineUnwindNode, inlineExitNode); + if (dispatchNode == NULL) { + dispatchNode = getUnwindNode(); + } + if (dispatchNode != NULL) { + addEdge(inlineUnwindNode, dispatchNode, 1); + } else { + setUnwindNode(inlineUnwindNode); + addEdge(inlineUnwindNode, getExitNode()); + } } } -void -ControlFlowGraph::print(::std::ostream& os, ControlFlowGraph::Node::Annotator* annotator) -{ - MemoryManager mm(getMaxNodeId(), "ControlFlowGraph::print.mm"); - StlVector<Node*> nodes(mm); - getNodesPostOrder(nodes); - StlVector<Node*>::reverse_iterator - iter = nodes.rbegin(), - end = nodes.rend(); - for(; iter != end; iter++) { - (*iter)->print(os, annotator); - os << ::std::endl; +void ControlFlowGraph::spliceFlowGraphInline(CFGInst* instAfter, ControlFlowGraph& inlineFG, bool keepDispatch) { + Node* node = instAfter->getNode(); + Edge* edgeToInlined = NULL; + if (node->getLastInst() == instAfter) { + edgeToInlined = node->getUnconditionalEdge(); + } else {//WARN: no label inst created -> possible problems if method is used in HLO + Node* newBlock = splitNodeAtInstruction(instAfter, true, keepDispatch, NULL); + assert(newBlock->getInDegree() == 1); + edgeToInlined = newBlock->getInEdges().front(); } -} + assert(edgeToInlined!=NULL); + spliceFlowGraphInline(edgeToInlined, inlineFG); + } -void -ControlFlowGraph::moveInEdges(ControlFlowGraph::Node* oldNode, ControlFlowGraph::Node* newNode) -{ + +void ControlFlowGraph::moveInEdges(Node* oldNode, Node* newNode) { assert(oldNode != newNode); - assert(oldNode->getKind() == newNode->getKind()); - EdgeList& oldIns = oldNode->_inEdges; - EdgeList& newIns = newNode->_inEdges; - newIns.splice(newIns.begin(), oldIns, oldIns.begin(), oldIns.end()); + assert(oldNode->getKind() == newNode->getKind() || (getReturnNode()==NULL && newNode->isExitNode())); + Edges& oldIns = oldNode->inEdges; + Edges& newIns = newNode->inEdges; + newIns.insert(newIns.begin(), oldIns.begin(), oldIns.end()); + oldIns.clear(); // Reset edge pointers and update branch instructions. resetInEdges(newNode); assert(oldNode->getInDegree() == 0); // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; + lastModifiedTraversalNumber = traversalNumber; } void -ControlFlowGraph::moveOutEdges(ControlFlowGraph::Node* oldNode, ControlFlowGraph::Node* newNode) -{ +ControlFlowGraph::moveOutEdges(Node* oldNode, Node* newNode) { assert(oldNode->getKind() == newNode->getKind()); - EdgeList& oldOuts = oldNode->_outEdges; - EdgeList& newOuts = newNode->_outEdges; - newOuts.splice(newOuts.end(), oldOuts, oldOuts.begin(), oldOuts.end()); + Edges& oldOuts = oldNode->outEdges; + Edges& newOuts = newNode->outEdges; + newOuts.insert(newOuts.end(), oldOuts.begin(), oldOuts.end()); + oldOuts.clear(); resetOutEdges(newNode); assert(oldNode->getOutDegree() == 0); // Mark the graph modified. - _lastModifiedTraversalNumber = _traversalNumber; + lastModifiedTraversalNumber = traversalNumber; } -void -ControlFlowGraph::Node::print(::std::ostream& os, ControlFlowGraph::Node::Annotator* annotator) -{ - os << "Block "; - printLabel(os); - os << ": "; - if(annotator) - annotator->annotateNode(os, this); - os << ::std::endl; - - // Print predecessors - os << " Predecessors:"; - EdgeList::iterator - in = _inEdges.begin(), - inEnd = _inEdges.end(); - for(; in != inEnd; ++in) { - os << " "; - (*in)->getSourceNode()->printLabel(os); - } - os << ::std::endl; - - // Print successors - os << " Successors:"; - EdgeList::iterator - out = _outEdges.begin(), - outEnd = _outEdges.end(); - for(; out != outEnd; ++out) { - os << " "; - (*out)->getTargetNode()->printLabel(os); - } - os << ::std::endl; - - // Print instructions - printInsts(os, 2); + +void ControlFlowGraph::resetInEdges(Node* node) { + Edges& edges = node->inEdges; + for(int i=(int)edges.size(); --i>=0;) { + Edge* edge = edges[i]; + // The old successor; node is the new successor + Node* old = edge->getTargetNode(); + if(old != node) { + Node* pred = edge->getSourceNode(); + // Check if another edge already goes to node. . + bool redundant = (pred->findTargetEdge(node) != NULL); + // Set this edge to point to node. Note, we do this even if the + // edge is to be deleted. removeEdge only works if the edge + // is well-formed. + edge->target = node; + // Update control transfer instruction in source. + CFGInst* lastInst = pred->getLastInst(); + if(pred->isBlockNode() && lastInst!=NULL) { + lastInst->updateControlTransferInst(old, node); + } + if(redundant) { + // Edge is redundant - eliminate. + if(pred->getOutDegree() == 2) { + // Pred already has edge to node and succ, and no other successors. + // We can eliminate the branch and the edge to succ. + if(pred->isBlockNode()) { + lastInst->removeRedundantBranch(); + } + } + removeEdge(edge); + } + } + } } -void -ControlFlowGraph::Node::printLabel(::std::ostream& os) -{ - os << "#" << (int) getId(); +void ControlFlowGraph::resetOutEdges(Node* node) { + Edges& edges = node->outEdges; + for(int i=(int)edges.size(); --i>=0;) { + Edge* edge = edges[i]; + // The old predecessor; node is the new predecessor + Node* old = edge->getSourceNode(); + if(old != node) { + Node* succ = edge->getTargetNode(); + // Check if another edge already comes from node. + bool redundant = (succ->findSourceEdge(node) != NULL); + // Set this edge to point to node. Note, we do this even if the + // edge is to be deleted. removeEdge only works if the edge + // is well-formed. + edge->source = node; + if(redundant) { + // Edge is redundant - eliminate. + removeEdge(edge); + } + } + } +} + +Node* ControlFlowGraph::splitNode(Node* node, bool newBlockAtEnd, CFGInst* inst) { + assert(node->isBlockNode()); + Node* newNode = createBlockNode(inst); + if(newBlockAtEnd) { + // move edges + moveOutEdges(node, newNode); + addEdge(node, newNode); + } else { // new block at beginning + // move edges + moveInEdges(node, newNode); + addEdge(newNode, node); + } + return newNode; +} + +Node* ControlFlowGraph::splitEdge(Edge *edge, CFGInst* inst) { + Node* target = edge->getTargetNode(); + Node* newNode = createBlockNode(inst); + + replaceEdgeTarget(edge, newNode); + addEdge(newNode, target); + + return newNode; +} + +void ControlFlowGraph::moveInstructions(Node* fromNode, Node* toNode, bool prepend) { + CFGInst* to = prepend ? toNode->getFirstInst() : toNode->getLastInst(); + CFGInst *inst = fromNode->getFirstInst(); + if (inst!=NULL && inst->isLabel()) { //skip block label if exists + inst = inst->next(); + } + for (; inst != NULL; ) { + CFGInst *next = inst->next(); + inst->unlink(); + if (to == NULL) { + if (prepend) { + toNode->prependInst(inst); + } else { + toNode->appendInst(inst); + } + } else { + inst->insertAfter(to); + } + to = inst; + assert(prepend || to == toNode->getLastInst()); + inst = next; + } +} + +class CountFreqsAlgorithm { +public: + CountFreqsAlgorithm(MemoryManager& _mm, ControlFlowGraph* _fg) : + mm(_mm), fg(_fg), loopTree(fg->getLoopTree()), + useCyclicFreqs(false), cyclicFreqs(NULL), exitEdges(mm) + { + if (!loopTree->isValid()) { + loopTree->rebuild(false); + } + uint32 nNodes = fg->getNodeCount(); + cyclicFreqs = new (mm) double[nNodes]; + std::fill(cyclicFreqs, cyclicFreqs + nNodes, 1); + } + + void estimate() { + smoothLinearFrequencies(); + LoopNode* topLevelLoops = (LoopNode*)loopTree->getRoot(); + if (topLevelLoops->getChild()!=NULL) { //if there are loops in method + useCyclicFreqs = true; + for (LoopNode* loopHead = topLevelLoops->getChild(); loopHead!=NULL; loopHead = loopHead->getSiblings()) { + estimateCyclicFrequencies(loopHead); + } + smoothLinearFrequencies(); + } + } + + + void smoothLinearFrequencies() { + const Nodes& nodes = fg->getNodesPostOrder(); + for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) { + Node* node = *it; + const Edges& inEdges = node->getInEdges(); + if (inEdges.empty()) { + //node is entry, do nothing + assert (node == fg->getEntryNode()); + continue; + } + double freq = 0.0; + for(Edges::const_iterator it = inEdges.begin(), itEnd = inEdges.end(); it!=itEnd; it++) { + Edge* edge = *it; + if (loopTree->isBackEdge(edge)) { + continue; //only linear freq estimation + } + Node* fromNode = edge->getSourceNode(); + if (fromNode->getTraversalNum()!=node->getTraversalNum()) { + continue;//unreachable source node + } + double fromFreq = fromNode->getExecCount(); + freq += fromFreq * edge->getEdgeProb(); + } + if (useCyclicFreqs && loopTree->isLoopHeader(node)) { + freq *= cyclicFreqs[node->getDfNum()]; + } + node->setExecCount(freq); + } + } + + void estimateCyclicFrequencies(LoopNode* loopHead) { + //process all child loops first + bool hasChildLoop = loopHead->getChild()!=NULL; + if (hasChildLoop) { + for (LoopNode* childHead = loopHead->getChild(); childHead!=NULL; childHead = childHead->getSiblings()) { + estimateCyclicFrequencies(childHead); + } + } + findLoopExits(loopHead); + if (hasChildLoop) { + smoothLinearFrequencies(); + } + Node* cfgLoopHead = loopHead->getHeader(); + double inFlow = cfgLoopHead->getExecCount(); //node has linear freq here + double exitsFlow = 0; + //sum all exits flow + for (Edges::const_iterator it = exitEdges.begin(), end = exitEdges.end(); it!=end; ++it) { + Edge* edge = *it; + Node* fromNode = edge->getSourceNode(); + exitsFlow += edge->getEdgeProb() * fromNode->getExecCount(); + } + // if loop will make multiple iteration exitsFlow becomes equals to inFlow + double loopCycles = inFlow / exitsFlow; + assert(loopCycles > 1); + cyclicFreqs[cfgLoopHead->getDfNum()] = loopCycles; + } + + void findLoopExits(LoopNode* loop) { + exitEdges.clear(); + const Nodes& nodes = loop->getNodesInLoop(); + for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { + Node* node = *it; + const Edges& outEdges = node->getOutEdges(); + for(Edges::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) { + Edge* edge = *eit; + if (loop->isLoopExit(edge)) { + exitEdges.push_back(edge); + } + } + } + } +private: + MemoryManager& mm; + ControlFlowGraph* fg; + LoopTree* loopTree; + bool useCyclicFreqs; + double* cyclicFreqs; + Edges exitEdges; +}; + +//count node exec count from probs +void ControlFlowGraph::smoothEdgeProfile() { + assert(isEdgeProfileConsistent(true, false, true)); + if (isEdgeProfileConsistent(true, true)) { + return; + } + assert(entryNode->getExecCount()!=0); + CountFreqsAlgorithm c(mm, this); + c.estimate(); + lastProfileUpdateTraversalNumber = traversalNumber; + assert(isEdgeProfileConsistent(true, true, true)); +} + +////////////////////////////////////////////////////////////////////////// +/// CFGInst methods + +CFGInst* CFGInst::next() const { + CFGInst* next = (CFGInst*)getNext(); + return (node!=NULL && next == node->instsHead) ? NULL : next; +} + +CFGInst* CFGInst::prev() const { + CFGInst* prev = (CFGInst*)getPrev(); + return (node!=NULL && prev == node->instsHead) ? NULL : prev; +} + +void CFGInst::insertBefore(CFGInst* inst) { + assert(node == NULL); + CFGInst* nextInst = next(); + unlink(); + Node* newNode = inst->getNode(); + if (newNode!= NULL) { + newNode->insertInst((CFGInst*)inst->getPrev(), this); + } else { + ((Dlink*)this)->insertBefore(inst); + } + if (nextInst!=this) { + nextInst->insertBefore(inst); + } +} + +void CFGInst::insertAfter(CFGInst* inst) { + assert(node == NULL); + CFGInst* nextInst = next(); + unlink(); + Node* newNode = inst->getNode(); + if (newNode!=NULL) { + newNode->insertInst(inst, this); + } else { + ((Dlink*)this)->insertAfter(inst); + } + if (nextInst!=this) { + nextInst->insertAfter(this); + } } -} //namespace Jitrino +} //namespace diff --git vm/jitrino/src/shared/ControlFlowGraph.h vm/jitrino/src/shared/ControlFlowGraph.h index 81ed85a..2124cd2 100644 --- vm/jitrino/src/shared/ControlFlowGraph.h +++ vm/jitrino/src/shared/ControlFlowGraph.h @@ -1,24 +1,24 @@ /* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ /** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.14.24.4 $ - * - */ +* @author Intel, Mikhail Y. Fursov +* @version $Revision$ +* +*/ #ifndef _CONTROLFLOWGRAPH_ #define _CONTROLFLOWGRAPH_ @@ -26,426 +26,519 @@ #define _CONTROLFLOWGRAPH_ #include <assert.h> #include <iostream> +#include "Dlink.h" #include "Stl.h" #include "open/types.h" namespace Jitrino { -const uint32 UINT32_MAX = (uint32) -1; +class Edge; +class Node; +class CFGInst; +class ControlFlowGraph; +class Type; +class DominatorTree; +class LoopTree; -class ControlFlowGraph -{ +typedef StlVector<Edge*> Edges; +typedef StlVector<Node*> Nodes; + +class Edge { + friend class ControlFlowGraph; + friend class ControlFlowGraphFactory; public: - ControlFlowGraph(MemoryManager& mm) : _entry(NULL), _exit(NULL), - _return(NULL), _unwind(NULL), - _nodes(mm), _nodeIDGenerator(0), _edgeIDGenerator(0), _nodeCount(0), - _traversalNumber(0), _lastModifiedTraversalNumber(0), - _lastOrderingTraversalNumber(0), - _lastEdgeRemovalTraversalNumber(0) { } + enum Kind { // shortcut: max1: only one edge of this type/node. maxN: multiple edges/node + Kind_Dispatch = 1, // All *->DN edges. + Kind_Unconditional = 2, // Jump or fall-through with no branch BN->BN, *->EXIT (max1) + Kind_False = 4, // Fall-through after not-taken branch BN->BN, default target of switches (max1) + Kind_True = 8, // A taken branch BN->BN, switch edges (except default) (maxN) + Kind_Catch = 16 // All DN->BN edges (maxN) + }; + + virtual ~Edge() {} + + + // Get the unique edge ID. This is unique for all edges in the containing flow graph. + // It is constant for the lifetime of this edge. + uint32 getId() const {return id;} + + virtual Kind getKind() const; + bool isDispatchEdge() const {return getKind() == Edge::Kind_Dispatch;} + bool isUnconditionalEdge() const {return getKind() == Edge::Kind_Unconditional;} + bool isFalseEdge() const {return getKind() == Edge::Kind_False;} + bool isTrueEdge() const {return getKind() == Edge::Kind_True;} + bool isCatchEdge() const {return getKind() == Edge::Kind_Catch;} + + Node* getSourceNode() const {return source;} + Node* getTargetNode() const {return target;} + Node* getNode(bool isForward) const {return isForward ? target : source;} + + + //profile info + double getEdgeProb() const {return prob;} + void setEdgeProb(double val) {prob = val;} + +protected: + Edge() : id (MAX_UINT32), source(NULL), target(NULL), prob(0) {} - class Edge; - /** - * A doubly-linked list of edges. - **/ - typedef StlList<Edge*> EdgeList; - - class Node; - /** - * A doubly-linked list of Nodes. - **/ - typedef StlList<Node*> NodeList; + void setId(uint32 _id) {id = _id;} + + uint32 id; + Node *source; + Node *target; + double prob; +}; + +class CFGInst : protected Dlink { +friend class Node; +friend class Edge; +friend class ControlFlowGraph; +public: + virtual ~CFGInst(){} + + Node* getNode() const {return node;} + CFGInst* next() const; + CFGInst* prev() const; + + // unlinks inst from node + void unlink() {node = NULL; Dlink::unlink();} - /** - * Base class for CFG Edges. An Edge represents control flow between two nodes: both explicit (branches - * and fall-throughs) and implicit (exceptions). A CFG may contain more than one edge between the two given nodes. - **/ - class Edge { - friend class ControlFlowGraph; - friend class Node; - public: - enum Kind { - True, // A taken branch BN->BN - False, // Fall-through after not-taken branch BN->BN - Unconditional, // Jump or fall-through with no branch BN->BN - Exception, // Exception throw (to DispatchNode) *->DN - Catch, // Exception catch (from DispatchNode to handler) DN->BN - Switch, // A taken switch BN->BN - Exit, // Any edge to the exit node. - Unknown - }; - - - - // Get the unique edge ID. This is unique for all edges in the containing flow graph. - // It is constant for the lifetime of this edge. - uint32 getId() const { return _id; } - - virtual Kind getKind() = 0; - - Node* getSourceNode() { return _source; } - Node* getTargetNode() { return _target; } - Node* getNode(bool isForward) { return isForward ? _target : _source; } - - protected: - Edge(Node* source, Node* target) : _id(UINT32_MAX), _source(source), _target(target) {} - Edge() : _id(UINT32_MAX), _source(NULL), _target(NULL) {} - - virtual ~Edge() {} - private: - void setId(uint32 num) { _id = num; } - void setSourceNode(Node* source) { _source=source; } - void setTargetNode(Node* target) { _target=target; } - - uint32 _id; - Node* _source; - Node* _target; - }; + // inserts 'this' before 'inst'. Assign node to 'this' + // if 'this' inst has next inst, it's also inserted + void insertBefore(CFGInst* inst); + + // inserts 'this' after 'inst'. Assign node to 'this' + // if 'this' inst has next inst, it's also inserted + void insertAfter(CFGInst* inst); - /** - * Base class for CFG nodes. A node may be either a block or dispatch - * node. A block node represents a basic block and contains a sequence of - * instructions with a single entry point at the beginning and a single - * exit at the end. A block node is explicit; the JIT - * will eventually generate instructions corresponding to this node. - * A dispatch node is used to model implicit control flow for throwing and catching - * exceptions. A dispatch node is implicit; the JIT does not generate code. - * Instead, the virtual machine performs the actual dispatch operation. - **/ - class Node { - friend class ControlFlowGraph; - public: - enum Kind { - Block, // Basic block - Dispatch, // Exception Dispatch - Exit // Exit - }; - - // Get the unique node ID. This is unique for all nodes in the containing flow graph. - // It is constant for the lifetime of this node. This provides a sparse id between 0 - // and the graph's getMaxNodeId(). - uint32 getId() const { return _id; } - - // Get the depth first numbering of this node computed during the last pass. - // Use this number as a dense id during a short phase. - uint32 getDfNum() const { return _dfNumber; } - uint32 getPreNum() const { return _preNumber; } - uint32 getPostNum() const { return _postNumber; } - - // Get the traversal number of this node. This is a monotonically increasing value, - // and always less than or equal to the traversal number of the graph itself. - // The traversal number is used mark a node visited during a particular traversal. - uint32 getTraversalNum() const { return _traversalNumber; } - void setTraversalNum(uint32 num) { _traversalNumber = num; } - - bool isBlockNode() const { return _kind==Block; } - bool isDispatchNode() const { return _kind==Dispatch; } - bool isExitNode() const { return _kind==Exit; } - Kind getKind() const { return _kind; } - - const EdgeList& getInEdges() const { return _inEdges; } - uint32 getInDegree() const { return (uint32) _inEdges.size(); } - // For dispatch nodes, edges will be in control flow order (e.g., first handler to match, second, etc.). - const EdgeList& getOutEdges() const { return _outEdges; } - uint32 getOutDegree() const { return (uint32) _outEdges.size(); } - const EdgeList& getEdges(bool isForward) const { return isForward ? _outEdges : _inEdges; } - - // Find the edge corresponding to a particular source or target. Return NULL if - // no such edge is found. - Edge* findSource(Node* source); - Edge* findTarget(Node* target); - - // Return true if this node contains no instructions - virtual bool isEmpty() const = 0; - - // Get unique edge that matches this kind. Return NULL if no such edge exists. - Edge* getTrueEdge() { return getOutEdge(Edge::True); } - Edge* getFalseEdge() { return getOutEdge(Edge::False); } - Edge* getUnconditionalEdge() { return getOutEdge(Edge::Unconditional); } - Edge* getExceptionEdge() { return getOutEdge(Edge::Exception); } - - class Annotator { - public: - virtual ~Annotator() {} - virtual void annotateNode(::std::ostream& os, Node* node) = 0; - }; - - virtual void print(::std::ostream& os, Annotator* annotator=NULL); - virtual void printLabel(::std::ostream& os); - virtual void printInsts(::std::ostream& os, uint32 indent=0) = 0; - - class ChainedAnnotator : public Annotator { - public: - ChainedAnnotator(Annotator* a1=NULL, Annotator* a2=NULL, Annotator* a3=NULL) { - add(a1); - add(a2); - add(a3); - } - virtual ~ChainedAnnotator() {}; - virtual void annotateNode(::std::ostream& os, Node* node) { - ::std::list<Annotator*>::iterator i; - for(i = _annotators.begin(); i != _annotators.end(); ++i) { - (*i)->annotateNode(os, node); - os << " "; - } - } + virtual bool isHeaderCriticalInst() const {return isLabel();} + virtual bool isLabel() const {return false;} - void add(Annotator* annotator) { - if(annotator != NULL) - _annotators.push_back(annotator); - } +protected: + // called from CFG to detect BB->BB block edges + virtual Edge::Kind getEdgeKind(const Edge* edge) const = 0; + // called from CFG when edge target is replaced + virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget) {} + // called from CFG when 2 blocks are merging and one of the branches is redundant. + virtual void removeRedundantBranch(){}; - void clear() { - _annotators.clear(); - } - private: - ::std::list<Annotator*> _annotators; - }; - - protected: - // Constructs a new node. If isBlock, the new node is a BlockNode, otherwise - // it is a dispatch node. - Node(MemoryManager& mm, Kind kind=Block) : - _id(UINT32_MAX), _dfNumber(UINT32_MAX), _preNumber(UINT32_MAX), _postNumber(UINT32_MAX), _traversalNumber(0), _kind(kind), - _inEdges(mm), _outEdges(mm) {} - - virtual ~Node() {} - private: - void setId(uint32 num) { _id = num; } - void setDFNum(uint32 num) { _dfNumber = num; } - void setPreNum(uint32 num) { _preNumber = num; } - void setPostNum(uint32 num) { _postNumber = num; } - - Edge* getOutEdge(Edge::Kind kind); - - uint32 _id; - uint32 _dfNumber; - uint32 _preNumber; - uint32 _postNumber; - uint32 _traversalNumber; - Kind _kind; - - // Only blocks ending in switch statements have > 2 out edges. - // Using a doubly linked list is pretty heavy weight for this. - EdgeList _inEdges; - EdgeList _outEdges; +protected: + CFGInst() : node(NULL) {} + Node* node; +}; + +class Node { + friend class ControlFlowGraph; + friend class ControlFlowGraphFactory; + friend class CFGInst; +public: + enum Kind { + Kind_Block, // Basic block + Kind_Dispatch, // Exception Dispatch + Kind_Exit // Exit }; - // Get unique entry node. This node dominates every other node in the graph. - Node* getEntry() { return _entry; } - void setEntry(Node* node) { _entry = node; } + virtual ~Node() {} + + Kind getKind() const {return kind;} + + // Get the unique node ID. This is unique for all nodes in the containing flow graph. + // It is constant for the lifetime of this node. This provides a sparse id between 0 + // and the graph's getMaxNodeId(). + uint32 getId() const {return id;} + + // Get the depth first numbering of this node computed during the last pass. + // Use this number as a dense id during a short phase. + uint32 getDfNum() const {return dfNumber;} + uint32 getPreNum() const {return preNumber;} + uint32 getPostNum() const {return postNumber;} + - // Get unique exit node. This node post-dominates every other node in the graph. - Node* getReturn() { return _return; } - void setReturn(Node* node) { _return = node; } + bool isBlockNode() const {return getKind() == Node::Kind_Block;} + bool isDispatchNode() const {return getKind() == Node::Kind_Dispatch;} + bool isExitNode() const {return getKind() == Node::Kind_Exit;} + bool isCatchBlock() const {return getInDegree() >=1 && getInEdges().front()->isCatchEdge();} + + //edges + const Edges& getInEdges() const {return inEdges;} + const Edges& getOutEdges() const {return outEdges;} + const Edges& getEdges(bool isForward) const {return isForward ? outEdges : inEdges;} + + // Get the first edge that matches this kind. + // Return NULL if no such edge exists, + Edge* getOutEdge(Edge::Kind edgeKind) const; + Edge* getUnconditionalEdge() const {return getOutEdge(Edge::Kind_Unconditional);} + Edge* getFalseEdge() const {return getOutEdge(Edge::Kind_False);} + Edge* getTrueEdge() const {return getOutEdge(Edge::Kind_True);} + Edge* getExceptionEdge() const {return getOutEdge(Edge::Kind_Dispatch);} + bool isConnectedTo(bool isForward, Node* node) const {return findEdgeTo(isForward, node)!=NULL;} + Edge* findEdgeTo(bool isForward, Node* node) const; + + // return target of the first edge with specified kind found. + // return NULL if no edge found with specified kind + Node* getEdgeTarget(Edge::Kind edgeKind) const {Edge* edge = getOutEdge(edgeKind); return edge == NULL ? NULL : edge->getTargetNode();} + Node* getUnconditionalEdgeTarget() const {return getEdgeTarget(Edge::Kind_Unconditional);} + Node* getFalseEdgeTarget() const {return getEdgeTarget(Edge::Kind_False);} + Node* getTrueEdgeTarget() const {return getEdgeTarget(Edge::Kind_True);} + Node* getExceptionEdgeTarget() const {return getEdgeTarget(Edge::Kind_Dispatch);} + + // Find the edge corresponding to a particular source or target. Return NULL if + // no such edge is found. + Edge* findEdge(bool isForward, const Node* node) const; + Edge* findSourceEdge(const Node* source) const {return findEdge(false, source);} + Edge* findTargetEdge(const Node* target) const {return findEdge(true, target);} + + uint32 getOutDegree() const {return getOutEdges().size();} + uint32 getInDegree() const {return getInEdges().size();} - // Get unique exit node. This node post-dominates every other node in the graph. - Node* getUnwind() { return _unwind; } - void setUnwind(Node* node) { _unwind = node; } + bool hasOnlyOneSuccEdge() const {return getOutDegree() == 1;} + bool hasOnlyOnePredEdge() const {return getInDegree() == 1;} + bool hasTwoOrMoreSuccEdges() const {return getOutDegree() >= 2;} + bool hasTwoOrMorePredEdges() const {return getInDegree() >= 2;} - // Get unique exit node. This node post-dominates every other node in the graph. - Node* getExit() { return _exit; } - void setExit(Node* node) { _exit = node; } - // Return a list of all nodes in the graph. The order in the list has no semantic + + // insts + + // appends inst to the end of node list. + // if inst is a list of insts (has next insts) -> the whole list is appended + void appendInst(CFGInst* newInst, CFGInst* instBefore = NULL); + + // appends inst to the beginning of node list. Checks "block header critical inst" property + // if inst is a list of insts (has next insts) -> the whole list is prepended + void prependInst(CFGInst* newInst, CFGInst* instAfter = NULL); + + // counts number of inst in node. Complexity ~ num of insts + uint32 getInstCount(bool ignoreLabels = true) const; + bool isEmpty(bool ignoreLabels = true) const {CFGInst* inst = getFirstInst(); return inst == NULL || (ignoreLabels && inst->isLabel() && inst->next() == NULL);} + CFGInst* getFirstInst() const {return instsHead->getNext() != instsHead ? (CFGInst*)instsHead->getNext() : NULL;} + CFGInst* getLastInst() const {return instsHead->getPrev() != instsHead ? (CFGInst*)instsHead->getPrev() : NULL;} + + //profile info + double getExecCount() const {return execCount;} + void setExecCount(double val) {execCount = val;} + + //mod count + uint32 getTraversalNum() const {return traversalNumber;} + void setTraversalNum(uint32 num) {traversalNumber = num;} + + CFGInst* getSecondInst() const {return isEmpty() ? NULL : getFirstInst()->next();} + CFGInst* getLabelInst() const {CFGInst* first = getFirstInst(); assert(first==NULL || first->isLabel()); return first;} + +protected: + + Node(MemoryManager& mm, Kind _kind); + + void setId(uint32 _id) {id = _id;} + void insertInst(CFGInst* prev, CFGInst* newInst); + + uint32 id; + uint32 dfNumber; + uint32 preNumber; + uint32 postNumber; + uint32 traversalNumber; + Kind kind; + + Edges inEdges; + Edges outEdges; + + CFGInst* instsHead; + double execCount; +}; + +class ControlFlowGraphFactory { +public: + ControlFlowGraphFactory(){} + virtual ~ControlFlowGraphFactory(){} + virtual Node* createNode(MemoryManager& mm, Node::Kind kind); + virtual Edge* createEdge(MemoryManager& mm, Node::Kind srcKind, Node::Kind dstKind); +}; + + +class ControlFlowGraph { +public: + + ControlFlowGraph(MemoryManager& mm, ControlFlowGraphFactory* factory = NULL); + virtual ~ControlFlowGraph(){}; + + // Return a collection of all nodes in the graph. The order in the list has no semantic // value. Note this also returns unreachable nodes. - const NodeList& getNodes() const { return _nodes; } + const Nodes& getNodes() const {return nodes;} + + // Get unique entry node. This node dominates every other node in the graph. + Node* getEntryNode() const {return entryNode;} + void setEntryNode(Node* e) {assert(e!=NULL); entryNode = e; lastModifiedTraversalNumber = traversalNumber;} + + // Get unique exit node. This node post-dominates every other node in the graph. + Node* getExitNode() const {return exitNode;} + void setExitNode(Node* e) {assert(e!=NULL); exitNode = e; lastModifiedTraversalNumber = traversalNumber;} - Node* createBlockNode() { return _createNode(Node::Block); } - Node* createDispatchNode() { return _createNode(Node::Dispatch); } - Node* createExitNode() { return _createNode(Node::Exit); } - Edge* createEdge(Node* source, Node* target) { return _createEdge(source, target); } + // Get unique exit block node. + // This node post-dominates every other block node in the graph. + Node* getReturnNode() const {return returnNode; } + void setReturnNode(Node* node) {assert(returnNode==NULL); assert(node->isBlockNode()); returnNode = node;} + + // Get unique unwind node. This node post-dominates every other dispatch node in the graph. + Node* getUnwindNode() const {return unwindNode;} + void setUnwindNode(Node* node) {assert(unwindNode==NULL); assert(node->isDispatchNode()); unwindNode = node;} + + uint32 getMaxNodeId() const {return nodeIDGenerator;} + + Node* createNode(Node::Kind kind, CFGInst* inst = NULL); + + Node* createBlockNode(CFGInst* inst = NULL) {return createNode(Node::Kind_Block, inst);} + Node* createDispatchNode(CFGInst* inst = NULL) {return createNode(Node::Kind_Dispatch, inst);} + + Node* createExitNode(CFGInst* inst = NULL) {return createNode(Node::Kind_Exit, inst);} + + //removes node and all it's in/out edges void removeNode(Node* node); - void removeNode(NodeList::iterator i); - void removeEdge(Edge* edge); - void removeEdge(Node* source, Node* target); - // Replace old edge target with new edge target and update the source branch - // instruction if necessary. - Edge* replaceEdgeTarget(Edge* edge, Node* newTarget); + // Return the number of nodes in the graph that are reachable. Recompute if the graph was modified. + uint32 getNodeCount() { if(!hasValidOrdering()) orderNodes(); return nodeCount; } + + // return cached postorder collection + const Nodes& getNodesPostOrder() {if (!hasValidOrdering()) orderNodes(); return postOrderCache;} + + template <class Container> + void getNodes(Container& container) { + container.insert(container.begin(), nodes.begin(), nodes.end()); + } - // Given an STL container (e.g., vector, List, list), append the nodes of this CFG - // in Postorder. Excluding loop back edges, this will be a reverse topological ordering - // of the nodes. To get Reverse Postorder (topological ordering), use a reverse_iterator. template <class Container> void getNodesPostOrder(Container& container, bool isForward=true) { - _lastOrderingTraversalNumber = ++_traversalNumber; - _currentPreNumber = _currentPostNumber = 0; - getNodesDFS((Container*) NULL, &container, isForward ? _entry : _exit, isForward); - assert(_currentPreNumber == _currentPostNumber); - _nodeCount = _currentPreNumber; + runDFS((Container*) NULL, &container, isForward); } - // Given an STL container (e.g., vector, List, list), append the nodes of this CFG - // in Preorder. Note this is sometimes called DepthFirst order. + template <class Container> void getNodesPreOrder(Container& container, bool isForward=true) { - _lastOrderingTraversalNumber = ++_traversalNumber; - _currentPreNumber = _currentPostNumber = 0; - getNodesDFS(&container, (Container*) NULL, isForward ? _entry : _exit, isForward); - assert(_currentPreNumber == _currentPostNumber); - _nodeCount = _currentPreNumber; - } - - void orderNodes(bool isForward=true) { - _lastOrderingTraversalNumber = ++_traversalNumber; - _currentPreNumber = _currentPostNumber = 0; - getNodesDFS((NodeList*) NULL, (NodeList*) NULL, _entry, isForward); - assert(_currentPreNumber == _currentPostNumber); - _nodeCount = _currentPreNumber; + runDFS(&container, (Container*) NULL, isForward); } - // Remove all unreachable nodes from CFG, - void purgeUnreachableNodes() { - purgeUnreachableNodes((NodeList*) NULL); + void orderNodes(bool isForward=true) { + runDFS((Nodes*) NULL, (Nodes*) NULL, isForward); } - // Remove all unreachable nodes from CFG. Add removed nodes to container. - template <class Container> - void purgeUnreachableNodes(Container& container) { - purgeUnreachableNodes(&container); - } + //edges: + //creates new edge from source to target + Edge* addEdge(Node* source, Node* target, double edgeProb = 1.0); + uint32 getMaxEdgeId() const {return edgeIDGenerator;} + void removeEdge(Edge* edge); + void removeEdge(Node* source, Node* target) {removeEdge(source->findTargetEdge(target));} + + Edge* replaceEdgeTarget(Edge* edge, Node *newTarget); - // Remove all critical edges from Graph - // Does not split exception edges (edges to Dispatch nodes) - // unless parameter is true. - void splitCriticalEdges(bool includeExceptionEdges); + // adds unconditional edge for BB->BB,BB->E or dispatch edge for *->DN nodes + + //profile info + bool hasEdgeProfile() const {return annotatedWithEdgeProfile;} + void setEdgeProfile(bool val) {annotatedWithEdgeProfile = val;} + //check if edge profile is consistent. + //Checks only reachable nodes. Recalculates postorder cache if needed. + bool isEdgeProfileConsistent(bool checkEdgeProbs = true, bool checkExecCounts = true, bool doAssert=false); + //count node exec count from probs + void smoothEdgeProfile(); - // Remove all empty nodes from CFG. - void purgeEmptyNodes(bool preserveCriticalEdges=true); - // Combine nodes from CFG that can be folded together. - void mergeAdjacentNodes(); - // The traversal number is analogous to a monotonically increasing timestamp. // It is updated anytime an ordering traversal is performed on the CFG. // If a modification was performed after an ordering, the ordering is invalid. - uint32 getTraversalNum() const { return _traversalNumber; } + uint32 getTraversalNum() const {return traversalNumber;} + void setTraversalNum(uint32 newTraversalNum) {traversalNumber = newTraversalNum;} // The modification traversal number is the traversal number of the // last add/remove of a node/edge in the graph. - uint32 getModificationTraversalNum() const { return _lastModifiedTraversalNumber; } + uint32 getModificationTraversalNum() const { return lastModifiedTraversalNumber; } // The modification traversal number is the traversal number of the // last remove of an edge in the graph. - uint32 getEdgeRemovalTraversalNum() const { return _lastEdgeRemovalTraversalNumber; } + uint32 getEdgeRemovalTraversalNum() const { return lastEdgeRemovalTraversalNumber; } // The ordering traversal number is the traversal number after the last depth // first ordering. Node pre/postnumbers are valid if // getOrderingTraversalNum() > getModificationTraversalNum(). - uint32 getOrderingTraversalNum() const { return _lastOrderingTraversalNumber; } - + uint32 getOrderingTraversalNum() const { return lastOrderingTraversalNumber; } + // Return true if the current ordering is still valid. bool hasValidOrdering() const { return getOrderingTraversalNum() > getModificationTraversalNum(); } - // Return the number of nodes in the graph. Recompute if the graph was modified. - uint32 getNodeCount() { if(!hasValidOrdering()) orderNodes(); return _nodeCount; } + //Memory manager used by graph + MemoryManager& getMemoryManager() const {return mm;} + + Node* splitReturnNode(CFGInst* headerInst=NULL) {return splitNode(getReturnNode(), false, headerInst);} + + // this utility splits a node at a particular instruction, leaving the instruction in the + // same node and moving all insts (before inst : splitAfter=false/after inst : splitAfter=true + // to the newly created note + // returns the new node created + Node* splitNodeAtInstruction(CFGInst *inst, bool splitAfter, bool keepDispatch, CFGInst* headerInst); + + Node* spliceBlockOnEdge(Edge* edge, CFGInst* inst = NULL); + + // Inline inlineFG info this CFG after 'instAfter' (splits inst's node if needed) + // move all nodes from inlinedFG except exit node to 'this' FG + // relies on valid 'return' and 'unwind' nodes on inlinedFG + void spliceFlowGraphInline(CFGInst* instAfter, ControlFlowGraph& inlineFG, bool keepDispatch=true); + + // Inline inlineFG info this CFG moving egde head to inlinedFG prolog + // move all nodes from inlinedFG except exit node to 'this' FG + // relies on valid 'return' and 'unwind' nodes on inlinedFG + void spliceFlowGraphInline(Edge* edge, ControlFlowGraph& inlineFG); + + // Remove all critical edges from Graph + // Does not split exception edges (edges to Dispatch nodes) + // unless parameter is true. + void splitCriticalEdges(bool includeExceptionEdges, Nodes* newNodes = NULL); + + + void moveInstructions(Node* fromNode, Node* toNode, bool prepend); + + + // Combine nodes from CFG that can be folded together. + void mergeAdjacentNodes(bool skipEntry = false, bool mergeByDispatch= false); + + void mergeBlocks(Node* source, Node* target, bool keepFirst=true); - void setTraversalNum(uint32 traversalNumber) { _traversalNumber=traversalNumber; } - uint32 getMaxNodeId() const { return (uint32) _nodeIDGenerator; } - uint32 getMaxEdgeId() const { return (uint32) _edgeIDGenerator; } - virtual void print(::std::ostream& os, Node::Annotator* annotator=NULL); + // Remove all empty nodes from CFG. + void purgeEmptyNodes(bool preserveCriticalEdges = false, bool removeEmptyCatchBlocks = false); + + // Remove all unreachable nodes from CFG, + void purgeUnreachableNodes() { purgeUnreachableNodes((Nodes*) NULL); } + + // Remove all unreachable nodes from CFG. Add removed nodes to container. + template <class Container> + void purgeUnreachableNodes(Container& container) { purgeUnreachableNodes(&container);} + + DominatorTree* getDominatorTree() const {return domTree;} + DominatorTree* getPostDominatorTree() const {return postDomTree;} + LoopTree* getLoopTree() const {return loopTree;} + + void setDominatorTree(DominatorTree* dom) {domTree = dom;} + void setPostDominatorTree(DominatorTree* dom) {domTree = dom;} + void setLoopTree(LoopTree* lt) {loopTree= lt;} + protected: - virtual ~ControlFlowGraph() {}; - // Link the node into the CFG. The CFG now owns the node. void addNode(Node* node); - void addNode(NodeList::iterator pos, Node* node); - - // Link the edge into the CFG. - void addEdge(Node* source, Node* target, Edge* edge); - void setNewEdgeId(Edge* edge) { edge->setId(_edgeIDGenerator++); } - - // Callbacks implemented by subclasses. - virtual Node* _createNode(Node::Kind kind) = 0; - virtual Edge* _createEdge(Node* source, Node* target) = 0; - virtual void _updateBranchInstruction(Node* source, Node* oldTarget, Node* newTarget) = 0; - virtual void _removeBranchInstruction(Node* source) = 0; - virtual void _moveInstructions(Node* fromNode, Node* toNode, bool prepend) = 0; - - // Helper methods for subclasses. Subclasses will need to manage - // instructions. - void mergeNodes(Node* source, Node* target, bool keepFirst=true); - Node* splitNode(Node* node, bool newBlockAtEnd=true); - Node* splitEdge(Edge* edge); - -private: + void addEdge(Node* source, Node* target, Edge* edge, double edgeProb); + void removeNode(Nodes::iterator i, bool erase); + + void setNewEdgeId(Edge* edge) { edge->setId(edgeIDGenerator++); } + + void moveInEdges(Node* oldNode, Node* newNode); + void moveOutEdges(Node* oldNode, Node* newNode); + + void resetInEdges(Node* node); + void resetOutEdges(Node* node); + + //low-level helper methods + // WARN: this method does not keep dispatch on original block if newBlockAtEnd=true! + // WARN: does not move instructions + Node* splitNode(Node* node, bool newBlockAtEnd, CFGInst* inst); + Node* splitEdge(Edge* edge, CFGInst* inst); + bool ControlFlowGraph::isBlockMergeAllowed(Node* source, Node* target, bool allowMergeDispatch) const; + + // Helper for getNodesPre/PostOrder above. + template <class Container> + void runDFS(Container* preOrderContainer, Container* postOrderContainer, bool isForward) { + Node* startNode; + if (isForward) { + lastOrderingTraversalNumber = ++traversalNumber; + postOrderCache.clear(); + startNode = entryNode; + } else { + assert(exitNode!=NULL); + startNode = exitNode; + } + currentPreNumber = currentPostNumber = 0; + getNodesDFS(preOrderContainer, postOrderContainer, startNode, isForward); + assert(currentPreNumber == currentPostNumber); + if (isForward) { + nodeCount = currentPreNumber; + } + } // Helper for getNodesPre/PostOrder above. template <class Container> void getNodesDFS(Container* preOrderContainer, Container* postOrderContainer, Node* node, bool isForward=true) { - uint32 marked = _traversalNumber; + uint32 marked = traversalNumber; node->setTraversalNum(marked); - if(isForward) - node->setDFNum(_currentPreNumber); - node->setPreNum(_currentPreNumber++); - if(preOrderContainer != NULL) + if(isForward) { + node->dfNumber = currentPreNumber; + } + node->preNumber = currentPreNumber++; + if(preOrderContainer != NULL) { preOrderContainer->push_back(node); - EdgeList::const_iterator - i = node->getEdges(isForward).begin(), - iend = node->getEdges(isForward).end(); + } + Edges::const_iterator i = node->getEdges(isForward).begin(), iend = node->getEdges(isForward).end(); for(; i != iend; i++) { - Node* succ = (*i)->getNode(isForward); + Edge* edge = *i; + Node* succ = edge->getNode(isForward); if(succ->getTraversalNum() < marked) { getNodesDFS(preOrderContainer, postOrderContainer, succ, isForward); } } - node->setPostNum(_currentPostNumber++); - if(postOrderContainer != NULL) + node->postNumber = currentPostNumber++; + if (postOrderContainer != NULL) { postOrderContainer->push_back(node); + } + if (isForward) { + postOrderCache.push_back(node); + } } // Remove all nodes unreachable from entry. template <class Container> - void purgeUnreachableNodes(Container* container) { - if(!hasValidOrdering()) - orderNodes(); - - NodeList::iterator - iter = _nodes.begin(), - end = _nodes.end(); - for(; iter != end;) { - NodeList::iterator current = iter; - Node* node = *iter; - ++iter; - if(node->_traversalNumber < _traversalNumber) { - removeNode(current); - if(container != NULL) - container->push_back(node); - assert(node != _entry); - if (node == _exit) _exit = NULL; - if (node == _return) _return = NULL; - if (node == _unwind) _unwind = NULL; + void purgeUnreachableNodes(Container* container) { + if(!hasValidOrdering()) { + orderNodes(); } - } - } - void moveInEdges(Node* oldNode, Node* newNode); - void moveOutEdges(Node* oldNode, Node* newNode); - - void resetInEdges(Node* node); - void resetOutEdges(Node* node); + Nodes::iterator iter = nodes.begin(), end = nodes.end(); + for(; iter != end;) { + Nodes::iterator current = iter; + Node* node = *iter; + ++iter; + if(node->traversalNumber < traversalNumber) { + removeNode(current, false); + if(container != NULL) { + container->push_back(node); + } + } + } + nodes.erase(std::remove(nodes.begin(), nodes.end(), (Node*)NULL), nodes.end()); + } - Node* _entry; - Node* _exit; - Node* _return; - Node* _unwind; - - NodeList _nodes; - - uint32 _nodeIDGenerator; - uint32 _edgeIDGenerator; - uint32 _nodeCount; - uint32 _traversalNumber; - uint32 _lastModifiedTraversalNumber; - uint32 _lastOrderingTraversalNumber; - uint32 _lastEdgeRemovalTraversalNumber; - uint32 _currentPreNumber; - uint32 _currentPostNumber; + MemoryManager& mm; + ControlFlowGraphFactory* factory; + Node* entryNode; + Node* returnNode; + Node* exitNode; + Node* unwindNode; + + Nodes nodes; + Nodes postOrderCache; + + uint32 nodeIDGenerator; + uint32 edgeIDGenerator; + uint32 nodeCount; + uint32 traversalNumber; + uint32 lastModifiedTraversalNumber; + uint32 lastOrderingTraversalNumber; + uint32 lastEdgeRemovalTraversalNumber; + uint32 lastProfileUpdateTraversalNumber; + uint32 currentPreNumber; + uint32 currentPostNumber; + + bool annotatedWithEdgeProfile; + + DominatorTree* domTree; + DominatorTree* postDomTree; + LoopTree* loopTree; }; -typedef ControlFlowGraph::Node ControlFlowNode; -typedef ControlFlowGraph::Edge ControlFlowEdge; } //namespace Jitrino diff --git vm/jitrino/src/shared/CountWriters.cpp vm/jitrino/src/shared/CountWriters.cpp index 621e4f6..a4dcda3 100644 --- vm/jitrino/src/shared/CountWriters.cpp +++ vm/jitrino/src/shared/CountWriters.cpp @@ -23,11 +23,16 @@ #include "CountWriters.h" #include <iostream> #include <fstream> +#include <algorithm> +#include <vector> #include <stdio.h> #include <assert.h> #ifdef _WIN32 -#include <windows.h> +#pragma pack(push) + #include <windows.h> +#pragma pack(pop) + #endif @@ -50,8 +55,8 @@ namespace Jitrino CounterBase::CounterBase (const char* s) : key(s) { - next = head; - head = this; + next = head; + head = this; } @@ -62,12 +67,12 @@ CounterBase::~CounterBase () void CounterBase::link () { - for (CounterBase* ptr = head; ptr != 0; ptr = ptr->next) - if (ptr == this) - return; + for (CounterBase* ptr = head; ptr != 0; ptr = ptr->next) + if (ptr == this) + return; - next = head; - head = this; + next = head; + head = this; } @@ -82,78 +87,91 @@ CounterBase* CounterBase::head = 0; CountWriterFile::CountWriterFile (const char* s) :file(0) { - open(s); + open(s); } CountWriterFile::~CountWriterFile () { - close(); + close(); } bool CountWriterFile::open (const char* fname) { - assert(file == 0); - - if (fname != 0 && *fname != 0) - { - file = new ofstream; - file->open(fname, ios::app); - if (!*file) - { - delete file; - file = 0; - return false; - } - } - - return true; + assert(file == 0); + + if (fname != 0 && *fname != 0) + { + file = new ofstream; + file->open(fname, ios::app); + if (!*file) + { + delete file; + file = 0; + return false; + } + } + + return true; +} + + +static bool compareCounters (CounterBase* a, CounterBase* b) +{ + return strcmp(a->key, b->key) < 0; } void CountWriterFile::close () { - if ((os = file) == 0) - os = &cout; + if ((os = file) == 0) + os = &cout; + + *os << RUNSTART << endl; + + vector<CounterBase*> counts; + + for (CounterBase* ptr = CounterBase::head; ptr != 0 ; ptr = ptr->next) + if (ptr->key != 0) + counts.push_back(ptr); - *os << RUNSTART << endl; + sort(counts.begin(), counts.end(), compareCounters); - for (CounterBase* ptr = CounterBase::head; ptr != 0 ; ptr = ptr->next) - if (ptr->key != 0) - ptr->write(*this); + for (vector<CounterBase*>::iterator ptr = counts.begin(), end = counts.end(); ptr != end; ++ptr) + (*ptr)->write(*this); - *os << RUNSTOP << endl; + *os << RUNSTOP << endl; - if (file != 0) - { - delete file; - file = 0; - } + if (file != 0) + { + delete file; + file = 0; + } } void CountWriterFile::write (const char* key, const char* value) { - *os << key << "=" << value << endl; + *os << key << "=" << value << endl; } void CountWriterFile::write (const char* key, int value) { - *os << key << "=" << value << endl; + *os << key << "=" << value << endl; } -void CountWriterFile::write (const char* key, unsigned value) +void CountWriterFile::write (const char* key, size_t value) { - *os << key << "=" << value << endl; + *os << key << "=" << value << endl; } void CountWriterFile::write (const char* key, double value) { - *os << key << "=" << value << endl; + *os << key << "=" << value << endl; } @@ -167,92 +185,92 @@ #ifdef _WIN32 CountWriterMail::CountWriterMail (const char* s) : sloth(INVALID_HANDLE_VALUE) { - open(s); + open(s); } CountWriterMail::~CountWriterMail () { - if (sloth != INVALID_HANDLE_VALUE) - close(); + if (sloth != INVALID_HANDLE_VALUE) + close(); } -// 'server' should be name of the computer to which mail is sent or 0 +// 'server' should be name of the computer to which mail is sent or 0 // bool CountWriterMail::open (const char* server) { - assert(sloth == INVALID_HANDLE_VALUE); + assert(sloth == INVALID_HANDLE_VALUE); - char slotname[128]; - _snprintf(slotname, sizeof(slotname), "\\\\%s\\mailslot\\"MAILSLOT, (server == 0 || *server == 0) ? "." : server); + char slotname[128]; + _snprintf(slotname, sizeof(slotname), "\\\\%s\\mailslot\\"MAILSLOT, (server == 0 || *server == 0) ? "." : server); - sloth = CreateFile(slotname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + sloth = CreateFile(slotname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - mail(RUNSTART"\0", strlen(RUNSTART)); + mail(RUNSTART"\0", strlen(RUNSTART)); - if (sloth == INVALID_HANDLE_VALUE) - cerr << "CountWriter failed to write to '" << slotname << "' (server not running?)" << endl; + if (sloth == INVALID_HANDLE_VALUE) + cerr << "CountWriter failed to write to '" << slotname << "' (server not running?)" << endl; - return sloth != INVALID_HANDLE_VALUE; + return sloth != INVALID_HANDLE_VALUE; } void CountWriterMail::close () { - for (CounterBase* ptr = CounterBase::head; ptr != 0 && sloth != INVALID_HANDLE_VALUE; ptr = ptr->next) - if (ptr->key != 0) - ptr->write(*this); + for (CounterBase* ptr = CounterBase::head; ptr != 0 && sloth != INVALID_HANDLE_VALUE; ptr = ptr->next) + if (ptr->key != 0) + ptr->write(*this); - mail(RUNSTOP"\0", strlen(RUNSTOP)); + mail(RUNSTOP"\0", strlen(RUNSTOP)); - if (sloth != INVALID_HANDLE_VALUE) - { - CloseHandle(sloth); - sloth = INVALID_HANDLE_VALUE; - } + if (sloth != INVALID_HANDLE_VALUE) + { + CloseHandle(sloth); + sloth = INVALID_HANDLE_VALUE; + } } void CountWriterMail::write (const char* key, const char* value) { - char buff[128]; - mail(buff, _snprintf(buff, sizeof(buff), "%s=%s", key, value)); + char buff[128]; + mail(buff, _snprintf(buff, sizeof(buff), "%s=%s", key, value)); } void CountWriterMail::write (const char* key, int value) { - char buff[128]; - mail(buff, _snprintf(buff, sizeof(buff), "%s=%i", key, value)); + char buff[128]; + mail(buff, _snprintf(buff, sizeof(buff), "%s=%i", key, value)); } -void CountWriterMail::write (const char* key, unsigned value) +void CountWriterMail::write (const char* key, size_t value) { - char buff[128]; - mail(buff, _snprintf(buff, sizeof(buff), "%s=%u", key, value)); + char buff[128]; + mail(buff, _snprintf(buff, sizeof(buff), "%s=%u", key, value)); } void CountWriterMail::write (const char* key, double value) { - char buff[128]; - mail(buff, _snprintf(buff, sizeof(buff), "%s=%G", key, value)); + char buff[128]; + mail(buff, _snprintf(buff, sizeof(buff), "%s=%G", key, value)); } void CountWriterMail::mail (const char* str, size_t bytes) { - assert(str[bytes] == 0); - bytes++; - DWORD written; - if (sloth != INVALID_HANDLE_VALUE && - WriteFile(sloth, str, static_cast<DWORD>(bytes), &written, 0) == 0) - { - CloseHandle(sloth); - sloth = INVALID_HANDLE_VALUE; - } + assert(str[bytes] == 0); + bytes++; + DWORD written; + if (sloth != INVALID_HANDLE_VALUE && + WriteFile(sloth, str, static_cast<DWORD>(bytes), &written, 0) == 0) + { + CloseHandle(sloth); + sloth = INVALID_HANDLE_VALUE; + } } #endif //#ifdef _WIN32 diff --git vm/jitrino/src/shared/CountWriters.h vm/jitrino/src/shared/CountWriters.h index be376ba..3fa04ff 100644 --- vm/jitrino/src/shared/CountWriters.h +++ vm/jitrino/src/shared/CountWriters.h @@ -35,20 +35,20 @@ class CountWriterFile : public CountWrit { public: - CountWriterFile (const char* = 0); - /*virtual*/ ~CountWriterFile (); + CountWriterFile (const char* = 0); + /*virtual*/ ~CountWriterFile (); - bool open (const char*); - void close (); + bool open (const char*); + void close (); - /*virtual*/ void write (const char* key, const char* value); - /*virtual*/ void write (const char* key, int value); - /*virtual*/ void write (const char* key, unsigned value); - /*virtual*/ void write (const char* key, double value); + /*virtual*/ void write (const char* key, const char* value); + /*virtual*/ void write (const char* key, int value); + /*virtual*/ void write (const char* key, size_t value); + /*virtual*/ void write (const char* key, double value); protected: - std::ofstream* file; + std::ofstream* file; std::ostream* os; }; @@ -60,22 +60,22 @@ class CountWriterMail : public CountWrit { public: - CountWriterMail (const char* = 0); - /*virtual*/ ~CountWriterMail (); + CountWriterMail (const char* = 0); + /*virtual*/ ~CountWriterMail (); - bool open (const char*); - void close (); + bool open (const char*); + void close (); - /*virtual*/ void write (const char* key, const char* value); - /*virtual*/ void write (const char* key, int value); - /*virtual*/ void write (const char* key, unsigned value); - /*virtual*/ void write (const char* key, double value); + /*virtual*/ void write (const char* key, const char* value); + /*virtual*/ void write (const char* key, int value); + /*virtual*/ void write (const char* key, size_t value); + /*virtual*/ void write (const char* key, double value); protected: - void mail (const char*, size_t); + void mail (const char*, size_t); - void* sloth; + void* sloth; }; #endif //#ifdef _WIN32 diff --git vm/jitrino/src/shared/Counter.h vm/jitrino/src/shared/Counter.h index 96dff4f..e529eeb 100644 --- vm/jitrino/src/shared/Counter.h +++ vm/jitrino/src/shared/Counter.h @@ -23,19 +23,22 @@ #ifndef _COUNTER_H_ #define _COUNTER_H_ + +#include <stddef.h> + + namespace Jitrino { -class CountWriter -{ +class CountWriter { public: - virtual ~CountWriter () {} + virtual ~CountWriter () {} - virtual void write (const char* key, const char* value) = 0; - virtual void write (const char* key, int value) = 0; - virtual void write (const char* key, unsigned int value) = 0; - virtual void write (const char* key, double value) = 0; + virtual void write (const char* key, const char* value) = 0; + virtual void write (const char* key, int value) = 0; + virtual void write (const char* key, size_t value) = 0; + virtual void write (const char* key, double value) = 0; }; @@ -43,19 +46,19 @@ class CounterBase { public: - CounterBase (const char* s = 0); - virtual ~CounterBase (); + CounterBase (const char* s = 0); + virtual ~CounterBase (); - void setName (const char* s) {key = s;} - void link (); - virtual void write (CountWriter&) = 0; + void setName (const char* s) {key = s;} + void link (); + virtual void write (CountWriter&) = 0; - const char* key; + const char* key; //protected: - CounterBase* next; - static CounterBase* head; + CounterBase* next; + static CounterBase* head; }; @@ -64,18 +67,17 @@ class Counter : public CounterBase { public: - Counter (const char* s) : CounterBase(s) {} - Counter (const char* s, const T& v) : CounterBase(s), value(v) {} + Counter (const char* s) : CounterBase(s) {} + Counter (const char* s, const T& v) : CounterBase(s), value(v) {} - /*virtual*/void write (CountWriter& logs) {logs.write(key, value);} + /*virtual*/void write (CountWriter& logs) {logs.write(key, value);} - operator T& () {return value;} + operator T& () {return value;} - T value; + T value; }; - } //namespace Jitrino #endif //#ifndef _COUNTER_H_ diff --git vm/jitrino/src/shared/Dlink.h vm/jitrino/src/shared/Dlink.h index bb66afb..eef68b9 100644 --- vm/jitrino/src/shared/Dlink.h +++ vm/jitrino/src/shared/Dlink.h @@ -26,6 +26,9 @@ #define _DLINK_H namespace Jitrino { class Dlink { +protected: + // add vtable to Dlink to see Dlink successors fields in VS debugger + virtual void vtable_stub() const {} public: Dlink() { _next = _prev = this; @@ -93,15 +96,15 @@ protected: class DlinkElem : public Dlink { public: - DlinkElem(void* e) : elem(e) {} - DlinkElem() {elem = NULL;} - DlinkElem* getNext() {return (DlinkElem*)Dlink::getNext();} - DlinkElem* getPrev() {return (DlinkElem*)Dlink::getPrev();} - void* getElem() {return elem;} - void setElem(void* e){elem = e;} + DlinkElem(void* e) : elem(e) {} + DlinkElem() {elem = NULL;} + DlinkElem* getNext() {return (DlinkElem*)Dlink::getNext();} + DlinkElem* getPrev() {return (DlinkElem*)Dlink::getPrev();} + void* getElem() {return elem;} + void setElem(void* e){elem = e;} void moveTo(DlinkElem *head) {Dlink::moveTo((Dlink *) head);} private: - void* elem; + void* elem; }; } //namespace Jitrino diff --git vm/jitrino/src/shared/Dominator.cpp vm/jitrino/src/shared/Dominator.cpp new file mode 100644 index 0000000..ad88787 --- /dev/null +++ vm/jitrino/src/shared/Dominator.cpp @@ -0,0 +1,229 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Pavel A. Ozhdikhin + * @version $Revision$ + * + */ + +#include "Dominator.h" + +namespace Jitrino { + +// BOTTOM : no idom. idom[entry] = BOTTOM +#define NONE MAX_UINT32 +// TOP : no information computed yet +#define UNDEFINED 0 + +// Cooper / Harvey / Kennedy variation on simple iterative dominator algorithm. +// They claim that this is faster than Lengauer / Tarjan in practice. +DominatorTree* +DominatorBuilder::computeDominators(MemoryManager& mm, ControlFlowGraph* flowgraph, bool isPost, bool ignoreUnreach) { + // Temp memory manager + MemoryManager tmm(flowgraph->getMaxNodeId()*(sizeof(Node*)*2), "DominatorBuilder::computeDominators"); + Nodes nodes(tmm); + + // Get the nodes of the flowgraph in postorder. + flowgraph->getNodesPostOrder(nodes, !isPost); + uint32 numNodes = (uint32) nodes.size(); +#ifdef _DEBUG + // Start (entry/exit) node should be last. + Node* start = nodes.back(); + assert((start == (isPost ? flowgraph->getExitNode() : flowgraph->getEntryNode()) + && start->getPostNum() == numNodes-1)); +#endif + // Initialize the idom array to UNDEFINED. Idiom maps the postorder + // number of a node to the postorder number of its idom. + StlVector<uint32> idom(tmm); + idom.insert(idom.end(), (unsigned int) numNodes-1, UNDEFINED); + // Initialize idom[entry] = NONE. + idom.insert(idom.end(), NONE); + + // Find maximal fixed point + bool changed = true; + while(changed) { + changed = false; + // Process all nodes except entry in reverse postorder. + Nodes::reverse_iterator i; + for(i = nodes.rbegin()+1; i != nodes.rend(); ++i) { + Node* node = *i; + uint32 nodeNum = node->getPostNum(); + + // Compute updated idom from predecessors + uint32 newIdom = UNDEFINED; + Edges::const_iterator j; + for(j = node->getEdges(isPost).begin(); j != node->getEdges(isPost).end(); ++j) { + Node* pred = (*j)->getNode(isPost); + // Assert that pred is reachable. + if (!ignoreUnreach) + assert(pred->getTraversalNum() == flowgraph->getTraversalNum()); + if (!ignoreUnreach || (ignoreUnreach && (pred->getTraversalNum() == flowgraph->getTraversalNum()))) { + uint32 predNum = pred->getPostNum(); + // Skip unprocessed preds (only happens on first iteration). + if(idom[predNum] != UNDEFINED) + // Intersect dominator sets. + newIdom = (newIdom == UNDEFINED) ? predNum : intersect(idom, newIdom, predNum); + } + } + assert(newIdom != UNDEFINED); + + // Update if changed + if(newIdom != idom[nodeNum]) { + // Assert that we are converging. + assert(newIdom > idom[nodeNum]); + idom[nodeNum] = newIdom; + changed = true; + } + } + } + + // Build dominator tree and return. + return new (mm) DominatorTree(mm, flowgraph, nodes, idom, isPost); +} + +uint32 +DominatorBuilder::intersect(StlVector<uint32>& idom, uint32 finger1, uint32 finger2) { + // Intersect the dominator sets represented by finger1 and finger2. + while(finger1 != finger2) { + while(finger1 < finger2) + finger1 = idom[finger1]; + while(finger2 < finger1) + finger2 = idom[finger2]; + } + // Set should at least contain root/entry. + assert(finger1 != NONE); + return finger1; +} + +DominatorTree::DominatorTree(MemoryManager& mm, + ControlFlowGraph* fg, + Nodes& nodes, + StlVector<uint32>& idom, + bool isPostDominator) + : flowgraph(fg), traversalNum(fg->getTraversalNum()), + numNodes(fg->getMaxNodeId()), + _isPostDominator(isPostDominator), tree(mm, numNodes, NULL) { + // Create the dominator tree nodes.. + uint32 postNum, id=MAX_UINT32; + for(postNum = 0; postNum < nodes.size(); ++postNum) { + Node* node = nodes[postNum]; + id = node->getId(); + tree[id] = new (mm) DominatorNode(node); + } + + // Create tree itself. Note that the children of each + // dominator parent node will be in sorted in + // reverse postorder. It's assumed that nodes is + // in postorder. + for(postNum = 0; postNum < nodes.size(); ++postNum) { + Node* node = nodes[postNum]; + id = node->getId(); + // Assert post-ordering of nodes. + assert((uint32) postNum == node->getPostNum()); + if(idom[postNum] != NONE) { + // Assert that idoms are acyclic. + assert(idom[postNum] > postNum); + Node* parent = nodes[idom[postNum]]; + uint32 parentId = parent->getId(); + assert(tree[parentId] != NULL); + // Assert that new child (added to beginning) has highest postorder number. + assert(tree[parentId]->getChild() == NULL || tree[parentId]->getChild()->getNode()->getPostNum() < postNum); + tree[parentId]->addChild(tree[id]); + } + } + + // Last node is root. + root = tree[id]; + computeOrder(); +} + +bool DominatorTree::dominates(Node* a, Node* b) { + assert(a != NULL && b != NULL); + assert(a->getId() < numNodes && b->getId() < numNodes); + return a==b || isAncestor(tree[a->getId()], tree[b->getId()]); +} + + +DomFrontier::DomFrontier(MemoryManager& mm, + DominatorTree& d, + ControlFlowGraph* fg) +: memManager(mm), dom(d), isPostDominator(d.isPostDominator()) { + // To Do: may want to keep number of nodes in flow graph instead of recomputing every time + numNodes = (uint32) fg->getNodeCount(); + + // if flow graph has been modified since dominator was computed, then + // dominator information needs to be recomputed + if (!dom.isValid()) { + DominatorBuilder db; + dom = *db.computeDominators(memManager,fg); + } + + beenComputed = new (memManager) BitSet(memManager, numNodes); + DF = (List<Node>**) memManager.alloc(sizeof(List<Node>*)*numNodes); + memset(DF, 0, numNodes*sizeof(List<Node>*)); // initialized with NULL +} + +void DomFrontier::addDF(uint32 entry, Node* n) { + assert(entry < numNodes); + // make sure no duplicate entry + for (List<Node>* l = DF[entry]; l != NULL; l = l->getNext()) + if (l->getElem() == n) + return; + DF[entry] = new (memManager) List<Node>(n,DF[entry]); +} + +void DomFrontier::computeDomFrontier(Node* node) { + uint32 dfnum = node->getDfNum(); + // if dom frontiers are not computed yet + if (beenComputed->getBit(dfnum)) + return; + beenComputed->setBit(dfnum,true); + + // If this is a post-dominance frontier, use the reverse graph. + bool forward = !isPostDominator; + + // compute DF local: the successors of node that are not strictly + // dominated by node + const Edges& edges = node->getEdges(forward); + Edges::const_iterator eiter; + for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { + Edge* e = *eiter; + Node *succ = e->getNode(forward); + if (dom.getIdom(succ) != node) { + addDF(dfnum,succ); + } + } + + // compute DF up: Nodes in the dom frontier of node that are dominated + // by node's immediate dominator + for (DominatorNode* c = dom.getDominatorNode(node)->getChild(); c != NULL; c = c->getSiblings()) { + Node* child = c->getNode(); + computeDomFrontier(child); + + // go over each frontier of child + for (List<Node>* f = DF[child->getDfNum()];f != NULL; f = f->getNext()) { + Node *elem = f->getElem(); + // if node does not strictly dominates elem + if (elem == node || !dom.dominates(node,elem)) { + addDF(dfnum,elem); + } + } + } +} + + +} //namespace Jitrino diff --git vm/jitrino/src/shared/Dominator.h vm/jitrino/src/shared/Dominator.h new file mode 100644 index 0000000..590ae81 --- /dev/null +++ vm/jitrino/src/shared/Dominator.h @@ -0,0 +1,163 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Pavel A. Ozhdikhin + * @version $Revision$ + * + */ + +#ifndef _FLOWGRAPHDOM_H_ +#define _FLOWGRAPHDOM_H_ + +#include "MemoryManager.h" +#include "Stl.h" +#include "BitSet.h" +#include "Tree.h" +#include "List.h" +#include "ControlFlowGraph.h" + +namespace Jitrino { + + +/** + * A DominatorNode represents (post)dominance information computed for a + * ControlFlowNode. A DominatorNode may be use to navigate the + * DominatorTree (see below). + **/ +class DominatorNode : public TreeNode { +public: + DominatorNode(Node* n) : node(n) {} + DominatorNode* getChild() {return (DominatorNode*)child;} + DominatorNode* getSiblings() {return (DominatorNode*)siblings;} + DominatorNode* getParent() {return (DominatorNode*)parent;} + Node* getNode() {return node;} +private: + Node* node; +}; + + +/** + * A DominatorTree represents (post)dominance information computed for a + * ControlFlowGraph. It may be used to query or navigate (post)dominance + * relationships. The root of the tree is the DominatorNode of the + * entry/exit, and the parent of any node (other than the root) is the + * immediate dominator/post-dominator. + * + * Note that a DominatorTree is invalidated when the underlying CFG + * is modified. The DominatorTree can still be queried/navigated, + * but may no longer reflect the CFG. + **/ +class DominatorTree: public Tree { + friend class DominatorBuilder; +public: + // Returns true if a == b or a strictly (post)dominates b. + bool dominates(Node* a, Node* b); + + // Returns the immediate (post)dominator of n. Return NULL if no nodes (post)dominate n. + Node* getIdom(Node* n) { + DominatorNode* idom = getDominatorNode(n)->getParent(); + return (idom == NULL) ? NULL : idom->getNode(); + } + + // Returns the dominator tree node associated with this CFG node. + // Use the tree node to traverse the (post)dominator tree. + DominatorNode* getDominatorNode(Node* n) {return tree[n->getId()];} + + // Returns the root tree node of the (post)dominator tree. If this is a + // dominator tree, this is the tree node of the entry. If this is a + // post-dominator tree, this is the tree node of the exit. + DominatorNode* getDominatorRoot() { + return (DominatorNode*) root; + } + + // Returns the number of nodes in the tree. + uint32 getNumNodes() const { return numNodes; } + + // True if this is a post-dominator tree. + bool isPostDominator() const { return _isPostDominator; } + + // True if the graph was not modified since the dominator was computed. + bool isValid() { + return traversalNum > flowgraph->getModificationTraversalNum(); + } + uint32 getTraversalNum() { return traversalNum; } + + // True if node has dominator information. Note, if the dominator tree + // is not valid overall, it is up to the caller to ensure that an + // individual nodes information is still valid. + bool hasDomInfo(Node *n) { + return (n->getId() < numNodes && tree[n->getId()] != NULL); + } + +private: + DominatorTree(MemoryManager& mm, ControlFlowGraph* fg, StlVector<Node*>& nodes, + StlVector<uint32>& idom, bool isPostDominator); + + ControlFlowGraph* flowgraph; + uint32 traversalNum; + uint32 numNodes; + bool _isPostDominator; + StlVector<DominatorNode*> tree; +}; + + +/** + * A DominatorBuilder is used to compute (post)dominator information given + * a CFG. + **/ +class DominatorBuilder { +public: + DominatorBuilder() {} + DominatorTree* computeDominators(MemoryManager& mm, ControlFlowGraph* flowgraph, bool isPost=false, bool ignoreUnreach = false); + DominatorTree* computePostdominators(MemoryManager& mm, ControlFlowGraph* flowgraph, bool ignoreUnreach) { return computeDominators(mm, flowgraph, true, ignoreUnreach); } +private: + uint32 intersect(StlVector<uint32>& idom, uint32 num1, uint32 num2); +}; + +/** + * DomFrontier provides dominance frontier information given + * a dominator tree. Note, if passed a post-dominator tree, + * the post-dominance frontier is, by definition, the control + * dependence set. + **/ +class DomFrontier { +public: + DomFrontier(MemoryManager& mm, DominatorTree& d, ControlFlowGraph* fg); + void printDomFrontier(::std::ostream&, Node* n); + uint32 getNumNodes() {return numNodes;} + List<Node>* getFrontiersOf(Node* n) { + assert(n->getDfNum() < numNodes); + computeDomFrontier(n); + return DF[n->getDfNum()]; + } + DominatorTree& getDominator() {return dom;} +private: + void computeDomFrontier(Node* n); + void addDF(uint32 entry, Node* n); + + + List<Node>** DF; + uint32 numNodes; + BitSet* beenComputed; + MemoryManager& memManager; + DominatorTree& dom; + bool isPostDominator; +}; + +} //namespace Jitrino + +#endif // _FLOWGRAPHDOM_H_ diff --git vm/jitrino/src/shared/Exceptions.h vm/jitrino/src/shared/Exceptions.h index 1243866..2ab4d2d 100644 --- vm/jitrino/src/shared/Exceptions.h +++ vm/jitrino/src/shared/Exceptions.h @@ -29,9 +29,9 @@ class IndexOutOfBoundsException { public: IndexOutOfBoundsException() : msg("") { assert(0); } IndexOutOfBoundsException(const char* message) : msg(message) { assert(0); } - const char* getMessage() {return msg;} + const char* getMessage() {return msg;} private: - const char* msg; + const char* msg; }; class TranslationException { diff --git vm/jitrino/src/shared/FixFileName.cpp vm/jitrino/src/shared/FixFileName.cpp new file mode 100644 index 0000000..d98b6a7 --- /dev/null +++ vm/jitrino/src/shared/FixFileName.cpp @@ -0,0 +1,145 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Sergey L. Ivashin + * @version $Revision$ + * + */ + + +#include <FixFileName.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <iomanip> + +#ifdef _WIN32 + #define PATHSEPCHAR '\\' +#else //PLATFORM_POSIX + #define PATHSEPCHAR '/' +#endif //ifdef _WIN32 + + +using namespace std; + + +namespace Jitrino +{ + + +static bool isValid (int c) +{ +#ifdef _PMF_LOG_ANY +// On Window any characters expect 0x00 - 0x17 and <>:"/\| are acceptable in file/directory name + if (c < 0x20) + return false; + if (strchr("<>:\"/\\|", c) != 0) + return false; + return true; +#else +// But we are using more safe approach + return ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + ('0' <= c && c <= '9') || + strchr(".-_$()[],;:", c) != 0; +#endif +} + + +static unsigned int hash (const char* ptr, size_t count) +{ + unsigned int r = 0; + + for (; count != 0; --count) + r = (r << 1) ^ (*ptr++); + + return r; +} + + +static void reserve (char*& ptr, char* end, size_t n) +{ + if (ptr + n > end) + ptr = end - n; +} + + +void fix_file_name (char* goodname, int goodmax, const char* badname) +{ + size_t badnamesz = strlen(badname), + badnamemx = badnamesz * 3 + 1; // in the worst case, 1 char replaced by 3 '~88' + char* work = new char[badnamemx]; + + char* src = work; + for (; *badname != 0; ++badname) + { + int c = *badname & 0xFF; + + if (c == '<' || c == '>') + *src++ = '_'; + + else if (c == '/' || c == '\\') + *src++ = PATHSEPCHAR; + + else if (isValid(c)) + *src++ = (char)c; + + else + src += sprintf(src, "~%x", c); + } + *src = 0; + + src = work; + char* dst = goodname; + char* dstend = goodname + goodmax - 1; + + for (; *src != 0; ++src) + { + // find next part of source file name to process + const char* srcpart = src; + while (*src != '/' && *src != '\\' && *src != '.' && *src != 0) + ++src; + + size_t partsz = src - srcpart; + + if (partsz > MAXFILEPARTSIZE) + {// will copy MAXFILEPARTSIZE chars + reserve(dst, dstend, MAXFILEPARTSIZE); + char temp[10]; + int n = sprintf(temp, "~%x", hash(srcpart, partsz) & 0xFFF); + memcpy(dst, srcpart, MAXFILEPARTSIZE - n); + dst += MAXFILEPARTSIZE - n; + memcpy(dst, temp, n); + dst += n; + } + else + {// will copy partsz chars + reserve(dst, dstend, partsz); + memcpy(dst, srcpart, partsz); + dst += partsz; + } + + reserve(dst, dstend, 1); + *dst++ = *src; + if (*src == 0) + break; + } + + delete [] work; +} + +} //namespace Jitrino diff --git vm/jitrino/src/shared/FixFileName.h vm/jitrino/src/shared/FixFileName.h new file mode 100644 index 0000000..75efe82 --- /dev/null +++ vm/jitrino/src/shared/FixFileName.h @@ -0,0 +1,49 @@ + +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Sergey L. Ivashin + * @version $Revision$ + * + */ + +#ifndef _FIXFILENAME_H_ +#define _FIXFILENAME_H_ + +#include <stddef.h> + + +namespace Jitrino +{ + +// max acceptable file name part (between '/' or '.') +const size_t MAXFILEPARTSIZE = 75; + +// max acceptable file name +const size_t MAXFILENAMESIZE = MAXFILEPARTSIZE * 4; + +// used in StrSubstitution only +const size_t MAXLOGFILENAME = 500; + + +void fix_file_name (char* goodname, int goodmax, const char* badname); + + +} + + +#endif //#ifndef _FIXFILENAME_H_ diff --git vm/jitrino/src/shared/Graph.cpp vm/jitrino/src/shared/Graph.cpp deleted file mode 100644 index f2089ef..0000000 --- vm/jitrino/src/shared/Graph.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.9.22.4 $ - * - */ - -#include <stdlib.h> -#include "Type.h" -#include "Graph.h" -#include "Stack.h" - -#include <string.h> - -namespace Jitrino { - -// -// count number of nodes -// - -uint32 Graph::countNodes() { - uint32 numNodes = 0; - for (Node* n = head.next(); n != &head; n = n->next()) - numNodes++; - return numNodes; -} - -// -// assign depth first numbering starting from an initial node and propagating forward -// - -void Graph::assignDfNum(Node* node, uint32& dfNum, StlVector<Node*>& dfnMap) { - if (node->getTraversalNum() >= traversalNum) - return; - node->setTraversalNum((uint16)traversalNum); - - // set node's depth first number - dfnMap.push_back(node); - node->setDfNum(dfNum++); - assert(dfNum == dfnMap.size()); - - // traverse each successor - for (Edge* e = node->getSuccEdges(); e != NULL; e = e->getNextSuccEdge()) - assignDfNum(e->getSuccNode(), dfNum, dfnMap); -} - - - -// -// add <pred,succ> edge into pred and succ nodes -// the user needs to supply the edge to insert -// - -void Graph::addEdge(Node *predNode, Node* succNode, Edge *edge) { -#ifdef _DEBUGx - ::std::cout << "add edge<"; - predNode->print(cout);cout << ","; - succNode->print(cout);cout << ">" << ::std::endl; -#endif - assert(!predNode->hasEdge(succNode)); - edge->setNextSuccEdge(predNode->getSuccEdges()); - predNode->setSuccEdges(edge); - edge->setSuccNode(succNode); - - edge->setNextPredEdge(succNode->getPredEdges()); - succNode->setPredEdges(edge); - edge->setPredNode(predNode); - - setBeenModified(true); -} - -// -// same as before, but the user does not need to supply the edge to insert, it is -// created automatically -// -void Graph::addEdge(Node *predNode, Node* succNode) { - Edge *edge = new (memManager)Edge(); - addEdge(predNode, succNode, edge); -} - -Edge * Graph::deleteEdgeToSuccessor(Node* predNode, Node* succNode) { - Edge *edge; - Edge *prev = NULL; - for (edge = predNode->getSuccEdges(); edge != NULL; edge = edge->getNextSuccEdge()) { - if (edge->getSuccNode() == succNode) - break; - prev = edge; - } - assert(edge != NULL); - if (prev != NULL) - prev->setNextSuccEdge(edge->getNextSuccEdge()); - else - predNode->setSuccEdges(edge->getNextSuccEdge()); - return edge; -} - -void Graph::deleteEdgeToPredecessor(Node *succNode, Edge *edge) { - Edge *e; - Edge *prev = NULL; - for (e = succNode->getPredEdges(); e != NULL; e = e->getNextPredEdge()) { - if (e == edge) - break; - prev = e; - } - if (prev != NULL) - prev->setNextPredEdge(edge->getNextPredEdge()); - else - succNode->setPredEdges(edge->getNextPredEdge()); -} - -// -// remove edges between pred and succ nodes, returns the edge -// -Edge * Graph::deleteEdge(Node* predNode, Node* succNode) { - Edge *edge = deleteEdgeToSuccessor(predNode,succNode); - deleteEdgeToPredecessor(succNode,edge); - return edge; -} - -// -// move edges from succ node to predecessor node -// -void Graph::mergeNodeWithSuccessor(Node* predNode, Node* succNode) { - if (succNode->hasOnlyOnePredEdge()) { - // delete the edge between predecessor and successor - deleteEdgeToSuccessor(predNode,succNode); - Edge *edge; - for (edge = succNode->getSuccEdges(); edge != NULL; edge = edge->getNextSuccEdge()) { - edge->setPredNode(predNode); - } - Edge *prev = NULL; - for (edge = predNode->getSuccEdges(); edge != NULL; edge = edge->getNextSuccEdge()) { - prev = edge; - } - if (prev != NULL) { - prev->setNextSuccEdge(succNode->getSuccEdges()); - } else - predNode->setSuccEdges(succNode->getSuccEdges()); - succNode->unlink(); - } else { // more general case, less efficient - Edge *edge = deleteEdge(predNode,succNode); - Edge *first = succNode->getSuccEdges(); - addEdge(predNode,first->getSuccNode(),edge); - for (edge = first->getNextSuccEdge(); edge != NULL; edge = edge->getNextSuccEdge()) { - addEdge(predNode,edge->getSuccNode()); - } - } -} - - -// -// move successor edges from node 'from' to a newly created node 'to' - -void Graph::moveSuccEdgesToNewNode(Node* from, Node *to) { - assert(to->getSuccEdges()==NULL); - for (Edge *edge = from->getSuccEdges(); edge != NULL; edge = edge->getNextSuccEdge()) { - edge->setPredNode(to); - } - to->setSuccEdges(from->getSuccEdges()); - from->setSuccEdges(NULL); -} - - -// -// return true, if there exists an edge between predNode and succNode -// only used for assertion -// -bool Node::hasEdge(Node* succNode) { - for (Edge* e = succs; e != NULL; e = e->getNextSuccEdge()) - if (e->getSuccNode() == succNode) - return true; - return false; -} - -// -// generic print node id (only prints the depth-first number) -// - -void Node::print(::std::ostream& cout) { - cout << "Node" << (int32)dfnum << ::std::endl; -} - - -/*********** support for DOT files ******************/ - -void Graph::printDotBody() { - ::std::ostream& out = *os; - Node *head = getNodeList(); - Node *node; - for (node = head->next(); node != head; node = node->next()) - node->printDotNode(out); - for (node = head->next(); node != head; node = node->next()) - for (Edge *edge = node->getSuccEdges(); edge != NULL; edge = edge->getNextSuccEdge()) - edge->printDotEdge(out); -} - - -void Node::printDotNode(::std::ostream& out) { - print(out); - out << " [label=\""; - print(out); - out << "\"]" << ::std::endl; -} - -void Edge::printDotEdge(::std::ostream& out) { - predNode->print(out); - out << " -> "; - succNode->print(out); - out << ";" << ::std::endl; -} - - - -} //namespace Jitrino diff --git vm/jitrino/src/shared/Graph.h vm/jitrino/src/shared/Graph.h deleted file mode 100644 index 6c5b486..0000000 --- vm/jitrino/src/shared/Graph.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.8.24.4 $ - * - */ - -// -// Graph.h -// -// Generic graph with nodes and bidirectional edges to be used for multiple purposes, -// for example: - Control Flow Graph construction, -// - Call Graph -// - Dependence analysis graphs -// - Class Hierarchy Analysis, -// - etc... -// -#ifndef _GRAPH_ -#define _GRAPH_ - -#include "Stl.h" -#include "Dlink.h" -#include "PrintDotFile.h" - -namespace Jitrino { - -// -// Generic Bidirectional Edge -// You can use it directly, or subclass if you require more information. -// - -class Node; - -class Edge { - -public: - Edge() : predNode(NULL), succNode(NULL), nextPredEdge(NULL), nextSuccEdge(NULL) {} - virtual ~Edge() {} - Node* getPredNode() {return predNode; } - Node* getSuccNode() {return succNode; } - Edge* getNextPredEdge() {return nextPredEdge; } - Edge* getNextSuccEdge() {return nextSuccEdge; } - int getEdgeFlags() {return edgeFlags; } - - // these routines are not meant for general purpose use - void setNextPredEdge(Edge* e) {nextPredEdge = e; } - void setNextSuccEdge(Edge* e) {nextSuccEdge = e; } - void setPredNode(Node *n) {predNode = n; } - void setSuccNode(Node *n) {succNode = n; } - void setEdgeFlags(int flags) {edgeFlags = flags;} - virtual void printDotEdge(::std::ostream& os); // for DOT files -protected: - Node* predNode; Node * succNode; - Edge* nextPredEdge; Edge * nextSuccEdge; - int edgeFlags; // generic edge flags to be used by different algorithms -}; - - - - -// invalid depth first number -#define INVALID_DFN ((uint32)-1) - -// -// Generic Node -) -// You can use it directly, or subclass if you require more information. -// - -class Node : public Dlink { - - public: - Node(): traversalNum(0), dfnum(INVALID_DFN), succs(NULL), preds(NULL) {} - virtual ~Node() {} - // - // true if there is any edge to a successor node. - bool hasEdge(Node* succNode); - - // utilities to perform node numbering - uint16 getTraversalNum() {return traversalNum;} - void setTraversalNum(uint16 num) {traversalNum = num;} - uint32 getDfNum() {return dfnum;} - void setDfNum(uint32 num) {dfnum = num;} - - // return the start list of predecessor or successor edges - Edge* getSuccEdges() {return succs;} - Edge* getPredEdges() {return preds;} - - // the following inherited from DLink, next and previous node in a linked list - Node* next() {return (Node*)_next;} - Node* prev() {return (Node*)_prev;} - - // the following utilities are useful in some tests - bool hasOnlyOneSuccEdge() { return succs != NULL && succs->getNextSuccEdge() == NULL; } - bool hasOnlyOnePredEdge() { return preds != NULL && preds->getNextPredEdge() == NULL; } - bool hasTwoOrMoreSuccEdges() { return succs != NULL && succs->getNextSuccEdge() != NULL; } - bool hasTwoOrMorePredEdges() { return preds != NULL && preds->getNextPredEdge() != NULL; } - void setSuccEdges(Edge* list) {succs = list;} - void setPredEdges(Edge* list) {preds = list;} - - virtual void print(::std::ostream& cout); - virtual void printDotNode(::std::ostream& cout); // for Dot files - - private: - friend class Graph; // associated graph to which this node belongs to - -protected: - // - // indicate if the node has been visited or not - // - uint16 traversalNum; - uint32 dfnum; // depth first number - // - // linked list of successors and predecessors - // - Edge* succs; - Edge* preds; -}; - - -// -// Generic Graph. Not too much information so far, add as you need. -// - -class Graph: public PrintDotFile { - -public: - Graph(MemoryManager& mm) : - memManager(mm), traversalNum(0) {} - - MemoryManager& getMemoryManager() { return memManager; } - uint32 getTraversalNum() {return traversalNum;} - void setTraversalNum(uint32 num) {traversalNum = num;} - void setBeenModified(bool mod) {beenModified = mod;} - bool getBeenModified() {return beenModified;} - // - // modify flow graph routines - // - void addEdge(Node* pred, Node* succ); - Edge * deleteEdge(Node* pred, Node* succ); - void addEdge(Node* pred, Node* succ, Edge *edge); - - // more elaborate modify routines - void mergeNodeWithSuccessor(Node *pred, Node *succ); - void moveSuccEdgesToNewNode(Node *from, Node *to); - - // - // insert node in the node list - // - void insertNode(Node* node) {node->insertBefore(&head);} - // - // get node list - // - Node* getNodeList() {return &head;} - // - // assign depth first numbering starting from a node - // - void assignDfNum(Node* n, uint32& dfNum, StlVector<Node*>& dfnMap); - // - // count nodes in the graph - // - uint32 countNodes(); - // - /* for DOT files support */ - virtual void printDotBody(); - -protected: - // The following node provided to keep a list of the nodes in the graph - Node head; - - MemoryManager& memManager; - uint32 traversalNum; - bool beenModified; // graph has changed -private: - Edge * deleteEdgeToSuccessor(Node* pred, Node* succ); - void deleteEdgeToPredecessor(Node* succ, Edge *edge); -}; - - -} //namespace Jitrino - -#endif // _GRAPH_ diff --git vm/jitrino/src/shared/HashSet.h vm/jitrino/src/shared/HashSet.h index 91144e4..5c26fa2 100644 --- vm/jitrino/src/shared/HashSet.h +++ vm/jitrino/src/shared/HashSet.h @@ -38,63 +38,63 @@ template<class KEY, class ELEM> class Ha public: typedef StlHashMap<KEY,ELEM>::iterator iterator; typedef StlHashMap<KEY,ELEM>::const_iterator const_iterator; - // - // Constructor - // + // + // Constructor + // HashSet(MemoryManager& memManager) : map(memManager) { } - // - // Copy constructor - // - HashSet(MemoryManager& memManager, const HashSet<KEY,ELEM> &set) + // + // Copy constructor + // + HashSet(MemoryManager& memManager, const HashSet<KEY,ELEM> &set) : map(memManager) { const_iterator iter = set.map.begin(), end = set.map.end(); for (; iter != end; iter++) map.insert(*iter); - } + } // // Returns number of elements in the set // uint32 getSize() const {return (uint32)map.size();} - // - // Returns true if set contains the element, false otherwise - // - bool contains(KEY key) const { + // + // Returns true if set contains the element, false otherwise + // + bool contains(KEY key) const { return map.find(key) != map.end(); - } - // - // Inserts element into the set - // + } + // + // Inserts element into the set + // void insert(KEY key, ELEM elem) {map[key] = elem;} // // Removes element from the set // void remove(KEY key) {map.erase(key);} - // - // Removes all element from the set - // + // + // Removes all element from the set + // void clear() {map.clear();} - // - // Checks if set is empty - // + // + // Checks if set is empty + // bool isEmpty() {return map.empty();} - // - // Copies another set - // - void copyFrom(const HashSet<KEY,ELEM>& set) { - if (this != &set) { + // + // Copies another set + // + void copyFrom(const HashSet<KEY,ELEM>& set) { + if (this != &set) { map.clear(); const_iterator iter = set.map.begin(), end = set.map.end(); for (; iter != end; iter++) map.insert(*iter); - } - } - // - // Unions with another set - // - void unionWith(const HashSet<KEY,ELEM>& set) { + } + } + // + // Unions with another set + // + void unionWith(const HashSet<KEY,ELEM>& set) { const_iterator iter = set.map.begin(), end = set.map.end(); for (; iter != end; iter++) { @@ -102,11 +102,11 @@ public: assert((iter2 == map.end()) || (iter2->second == iter->second)); map.insert(*iter); } - } - // - // Intersects with another set - // - void intersectWith(const HashSet<KEY,ELEM>& set) { + } + // + // Intersects with another set + // + void intersectWith(const HashSet<KEY,ELEM>& set) { // // Find elements that are in this set but are not in 'set' and // write them into 'removeList'. @@ -125,16 +125,16 @@ public: // for (uint32 i = 0; i < removeListSize; i++) map.erase(removeList[i]); - } - // - // Subtracts another set - // - void subtract(const HashSet<KEY,ELEM>& set) { + } + // + // Subtracts another set + // + void subtract(const HashSet<KEY,ELEM>& set) { const_iterator iter = set.map.begin(), end = set.map.end(); for (; iter != end; iter++) map.erase(iter->first); - } + } // // Checks if set is subset of another set // @@ -159,9 +159,9 @@ public: } return true; } - // - // Checks if set is equal to another set - // + // + // Checks if set is equal to another set + // bool isEqual(const HashSet<KEY,ELEM>& set) { return isSubset(set) && set.isSubset(*this); } diff --git vm/jitrino/src/shared/HashTable.h vm/jitrino/src/shared/HashTable.h index a380f17..4467690 100644 --- vm/jitrino/src/shared/HashTable.h +++ vm/jitrino/src/shared/HashTable.h @@ -37,116 +37,117 @@ class HashTableIterImpl; // forward decl // to get type safety // struct HashTableLink { - HashTableLink(void* k, void* e, HashTableLink* nxt) - : keyPtr(k), elemPtr(e), next(nxt) {} - HashTableLink() { - keyPtr = elemPtr = NULL; - next = NULL; - } - void* keyPtr; - void* elemPtr; - HashTableLink* next; + HashTableLink(void* k, void* e, HashTableLink* nxt) + : keyPtr(k), elemPtr(e), next(nxt) {} + HashTableLink() { + keyPtr = elemPtr = NULL; + next = NULL; + } + void* keyPtr; + void* elemPtr; + HashTableLink* next; }; class HashTableImpl { public: - HashTableImpl(MemoryManager& mm, uint32 size) + HashTableImpl(MemoryManager& mm, uint32 size) : memManager(mm), table(0), tableSize(size) { - table = new (memManager) HashTableLink*[tableSize]; - for (uint32 i=0; i<tableSize; i++) - table[i] = NULL; - } - HashTableImpl(MemoryManager& mm,uint32 size,HashTableLink** t) - : memManager(mm), table(t), tableSize(size) { - removeAll(); - } - virtual ~HashTableImpl() {} - void* lookup(void* key) const { - HashTableLink* entry = lookupEntry(key); - if (entry == NULL) - return NULL; - return entry->elemPtr; - } - void insert(void* key, void* value) { - HashTableLink* entry = lookupEntry(key); - if (entry == NULL) { - uint32 idx = getTableIndex(key); - HashTableLink* link = createLink(key,value); - link->next = table[idx]; - table[idx] = link; - } else { - entry->elemPtr = value; - } - } - void remove(void* key) { - uint32 idx = getTableIndex(key); - HashTableLink* prev = NULL; - for (HashTableLink* e = table[idx]; e != NULL; prev = e, e = e->next) { - if (equals(e->keyPtr,key)) { - if (e == table[idx]) - table[idx] = e->next; - else - prev->next = e->next; - freeLink(e); - return; - } - } - } - void removeAll() { - for (uint32 i=0; i<tableSize; i++) { - HashTableLink* link; - if ((link = table[i]) == NULL) - continue; - do { - HashTableLink* next = link->next; - freeLink(link); - link = next; - } while (link != NULL); - table[i] = NULL; - } - } + table = new (memManager) HashTableLink*[tableSize]; + for (uint32 i=0; i<tableSize; i++) + table[i] = NULL; + } + HashTableImpl(MemoryManager& mm,uint32 size,HashTableLink** t) + : memManager(mm), table(t), tableSize(size) { + removeAll(); + } + virtual ~HashTableImpl() {} + + void* lookup(void* key) const { + HashTableLink* entry = lookupEntry(key); + if (entry == NULL) + return NULL; + return entry->elemPtr; + } + void insert(void* key, void* value) { + HashTableLink* entry = lookupEntry(key); + if (entry == NULL) { + uint32 idx = getTableIndex(key); + HashTableLink* link = createLink(key,value); + link->next = table[idx]; + table[idx] = link; + } else { + entry->elemPtr = value; + } + } + void remove(void* key) { + uint32 idx = getTableIndex(key); + HashTableLink* prev = NULL; + for (HashTableLink* e = table[idx]; e != NULL; prev = e, e = e->next) { + if (equals(e->keyPtr,key)) { + if (e == table[idx]) + table[idx] = e->next; + else + prev->next = e->next; + freeLink(e); + return; + } + } + } + void removeAll() { + for (uint32 i=0; i<tableSize; i++) { + HashTableLink* link; + if ((link = table[i]) == NULL) + continue; + do { + HashTableLink* next = link->next; + freeLink(link); + link = next; + } while (link != NULL); + table[i] = NULL; + } + } protected: - virtual HashTableLink* lookupEntry(void* key) const { + virtual HashTableLink* lookupEntry(void* key) const { #ifdef _DEBUG - ((HashTableImpl *)this)->numLookup++; + ((HashTableImpl *)this)->numLookup++; #endif - for (HashTableLink* e = table[getTableIndex(key)]; e != NULL; e = e->next) { + for (HashTableLink* e = table[getTableIndex(key)]; e != NULL; e = e->next) { #ifdef _DEBUG - ((HashTableImpl *)this)->numLookupEntry++; + ((HashTableImpl *)this)->numLookupEntry++; #endif - if (equals(e->keyPtr,key)) { + if (equals(e->keyPtr,key)) { #ifdef _DEBUG - ((HashTableImpl *)this)->numFound++; + ((HashTableImpl *)this)->numFound++; #endif - return e; - } - } - return NULL; - } - uint32 getTableIndex(void* key) const { - return getHashCode(key) % tableSize; - } - virtual HashTableLink* createLink(void* key,void* elem) { - return new (memManager) HashTableLink(key,elem,NULL); - } - virtual void freeLink(HashTableLink* link) { - delete link; - } - virtual bool equals(void* key1,void* key2) const = 0; - virtual uint32 getHashCode(void* key) const = 0; + return e; + } + } + return NULL; + } + uint32 getTableIndex(void* key) const { + return getHashCode(key) % tableSize; + } + virtual HashTableLink* createLink(void* key,void* elem) { + return new (memManager) HashTableLink(key,elem,NULL); + } + virtual void freeLink(HashTableLink* link) { + delete link; + } + virtual bool equals(void* key1,void* key2) const = 0; + virtual uint32 getHashCode(void* key) const = 0; - friend class HashTableIterImpl; - // - // protected fields - // - MemoryManager& memManager; - HashTableLink** table; - uint32 tableSize; + friend class HashTableIterImpl; + // + // protected fields + // + MemoryManager& memManager; + HashTableLink** table; + uint32 tableSize; public: - static uint32 numLookup; - static uint32 numLookupEntry; - static uint32 numFound; + static uint32 numLookup; + static uint32 numLookupEntry; + static uint32 numFound; }; // @@ -154,171 +155,171 @@ public: // class HashTableIterImpl { public: - HashTableIterImpl(HashTableImpl* ht) - : hashTable(ht), nextEntry(0) { - nextElem = hashTable->table[0]; - searchNextElem(); - } - bool getNextElem(void*& key, void*& elem) { - if (nextElem != NULL) { - elem = nextElem->elemPtr; - key = nextElem->keyPtr; - nextElem = nextElem->next; - searchNextElem(); - return true; - } - return false; - } + HashTableIterImpl(HashTableImpl* ht) + : hashTable(ht), nextEntry(0) { + nextElem = hashTable->table[0]; + searchNextElem(); + } + bool getNextElem(void*& key, void*& elem) { + if (nextElem != NULL) { + elem = nextElem->elemPtr; + key = nextElem->keyPtr; + nextElem = nextElem->next; + searchNextElem(); + return true; + } + return false; + } protected: - void searchNextElem() { - if (nextElem != NULL) - return; - // skip entry table entries - for (nextEntry++; nextEntry < hashTable->tableSize; nextEntry++) { - if (hashTable->table[nextEntry] != NULL) { - nextElem = hashTable->table[nextEntry]; - break; - } - } - } + void searchNextElem() { + if (nextElem != NULL) + return; + // skip entry table entries + for (nextEntry++; nextEntry < hashTable->tableSize; nextEntry++) { + if (hashTable->table[nextEntry] != NULL) { + nextElem = hashTable->table[nextEntry]; + break; + } + } + } - HashTableImpl* hashTable; - uint32 nextEntry; - HashTableLink* nextElem; + HashTableImpl* hashTable; + uint32 nextEntry; + HashTableLink* nextElem; }; template<class KEY> struct LinkWithKey : HashTableLink { - LinkWithKey(KEY* k,void* e,HashTableLink* next) : - HashTableLink(&key,e,next), key(k) {} - LinkWithKey() : HashTableLink(&key,NULL,NULL), key() {} - KEY key; + LinkWithKey(KEY* k,void* e,HashTableLink* next) : + HashTableLink(&key,e,next), key(k) {} + LinkWithKey() : HashTableLink(&key,NULL,NULL), key() {} + KEY key; }; template <class KEY> class KeyLinkHashTable : HashTableImpl { public: - KeyLinkHashTable(MemoryManager& mm,uint32 size) : HashTableImpl(mm,size) {} - virtual ~KeyLinkHashTable() {} - void* lookup(KEY* key) const {return HashTableImpl::lookup(key);} - void insert(KEY* key,void* value) {HashTableImpl::insert(key,value);} - void remove(KEY* key) {HashTableImpl::remove(key);} - void removeAll() {HashTableImpl::removeAll();} + KeyLinkHashTable(MemoryManager& mm,uint32 size) : HashTableImpl(mm,size) {} + virtual ~KeyLinkHashTable() {} + void* lookup(KEY* key) const {return HashTableImpl::lookup(key);} + void insert(KEY* key,void* value) {HashTableImpl::insert(key,value);} + void remove(KEY* key) {HashTableImpl::remove(key);} + void removeAll() {HashTableImpl::removeAll();} protected: - virtual HashTableLink* lookupEntry(void* key) const { - return HashTableImpl::lookupEntry(key); - } - virtual HashTableLink* createLink(void* key,void* elem) { - return new (memManager) LinkWithKey<KEY>((KEY*)key,elem,NULL); - } - virtual void freeLink(HashTableLink* link) { - delete (LinkWithKey<KEY>*)link; - } - virtual bool equals(void* key1,void* key2) const { - return ((KEY*)key1)->equals((KEY*)key2); - } - virtual uint32 getHashCode(void* key) const { - return ((KEY*)key)->getHashCode(); - } + virtual HashTableLink* lookupEntry(void* key) const { + return HashTableImpl::lookupEntry(key); + } + virtual HashTableLink* createLink(void* key,void* elem) { + return new (memManager) LinkWithKey<KEY>((KEY*)key,elem,NULL); + } + virtual void freeLink(HashTableLink* link) { + delete (LinkWithKey<KEY>*)link; + } + virtual bool equals(void* key1,void* key2) const { + return ((KEY*)key1)->equals((KEY*)key2); + } + virtual uint32 getHashCode(void* key) const { + return ((KEY*)key)->getHashCode(); + } }; template<class KEY,uint32 NUM_LINKS> class FixedKeyLinkHashTable : public KeyLinkHashTable<KEY> { public: - FixedKeyLinkHashTable(MemoryManager& mm,uint32 size) - : KeyLinkHashTable<KEY>(mm,size) { - freeList = &links[0]; - for (uint32 i=0; i<NUM_LINKS-1; i++) { - // initialize - links[i].next = &links[i+1]; - } - } + FixedKeyLinkHashTable(MemoryManager& mm,uint32 size) + : KeyLinkHashTable<KEY>(mm,size) { + freeList = &links[0]; + for (uint32 i=0; i<NUM_LINKS-1; i++) { + // initialize + links[i].next = &links[i+1]; + } + } protected: - virtual HashTableLink* lookupEntry(void* key) const { - Link* link = (Link*)KeyLinkHashTable<KEY>::lookupEntry(key); - if (link == NULL) - return NULL; - ((FixedKeyLinkHashTable *)this)->moveToFront(link); - return link; - } - virtual HashTableLink* createLink(void* key,void* elem) { - Link* link; - if (freeList == NULL) { - // get last guy at the end of mru list - link = (Link*)mruList.getPrev()->getElem(); - FixedKeyLinkHashTable<KEY,NUM_LINKS>::remove(&link->key); - } - assert(freeList != NULL); - link = freeList; - freeList = (Link*)freeList->next; - link->elemPtr = elem; - link->key.copy((KEY*)key); - moveToFront(link); - return link; - } - virtual void freeLink(HashTableLink* link) { - Link* l = (Link*)link; - l->next = freeList; - freeList = l; - l->elemPtr = NULL; - l->mruLink.unlink(); - } + virtual HashTableLink* lookupEntry(void* key) const { + Link* link = (Link*)KeyLinkHashTable<KEY>::lookupEntry(key); + if (link == NULL) + return NULL; + ((FixedKeyLinkHashTable *)this)->moveToFront(link); + return link; + } + virtual HashTableLink* createLink(void* key,void* elem) { + Link* link; + if (freeList == NULL) { + // get last guy at the end of mru list + link = (Link*)mruList.getPrev()->getElem(); + FixedKeyLinkHashTable<KEY,NUM_LINKS>::remove(&link->key); + } + assert(freeList != NULL); + link = freeList; + freeList = (Link*)freeList->next; + link->elemPtr = elem; + link->key.copy((KEY*)key); + moveToFront(link); + return link; + } + virtual void freeLink(HashTableLink* link) { + Link* l = (Link*)link; + l->next = freeList; + freeList = l; + l->elemPtr = NULL; + l->mruLink.unlink(); + } private: - struct Link : LinkWithKey<KEY> { - Link() : LinkWithKey<KEY>() { - mruLink.setElem(this); - } - DlinkElem mruLink; - }; - void moveToFront(Link* link) { - link->mruLink.unlink(); - link->mruLink.insertAfter(&mruList); - } - Link links[NUM_LINKS]; - Link* freeList; - DlinkElem mruList; + struct Link : LinkWithKey<KEY> { + Link() : LinkWithKey<KEY>() { + mruLink.setElem(this); + } + DlinkElem mruLink; + }; + void moveToFront(Link* link) { + link->mruLink.unlink(); + link->mruLink.insertAfter(&mruList); + } + Link links[NUM_LINKS]; + Link* freeList; + DlinkElem mruList; }; struct DoublePtrKey { - DoublePtrKey(DoublePtrKey* key) { - copy(key); - } - DoublePtrKey(void* k1, void*k2) { - key1 = k1; key2 = k2; - } - void copy(const DoublePtrKey* key) { - key1 = key->key1; key2 = key->key2; - } - bool equals(const DoublePtrKey* key) const { - return (key1 == key->key1 && key2 == key->key2); - } - uint32 getHashCode() const { + DoublePtrKey(DoublePtrKey* key) { + copy(key); + } + DoublePtrKey(void* k1, void*k2) { + key1 = k1; key2 = k2; + } + void copy(const DoublePtrKey* key) { + key1 = key->key1; key2 = key->key2; + } + bool equals(const DoublePtrKey* key) const { + return (key1 == key->key1 && key2 == key->key2); + } + uint32 getHashCode() const { return ((uint32)(((POINTER_SIZE_INT)key1)>>3) ^ (uint32)(((POINTER_SIZE_INT)key2)>>3)); - } - void* key1; - void* key2; + } + void* key1; + void* key2; }; class DoubleKeyHashTable : KeyLinkHashTable<DoublePtrKey> { public: - DoubleKeyHashTable(MemoryManager& mm,uint32 size) - : KeyLinkHashTable<DoublePtrKey>(mm,size) {} - virtual ~DoubleKeyHashTable() {} - void* lookup(void* key1,void* key2) const { - DoublePtrKey key(key1,key2); - return KeyLinkHashTable<DoublePtrKey>::lookup(&key); - } - void insert(void* key1,void* key2,void* value) { - DoublePtrKey key(key1,key2); - KeyLinkHashTable<DoublePtrKey>::insert(&key,value); - } - void remove(void* key1,void* key2) { - DoublePtrKey key(key1,key2); - KeyLinkHashTable<DoublePtrKey>::remove(&key); - } - void removeAll() { - KeyLinkHashTable<DoublePtrKey>::removeAll(); - } + DoubleKeyHashTable(MemoryManager& mm,uint32 size) + : KeyLinkHashTable<DoublePtrKey>(mm,size) {} + virtual ~DoubleKeyHashTable() {} + void* lookup(void* key1,void* key2) const { + DoublePtrKey key(key1,key2); + return KeyLinkHashTable<DoublePtrKey>::lookup(&key); + } + void insert(void* key1,void* key2,void* value) { + DoublePtrKey key(key1,key2); + KeyLinkHashTable<DoublePtrKey>::insert(&key,value); + } + void remove(void* key1,void* key2) { + DoublePtrKey key(key1,key2); + KeyLinkHashTable<DoublePtrKey>::remove(&key); + } + void removeAll() { + KeyLinkHashTable<DoublePtrKey>::removeAll(); + } }; // @@ -327,63 +328,63 @@ public: template <class KEY, class VALUE> class HashTable : public HashTableImpl { public: - HashTable(MemoryManager& mm,uint32 sz) : HashTableImpl(mm,sz) {} - VALUE* lookup(KEY* key) const {return (VALUE*)HashTableImpl::lookup(key);} - void insert(KEY* key, VALUE* value) {HashTableImpl::insert(key,value);} - void remove(KEY* key) {HashTableImpl::remove(key);} + HashTable(MemoryManager& mm,uint32 sz) : HashTableImpl(mm,sz) {} + VALUE* lookup(KEY* key) const {return (VALUE*)HashTableImpl::lookup(key);} + void insert(KEY* key, VALUE* value) {HashTableImpl::insert(key,value);} + void remove(KEY* key) {HashTableImpl::remove(key);} protected: - virtual bool keyEquals(KEY* key1, KEY* key2) const = 0; - virtual uint32 getKeyHashCode(KEY* key) const = 0; + virtual bool keyEquals(KEY* key1, KEY* key2) const = 0; + virtual uint32 getKeyHashCode(KEY* key) const = 0; private: - bool equals(void* key1, void* key2) const {return keyEquals((KEY*)key1,(KEY*)key2);} - uint32 getHashCode(void* key) const {return getKeyHashCode((KEY*)key);} + bool equals(void* key1, void* key2) const {return keyEquals((KEY*)key1,(KEY*)key2);} + uint32 getHashCode(void* key) const {return getKeyHashCode((KEY*)key);} }; template <class KEY, class VALUE> class ConstHashTable : public HashTableImpl { public: - ConstHashTable(MemoryManager& mm,uint32 sz) : HashTableImpl(mm,sz) {} - const VALUE* lookup(const KEY* key) const {return (const VALUE*)HashTableImpl::lookup((void *)key);} - void insert(const KEY* key, const VALUE* value) {HashTableImpl::insert((void *)key,(void *)value);} - void remove(const KEY* key) {HashTableImpl::remove((void *)key);} + ConstHashTable(MemoryManager& mm,uint32 sz) : HashTableImpl(mm,sz) {} + const VALUE* lookup(const KEY* key) const {return (const VALUE*)HashTableImpl::lookup((void *)key);} + void insert(const KEY* key, const VALUE* value) {HashTableImpl::insert((void *)key,(void *)value);} + void remove(const KEY* key) {HashTableImpl::remove((void *)key);} protected: - virtual bool keyEquals(const KEY* key1, const KEY* key2) const = 0; - virtual uint32 getKeyHashCode(const KEY* key) const = 0; + virtual bool keyEquals(const KEY* key1, const KEY* key2) const = 0; + virtual uint32 getKeyHashCode(const KEY* key) const = 0; private: - bool equals(void* key1, void* key2) const {return keyEquals((const KEY*)key1,(const KEY*)key2);} - uint32 getHashCode(void* key) const {return getKeyHashCode((const KEY*)key);} + bool equals(void* key1, void* key2) const {return keyEquals((const KEY*)key1,(const KEY*)key2);} + uint32 getHashCode(void* key) const {return getKeyHashCode((const KEY*)key);} }; template <class ELEM_TYPE> class PtrHashTable : public HashTable<void,ELEM_TYPE> { public: - PtrHashTable(MemoryManager& mm,uint32 size) : HashTable<void,ELEM_TYPE>(mm,size) {} + PtrHashTable(MemoryManager& mm,uint32 size) : HashTable<void,ELEM_TYPE>(mm,size) {} protected: - virtual bool keyEquals(void* key1,void* key2) const { - return key1 == key2; - } - virtual uint32 getKeyHashCode(void* key) const { - // return hash of address bits - return ((uint32)(((POINTER_SIZE_INT)key) >> sizeof(void*))); - } + virtual bool keyEquals(void* key1,void* key2) const { + return key1 == key2; + } + virtual uint32 getKeyHashCode(void* key) const { + // return hash of address bits + return ((uint32)(((POINTER_SIZE_INT)key) >> sizeof(void*))); + } }; template <class KEY, class ELEM_TYPE> class HashTableIter : public HashTableIterImpl { public: - HashTableIter(HashTable<KEY,ELEM_TYPE>* ht) : HashTableIterImpl(ht) {} - bool getNextElem(KEY*& key, ELEM_TYPE*& elem) { - return HashTableIterImpl::getNextElem((void*&)key,(void*&)elem); - } + HashTableIter(HashTable<KEY,ELEM_TYPE>* ht) : HashTableIterImpl(ht) {} + bool getNextElem(KEY*& key, ELEM_TYPE*& elem) { + return HashTableIterImpl::getNextElem((void*&)key,(void*&)elem); + } }; template <class KEY, class ELEM_TYPE> class ConstHashTableIter : public HashTableIterImpl { public: - ConstHashTableIter(ConstHashTable<KEY,ELEM_TYPE>* ht) : HashTableIterImpl(ht) {} - bool getNextElem(const KEY*& key, const ELEM_TYPE*& elem) { - return HashTableIterImpl::getNextElem((void*&)key,(void*&)elem); - } + ConstHashTableIter(ConstHashTable<KEY,ELEM_TYPE>* ht) : HashTableIterImpl(ht) {} + bool getNextElem(const KEY*& key, const ELEM_TYPE*& elem) { + return HashTableIterImpl::getNextElem((void*&)key,(void*&)elem); + } }; } //namespace Jitrino diff --git vm/jitrino/src/shared/InlineInfo.h vm/jitrino/src/shared/InlineInfo.h index 02078d2..1c00cbd 100644 --- vm/jitrino/src/shared/InlineInfo.h +++ vm/jitrino/src/shared/InlineInfo.h @@ -30,11 +30,15 @@ #include "MemoryManager.h" #include "Stl.h" #include "Log.h" #include "Type.h" +#include "CGSupport.h" namespace Jitrino { +class Inst; + class InlineInfo { - typedef StlList<MethodDesc*> MethodDescList; + typedef ::std::pair<MethodDesc*, uint32> InlinePair; + typedef StlList<InlinePair*> InlinePairList; public: InlineInfo(MemoryManager& mm) : @@ -47,10 +51,10 @@ public: { if ( ii.inlineChain ) { init(); - MethodDescList::const_reverse_iterator it(ii.inlineChain->end()); - MethodDescList::const_reverse_iterator last(ii.inlineChain->begin()); + InlinePairList::const_reverse_iterator it(ii.inlineChain->end()); + InlinePairList::const_reverse_iterator last(ii.inlineChain->begin()); for (; it != last; ++it) { - MethodDesc* md = (*it); + InlinePair* md = (*it); inlineChain->push_front(md); } } @@ -60,9 +64,9 @@ public: { if ( ii.inlineChain ) { init(); - MethodDescList::const_iterator it = ii.inlineChain->begin(); + InlinePairList::const_iterator it = ii.inlineChain->begin(); for (; it != ii.inlineChain->end(); ++it) { - MethodDesc* md = (*it); + InlinePair* md = (*it); addLevelFast(md); } }else{ @@ -74,27 +78,31 @@ public: // adds a new level to the chain of inlined methods // convention is to add in 'parent-first' order // - void addLevel(MethodDesc* md) + void addLevel(MethodDesc* md, uint32 bcOff) { init(); - addLevelFast(md); + InlinePair* inlPair = new(memMgr) InlinePair(md, bcOff); + addLevelFast(inlPair); } - void prependLevel(MethodDesc* md) + void prependLevel(MethodDesc* md, uint32 bcOff) { init(); - inlineChain->push_front(md); + InlinePair* inlPair = new(memMgr) InlinePair(md, bcOff); + inlineChain->push_front(inlPair); } - void printLevels(CategoryStream<LogIR>& os) const + void printLevels(std::ostream& os) const { if ( isEmpty() ) { return; } - MethodDescList::const_iterator it = inlineChain->begin(); + InlinePairList::const_iterator it = inlineChain->begin(); for (; it != inlineChain->end(); ++it) { - MethodDesc* md = (*it); - os << md->getParentType()->getName() << "." << md->getName() << " "; + InlinePair* md = (*it); + os << ((MethodDesc*)md->first)->getParentType()->getName() << "." + << ((MethodDesc*)md->first)->getName() << " " << " bcOff " + << md->second << " "; } os << ::std::endl; } @@ -109,14 +117,16 @@ protected: void init() { if ( !isInitialized() ) { - inlineChain = new (memMgr) MethodDescList(memMgr); + inlineChain = new (memMgr) InlinePairList(memMgr); } } - void addLevelFast(MethodDesc* md) { inlineChain->push_back(md); } + void addLevelFast(InlinePair* inlPair) { + inlineChain->push_back(inlPair); + } private: MemoryManager& memMgr; - MethodDescList* inlineChain; + InlinePairList* inlineChain; }; // @@ -133,18 +143,15 @@ public: void setParentBuilder(InlineInfoBuilder* builder) { parent = builder; } - void buildInlineInfo(InlineInfo* ii) // ii must be non-NULL - { - if ( parent ) { - parent->buildInlineInfo(ii); - } - addCurrentLevel(ii); - } - void buildInlineInfoForInst(Inst* inst, MethodDesc* target_md = NULL); -private: - - virtual void addCurrentLevel(InlineInfo* ii) = 0; // ii must be non-NULL + void buildInlineInfo(InlineInfo* ii, uint32 offset); // ii must be non-NULL + uint32 buildInlineInfoForInst(Inst* inst, uint32 offset, MethodDesc* target_md = NULL); + virtual uint32 getCurrentBcOffset() = 0; + virtual MethodDesc* getCurrentMd() = 0; +protected: InlineInfoBuilder* parent; +private: + virtual void addCurrentLevel(InlineInfo* ii, uint32 offset) = 0; // ii must be non-NULL + virtual void setCurrentBcOffset(uint32 offSet) = 0; }; } //namespace Jitrino diff --git vm/jitrino/src/shared/Interval.cpp vm/jitrino/src/shared/Interval.cpp new file mode 100644 index 0000000..ac68abb --- /dev/null +++ vm/jitrino/src/shared/Interval.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Nikolay A. Sidelnikov + * @version $Revision$ + * + */ + +#include "Interval.h" +namespace Jitrino +{ + +bool Interval::startOrExtend (size_t instIdx) +{ + Span * last = spans.size() > 0 ? &spans.back() : NULL; + + if ( last != NULL && instIdx == last->beg ){ // open the last span + last->beg=0; + return true; + } + if (last == NULL || last->beg != 0) + {// insert open span + Span tmp={ 0, instIdx }; + spans.push_back(tmp); + return true; + } +// continue the same open use + return false; +} + +void Interval::stop (size_t instIdx) +{ + Span * last=spans.size()>0?&spans.back():NULL; + if ( last==NULL || ( last->beg != 0 && last->beg !=instIdx ) ){ // closed + Span tmp={ instIdx, instIdx }; // probably dead def, add the shortest possible span + spans.push_back(tmp); + }else{ // last!=NULL && ( last->beg == 0 || last->beg ==instIdx ) + last->beg=instIdx; + } +} + +void Interval::finish(bool sort) +{ + if (sort) + ::std::sort(spans.begin(), spans.end(), Span::less); + if (spans.size() != 0){ + beg = spans.front().beg; + end = spans.back().end; + assert(beg <= end); + } +} + + +// Determinate if two operands conflict (i.e. can be assigned to the same register) +// +bool Interval::conflict (const Interval * r, int& adj) const +{ + int d; + if (beg <= r->end && r->beg <= end) + { + Spans::const_iterator + i = spans.begin(), iend = spans.end(), + k = r->spans.begin(), kend = r->spans.end(); + + while (i != iend && k != kend) + { + if ((d = i->end - k->beg) < 0) + { + if (d == -1) + ++adj; + ++i; + } + else if ((d = i->beg - k->end) > 0) + { + if (d == 1) + ++adj; + ++k; + } + else + return true; + } + } + + return false; +} + + +void Interval::unionWith(const Interval * r) +{ + for (Spans::const_iterator it = r->spans.begin(); it != r->spans.end(); it++) + spans.push_back(*it); + finish(); +} + + +::std::ostream& operator << (::std::ostream& os, const Interval::Span& x) +{ + os << " [" << x.beg << "," << x.end << "]"; + return os; +} + +::std::ostream& operator << (::std::ostream& os, const Interval::Spans& x) +{ + for (Interval::Spans::const_iterator i = x.begin(); i != x.end(); ++i) + os << *i; + return os; +} + +::std::ostream& operator << (::std::ostream& os, const Interval& x) +{ + os << "beg: " << x.beg << " end: " << x.end << " spans: " << x.spans; + return os; +} +} + diff --git vm/jitrino/src/shared/Interval.h vm/jitrino/src/shared/Interval.h new file mode 100644 index 0000000..e6d2c26 --- /dev/null +++ vm/jitrino/src/shared/Interval.h @@ -0,0 +1,77 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Nikolay A. Sidelnikov + * @version $Revision$ + * + */ + + +#ifndef _INTERVAL_H_ +#define _INTERVAL_H_ + +#include "Stl.h" +#include <stdlib.h> +#include <fstream> +#include <string.h> + +namespace Jitrino +{ + +// TODO: Shared with bin-pack reg allocator (Ia32RegAlloc2) => +// Move to separate shared/Interval.* files or create Ia32RegAlloc2 h with these definitions +// change Ia32RegAlloc2 as necessary to use shared Interval + +struct Interval +{ + struct Span + { + size_t beg, end; + static bool less (const Span& x, const Span& y) + { + return x.beg < y.end; // to order properly spans like [124,130] [124,124] + } + }; + + typedef StlVector<Span> Spans; + Spans spans; // liveness data in form of list of intervals + size_t beg, end; // start point of first interval and end point of last interval + + + Interval(MemoryManager& mm) + :spans(mm), beg(0), end(0){} + + bool startOrExtend (size_t instIdx); + void stop(size_t instIdx); + void finish(bool sort = true); + void unionWith(const Interval * r); + bool conflict (const Interval * r, int& adj) const; + +}; + +::std::ostream& operator << (::std::ostream& os, const Interval::Span& x); + +::std::ostream& operator << (::std::ostream& os, const Interval::Spans& x); + +::std::ostream& operator << (::std::ostream& os, const Interval& x); + +// <= TODO: Shared with bin-pack reg allocator (Ia32RegAlloc2) +// Move to separate shared/Interval.* files or create Ia32RegAlloc2 h with these definitions +} + +#endif + diff --git vm/jitrino/src/shared/List.h vm/jitrino/src/shared/List.h index 017635f..0b00820 100644 --- vm/jitrino/src/shared/List.h +++ vm/jitrino/src/shared/List.h @@ -28,30 +28,30 @@ #include <assert.h> template <class T> class List { public: - List(T* i, List* t) : elem(i), tl(t) {} - List* getNext() {return tl;} - T* getElem() {return elem;} + List(T* i, List* t) : elem(i), tl(t) {} + List* getNext() {return tl;} + T* getElem() {return elem;} private: - T* elem; - List* tl; + T* elem; + List* tl; }; template <class T> class ListIter { public: - ListIter(List<T>* hd) {next = hd;} - bool hasNext() {return next != NULL;} - T* getNext() { - if (hasNext() == false) { - assert(0); - return NULL; - } - T* elem = next->getElem(); - next = next->getNext(); - return elem; - } + ListIter(List<T>* hd) {next = hd;} + bool hasNext() {return next != NULL;} + T* getNext() { + if (hasNext() == false) { + assert(0); + return NULL; + } + T* elem = next->getElem(); + next = next->getNext(); + return elem; + } private: - List<T>* next; + List<T>* next; }; #endif // _LIST_H_ diff --git vm/jitrino/src/shared/LoopTree.cpp vm/jitrino/src/shared/LoopTree.cpp new file mode 100644 index 0000000..e38854d --- /dev/null +++ vm/jitrino/src/shared/LoopTree.cpp @@ -0,0 +1,345 @@ +/* +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @author Intel, Mikhail Y. Fursov +* @version $Revision$ +* +*/ + +#include "LoopTree.h" +#include "Dominator.h" + +namespace Jitrino { + +LoopTree::LoopTree(MemoryManager& _mm, ControlFlowGraph* f, EdgeCoalescerCallback* _coalesceCallback) +: mm(_mm), fg(f), traversalNum(0), headerMap(_mm), headers(_mm), coalesceCallback(_coalesceCallback), normalized(false) +{ + // create a root loop containing all loops within the method + root = new (mm) LoopNode(mm, this, NULL); +} + +// +// we find loop headers and then find loop edges because coalesceLoops +// introduces new blocks and edges into the flow graph. dom does not +// dominator information for the newly created blocks. +// +void LoopTree::findLoopHeaders(Nodes& headers) { // out + DominatorTree* dom = fg->getDominatorTree(); + const Nodes& nodes = fg->getNodes(); + Nodes::const_iterator niter; + for(niter = nodes.begin(); niter != nodes.end(); ++niter) { + Node* n = *niter; + // if n dominates its predecessor, then the edge is an loop back edge + const Edges& edges = n->getInEdges(); + Edges::const_iterator eiter; + for(eiter = edges.begin(); eiter != edges.end(); ++eiter) { + Node* pred = (*eiter)->getSourceNode(); + if (dom->dominates(n, pred)) { + headers.push_back(n); + break; + } + } + } +} + +// +// check each header to see if multiple loops share the head +// if found, coalesce those loop edges. +void LoopTree::findAndCoalesceLoopEdges(const Nodes& headers) { + DominatorTree* dom = fg->getDominatorTree(); + assert(dom->isValid()); + MemoryManager mm(1024, "LoopTree::findAndCoalesceEdges"); + Edges entryEdges(mm); + Edges loopEdges(mm); + for (Nodes::const_iterator it = headers.begin(), end = headers.end(); it!=end; ++it) { + Node* head = *it; + entryEdges.clear(); + loopEdges.clear(); + + // if n dominates its predecessor, then the edge is an loop back edge + const Edges& inEdges = head->getInEdges(); + for(Edges::const_iterator eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { + Node* pred = (*eiter)->getSourceNode(); + if (dom->dominates(head, pred)) { + loopEdges.push_back(*eiter); + } else { + entryEdges.push_back(*eiter); + } + } + assert(!entryEdges.empty() && !loopEdges.empty()); + + if (head->isBlockNode()) { + // Create unique preheader if + // a) more than one entry edge or + // b) the one entry edge is a critical edge + if ((entryEdges.size() > 1) || (entryEdges.front()->getSourceNode()->getOutDegree() > 1)) { + coalesceEdges(entryEdges); + } + + // Create unique tail if + // a) more than one back edge or + // b) the one back edge is a critical edge + if ((loopEdges.size() > 1) || loopEdges.front()->getSourceNode()->getOutDegree() > 1) { + Edge* backEdge = coalesceEdges(loopEdges); + loopEdges.push_back(backEdge); + } + } + } +} + + +// +// header map is ready to use for parent loops +// +LoopNode* LoopTree::findEnclosingLoop(Node* header) { + LoopNode* loop = headerMap[header->getDfNum()]; + return loop != NULL ? loop : (LoopNode*)root; +} + + +class CompareDFN { +public: + bool operator() (Node* h1, Node* h2) { return h1->getDfNum() < h2->getDfNum(); } +}; + +// +// If loop A is contained in loop B, then B's header must dominate +// A's header. We sort loop edges based on headers' dfn so as to +// construct loops from the outermost to the innermost +// +void LoopTree::formLoopHierarchy(Nodes& headers) { + + // sort headers based on their depth first number + std::sort(headers.begin(), headers.end(), CompareDFN()); + + assert(fg->hasValidOrdering()); + + // create loops in df num order + for (Nodes::const_iterator it = headers.begin(), end = headers.end(); it!=end; ++it) { + Node* header = *it; + createLoop(header); + } +} + +void LoopNode::clear() { + assert(this == loopTree->root); + child = NULL; +} + +void LoopNode::backwardMarkNode(Node* node) { + if(node->getTraversalNum() > loopTree->fg->getTraversalNum()) { + return; + } + + markNode(node); + + const Edges& inEdges = node->getInEdges(); + for(Edges::const_iterator eiter = inEdges.begin(); eiter != inEdges.end(); ++eiter) { + Edge* e = *eiter; + backwardMarkNode(e->getSourceNode()); + } +} + +void LoopNode::markNode(Node* node) { + assert(node->getTraversalNum() == loopTree->fg->getTraversalNum()); + loopTree->headerMap[node->getDfNum()] = this; + nodesInLoop.push_back(node); + node->setTraversalNum(node->getTraversalNum()+1); +} + +// +// traverse graph backward starting from tail until header is reached +// +void LoopNode::markNodesOfLoop() { + DominatorTree* dom = loopTree->fg->getDominatorTree(); + assert(dom->isValid()); + + markNode(header); + // starting backward traversal + const Edges& inEdges = header->getInEdges(); + for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) { + Edge* edge = *ite; + Node* tail = edge->getSourceNode(); + if (dom->dominates(header, tail)) { + backwardMarkNode(tail); + } + } + uint32 fgTraversalNum = loopTree->fg->getTraversalNum(); + for (Nodes::const_iterator it = nodesInLoop.begin(), end = nodesInLoop.end(); it!=end; ++it) { + Node* node = *it; + assert(node->getTraversalNum() == fgTraversalNum + 1); + node->setTraversalNum(fgTraversalNum); + } +} + + +void LoopTree::createLoop(Node* header) { + // walk up the hierarchy to find which loop contains it + LoopNode* loop = new (mm) LoopNode(mm, this, header); + LoopNode* parent = findEnclosingLoop(header); + parent->addChild(loop); + loop->markNodesOfLoop(); +} + + + +// create a new <block> that sinks all edges +// create a new edge <block>-><header>. +// return the newly created block. +// +Edge* LoopTree::coalesceEdges(Edges& edges) { + Node* header = edges.back()->getTargetNode(); + + // create a new block and re-target all loop edges to the block + Node* block = fg->createNode(header->getKind()); + + if (coalesceCallback!=NULL) { + coalesceCallback->coalesce(header, block, edges.size()); + } + //retarget all edges + for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) { + Edge* e = *ite; + assert(e->getTargetNode() == header); // must share the same header + + fg->replaceEdgeTarget(e, block); + block->setExecCount(block->getExecCount()+e->getSourceNode()->getExecCount()*e->getEdgeProb()); + } + + // create factored edge <block,header> + Edge* edge = fg->addEdge(block,header); + edge->setEdgeProb(1.0); + return edge; +} + + + +void LoopTree::rebuild(bool doNormalization) { + if (isValid() && (!doNormalization || normalized)) { + return; + } + normalized = false; + + DominatorTree* dom = fg->getDominatorTree(); + if ( dom==NULL || !dom->isValid()) { + DominatorBuilder db; + dom = db.computeDominators(mm, fg, false, false); + fg->setDominatorTree(dom); + } + + headers.clear(); + findLoopHeaders(headers); + + if (doNormalization) { + findAndCoalesceLoopEdges(headers); + normalized = true; + if (!dom->isValid()) { + DominatorBuilder db; + dom = db.computeDominators(fg->getMemoryManager(), fg); + fg->setDominatorTree(dom); + } + } + + if (isValid()) { + return; // double check after normalization + } + + //cleanup + headerMap.clear(); + ((LoopNode*)root)->clear(); + + uint32 numBlocks = fg->getNodeCount(); + headerMap.resize(numBlocks); + + formLoopHierarchy(headers); + + computeOrder(); // compute pre/post nums for loop nodes + + traversalNum = fg->getTraversalNum(); +} + +bool LoopTree::isLoopHeader(const Node* node) const { + assert(isValid()); + LoopNode* loop = headerMap[node->getDfNum()]; + return loop!=NULL && loop->header == node; +} + + +LoopNode* LoopTree::getLoopNode(const Node* node, bool containingLoop) const { + assert(isValid()); + LoopNode* loop = headerMap[node->getDfNum()]; + if (loop == NULL) { + return NULL; + } + LoopNode* result = containingLoop && node == loop->getHeader() ? (LoopNode*)loop->getParent() : loop; + return result; +} + + +Node* LoopTree::getLoopHeader(const Node* node, bool containingLoop) const { + LoopNode* headerLoop = getLoopNode(node, containingLoop); + Node* header = headerLoop == NULL ? NULL : headerLoop->getHeader(); + return header; +} + +uint32 LoopTree::getLoopDepth(const Node* node) const { + LoopNode* header = getLoopNode(node, false); + return header == 0 ? 0 : header->getDepth(); +} + +bool LoopTree::isLoopExit(const Edge* edge) const { + LoopNode* srcLoop = getLoopNode(edge->getSourceNode(), false); + if (srcLoop == NULL) { //source not in loop + return false; + } + LoopNode* dstLoop = getLoopNode(edge->getTargetNode(), false); + return dstLoop == NULL || (dstLoop!=srcLoop && dstLoop->getDepth() <= srcLoop->getDepth()); +} + +bool LoopTree::isBackEdge(const Edge* edge) const { + assert(isValid()); + return fg->getDominatorTree()->dominates(edge->getTargetNode(), edge->getSourceNode()); +} + + +bool LoopNode::inLoop(const Node* node) const { + assert(this!=loopTree->getRoot()); + assert(loopTree->isValid()); + LoopNode* nodeLoop = loopTree->headerMap[node->getDfNum()]; + bool result = nodeLoop!=NULL && (nodeLoop == this || loopTree->isAncestor(this, nodeLoop)); + return result; +} + +Node* LoopNode::getHeader() const { + assert(loopTree->isValid()); + return header; +} + +const Nodes& LoopNode::getNodesInLoop() const { + assert(loopTree->isValid()); + return nodesInLoop; +} + +bool LoopNode::isLoopExit(const Edge* e) const { + return inLoop(e->getSourceNode()) && !inLoop(e->getTargetNode()); +} + +bool LoopNode::isBackEdge(const Edge* e) const { + assert(loopTree->isValid()); + return e->getTargetNode() == header && loopTree->isBackEdge(e); +} + +}//namespace diff --git vm/jitrino/src/shared/LoopTree.h vm/jitrino/src/shared/LoopTree.h new file mode 100644 index 0000000..e83493c --- /dev/null +++ vm/jitrino/src/shared/LoopTree.h @@ -0,0 +1,137 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Intel, Mikhail Y. Fursov + * @version $Revision$ + * + */ + +#ifndef _LOOP_TREE_H_ +#define _LOOP_TREE_H_ + +#include "Tree.h" +#include "Stl.h" +#include "MemoryManager.h" +#include "ControlFlowGraph.h" + +namespace Jitrino { + +class LoopTree; +class EdgeCoalescerCallback { +public: + virtual ~EdgeCoalescerCallback(){}; + virtual void coalesce(Node* header, Node* newPreHeader, uint32 numEdges) = 0; +}; + +class LoopNode : public TreeNode { +public: + LoopNode* getChild() const {return (LoopNode*)child;} + LoopNode* getSiblings() const {return (LoopNode*)siblings;} + LoopNode* getParent() const {return (LoopNode*)parent;} + + bool inLoop(const Node* node) const; + + Node* getHeader() const; + + // return all nodes in loop; + const Nodes& getNodesInLoop() const; + + // return true is this edge is a loop exit from this loop. + bool isLoopExit(const Edge* e) const; + + // return true is this edge is a back edge for this loop. + bool isBackEdge(const Edge* e) const; + +private: + friend class LoopTree; + + LoopNode(MemoryManager& mm, LoopTree* lt, Node* hd) : loopTree(lt), header(hd), nodesInLoop(mm){} + + void markNodesOfLoop(); + void markNode(Node* node); + void backwardMarkNode(Node* currentTail); + void clear(); + + LoopTree* loopTree; + Node* header; // loop entry point + Nodes nodesInLoop; +}; + +typedef StlVector<LoopNode*> LoopNodes; + +class LoopTree : public Tree { + friend class LoopNode; +public: + LoopTree(MemoryManager& mm, ControlFlowGraph* f, EdgeCoalescerCallback* coalesceCallback = NULL); + + // rebuilds loop tree if needed. + void rebuild(bool doNormalization); + + bool hasLoops() const { assert(isValid()); return ((LoopNode*)root)->getChild()!=NULL;} //root node is artificial + + bool isLoopHeader(const Node* node) const; + + Node* getLoopHeader(const Node* node, bool containingLoop = true) const; + + LoopNode* getLoopNode(const Node* node, bool containingLoop) const; + + uint32 getLoopDepth(const Node* node) const; + + // true if edge is exit from any loop + bool isLoopExit(const Edge* e) const; + + bool isBackEdge(const Edge* e) const; + + bool isValid() const { return traversalNum > fg->getModificationTraversalNum(); } + + uint32 getTraversalNum() { return traversalNum; } + + EdgeCoalescerCallback* getCoalesceCallback() const {return coalesceCallback;} + void setCoalesceCallback(EdgeCoalescerCallback* callback) {coalesceCallback = callback;} + + bool isNormalized() const { return normalized;} + + uint32 getMaxLoopDepth() const {return getHeight()-1;} +private: + + void findLoopHeaders(Nodes& headers); + void findAndCoalesceLoopEdges(const Nodes& headers); + Edge* coalesceEdges(Edges& edges); + void formLoopHierarchy(Nodes& headers); + LoopNode* findEnclosingLoop(Node* header); + void createLoop(Node* header); + + MemoryManager& mm; + ControlFlowGraph* fg; + uint32 traversalNum; + + //nodes by dfn + // loop header by node->dfn. + // Note: if node is loop header this map contains LoopNode for this, but not for containig header + LoopNodes headerMap; + // all loop headers. Used for private needs during loop-tree computation + Nodes headers; + EdgeCoalescerCallback* coalesceCallback; + //indicates that loop tree was normalized during previous rebuild + bool normalized; + +}; + +} + +#endif + diff --git vm/jitrino/src/shared/MapSet.h vm/jitrino/src/shared/MapSet.h index 598682c..72078cd 100644 --- vm/jitrino/src/shared/MapSet.h +++ vm/jitrino/src/shared/MapSet.h @@ -38,70 +38,70 @@ namespace Jitrino { template<class KEY, class ELEM> class MapSet : public StlMap<KEY, ELEM> { public: - typedef StlMap<KEY,ELEM> Map; + typedef StlMap<KEY,ELEM> Map; #ifdef PLATFORM_POSIX typedef typename Map::const_iterator const_iterator; typedef typename Map::iterator iterator; typedef typename Map::value_type value_type; #endif - // - // Constructor - // + // + // Constructor + // MapSet(MemoryManager& memManager) : Map(memManager) { } - // - // Copy constructor - // - MapSet(MemoryManager& memManager, const MapSet<KEY,ELEM> &set) + // + // Copy constructor + // + MapSet(MemoryManager& memManager, const MapSet<KEY,ELEM> &set) : Map(memManager) { const_iterator iter = set.begin(), end = set.end(); - for (; iter != end; iter++) { - value_type val = *iter; + for (; iter != end; iter++) { + value_type val = *iter; insert(val.first, val.second); - } - } + } + } // // Returns number of elements in the set // uint32 getSize() const {return (uint32) size();} - // - // Returns true if set contains the element, false otherwise - // - bool contains(KEY key) const { + // + // Returns true if set contains the element, false otherwise + // + bool contains(KEY key) const { return find(key) != end(); - } - // - // Inserts element into the set - // + } + // + // Inserts element into the set + // void insert(KEY key, ELEM elem) {(*this)[key] = elem;} // // Removes element from the set // void remove(KEY key) {erase(key);} - + - // - // Checks if set is empty - // + // + // Checks if set is empty + // bool isEmpty() {return empty();} - // - // Copies another set - // - void copyFrom(const MapSet<KEY,ELEM>& set) { - if (this != &set) { + // + // Copies another set + // + void copyFrom(const MapSet<KEY,ELEM>& set) { + if (this != &set) { clear(); const_iterator iter = set.begin(), end = set.end(); for (; iter != end; iter++) insert(iter->first, iter->second); - } - } - // - // Unions with another set - // - void unionWith(const MapSet<KEY,ELEM>& set) { + } + } + // + // Unions with another set + // + void unionWith(const MapSet<KEY,ELEM>& set) { const_iterator iter = set.begin(), setend = set.end(); for (; iter != setend; iter++) { @@ -110,11 +110,11 @@ #endif if (iter2 == end()) insert(iter->first, iter->second); } - } - // - // Intersects with another set - // - void intersectWith(const MapSet<KEY,ELEM>& set) { + } + // + // Intersects with another set + // + void intersectWith(const MapSet<KEY,ELEM>& set) { // // Find elements that are in this set bat are not in 'set' and // write them into 'removeList'. @@ -133,16 +133,16 @@ #endif // for (uint32 i = 0; i < removeListSize; i++) erase(removeList[i]); - } - // - // Subtracts another set - // - void subtract(const MapSet<KEY,ELEM>& set) { + } + // + // Subtracts another set + // + void subtract(const MapSet<KEY,ELEM>& set) { const_iterator iter = set.begin(), setend = set.end(); for (; iter != setend; iter++) erase(iter->first); - } + } // // Checks if the set is subset of another set // @@ -166,9 +166,9 @@ #endif } return true; } - // - // Checks if the set is equal to another set - // + // + // Checks if the set is equal to another set + // bool isEqual(const MapSet<KEY,ELEM>& set) { return isSubset(set) && set.isSubset(*this); } diff --git vm/jitrino/src/shared/MemoryAttribute.h vm/jitrino/src/shared/MemoryAttribute.h index 2ada301..cfcf807 100644 --- vm/jitrino/src/shared/MemoryAttribute.h +++ vm/jitrino/src/shared/MemoryAttribute.h @@ -202,7 +202,7 @@ public: // // Prints tag // - void print(::std::ostream& os) const { + void print(::std::ostream& os) const { assert(info[tag].tag == tag); os << info[tag].name; printId(os); @@ -240,7 +240,7 @@ public: } bool hasUnknownId() const {return id.all == UnknownMemoryContextId;} uint32 getId() const; - void printId(::std::ostream& os) const; + void printId(::std::ostream& os) const; // // Fields // diff --git vm/jitrino/src/shared/MemoryManager.cpp vm/jitrino/src/shared/MemoryManager.cpp index 3c114ca..6f2484f 100644 --- vm/jitrino/src/shared/MemoryManager.cpp +++ vm/jitrino/src/shared/MemoryManager.cpp @@ -26,11 +26,15 @@ #include <stdio.h> #include <assert.h> #include "MemoryManager.h" +//#define JIT_MEM_CHECK + +#ifdef JIT_MEM_CHECK +#include "mkernel.h" +#endif namespace Jitrino { -//#define JIT_MEM_CHECK #ifdef JIT_MEM_CHECK @@ -38,7 +42,7 @@ #define JIT_MEM_CHECK_PADDING_SIZE 8 #define JIT_MEM_CHECK_DEFAULT_VAL 'x' #define JIT_MEM_CHECK_PADDING_VAL 'p' - +static Mutex checkPointsMutex; typedef std::map<const Arena*, std::vector<size_t>*> CheckPointsByArena; static CheckPointsByArena checkPointsByArena; @@ -62,7 +66,7 @@ #endif static const uint32 mm_default_next_arena_size = 4096-ARENA_HEADER_SIZE; -MemoryManager::MemoryManager(size_t initial_estimate, char* name) +MemoryManager::MemoryManager(size_t initial_estimate, const char* name) { _arena = NULL; _bytes_allocated = 0; @@ -119,7 +123,9 @@ void MemoryManager::_alloc_arena(size_t assert(((POINTER_SIZE_INT)_arena->next_byte & BITS_TO_CLEAR) == 0); #ifdef JIT_MEM_CHECK + checkPointsMutex.lock(); checkPointsByArena[_arena] = new std::vector<size_t>(); + checkPointsMutex.unlock(); size_t allocated_size = _arena->last_byte - _arena->bytes; memset(_arena->bytes, JIT_MEM_CHECK_DEFAULT_VAL, allocated_size); #endif @@ -132,12 +138,14 @@ void MemoryManager::_free_arenas(Arena * Arena* last = a; a = a->next_arena; #ifdef JIT_MEM_CHECK + checkPointsMutex.lock(); _check_arena_paddings(last); CheckPointsByArena::iterator it = checkPointsByArena.find(last); m_assert(it!=checkPointsByArena.end()); std::vector<size_t>* v = it->second; checkPointsByArena.erase(it); delete v; + checkPointsMutex.unlock(); #endif free_arena(last); } @@ -224,6 +232,7 @@ #endif assert(((POINTER_SIZE_INT)_arena->next_byte & BITS_TO_CLEAR) == 0); #ifdef JIT_MEM_CHECK + checkPointsMutex.lock(); _check_arena_default_val_on_alloc(_arena, mem - _arena->bytes, size); CheckPointsByArena::iterator it = checkPointsByArena.find(_arena); assert(it!=checkPointsByArena.end()); @@ -231,6 +240,7 @@ #ifdef JIT_MEM_CHECK //push offset of the current padding from the start of arena v->push_back((_arena->next_byte - _arena->bytes) - JIT_MEM_CHECK_PADDING_SIZE); memset(mem + size - JIT_MEM_CHECK_PADDING_SIZE, JIT_MEM_CHECK_PADDING_VAL, JIT_MEM_CHECK_PADDING_SIZE); + checkPointsMutex.unlock(); #endif diff --git vm/jitrino/src/shared/MemoryManager.h vm/jitrino/src/shared/MemoryManager.h index 86426d9..b7a7ad5 100644 --- vm/jitrino/src/shared/MemoryManager.h +++ vm/jitrino/src/shared/MemoryManager.h @@ -33,7 +33,7 @@ namespace Jitrino { class MemoryManager { public: - MemoryManager(size_t initial_estimate,char* name); + MemoryManager(size_t initial_estimate, const char* name); virtual ~MemoryManager(); void *alloc(size_t size); size_t bytes_allocated() { return _bytes_allocated; } diff --git vm/jitrino/src/shared/PlatformDependant.h vm/jitrino/src/shared/PlatformDependant.h index 18f4578..a2521f6 100644 --- vm/jitrino/src/shared/PlatformDependant.h +++ vm/jitrino/src/shared/PlatformDependant.h @@ -30,11 +30,11 @@ #ifndef _MSC_VER #else #pragma warning( push, 4 ) #pragma warning( disable : 4100 4127 4201 4511 4512 ) - #pragma conform( forScope, on ) + #pragma conform( forScope, on ) #endif //_MSC_VER #undef stdcall__ -#undef cdecl_ +#undef cdecl_ #ifdef PLATFORM_POSIX #ifndef __stdcall @@ -45,11 +45,29 @@ #ifndef _cdecl #define _cdecl #endif - #define stdcall__ __attribute__ ((__stdcall__)) #define cdecl_ __attribute__ ((__cdecl__)) +#ifdef _EM64T_ + #define stdcall__ +#else + #define stdcall__ __attribute__ ((__stdcall__)) +#endif + #else #define stdcall__ - #define cdecl_ + #define cdecl_ + + //--signbit implementation for windows platform + #include <float.h> + + inline int signbit(double d) { + return _copysign(1, d) < 0; + } + + inline int signbit(float f) { + return _copysign(1, f) < 0; + } + //---- + #endif #endif // _PLATFORMDEPENDANT_H_ diff --git vm/jitrino/src/shared/PrintDotFile.cpp vm/jitrino/src/shared/PrintDotFile.cpp index 682b19b..92382fd 100644 --- vm/jitrino/src/shared/PrintDotFile.cpp +++ vm/jitrino/src/shared/PrintDotFile.cpp @@ -24,15 +24,15 @@ // interface to print dot files, you should subclass this class and // implement the printBody() method // -#include <stdlib.h> -#include <fstream> -#include <iostream> -#include <streambuf> -#include <string> #include "PrintDotFile.h" #include "Inst.h" #include "optimizer.h" #include "Log.h" +#include <stdlib.h> +#include <fstream> +#include <iostream> +#include <streambuf> + namespace Jitrino { @@ -46,7 +46,7 @@ typedef int int_type; class dotbuf : public ::std::streambuf { public: - dotbuf(::std::streambuf* sb) : + dotbuf(::std::streambuf* sb) : inquotes(false), bracedepth(0), m_sb(sb) {} protected: @@ -86,68 +86,38 @@ private: class dotstream : public ::std::ostream { public: - dotstream(::std::ostream& out) : - ::std::ostream(&m_buf), m_buf(out.rdbuf()) {} + dotstream(::std::ostream& out) : + ::std::ostream(&m_buf), m_buf(out.rdbuf()) {} private: dotbuf m_buf; }; -void PrintDotFile::printDotFile(MethodDesc& mh, const char *suffix) { - const int name_len = 1024; - char filename[name_len]; - memset(filename, 'a', name_len-1); - filename[name_len-1] = '\0'; - createFileName(mh,filename,suffix); - ::std::ofstream fos(filename); +void PrintDotFile::printDotFile(MethodDesc& mh, const char * suffix) { + if (Log::isLogEnabled(LogStream::DOTDUMP)) { + if (suffix != 0) { + char* fname = Log::makeDotFileName(suffix); + + LogStream logs(fname); + printDotFile(mh, logs.out()); + + delete [] fname; + } + else { + printDotFile(mh, Log::log(LogStream::DOTDUMP).out()); + } + } +} + +void PrintDotFile::printDotFile(MethodDesc& mh, ::std::ostream& fos) { dotstream dos(fos); os = &dos; printDotHeader(mh); printDotBody(); printDotEnd(); - fos.close(); } -void PrintDotFile::createFileName(MethodDesc& mh, char* filename,const char *suffix) { - // - // create "className::methodNameAndSignature.suffix.dot" in the current dot file directory, - // add method's signature later - // - const char *type_name = mh.getParentType()->getName(); - const char *meth_name = mh.getName(); - const char *sgnt_name = mh.getSignatureString(); - const char *dot_file_dir = Log::getDotFileDirName(); - assert(dot_file_dir != NULL); - const uint32 buf_len = 1024; - char buf[buf_len]; - -#ifndef NDEBUG - uint32 len = strlen(type_name) + strlen(meth_name) + - strlen(sgnt_name) + strlen(suffix) + strlen(dot_file_dir); - assert(len < strlen(filename) - 16 /* all the dots and count */); - assert(buf_len > len); -#endif - - /*if (optimizerFlags.number_dots) { - ++count; - sprintf(buf, "%s.%s%s.%d.%s.dot", - type_name, - meth_name, - sgnt_name, - count, - suffix); - } else {*/ - sprintf(buf, "%s.%s%s.%s.dot", - type_name, - meth_name, - sgnt_name, - suffix); - //} - Log::fixFileName(buf); - sprintf(filename, "%s/%s", dot_file_dir, buf); -}; - void PrintDotFile::printDotHeader(MethodDesc& mh) { *os << "digraph dotgraph {" << ::std::endl << "fontpath=\"c:\\winnt\\fonts\";" << ::std::endl diff --git vm/jitrino/src/shared/PrintDotFile.h vm/jitrino/src/shared/PrintDotFile.h index 69d8e09..0c18249 100644 --- vm/jitrino/src/shared/PrintDotFile.h +++ vm/jitrino/src/shared/PrintDotFile.h @@ -30,9 +30,8 @@ #define _PRINTDOTFILE_ // interface to print dot files, you should subclass this class and // implement the printBody() method // -#include <stdlib.h> + #include <fstream> -#include <string.h> namespace Jitrino { @@ -44,17 +43,16 @@ public: // // dump out to a filename composed of the method descriptor and a suffix // - virtual void printDotFile(MethodDesc& mh, const char *suffix); + virtual void printDotFile(MethodDesc& mh, const char * /*suffix*/); virtual void printDotHeader(MethodDesc& mh); virtual void printDotEnd (); virtual void printDotBody (); protected: - virtual ~PrintDotFile() {}; - ::std::ostream* os; + void printDotFile(MethodDesc& mh, ::std::ostream& fos); + virtual ~PrintDotFile() {}; + ::std::ostream* os; int count; -private: - void createFileName(MethodDesc& mh, char* filename,const char *suffix); }; } //namespace Jitrino diff --git vm/jitrino/src/shared/PropertyTable.cpp vm/jitrino/src/shared/PropertyTable.cpp deleted file mode 100644 index 65167f7..0000000 --- vm/jitrino/src/shared/PropertyTable.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.16.16.2.4.4 $ - * - */ - -#include <ctype.h> -#include <stdlib.h> -#include <iostream> -#include <fstream> -#include "PropertyTable.h" -#include "methodtable.h" -#include "PlatformDependant.h" - -namespace Jitrino { - -bool JitrinoParameterTable::insertfromcommandline = false; - -void -JitrinoParameterTable::commandLineError(const char *badParam) -{ - if (readingFile) { - ::std::cerr << "JitrinoParameterTable: Bad parameter found in file " << readingFile << ":\n"; - } else { - ::std::cerr << "JitrinoParameterTable: Bad parameter on command line:\n"; - } - ::std::cerr << " " << badParam << "\n"; - exit(1); -} - -JitrinoParameterTable::JitrinoParameterTable(MemoryManager &mm, uint32 size) : - table(mm, size), _createdStrings(), readingFile(0), - memManager(mm), next(0), mtable(0), tablesize(size) -{ -} - -JitrinoParameterTable::~JitrinoParameterTable() -{ - ::std::list<char *>::iterator a = _createdStrings.begin(); - ::std::list<char *>::iterator b = _createdStrings.end(); - while (a != b) { - ++a; - } -} - -JitrinoParameterTable * -JitrinoParameterTable::insert(const char *propertyName, const char *value) -{ - // insertfromcommandline==true if there was any insertion from command line - insertfromcommandline = true; - -#ifdef PARAM_DEBUG - ::std::cerr << "Entering param " << propertyName << " -> " << value << "\n"; -#endif - if (strncmp(propertyName,"METHODS",8)==0) { - Method_Table *newmtable = new (memManager) Method_Table(value, "Jitrino", true); - JitrinoParameterTable *newpt = - new (memManager) JitrinoParameterTable(memManager, tablesize); - newpt->next = this; - newpt->mtable = newmtable; - newpt->readingFile = readingFile; readingFile = 0; - // add entries from this to newpt - TableIterType titer(&table); - const char *key, *elem; - while (titer.getNextElem(key, elem)) { - newpt->table.insert(key, elem); - } - return newpt; - } else if (strncmp(propertyName,"LOG",4)==0) { - const char *oldval = table.lookup(propertyName); - if (oldval) { - uint32 size1 = (uint32) strlen(oldval); - uint32 size2 = (uint32) strlen(value); - uint32 size = (uint32) (size1 + size2 + 1); - char *tmp1= new (memManager) char[size+1]; - strcpy(tmp1,oldval); - tmp1[size1] = ','; - strcpy(tmp1+size1+1,value); - _createdStrings.push_back(tmp1); - value = tmp1; - } - } - table.insert(propertyName, value); - { -#ifdef PARAM_DEBUG - const char *newvalue = lookup(propertyName); - if (newvalue) { - ::std::cerr << "New value is " << newvalue << "\n"; - } else { - ::std::cerr << " New value is NULL!! \n"; - } -#endif - } - return this; -} - -// must have stringStart <= stringEnd. -// if stringStart is 0, then stringEnd must be 0 also. -// string goes from stringStart to stringEnd-1 -char * -JitrinoParameterTable::cacheString(const char *stringStart, const char *stringEnd) -{ - uint32 size = (uint32) (stringEnd-stringStart); - char *tmp1= new (memManager) char[size+1]; - strncpy(tmp1,stringStart,size); - tmp1[size]='\0'; - _createdStrings.push_back(tmp1); - return tmp1; -} - -JitrinoParameterTable * -JitrinoParameterTable::insertFromCommandLine(const char *commandLineParameter) -{ - const char *was_file = lookup("fromfile"); - JitrinoParameterTable *t = this; - t = t->parseCommandLine(commandLineParameter); - const char *now_file = t->lookup("fromfile"); - if (was_file != now_file) { - return t->readFromFile(now_file); - } - return t; -} - -JitrinoParameterTable * -JitrinoParameterTable::parseCommandLine(const char *commandLineParameter) -{ - const char *p3 = commandLineParameter; - JitrinoParameterTable *t = this; - if (p3 != 0) { - if (*p3 == '#') return t; // Ignore lines beginning with the '#' character. - bool done=(*p3 == '\0'); - while (!done) { - const char *propStart = p3; - const char *propEnd = 0; - const char *valueStart = 0; - const char *valueEnd = 0; - bool quoted = false; - bool wasQuoted = false; - - do { - switch (*p3) { - case '=': - if (!quoted) { - propEnd = p3; valueStart = p3+1; - } - ++p3; break; - case ',': - if (quoted) { - ++p3; - break; - } - // otherwise fall through: - case '\0': - done = true; - if (valueStart) { - valueEnd = p3; - } else { - propEnd = p3; - } - break; - case '"': - if (quoted) { - quoted = false; - wasQuoted = true; - } else { - if (wasQuoted) { - t->commandLineError(commandLineParameter); - } - quoted = true; - } - ++p3; - break; - default: - ++p3; - break; - } - } while (!done); - if ( valueStart == 0 ) { - // - // no value means "on" - // - t->insert(cacheString(propStart,propEnd), "on"); - }else{ - if (wasQuoted) { - if ( (*valueStart != '"') || (*(valueEnd-1) != '"') ) { - t->commandLineError(commandLineParameter); - } - ++valueStart; - --valueEnd; - } - t = t->insert(cacheString(propStart,propEnd), cacheString(valueStart,valueEnd)); - } - done = (*p3 == '\0'); - ++p3; - } - } - return t; -} - -JitrinoParameterTable * -JitrinoParameterTable::readFromFile(const char *fileName) -{ - ::std::ifstream source(fileName); - if (!source) { - ::std::cerr << "unable to open " << fileName << " for reading.\n"; - exit(1); - } - char inbuf[4096]; - inbuf[0] = '\0'; - source >> inbuf; - JitrinoParameterTable *t = this; - t->readingFile = fileName; - while (inbuf[0] != '\0') { - t = t->insertFromCommandLine(inbuf); - inbuf[0] = '\0'; - source >> inbuf; - if(source.eof()) - break; - } - t->readingFile = 0; - return t; -} - -const char * -JitrinoParameterTable::lookup(const char *propertyName) const -{ - if ( !insertfromcommandline ) return NULL; - const char *a = table.lookup(propertyName); - return a; -} - -bool JitrinoParameterTable::lookupBool(const char *propertyName, bool def) const -{ - if ( !insertfromcommandline ) return def; - const char *s = lookup(propertyName); - if (s != 0) { - if ((strnicmp(s,"yes",10)==0) || - (strnicmp(s,"true",10)==0) || - (strnicmp(s,"on",10)==0) || - (strnicmp(s,"t",10)==0) || - (strnicmp(s,"y",1)==0)) { - return true; - } - } else { - return def; - } - return false; -} - -char JitrinoParameterTable::lookupChar(const char *propertyName, char def) const -{ - if ( !insertfromcommandline ) return def; - const char *s = lookup(propertyName); - if (s == 0) { - return def; - } else { - return *s; - }; -} - -int JitrinoParameterTable::lookupInt(const char *propertyName, int def) const -{ - if ( !insertfromcommandline ) return def; - const char *s = lookup(propertyName); - if (s == 0) { - return def; - } - int i=0; - int j = sscanf(s, "%d", &i); - if (j == 1) { - return i; - } else { - return -123456789; - } -} - -unsigned int JitrinoParameterTable::lookupUint(const char *propertyName, - unsigned int def) const -{ - if ( !insertfromcommandline ) return def; - const char *s = lookup(propertyName); - if (s == 0) { - return def; - } - unsigned int i=0; - unsigned int j = sscanf(s, "%u", &i); - if (j == 1) { - return i; - } else { - return def; - } -} - -void JitrinoParameterTable::print(::std::ostream &outs) const -{ - outs << "printing JitrinoParameterTable\n"; - - outs << "Created Strings: "; - ::std::list<char *>::const_iterator a = _createdStrings.begin(); - ::std::list<char *>::const_iterator b = _createdStrings.end(); - while (a != b) { - char *av = *a; - outs << "\"" << av << "\" "; - ++a; - } - outs << "\n"; - outs << "The table:\n"; - TableIterType iter(&(((JitrinoParameterTable *)this)->table)); - const char *key, *value; - if (iter.getNextElem(key, value)) { - outs << "{ " << key << "=" << "\"" << value << "\""; -#ifdef PARAM_DEBUG - ::std::cerr << "saw binding of key "; - ::std::cerr << key; - ::std::cerr << "\n"; -#endif - while (iter.getNextElem(key, value)) { - outs << ",\n " << key << "=" << "\"" << value << "\""; -#ifdef PARAM_DEBUG - ::std::cerr << "saw binding of key "; - ::std::cerr << key; - ::std::cerr << "\n"; -#endif - } - outs << "\n}\n"; - } else { - outs << "EMPTY\n"; - } -} - -JitrinoParameterTable * -JitrinoParameterTable::getTableForMethod(MethodDesc &md) -{ - JitrinoParameterTable *t = this; - while (t && t->mtable && !t->mtable->accept_this_method(md)) { - t = t->next; - } - assert(t); - return t; -} - -} //namespace Jitrino diff --git vm/jitrino/src/shared/PropertyTable.h vm/jitrino/src/shared/PropertyTable.h deleted file mode 100644 index a44f708..0000000 --- vm/jitrino/src/shared/PropertyTable.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.8.24.4 $ - * - */ - -#ifndef _JITRINO_PARAMETER_TABLE_H_ -#define _JITRINO_PARAMETER_TABLE_H_ -#include <iostream> -#include <string.h> -#include <stdlib.h> -#include <list> -#include "HashTable.h" - -namespace Jitrino { - -template <class ELEM_TYPE> -class StringHashTable : public ConstHashTable<char, ELEM_TYPE> { -public: - StringHashTable(MemoryManager& mm, uint32 size) : ConstHashTable<char,ELEM_TYPE>(mm,size) {} -protected: - virtual bool keyEquals(const char* key1,const char* key2) const { - return (strcmp(key1,key2)==0); - } - virtual uint32 getKeyHashCode(const char* key) const { - // return some hash function; - uint32 hash = 0; - while (*key != '\0') { - hash <<= 3; - hash += *key; - ++key; - } - return hash; - } -}; - -class Method_Table; -class MethodDesc; - -class JitrinoParameterTable { -private: - typedef StringHashTable<char> TableType; - typedef ConstHashTableIter<char,char> TableIterType; - TableType table; - ::std::list<char *> _createdStrings; - const char *readingFile; - MemoryManager &memManager; - - JitrinoParameterTable *next; - Method_Table* mtable; - uint32 tablesize; - - // insertfromcommandline==true if there was any insertion from command line - static bool insertfromcommandline; -public: - JitrinoParameterTable(MemoryManager& mm, uint32 size); - ~JitrinoParameterTable(); - - JitrinoParameterTable *insert(const char *propertyName, const char *value); - JitrinoParameterTable *insertFromCommandLine(const char *commandLineParameter); - JitrinoParameterTable *readFromFile(const char *fileName); - - const char *lookup(const char *propertyName) const; - bool lookupBool(const char *propertyName, bool def) const; - char lookupChar(const char *propertyName, char def) const; - int lookupInt(const char *propertyName, int def) const; - unsigned int lookupUint(const char *propertyName, unsigned int def) const; - // only does first 20 chars; uses static var so must be single-threaded!! - static const char *stringToLower(const char *thestring); - void print(::std::ostream &outs) const; - - JitrinoParameterTable *getTableForMethod(MethodDesc &md); -private: - char *cacheString(const char *stringStart, const char *stringEnd); - static char _tmp[21]; - void commandLineError(const char *badParam); - JitrinoParameterTable *parseCommandLine(const char *commandLineParameter); -}; - -} //namespace Jitrino - -#endif // _JITRINO_PARAMETER_TABLE_H_ diff --git vm/jitrino/src/shared/Queue.h vm/jitrino/src/shared/Queue.h index 165df12..4f021c7 100644 --- vm/jitrino/src/shared/Queue.h +++ vm/jitrino/src/shared/Queue.h @@ -85,7 +85,7 @@ public: Queue(MemoryManager& m) : queueImpl(m) {} T* pop() {return (T*)queueImpl::pop();} void push(T* elem) {queueImpl::push(elem);} - T* top() {return (T*)queueImpl::top();} + T* top() {return (T*)queueImpl::top();} }; } //namespace Jitrino diff --git vm/jitrino/src/shared/Stack.h vm/jitrino/src/shared/Stack.h index 37f2a5f..8d702dd 100644 --- vm/jitrino/src/shared/Stack.h +++ vm/jitrino/src/shared/Stack.h @@ -31,36 +31,36 @@ namespace Jitrino { class stackImpl { public: - stackImpl(MemoryManager& m) : mm(m) {} - void* pop() { - if (isEmpty()) return NULL; - stackElem* e = workList.next(); - free(e); // put it back to freeList - return e->elem; - } - void push(void *elem) { - stackElem* se = getFreeStackElem(); - if (se == NULL) - se = new (mm) stackElem(); - se->elem = elem; - se->insertAfter(&workList); - }; - // if stack is empty, NULL is returned - void* top() {return workList.next()->elem;} - // returns true if empty - bool isEmpty() {return workList.next() == &workList;} + stackImpl(MemoryManager& m) : mm(m) {} + void* pop() { + if (isEmpty()) return NULL; + stackElem* e = workList.next(); + free(e); // put it back to freeList + return e->elem; + } + void push(void *elem) { + stackElem* se = getFreeStackElem(); + if (se == NULL) + se = new (mm) stackElem(); + se->elem = elem; + se->insertAfter(&workList); + }; + // if stack is empty, NULL is returned + void* top() {return workList.next()->elem;} + // returns true if empty + bool isEmpty() {return workList.next() == &workList;} private: - class stackElem : public Dlink - { - public: - void *elem; + class stackElem : public Dlink + { + public: + void *elem; - stackElem() : elem(NULL) {} - stackElem* next() {return (stackElem*)_next;} - stackElem* prev() {return (stackElem*)_prev;} - }; + stackElem() : elem(NULL) {} + stackElem* next() {return (stackElem*)_next;} + stackElem* prev() {return (stackElem*)_prev;} + }; - MemoryManager& mm; + MemoryManager& mm; stackElem freeList; stackElem workList; @@ -73,7 +73,7 @@ private: if (n != &freeList) // there is a free node { n->unlink(); - n->elem = NULL; + n->elem = NULL; return n; } return NULL; @@ -83,10 +83,10 @@ private: template <class T> class Stack : public stackImpl { public: - Stack(MemoryManager& m) : stackImpl(m) {} - T* pop() {return (T*)stackImpl::pop();} - void push(T* elem) {stackImpl::push(elem);} - T* top() {return (T*)stackImpl::top();} + Stack(MemoryManager& m) : stackImpl(m) {} + T* pop() {return (T*)stackImpl::pop();} + void push(T* elem) {stackImpl::push(elem);} + T* top() {return (T*)stackImpl::top();} }; } //namespace Jitrino diff --git vm/jitrino/src/shared/Stl.h vm/jitrino/src/shared/Stl.h index 55923c9..f49f601 100644 --- vm/jitrino/src/shared/Stl.h +++ vm/jitrino/src/shared/Stl.h @@ -47,6 +47,7 @@ #else #include <ext/stl_hash_fun.h> #endif + #else #undef _STDEXT_BEGIN @@ -357,7 +358,7 @@ public: StlMultiSet(Allocator const& a) : MultiSet(Traits(), a) {} StlMultiSet(Traits const& t, Allocator const& a) : MultiSet(t, a) {} - bool has(const KeyT& k) const { return (find(k) != StlMultiSet<KeyT>::end()); }; + bool has(const KeyT& k) const { return (find(k) != StlMultiSet<KeyT>::end()); }; }; /** @@ -442,7 +443,7 @@ public: StlHashSet(Allocator const& a, size_type n, HashFun const& h) : HashSet(n, h, CompareFun(), a) {} StlHashSet(Allocator const& a, size_type n, HashFun const& h, CompareFun const& c) : HashSet(n, h, c, a) {} - bool has(const T& k) const { return (find(k) != end()); }; + bool has(const T& k) const { return (find(k) != StlHashSet<T,HashCompareFun,Allocator>::end()); }; }; #endif @@ -473,7 +474,7 @@ public: StlHashMultiSet(Allocator const& a, size_type n, HashFun const& h) : HashMultiSet(n, h, CompareFun(), a) {} StlHashMultiSet(Allocator const& a, size_type n, HashFun const& h, CompareFun const& c) : HashMultiSet(n, h, c, a) {} - bool has(const T& k) const { return (find(k) != end()); }; + bool has(const T& k) const { return (find(k) != StlHashMultiSet<T,HashCompareFun,Allocator>::end()); }; }; #endif @@ -505,7 +506,7 @@ public: StlHashMap(Allocator const& a, size_type n, HashFun const& h) : HashMap(n, h, CompareFun(), a) {} StlHashMap(Allocator const& a, size_type n, HashFun const& h, CompareFun const& c) : HashMap(n, h, c, a) {} - bool has(const KeyT& k) const { return (find(k) != end()); }; + bool has(const KeyT& k) const { return (find(k) != StlHashMap<KeyT,ValueT,HashCompareFun,Allocator>::end()); }; }; #endif @@ -536,7 +537,7 @@ public: StlHashMultiMap(Allocator const& a, size_type n, HashFun const& h) : HashMultiMap(n, h, CompareFun(), a) {} StlHashMultiMap(Allocator const& a, size_type n, HashFun const& h, CompareFun const& c) : HashMultiMap(n, h, c, a) {} - bool has(const KeyT& k) const { return (find(k) != end()); }; + bool has(const KeyT& k) const { return (find(k) != StlHashMultiMap<KeyT,ValueT,HashCompareFun,Allocator>::end()); }; }; #endif diff --git vm/jitrino/src/shared/Timer.h vm/jitrino/src/shared/Timer.h deleted file mode 100644 index 5017a91..0000000 --- vm/jitrino/src/shared/Timer.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Intel, Mikhail Y. Fursov - * @version $Revision: 1.13.16.1.4.4 $ - * - */ - -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#ifndef PLATFORM_POSIX -// must be here, before <windows.h> to avoid compile-time errors -// with winsock.h - -// http://www.microsoft.com/msdownload/platformsdk/sdkupdate/2600.2180.7/contents.htm -#include <winsock2.h> -#include <windows.h> -#define TIMERS_IMPLEMENTED 1 -#endif -#include "Jitrino.h" -#include <ostream> - - -namespace Jitrino { - -class Timer; - - -class Timer { - const char * name; // Name for the event counter - int64 startTime; - int64 totalTime; - int64 correction; - double calibrationTime; - double timerFrequency; - bool isOn; - Timer *next; - int recursionCount; -public: - Timer(const char *_name, Timer *next0) : name(_name), isOn(false), next(next0), - recursionCount(0) { - //calibrateTimer(); - resetTimer(); - }; - - void setFrequency() { -#ifdef TIMERS_IMPLEMENTED -#ifdef USE_THREAD_TIMER - timerFrequency = 10000000; -#else - LARGE_INTEGER getFrequency; - QueryPerformanceFrequency(&getFrequency); - timerFrequency = (double) getFrequency.QuadPart; -#endif -#endif - } - - static int64 getCounter() { -#ifdef TIMERS_IMPLEMENTED -#ifdef USE_THREAD_TIMER - FILETIME creation; - FILETIME exit; - FILETIME system; - FILETIME user; - GetThreadTimes(GetCurrentThread(), &creation, &exit, &system, &user); - return (((int64) user.dwHighDateTime) << 32) + user.dwLowDateTime; -#else - LARGE_INTEGER getCount; - QueryPerformanceCounter(&getCount); - return getCount.QuadPart; -#endif -#else - return 0; -#endif - } - - void calibrateTimer() { - totalTime = 0; - correction = 0; - startTimer(); - stopTimer(); - correction = totalTime; - } - - // - // Clear the timer. - // - void resetTimer() { - setFrequency(); - isOn = false; - recursionCount = 0; - calibrateTimer(); - totalTime = 0; - } - - // - // Start the timer. Continue timing from where we were. - // - void startTimer() { - if (recursionCount++ == 0) { - startTime = getCounter(); - isOn = true; - } - } - // - // Stop the timer. - // - void stopTimer() { - if (--recursionCount == 0) { - int64 finishTime = getCounter(); - int64 deltaT = (finishTime - startTime - correction); - totalTime = totalTime + deltaT; - isOn = false; - } - } - - int64 getTime() { - return totalTime; - } - - double getSeconds() { - return (((double)totalTime) / timerFrequency); - } - - double getFrequency() { - return timerFrequency; - } - - // - // Print data on the event - // - void print(::std::ostream & os) { - os << "Timer: " << name; - os << "\t"; - os << getSeconds() << " seconds"; - os << ::std::endl; - } - - Timer *getNext() { - return next; - } -}; - -class PhaseTimer { - Timer* t; -public: - PhaseTimer(Timer* &tin, const char *name) : t(tin) { - if (!t) { - tin = Jitrino::addTimer(name); - t = tin; - } - if (Jitrino::flags.time) - t->startTimer(); - else - t = 0; - } - ~PhaseTimer() { - if (t) - t->stopTimer(); - } -}; - -class PhaseInvertedTimer { - Timer* t; -public: - PhaseInvertedTimer(Timer* &tin) : t(tin) { - if (t) - t->stopTimer(); - } - ~PhaseInvertedTimer() { - if (t) - t->startTimer(); - } -}; - -} //namespace Jitrino - -#endif // _TIMER_H_ diff --git vm/jitrino/src/shared/Tree.h vm/jitrino/src/shared/Tree.h index 2d7e1b3..1aa1d28 100644 --- vm/jitrino/src/shared/Tree.h +++ vm/jitrino/src/shared/Tree.h @@ -24,6 +24,9 @@ #ifndef _TREE_H_ #define _TREE_H_ #include "PrintDotFile.h" +#include "open/types.h" + +#include <assert.h> #include <string> namespace Jitrino { @@ -116,8 +119,7 @@ public: if(child != NULL) { i = child->getHeight(); - TreeNode *siblings = child->siblings; - while (siblings != NULL) { + for (TreeNode *siblings = child->siblings; siblings!=NULL; siblings = siblings->siblings) { uint32 j = siblings->getHeight(); if(j > i) i = j; } @@ -133,9 +135,20 @@ public: i += siblings->getCount(); return i; } + + //return number of parents + uint32 getDepth() const { + return parent != NULL ? parent->getDepth() + 1 : 0; + } uint32 getPreNum() const { return preNum; } uint32 getPostNum() const { return postNum; } + + // Return true if this is a proper ancestor of n. + bool isAncestorOf(TreeNode* n) { + return (preNum < n->preNum) && (postNum > n->postNum); + } + protected: TreeNode* child; TreeNode* siblings; @@ -155,6 +168,7 @@ public: PrintDotFile::printDotFile(mh,suffix); } virtual void printDotBody() { + if (root == NULL) return; root->printDotTreeNode(*os); // // lay out ranks @@ -167,11 +181,11 @@ public: root->printIndentedNode(os, indentstr); } - uint32 getHeight() const { return root->getHeight(); } - uint32 getCount() const { return root->getCount(); } + uint32 getHeight() const { return root==NULL ? 0 : root->getHeight(); } + uint32 getCount() const { return root == NULL ? 0: root->getCount(); } // Return true if n1 is a proper ancestor of n2. - bool isAncestor(TreeNode* n1, TreeNode* n2) { + bool isAncestor(const TreeNode* n1, const TreeNode* n2) const { return (n1->preNum < n2->preNum) && (n1->postNum > n2->postNum); } diff --git vm/jitrino/src/shared/Type.cpp vm/jitrino/src/shared/Type.cpp index 72b9c36..13b58ce 100644 --- vm/jitrino/src/shared/Type.cpp +++ vm/jitrino/src/shared/Type.cpp @@ -31,7 +31,7 @@ uint32 Type::nextTypeId = 1; bool Type::mayAlias(TypeManager* typeManager, Type* t1, Type* t2) { - assert(t1 && t2); + assert(t1 && t2); t1 = t1->getNonValueSupertype(); t2 = t2->getNonValueSupertype(); if (t1==t2) return true; @@ -106,9 +106,9 @@ Type* TypeManager::getPrimitiveType(Type case Type::IntPtr: return getIntPtrType(); case Type::UIntPtr: return getUIntPtrType(); case Type::Void: return getVoidType(); - case Type::Tau: return getTauType(); - case Type::Boolean: return getBooleanType(); - case Type::Char: return getCharType(); + case Type::Tau: return getTauType(); + case Type::Boolean: return getBooleanType(); + case Type::Char: return getCharType(); default: assert(0); return NULL; } } @@ -128,12 +128,14 @@ Type* TypeManager::toInternalType(Type* case Type::Double: case Type::Float: case Type::SystemObject: + case Type::SystemClass: case Type::SystemString: case Type::NullObject: case Type::Array: case Type::Object: case Type::ManagedPtr: case Type::CompressedSystemObject: + case Type::CompressedSystemClass: case Type::CompressedSystemString: case Type::CompressedNullObject: case Type::CompressedArray: @@ -167,6 +169,9 @@ bool TypeManager::isSubTypeOf(Type *type if (oneIsCompressed != twoIsCompressed) return false; switch (type1->tag) { + case Type::SystemClass: + // java/lang/class has only one ancestor - java/lang/Object + return type2->tag == Type::SystemObject; case Type::SystemString: case Type::Object: object_type: @@ -295,12 +300,14 @@ TypeManager::TypeManager(MemoryManager& typedReference(Type::TypedReference), theSystemStringType(NULL), theSystemObjectType(NULL), + theSystemClassType(NULL), nullObjectType(Type::NullObject), offsetType(Type::Offset), offsetPlusHeapbaseType(Type::OffsetPlusHeapbase), compressedSystemStringType(NULL), compressedSystemObjectType(NULL), + compressedSystemClassType(NULL), compressedNullObjectType(Type::CompressedNullObject), userValueTypes(mm,32), @@ -346,7 +353,7 @@ TypeManager::initBuiltinType(Type::Tag t void TypeManager::init(CompilationInterface &compInt) { - init(); + init(); areReferencesCompressed = compInt.areReferencesCompressed(); } @@ -355,19 +362,26 @@ TypeManager::init() { areReferencesCompressed = false; void* systemStringVMTypeHandle = getSystemStringVMTypeHandle(); void* systemObjectVMTypeHandle = getSystemObjectVMTypeHandle(); + void* systemClassVMTypeHandle = getSystemClassVMTypeHandle(); theSystemStringType = new (memManager) ObjectType(Type::SystemString,systemStringVMTypeHandle,*this); theSystemObjectType = new (memManager) ObjectType(Type::SystemObject,systemObjectVMTypeHandle,*this); + theSystemClassType = new (memManager) + ObjectType(Type::SystemClass,systemClassVMTypeHandle,*this); userObjectTypes.insert(systemStringVMTypeHandle,theSystemStringType); userObjectTypes.insert(systemObjectVMTypeHandle,theSystemObjectType); + userObjectTypes.insert(systemClassVMTypeHandle,theSystemClassType); compressedSystemStringType = new (memManager) ObjectType(Type::CompressedSystemString,systemStringVMTypeHandle,*this); compressedSystemObjectType = new (memManager) ObjectType(Type::CompressedSystemObject,systemObjectVMTypeHandle,*this); + compressedSystemClassType = new (memManager) + ObjectType(Type::CompressedSystemClass,systemClassVMTypeHandle,*this); compressedUserObjectTypes.insert(systemStringVMTypeHandle,compressedSystemStringType); compressedUserObjectTypes.insert(systemObjectVMTypeHandle,compressedSystemObjectType); + compressedUserObjectTypes.insert(systemClassVMTypeHandle,compressedSystemClassType); tauType = new (memManager) Type(Type::Tau); voidType = new (memManager) Type(Type::Void); @@ -412,7 +426,7 @@ TypeManager::getArrayType(Type* elemType type = new (memManager) ArrayType(elemNamedType,arrayVMTypeHandle,*this, isCompressed); if (type->getAllocationHandle()!=0) { // type is resolved - lookupTable.insert(elemNamedType,type); + lookupTable.insert(elemNamedType,type); } } return type; @@ -427,7 +441,7 @@ TypeManager::getObjectType(void* vmTypeH void* elemClassHandle = getArrayElemVMTypeHandle(vmTypeHandle); assert(elemClassHandle != NULL); NamedType* elemType; - if (isArrayOfUnboxedElements(vmTypeHandle)) { + if (isArrayOfPrimitiveElements(vmTypeHandle)) { elemType = getValueType(elemClassHandle); } else { elemType = getObjectType(elemClassHandle, areReferencesCompressed); @@ -479,6 +493,12 @@ bool NamedType::needsInitialization(){ return typeManager.needsInitialization(vmTypeHandle); } + +bool +NamedType::isFinalizable(){ + return typeManager.isFinalizable(vmTypeHandle); +} + bool NamedType::isBeforeFieldInit() { return typeManager.isBeforeFieldInit(vmTypeHandle); @@ -549,6 +569,8 @@ TypeManager::uncompressType(Type *compRe } case Type::CompressedSystemObject: return getSystemObjectType(); + case Type::CompressedSystemClass: + return getSystemClassType(); case Type::CompressedSystemString: return getSystemStringType(); case Type::CompressedObject: @@ -578,6 +600,8 @@ TypeManager::compressType(Type *uncompRe } case Type::SystemObject: return getCompressedSystemObjectType(); + case Type::SystemClass: + return getCompressedSystemClassType(); case Type::SystemString: return getCompressedSystemStringType(); case Type::Object: @@ -724,6 +748,7 @@ void Type::print(::std::ostream& os) case TypedReference: s = "typedref"; break; case Value: s = "value"; break; case SystemObject: s = "object"; break; + case SystemClass: s = "class"; break; case SystemString: s = "string"; break; case Array: s = "[]"; break; case Object: s = "object"; break; @@ -735,6 +760,7 @@ void Type::print(::std::ostream& os) case MethodPtr: s = "method"; break; case VTablePtr: s = "vtable"; break; case CompressedSystemObject: s = "cmpobject"; break; + case CompressedSystemClass: s = "cmpclass"; break; case CompressedSystemString: s = "cmpstring"; break; case CompressedArray: s = "cmp[]"; break; case CompressedObject: s = "cmpo"; break; @@ -855,6 +881,7 @@ Type::getPrintString(Tag t) { case TypedReference: s = "trf"; break; case Value: s = "val"; break; case SystemObject: s = "obj"; break; + case SystemClass: s = "cls"; break; case SystemString: s = "str"; break; case NullObject: s = "nul"; break; case Offset: s = "off"; break; @@ -866,6 +893,7 @@ Type::getPrintString(Tag t) { case MethodPtr: s = "fun"; break; case VTablePtr: s = "vtb"; break; case CompressedSystemObject: s = "cob"; break; + case CompressedSystemClass: s = "ccl"; break; case CompressedSystemString: s = "cst"; break; case CompressedNullObject: s = "cnl"; break; case CompressedArray: s = "c[]"; break; @@ -927,6 +955,7 @@ Type* TypeManager::convertToOldType(Type case Type::Offset: case Type::OffsetPlusHeapbase: case Type::SystemObject: + case Type::SystemClass: case Type::SystemString: case Type::NullObject: case Type::Array: @@ -934,6 +963,7 @@ Type* TypeManager::convertToOldType(Type case Type::BoxedValue: case Type::VTablePtr: case Type::CompressedSystemObject: + case Type::CompressedSystemClass: case Type::CompressedSystemString: case Type::CompressedNullObject: case Type::CompressedArray: @@ -994,117 +1024,119 @@ Type* TypeManager::convertToOldType(Type /* The following structure and array contain a mapping between Type::Tag and its string representation. The array must be - ordered by Tag - must cover all available Tag-s + ordered by Tag + must cover all available Tag-s The 'tag; field exists only in debug build and is excluded from the release bundle. It's used to control whether the array is arranged properly. */ #ifdef _DEBUG -#define DECL_TAG_ITEM(tag, printout) { Type::tag, #tag, printout } +#define DECL_TAG_ITEM(tag, printout) { Type::tag, #tag, printout } #else - #define DECL_TAG_ITEM(tag, printout) { #tag, printout } + #define DECL_TAG_ITEM(tag, printout) { #tag, printout } #endif static const struct { #ifdef _DEBUG - Type::Tag tag; + Type::Tag tag; #endif - const char * name; - // the [5] has no special meaning. That was the max number of - // chars used in the existing code, so I decided to keep the 5. - // it's ok to increae it if neccessary. - char print_name[5]; + const char * name; + // the [5] has no special meaning. That was the max number of + // chars used in the existing code, so I decided to keep the 5. + // it's ok to increae it if neccessary. + char print_name[5]; } type_tag_names[] = { - DECL_TAG_ITEM(Tau, "tau "), - DECL_TAG_ITEM(Void, "v "), - DECL_TAG_ITEM(Boolean, "b "), - DECL_TAG_ITEM(Char, "chr "), - - DECL_TAG_ITEM(IntPtr, "i "), - DECL_TAG_ITEM(Int8, "i1 "), - DECL_TAG_ITEM(Int16, "i2 "), - DECL_TAG_ITEM(Int32, "i4 "), - DECL_TAG_ITEM(Int64, "i8 "), - DECL_TAG_ITEM(UIntPtr, "u "), - - DECL_TAG_ITEM(UInt8, "u1 "), - DECL_TAG_ITEM(UInt16, "u2 "), - DECL_TAG_ITEM(UInt32, "u4 "), - DECL_TAG_ITEM(UInt64, "u8 "), - - DECL_TAG_ITEM(Single, "r4 "), - DECL_TAG_ITEM(Double, "r8 "), - DECL_TAG_ITEM(Float, "r "), - - DECL_TAG_ITEM(TypedReference, "trf "), - DECL_TAG_ITEM(Value, "val"), - - DECL_TAG_ITEM(Offset, "off "), - DECL_TAG_ITEM(OffsetPlusHeapbase, "ohb "), - - DECL_TAG_ITEM(SystemObject, "obj "), - DECL_TAG_ITEM(SystemString, "str "), - DECL_TAG_ITEM(NullObject, "nul "), - DECL_TAG_ITEM(Array, "[] "), - DECL_TAG_ITEM(Object, "o "), - DECL_TAG_ITEM(BoxedValue, "bval"), - - DECL_TAG_ITEM(UnmanagedPtr, "* "), - DECL_TAG_ITEM(ManagedPtr, "& "), - DECL_TAG_ITEM(MethodPtr, "fun "), - DECL_TAG_ITEM(VTablePtr, "vtb "), - - DECL_TAG_ITEM(CompressedSystemObject, "cob "), - DECL_TAG_ITEM(CompressedSystemString, "cst "), - DECL_TAG_ITEM(CompressedNullObject, "cnl "), - DECL_TAG_ITEM(CompressedArray, "c[] "), - DECL_TAG_ITEM(CompressedObject, "co "), - - DECL_TAG_ITEM(CompressedMethodPtr, "cfun"), - DECL_TAG_ITEM(CompressedVTablePtr, "cvtb"), - DECL_TAG_ITEM(OrNull, "ornl"), - - DECL_TAG_ITEM(VTablePtrObj, "vtb "), - DECL_TAG_ITEM(ITablePtrObj, "itb "), - DECL_TAG_ITEM(ArrayLength, "len "), - DECL_TAG_ITEM(ArrayElementType, "elem"), - DECL_TAG_ITEM(Singleton, "ston"), - DECL_TAG_ITEM(NumTypeTags, "XXXX"), + DECL_TAG_ITEM(Tau, "tau "), + DECL_TAG_ITEM(Void, "v "), + DECL_TAG_ITEM(Boolean, "b "), + DECL_TAG_ITEM(Char, "chr "), + + DECL_TAG_ITEM(IntPtr, "i "), + DECL_TAG_ITEM(Int8, "i1 "), + DECL_TAG_ITEM(Int16, "i2 "), + DECL_TAG_ITEM(Int32, "i4 "), + DECL_TAG_ITEM(Int64, "i8 "), + DECL_TAG_ITEM(UIntPtr, "u "), + + DECL_TAG_ITEM(UInt8, "u1 "), + DECL_TAG_ITEM(UInt16, "u2 "), + DECL_TAG_ITEM(UInt32, "u4 "), + DECL_TAG_ITEM(UInt64, "u8 "), + + DECL_TAG_ITEM(Single, "r4 "), + DECL_TAG_ITEM(Double, "r8 "), + DECL_TAG_ITEM(Float, "r "), + + DECL_TAG_ITEM(TypedReference, "trf "), + DECL_TAG_ITEM(Value, "val"), + + DECL_TAG_ITEM(Offset, "off "), + DECL_TAG_ITEM(OffsetPlusHeapbase, "ohb "), + + DECL_TAG_ITEM(SystemObject, "obj "), + DECL_TAG_ITEM(SystemClass, "cls "), + DECL_TAG_ITEM(SystemString, "str "), + DECL_TAG_ITEM(NullObject, "nul "), + DECL_TAG_ITEM(Array, "[] "), + DECL_TAG_ITEM(Object, "o "), + DECL_TAG_ITEM(BoxedValue, "bval"), + + DECL_TAG_ITEM(UnmanagedPtr, "* "), + DECL_TAG_ITEM(ManagedPtr, "& "), + DECL_TAG_ITEM(MethodPtr, "fun "), + DECL_TAG_ITEM(VTablePtr, "vtb "), + + DECL_TAG_ITEM(CompressedSystemObject, "cob "), + DECL_TAG_ITEM(CompressedSystemClass, "ccl "), + DECL_TAG_ITEM(CompressedSystemString, "cst "), + DECL_TAG_ITEM(CompressedNullObject, "cnl "), + DECL_TAG_ITEM(CompressedArray, "c[] "), + DECL_TAG_ITEM(CompressedObject, "co "), + + DECL_TAG_ITEM(CompressedMethodPtr, "cfun"), + DECL_TAG_ITEM(CompressedVTablePtr, "cvtb"), + DECL_TAG_ITEM(OrNull, "ornl"), + + DECL_TAG_ITEM(VTablePtrObj, "vtb "), + DECL_TAG_ITEM(ITablePtrObj, "itb "), + DECL_TAG_ITEM(ArrayLength, "len "), + DECL_TAG_ITEM(ArrayElementType, "elem"), + DECL_TAG_ITEM(Singleton, "ston"), + DECL_TAG_ITEM(NumTypeTags, "XXXX"), }; static const uint32 type_tag_names_count = sizeof(type_tag_names)/sizeof(type_tag_names[0]); #ifdef _DEBUG static inline void checkArray() { - static bool doArrayCheck = true; - if( !doArrayCheck ) return; - doArrayCheck = false; - for( uint32 i=0; i<type_tag_names_count; i++ ) { - assert( (uint32)(type_tag_names[i].tag) == i ); - } + static bool doArrayCheck = true; + if( !doArrayCheck ) return; + doArrayCheck = false; + for( uint32 i=0; i<type_tag_names_count; i++ ) { + assert( (uint32)(type_tag_names[i].tag) == i ); + } } #else - #define checkArray() + #define checkArray() #endif Type::Tag Type::str2tag(const char * tagname) { - checkArray(); - - for( uint32 i=0; i<type_tag_names_count; i++ ) { - if( 0 == strcmpi(type_tag_names[i].name, tagname) ) { - return (Tag)i; // the map is ordered, thus '[i].tag == tag' - } - } - return InavlidTag; + checkArray(); + + for( uint32 i=0; i<type_tag_names_count; i++ ) { + if( 0 == strcmpi(type_tag_names[i].name, tagname) ) { + return (Tag)i; // the map is ordered, thus '[i].tag == tag' + } + } + return InavlidTag; } const char * Type::tag2str(Tag t) { - checkArray(); + checkArray(); - assert( t > 0 && t<NumTypeTags ); - return t > 0 && t<NumTypeTags ? type_tag_names[t].name : type_tag_names[NumTypeTags].name; + assert( t > 0 && t<NumTypeTags ); + return t > 0 && t<NumTypeTags ? type_tag_names[t].name : type_tag_names[NumTypeTags].name; } diff --git vm/jitrino/src/shared/Type.h vm/jitrino/src/shared/Type.h index 2d36335..eb98d38 100644 --- vm/jitrino/src/shared/Type.h +++ vm/jitrino/src/shared/Type.h @@ -83,7 +83,7 @@ public: TypedReference, // typed reference // (1.2) User-defined un-boxed value type - Value, // user-defined value type + Value, // user-defined value type // Offset type Offset, // offset into an object @@ -95,6 +95,7 @@ public: // (2.1.1) Built-in object types SystemObject, // System.Object + SystemClass, // System.Class SystemString, // System.String // special null object reference @@ -121,6 +122,7 @@ public: // (2.1.1) Built-in object types CompressedSystemObject, // System.Object + CompressedSystemClass, // System.Class CompressedSystemString, // System.String // special null object reference @@ -144,10 +146,11 @@ public: Singleton, NumTypeTags, - InavlidTag = NumTypeTags + InavlidTag = NumTypeTags }; Type(Tag t) : tag(t), id(++nextTypeId) {} virtual ~Type() {} + const Tag tag; bool isBuiltinValue() {return isBuiltinValue(tag); } bool isNumeric() {return isNumeric(tag); } @@ -175,6 +178,7 @@ public: bool isOffset() {return (tag == Type::Offset); } bool isOffsetPlusHeapbase() {return (tag == Type::OffsetPlusHeapbase); } bool isSystemObject() {return isSystemObject(tag); } + bool isSystemClass() {return isSystemClass(tag); } bool isSystemString() {return (tag == Type::SystemString);} bool isSignedInteger() {return isSignedInteger(tag);} bool isFloatingPoint() {return isFloatingPoint(tag);} @@ -272,6 +276,7 @@ public: static Tag compressReference(Tag tag) { switch (tag) { case SystemObject: return CompressedSystemObject; + case SystemClass: return CompressedSystemClass; case SystemString: return CompressedSystemString; case NullObject: return CompressedNullObject; case Array: return CompressedArray; @@ -285,6 +290,7 @@ public: static Tag unCompressReference(Tag tag) { switch (tag) { case CompressedSystemObject: return SystemObject; + case CompressedSystemClass: return SystemClass; case CompressedSystemString: return SystemString; case CompressedNullObject: return NullObject; case CompressedArray: return Array; @@ -306,11 +312,14 @@ public: return ((tag == Array) || (tag == CompressedArray));; } static bool isBuiltinObject(Tag tag) { - return (isSystemObject(tag) || isSystemString(tag)); + return (isSystemObject(tag) || isSystemClass(tag) || isSystemString(tag)); } static bool isSystemObject(Tag tag) { return ((tag == SystemObject) || (tag == CompressedSystemObject)); } + static bool isSystemClass(Tag tag) { + return ((tag == SystemClass) || (tag == CompressedSystemClass)); + } static bool isSystemString(Tag tag) { return ((tag == SystemString)||(tag == CompressedSystemString)); } @@ -333,18 +342,18 @@ public: return ((tag == VTablePtr)||(tag == CompressedVTablePtr)); } static const char* getPrintString(Tag); - /** - * Converts a string representation of a Tag to appropriate Tag. - * The search is case insensitive. - * Returns Tag::InavlidTag if no mapping found. - */ - static Tag str2tag(const char * tagname); - /** - * Converts a Tag into its string representation, i.e. "Void" or "UInt32". - * Never returns NULL, but pointer to string like "invalid type tag" instead. - * Don't mess with getPrintString() which returns a short 4-symbol abbreviation. - */ - static const char * tag2str(Tag tag); + /** + * Converts a string representation of a Tag to appropriate Tag. + * The search is case insensitive. + * Returns Tag::InavlidTag if no mapping found. + */ + static Tag str2tag(const char * tagname); + /** + * Converts a Tag into its string representation, i.e. "Void" or "UInt32". + * Never returns NULL, but pointer to string like "invalid type tag" instead. + * Don't mess with getPrintString() which returns a short 4-symbol abbreviation. + */ + static const char * tag2str(Tag tag); // Could locations containing values of these types be the same? static bool mayAlias(TypeManager*, Type*, Type*); @@ -369,8 +378,9 @@ class PtrType : public Type { public: PtrType(Type* t,bool isManagedPtr,ValueName array=NULL, ValueName index=NULL) : Type(isManagedPtr ? ManagedPtr : UnmanagedPtr), pointedToType(t), array(array), index(index) {} - PtrType* asPtrType() { return this; } virtual ~PtrType() {} + + PtrType* asPtrType() { return this; } Type* getPointedToType() {return pointedToType;} ValueName getArrayName() { return array; } ValueName getIndexName() { return index; } @@ -384,8 +394,9 @@ private: class FunctionPtrType : public Type { public: FunctionPtrType(bool isCompressed=false) : Type(isCompressed ? CompressedMethodPtr : MethodPtr) { } - FunctionPtrType* asFunctionPtrType() { return this; } virtual ~FunctionPtrType() {} + + FunctionPtrType* asFunctionPtrType() { return this; } virtual uint32 getNumParams() = 0; virtual Type* getParamType(uint32) = 0; virtual Type* getReturnType() = 0; @@ -397,6 +408,7 @@ public: MethodPtrType(MethodDesc* md, TypeManager& tm, bool isCompressed=false, ValueName obj=NULL) : FunctionPtrType(isCompressed), methodDesc(md), methodSig(md->getMethodSig()), typeManager(tm), object(obj) {} virtual ~MethodPtrType() {} + MethodPtrType* asMethodPtrType() { return this; } uint32 getNumParams() { return methodSig->getNumParams(); } Type* getParamType(uint32 i); @@ -417,6 +429,7 @@ public: VTablePtrType(Type* t, bool isCompressed=false) : Type(isCompressed? CompressedVTablePtr : VTablePtr), baseType(t) {} virtual ~VTablePtrType() {} + Type* getBaseType() {return baseType;} virtual void print(::std::ostream& os); private: @@ -438,6 +451,7 @@ public: NamedType* asNamedType() { return this; } bool needsInitialization(); + bool isFinalizable(); bool isBeforeFieldInit(); bool isLikelyExceptionType(); bool isVariableSizeType(); @@ -465,6 +479,7 @@ class UserValueType : public NamedType { public: UserValueType(void* td,TypeManager& tm) : NamedType(Value,td,tm) {} virtual ~UserValueType() {} + virtual const char* getName(); virtual const char* getNameQualifier(); // @@ -635,6 +650,7 @@ class TypeManager { public: TypeManager(MemoryManager& mm); virtual ~TypeManager() {} + void init(CompilationInterface &compInt); void init(); MemoryManager& getMemManager() {return memManager;} @@ -667,10 +683,12 @@ public: Type* getOffsetPlusHeapbaseType() {return &offsetPlusHeapbaseType;} ObjectType* getSystemStringType() {return theSystemStringType;} ObjectType* getSystemObjectType() {return theSystemObjectType;} + ObjectType* getSystemClassType() {return theSystemClassType;} Type* getCompressedNullObjectType() {return &compressedNullObjectType;} ObjectType* getCompressedSystemStringType(){return compressedSystemStringType;} ObjectType* getCompressedSystemObjectType(){return compressedSystemObjectType;} + ObjectType* getCompressedSystemClassType() {return compressedSystemClassType;} NamedType* getValueType(void* vmTypeHandle); ObjectType* getObjectType(void* vmTypeHandle, bool isCompressed=false); @@ -700,7 +718,7 @@ public: } return type; } - Type* getFunPtrType(Type* retType,uint32 numParams,Type** paramTypes) { + Type* getFunPtrType(Type* retType,uint32 numParams,Type** paramTypes) { assert(0); return NULL; } @@ -802,17 +820,17 @@ public: Type * convertToOldType(Type*); ObjectType* getObjectTypeFromAllocationHandle(void* vmAllocationHandle, bool isCompressed=false) - { - if (vmAllocationHandle==NULL) - return NULL; - void * vmTypeHandle = getTypeHandleFromAllocationHandle(vmAllocationHandle); - if ( vmTypeHandle==NULL - || vmTypeHandle>(void*)-100 - || ((POINTER_SIZE_INT)vmTypeHandle&0x3)!=0 ) { - return NULL; - } - return getObjectType(vmTypeHandle, isCompressed); - } + { + if (vmAllocationHandle==NULL) + return NULL; + void * vmTypeHandle = getTypeHandleFromAllocationHandle(vmAllocationHandle); + if ( vmTypeHandle==NULL + || vmTypeHandle>(void*)-100 + || ((POINTER_SIZE_INT)vmTypeHandle&0x3)!=0 ) { + return NULL; + } + return getObjectType(vmTypeHandle, isCompressed); + } private: MemoryManager& memManager; @@ -837,11 +855,13 @@ private: ValueType typedReference; ObjectType* theSystemStringType; ObjectType* theSystemObjectType; + ObjectType* theSystemClassType; Type nullObjectType; Type offsetType; Type offsetPlusHeapbaseType; ObjectType* compressedSystemStringType; ObjectType* compressedSystemObjectType; + ObjectType* compressedSystemClassType; Type compressedNullObjectType; // hashtable for user-defined object and value types PtrHashTable<NamedType> userValueTypes; @@ -878,6 +898,7 @@ public: // virtual void* getBuiltinValueTypeVMTypeHandle(Type::Tag) = 0; virtual void* getSystemObjectVMTypeHandle() = 0; + virtual void* getSystemClassVMTypeHandle() = 0; virtual void* getSystemStringVMTypeHandle() = 0; virtual void* getArrayVMTypeHandle(void* elemVMTypeHandle,bool isUnboxed) = 0; virtual const char* getTypeName(void* vmTypeHandle) = 0; @@ -886,7 +907,7 @@ public: virtual const char* getMethodName(MethodDesc*) = 0; virtual void* getArrayElemVMTypeHandle(void* vmTypeHandle) = 0; virtual bool isArrayType(void* vmTypeHandle) = 0; - virtual bool isArrayOfUnboxedElements(void* vmTypeHandle) = 0; + virtual bool isArrayOfPrimitiveElements(void* vmTypeHandle) = 0; virtual bool isEnumType(void* vmTypeHandle) = 0; virtual bool isValueType(void* vmTypeHandle) = 0; virtual bool isFinalType(void* vmTypeHandle) = 0; @@ -895,7 +916,9 @@ public: virtual bool isAbstractType(void* vmTypeHandle) = 0; virtual bool isSystemStringType(void* vmTypeHandle) = 0; virtual bool isSystemObjectType(void* vmTypeHandle) = 0; + virtual bool isSystemClassType(void* vmTypeHandle) = 0; virtual bool needsInitialization(void* vmTypeHandle) = 0; + virtual bool isFinalizable(void* vmTypeHandle) = 0; virtual bool isBeforeFieldInit(void* vmTypeHandle) = 0; virtual bool isInitialized(void* vmTypeHandle) = 0; virtual bool isVariableSizeType(void* vmTypeHandle) = 0; @@ -915,7 +938,7 @@ public: virtual uint32 getVTableOffset() = 0; virtual void* getTypeHandleFromAllocationHandle(void* vmAllocationHandle) = 0; - + }; } //namespace Jitrino diff --git vm/jitrino/src/shared/XTimer.cpp vm/jitrino/src/shared/XTimer.cpp index 86897a5..739f70e 100644 --- vm/jitrino/src/shared/XTimer.cpp +++ vm/jitrino/src/shared/XTimer.cpp @@ -23,12 +23,21 @@ #include "XTimer.h" #ifdef _WIN32 -#include <windows.h> +#pragma pack(push) + #include <windows.h> + #define snprintf _snprintf +#pragma pack(pop) + +#include <algorithm> + #define TIMERS_IMPLEMENTED //#define USE_THREAD_TIMER #endif +using namespace std; + + namespace Jitrino { @@ -41,28 +50,28 @@ void XTimer::initialize (bool on) { #ifdef TIMERS_IMPLEMENTED - if (!enabled && on) - { - enabled = true; + if (!enabled && on) + { + enabled = true; #ifdef USE_THREAD_TIMER - frequency = 10000000; + frequency = 10000000; #else - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - frequency = (double)freq.QuadPart; + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + frequency = (double)freq.QuadPart; #endif - XTimer xt; - correction = 0; - xt.start(); xt.stop(); - xt.start(); xt.stop(); - xt.start(); xt.stop(); - xt.start(); xt.stop(); - correction = xt.totalTime/4; - } + XTimer xt; + correction = 0; + xt.start(); xt.stop(); + xt.start(); xt.stop(); + xt.start(); xt.stop(); + xt.start(); xt.stop(); + correction = xt.totalTime/4; + } - enabled = on; + enabled = on; #endif //#ifdef TIMERS_IMPLEMENTED } @@ -108,9 +117,9 @@ void XTimer::reset () // void XTimer::start () { - if (enabled) - if (state++ == 0) - startTime = getCounter(); + if (enabled) + if (state++ == 0) + startTime = getCounter(); } @@ -119,18 +128,18 @@ void XTimer::start () // void XTimer::stop () { - if (enabled) - if (--state == 0) - totalTime += getCounter() - startTime - correction; + if (enabled) + if (--state == 0) + totalTime += getCounter() - startTime - correction; } double XTimer::getSeconds() const { - if (enabled) - return (((double)totalTime) / frequency); - else - return 0; + if (enabled) + return (((double)totalTime) / frequency); + else + return 0; } @@ -142,4 +151,40 @@ double XTimer::getFrequency() */ +void SummTimes::add (const char* key, double seconds) +{ + for (iterator ptr = begin(); ptr != end(); ++ptr) + if (strcmp(ptr->first, key) == 0) + { + ptr->second += seconds; + return; + } + + push_back(value_type(key, seconds)); +} + + +#ifdef _WIN32 +static bool compare (SummTimes::value_type& a, SummTimes::value_type& b) +{ + return strcmp(a.first, b.first) < 0; +} +#endif + + +void SummTimes::write (CountWriter& logs) +{ +#ifdef _WIN32 + sort(begin(), end(), compare); +#endif + + char temp[100]; + for (iterator ptr = begin(); ptr != end(); ++ptr) + { + snprintf(temp, sizeof(temp), "action %s time", ptr->first); + logs.write(temp, ptr->second); + } +} + + } //namespace Jitrino diff --git vm/jitrino/src/shared/XTimer.h vm/jitrino/src/shared/XTimer.h index a827e35..2e74ac8 100644 --- vm/jitrino/src/shared/XTimer.h +++ vm/jitrino/src/shared/XTimer.h @@ -25,6 +25,7 @@ #define _XTIMER_H_ #include "Counter.h" #include "open/types.h" //typedef unsigned long long in64; +#include <vector> namespace Jitrino @@ -35,22 +36,22 @@ class XTimer { public: - XTimer () : totalTime(0), state(0) {} + XTimer () : totalTime(0), state(0) {} - static void initialize (bool on); + static void initialize (bool on); - void reset (); - void start (); - void stop (); - int64 getTotal () const {return totalTime;} - double getSeconds () const; + void reset (); + void start (); + void stop (); + int64 getTotal () const {return totalTime;} + double getSeconds () const; - //static double getFrequency (); + //static double getFrequency (); protected: int64 startTime, - totalTime; + totalTime; int state; }; @@ -59,10 +60,10 @@ class CountTime : public CounterBase, pu { public: - CountTime (const char* s) : CounterBase(s) {} - virtual ~CountTime () {} + CountTime (const char* name) : CounterBase(name) {} + virtual ~CountTime () {} - /*virtual*/void write (CountWriter& logs) {logs.write(key, getSeconds());} + /*virtual*/void write (CountWriter& logs) {logs.write(key, getSeconds());} }; @@ -70,12 +71,22 @@ class AutoTimer { public: - AutoTimer (CountTime& c) :counter(c) {counter.start();} - ~AutoTimer () {counter.stop();} + AutoTimer (CountTime& c) :counter(c) {counter.start();} + ~AutoTimer () {counter.stop();} protected: - CountTime& counter; + CountTime& counter; +}; + + +struct SummTimes : public std::vector<std::pair<const char*, double> >, public CounterBase +{ + SummTimes (const char* name) : CounterBase(name) {} + + void add (const char* key, double seconds); + + /*virtual*/void write (CountWriter&); }; diff --git vm/jitrino/src/shared/methodtable.cpp vm/jitrino/src/shared/methodtable.cpp index 70e3680..9ea88c9 100644 --- vm/jitrino/src/shared/methodtable.cpp +++ vm/jitrino/src/shared/methodtable.cpp @@ -367,11 +367,11 @@ Method_Table::Method_Table(const char *d } bool Method_Table::accept_this_method(MethodDesc &md) { - const char* classname = md.getParentType()->getName(); - const char *methodname = md.getName(); - const char *signature = md.getSignatureString(); + const char* classname = md.getParentType()->getName(); + const char *methodname = md.getName(); + const char *signature = md.getSignatureString(); - return accept_this_method(classname, methodname, signature); + return accept_this_method(classname, methodname, signature); } bool Method_Table::accept_this_method(const char* classname, const char *methodname, const char *signature) @@ -415,7 +415,7 @@ bool Method_Table::accept_this_method(co } bool Method_Table::is_in_list_generation_mode() { - return _dump_to_file; + return _dump_to_file; } } //namespace Jitrino diff --git vm/jitrino/src/shared/mkernel.cpp vm/jitrino/src/shared/mkernel.cpp index 8642009..668ee66 100644 --- vm/jitrino/src/shared/mkernel.cpp +++ vm/jitrino/src/shared/mkernel.cpp @@ -19,16 +19,162 @@ */ /** * @file - * @brief Contains implementation of utilities declared in #mkernel.h. + * @brief Implementation of utilities declared in #mkernel.h. */ #include "mkernel.h" -#ifdef PLATFORM_POSIX +#ifdef _WIN32 + #include <map> + using std::map; +#else #include <unistd.h> + #include <pthread.h> #endif namespace Jitrino { +#ifdef _WIN32 +typedef void (*RELEASE_FPTR)(void *); +class FMAP : public map<TlsKey, RELEASE_FPTR>, public Mutex +{}; + +/** + * Creates, initializes and caches the map to store RELEASE_FPTS functions. + * + * As the allocKey() and thus release function registration is done from + * few static initializers, then this separate getter function instead of + * static FMAP - to ensure no problems with static initializers. + * + * The dynamic allocation is for the same reason, to avoid static + * destructors conflict (e.g. if Tls::releaseKey is called after the ~FMAP). + * + */ +static FMAP* get_fmap(void) +{ + static FMAP * fmap = NULL; + if (fmap == NULL) { + fmap = new FMAP(); + } + return fmap; +} +#endif // ~ifdef _WIN32 + +TlsKey Tls::allocKey(void (*free_func) (void *)) +{ +#ifdef _WIN32 + DWORD key = TlsAlloc(); + assert(key != TLS_OUT_OF_INDEXES); + if (free_func != NULL) { + FMAP& fmap = *get_fmap(); + fmap.lock(); + fmap[key] = free_func; + fmap.unlock(); + } +#else + pthread_key_t key; + int res = pthread_key_create(&key, free_func); + assert(!res); res = res; +#endif + return (TlsKey)key; +} + +void Tls::releaseKey(TlsKey key) +{ +#ifdef _WIN32 + BOOL res = TlsFree((DWORD)key); + FMAP& fmap = *get_fmap(); + fmap.lock(); + if (fmap.find(key) != fmap.end()) { + fmap.erase(key); + } + fmap.unlock(); + assert(res); res = res; +#else + int res = pthread_key_delete(key); + assert(!res); res = res; +#endif +} +#ifdef _WIN32 +void Tls::threadDetach(void) +{ + FMAP& fmap = *get_fmap(); + fmap.lock(); + for(FMAP::iterator i=fmap.begin(); i != fmap.end(); i++) { + TlsKey key = i->first; + void* data = Tls::get(key); + if (data != NULL) { + Tls::put(key, NULL); + i->second(data); + } + } + fmap.unlock(); +} + +void Tls::processDetach(void) +{ + FMAP* fmap = get_fmap(); + delete fmap; +} + +#endif + +void Tls::put(TlsKey key, void* pval) +{ +#ifdef _WIN32 + BOOL res = TlsSetValue((DWORD)key, pval); + assert(res); res = res; +#else + int res = pthread_setspecific((pthread_key_t)key, pval); + assert(!res); res = res; +#endif +} + +void* Tls::get(TlsKey key) +{ +#ifdef _WIN32 + void * pval = TlsGetValue((DWORD)key); + assert(pval != NULL || GetLastError() == NO_ERROR); +#else + void * pval = pthread_getspecific((pthread_key_t)key); +#endif + return pval; +} + +void TlsList::push(TlsKey key, void * pval) +{ + ListItem* top = (ListItem*)Tls::get(key); + ListItem* thiz = new ListItem(top, pval); + Tls::put(key, thiz); +} + +void* TlsList::pop(TlsKey key) +{ + ListItem* top = (ListItem*)Tls::get(key); + void * data = NULL; + if (top != NULL) { + data = top->data; + Tls::put(key, top->prev); + delete top; + } + else { + // pop on empty stack + assert(false); + } + return data; +} + +void* TlsList::get(TlsKey key) +{ + ListItem* top = (ListItem*)Tls::get(key); + // get() on empty stack - unexpected and wrong usage. + assert(top != NULL); +#ifdef _DEBUG + assert(top->magic == ListItem::MAGIC); +#endif + return top->data; +} + + const unsigned Runtime::num_cpus = Runtime::init_num_cpus(); unsigned Runtime::init_num_cpus(void) diff --git vm/jitrino/src/shared/mkernel.h vm/jitrino/src/shared/mkernel.h index d5d4470..d8d0b86 100644 --- vm/jitrino/src/shared/mkernel.h +++ vm/jitrino/src/shared/mkernel.h @@ -27,17 +27,33 @@ #if !defined(__MKERNEL_H_INCLUDED__) #define __MKERNEL_H_INCLUDED__ -#ifdef PLATFORM_POSIX -#include <pthread.h> -#include <semaphore.h> +#ifdef _WIN32 + // windows.h include introduces min/max defines, which conflicts + // with STL's min/max used in many other places. This define prevents + // them to appear. + #define NOMINMAX 1 + // windows.h enforces its own aligment, which may conflict with + // currently used default one. + // Note: EVERY inclusion of windows.h in Jitrino must be surrounded + // with \#pragma pack(push/pop) + #pragma pack(push) + // <winsock2.h> must be included before <windows.h> to avoid + // compile-time errors with winsock.h. For more details, see: + //www.microsoft.com/msdownload/platformsdk/ .. + // .. sdkupdate/2600.2180.7/contents.htm + #include <winsock2.h> + #include <windows.h> + #define vsnprintf _vsnprintf + #pragma pack(pop) + // ... well, just to be absolutely sure... + #undef min + #undef max #else -// <winsock2.h> must be included before <windows.h> to avoid compile-time -// errors with winsock.h. For more details, see: -//www.microsoft.com/msdownload/platformsdk/sdkupdate/2600.2180.7/contents.htm -#include <winsock2.h> -#include <windows.h> - + #include <pthread.h> + #include <semaphore.h> #endif +#include <assert.h> + namespace Jitrino { @@ -64,7 +80,7 @@ namespace Jitrino { * @note On Windows platform the underlying OS object is not Mutex, but * CriticalSection instead, as it's a bit lighter and faster. * - * @see #AutoUnlock + * @see AutoUnlock */ class Mutex { #ifdef PLATFORM_POSIX @@ -125,7 +141,8 @@ #endif // ~ifdef PLATFORM_POSIX }; /** - * @brief Automatically unlocks a #Mutex when goes out of scope. + * @brief Automatically unlocks a Mutex when AutoLock object goes out of + * scope. * * Class AutoUnlock is an utility class to handy acquire and [automagically] * release Mutex lock. @@ -240,6 +257,314 @@ private: Runtime& operator=(const Runtime&); }; +/** + * @brief Key used to identify data in TLS. + */ +typedef unsigned long TlsKey; + +/** + * @brief Basic thread local storage (TLS) functionality. + * + * The functionality is made similar to the POSIX one - when a TLS key + * allocated, user may specify a function (<i>release function</i>) which + * will be called on thread's death to release the data stored in TLS. + * + * With POSIX threads this functionality is by design. On Windows, this + * functionality is emulated by the Tls class. + * + * The emulation's behavior was made as much close to the one specified by + * POSIX, though some differences still exist. + * + * - the release function is called only if data currently stored in TLS + * is not NULL + * - NULL value is associated with TLS key before calling release function + * - (the difference) if release function re-associates a data with the TLS + * key, this data is ignored (in other words, release function is called + * no more than once for each thread) + * + * @note Emulation on Windows requires external support - currently special + * method Tls::threadEnd is called on DLL_THREAD_DETACH. As our code lives + * in dll it's enough for all our needs. If the code (and especially the + * release function behaviour) need to be reused for a threads in process, + * the Tls::threadEnd() must be called at the end of thread function. + */ +class Tls { +public: + /** + * @brief Allocates a key for TLS. + * + * Initial value associated with each key in NULL. + * + * @param free_func - a function will be called when thread is about to + * finish, so it can free up the data stored in TLS. See Tls class + * comments. + */ + static TlsKey allocKey(void (*free_func) (void *) = NULL); + /** + * @brief Releases the TlsKey. + */ + static void releaseKey(TlsKey key); +#ifdef _WIN32 + /** + * @brief Special-purpose method - used to emulate POSIX-like behavior + * with release function that may free up a data stored in TLS. + * + * Must be called when thread is about to finish. + */ + static void threadDetach(void); + /** + * @brief Special-purpose method - used to cleanup dynamically + * allocated map. + * + * Must be called when thread is about to finish. + */ + static void processDetach(void); +#endif + /** + * @brief Puts \c data into TLS. + */ + static void put(TlsKey key, void* data); + /** + * @brief Gets \c data from TLS. + * + * If there were no preceding put() operations in the current thread, + * NULL returned. + */ + static void* get(TlsKey key); +}; + +/** + * A handy wrapper to organize TLS storage, with auto-<i>magic</i> release + * of allocated data. + * + * TlsStorage is used to manage a thread-local copy of data that exists + * in a <i>single copy per each thread</i>. Here it differs from TlsList + * and TlsStack that organize a thread local stack storage of several + * instances of a data. + * + * The TlsStore presumes that a data stored in it is dynamically allocated + * using <code>global operator new</code>. Upon a thread termination, a + * non-<b>NULL</b> data is deallocated using <code>global operator + * delete</code>. + * + * + * Usage example: + * <pre> + * <code> + * static TlsStore<SomeStruct> globalStore; + * + * foo() + * { + * SomeStruct* data = globalStore.get(); + * if (data == NULL) { + * data = new SomeStru(); + * data->init(); + * globalStore.put(data); + * } + * + * } + * </code> + * </pre> + */ +template <class T> struct TlsStore { + /** + * @brief Allocates a TlsKey to be used for TLS manipulations. + */ + TlsStore() + { + m_key = Tls::allocKey(free); + } + + /** + * @brief Releases TlsKey. + */ + ~TlsStore() + { + Tls::releaseKey(m_key); + } + + /** + * @brief Returns the stored data or NULL if there were no data stored. + */ + T* get(void) const + { + return (T*)Tls::get(m_key); + } + /** + * @brief Stores the data into TLS, \b NULL-s are ok. + * + * If there were a data stored before, the previous data is freed. + */ + void put(T* pt) const + { + T* prev = get(); + if (prev != NULL) { + free(prev); + } + Tls::put(m_key, pt); + } + /** + * Releases the data (calls delete) + * + * The method is invoked upon a thread termination to deallocate + * data stored in TLS. + */ + static void free(void* p) + { + delete (T*)p; + } +private: + TlsKey m_key; +}; + + +/** + * @brief Provides basic functionality to organize stack of infos in TLS. + * + * <code> + * <pre> + * TlsKey globalKey = Tls::allocKey(NULL); + * foo() + * { + * SomeStru fooLocalData; + * TlsList::push(globalKey, &fooLocalData); + * boo(); + * TlsList::pop(globalKey); + * } + * + * boo() + * { + * SomeStru* data = (SomeStru*)TlsList::get(globalKey); + * // do something + * } + * </pre> + * </code> + * + * \c foo() may be called in the same thread several times, and every time + * the latest data will be available for \c boo(). + * + * @note Number of \c pop()-s must be strictly balanced with the number of + * push()-es, or a memory leak occurs. + * + * @note TlsList really stores its special data into TLS, so never mix + * calls of Tls::put()/Tls::get() with TlsList's methods with the same + * key. + * + * Normally, the TlsList may be used to store a pointer to general data, + * while for a particular data structures the template class TlsStack may + * be more convinient. + * + * @see TlsStack + */ +class TlsList { +public: +public: + /** + * @brief Pushes the \c data onto TLS stack. + */ + static void push(TlsKey key, void* data); + /** + * @brief Pops out the \c data from TLS stack. + */ + static void* pop(TlsKey key); + /** + * @brief Returns top data item from TLS stack and leaves it on stack. + */ + static void* get(TlsKey key); +private: + /** + * Helper structure to organize linked list of datas in TLS. + */ + struct ListItem + { + ListItem(ListItem* _prev, void* _data) + { + prev = _prev; + data = _data; +#ifdef _DEBUG + magic = MAGIC; +#endif + } + +#ifdef _DEBUG + /** + * @brief A signature, used to verify data integrity. + */ + unsigned magic; + static const unsigned MAGIC = 0x4C495354; // 'LIST' in hex + ~ListItem() + { + assert(magic == MAGIC); + } +#endif + void * data; + ListItem* prev; + }; +}; + +/** + * @brief Handy wrapper for TlsList. + * + * Use as following: + * + * <code> + * TlsStack<SomeStruct> globalSomeStructStack; // must be static global + * </code> + * + * @note Note the declaration in the example. It's the type itself, and not + * the pointer - methods os TlsStack do \b not copy data. Instead only + * pointer to the specified data is stored. + * + * The result is that the stored data must be have it's scope not less than + * appropriate push/pop sequence. + */ +template<class AType> class TlsStack { +public: + /** + * @brief Allocates a TlsKey to be used for TLS manipulations. + */ + TlsStack(void) + { + m_key = Tls::allocKey(); + } + /** + * @brief Releases TlsKey. + */ + ~TlsStack() + { + Tls::releaseKey(m_key); + } + /** + * @brief Pushes the \c item onto TLS stack. + */ + void push(AType& item) + { + push(&item); + } + /** + * @brief Pushes the \c pitem onto TLS stack. + */ + void push(AType* pitem) + { + TlsList::push(m_key, pitem); + } + /** + * @brief Returns top data item from TLS stack and leaves it on stack. + */ + AType* get(void) + { + return (AType*)TlsList::get(m_key); + } + /** + * @brief Pops out the an item from TLS stack. + */ + AType* pop(void) + { + return (AType*)TlsList::pop(m_key); + } +private: + TlsKey m_key; +}; }; // ~namespace Jitrino diff --git vm/jitrino/src/translator/ByteCodeParser.h vm/jitrino/src/translator/ByteCodeParser.h index f98ec2d..d6c7690 100644 --- vm/jitrino/src/translator/ByteCodeParser.h +++ vm/jitrino/src/translator/ByteCodeParser.h @@ -31,6 +31,7 @@ namespace Jitrino { class ByteCodeParserCallback { public: virtual ~ByteCodeParserCallback() {} + // parses one byte code starting at given offset, // updates nextOffset to point at next byte code, // returns false if parsing should stop diff --git vm/jitrino/src/translator/ExceptionInfo.cpp vm/jitrino/src/translator/ExceptionInfo.cpp index 8e87603..51dc05c 100644 --- vm/jitrino/src/translator/ExceptionInfo.cpp +++ vm/jitrino/src/translator/ExceptionInfo.cpp @@ -27,10 +27,10 @@ #include "ExceptionInfo.h" namespace Jitrino { CatchHandler::CatchHandler(uint32 id, - uint32 beginOffset, - uint32 endOffset, - CatchBlock* tryBlock, - Type* excType) + uint32 beginOffset, + uint32 endOffset, + CatchBlock* tryBlock, + Type* excType) : Handler(id,beginOffset,endOffset,tryBlock), exceptionType(excType), nextHandler(NULL) {} diff --git vm/jitrino/src/translator/ExceptionInfo.h vm/jitrino/src/translator/ExceptionInfo.h index 460860f..d9602c4 100644 --- vm/jitrino/src/translator/ExceptionInfo.h +++ vm/jitrino/src/translator/ExceptionInfo.h @@ -30,6 +30,7 @@ class LabelInst; class ExceptionInfo { public: virtual ~ExceptionInfo() {} + uint32 getId() {return id;} uint32 getBeginOffset(){return beginOffset;} uint32 getEndOffset() {return endOffset;} @@ -67,6 +68,7 @@ public: ExceptionInfo* _tryBlock) : ExceptionInfo(id,beginOffset,endOffset), tryBlock(_tryBlock) {} virtual ~Handler() {} + uint32 getTryRegionId() {return tryBlock->getId();} ExceptionInfo* getTryBlock() {return tryBlock;} private: @@ -105,6 +107,7 @@ public: uint32 exceptionIndex) : ExceptionInfo(id,beginOffset,endOffset), handlers(NULL), excTableIndex(exceptionIndex) {} virtual ~CatchBlock() {} + bool isCatchBlock() {return true;} uint32 getExcTableIndex() { return excTableIndex; } void addHandler(CatchHandler* handler) { diff --git vm/jitrino/src/translator/TranslatorIntfc.cpp vm/jitrino/src/translator/TranslatorIntfc.cpp index e6ed327..7a1eac8 100644 --- vm/jitrino/src/translator/TranslatorIntfc.cpp +++ vm/jitrino/src/translator/TranslatorIntfc.cpp @@ -28,224 +28,119 @@ #include "JavaTranslator.h" #include "irmanager.h" #include "IRBuilder.h" #include "simplifier.h" -#include "PropertyTable.h" #include "Log.h" #include "methodtable.h" #include "CompilationContext.h" +#include "FlowGraph.h" namespace Jitrino { -void TranslatorIntfc::readFlagsFromCommandLine(CompilationContext* cs, bool ia32Cg) -{ - JitrinoParameterTable* params = cs->getThisParameterTable(); - TranslatorFlags& flags = *cs->getTranslatorFlags(); - flags.propValues = params->lookupBool("tra::propValues", true); - bool defaultGenCharArrayCopy = ia32Cg ? false : true; - flags.genCharArrayCopy = params->lookupBool("tra::genCharArrayCopy", - defaultGenCharArrayCopy); - flags.onlyBalancedSync = params->lookupBool("tra::balancedSync", false); - -#ifdef _IPF_ - flags.optArrayInit = params->lookupBool("tra::optArrayInit", false); -#else - flags.optArrayInit = params->lookupBool("tra::optArrayInit", true); -#endif - flags.ignoreSync = params->lookupBool("tra::ignoreSync",false); - flags.syncAsEnterFence = params->lookupBool("tra::syncAsEnterFence",false); - flags.newCatchHandling = params->lookupBool("tra::newCatchHandling",true); - flags.inlineMethods = params->lookupBool("tra::inlineMethods", true); - - flags.guardedInlining = params->lookupBool("tra::guardedInlining", true); - // - // see optimizer.cpp for additional info about the "client" option - // - if ( params->lookupBool("client", false) ) { - flags.guardedInlining = false; - } - - flags.magicMinMaxAbs = params->lookupBool("tra::magicMinMaxAbs", false); - flags.genMinMaxAbs = params->lookupBool("tra::genMinMaxAbs", false); - flags.genFMinMaxAbs = params->lookupBool("tra::genFMinMaxAbs", false); - const char* skipMethods = params->lookup("opt::inline::skip_methods"); - if(skipMethods == NULL) { - flags.inlineSkipTable = NULL; - } else { - flags.inlineSkipTable = new Method_Table(strdup(skipMethods), "SKIP_METHODS", true); - } - flags.magicClass=(char *)params->lookup("tra::useMagicMethods"); //NULL if not specified +void TranslatorSession::run () { + TranslatorAction* action = (TranslatorAction*)getAction(); + flags = action->getFlags(); + translate(); + postTranslatorCleanup(); } -void TranslatorIntfc::showFlagsFromCommandLine() -{ - Log::out() << " tra::inlineMethods[={ON|off}] = bytecode inlining" << ::std::endl; - Log::out() << " tra::propValues[={ON|off}] = propagate values during translation" << ::std::endl; - Log::out() << " tra::guardedInlining[={on|OFF}] = do guarded inlining during translation" << ::std::endl; - Log::out() << " tra::genCharArrayCopy[={on|off}] = generate intrinsic calls to char array copy" << ::std::endl; - Log::out() << " tra::useMagicMethods[={MagicClass name}] = use magic methods with magic class named MagicClass"<< ::std::endl; - Log::out() << " tra::balancedSync[={on|OFF}] = treat all synchronization as balanced" << ::std::endl; - Log::out() << " tra::ignoreSync[={on|OFF}] = do not generate synchronization" << ::std::endl; - Log::out() << " tra::syncAsEnterFence[={on|OFF}] = implement synchronization as monitor enter fence" << ::std::endl; - Log::out() << " tra::magicMinMaxAbs[={on|OFF}] = treat java/lang/Math::min and max as magic"<< ::std::endl; - Log::out() << " tra::genMinMaxAbs[={on|OFF}] = use special opcodes for Min/Max/Abs, rather than using Select"<< ::std::endl; - Log::out() << " tra::genFMinMaxAbs[={on|OFF}] = also use opcodes for float Min/Max/Abs, rather than using Select"<< ::std::endl; +// this is the regular routine to be used to generate IR for a method +void TranslatorSession::translate() { + CompilationContext* cc = getCompilationContext(); + IRManager* irm = cc->getHIRManager(); + assert(irm); + MethodDesc& methodDesc = irm->getMethodDesc(); + if (methodDesc.isJavaByteCodes()) { + //create IRBuilder + MemoryManager& mm = cc->getCompilationLevelMemoryManager(); + TranslatorAction* myAction = (TranslatorAction*)getAction(); + IRBuilder* irb = (IRBuilder*)myAction->getIRBuilderAction()->createSession(mm); + irb->setCompilationContext(cc); + MemoryManager tmpMM(1024, "IRBuilder::tmpMM"); + irb->init(irm, &flags, tmpMM); + JavaTranslator::translateMethod(*cc->getVMCompilationInterface(), methodDesc, *irb); + } else { + assert(false); + } } -void IRBuilder::readFlagsFromCommandLine(CompilationContext* cs) -{ - JitrinoParameterTable* params = cs->getThisParameterTable(); - IRBuilderFlags &irBuilderFlags = *cs->getIRBuilderFlags(); - - // - // IRBuilder expansion flags - // - irBuilderFlags.expandMemAddrs = params->lookupBool("irb::expandMemAddrs", true); - irBuilderFlags.expandElemAddrs = params->lookupBool("irb::expandElemAddrs", true); - irBuilderFlags.expandCallAddrs = params->lookupBool("irb::expandCallAddrs", false); - irBuilderFlags.expandVirtualCallAddrs = params->lookupBool("irb::expandVirtualCallAddrs", true); - irBuilderFlags.expandNullChecks = params->lookupBool("irb::expandNullChecks", true); - irBuilderFlags.expandElemTypeChecks = params->lookupBool("irb::expandElemTypeChecks", true); - - // - // IRBuilder translation-time optimizations - // - irBuilderFlags.doCSE = params->lookupBool("irb::doCSE", true); - irBuilderFlags.doSimplify = params->lookupBool("irb::doSimplify", true); - - irBuilderFlags.suppressCheckBounds = params->lookupBool("irb::suppressCheckBounds", false); - - irBuilderFlags.insertMethodLabels = params->lookupBool("irb::insertMethodLabels", true); - irBuilderFlags.compressedReferences = params->lookupBool("irb::compressedReferences", false); - - irBuilderFlags.genMinMaxAbs = params->lookupBool("tra::genMinMaxAbs", false); - irBuilderFlags.genFMinMaxAbs = params->lookupBool("tra::genFMinMaxAbs", false); - - irBuilderFlags.useNewTypeSystem = params->lookupBool("tra::useNewTypeSystem", false); +void TranslatorSession::postTranslatorCleanup() { + IRManager* irm = getCompilationContext()->getHIRManager(); + ControlFlowGraph& flowGraph = irm->getFlowGraph(); + MethodDesc& methodDesc = irm->getMethodDesc(); + if (Log::isEnabled()) { + Log::out() << "PRINTING LOG: After Translator" << std::endl; + FlowGraph::printHIR(Log::out(), flowGraph, methodDesc); + } + FlowGraph::doTranslatorCleanupPhase(*irm); + if (Log::isEnabled()) { + Log::out() << "PRINTING LOG: After Cleanup" << std::endl; + FlowGraph::printHIR(Log::out(), flowGraph, methodDesc); + } } -void IRBuilder::showFlagsFromCommandLine() -{ - // - // IRBuilder expansion flags - // - Log::out() << " irb::expandMemAddrs[={ON|off}] = ?" << ::std::endl; - Log::out() << " irb::expandElemAddrs[={ON|off}] = ?" << ::std::endl; - Log::out() << " irb::expandCallAddrs[={on|OFF}] = ?" << ::std::endl; - Log::out() << " irb::expandVirtualCallAddrs[={ON|off}] = ?" << ::std::endl; - Log::out() << " irb::expandNullChecks[={ON|off}] = ?" << ::std::endl; - Log::out() << " irb::expandElemTypeChecks[={ON|off}] = ?" << ::std::endl; - // - // IRBuilder translation-time optimizations - // - Log::out() << " irb::doCSE[={ON|off}] = ?" << ::std::endl; - Log::out() << " irb::doSimplify[={ON|off}] = ?" << ::std::endl; - - Log::out() << " irb::suppressCheckBounds[={on|OFF}] = omit all bounds checks" << ::std::endl; +static const char* help = \ + " inlineMethods[={ON|off}] - bytecode inlining\n"\ + " propValues[={ON|off}] - propagate values during translation\n"\ + " guardedInlining[={on|OFF}] - do guarded inlining during translation\n"\ + " genCharArrayCopy[={on|off}] - generate intrinsic calls to char array copy\n"\ + " genArrayCopy[={ON|off}] - inline java/lang/System::arraycopy call\n"\ + " useMagicMethods[={MagicClass name}] - use magic methods with magic class named MagicClass\n"\ + " balancedSync[={on|OFF}] - treat all synchronization as balanced\n"\ + " ignoreSync[={on|OFF}] - do not generate synchronization\n"\ + " syncAsEnterFence[={on|OFF}] - implement synchronization as monitor enter fence\n"\ + " magicMinMaxAbs[={on|OFF}] - treat java/lang/Math::min and max as magic\n"\ + " genMinMaxAbs[={on|OFF}] - use special opcodes for Min/Max/Abs\n"\ + " genFMinMaxAbs[={on|OFF}] - also use opcodes for float Min/Max/Abs\n"; - Log::out() << " irb::insertMethodLabels[={on|OFF}] = ?" << ::std::endl; - Log::out() << " irb::compressedReferences[={on|OFF}] = force compressed references\n"; -} -static void -InitIRBuilderFlags(CompilationInterface& compilationInterface, - MethodDesc& methodDesc) { - // - // Flags from compilation environment - // - IRBuilderFlags& irBuilderFlags = *compilationInterface.getCompilationContext()->getIRBuilderFlags(); - irBuilderFlags.insertWriteBarriers = compilationInterface.insertWriteBarriers(); - irBuilderFlags.compressedReferences = irBuilderFlags.compressedReferences || compilationInterface.areReferencesCompressed(); -} -// -// this is the regular routine to be used to generate IR for a method -// -void -TranslatorIntfc::translateByteCodes(IRManager& irManager) { - CompilationInterface& compilationInterface = irManager.getCompilationInterface(); - MethodDesc &methodDesc = irManager.getMethodDesc(); - //assert(flags); - //assert(IRBuilder::flagsFromCommandLine); - InitIRBuilderFlags(compilationInterface,irManager.getMethodDesc()); +static ActionFactory<TranslatorSession, TranslatorAction> _translator("translator", help); - IRBuilder irBuilder(irManager); - if (methodDesc.isJavaByteCodes()) { - JavaTranslator javaTranslator; - javaTranslator.translateMethod(compilationInterface, - methodDesc, - irBuilder); - } else { - assert(false); - } -} +void TranslatorAction::init() { + readFlags(); + MemoryManager& mm = getJITInstanceContext().getGlobalMemoryManager(); + irbAction = (IRBuilderAction*)createAuxAction(mm, IRBUILDER_ACTION_NAME, "irbuilder"); + irbAction->init(); +} -// -// this is the routine to be used to generate IR for an inlined method -// -void -TranslatorIntfc::translateByteCodesInline(IRManager& irManager, - uint32 numArgs, Opnd** argOpnds, uint32 inlineDepth) { - CompilationInterface& compilationInterface = irManager.getCompilationInterface(); - MethodDesc& methodDesc = irManager.getMethodDesc(); +void TranslatorAction::readFlags() { + flags.propValues = getBoolArg("propValues", true); +#if defined(_IPF_) + flags.genCharArrayCopy = getBoolArg("genCharArrayCopy", true); + flags.optArrayInit = getBoolArg("optArrayInit", false); +#else + flags.genCharArrayCopy = getBoolArg("genCharArrayCopy", false); + flags.optArrayInit = getBoolArg("optArrayInit", true); +#endif + flags.genArrayCopy = getBoolArg("genArrayCopy", true); + flags.onlyBalancedSync = getBoolArg("balancedSync", false); - InitIRBuilderFlags(compilationInterface,methodDesc); + flags.ignoreSync = getBoolArg("ignoreSync",false); + flags.syncAsEnterFence = getBoolArg("syncAsEnterFence",false); + flags.newCatchHandling = getBoolArg("newCatchHandling",true); - IRBuilder irBuilder(irManager); + flags.inlineMethods = getBoolArg("inlineMethods", false); + flags.guardedInlining = getBoolArg("guardedInlining", false); - if (methodDesc.isJavaByteCodes()) { - Opnd* returnOpnd = irManager.getReturnOpnd(); - JavaTranslateMethodForIRInlining( - compilationInterface, - methodDesc, - irBuilder, - numArgs, - argOpnds, - returnOpnd ? &returnOpnd : 0, - NULL, - NULL, - inlineDepth); - if (returnOpnd != irManager.getReturnOpnd()) - irManager.setReturnOpnd(returnOpnd); + flags.magicMinMaxAbs = getBoolArg("magicMinMaxAbs", false); + flags.genMinMaxAbs = getBoolArg("genMinMaxAbs", false); + flags.genFMinMaxAbs = getBoolArg("genFMinMaxAbs", false); + + const char* skipMethods = getStringArg("skipMethods", NULL); + if(skipMethods == NULL) { + flags.inlineSkipTable = NULL; } else { - assert(0); + flags.inlineSkipTable = new Method_Table(strdup(skipMethods), "SKIP_METHODS", true); } -} -// -// this routine is used for IR inlining, generating IR for a particular method -// -void -TranslatorIntfc::generateMethodIRForInlining( - CompilationInterface& compilationInterface, - MethodDesc& methodDesc, - IRBuilder& irBuilder, - uint32 numActualArgs, - Opnd** actualArgs, - Opnd** returnOpnd, - CFGNode** returnNode, - Inst* inlineSite, - uint32 inlineDepth) { - - if (methodDesc.isJavaByteCodes()) { - JavaTranslateMethodForIRInlining( - compilationInterface, - methodDesc, - irBuilder, - numActualArgs, - actualArgs, - returnOpnd, - returnNode, - inlineSite, - inlineDepth); - } else { - assert(0); - } + flags.magicClass=(char *)getStringArg("useMagicMethods", NULL); } + OpndStack::OpndStack(MemoryManager& memManager,uint32 slots) : maxSlots(slots) { diff --git vm/jitrino/src/translator/TranslatorIntfc.h vm/jitrino/src/translator/TranslatorIntfc.h index 937627e..08966cb 100644 --- vm/jitrino/src/translator/TranslatorIntfc.h +++ vm/jitrino/src/translator/TranslatorIntfc.h @@ -23,6 +23,8 @@ #ifndef _TRANSLATOR_INTFC_H_ #define _TRANSLATOR_INTFC_H_ +#include "PMFAction.h" + #include "open/types.h" #include <string.h> #include <assert.h> @@ -33,67 +35,59 @@ class MethodDesc; class IRBuilder; class InstFactory; class CompilationInterface; -class FlowGraph; +class ControlFlowGraph; class Opnd; class Inst; -class CFGNode; +class Node; class ExceptionInfo; class IRManager; class MemoryManager; -class JitrinoParameterTable; class Method_Table; class CompilationContext; +class SessionAction; // to select which byte code translator optimizations are done struct TranslatorFlags { - bool propValues : 1; // do value propagation - bool inlineMethods : 1; // do method inlining - bool guardedInlining : 1; // a step further for inlining - bool genCharArrayCopy : 1; // generate intrinsic calls to CharArrayCopy - bool onlyBalancedSync : 1; // treat all method synchronization as balanced - bool ignoreSync : 1; // do not generate monitor enter/exit instructions - bool syncAsEnterFence : 1; // implement monitor enter as enter fence and - bool newCatchHandling : 1; // use fix for catch handler ordering problem - bool magicMinMaxAbs : 1; // recognize, e.g., java/lang/Math.min/max/abs - bool genMinMaxAbs : 1; // gen min/max/abs opcodes instead of using select - bool genFMinMaxAbs : 1; // gen min/max/abs opcodes for floats - bool optArrayInit : 1; // skip array initializers from optimizations - Method_Table* inlineSkipTable; // do not inline these methods - char *magicClass; // Name of the MagicClass. NULL if no class specified. - }; - -class TranslatorIntfc { + bool propValues : 1; // do value propagation + bool inlineMethods : 1; // do method inlining + bool guardedInlining : 1; // a step further for inlining + bool genCharArrayCopy : 1; // generate intrinsic calls to CharArrayCopy + bool genArrayCopy : 1; // inline java/lang/System::arraycopy call + bool onlyBalancedSync : 1; // treat all method synchronization as balanced + bool ignoreSync : 1; // do not generate monitor enter/exit instructions + bool syncAsEnterFence : 1; // implement monitor enter as enter fence and + bool newCatchHandling : 1; // use fix for catch handler ordering problem + bool magicMinMaxAbs : 1; // recognize, e.g., java/lang/Math.min/max/abs + bool genMinMaxAbs : 1; // gen min/max/abs opcodes instead of using select + bool genFMinMaxAbs : 1; // gen min/max/abs opcodes for floats + bool optArrayInit : 1; // skip array initializers from optimizations + Method_Table* inlineSkipTable; // do not inline these methods + char *magicClass; // Name of the MagicClass. NULL if no class specified. +}; + +class IRBuilderAction; +class TranslatorAction: public Action { +public: + void init(); + const TranslatorFlags& getFlags() const {return flags;} + IRBuilderAction* getIRBuilderAction() const {return irbAction;} +protected: + void readFlags(); + TranslatorFlags flags; + IRBuilderAction* irbAction; +}; + +class TranslatorSession: public SessionAction { public: + virtual void run (); +private: + void translate(); + void postTranslatorCleanup(); - virtual ~TranslatorIntfc() {} - - // all TranslatorIntfc::flags fields are initialized by readTranslatorCommandLineParams() - static void readFlagsFromCommandLine(CompilationContext* cs, bool ia32Cg); - static void showFlagsFromCommandLine(); - - virtual void translateMethod(CompilationInterface&, MethodDesc&, IRBuilder&) = 0; - - // this is the regular routine to be used to generate IR for a method - static void translateByteCodes(IRManager&); - - // for inlining - static void translateByteCodesInline(IRManager& irManager, - uint32 numArgs, Opnd** argOpnds, uint32 inlineDepth); - - // this routine is used for IR inlining and generating IR for a particular method - // FG is obtained from irBuilder - static void generateMethodIRForInlining( - CompilationInterface& compilationInterface, - MethodDesc& methodDesc, - IRBuilder& irBuilder, - uint32 numActualArgs, - Opnd** actualArgs, - Opnd** returnOpnd, - CFGNode** returnNode, - Inst* inlineSite, - uint32 inlineDepth); + TranslatorFlags flags; }; + class OpndStack { public: OpndStack(MemoryManager& memManager,uint32 slots); @@ -179,7 +173,7 @@ extern void IRinline(CompilationInterface& compilationInterface, IRBuilder& irBuilder, InstFactory& instFactory, - FlowGraph* fg); + ControlFlowGraph* fg); } //namespace Jitrino diff --git vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp index 6c233f0..6b00a85 100644 --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.cpp @@ -19,10 +19,7 @@ * @version $Revision: 1.34.8.4.4.4 $ */ -#include <assert.h> -#include <stdio.h> #include "Stl.h" -#include "JavaByteCodeParser.h" #include "JavaByteCodeTranslator.h" #include "JavaTranslator.h" #include "Log.h" @@ -33,6 +30,10 @@ #include "InlineInfo.h" #include "open/bytecodes.h" #include "irmanager.h" #include "Jitrino.h" +#include "EMInterface.h" + +#include <assert.h> +#include <stdio.h> namespace Jitrino { @@ -49,24 +50,14 @@ float JavaByteCodeTranslator::MaxRelativ bool JavaByteCodeTranslator::isProfileAllowsInlining(MethodDesc* inlinee) { //do not inline methods with not initialized classes -> these paths are cold! CompilationContext* ctx = compilationInterface.getCompilationContext(); - JITModeData* modeData = ctx->getCurrentModeData(); - ProfilingInterface* pi = modeData->getProfilingInterface(); + ProfilingInterface* pi = ctx->getProfilingInterface(); if (pi==NULL || !pi->isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_USE)) { return true; } - MemoryManager& mm = ctx->getCompilationLevelMemoryManager(); - EntryBackedgeMethodProfile* inlineeProfile = - (EntryBackedgeMethodProfile*)pi->getMethodProfile(mm, ProfileType_EntryBackedge, *inlinee, JITProfilingRole_USE); - if (inlineeProfile != NULL) { - MethodDesc* inliner = &methodToCompile; - EntryBackedgeMethodProfile* inlinerProfile = - (EntryBackedgeMethodProfile*)pi->getMethodProfile(mm, ProfileType_EntryBackedge, *inliner, JITProfilingRole_USE); - if (inlinerProfile!=NULL) { - //inlinerProfile could be NULL even in DPGO mode! -> LazyExceptionOpt compilation to detect side-effects - if (inlineeProfile->getEntryExecCount() >= inlinerProfile->getEntryExecCount() * MaxRelativeInlineHotness) { - return true; - } - } + uint32 inlineeHotness = pi->getProfileMethodCount(*inlinee); + uint32 myHotness = pi->getProfileMethodCount(methodToCompile); + if (inlineeHotness >= myHotness * MaxRelativeInlineHotness) { + return true; } return false; } @@ -77,7 +68,7 @@ JavaByteCodeTranslator::inlineMethod(Met return false; bool doSkip = (translationFlags.inlineSkipTable == NULL) ? false : translationFlags.inlineSkipTable->accept_this_method(*methodDesc); if(doSkip) { - Log::cat_opt_inline()->info << "Skipping inlining of " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; + Log::out() << "Skipping inlining of " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; return false; } ObjectType * methodClass = (ObjectType*)methodDesc->getParentType(); @@ -95,14 +86,14 @@ JavaByteCodeTranslator::inlineMethod(Met || methodDesc->isPrivate() || methodClass->isFinalClass()); if(!doInline) { - Log::cat_opt_inline()->info << "Cannot inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; + Log::out() << "Cannot inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; return false; } uint32 numByteCodes = methodDesc->getByteCodeSize(); bool result = (numByteCodes > 0 && numByteCodes < MaxInlineSize) && (inlineDepth < MaxInlineDepth); if(result) - Log::cat_opt_inline()->info << "Translator inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; + Log::out() << "Translator inline " << methodDesc->getParentType()->getName() << "." << methodDesc->getName() << ::std::endl; return result; } @@ -141,9 +132,9 @@ JavaByteCodeTranslator::JavaByteCodeTran compilationInterface(ci), methodToCompile(methodDesc), parser(bcp), - typeManager(irb.getTypeManager()), + typeManager(*irb.getTypeManager()), irBuilder(irb), - translationFlags(*ci.getCompilationContext()->getTranslatorFlags()), + translationFlags(*irb.getTranslatorFlags()), cfgBuilder(cfg), // CHECK ? for static sync methods must ensure at least one slot on stack for monitor enter/exit code opndStack(mm,methodDesc.getMaxStack()+1), @@ -154,13 +145,13 @@ JavaByteCodeTranslator::JavaByteCodeTran inlineDepth(0), prepass(memManager, typeManager, - irBuilder.getInstFactory().getMemManager(), + irBuilder.getInstFactory()->getMemManager(), methodDesc, ci, NULL), lockAddr(NULL), oldLockValue(NULL), - thisLevelBuilder(NULL, methodDesc), + thisLevelBuilder(NULL, methodDesc,irb.getBcOffset()), inlineBuilder(NULL), jsrEntryMap(NULL), retOffsets(mm), @@ -224,7 +215,7 @@ JavaByteCodeTranslator::JavaByteCodeTran uint32 numActualArgs, Opnd** actualArgs, Opnd** returnopnd, // non-null for IR inlining - CFGNode** returnnode, // returns the block where is a return + Node** returnnode, // returns the block where is a return // (only one for inlined methods) ExceptionInfo *inliningexceptinfo, uint32 inlDepth, bool startNewBlock, @@ -234,9 +225,9 @@ JavaByteCodeTranslator::JavaByteCodeTran compilationInterface(ci), methodToCompile(methodDesc), parser(bcp), - typeManager(irb.getTypeManager()), + typeManager(*irb.getTypeManager()), irBuilder(irb), - translationFlags(*ci.getCompilationContext()->getTranslatorFlags()), + translationFlags(*irb.getTranslatorFlags()), cfgBuilder(cfg), // CHECK ? for static sync methods must ensure at least one slot on stack for monitor enter/exit code opndStack(mm,methodDesc.getMaxStack()+1), @@ -247,13 +238,13 @@ JavaByteCodeTranslator::JavaByteCodeTran inlineDepth(inlDepth), prepass(memManager, typeManager, - irBuilder.getInstFactory().getMemManager(), + irBuilder.getInstFactory()->getMemManager(), methodDesc, ci, actualArgs), lockAddr(NULL), oldLockValue(NULL), - thisLevelBuilder(parent, methodDesc), + thisLevelBuilder(parent, methodDesc, irb.getBcOffset()), inlineBuilder(&thisLevelBuilder), jsrEntryMap(parentJsrEntryMap), retOffsets(mm), @@ -267,9 +258,9 @@ JavaByteCodeTranslator::JavaByteCodeTran // create a new basic block LabelInst *label = irBuilder.createLabel(); cfgBuilder.genBlock(label); - inliningNodeBegin = label->getCFGNode(); + inliningNodeBegin = label->getNode(); } else { - inliningNodeBegin = irBuilder.getCurrentLabel()->getCFGNode(); + inliningNodeBegin = irBuilder.getCurrentLabel()->getNode(); } // create a prolog instruction irBuilder.genMethodEntryMarker(&methodDesc); @@ -305,7 +296,7 @@ JavaByteCodeTranslator::JavaByteCodeTran void JavaByteCodeTranslator::initJsrEntryMap() { - MemoryManager& ir_mem_manager = irBuilder.getIRManager().getMemoryManager(); + MemoryManager& ir_mem_manager = irBuilder.getIRManager()->getMemoryManager(); jsrEntryMap = new (ir_mem_manager) JsrEntryInstToRetInstMap(ir_mem_manager); } @@ -548,7 +539,7 @@ JavaByteCodeTranslator::offset(uint32 of } // start a new basic block - Log::cat_fe()->debug << "TRANSLATOR BASICBLOCK " << (int32)offset << " " << ::std::endl; + Log::out() << "TRANSLATOR BASICBLOCK " << (int32)offset << " " << ::std::endl; // finish the previous basic block, if any work was required if (!lastInstructionWasABranch) { @@ -577,22 +568,22 @@ JavaByteCodeTranslator::offset(uint32 of exceptionInfo = exceptionInfo->getNextExceptionInfoAtOffset()) { if (exceptionInfo->isCatchBlock()) { CatchBlock* catchBlock = (CatchBlock*)exceptionInfo; - Log::cat_fe()->debug << "TRY REGION " << (int)exceptionInfo->getBeginOffset() + Log::out() << "TRY REGION " << (int)exceptionInfo->getBeginOffset() << " " << (int)exceptionInfo->getEndOffset() << ::std::endl; CatchHandler *first = ((CatchBlock*)exceptionInfo)->getHandlers(); - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { for (; first != NULL; first = first->getNextHandler()) { - Log::cat_fe()->debug << " handler " << (int)first->getBeginOffset() << ::std::endl; + Log::out() << " handler " << (int)first->getBeginOffset() << ::std::endl; } } if (catchBlock->getLabelInst() == NULL) { - CFGNode *dispatchNode = cfgBuilder.createDispatchNode(); + Node *dispatchNode = cfgBuilder.createDispatchNode(); catchBlock->setLabelInst((LabelInst*)dispatchNode->getFirstInst()); ((LabelInst*)dispatchNode->getFirstInst())->setState(catchBlock); } if (labelInst->getState() == NULL) labelInst->setState(catchBlock); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "LABEL "; labelInst->print(Log::out()); Log::out() << labelInst->getState(); Log::out() << "CATCH ";catchBlock->getLabelInst()->print(Log::out()); Log::out() << ::std::endl; } @@ -600,7 +591,7 @@ JavaByteCodeTranslator::offset(uint32 of // catch handler block isCatchHandler = true; CatchHandler* handler = (CatchHandler*)exceptionInfo; - Log::cat_fe()->debug << "CATCH REGION " << (int)exceptionInfo->getBeginOffset() + Log::out() << "CATCH REGION " << (int)exceptionInfo->getBeginOffset() << " " << (int)exceptionInfo->getEndOffset() << ::std::endl; if (translationFlags.newCatchHandling) { handlerExceptionType = (handlerExceptionType == NULL) ? @@ -614,13 +605,13 @@ JavaByteCodeTranslator::offset(uint32 of if (translationFlags.newCatchHandling) { labelInst = (LabelInst*) - irBuilder.getInstFactory().makeCatchLabel( + irBuilder.getInstFactory()->makeCatchLabel( handler->getExceptionOrder(), handler->getExceptionType()); catchLabels.push_back(labelInst); } else { labelInst = (LabelInst*) - irBuilder.getInstFactory().makeCatchLabel( + irBuilder.getInstFactory()->makeCatchLabel( labelInst->getLabelId(), handler->getExceptionOrder(), handlerExceptionType); @@ -628,7 +619,7 @@ JavaByteCodeTranslator::offset(uint32 of } labelInst->setState(oldLabel->getState()); exceptionInfo->setLabelInst(labelInst); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "LABEL "; labelInst->print(Log::out()); Log::out() << labelInst->getState(); Log::out() << "CATCH "; handler->getLabelInst()->print(Log::out()); Log::out() << ::std::endl; } @@ -654,15 +645,13 @@ JavaByteCodeTranslator::offset(uint32 of // empty out the stack operand opndStack.makeEmpty(); } - CFGNode* node = cfgBuilder.genBlock(labelInst); - for(::std::vector<LabelInst*>::iterator iter = oldLabels.begin(); iter != oldLabels.end(); ++iter) - (*iter)->setCFGNode(node); + cfgBuilder.genBlock(labelInst); } // // Load var operands where current basic block begins // for (uint32 k=numVars; k < (uint32)stateInfo->stackDepth; k++) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "STACK ";stateInfo->stack[k].type->print(Log::out()); Log::out() << ::std::endl; } @@ -705,17 +694,17 @@ JavaByteCodeTranslator::parseDone() Inst* entry_inst = entry_inst_i->second; jsrEntryMap->insert(std::make_pair(entry_inst, ret_inst)); } - irBuilder.getIRManager().setJsrEntryMap(jsrEntryMap); + irBuilder.getIRManager()->setJsrEntryMap(jsrEntryMap); if (isInlinedMethod) { CatchBlock *catchSyncBlock = NULL; if (methodToCompile.isSynchronized()) { // generate fake exception info to catch any exception in the code catchSyncBlock = new (memManager) CatchBlock(0,0,methodToCompile.getByteCodeSize(), MAX_UINT32); - const CFGNodeDeque& nodes = cfgBuilder.getCFG()->getNodes(); - CFGNodeDeque::const_iterator niter = ::std::find(nodes.begin(), nodes.end(), inliningNodeBegin); + const Nodes& nodes = cfgBuilder.getCFG()->getNodes(); + Nodes::const_iterator niter = ::std::find(nodes.begin(), nodes.end(), inliningNodeBegin); for(; niter != nodes.end(); ++niter) { - CFGNode* node = *niter; + Node* node = *niter; LabelInst *first = (LabelInst*)node->getFirstInst(); if (node->isDispatchNode()) continue; ExceptionInfo *existingInfo = (ExceptionInfo*)first->getState(); @@ -740,11 +729,11 @@ JavaByteCodeTranslator::parseDone() // propagate exception info to the inlined basic blocks if (exceptionInfo != NULL) { - const CFGNodeDeque& nodes = cfgBuilder.getCFG()->getNodes(); - CFGNodeDeque::const_iterator niter = ::std::find(nodes.begin(), nodes.end(), inliningNodeBegin); + const Nodes& nodes = cfgBuilder.getCFG()->getNodes(); + Nodes::const_iterator niter = ::std::find(nodes.begin(), nodes.end(), inliningNodeBegin); for(++niter; niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - LabelInst *first = (LabelInst*)((CFGNode*)node)->getFirstInst(); + Node* node = *niter; + LabelInst *first = (LabelInst*)(node)->getFirstInst(); ExceptionInfo *existingInfo = (ExceptionInfo*)first->getState(); if (existingInfo == NULL) { first->setState(exceptionInfo); @@ -766,7 +755,7 @@ JavaByteCodeTranslator::parseDone() // fix synchronized methods if (methodToCompile.isSynchronized()) { // generate fake exception dispatch node - CFGNode *dispatchNode = cfgBuilder.createDispatchNode(); + Node *dispatchNode = cfgBuilder.createDispatchNode(); // propagate exception info (if any) exceptionInfo = inliningExceptionInfo; catchSyncBlock->setLabelInst((LabelInst*)dispatchNode->getFirstInst()); @@ -779,14 +768,14 @@ JavaByteCodeTranslator::parseDone() labelInst = (CatchLabelInst*) - irBuilder.getInstFactory().makeCatchLabel( + irBuilder.getInstFactory()->makeCatchLabel( label->getLabelId(), 0/*order*/, exceptionType); // generate a catch handler to handle any exception CatchHandler* - handler = new (irBuilder.getInstFactory().getMemManager()) + handler = new (irBuilder.getInstFactory()->getMemManager()) CatchHandler(0,0,0,catchSyncBlock,exceptionType); catchSyncBlock->addHandler(handler); // propagate exception info (if any) @@ -841,11 +830,14 @@ JavaByteCodeTranslator::parseDone() } } // end the method scope - if (numArgs > 0) { + if ((numArgs > 0) && (!methodToCompile.isStatic())) { Opnd *thisOpnd = args[0]; - irBuilder.genMethodEndMarker(&methodToCompile, thisOpnd); + // resultOpnd is needed to produce method exit event + irBuilder.genMethodEndMarker(&methodToCompile, thisOpnd, + returnOpnd != NULL ? *returnOpnd : NULL); } else { - irBuilder.genMethodEndMarker(&methodToCompile); + irBuilder.genMethodEndMarker(&methodToCompile, + returnOpnd != NULL ? *returnOpnd : NULL); } } } @@ -893,8 +885,8 @@ JavaByteCodeTranslator::ldc(uint32 const Type* constantType = compilationInterface.getConstantType(&methodToCompile,constPoolIndex); Opnd* opnd = NULL; - if (constantType->isSystemString()) { - opnd = irBuilder.genLdString(&methodToCompile,constPoolIndex); + if (constantType->isSystemString() || constantType->isSystemClass()) { + opnd = irBuilder.genLdRef(&methodToCompile,constPoolIndex,constantType); } else { const void* constantAddress = compilationInterface.getConstantValue(&methodToCompile,constPoolIndex); @@ -980,15 +972,26 @@ JavaByteCodeTranslator::astore(uint16 va //----------------------------------------------------------------------------- // field access byte codes //----------------------------------------------------------------------------- +Type* +JavaByteCodeTranslator::getFieldType(FieldDesc* field, uint32 constPoolIndex) { + Type* fieldType = field->getFieldType(); + if (!fieldType) { + // some problem with fieldType class handle. Let's try the constant_pool. + // (For example if the field type class is deleted, the field is beeing resolved successfully + // but field->getFieldType() returns NULL in this case) + fieldType = compilationInterface.getFieldType(&methodToCompile,constPoolIndex); + } + return fieldType; +} + void JavaByteCodeTranslator::getstatic(uint32 constPoolIndex) { FieldDesc* field = resolveStaticField(constPoolIndex, false); if (field && field->isStatic()) { - Type* fieldType = field->getFieldType(); - if (fieldType) { - pushOpnd(irBuilder.genLdStatic(fieldType,field)); - return; - } + Type* fieldType = getFieldType(field,constPoolIndex); + assert(fieldType); + pushOpnd(irBuilder.genLdStatic(fieldType,field)); + return; } // generate helper call for throwing respective exception linkingException(constPoolIndex, OPCODE_GETSTATIC); @@ -999,11 +1002,10 @@ void JavaByteCodeTranslator::putstatic(uint32 constPoolIndex) { FieldDesc* field = resolveStaticField(constPoolIndex, true); if (field && field->isStatic()) { - Type* fieldType = field->getFieldType(); - if (fieldType) { - irBuilder.genStStatic(fieldType,field,popOpnd()); - return; - } + Type* fieldType = getFieldType(field,constPoolIndex); + assert(fieldType); + irBuilder.genStStatic(fieldType,field,popOpnd()); + return; } // generate helper call for throwing respective exception linkingException(constPoolIndex, OPCODE_PUTSTATIC); @@ -1014,11 +1016,10 @@ void JavaByteCodeTranslator::getfield(uint32 constPoolIndex) { FieldDesc* field = resolveField(constPoolIndex, false); if (field && !field->isStatic()) { - Type* fieldType = field->getFieldType(); - if (fieldType) { - pushOpnd(irBuilder.genLdField(fieldType,popOpnd(),field)); - return; - } + Type* fieldType = getFieldType(field,constPoolIndex); + assert(fieldType); + pushOpnd(irBuilder.genLdField(fieldType,popOpnd(),field)); + return; } // generate helper call for throwing respective exception linkingException(constPoolIndex, OPCODE_GETFIELD); @@ -1030,13 +1031,12 @@ void JavaByteCodeTranslator::putfield(uint32 constPoolIndex) { FieldDesc* field = resolveField(constPoolIndex, true); if (field && !field->isStatic()) { - Type* fieldType = field->getFieldType(); - if (fieldType) { - Opnd* value = popOpnd(); - Opnd* ref = popOpnd(); - irBuilder.genStField(fieldType,ref,field,value); - return; - } + Type* fieldType = getFieldType(field,constPoolIndex); + assert(fieldType); + Opnd* value = popOpnd(); + Opnd* ref = popOpnd(); + irBuilder.genStField(fieldType,ref,field,value); + return; } // generate helper call for throwing respective exception linkingException(constPoolIndex, OPCODE_PUTFIELD); @@ -1718,7 +1718,7 @@ JavaByteCodeTranslator::invokevirtual(ui Opnd *tauNullChecked = irBuilder.genTauCheckNull(srcOpnds[0]); Opnd* thisOpnd = srcOpnds[0]; if (methodDesc->getParentType() != thisOpnd->getType()) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out()<<"CHECKVIRTUAL "; thisOpnd->printWithType(Log::out()); Log::out() << " : "; methodDesc->getParentType()->print(Log::out()); Log::out() <<"."<<methodDesc->getName()<<" "<< (int)methodDesc->getByteCodeSize()<< ::std::endl; @@ -1738,7 +1738,7 @@ JavaByteCodeTranslator::invokevirtual(ui if (returnType) { if ((isExactTypeOpnd(thisOpnd) || methodDesc->isFinal()) && inlineMethod(methodDesc)) { - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "XXX inline virtual:"; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } if(methodDesc->isInstanceInitializer()) { @@ -1764,16 +1764,16 @@ JavaByteCodeTranslator::invokevirtual(ui } return; } else if (guardedInlineMethod(methodDesc)) { - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "XXX guarded inline:"; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } VarOpnd *retVar = NULL; if (returnType->tag != Type::Void) retVar =irBuilder.genVarDef(returnType,false); - LabelInst *inlined = (LabelInst*)irBuilder.getInstFactory().makeLabel(); - LabelInst *target = (LabelInst*)irBuilder.getInstFactory().makeLabel(); - LabelInst *merge = (LabelInst*)irBuilder.getInstFactory().makeLabel(); + LabelInst *inlined = (LabelInst*)irBuilder.getInstFactory()->makeLabel(); + LabelInst *target = (LabelInst*)irBuilder.getInstFactory()->makeLabel(); + LabelInst *merge = (LabelInst*)irBuilder.getInstFactory()->makeLabel(); irBuilder.genTauTypeCompare(thisOpnd,methodDesc,target, tauNullChecked); @@ -1858,7 +1858,7 @@ JavaByteCodeTranslator::invokespecial(ui Opnd* dst; if (returnType && inlineMethod(methodDesc)) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "XXX inline special:";methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } if(methodDesc->isInstanceInitializer() || methodDesc->isClassInitializer()) @@ -1925,7 +1925,10 @@ JavaByteCodeTranslator::invokestatic(uin // // Try to match to charArrayCopy // - if (translationFlags.genCharArrayCopy == true && + if (translationFlags.genArrayCopy == true && + genArrayCopy(methodDesc,numArgs,srcOpnds,returnType)) { + return; + } else if (translationFlags.genCharArrayCopy == true && genCharArrayCopy(methodDesc,numArgs,srcOpnds,returnType)) { return; } else if (translationFlags.genMinMaxAbs == true && @@ -1969,7 +1972,7 @@ JavaByteCodeTranslator::invokeinterface( } if (returnType && (isExactTypeOpnd(thisOpnd) || methodDesc->isFinal()) && inlineMethod(methodDesc)) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "XXX inline interface:"; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } dst = JavaCompileMethodInline(compilationInterface, @@ -2195,7 +2198,7 @@ JavaByteCodeTranslator::needsReturnLabel if (!moreThanOneReturn && methodToCompile.getByteCodeSize()-1 != off) { if (!jumpToTheEnd) { // allocate one more label - labels[numLabels++] = (LabelInst*)irBuilder.getInstFactory().makeLabel(); + labels[numLabels++] = (LabelInst*)irBuilder.getInstFactory()->makeLabel(); } jumpToTheEnd = true; moreThanOneReturn = true; @@ -2428,7 +2431,7 @@ JavaByteCodeTranslator::genTypeArrayLoad pushOpnd(irBuilder.genLdNull()); return; } - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Array type is "; type->print(Log::out()); Log::out() << ::std::endl; stateInfo->stack[5].type->print(Log::out()); Log::out() << ::std::endl; @@ -2602,7 +2605,7 @@ JavaByteCodeTranslator::genInvokeStatic( ::std::cerr << "Unknown Magic " << methodName << ::std::endl; } if (inlineMethod(methodDesc)) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "XXX inline static:"; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } irBuilder.genTauSafe(); // always safe, is a static method call @@ -2639,6 +2642,301 @@ JavaByteCodeTranslator::newFallthroughBl } bool +JavaByteCodeTranslator::genArrayCopy(MethodDesc * methodDesc, + uint32 numArgs, + Opnd ** srcOpnds, + Type * returnType) { + + // + // Check if method is java/lang/System.arraycopy + // (Object src, int srcPos, Object dst, int dstPos, int len) + // + if (strcmp(methodDesc->getName(),"arraycopy") != 0 || + strcmp(methodDesc->getParentType()->getName(),"java/lang/System") !=0) + return false; + + // + // an ArrayStoreException is thrown and the destination is not modified: + // + // - The src argument refers to an object that is not an array. + // - The dest argument refers to an object that is not an array. + // - The src argument and dest argument refer to arrays whose component types are different primitive types. + // - The src argument refers to an array with a primitive component type and the dest argument + // refers to an array with a reference component type. + // - The src argument refers to an array with a reference component type and the dest argument + // refers to an array with a primitive component type. + // + assert(numArgs == 5); + Opnd * src = srcOpnds[0]; + Opnd * srcPos = srcOpnds[1]; + Type * srcType = src->getType(); + Type * srcPosType = srcPos->getType(); + Opnd * dst = srcOpnds[2]; + Opnd * dstPos = srcOpnds[3]; + Type * dstType = dst->getType(); + Type * dstPosType = dstPos->getType(); + Opnd * len = srcOpnds[4]; + assert(srcType->isObject() && + srcPosType->isInt4() && + dstType->isObject() && + dstPosType->isInt4() && + len->getType()->isInt4()); + + bool throwsASE = false; + bool srcIsArray = srcType->isArray(); + bool dstIsArray = dstType->isArray(); + ArrayType* srcAsArrayType = srcType->asArrayType(); + ArrayType* dstAsArrayType = dstType->asArrayType(); + bool srcIsArrOfPrimitive = srcIsArray && typeManager.isArrayOfPrimitiveElements(srcAsArrayType->getVMTypeHandle()); + bool dstIsArrOfPrimitive = dstIsArray && typeManager.isArrayOfPrimitiveElements(dstAsArrayType->getVMTypeHandle()); + if ( !(srcIsArray && dstIsArray) ) { + throwsASE = true; + } else if ( srcIsArrOfPrimitive ) { + if( !dstIsArrOfPrimitive || srcType != dstType ) + throwsASE = true; + } else if( dstIsArrOfPrimitive ) { + throwsASE = true; + } else { // the both are of objects + // Here is some inaccuracy. If src is a subclass of dst there is no ASE for sure. + // If it is not, we should check the assignability of each element being copied. + // To avoid this we just reject the inlining of System::arraycopy call in this case. + NamedType* srcElemType = srcAsArrayType->getElementType(); + NamedType* dstElemType = dstAsArrayType->getElementType(); + throwsASE = ! typeManager.isSubClassOf(srcElemType->getVMTypeHandle(),dstElemType->getVMTypeHandle()); + } + if ( throwsASE ) + return false; // reject the inlining of System::arraycopy call + + if (Log::isEnabled()) { + Log::out() << "XXX array copy: "; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; + } + // + // Generate exception condition checks: + // chknull src + // chknull dst + // cmpbr srcPos < 0, boundsException + // cmpbr dstPos < 0, boundsException + // cmpbr len < 0, boundsException + // srcEnd = add srcPos, len + // srcLen = src.length + // cmpbr srcEnd > srcLen, boundsException + // dstEnd = add dstPos, len + // dstLen = dst.length + // cmpbr dstEnd > dstLen, boundsException + // + // diff = Cmp3(dstPos,srcPos) + // // 1 if dstPos > srcPos + // // 0 if dstPos == srcPos + // // -1 if dstPos < srcPos + // if (src == dst && diff == 0) // nothing to do + // goto L1: + // + // if (diff > 0) + // goto reverseCopying: + // + // indexSrc = srcPos + // indexDst = dstPos + // increment = 1 + // copyDirectLoopHeader: + // if (indexSrc == srcEnd) + // goto L1: + // dst[indexDst] = src[indexSrc] + // indexSrc += increment + // indexDst += increment + // goto copyDirectLoopHeader: + // + // reverseCopying: + // indexSrc = srcPos + len - 1 + // indexDst = dstPos + len - 1 + // decrement = 1 + // copyReverseLoopHeader: + // if (indexSrc < srcPos) + // goto L1: + // dst[indexDst] = src[indexSrc] + // indexSrc -= decrement + // indexDst -= decrement + // goto copyReverseLoopHeader: + // + // boundsException: + // chkbounds -1, src + // L1: + // + Opnd *tauSrcNullChecked = irBuilder.genTauCheckNull(src); + Opnd *tauDstNullChecked = irBuilder.genTauCheckNull(dst); + + LabelInst * reverseCopying = irBuilder.createLabel(); + LabelInst * boundsException = irBuilder.createLabel(); + LabelInst * L1 = irBuilder.createLabel(); + Type * intType = typeManager.getInt32Type(); + + newFallthroughBlock(); + Opnd * zero = irBuilder.genLdConstant((int32)0); + Opnd * one = irBuilder.genLdConstant((int32)1); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,srcPos); + + newFallthroughBlock(); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,dstPos); + + newFallthroughBlock(); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,zero,len); + + Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); + + newFallthroughBlock(); + Opnd * srcLen = irBuilder.genArrayLen(intType,Type::Int32,src); + Opnd * srcEnd = irBuilder.genAdd(intType,mod,srcPos,len); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,srcEnd,srcLen); + + newFallthroughBlock(); + Opnd * dstEnd = irBuilder.genAdd(intType,mod,dstPos,len); + Opnd * dstLen = irBuilder.genArrayLen(intType,Type::Int32,dst); + irBuilder.genBranch(Type::Int32,Cmp_GT,boundsException,dstEnd,dstLen); + + newFallthroughBlock(); + + // The case of same arrays and same positions + Opnd * diff = irBuilder.genCmp3(intType,Type::Int32,Cmp_GT,dstPos,srcPos); + Opnd * sameArrays = irBuilder.genCmp(intType,Type::IntPtr,Cmp_EQ,src,dst); + Opnd * zeroDiff = irBuilder.genCmp(intType,Type::Int32,Cmp_EQ,diff,zero); + Opnd * nothingToCopy = irBuilder.genAnd(intType,sameArrays,zeroDiff); + irBuilder.genBranch(Type::Int32,Cmp_GT,L1,nothingToCopy,zero); + + newFallthroughBlock(); + + // Choosing direction + + irBuilder.genBranch(Type::Int32,Cmp_GT,reverseCopying,diff,zero); + + newFallthroughBlock(); + + { //Direct Copying + + // indexes for using inside the loop + VarOpnd* srcPosVar = irBuilder.genVarDef(srcPosType, false); + VarOpnd* dstPosVar = irBuilder.genVarDef(dstPosType, false); + + irBuilder.genStVar(srcPosVar, srcPos); + irBuilder.genStVar(dstPosVar, dstPos); + + Opnd* srcPosOpnd = NULL; + Opnd* dstPosOpnd = NULL; + + // Loop Header + LabelInst * loopHead = irBuilder.createLabel(); + irBuilder.genLabel(loopHead); + cfgBuilder.genBlockAfterCurrent(loopHead); + + // loop exit condition (srcIndex = srcStartIndex + len) + srcPosOpnd = irBuilder.genLdVar(srcPosType,srcPosVar); + irBuilder.genBranch(Type::Int32,Cmp_EQ,L1,srcPosOpnd,srcEnd); + + newFallthroughBlock(); + // array bounds have been checked directly + // the types have been checked above so tauAddressInRange is tauSafe + Opnd *tauSrcAddressInRange = irBuilder.genTauSafe(); + Opnd *tauDstAddressInRange = irBuilder.genTauSafe(); + Opnd *tauDstBaseTypeChecked = irBuilder.genTauSafe(); + + // load indexes + srcPosOpnd = irBuilder.genLdVar(srcPosType,srcPosVar); + dstPosOpnd = irBuilder.genLdVar(dstPosType,dstPosVar); + + Type* srcElemType = srcType->asArrayType()->getElementType(); + Type* dstElemType = dstType->asArrayType()->getElementType(); + + // copy element + // (Checks are performed before the loop) + Opnd* elem = irBuilder.genLdElem(srcElemType,src,srcPosOpnd, + tauSrcNullChecked, tauSrcAddressInRange); + irBuilder.genStElem(dstElemType,dst,dstPosOpnd,elem, + tauDstNullChecked, tauDstBaseTypeChecked, tauDstAddressInRange); + + // increment indexes + srcPosOpnd = irBuilder.genAdd(srcPosType,mod,srcPosOpnd,one); + dstPosOpnd = irBuilder.genAdd(dstPosType,mod,dstPosOpnd,one); + + // store indexes + irBuilder.genStVar(srcPosVar, srcPosOpnd); + irBuilder.genStVar(dstPosVar, dstPosOpnd); + + // back edge + irBuilder.genJump(loopHead); + + } // End of Direct Copying + + { //Reverse Copying + irBuilder.genLabel(reverseCopying); + cfgBuilder.genBlockAfterCurrent(reverseCopying); + + // indexes for using inside the loop + VarOpnd* srcPosVar = irBuilder.genVarDef(srcPosType, false); + VarOpnd* dstPosVar = irBuilder.genVarDef(dstPosType, false); + + Opnd* lastSrcIdx = irBuilder.genSub(srcPosType,mod,srcEnd,one); + Opnd* lastDstIdx = irBuilder.genSub(dstPosType,mod,dstEnd,one); + + irBuilder.genStVar(srcPosVar, lastSrcIdx); + irBuilder.genStVar(dstPosVar, lastDstIdx); + + Opnd* srcPosOpnd = NULL; + Opnd* dstPosOpnd = NULL; + + // Loop Header + LabelInst * loopHead = irBuilder.createLabel(); + irBuilder.genLabel(loopHead); + cfgBuilder.genBlockAfterCurrent(loopHead); + + // loop exit condition (srcIndex < srcPos) + srcPosOpnd = irBuilder.genLdVar(srcPosType,srcPosVar); + irBuilder.genBranch(Type::Int32,Cmp_GT,L1,srcPos,srcPosOpnd); + + newFallthroughBlock(); + // array bounds have been checked directly + // the types have been checked above so tauAddressInRange is tauSafe + Opnd *tauSrcAddressInRange = irBuilder.genTauSafe(); + Opnd *tauDstAddressInRange = irBuilder.genTauSafe(); + Opnd *tauDstBaseTypeChecked = irBuilder.genTauSafe(); + + // load indexes + srcPosOpnd = irBuilder.genLdVar(srcPosType,srcPosVar); + dstPosOpnd = irBuilder.genLdVar(dstPosType,dstPosVar); + + Type* srcElemType = srcType->asArrayType()->getElementType(); + Type* dstElemType = dstType->asArrayType()->getElementType(); + + // copy element + // (Checks are performed before the loop) + Opnd* elem = irBuilder.genLdElem(srcElemType,src,srcPosOpnd, + tauSrcNullChecked, tauSrcAddressInRange); + irBuilder.genStElem(dstElemType,dst,dstPosOpnd,elem, + tauDstNullChecked, tauDstBaseTypeChecked, tauDstAddressInRange); + + // decrement indexes + srcPosOpnd = irBuilder.genSub(srcPosType,mod,srcPosOpnd,one); + dstPosOpnd = irBuilder.genSub(dstPosType,mod,dstPosOpnd,one); + + // store indexes + irBuilder.genStVar(srcPosVar, srcPosOpnd); + irBuilder.genStVar(dstPosVar, dstPosOpnd); + + // back edge + irBuilder.genJump(loopHead); + + } // End of Reverse Copying + + + irBuilder.genLabel(boundsException); + cfgBuilder.genBlockAfterCurrent(boundsException); + Opnd * minusOne = irBuilder.genLdConstant((int32)-1); + irBuilder.genTauCheckBounds(src,minusOne,tauSrcNullChecked); + + irBuilder.genLabel(L1); + cfgBuilder.genBlockAfterCurrent(L1); + + return true; +} + +bool JavaByteCodeTranslator::genCharArrayCopy(MethodDesc * methodDesc, uint32 numArgs, Opnd ** srcOpnds, @@ -2671,7 +2969,7 @@ JavaByteCodeTranslator::genCharArrayCopy ((ArrayType *)dstType)->getElementType()->isChar())) return false; - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "XXX char array copy: "; methodDesc->printFullName(Log::out()); Log::out() << ::std::endl; } // @@ -2759,9 +3057,9 @@ JavaByteCodeTranslator::genMinMax(Method Type *type = src0->getType(); assert(type == src1->getType()); - IRManager& irm = irBuilder.getIRManager(); + IRManager& irm = *irBuilder.getIRManager(); MethodDesc& md = irm.getMethodDesc(); - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Saw call to java/lang/Math::min from " << md.getParentType()->getName() << "::" @@ -2780,9 +3078,9 @@ JavaByteCodeTranslator::genMinMax(Method Type *type = src0->getType(); assert(type == src1->getType()); - IRManager& irm = irBuilder.getIRManager(); + IRManager& irm = *irBuilder.getIRManager(); MethodDesc& md = irm.getMethodDesc(); - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Saw call to java/lang/Math::max from " << md.getParentType()->getName() << "::" @@ -2801,9 +3099,9 @@ JavaByteCodeTranslator::genMinMax(Method Opnd *src0 = srcOpnds[0]; Type *type = src0->getType(); - IRManager& irm = irBuilder.getIRManager(); + IRManager& irm = *irBuilder.getIRManager(); MethodDesc& md = irm.getMethodDesc(); - if (Log::cat_fe()->isDebugEnabled()) { + if (Log::isEnabled()) { Log::out() << "Saw call to java/lang/Math::abs from " << md.getParentType()->getName() << "::" diff --git vm/jitrino/src/translator/java/JavaByteCodeTranslator.h vm/jitrino/src/translator/java/JavaByteCodeTranslator.h index e7b306d..bed7069 100644 --- vm/jitrino/src/translator/java/JavaByteCodeTranslator.h +++ vm/jitrino/src/translator/java/JavaByteCodeTranslator.h @@ -23,17 +23,18 @@ #ifndef _JAVABYTECODETRANSLATOR_H_ #define _JAVABYTECODETRANSLATOR_H_ -#include "VMInterface.h" -#include "TranslatorIntfc.h" +#include "JavaTranslator.h" #include "IRBuilder.h" -#include "Opnd.h" -#include "FlowGraph.h" #include "JavaByteCodeParser.h" #include "JavaLabelPrepass.h" #include "JavaFlowGraphBuilder.h" +#include "VMInterface.h" + namespace Jitrino { +class Opnd; + class JavaByteCodeTranslator : public JavaByteCodeParserCallback { public: virtual ~JavaByteCodeTranslator() { @@ -57,7 +58,7 @@ public: TypeManager& typeManager, JavaFlowGraphBuilder& cfg, uint32 numActualArgs,Opnd **actualArgs, - Opnd **returnOpnd, CFGNode **returnNode, + Opnd **returnOpnd, Node **returnNode, ExceptionInfo *exceptionInfo, // propagated exception info uint32 inlineDepth, bool startNewBlock, InlineInfoBuilder* parent, @@ -237,17 +238,25 @@ private: class JavaInlineInfoBuilder : public InlineInfoBuilder { public: - JavaInlineInfoBuilder(InlineInfoBuilder* parent, MethodDesc& thisMethodDesc) : - InlineInfoBuilder(parent), methodDesc(thisMethodDesc) + JavaInlineInfoBuilder(InlineInfoBuilder* parent, + MethodDesc& thisMethodDesc, uint32 byteCodeOffset) : + InlineInfoBuilder(parent), methodDesc(thisMethodDesc), + bcOffset(byteCodeOffset) {} + virtual uint32 getCurrentBcOffset() { return bcOffset; }; + virtual MethodDesc* getCurrentMd() { return &methodDesc; }; + private: - virtual void addCurrentLevel(InlineInfo* ii) + virtual void addCurrentLevel(InlineInfo* ii, uint32 currOffset) { - ii->addLevel(&methodDesc); + ii->addLevel(&methodDesc, currOffset); } + virtual void setCurrentBcOffset(uint32 offSet) { bcOffset = offSet; }; + MethodDesc& methodDesc; + uint32 bcOffset; }; static uint32 MaxSelfSizeForInlining; // in bytes @@ -307,6 +316,7 @@ private: void genInvokeStatic(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds,Type * returnType); bool genCharArrayCopy(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); + bool genArrayCopy(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); bool genMinMax(MethodDesc * methodDesc,uint32 numArgs,Opnd ** srcOpnds, Type * returnType); void newFallthroughBlock(); @@ -355,7 +365,7 @@ private: MethodDesc* resolveInterfaceMethod(uint32 cpIndex); NamedType* resolveType(uint32 cpIndex); NamedType* resolveTypeNew(uint32 cpIndex); - Type* getFieldType(FieldDesc* fieldDesc); + Type* getFieldType(FieldDesc* fieldDesc,uint32 cpIndex); const char* methodSignatureString(uint32 cpIndex); // // @@ -393,7 +403,7 @@ private: ByteCodeParser& parser; TypeManager& typeManager; IRBuilder& irBuilder; - TranslatorFlags& translationFlags; + TranslatorFlags translationFlags; JavaFlowGraphBuilder& cfgBuilder; // // byte code parsing state @@ -408,13 +418,13 @@ private: // used for IR inlining // Opnd** returnOpnd; // if non-null, used this operand - CFGNode ** returnNode; // returns the node where the return is located + Node ** returnNode; // returns the node where the return is located // // method state // bool isInlinedMethod; // is this method being inlined? ExceptionInfo* inliningExceptionInfo; // instruction where inlining begins - CFGNode* inliningNodeBegin; // used by inlining of synchronized methods + Node* inliningNodeBegin; // used by inlining of synchronized methods uint32 numLabels; // number of labels in this method uint32 numVars; // number of variables in this method uint32 numStackVars; // number of non-empty stack locations in this method diff --git vm/jitrino/src/translator/java/JavaFlowGraphBuilder.cpp vm/jitrino/src/translator/java/JavaFlowGraphBuilder.cpp index 937f590..063946b 100644 --- vm/jitrino/src/translator/java/JavaFlowGraphBuilder.cpp +++ vm/jitrino/src/translator/java/JavaFlowGraphBuilder.cpp @@ -20,79 +20,76 @@ * */ -#include <stdlib.h> -#include <string.h> #include "Log.h" #include "Opcode.h" #include "Type.h" -#include "FlowGraph.h" #include "Stack.h" #include "IRBuilder.h" #include "ExceptionInfo.h" #include "JavaFlowGraphBuilder.h" #include "TranslatorIntfc.h" #include "irmanager.h" +#include "FlowGraph.h" + +#include <stdlib.h> +#include <string.h> namespace Jitrino { -CFGNode* JavaFlowGraphBuilder::genBlock(LabelInst* label) { +Node* JavaFlowGraphBuilder::genBlock(LabelInst* label) { if (currentBlock == NULL) { - currentBlock = fg->createBlock(label); - assert(fg->getEntry()==NULL); - fg->setEntry(currentBlock); + currentBlock = createBlockNodeOrdered(label); + assert(fg->getEntryNode()==NULL); + fg->setEntryNode(currentBlock); } else { - currentBlock = fg->createBlock(label); + currentBlock = createBlockNodeOrdered(label); } return currentBlock; } -CFGNode* JavaFlowGraphBuilder::genBlockAfterCurrent(LabelInst *label) { +Node* JavaFlowGraphBuilder::genBlockAfterCurrent(LabelInst *label) { // hidden exception info void *exceptionInfo = ((LabelInst*)currentBlock->getFirstInst())->getState(); - currentBlock = fg->createBlockAfter(label,currentBlock); + currentBlock = createBlockNodeAfter(currentBlock, label); label->setState(exceptionInfo); return currentBlock; } -CFGNode *JavaFlowGraphBuilder::createDispatchNode() { - return fg->createDispatchNode(); -} -void JavaFlowGraphBuilder::edgeForFallthrough(CFGNode* block) { +void JavaFlowGraphBuilder::edgeForFallthrough(Node* block) { // // find fall through basic block; skip handler nodes // - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter = ::std::find(nodes.begin(), nodes.end(), block); - assert(niter != nodes.end()); - TranslatorFlags& translatorFlags = *irBuilder.getIRManager().getCompilationContext()->getTranslatorFlags(); - for(++niter; niter != nodes.end(); ++niter) { - if (translatorFlags.newCatchHandling) { - CFGNode* node = *niter; - if(node->isBasicBlock() && !node->getLabel()->isCatchLabel()) + NodeList::const_iterator niter = std::find(fallThruNodes.begin(), fallThruNodes.end(), block); + assert(niter != fallThruNodes.end()); + TranslatorFlags* translatorFlags = irBuilder.getTranslatorFlags(); + for(++niter; niter != fallThruNodes.end(); ++niter) { + Node* node = *niter; + if (translatorFlags->newCatchHandling) { + if (node->isBlockNode() && !((LabelInst*)node->getFirstInst())->isCatchLabel()) { break; - } else { - if((*niter)->isBasicBlock()) + } + } else if (node->isBlockNode()) { break; } } - assert(niter != nodes.end()); - CFGNode* fallthrough = *niter; - fg->addEdge(block,fallthrough); + assert(niter != fallThruNodes.end()); + Node* fallthrough = *niter; + addEdge(block,fallthrough); } -CFGNode * JavaFlowGraphBuilder::edgesForBlock(CFGNode* block) { +Node * JavaFlowGraphBuilder::edgesForBlock(Node* block) { // // find if this block has any region that could catch the exception // - CFGNode *dispatch = NULL; + Node *dispatch = NULL; ExceptionInfo *exceptionInfo = (CatchBlock*)((LabelInst*)block->getFirstInst())->getState(); if (exceptionInfo != NULL) { - dispatch = exceptionInfo->getLabelInst()->getCFGNode(); + dispatch = exceptionInfo->getLabelInst()->getNode(); }else{ - dispatch = fg->getUnwind(); + dispatch = fg->getUnwindNode(); } assert(dispatch->isDispatchNode()); @@ -100,15 +97,18 @@ CFGNode * JavaFlowGraphBuilder::edgesFor // split the block so that // each potentially-exceptional instruction ends a block // - Inst* first = block->getFirstInst(); - Inst* last = block->getLastInst(); + Inst* first = (Inst*)block->getFirstInst(); + Inst* last = (Inst*)block->getLastInst(); Inst* lastExceptionalInstSeen = NULL; - for (Inst* inst = first->next(); inst != first; inst = inst->next()) { + for (Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) { if (lastExceptionalInstSeen != NULL) { // start a new basic block - CFGNode *newblock = fg->createBlockAfter(block); - Inst *ins = lastExceptionalInstSeen->next(); - ins->moveTailTo(first, newblock->getFirstInst()); + Node *newblock = createBlockNodeAfter(block); + for (Inst *ins = lastExceptionalInstSeen->getNextInst(), *nextIns = NULL; ins!=NULL; ins = nextIns) { + nextIns = ins->getNextInst(); + ins->unlink(); + newblock->appendInst(ins); + } // now fix up the CFG, duplicating edges if (!lastExceptionalInstSeen->isThrow()) @@ -116,16 +116,14 @@ CFGNode * JavaFlowGraphBuilder::edgesFor // // add an edge to handler entry node // - assert(!block->findTarget(dispatch)); + assert(!block->findTargetEdge(dispatch)); fg->addEdge(block,dispatch); block = newblock; - first = block->getFirstInst(); lastExceptionalInstSeen = NULL; } if (inst->getOperation().canThrow()) { lastExceptionalInstSeen = inst; } - inst->setNode(block); } // @@ -134,17 +132,16 @@ CFGNode * JavaFlowGraphBuilder::edgesFor switch(last->getOpcode()) { case Op_Jump: { - fg->addEdge(block,((BranchInst*)last)->getTargetLabel()->getCFGNode()); + fg->addEdge(block,((BranchInst*)last)->getTargetLabel()->getNode()); last->unlink(); } break; case Op_Branch: case Op_JSR: - fg->addEdge(block,((BranchInst*)last)->getTargetLabel()->getCFGNode()); + addEdge(block, ((BranchInst*)last)->getTargetLabel()->getNode()); edgeForFallthrough(block); break; case Op_Throw: - case Op_ThrowLazy: case Op_ThrowSystemException: case Op_ThrowLinkingException: // throw/rethrow creates an edge to a handler that catches the exception @@ -152,7 +149,7 @@ CFGNode * JavaFlowGraphBuilder::edgesFor assert(lastExceptionalInstSeen == last); break; case Op_Return: - fg->addEdge(block,fg->getReturn()); + addEdge(block, fg->getReturnNode()); break; case Op_Ret: break; // do not do anything @@ -161,18 +158,20 @@ CFGNode * JavaFlowGraphBuilder::edgesFor SwitchInst *sw = (SwitchInst*)last; uint32 num = sw->getNumTargets(); for (uint32 i = 0; i < num; i++) { - CFGNode* target = sw->getTarget(i)->getCFGNode(); + Node* target = sw->getTarget(i)->getNode(); // two switch values may go to the same block - if (!block->findTarget(target)) + if (!block->findTargetEdge(target)) { fg->addEdge(block,target); + } } - CFGNode* target = sw->getDefaultTarget()->getCFGNode(); - if (!block->findTarget(target)) + Node* target = sw->getDefaultTarget()->getNode(); + if (!block->findTargetEdge(target)) { fg->addEdge(block,target); + } } break; - default: - if (block != fg->getReturn()) { // a fallthrough edge is needed + default:; + if (block != fg->getReturnNode()) { // a fallthrough edge is needed // if the basic block does not have any outgoing edge, add one fall through edge if (block->getOutEdges().empty()) edgeForFallthrough(block); @@ -181,14 +180,14 @@ CFGNode * JavaFlowGraphBuilder::edgesFor // // add an edge to handler entry node // - if (lastExceptionalInstSeen != NULL && !block->findTarget(dispatch)) + if (lastExceptionalInstSeen != NULL && !block->findTargetEdge(dispatch)) fg->addEdge(block,dispatch); return block; } -void JavaFlowGraphBuilder::edgesForHandler(CFGNode* entry) { +void JavaFlowGraphBuilder::edgesForHandler(Node* entry) { CatchBlock *catchBlock = (CatchBlock*)((LabelInst*)entry->getFirstInst())->getState(); - if(entry == fg->getUnwind()) + if(entry == fg->getUnwindNode()) // No local handlers for unwind. return; // @@ -196,34 +195,33 @@ void JavaFlowGraphBuilder::edgesForHandl // CatchHandler * handlers = catchBlock->getHandlers(); for (;handlers != NULL; handlers = handlers->getNextHandler()) { - fg->addEdge(entry,handlers->getLabelInst()->getCFGNode()); + fg->addEdge(entry,handlers->getLabelInst()->getNode()); } // edges for uncaught exception ExceptionInfo *nextBlock = NULL; for (nextBlock = catchBlock->getNextExceptionInfoAtOffset(); - nextBlock != NULL; nextBlock = nextBlock->getNextExceptionInfoAtOffset()) { + nextBlock != NULL; nextBlock = nextBlock->getNextExceptionInfoAtOffset()) + { if (nextBlock->isCatchBlock()) { - CFGNode *next = nextBlock->getLabelInst()->getCFGNode(); + Node *next = nextBlock->getLabelInst()->getNode(); fg->addEdge(entry,next); break; } } if(nextBlock == NULL) { - fg->addEdge(entry,fg->getUnwind()); + fg->addEdge(entry,fg->getUnwindNode()); } } void JavaFlowGraphBuilder::createCFGEdges() { - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter; - for(niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* node = *niter; - if (node->isBasicBlock()) + for (NodeList::iterator it = fallThruNodes.begin(); it!=fallThruNodes.end(); ++it) { + Node* node = *it; + if (node->isBlockNode()) node = edgesForBlock(node); else if (node->isDispatchNode()) edgesForHandler(node); else - assert(node == fg->getExit()); + assert(node == fg->getExitNode()); } } @@ -235,18 +233,18 @@ #define BLACK 1 // node can reach exit // that are reachable from exit node with BLACK. // void JavaFlowGraphBuilder::reverseDFS( StlVector<int8>& state, - CFGNode* targetNode, + Node* targetNode, uint32* nodesCounter ) { - const CFGEdgeDeque& in_edges = targetNode->getInEdges(); + const Edges& in_edges = targetNode->getInEdges(); assert( state[targetNode->getId()] == WHITE ); state[targetNode->getId()] = BLACK; *nodesCounter += 1; - for( CFGEdgeDeque::const_iterator in_iter = in_edges.begin(); in_iter != in_edges.end(); in_iter++ ){ - CFGNode* srcNode = (*in_iter)->getSourceNode(); + for( Edges::const_iterator in_iter = in_edges.begin(); in_iter != in_edges.end(); in_iter++ ){ + Node* srcNode = (*in_iter)->getSourceNode(); if( state[srcNode->getId()] != BLACK ){ reverseDFS( state, srcNode, nodesCounter ); @@ -261,56 +259,26 @@ void JavaFlowGraphBuilder::reverseDFS( S // for while(true){;} loops, if they exist. // void JavaFlowGraphBuilder::forwardDFS( StlVector<int8>& state, - CFGNode* srcNode ) + Node* srcNode, + Edges& edgesForSplicing) { // Flip the state, so the same node will not be visited more than twice. state[srcNode->getId()] = ~state[srcNode->getId()]; - const CFGEdgeDeque& out_edges = srcNode->getOutEdges(); + const Edges& out_edges = srcNode->getOutEdges(); - for( CFGEdgeDeque::const_iterator out_iter = out_edges.begin(); out_iter != out_edges.end(); out_iter++ ){ + for( Edges::const_iterator out_iter = out_edges.begin(); out_iter != out_edges.end(); out_iter++ ){ - CFGNode* targetNode = (*out_iter)->getTargetNode(); + Node* targetNode = (*out_iter)->getTargetNode(); const int32 targetState = state[targetNode->getId()]; if( targetState == BLACK || targetState == WHITE ){ // Keep searching ... - forwardDFS( state, targetNode ); - - } else if( targetState == ~WHITE && - srcNode->hasOnlyOneSuccEdge() ){ - // Find an infinite loop that will never reach exit node. - assert( state[srcNode->getId()] == ~WHITE ); - irBuilder.genLabel( (LabelInst*)targetNode->getFirstInst() ); - Opnd* args[] = { irBuilder.genTauSafe(), irBuilder.genTauSafe() }; - Type* returnType = irBuilder.getTypeManager().getVoidType(); - - irBuilder.genJitHelperCall( PseudoCanThrow, - returnType, - sizeof(args) / sizeof(args[0]), - args ); - - ExceptionInfo* exceptionInfo = - (CatchBlock*)((LabelInst*)targetNode->getFirstInst())->getState(); - CFGNode* dispatch = NULL; - - if( exceptionInfo != NULL) { - dispatch = exceptionInfo->getLabelInst()->getCFGNode(); - } else { - dispatch = fg->getUnwind(); - } - - assert( !targetNode->findTarget(dispatch) ); - fg->addEdge( targetNode, dispatch ); + forwardDFS( state, targetNode, edgesForSplicing ); + } else if( targetState == ~WHITE){ state[targetNode->getId()] = ~BLACK; // Now it can reach exit node. - - if( Log::cat_fe()->isIREnabled() ){ - MethodDesc &methodDesc = irBuilder.getIRManager().getMethodDesc(); - Log::out() << "PRINTING LOG: After resolveWhileTrue" << ::std::endl; - targetNode->print( Log::out() ); - fg->printInsts( Log::out(), methodDesc ); - } + edgesForSplicing.push_back((*out_iter)); } } @@ -334,20 +302,81 @@ void JavaFlowGraphBuilder::resolveWhileT // Pass 1: Identify all the nodes that are reachable from exit node. // uint32 nodesAffected = 0; - reverseDFS( state, fg->getExit(), &nodesAffected ); + reverseDFS( state, fg->getExitNode(), &nodesAffected ); // // Pass 2: Add dispatches for while(true){;} loops, if they exist. // if( nodesAffected < fg->getNodes().size() ){ - forwardDFS( state, fg->getEntry() ); + Edges edgesForSplicing(mm); + forwardDFS( state, fg->getEntryNode(), edgesForSplicing ); + for (uint32 i=0; i < edgesForSplicing.size(); i++) { + Edge* e= edgesForSplicing[i]; + Node* targetNode = e->getTargetNode(); + LabelInst* newLabel = irBuilder.createLabel(); + Node* node = fg->spliceBlockOnEdge(e, newLabel); + irBuilder.genLabel(newLabel); + + Opnd* args[] = { irBuilder.genTauSafe(), irBuilder.genTauSafe() }; + Type* returnType = irBuilder.getTypeManager()->getVoidType(); + irBuilder.genJitHelperCall( PseudoCanThrow, + returnType, + sizeof(args) / sizeof(args[0]), + args ); + + ExceptionInfo* exceptionInfo = + (CatchBlock*)((LabelInst*)targetNode->getFirstInst())->getState(); + Node* dispatch = NULL; + + if( exceptionInfo != NULL) { + dispatch = exceptionInfo->getLabelInst()->getNode(); + } else { + dispatch = fg->getUnwindNode(); } - return; + fg->addEdge(node, dispatch); + } + if( Log::isEnabled() ){ + MethodDesc &methodDesc = irBuilder.getIRManager()->getMethodDesc(); + Log::out() << "PRINTING LOG: After resolveWhileTrue" << ::std::endl; + FlowGraph::printHIR(Log::out(), *fg, methodDesc ); + } + + } } +Node* JavaFlowGraphBuilder::createBlockNodeOrdered(LabelInst* label) { + if (label == NULL) { + label = irBuilder.getInstFactory()->makeLabel(); + } + Node* node = fg->createBlockNode(label); + fallThruNodes.push_back(node); + return node; +} +Node* JavaFlowGraphBuilder::createBlockNodeAfter(Node* node, LabelInst* label) { + NodeList::iterator it = std::find(fallThruNodes.begin(), fallThruNodes.end(), node); + assert(it!=fallThruNodes.end()); + if (label == NULL) { + label = irBuilder.getInstFactory()->makeLabel(); + } + label->setState(((LabelInst*)node->getFirstInst())->getState()); + Node* newNode = fg->createBlockNode(label); + fallThruNodes.insert(++it, newNode); + return newNode; +} +Node* JavaFlowGraphBuilder::createDispatchNode() { + Node* node = fg->createDispatchNode(irBuilder.getInstFactory()->makeLabel()); + fallThruNodes.push_back(node); + return node; +} + +void JavaFlowGraphBuilder::addEdge(Node* source, Node* target) { + if (source->findTargetEdge(target) == NULL) { + fg->addEdge(source, target); + } +} // // construct flow graph @@ -356,11 +385,12 @@ void JavaFlowGraphBuilder::build() { // // create epilog, unwind, and exit // - fg->setReturn(fg->createBlockNode()); - fg->setUnwind(fg->createDispatchNode()); - fg->setExit(fg->createExitNode()); - fg->addEdge(fg->getReturn(), fg->getExit()); - fg->addEdge(fg->getUnwind(), fg->getExit()); + InstFactory* instFactory = irBuilder.getInstFactory(); + fg->setReturnNode(createBlockNodeOrdered()); + fg->setUnwindNode(createDispatchNode()); + fg->setExitNode(fg->createNode(Node::Kind_Exit, instFactory->makeLabel())); + fg->addEdge(fg->getReturnNode(), fg->getExitNode()); + fg->addEdge(fg->getUnwindNode(), fg->getExitNode()); // // second phase: construct edges // @@ -371,6 +401,7 @@ void JavaFlowGraphBuilder::build() { resolveWhileTrue(); eliminateUnnestedLoopsOnDispatch(); + } @@ -419,20 +450,20 @@ void JavaFlowGraphBuilder::build() { // void JavaFlowGraphBuilder::eliminateUnnestedLoopsOnDispatch() { - MemoryManager matched_nodes_mm(3*sizeof(CFGNode*), "unnested_loops_mm"); - CFGNodeDeque matched_dispatches(matched_nodes_mm); + MemoryManager matched_nodes_mm(3*sizeof(Node*), "unnested_loops_mm"); + Nodes matched_dispatches(matched_nodes_mm); bool found_goto_into_loop_warning = false; - const CFGNodeDeque& nodes = fg->getNodes(); - CFGNodeDeque::const_iterator niter; + const Nodes& nodes = fg->getNodes(); + Nodes::const_iterator niter; for (niter = nodes.begin(); niter != nodes.end(); ++niter) { - CFGNode* dispatch = *niter; + Node* dispatch = *niter; if ( dispatch->isDispatchNode() && dispatch->getInDegree() > 1 ) { - const CFGEdgeDeque& out_edges = dispatch->getOutEdges(); - for (CFGEdgeDeque::const_iterator out_iter = out_edges.begin(); + const Edges& out_edges = dispatch->getOutEdges(); + for (Edges::const_iterator out_iter = out_edges.begin(); out_iter != out_edges.end(); out_iter++) { - CFGNode* catch_node = (*out_iter)->getTargetNode(); + Node* catch_node = (*out_iter)->getTargetNode(); if ( !catch_node->isCatchBlock() ) { continue; } @@ -441,18 +472,18 @@ void JavaFlowGraphBuilder::eliminateUnne //assert(catch_node->hasOnlyOneSuccEdge()); //assert(catch_node->hasOnlyOnePredEdge()); - CFGNode* catch_target = (*(catch_node->getOutEdges().begin()))->getTargetNode(); + Node* catch_target = (*(catch_node->getOutEdges().begin()))->getTargetNode(); if ( catch_target->getInDegree() <= 1 ) { continue; } bool found_monitorexit = false; bool dispatch_is_after_target = false; bool monitorexit_after_catch_target = false; - const CFGEdgeDeque& in_edges = dispatch->getInEdges(); - for (CFGEdgeDeque::const_iterator in_iter = in_edges.begin(); + const Edges& in_edges = dispatch->getInEdges(); + for (Edges::const_iterator in_iter = in_edges.begin(); in_iter != in_edges.end(); in_iter++) { - CFGNode* pre_dispatch = (*in_iter)->getSourceNode(); + Node* pre_dispatch = (*in_iter)->getSourceNode(); if ( pre_dispatch == catch_target ) { dispatch_is_after_target = true; } @@ -476,14 +507,14 @@ void JavaFlowGraphBuilder::eliminateUnne }else if ( dispatch->getInDegree() > 2 ) { // goto into loop found matched_dispatches.push_back(dispatch); - if ( Log::cat_fe()->isDebugEnabled() ) { + if ( Log::isEnabled() ) { Log::out() << "goto into loop found, fixing..." << std::endl; } break; } } if ( !found_goto_into_loop_warning ) { - if ( Log::cat_fe()->isDebugEnabled() ) { + if ( Log::isEnabled() ) { Log::out() << "warning: maybe goto into loop with exception" << std::endl; } @@ -492,40 +523,41 @@ void JavaFlowGraphBuilder::eliminateUnne } } } - for ( CFGNodeDeque::const_iterator dispatch_iter = matched_dispatches.begin(); + InstFactory* instFactory = irBuilder.getInstFactory(); + for ( Nodes::const_iterator dispatch_iter = matched_dispatches.begin(); dispatch_iter != matched_dispatches.end(); dispatch_iter++ ) { - CFGNode* dispatch = (*dispatch_iter); - const CFGEdgeDeque& in_edges = dispatch->getInEdges(); - CFGEdgeDeque::const_iterator in_edge_iter = in_edges.begin(); + Node* dispatch = (*dispatch_iter); + const Edges& in_edges = dispatch->getInEdges(); assert(dispatch->getInDegree() > 1); - for (in_edge_iter++; in_edge_iter != in_edges.end(); in_edge_iter++) { - CFGEdge* in_edge = *in_edge_iter; - CFGNode* dup_dispatch = createDispatchNode(); + while (in_edges.size() > 1) { + Edge* in_edge = *(++in_edges.begin()); + Node* dup_dispatch = createDispatchNode(); fg->replaceEdgeTarget(in_edge, dup_dispatch); - const CFGEdgeDeque& out_edges = dispatch->getOutEdges(); - for (CFGEdgeDeque::const_iterator out_edge_iter = out_edges.begin(); + const Edges& out_edges = dispatch->getOutEdges(); + for (Edges::const_iterator out_edge_iter = out_edges.begin(); out_edge_iter != out_edges.end(); out_edge_iter++) { - CFGNode* dispatch_target = (*out_edge_iter)->getTargetNode(); + Node* dispatch_target = (*out_edge_iter)->getTargetNode(); if ( !dispatch_target->isCatchBlock() ) { fg->addEdge(dup_dispatch, dispatch_target); }else{ - CatchLabelInst* catch_label = (CatchLabelInst*)dispatch_target->getLabel(); - CFGNode* dup_catch = fg->createCatchNode(catch_label->getOrder(), catch_label->getExceptionType()); + CatchLabelInst* catch_label = (CatchLabelInst*)dispatch_target->getFirstInst(); + Node* dup_catch = createBlockNodeOrdered(instFactory->makeCatchLabel(catch_label->getOrder(), catch_label->getExceptionType())); fg->addEdge(dup_dispatch, dup_catch); assert(dispatch_target->getOutDegree() == 1); fg->addEdge(dup_catch, (*dispatch_target->getOutEdges().begin())->getTargetNode()); } + } } } } -bool JavaFlowGraphBuilder::lastInstIsMonitorExit(CFGNode* node) +bool JavaFlowGraphBuilder::lastInstIsMonitorExit(Node* node) { - Inst* last = node->getLastInst(); + Inst* last = (Inst*)node->getLastInst(); if ( last->getOpcode() == Op_TypeMonitorExit || last->getOpcode() == Op_TauMonitorExit ) { return true; @@ -534,9 +566,9 @@ bool JavaFlowGraphBuilder::lastInstIsMon } JavaFlowGraphBuilder::JavaFlowGraphBuilder(MemoryManager& mm, IRBuilder &irB) : - memManager(mm), currentBlock(NULL), irBuilder(irB) + memManager(mm), currentBlock(NULL), irBuilder(irB), fallThruNodes(mm) { - fg = &irBuilder.getFlowGraph(); + fg = irBuilder.getFlowGraph(); } } //namespace Jitrino diff --git vm/jitrino/src/translator/java/JavaFlowGraphBuilder.h vm/jitrino/src/translator/java/JavaFlowGraphBuilder.h index f0f9743..3492a11 100644 --- vm/jitrino/src/translator/java/JavaFlowGraphBuilder.h +++ vm/jitrino/src/translator/java/JavaFlowGraphBuilder.h @@ -23,40 +23,47 @@ #ifndef _JAVAFLOWGRAPHBUILDER_ #define _JAVAFLOWGRAPHBUILDER_ -#include "FlowGraph.h" +#include "MemoryManager.h" +#include "ControlFlowGraph.h" namespace Jitrino { - class JavaFlowGraphBuilder { public: // regular version JavaFlowGraphBuilder(MemoryManager&, IRBuilder &); // version for IR inlining - JavaFlowGraphBuilder(MemoryManager&, IRBuilder &, CFGNode *, FlowGraph *); - CFGNode* genBlock(LabelInst* blockLabel); - CFGNode* genBlockAfterCurrent(LabelInst *label); + JavaFlowGraphBuilder(MemoryManager&, IRBuilder &, Node *, ControlFlowGraph *); + Node* genBlock(LabelInst* blockLabel); + Node* genBlockAfterCurrent(LabelInst *label); void build(); - void buildIRinline(Opnd *ret, FlowGraph *, Inst *callsite); // version for IR inlining - CFGNode* createDispatchNode(); - FlowGraph* getCFG() { return fg; } + void buildIRinline(Opnd *ret, ControlFlowGraph*, Inst *callsite); // version for IR inlining + ControlFlowGraph* getCFG() { return fg; } + Node* createDispatchNode(); private: void createCFGEdges(); - CFGNode* edgesForBlock(CFGNode* block); - void edgesForHandler(CFGNode* entry); - void edgeForFallthrough(CFGNode* block); + Node* edgesForBlock(Node* block); + void edgesForHandler(Node* entry); + void edgeForFallthrough(Node* block); void eliminateUnnestedLoopsOnDispatch(); - bool lastInstIsMonitorExit(CFGNode* node); + bool lastInstIsMonitorExit(Node* node); void resolveWhileTrue(); - void reverseDFS( StlVector<int8>& state, CFGNode* targetNode, uint32* NodesCounter ); - void forwardDFS( StlVector<int8>& state, CFGNode* srcNode ); + void reverseDFS( StlVector<int8>& state, Node* targetNode, uint32* NodesCounter ); + void forwardDFS( StlVector<int8>& state, Node* srcNode, Edges& edges); + + Node* createBlockNodeOrdered(LabelInst* label = NULL); + Node* createBlockNodeAfter(Node* node, LabelInst* label = NULL); + void addEdge(Node* source, Node* target); + // // private fields // MemoryManager& memManager; - CFGNode* currentBlock; - FlowGraph* fg; + Node* currentBlock; + ControlFlowGraph* fg; IRBuilder& irBuilder; +typedef StlList<Node*> NodeList; + NodeList fallThruNodes; }; diff --git vm/jitrino/src/translator/java/JavaLabelPrepass.cpp vm/jitrino/src/translator/java/JavaLabelPrepass.cpp index 9fc94ea..b0f79be 100644 --- vm/jitrino/src/translator/java/JavaLabelPrepass.cpp +++ vm/jitrino/src/translator/java/JavaLabelPrepass.cpp @@ -97,7 +97,7 @@ void VariableIncarnation::mergeIncarnati // return if there is only one incarnation in chain. if (!(t || vi->_next)) return; - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Merging incarnations:" << ::std::endl; if (t) { Log::out() << " assigning common type:"; @@ -120,7 +120,7 @@ void VariableIncarnation::mergeIncarnati varType = tm->getCommonType(varType, vi->getDeclaredType()); } assert(varType); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " ;;set common type: "; varType->print(Log::out()); Log::out() << ::std::endl; @@ -215,7 +215,7 @@ void VariableIncarnation::createVarOpnd( if (opnd) return; opnd = irBuilder->genVarDef(declaredType, false); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "Create operand for VarIncarnation:" << ::std::endl; Log::out() << " opnd:"; opnd->print(Log::out()); Log::out() << ::std::endl; Log::out() << " VarInc:"; print(Log::out()); Log::out() << ::std::endl; @@ -302,7 +302,7 @@ public: exceptionType = prepass.typeManager.getSystemObjectType(); } jitrino_assert(compilationInterface, exceptionType); - Log::cat_fe()->debug << "Catch Exception Type = " << exceptionType->getName() << ::std::endl; + Log::out() << "Catch Exception Type = " << exceptionType->getName() << ::std::endl; CatchHandler* handler = new (memManager) CatchHandler(nextRegionId++, @@ -353,7 +353,7 @@ public: uint32 handlerLength, uint32 exceptionTypeToken) { - Log::cat_fe()->debug << "CatchBlock @ " << (int)tryOffset << "," << (int)tryOffset+(int)tryLength + Log::out() << "CatchBlock @ " << (int)tryOffset << "," << (int)tryOffset+(int)tryLength << " handler @ " << (int)handlerOffset << "," << (int)handlerOffset+(int)handlerLength << " exception type " << (int)exceptionTypeToken << "," << " numCatch " << numCatch << ::std::endl; @@ -386,7 +386,7 @@ public: if ( block->offsetSplits(tryOffset) || block->offsetSplits(endOffset) ) { if ( !unnested_try_regions_found ) { unnested_try_regions_found = true; - Log::cat_fe()->debug << "unnested try-regions encountered" << std::endl; + Log::out() << "unnested try-regions encountered" << std::endl; } } assert(tryOffset < endOffset); @@ -498,7 +498,7 @@ JavaLabelPrepass::JavaLabelPrepass(Memor // inlined version Opnd *actual = actualArgs[i]; type = actual->getType(); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "PARAM " << (int)i << " sig: "; methodSig->getParamType(i)->print(Log::out()); Log::out() << " actual: "; @@ -520,7 +520,7 @@ JavaLabelPrepass::JavaLabelPrepass(Memor } void JavaLabelPrepass::offset(uint32 offset) { - Log::cat_fe()->debug << ::std::endl << "PREPASS OFFSET " << (int32)offset << ", blockNo=" << blockNumber << ::std::endl; + Log::out() << std::endl << "PREPASS OFFSET " << (int32)offset << ", blockNo=" << blockNumber << std::endl; bytecodevisited->setBit(offset,true); if (offset==0) stateTable->restoreStateInfo(&stateInfo, offset); @@ -529,11 +529,11 @@ void JavaLabelPrepass::offset(uint32 off stateTable->restoreStateInfo(&stateInfo, offset); setStackVars(); if (!linearPassDone) { - Log::cat_fe()->debug << "LINEAR " << ::std::endl; + Log::out() << "LINEAR " << std::endl; propagateStateInfo(offset,isFallThruLabel); isFallThruLabel = true; } - Log::cat_fe()->debug << "BASICBLOCK " << (int32)offset << " " << blockNumber << ::std::endl; + Log::out() << "BASICBLOCK " << (int32)offset << " " << blockNumber << std::endl; ++blockNumber; visited->setBit(offset,true); stateTable->restoreStateInfo(&stateInfo,offset); @@ -549,7 +549,7 @@ void JavaLabelPrepass::offset(uint32 off break; } } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "CATCH " << (int32) offset << " "; handlerExceptionType->print(Log::out()); Log::out() << ::std::endl; @@ -568,7 +568,7 @@ void JavaLabelPrepass::offset(uint32 off void JavaLabelPrepass::setLabel(uint32 offset) { if (labels->getBit(offset)) // this label is already seen return; - Log::cat_fe()->debug << "SET LABEL " << (int) offset << " " << (int) numLabels << ::std::endl; + Log::out() << "SET LABEL " << (int) offset << " " << (int) numLabels << ::std::endl; labels->setBit(offset,true); numLabels++; } @@ -697,14 +697,14 @@ void JavaLabelPrepass::pushType(struc void JavaLabelPrepass::setStackVars() { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "SET STACK VARS:" << ::std::endl; } for (int i=numVars; i < stateInfo.stackDepth; i++) { struct StateInfo::SlotInfo* slot = &stateInfo.stack[i]; - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "SLOT " << i << ":" << ::std::endl; Log::out() << " type = "; if (slot->type) @@ -733,7 +733,7 @@ void JavaLabelPrepass::setStackVars() { slot->vars = new (memManager) SlotVar(var); } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "AFTER" << ::std::endl; Log::out() << " type = "; if (slot->type) @@ -749,7 +749,7 @@ void JavaLabelPrepass::setStackVars() { Log::out() << ::std::endl; } } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "SET STACK VARS DONE." << ::std::endl; } } @@ -1123,9 +1123,6 @@ void JavaLabelPrepass::dcmpg() void JavaLabelPrepass::new_(uint32 constPoolIndex) { StateInfo::SlotInfo slot; - slot.slotFlags = 0; - slot.varNumber = 0; - slot.jsrLabelOffset = 0; StateInfo::setNonNull(&slot); StateInfo::setExactType(&slot); Type* nType = resolveTypeNew(constPoolIndex); @@ -1165,10 +1162,6 @@ void JavaLabelPrepass::newarray(uint8 et void JavaLabelPrepass::anewarray(uint32 constPoolIndex) { popAndCheck(int32Type); StateInfo::SlotInfo slot; - slot.slotFlags = 0; - slot.varNumber = 0; - slot.jsrLabelOffset = 0; - StateInfo::setNonNull(&slot); StateInfo::setExactType(&slot); Type* type = resolveType(constPoolIndex); @@ -1267,8 +1260,8 @@ void JavaLabelPrepass::ldc(uint32 constP // load 32-bit quantity or string from constant pool Type* constantType = compilationInterface.getConstantType(&methodDesc,constPoolIndex); - if (constantType->isSystemString()) { - pushType(typeManager.getSystemStringType()); + if (constantType->isSystemString() || constantType->isSystemClass()) { + pushType(constantType); } else if (constantType->isInt4()) { pushType(int32Type); } else if (constantType->isSingle()) { @@ -1660,7 +1653,7 @@ void JavaLabelPrepass::genTypeStore(uint VariableIncarnation* offset_varinc = getOrCreateVarInc(offset, index, type, NULL/*prevVar*/); offset_varinc->setDeclaredType(typeManager.getCommonType(type, offset_varinc->getDeclaredType())); stateInfo.stack[index].vars = new (memManager) SlotVar(offset_varinc); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "genTypeStore: offset=" << offset << " index=" << index << " vars: "; @@ -1814,7 +1807,7 @@ void StateTable::copySlotInfo(StateInfo: } void StateTable::setStateInfo(StateInfo *inState, uint32 offset, bool isFallThru) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "SETSTATE offset=" <<(int)offset << " depth=" << inState->stackDepth << ::std::endl; printState(inState); } @@ -1837,7 +1830,7 @@ void StateTable::setStateInfo(StateInfo CatchBlock* except = *it; if ( except->hasOffset(offset) ) { - Log::cat_fe()->debug << "try-region begin=" << (int)except->getBeginOffset() + Log::out() << "try-region begin=" << (int)except->getBeginOffset() << " end=" << (int)except->getEndOffset() << ::std::endl; ExceptionInfo *prev = state->exceptionInfo; bool found = false; @@ -1870,7 +1863,7 @@ void StateTable::setStateInfo(StateInfo int stackDepth = inState->stackDepth; if (stackDepth > 0) { if (maxDepth < stackDepth) maxDepth = stackDepth; - Log::cat_fe()->debug << "MAXDEPTH " << maxDepth << ::std::endl; + Log::out() << "MAXDEPTH " << maxDepth << ::std::endl; struct StateInfo::SlotInfo *stack = state->stack; if (stack == NULL) { stack = new (memManager) StateInfo::SlotInfo[stackDepth+1]; @@ -1881,14 +1874,14 @@ void StateTable::setStateInfo(StateInfo state->stackDepth = stackDepth; } else { // needs to merge the states assert(state->stackDepth == stackDepth); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " before\n"; printState(state); } for (int i=0; i < stackDepth; i++) { struct StateInfo::SlotInfo *inSlot = &inState->stack[i]; struct StateInfo::SlotInfo *slot = &stack[i]; - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " i = " << i << ::std::endl; Log::out() << "inSlot->type: "; if (inSlot->type) { @@ -1914,7 +1907,7 @@ void StateTable::setStateInfo(StateInfo mergeSlots(inSlot, slot, offset, i < numVars); } } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " after\n"; printState(state); } @@ -1948,7 +1941,7 @@ void StateTable::mergeSlots(StateInfo::S Type* new_type = typeManager.getCommonType(in_type,type); if (new_type != NULL) { if (vars) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "addVarIncarnations to SlotVar:" << ::std::endl; Log::out() << " vars: "; vars->print(Log::out()); @@ -1961,7 +1954,7 @@ void StateTable::mergeSlots(StateInfo::S if (!isVar) { vars->mergeVarIncarnations(&typeManager); } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "result_vars: "; vars->print(Log::out()); } @@ -1978,7 +1971,7 @@ void StateTable::mergeSlots(StateInfo::S void StateTable::setStateInfoFromFinally(StateInfo *inState, uint32 offset) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "SETSTATE FROM FINALLY offset=" <<(int)offset << " depth=" << inState->stackDepth << ::std::endl; printState(inState); } @@ -1987,14 +1980,14 @@ void StateTable::setStateInfoFromFinall int stackDepth = inState->stackDepth; if (stackDepth > 0) { if (maxDepth < stackDepth) maxDepth = stackDepth; - Log::cat_fe()->debug << "MAXDEPTH " << maxDepth << ::std::endl; + Log::out() << "MAXDEPTH " << maxDepth << ::std::endl; struct StateInfo::SlotInfo *stack = state->stack; if (stack == NULL) { // stack must be propagated from JSR to jsrNext earlier assert(0); } assert(state->stackDepth == stackDepth); - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " before\n"; printState(state); } @@ -2003,7 +1996,7 @@ void StateTable::setStateInfoFromFinall struct StateInfo::SlotInfo *slot = &stack[i]; Type *intype = inSlot->type; Type *type = slot->type; - Log::cat_fe()->debug << "STACK " << i << ": "<< type << ::std::endl; + Log::out() << "STACK " << i << ": "<< type << ::std::endl; if (!type && intype) { // don't merge, just rewrite! slot->type = intype; // Consider copying not pointers but SlotVat structures. @@ -2017,7 +2010,7 @@ void StateTable::setStateInfoFromFinall mergeSlots(inSlot, slot, offset, i < numVars); } } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << " after\n"; printState(state); } @@ -2056,7 +2049,7 @@ void JavaLabelPrepass::propagateLocalVar uint32 handler_offset = handler->getBeginOffset(); struct StateInfo::SlotInfo *slot = &stateTable->getStateInfo(handler_offset)->stack[varIndex]; - Log::cat_fe()->debug << "HANDLER SLOT " << varIndex << " merged to offset " << handler_offset << ::std::endl; + Log::out() << "HANDLER SLOT " << varIndex << " merged to offset " << handler_offset << ::std::endl; stateTable->mergeSlots(inSlot, slot, handler_offset, true); } } diff --git vm/jitrino/src/translator/java/JavaLabelPrepass.h vm/jitrino/src/translator/java/JavaLabelPrepass.h index 087a93d..c1b4541 100644 --- vm/jitrino/src/translator/java/JavaLabelPrepass.h +++ vm/jitrino/src/translator/java/JavaLabelPrepass.h @@ -128,7 +128,7 @@ public: uint16 slotFlags; SlotVar *vars; uint32 jsrLabelOffset; - SlotInfo() : type(0), varNumber(0), slotFlags(0), vars(0), jsrLabelOffset(0) {} + SlotInfo() : type(NULL), varNumber(0), slotFlags(0), vars(NULL), jsrLabelOffset(0){} }; // remove all slots containing returnAddress for RET instruction with jsrNexOffset == offset @@ -290,6 +290,7 @@ public: case Type::NullObject: case Type::SystemString: case Type::SystemObject: + case Type::SystemClass: case Type::CompressedArray: case Type::CompressedObject: case Type::CompressedNullObject: @@ -561,7 +562,7 @@ public: state = new (memManager) StateInfo(); hashtable[offset] = state; } - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "CREATESTATE " <<(int)offset << " depth " << state->stackDepth << ::std::endl; printState(state); } @@ -574,7 +575,7 @@ public: void setStateInfoFromFinally(StateInfo *inState, uint32 offset); void restoreStateInfo(StateInfo *stateInfo, uint32 offset) { - if(Log::cat_fe()->isDebugEnabled()) { + if(Log::isEnabled()) { Log::out() << "INIT_STATE_FOR_BLOCK " <<(int)offset << " depth " << stateInfo->stackDepth << ::std::endl; printState(stateInfo); } @@ -593,7 +594,7 @@ public: for (CatchHandler *handler = block->getHandlers(); handler != NULL; handler = handler->getNextHandler()) { int cstart = handler->getBeginOffset(); - Log::cat_fe()->debug << "SETCATCHINFO "<<(int)cstart<<" "<<(int)prepass.getNumVars()<< ::std::endl; + Log::out() << "SETCATCHINFO "<<(int)cstart<<" "<<(int)prepass.getNumVars()<< ::std::endl; prepass.pushCatchLabel(cstart); int stackDepth = stateInfo->stackDepth; stateInfo->stackDepth = prepass.getNumVars(); diff --git vm/jitrino/src/translator/java/JavaTranslator.cpp vm/jitrino/src/translator/java/JavaTranslator.cpp index 26aaa55..0de1223 100644 --- vm/jitrino/src/translator/java/JavaTranslator.cpp +++ vm/jitrino/src/translator/java/JavaTranslator.cpp @@ -30,31 +30,30 @@ #include "ByteCodeParser.h" #include "JavaByteCodeTranslator.h" #include "MemoryEstimates.h" #include "Log.h" +#include "CGSupport.h" +#include "FlowGraph.h" namespace Jitrino { -void -JavaTranslator::translateMethod(CompilationInterface& compilationInterface, - MethodDesc& methodDesc, - IRBuilder& irBuilder) { +void JavaTranslator::translateMethod(CompilationInterface& ci, MethodDesc& methodDesc, IRBuilder& irBuilder) { + uint32 byteCodeSize = methodDesc.getByteCodeSize(); const unsigned char* byteCodes = methodDesc.getByteCodes(); - MemoryManager - translatorMemManager(byteCodeSize*ESTIMATED_TRANSLATOR_MEMORY_PER_BYTECODE, + MemoryManager translatorMemManager(byteCodeSize*ESTIMATED_TRANSLATOR_MEMORY_PER_BYTECODE, "JavaTranslator::translateMethod.translatorMemManager"); - JavaFlowGraphBuilder cfgBuilder(irBuilder.getInstFactory().getMemManager(),irBuilder); + JavaFlowGraphBuilder cfgBuilder(irBuilder.getInstFactory()->getMemManager(),irBuilder); ByteCodeParser parser((const uint8*)byteCodes,byteCodeSize); // generate code - JavaByteCodeTranslator translator(compilationInterface, + JavaByteCodeTranslator translator(ci, translatorMemManager, irBuilder, parser, methodDesc, - irBuilder.getTypeManager(), + *irBuilder.getTypeManager(), cfgBuilder); - // isInlined + // isInlined parser.parse(&translator); cfgBuilder.build(); } @@ -86,66 +85,21 @@ JavaCompileMethodInline(CompilationInter irBuilder, parser, methodDesc, - irBuilder.getTypeManager(), + *irBuilder.getTypeManager(), cfgBuilder, numActualArgs,actualArgs,NULL,NULL, (ExceptionInfo*)irBuilder.getCurrentLabel()->getState(), inlineDepth,false /* startNewBlock */, parentInlineInfoBuilder, parentJsrEntryMap); // isInlined=true for this c-tor + if ( compilationInterface.isBCMapInfoRequired()) { + size_t incSize = byteCodeSize * ESTIMATED_HIR_SIZE_PER_BYTECODE; + MethodDesc* parentMethod = compilationInterface.getMethodToCompile(); + incVectorHandlerSize(bcOffset2HIRHandlerName, parentMethod, incSize); + } parser.parse(&translator); return translator.getResultOpnd(); } -// version for IR inlining -void -JavaTranslateMethodForIRInlining( - CompilationInterface& compilationInterface, - MethodDesc& methodDesc, - IRBuilder& irBuilder, - uint32 numActualArgs, - Opnd** actualArgs, - Opnd** returnOpnd, - CFGNode** returnNode, - Inst* inlineSite, - uint32 inlineDepth) { - uint32 byteCodeSize = methodDesc.getByteCodeSize(); - const unsigned char* byteCodes = methodDesc.getByteCodes(); - MemoryManager - translatorMemManager(byteCodeSize*ESTIMATED_TRANSLATOR_MEMORY_PER_BYTECODE, - "JavaTranslator::translateMethod.translatorMemManager"); - - - JavaFlowGraphBuilder cfgBuilder(irBuilder.getInstFactory().getMemManager(), - irBuilder); - - ByteCodeParser parser((const uint8*)byteCodes,byteCodeSize); - // generate code - ExceptionInfo *exceptionInfo = NULL; - JavaByteCodeTranslator translator(compilationInterface, - translatorMemManager, - irBuilder, - parser, - methodDesc, - irBuilder.getTypeManager(), - cfgBuilder, - numActualArgs,actualArgs, - returnOpnd,returnNode, - exceptionInfo, - inlineDepth,true /* startNewBlock */, - NULL /* parentInlineInfoBuilder */, - NULL /* parentJsrEntryMap */); // isInlined=true for this c-tor - - translator.setNoInlineInfoBuilder(); - - parser.parse(&translator); - cfgBuilder.build(); - if(Log::cat_opt()->isDebugEnabled()) { - FlowGraph &ojo = irBuilder.getFlowGraph(); - Log::out() << "INLINED\n"; - ojo.printInsts(Log::out(),methodDesc); - } -} - } //namespace Jitrino diff --git vm/jitrino/src/translator/java/JavaTranslator.h vm/jitrino/src/translator/java/JavaTranslator.h index 6adf85c..b7a3a71 100644 --- vm/jitrino/src/translator/java/JavaTranslator.h +++ vm/jitrino/src/translator/java/JavaTranslator.h @@ -24,11 +24,13 @@ #ifndef _JAVATRANSLATOR_H_ #define _JAVATRANSLATOR_H_ #include "TranslatorIntfc.h" -#include "InlineInfo.h" +#include "Stl.h" namespace Jitrino { class Opnd; class JavaFlowGraphBuilder; +class Inst; +class InlineInfoBuilder; typedef StlMultiMap<Inst*, Inst*> JsrEntryInstToRetInstMap; typedef std::pair<JsrEntryInstToRetInstMap::const_iterator, @@ -48,25 +50,12 @@ extern Opnd* JavaCompileMethodInline( InlineInfoBuilder* parentInlineInfoBuilder, JsrEntryInstToRetInstMap* parentJsrEntryMap); -// version for IR inlining -void -JavaTranslateMethodForIRInlining( - CompilationInterface& compilationInterface, - MethodDesc& methodDesc, - IRBuilder& irBuilder, - uint32 numActualArgs, - Opnd** actualArgs, - Opnd** returnOpnd, - CFGNode** returnNode, - Inst* inlineSite, - uint32 inlineDepth); -class JavaTranslator : public TranslatorIntfc { +class JavaTranslator { public: + // translates into the IRBuilder object's flow graph. - void translateMethod(CompilationInterface&, - MethodDesc&, - IRBuilder&); + static void translateMethod(CompilationInterface& ci, MethodDesc& methodDesc, IRBuilder& irBuilder); }; } //namespace Jitrino diff --git vm/jitrino/src/vm/EMInterface.h vm/jitrino/src/vm/EMInterface.h new file mode 100644 index 0000000..036874a --- /dev/null +++ vm/jitrino/src/vm/EMInterface.h @@ -0,0 +1,119 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/* COPYRIGHT_NOTICE */ + +/** +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ + +#ifndef _EMINTERFACE_H_ +#define _EMINTERFACE_H_ + +#include "VMInterface.h" + + +namespace Jitrino { + +enum ProfileType { + ProfileType_Invalid =0, + ProfileType_EntryBackedge =1, + ProfileType_Edge = 2 +}; + +enum JITProfilingRole{ + JITProfilingRole_GEN =1, + JITProfilingRole_USE =2 +}; + +//M1 implementation of profiling interfaces +class MethodProfile; +class MemoryManager; +class EntryBackedgeMethodProfile; +class EdgeMethodProfile; + +typedef void PC_Callback_Fn(Method_Profile_Handle); + +class ProfilingInterface { +public: + virtual ~ProfilingInterface(){}; + + virtual MethodProfile* getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const = 0; + virtual bool hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const = 0; + virtual bool enableProfiling(PC_Handle pc, JITProfilingRole role) = 0; + virtual bool isProfilingEnabled(ProfileType pcType, JITProfilingRole jitRole) const = 0; + + + virtual uint32 getProfileMethodCount(MethodDesc& md, JITProfilingRole role = JITProfilingRole_USE) const = 0; + + virtual EntryBackedgeMethodProfile* createEBMethodProfile(MemoryManager& mm, MethodDesc& md) =0; + virtual bool isEBProfilerInSyncMode() const = 0; + virtual PC_Callback_Fn* getEBProfilerSyncModeCallback() const = 0; + + + virtual EdgeMethodProfile* createEdgeMethodProfile(MemoryManager& mm, MethodDesc& md, uint32 numEdgeCounters, uint32* counterKeys, uint32 checkSum) =0; + + + virtual uint32 getMethodEntryThreshold() const = 0; + virtual uint32 getBackedgeThreshold() const = 0; + + virtual EntryBackedgeMethodProfile* getEBMethodProfile(MemoryManager& mm, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const { + return (EntryBackedgeMethodProfile*)getMethodProfile(mm, ProfileType_EntryBackedge, md, role); + } + + virtual EdgeMethodProfile* getEdgeMethodProfile(MemoryManager& mm, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const { + return (EdgeMethodProfile*)getMethodProfile(mm, ProfileType_Edge, md, role); + } + +}; + +class MethodProfile { +public: + MethodProfile(Method_Profile_Handle _handle, ProfileType _type, MethodDesc& _md) + : handle(_handle), type(_type), md(_md){} + virtual ~MethodProfile(){}; + Method_Profile_Handle getHandle() const { return handle;} + MethodDesc& getMethod() const {return md;} + ProfileType getProfileType() const {return type;} +private: + Method_Profile_Handle handle; + ProfileType type; + MethodDesc& md; +}; + +class EntryBackedgeMethodProfile : public MethodProfile { +public: + EntryBackedgeMethodProfile (Method_Profile_Handle handle, MethodDesc& md): MethodProfile(handle, ProfileType_EntryBackedge, md){} + + virtual uint32 getEntryExecCount() const = 0; + virtual uint32 getBackedgeExecCount() const = 0; + virtual uint32* getEntryCounter() const = 0; + virtual uint32* getBackedgeCounter() const = 0; +}; + +class EdgeMethodProfile : public MethodProfile { +public: + EdgeMethodProfile (Method_Profile_Handle handle, MethodDesc& md): MethodProfile(handle, ProfileType_Edge, md){} + + virtual uint32 getNumCounters() const = 0; + virtual uint32 getCheckSum() const = 0; + virtual uint32* getEntryCounter() const = 0; + virtual uint32* getCounter(uint32 key) const = 0; +}; + +};//namespace + +#endif //_EMINTERFACE_H_ diff --git vm/jitrino/src/vm/VMInterface.cpp vm/jitrino/src/vm/VMInterface.cpp index b36614b..bb67352 100644 --- vm/jitrino/src/vm/VMInterface.cpp +++ vm/jitrino/src/vm/VMInterface.cpp @@ -34,87 +34,89 @@ namespace Jitrino { The following struct and array contains a mapping between RuntimeHelperId and its string representation. The array must be - ordered by RuntimeHelperId - must cover all available helpers + ordered by RuntimeHelperId + must cover all available helpers The id field exists only in debug build and is excluded from the release bundle. It's used to control whether the array is arranged properly. */ #ifdef _DEBUG -#define DECL_HELPER_ITEM(a) { CompilationInterface::Helper_##a, #a } +#define DECL_HELPER_ITEM(a) { CompilationInterface::Helper_##a, #a } #else -#define DECL_HELPER_ITEM(a) { #a } +#define DECL_HELPER_ITEM(a) { #a } #endif static struct { #ifdef _DEBUG - CompilationInterface::RuntimeHelperId id; + CompilationInterface::RuntimeHelperId id; #endif - const char * name; + const char * name; } runtime_helpers_names[] = { - DECL_HELPER_ITEM(Null), - DECL_HELPER_ITEM(NewObj_UsingVtable), - DECL_HELPER_ITEM(NewVector_UsingVtable), - DECL_HELPER_ITEM(NewObj), - DECL_HELPER_ITEM(NewVector), - DECL_HELPER_ITEM(NewMultiArray), - DECL_HELPER_ITEM(LdInterface), - DECL_HELPER_ITEM(LdString), - DECL_HELPER_ITEM(ObjMonitorEnter), - DECL_HELPER_ITEM(ObjMonitorExit), - DECL_HELPER_ITEM(TypeMonitorEnter), - DECL_HELPER_ITEM(TypeMonitorExit), - DECL_HELPER_ITEM(Cast), - DECL_HELPER_ITEM(IsInstanceOf), - DECL_HELPER_ITEM(InitType), - DECL_HELPER_ITEM(IsValidElemType), - DECL_HELPER_ITEM(Throw_KeepStackTrace), - DECL_HELPER_ITEM(Throw_SetStackTrace), + DECL_HELPER_ITEM(Null), + DECL_HELPER_ITEM(NewObj_UsingVtable), + DECL_HELPER_ITEM(NewVector_UsingVtable), + DECL_HELPER_ITEM(NewObj), + DECL_HELPER_ITEM(NewVector), + DECL_HELPER_ITEM(NewMultiArray), + DECL_HELPER_ITEM(LdInterface), + DECL_HELPER_ITEM(LdRef), + DECL_HELPER_ITEM(ObjMonitorEnter), + DECL_HELPER_ITEM(ObjMonitorExit), + DECL_HELPER_ITEM(TypeMonitorEnter), + DECL_HELPER_ITEM(TypeMonitorExit), + DECL_HELPER_ITEM(Cast), + DECL_HELPER_ITEM(IsInstanceOf), + DECL_HELPER_ITEM(InitType), + DECL_HELPER_ITEM(IsValidElemType), + DECL_HELPER_ITEM(Throw_KeepStackTrace), + DECL_HELPER_ITEM(Throw_SetStackTrace), DECL_HELPER_ITEM(Throw_Lazy), - DECL_HELPER_ITEM(EndCatch), - DECL_HELPER_ITEM(NullPtrException), - DECL_HELPER_ITEM(ArrayBoundsException), - DECL_HELPER_ITEM(ElemTypeException), - DECL_HELPER_ITEM(DivideByZeroException), - DECL_HELPER_ITEM(Throw_LinkingException), - DECL_HELPER_ITEM(CharArrayCopy), - DECL_HELPER_ITEM(DivI32), - DECL_HELPER_ITEM(DivU32), - DECL_HELPER_ITEM(DivI64), - DECL_HELPER_ITEM(DivU64), - DECL_HELPER_ITEM(DivSingle), - DECL_HELPER_ITEM(DivDouble), - DECL_HELPER_ITEM(RemI32), - DECL_HELPER_ITEM(RemU32), - DECL_HELPER_ITEM(RemI64), - DECL_HELPER_ITEM(RemU64), - DECL_HELPER_ITEM(RemSingle), - DECL_HELPER_ITEM(RemDouble), - DECL_HELPER_ITEM(MulI64), - DECL_HELPER_ITEM(ShlI64), - DECL_HELPER_ITEM(ShrI64), - DECL_HELPER_ITEM(ShruI64), - DECL_HELPER_ITEM(ConvStoI32), - DECL_HELPER_ITEM(ConvStoI64), - DECL_HELPER_ITEM(ConvDtoI32), - DECL_HELPER_ITEM(ConvDtoI64), - DECL_HELPER_ITEM(EnableThreadSuspension), - DECL_HELPER_ITEM(GetSuspReqFlag), + DECL_HELPER_ITEM(EndCatch), + DECL_HELPER_ITEM(NullPtrException), + DECL_HELPER_ITEM(ArrayBoundsException), + DECL_HELPER_ITEM(ElemTypeException), + DECL_HELPER_ITEM(DivideByZeroException), + DECL_HELPER_ITEM(Throw_LinkingException), + DECL_HELPER_ITEM(CharArrayCopy), + DECL_HELPER_ITEM(DivI32), + DECL_HELPER_ITEM(DivU32), + DECL_HELPER_ITEM(DivI64), + DECL_HELPER_ITEM(DivU64), + DECL_HELPER_ITEM(DivSingle), + DECL_HELPER_ITEM(DivDouble), + DECL_HELPER_ITEM(RemI32), + DECL_HELPER_ITEM(RemU32), + DECL_HELPER_ITEM(RemI64), + DECL_HELPER_ITEM(RemU64), + DECL_HELPER_ITEM(RemSingle), + DECL_HELPER_ITEM(RemDouble), + DECL_HELPER_ITEM(MulI64), + DECL_HELPER_ITEM(ShlI64), + DECL_HELPER_ITEM(ShrI64), + DECL_HELPER_ITEM(ShruI64), + DECL_HELPER_ITEM(ConvStoI32), + DECL_HELPER_ITEM(ConvStoI64), + DECL_HELPER_ITEM(ConvDtoI32), + DECL_HELPER_ITEM(ConvDtoI64), + DECL_HELPER_ITEM(EnableThreadSuspension), + DECL_HELPER_ITEM(GetSuspReqFlag), + DECL_HELPER_ITEM(MethodEntry), + DECL_HELPER_ITEM(MethodExit), #undef DECL_HELPER_ITEM }; static const unsigned runtime_helpers_names_count = sizeof(runtime_helpers_names)/sizeof(runtime_helpers_names[0]); #ifdef _DEBUG static inline void checkArray(void) { - static bool doCheck = true; - if( !doCheck ) return; + static bool doCheck = true; + if( !doCheck ) return; - doCheck = false; - // all helpers must be covered - for( size_t i=0; i<runtime_helpers_names_count; i++ ) { - // the map must be ordered by RuntimeHelperId - assert( (size_t)runtime_helpers_names[i].id == i ); - } + doCheck = false; + // all helpers must be covered + for( size_t i=0; i<runtime_helpers_names_count; i++ ) { + // the map must be ordered by RuntimeHelperId + assert( (size_t)runtime_helpers_names[i].id == i ); + } } #else #define checkArray() @@ -122,17 +124,17 @@ #endif const char* CompilationInterface::getRuntimeHelperName( RuntimeHelperId helperId ){ - checkArray(); - assert( Num_Helpers > helperId ); - return runtime_helpers_names[helperId].name; + checkArray(); + assert( Num_Helpers > helperId ); + return runtime_helpers_names[helperId].name; } CompilationInterface::RuntimeHelperId CompilationInterface::str2rid( const char * helperName ) { - checkArray(); - for( size_t i = 0; i<runtime_helpers_names_count; i++ ) { - if( !strcmpi(helperName, runtime_helpers_names[i].name)) return (RuntimeHelperId)i; - } - return Helper_Null; + checkArray(); + for( size_t i = 0; i<runtime_helpers_names_count; i++ ) { + if( !strcmpi(helperName, runtime_helpers_names[i].name)) return (RuntimeHelperId)i; + } + return Helper_Null; } diff --git vm/jitrino/src/vm/VMInterface.h vm/jitrino/src/vm/VMInterface.h index 847d5eb..6b8750b 100644 --- vm/jitrino/src/vm/VMInterface.h +++ vm/jitrino/src/vm/VMInterface.h @@ -23,6 +23,7 @@ #ifndef _VMINTERFACE_H_ #define _VMINTERFACE_H_ #include <cstring> +#include <string> #ifdef __GNUC__ typedef ::std::size_t size_t; #endif @@ -39,7 +40,7 @@ namespace Jitrino { // external declarations class TypeManager; -class JITModeData; +class JITInstanceContext; class Type; class NamedType; class ObjectType; @@ -47,6 +48,7 @@ class MethodPtrType; class PersistentInstructionId; class MemoryManager; class CompilationContext; +struct AddrLocation; /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// @@ -56,8 +58,8 @@ class CompilationContext; class ExceptionCallback { public: - virtual ~ExceptionCallback() {} + virtual void catchBlock(uint32 tryOffset, uint32 tryLength, uint32 handlerOffset, @@ -84,6 +86,7 @@ public: class MethodSignatureDesc { public: virtual ~MethodSignatureDesc() {} + virtual uint32 getNumParams() = 0; virtual Type** getParamTypes() = 0; virtual Type* getParamType(uint32 paramIndex) = 0; @@ -93,9 +96,10 @@ public: class TypeMemberDesc { public: virtual ~TypeMemberDesc() {} + virtual const char* getName() = 0; virtual const char* getSignatureString() = 0; - virtual void printFullName(::std::ostream& os) = 0; + virtual void printFullName(::std::ostream& os) = 0; virtual NamedType* getParentType() = 0; virtual uint32 getId() = 0; virtual bool isPrivate() = 0; @@ -105,6 +109,7 @@ public: class FieldDesc : public TypeMemberDesc { public: virtual ~FieldDesc() {} + // // this field is constant after it is initialized // can only be mutated by constructor (instance fields) or @@ -126,6 +131,7 @@ public: class MethodDesc : public TypeMemberDesc { public: virtual ~MethodDesc() {} + virtual bool isNative() = 0; virtual bool isSynchronized() = 0; virtual bool isNoInlining() = 0; @@ -213,6 +219,7 @@ inline ::std::ostream& operator<<(::std: class ClassHierarchyIterator { public: virtual ~ClassHierarchyIterator() {} + virtual bool isValid() = 0; // true if iterator is valid virtual bool hasNext() = 0; // true if iterator is not done virtual ObjectType* getNext() = 0; // return next class in iterator and advance iterator @@ -228,7 +235,10 @@ public: class CompilationInterface { public: + + CompilationInterface(CompilationContext* cc) : compilationContext(cc){} virtual ~CompilationInterface() {} + virtual TypeManager& getTypeManager() = 0; // // returns the method to compile @@ -273,17 +283,17 @@ public: uint32 constantToken) = 0; virtual const void* getConstantValue(MethodDesc* enclosingMethod, uint32 constantToken) = 0; - // resolve-by-name methods - /** - * Resolve a system class by its name. - * Returns NULL if no such class found. - */ - virtual ObjectType * resolveSystemClass( const char * klassName ) = 0; - /** - * Recursively looks up for a given method with a given signature in the given class. - * Returns NULL if no such method found. - */ - virtual MethodPtrType * resolveMethod( ObjectType * klass, const char * methodName, const char * methodSig) = 0; + // resolve-by-name methods + /** + * Resolve a system class by its name. + * Returns NULL if no such class found. + */ + virtual ObjectType * resolveSystemClass( const char * klassName ) = 0; + /** + * Recursively looks up for a given method with a given signature in the given class. + * Returns NULL if no such method found. + */ + virtual MethodPtrType * resolveMethod( ObjectType * klass, const char * methodName, const char * methodSig) = 0; // Class type is a subclass of ch=mh->getParentType() The function returns // a method description for a method overriding mh in type or in the closest @@ -320,7 +330,7 @@ public: Helper_NewVector, // Vector* vec = f(uint32 numElem, void* arrTypeRuntimeId) Helper_NewMultiArray, // Array * arr = f(void* arrTypeRuntimeId,uint32 numDims, uint32 dimN, ...,uint32 dim1) Helper_LdInterface, // Vtable* vtable = f(Object* obj, void* interfRuntimeId) - Helper_LdString, // String* str = f(void* classRuntimeId, uint32 strToken) + Helper_LdRef, // [String|Ref]* str = f(void* classRuntimeId, uint32 strToken) Helper_ObjMonitorEnter, // = f(Object* obj) Helper_ObjMonitorExit, // = f(Object* obj) Helper_TypeMonitorEnter, // = f(void* typeRuntimeId) @@ -330,8 +340,8 @@ public: Helper_InitType, // = f(void* typeRutimeId) Helper_IsValidElemType, // [1(yes)/0(no)] = f(Object* elem, Object* array) Helper_Throw_KeepStackTrace, // f(Object* exceptionObj) - Helper_Throw_SetStackTrace, // f(Object* exceptionObj) - Helper_Throw_Lazy, // f(MethodHandle /*of the <init>*/, .../*<init> params*/, ClassHandle) + Helper_Throw_SetStackTrace, // f(Object* exceptionObj) + Helper_Throw_Lazy, // f(MethodHandle /*of the <init>*/, .../*<init> params*/, ClassHandle) Helper_EndCatch, Helper_NullPtrException, // f() Helper_ArrayBoundsException,// f() @@ -361,6 +371,8 @@ public: Helper_ConvDtoI64, // int64 x = f(double x) Helper_EnableThreadSuspension,// f() Helper_GetSuspReqFlag,// int * = f() + Helper_MethodEntry, // f(MethodHandle) + Helper_MethodExit, // f(MethodHandle, void* ret_value) Num_Helpers }; // @@ -375,12 +387,12 @@ public: virtual void* getRuntimeHelperAddress(RuntimeHelperId) = 0; virtual void* getRuntimeHelperAddressForType(RuntimeHelperId id, Type* type) = 0; static const char* getRuntimeHelperName(RuntimeHelperId helperId); - /** - * Returns RuntimeHelperId by its string representation. Name comparison - * is case-sensitive. - * If the helperName is unknown, then Helper_Null is returned. - */ - static RuntimeHelperId str2rid( const char * helperName ); + /** + * Returns RuntimeHelperId by its string representation. Name comparison + * is case-sensitive. + * If the helperName is unknown, then Helper_Null is returned. + */ + static RuntimeHelperId str2rid( const char * helperName ); // // method side effects (for lazy exception throwing optimization) @@ -479,11 +491,7 @@ public: void * callbackData) = 0; // - // accessors for dynamic profiling flags - // - virtual bool isDynamicProfiling() = 0; - virtual uint32 getOptimizationLevel() = 0; - + // write barrier instructions virtual bool insertWriteBarriers() = 0; @@ -493,6 +501,16 @@ public: // produce BC to native map info virtual bool isBCMapInfoRequired() = 0; + virtual bool isCompileLoadEventRequired() = 0; + + // send compile + virtual void sendCompiledMethodLoadEvent(MethodDesc * methodDesc, + uint32 codeSize, void* codeAddr, uint32 mapLength, + AddrLocation* addrLocationMap, void* compileInfo) = 0; + + // get compilation params + virtual OpenMethodExecutionParams& getCompilationParams() = 0; + // synchronization inlining struct ObjectSynchronizationInfo { uint32 threadIdReg; // the register number that holds id of the current thread @@ -521,26 +539,22 @@ public: virtual VmCallingConvention getManagedCallingConvention() = 0; virtual VmCallingConvention getRuntimeHelperCallingConvention(RuntimeHelperId id) = 0; - /** - * Requests VM to request this JIT to synchronously (in the same thread) compile given method. - * @param method method to compile - * @return true on successful compilation, false otherwise - */ - virtual bool compileMethod(MethodDesc *method) = 0; - - /** - * @param method JIT internal method descriptor - * @return runtime handle of the corresponding VM object for the method - */ - virtual void* getRuntimeMethodHandle(MethodDesc *method) = 0; - - virtual JITModeData* getModeData() const = 0; - virtual JIT_Handle getJitHandle() const = 0; + /** + * Requests VM to request this JIT to synchronously (in the same thread) compile given method. + * @param method method to compile + * @return true on successful compilation, false otherwise + */ + virtual bool compileMethod(MethodDesc *method) = 0; - void setCompilationContext(CompilationContext* s) {compilationContext = s;} - CompilationContext* getCompilationContext() const {return compilationContext;} + /** + * @param method JIT internal method descriptor + * @return runtime handle of the corresponding VM object for the method + */ + virtual void* getRuntimeMethodHandle(MethodDesc *method) = 0; + + virtual CompilationContext* getCompilationContext() const {return compilationContext;} -private: +protected: /** Settings per compilation session: vminterface + optimizer flags and so on.. * Today we pass compilation interface through the all compilation. To avoid global * changes in JIT subcomponents interfaces CompilationContext struct is placed here. @@ -548,9 +562,16 @@ private: CompilationContext* compilationContext; }; +// AddrLocation data structure should be put in VM-JIT interface +struct AddrLocation { + void* start_addr; + uint16 location; +}; + class DataInterface { public: virtual ~DataInterface() {} + // // returns true if instance fields that are references are compressed // @@ -565,6 +586,7 @@ public: class GCInterface { public: virtual ~GCInterface() {} + virtual void enumerateRootReference(void** reference) = 0; virtual void enumerateCompressedRootReference(uint32* reference) = 0; virtual void enumerateRootManagedReference(void** slotReference, int slotOffset) = 0; @@ -577,12 +599,14 @@ public: class BinaryRewritingInterface { public: virtual ~BinaryRewritingInterface() {} + virtual void rewriteCodeBlock(Byte* codeBlock, Byte* newCode, size_t length) = 0; }; class Compiler { public: virtual ~Compiler() {} + // // Return true if the method has been successfully compiled, // false - otherwise @@ -590,65 +614,6 @@ public: virtual bool compileMethod(CompilationInterface*) = 0; }; -enum ProfileType { - ProfileType_Invalid =0, - ProfileType_EntryBackedge =1 -}; - -enum JITProfilingRole{ - JITProfilingRole_GEN =1, - JITProfilingRole_USE =2 -}; - -//M1 implementation of profiling interfaces -class MethodProfile; -class MemoryManager; -class EntryBackedgeMethodProfile; - -typedef void PC_Callback_Fn(Method_Profile_Handle); - -class ProfilingInterface { -public: - virtual ~ProfilingInterface() {} - - virtual MethodProfile* getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const = 0; - virtual bool hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const = 0; - virtual bool enableProfiling(PC_Handle pc, JITProfilingRole role) = 0; - virtual bool isProfilingEnabled(ProfileType pcType, JITProfilingRole jitRole) const = 0; - - - virtual EntryBackedgeMethodProfile* createEBMethodProfile(MemoryManager& mm, MethodDesc& md) =0; - virtual uint32 getEBProfilerMethodEntryThreshold() const = 0; - virtual uint32 getEBProfilerBackedgeThreshold() const = 0; - virtual bool isEBProfilerInSyncMode() const = 0; - virtual PC_Callback_Fn* getEBProfilerSyncModeCallback() const = 0; - -}; - -class MethodProfile { -public: - MethodProfile(Method_Profile_Handle _handle, ProfileType _type, MethodDesc& _md) - : handle(_handle), type(_type), md(_md){} - virtual ~MethodProfile(){}; - Method_Profile_Handle getHandle() const { return handle;} - MethodDesc& getMethod() const {return md;} - ProfileType getProfileType() const {return type;} -private: - Method_Profile_Handle handle; - ProfileType type; - MethodDesc& md; -}; - -class EntryBackedgeMethodProfile : public MethodProfile { -public: - EntryBackedgeMethodProfile (Method_Profile_Handle handle, MethodDesc& md): MethodProfile(handle, ProfileType_EntryBackedge, md){} - - virtual uint32 getEntryExecCount() const = 0; - virtual uint32 getBackedgeExecCount() const = 0; - virtual uint32* getEntryCounter() const = 0; - virtual uint32* getBackedgeCounter() const = 0; -}; - // assert which works even in release mode #define jitrino_assert(compInterface, e) { if (!(e)) { compInterface.hardAssert("Assertion failed", __LINE__, __FILE__); } } diff --git vm/jitrino/src/vm/drl/DrlEMInterface.cpp vm/jitrino/src/vm/drl/DrlEMInterface.cpp new file mode 100644 index 0000000..db10344 --- /dev/null +++ vm/jitrino/src/vm/drl/DrlEMInterface.cpp @@ -0,0 +1,214 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/* COPYRIGHT_NOTICE */ + +/** +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ + +#include "open/em_profile_access.h" +#include "DrlEMInterface.h" +#include "DrlVMInterface.h" +#include "JITInstanceContext.h" + +#include <assert.h> + +namespace Jitrino { + + +MethodProfile* DrlProfilingInterface::getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role) const { + assert(type == ProfileType_EntryBackedge || type == ProfileType_Edge); + Method_Profile_Handle mpHandle = profileAccessInterface->get_method_profile(emHandle, pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); + if (mpHandle==0) { + return NULL; + } + MethodProfile* p = NULL; + if (type == ProfileType_Edge) { + p = new (mm) DrlEdgeMethodProfile(mpHandle, md, profileAccessInterface); + } else { + uint32* eCounter = (uint32*)profileAccessInterface->eb_profiler_get_entry_counter_addr(mpHandle); + uint32* bCounter = (uint32*)profileAccessInterface->eb_profiler_get_backedge_counter_addr(mpHandle); + p = new (mm) DrlEntryBackedgeMethodProfile(mpHandle, md, eCounter, bCounter); + } + return p; +} + +bool DrlProfilingInterface::hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role) const { + if (type!=pcType) { + return false; + } + if (jitRole!=role) { + return false; + } + if (profileAccessInterface != NULL) { + Method_Profile_Handle mpHandle = profileAccessInterface->get_method_profile(emHandle, pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); + return mpHandle!=0; + } + return false; +} + +uint32 DrlProfilingInterface::getProfileMethodCount(MethodDesc& md, JITProfilingRole role) const { + assert(pcType ==ProfileType_Edge || pcType == ProfileType_EntryBackedge); + assert(jitRole == role); + Method_Handle methodHandle = ((DrlVMMethodDesc&)md).getDrlVMMethod(); + Method_Profile_Handle mph = profileAccessInterface->get_method_profile(emHandle, pcHandle, methodHandle); + if (mph == NULL) { + return 0; + } + uint32* counterAddr = NULL; + if (pcType == ProfileType_Edge) { + counterAddr = (uint32*)profileAccessInterface->edge_profiler_get_entry_counter_addr(mph); + } else { + counterAddr = (uint32*)profileAccessInterface->eb_profiler_get_entry_counter_addr(mph); + } + return *counterAddr; +} + +bool DrlProfilingInterface::enableProfiling(PC_Handle pc, JITProfilingRole role) { + assert(!profilingEnabled); + EM_PCTYPE _pcType = profileAccessInterface->get_pc_type(emHandle, pc); + if (_pcType != EM_PCTYPE_EDGE && _pcType!=EM_PCTYPE_ENTRY_BACKEDGE) { + return false; + } + JITInstanceContext* jitMode = JITInstanceContext::getContextForJIT(jitHandle); + if (jitMode->isJet()) { + if (role == JITProfilingRole_GEN) { + profilingEnabled = _pcType == EM_PCTYPE_ENTRY_BACKEDGE; + } else { + profilingEnabled = false; + } + } else { //OPT + profilingEnabled = true; + } + if (profilingEnabled) { + jitRole = role; + pcHandle = pc; + pcType = (_pcType == EM_PCTYPE_EDGE) ? ProfileType_Edge : ProfileType_EntryBackedge; + } + return profilingEnabled; +} + +bool DrlProfilingInterface::isProfilingEnabled(ProfileType pcType, JITProfilingRole role) const { + if( !profilingEnabled || (jitRole != role) ){ + return false; + } + + const EM_PCTYPE emPcType = profileAccessInterface->get_pc_type( emHandle, pcHandle ); + if( (emPcType == EM_PCTYPE_EDGE) && (pcType == ProfileType_Edge ) ){ + return true; + } + if( (emPcType == EM_PCTYPE_ENTRY_BACKEDGE) && (pcType == ProfileType_EntryBackedge) ){ + return true; + } + return false; +} + +EntryBackedgeMethodProfile* DrlProfilingInterface::createEBMethodProfile(MemoryManager& mm, MethodDesc& md) { + assert(isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_GEN)); + Method_Profile_Handle mpHandle = profileAccessInterface->eb_profiler_create_profile(pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); + assert(mpHandle!=0); + uint32* eCounter = (uint32*)profileAccessInterface->eb_profiler_get_entry_counter_addr(mpHandle); + uint32* bCounter = (uint32*)profileAccessInterface->eb_profiler_get_backedge_counter_addr(mpHandle); + + DrlEntryBackedgeMethodProfile* p = new (mm) DrlEntryBackedgeMethodProfile(mpHandle, md, eCounter, bCounter); + return p; +} + + +EdgeMethodProfile* DrlProfilingInterface::createEdgeMethodProfile( MemoryManager& mm, + MethodDesc& md, + uint32 numCounters, + uint32* counterKeys, + uint32 checkSum ) +{ + assert(isProfilingEnabled(ProfileType_Edge, JITProfilingRole_GEN)); + Method_Profile_Handle mpHandle = profileAccessInterface->edge_profiler_create_profile( + pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod(), numCounters, counterKeys, checkSum); + assert( mpHandle != NULL ); + + DrlEdgeMethodProfile* p = new (mm) DrlEdgeMethodProfile(mpHandle, md, profileAccessInterface); + return p; +} + +uint32 DrlProfilingInterface::getMethodEntryThreshold() const { + assert(pcHandle!=NULL); + EM_PCTYPE pcType = profileAccessInterface->get_pc_type(emHandle, pcHandle); + if (pcType == EM_PCTYPE_EDGE) { + return profileAccessInterface->edge_profiler_get_entry_threshold(pcHandle); + } else if ( pcType==EM_PCTYPE_ENTRY_BACKEDGE) { + return profileAccessInterface->eb_profiler_get_entry_threshold(pcHandle); + } else { + assert(0); + } + return 0; +} + +uint32 DrlProfilingInterface::getBackedgeThreshold() const { + assert(pcHandle!=NULL); + EM_PCTYPE pcType = profileAccessInterface->get_pc_type(emHandle, pcHandle); + if (pcType == EM_PCTYPE_EDGE) { + return profileAccessInterface->edge_profiler_get_backedge_threshold(pcHandle); + } else if ( pcType==EM_PCTYPE_ENTRY_BACKEDGE) { + return profileAccessInterface->eb_profiler_get_backedge_threshold(pcHandle); + } + assert(0); + return 0; +} + +bool DrlProfilingInterface::isEBProfilerInSyncMode() const { + assert(pcHandle!=NULL); + return profileAccessInterface->eb_profiler_is_in_sync_mode(pcHandle)!=0; +} + +PC_Callback_Fn* DrlProfilingInterface::getEBProfilerSyncModeCallback() const { + assert(pcHandle!=NULL); + assert(profileAccessInterface->eb_profiler_sync_mode_callback!=NULL); + return (PC_Callback_Fn*)profileAccessInterface->eb_profiler_sync_mode_callback; +} + + + +DrlEdgeMethodProfile::DrlEdgeMethodProfile (Method_Profile_Handle handle, MethodDesc& md, + EM_ProfileAccessInterface* _profileAccessInterface) +: EdgeMethodProfile(handle, md), profileAccessInterface(_profileAccessInterface) +{ +} + + +uint32 DrlEdgeMethodProfile::getNumCounters() const { + return profileAccessInterface->edge_profiler_get_num_counters(getHandle()); +} + +uint32 DrlEdgeMethodProfile::getCheckSum() const { + return profileAccessInterface->edge_profiler_get_checksum(getHandle()); +} + +uint32* DrlEdgeMethodProfile::getEntryCounter() const { + return (uint32*)profileAccessInterface->edge_profiler_get_entry_counter_addr(getHandle()); +} + +uint32* DrlEdgeMethodProfile::getCounter(uint32 key) const { + uint32* counter = (uint32*)profileAccessInterface->edge_profiler_get_counter_addr(getHandle(), key); + assert(counter!=NULL); + return counter; +} + + +} //namespace + + + diff --git vm/jitrino/src/vm/drl/DrlEMInterface.h vm/jitrino/src/vm/drl/DrlEMInterface.h new file mode 100644 index 0000000..10bab10 --- /dev/null +++ vm/jitrino/src/vm/drl/DrlEMInterface.h @@ -0,0 +1,94 @@ +/* +* Copyright 2005 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/* COPYRIGHT_NOTICE */ + +/** +* @author Mikhail Y. Fursov +* @version $Revision$ +*/ + +#ifndef _DRLEMINTERFACE_H_ +#define _DRLEMINTERFACE_H_ + +#include "EMInterface.h" + +namespace Jitrino { + +class DrlProfilingInterface : public ProfilingInterface { +public: + DrlProfilingInterface(EM_Handle _em, JIT_Handle _jit, EM_ProfileAccessInterface* emProfileAccess) + : emHandle(_em), pcHandle(NULL), pcType(ProfileType_Invalid), jitHandle(_jit), profileAccessInterface(emProfileAccess), + jitRole(JITProfilingRole_USE), profilingEnabled(false){} + + virtual MethodProfile* getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const; + virtual bool hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const; + virtual uint32 getProfileMethodCount(MethodDesc& md, JITProfilingRole role = JITProfilingRole_USE) const; + + virtual bool enableProfiling(PC_Handle pc, JITProfilingRole role); + virtual bool isProfilingEnabled(ProfileType pcType, JITProfilingRole jitRole) const ; + + virtual EntryBackedgeMethodProfile* createEBMethodProfile(MemoryManager& mm, MethodDesc& md); + virtual bool isEBProfilerInSyncMode() const; + virtual PC_Callback_Fn* getEBProfilerSyncModeCallback() const; + + virtual EdgeMethodProfile* createEdgeMethodProfile(MemoryManager& mm, MethodDesc& md, uint32 numEdgeCounters, uint32* counterKeys, uint32 checkSum); + + virtual uint32 getMethodEntryThreshold() const; + virtual uint32 getBackedgeThreshold() const; + +private: + EM_Handle emHandle; + //Only one profile per JIT is supported + PC_Handle pcHandle; + ProfileType pcType; + JIT_Handle jitHandle; + EM_ProfileAccessInterface* profileAccessInterface; + JITProfilingRole jitRole; + bool profilingEnabled; +}; + +class DrlEntryBackedgeMethodProfile : public EntryBackedgeMethodProfile { +public: + DrlEntryBackedgeMethodProfile(Method_Profile_Handle mph, MethodDesc& md, uint32* _entryCounter, uint32 *_backedgeCounter) + : EntryBackedgeMethodProfile(mph, md), entryCounter(_entryCounter), backedgeCounter(_backedgeCounter){} + + virtual uint32 getEntryExecCount() const {return *entryCounter;} + virtual uint32 getBackedgeExecCount() const {return *backedgeCounter;} + virtual uint32* getEntryCounter() const {return entryCounter;} + virtual uint32* getBackedgeCounter() const {return backedgeCounter;} + +private: + uint32* entryCounter; + uint32* backedgeCounter; +}; + + +class DrlEdgeMethodProfile : public EdgeMethodProfile { +public: + DrlEdgeMethodProfile (Method_Profile_Handle handle, MethodDesc& md, EM_ProfileAccessInterface* profileAccessInterface); + virtual uint32 getNumCounters() const; + virtual uint32 getCheckSum() const; + virtual uint32* getEntryCounter() const; + virtual uint32* getCounter(uint32 key) const ; + +private: + EM_ProfileAccessInterface* profileAccessInterface; + +}; + + +} +#endif diff --git vm/jitrino/src/vm/drl/DrlJITInterface.cpp vm/jitrino/src/vm/drl/DrlJITInterface.cpp index d39e346..3a56987 100644 --- vm/jitrino/src/vm/drl/DrlJITInterface.cpp +++ vm/jitrino/src/vm/drl/DrlJITInterface.cpp @@ -27,11 +27,12 @@ #endif #include "Jitrino.h" #include "DrlVMInterface.h" +#include "DrlEMInterface.h" #include "MemoryEstimates.h" -#include "PropertyTable.h" #include "Log.h" -#include "Profiler.h" +#include "PMF.h" #include "CompilationContext.h" +#include "JITInstanceContext.h" #include "jit_export.h" #include "jit_export_jpda.h" @@ -43,11 +44,11 @@ #include <stdio.h> #include <stdlib.h> #if !defined(_IPF_) // No .JET on IPF yet - #define USE_FAST_PATH + #define USE_FAST_PATH #endif #ifdef USE_FAST_PATH - #include "../../jet/jet.h" + #include "../../jet/jet.h" #endif namespace Jitrino { @@ -59,16 +60,25 @@ namespace Jitrino { // Optional functions that don't have to be provided. //////////////////////////////////////////////////////// +#ifdef USE_FAST_PATH +static bool isJET(JIT_Handle jit) +{ + JITInstanceContext* jitContext = Jitrino::getJITInstanceContext(jit); + return jitContext->isJet(); +} +#endif + + // Called once at the end of the constructor. extern "C" -JITEXPORT void +JITEXPORT void JIT_init(JIT_Handle jit, const char* name) { - std::string initMessage = std::string("Initializing Jitrino.") + name + + std::string initMessage = std::string("Initializing Jitrino.") + name + " -> "; std::string mode = "OPT"; #ifdef USE_FAST_PATH - if (JITModeData::isJetModeName(name)) mode = "JET"; + if (JITInstanceContext::isNameReservedForJet(name)) mode = "JET"; #endif initMessage = initMessage + mode + " compiler mode"; INFO(initMessage.c_str()); @@ -92,71 +102,68 @@ #endif #endif #ifdef USE_FAST_PATH - Jet::setup(jit); + Jet::setup(jit, name); #endif } // Called once at the end of the destructor. extern "C" -JITEXPORT void +JITEXPORT void JIT_deinit(JIT_Handle jit) { #ifdef USE_FAST_PATH - Jet::cleanup(); + Jet::cleanup(); #endif - profileCtrl.deInit(); - Jitrino::DeInit(); + Jitrino::DeInit(jit); } extern "C" -JITEXPORT void +JITEXPORT void JIT_next_command_line_argument(JIT_Handle jit, const char *name, const char *arg) { - Jitrino::NextCommandLineArgument(jit, name, arg); #ifdef USE_FAST_PATH - Jet::cmd_line_arg(jit, name, arg); + Jet::cmd_line_arg(jit, name, arg); #endif } extern "C" -JITEXPORT void +JITEXPORT void JIT_set_profile_access_interface(JIT_Handle jit, EM_Handle em, - EM_ProfileAccessInterface* pc_interface) + EM_ProfileAccessInterface* pc_interface) { - JITModeData* modeData = Jitrino::getJITModeData(jit); + JITInstanceContext* jitContext = Jitrino::getJITInstanceContext(jit); MemoryManager& mm = Jitrino::getGlobalMM(); - DrlProfilingInterface* pi = new (mm) DrlProfilingInterface(em, jit, - pc_interface); - modeData->setProfilingInterface(pi); + DrlProfilingInterface* pi = new (mm) DrlProfilingInterface(em, jit, pc_interface); + jitContext->setProfilingInterface(pi); } //Optional extern "C" -JITEXPORT bool -JIT_enable_profiling(JIT_Handle jit, PC_Handle pc, EM_JIT_PC_Role role) +JITEXPORT bool +JIT_enable_profiling(JIT_Handle jit, PC_Handle pc, EM_JIT_PC_Role role) { - JITModeData* modeData = Jitrino::getJITModeData(jit); - ProfilingInterface* pi = modeData->getProfilingInterface(); + JITInstanceContext* jitContext = Jitrino::getJITInstanceContext(jit); + ProfilingInterface* pi = jitContext->getProfilingInterface(); return pi->enableProfiling(pc, role == EM_JIT_PROFILE_ROLE_GEN ? JITProfilingRole_GEN: JITProfilingRole_USE); } extern "C" -JITEXPORT void +JITEXPORT void JIT_gc_start(JIT_Handle jit) { } extern "C" -JITEXPORT void +JITEXPORT void JIT_gc_end(JIT_Handle jit) { } extern "C" -JITEXPORT void +JITEXPORT void JIT_gc_object_died(JIT_Handle jit, void *java_ref) { } @@ -186,7 +193,7 @@ JIT_overridden_method_callback(JIT_Handl // Called if JIT registered itself to be notified when the method is // recompiled -// Returns TRUE if any code was modified and FALSE otherwise +// Returns TRUE if any code was modified and FALSE otherwise extern "C" JITEXPORT Boolean JIT_recompiled_method_callback(JIT_Handle jit, @@ -206,7 +213,7 @@ JIT_recompiled_method_callback(JIT_Handl //////////////////////////////////////////////////////// extern "C" -JITEXPORT JIT_Result +JITEXPORT JIT_Result JIT_gen_method_info(JIT_Handle jit, Compile_Handle compilation, Method_Handle method, JIT_Flags flags) { @@ -214,17 +221,9 @@ JIT_gen_method_info(JIT_Handle jit, Comp return JIT_FAILURE; } -#ifdef USE_FAST_PATH -static bool isJET(JIT_Handle jit) -{ - JITModeData* modeData = Jitrino::getJITModeData(jit); - return modeData->isJet(); -} -#endif - extern "C" -JITEXPORT JIT_Result +JITEXPORT JIT_Result JIT_compile_method(JIT_Handle jitHandle, Compile_Handle compilation, Method_Handle method, JIT_Flags flags) { @@ -233,55 +232,90 @@ JIT_compile_method(JIT_Handle jitHandle, } extern "C" -JITEXPORT JIT_Result +JITEXPORT JIT_Result JIT_compile_method_with_params(JIT_Handle jit, Compile_Handle compilation, Method_Handle method_handle, OpenMethodExecutionParams compilation_params) { - JIT_Flags flags; MemoryManager memManager(method_get_byte_code_size(method_handle)* - ESTIMATED_MEMORY_PER_BYTECODE, + ESTIMATED_MEMORY_PER_BYTECODE, "JIT_compile_method.memManager"); JIT_Handle jitHandle = method_get_JIT_id(compilation); - JITModeData* modeData = Jitrino::getJITModeData(jitHandle); - assert(modeData != NULL); - flags.opt_level = 0; - flags.insert_write_barriers = - compilation_params.exe_insert_write_barriers; - + JITInstanceContext* jitContext = Jitrino::getJITInstanceContext(jitHandle); + assert(jitContext!= NULL); + + DrlVMCompilationInterface compilationInterface(compilation, method_handle, jit, + memManager, compilation_params, NULL); + CompilationContext cs(memManager, &compilationInterface, jitContext); + compilationInterface.setCompilationContext(&cs); + + static int method_seqnb = 0; + int current_nb = method_seqnb++; + MethodDesc* md = compilationInterface.getMethodToCompile(); + const char* methodTypeName = md->getParentType()->getName(); + const char* methodName = md->getName(); + const char* methodSig = md->getSignatureString(); + PMF::Pipeline* pipep = jitContext->getPMF().selectPipeline(methodTypeName, methodName, methodSig); + cs.setPipeline((HPipeline*)pipep); + LogStreams::current(jitContext).beginMethod(methodTypeName, methodName, methodSig, method_seqnb); + Str pipename = pipep->getName(); + LogStream& info = LogStream::log(LogStream::INFO, (HPipeline*)pipep); + if (info.isEnabled()) { + info << "<" << current_nb << "\t" + << jitContext->getJITName() << "." << pipename + << "\tstart " + << methodTypeName << "." << methodName << methodSig + << "\tbyte code size=" << method_get_byte_code_size(method_handle) + << std::endl; + } + + JIT_Result result; + #ifdef USE_FAST_PATH - if (isJET(jit)){ - return Jet::compile_with_params(jitHandle, compilation, method_handle, + if (isJET(jit)) + result = Jet::compile_with_params(jitHandle, compilation, method_handle, compilation_params); + else +#endif // USE_FAST_PATH + + result = Jitrino::CompileMethod(&cs) ? JIT_SUCCESS : JIT_FAILURE; + + if (info.isEnabled()) { + info << current_nb << ">\t" + << jitContext->getJITName() << "." << pipename + << "\t end "; + //<< methodTypeName << "." << methodName << methodSig; + + if (result == JIT_SUCCESS) { + unsigned size = method_get_code_block_size_jit(method_handle, jit); + Byte * start = size ? method_get_code_block_addr_jit(method_handle, jit) : 0; + info << "\tnative code size=" << size + << " code range=[" << (void*)start << "," << (void*)(start+size) << "]"; + } + else + info << "\tFAILURE"; + + info << std::endl; } -#endif // USE_FAST_PATH - DrlVMCompilationInterface compilationInterface(compilation, - method_handle, - memManager, modeData, - flags); - CompilationContext cs(memManager, &compilationInterface, modeData); - compilationInterface.setCompilationContext(&cs); - bool success = Jitrino::CompileMethod(&compilationInterface); - return success ? JIT_SUCCESS : JIT_FAILURE; + LogStreams::current(jitContext).endMethod(); + return result; } -extern "C" +extern "C" JITEXPORT OpenMethodExecutionParams JIT_get_exe_capabilities (JIT_Handle jit) { #ifdef USE_FAST_PATH if (isJET(jit)) { return Jet::get_exe_capabilities(); } -#endif // USE_FAST_PATH +#endif // USE_FAST_PATH static const OpenMethodExecutionParams compilation_capabilities = { false, // exe_notify_method_entry false, // exe_notify_method_exit - false, // exe_notify_instance_field_read - false, // exe_notify_instance_field_write - false, // exe_notify_static_field_read - false, // exe_notify_static_field_write + false, // exe_notify_field_access + false, // exe_notify_field_modification false, // exe_notify_exception_throw false, // exe_notify_exception_catch false, // exe_notify_monitor_enter @@ -292,7 +326,7 @@ #endif // USE_FAST_PATH false, // exe_do_code_mapping false, // exe_do_local_var_mapping false, // exe_insert_write_barriers - }; + }; return compilation_capabilities; } @@ -302,7 +336,7 @@ JIT_unwind_stack_frame(JIT_Handle jit, M ::JitFrameContext *context) { #ifdef _DEBUG - if(Log::cat_rt()->isInfo2Enabled()) + if(Log::cat_rt()->isEnabled()) Log::cat_rt()->out() << "UNWIND_STACK_FRAME(" << class_get_name(method_get_class(method)) << "." << method_get_name(method) << ")" << ::std::endl; @@ -310,7 +344,7 @@ #endif #ifdef USE_FAST_PATH if (isJET(jit)) { - Jet::rt_unwind(jit, method, context); + Jet::rt_unwind(jit, method, context); return; } #endif @@ -319,13 +353,13 @@ #endif } extern "C" -JITEXPORT void +JITEXPORT void JIT_get_root_set_from_stack_frame(JIT_Handle jit, Method_Handle method, GC_Enumeration_Handle enum_handle, ::JitFrameContext *context) { #ifdef _DEBUG - if(Log::cat_rt()->isInfo2Enabled()) + if(Log::cat_rt()->isEnabled()) Log::cat_rt()->out() << "GET_ROOT_SET_FROM_STACK_FRAME(" << class_get_name(method_get_class(method)) << "." << method_get_name(method) << ")" << ::std::endl; @@ -333,9 +367,9 @@ #endif #ifdef USE_FAST_PATH if (isJET(jit)) { - Jet::rt_enum(jit, method, enum_handle, context); - return; - } + Jet::rt_enum(jit, method, enum_handle, context); + return; + } #endif DrlVMMethodDesc methodDesc(method, jit); @@ -345,10 +379,10 @@ #endif } extern "C" -JITEXPORT uint32 +JITEXPORT uint32 JIT_get_inline_depth(JIT_Handle jit, InlineInfoPtr ptr, uint32 offset) { - if (Log::cat_rt()->isInfo2Enabled()) { + if (Log::cat_rt()->isEnabled()) { Log::cat_rt()->out() << "GET_INLINE_DEPTH()" << ::std::endl; } return Jitrino::GetInlineDepth(ptr, offset); @@ -359,13 +393,23 @@ JITEXPORT Method_Handle JIT_get_inlined_method(JIT_Handle jit, InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) { - if (Log::cat_rt()->isInfo2Enabled()) { + if (Log::cat_rt()->isEnabled()) { Log::cat_rt()->out() << "GET_INLINED_METHOD()" << ::std::endl; } return Jitrino::GetInlinedMethod(ptr, offset, inline_depth); } extern "C" +JITEXPORT uint16 +JIT_get_inlined_bc(JIT_Handle jit, InlineInfoPtr ptr, uint32 offset, uint32 inline_depth) +{ + if (Log::cat_rt()->isEnabled()) { + Log::cat_rt()->out() << "GET_INLINED_BC()" << ::std::endl; + } + return Jitrino::GetInlinedBc(ptr, offset, inline_depth); +} + +extern "C" JITEXPORT Boolean JIT_can_enumerate(JIT_Handle jit, Method_Handle method, NativeCodePtr eip) { @@ -397,7 +441,7 @@ JIT_fix_handler_context(JIT_Handle jit, ::JitFrameContext *context) { #ifdef _DEBUG - if(Log::cat_rt()->isInfo2Enabled()) + if(Log::cat_rt()->isEnabled()) Log::cat_rt()->out() << "FIX_HANDLER_CONTEXT(" << class_get_name(method_get_class(method)) << "." << method_get_name(method) << ")" << ::std::endl; @@ -405,9 +449,9 @@ #endif #ifdef USE_FAST_PATH if (isJET(jit)) { - Jet::rt_fix_handler_context(jit, method, context); - return; - } + Jet::rt_fix_handler_context(jit, method, context); + return; + } #endif DrlVMMethodDesc methodDesc(method, jit); @@ -422,7 +466,7 @@ JIT_get_address_of_this(JIT_Handle jit, { #ifdef USE_FAST_PATH if (isJET(jit)) { - return Jet::rt_get_address_of_this(jit, method, context); + return Jet::rt_get_address_of_this(jit, method, context); } #endif DrlVMMethodDesc methodDesc(method, jit); @@ -440,7 +484,7 @@ JIT_call_returns_a_reference(JIT_Handle } extern "C" -JITEXPORT int32 +JITEXPORT int32 JIT_get_break_point_offset(JIT_Handle jit, Compile_Handle compilation, Method_Handle meth, JIT_Flags flags, unsigned bc_location) @@ -450,7 +494,7 @@ JIT_get_break_point_offset(JIT_Handle ji } extern "C" -JITEXPORT void * +JITEXPORT void * JIT_get_address_of_var(JIT_Handle jit, ::JitFrameContext *context, Boolean is_first, unsigned var_no) { @@ -471,7 +515,11 @@ JIT_supports_compressed_references(JIT_H { #ifdef USE_FAST_PATH if (isJET(jit)) { +#ifdef _EM64T_ + return true; +#else return false; +#endif } #endif DrlVMDataInterface dataIntf; @@ -481,13 +529,13 @@ #endif return false; } -extern "C" +extern "C" JITEXPORT void JIT_get_root_set_for_thread_dump(JIT_Handle jit, Method_Handle method, GC_Enumeration_Handle enum_handle, ::JitFrameContext *context) { - if(Log::cat_rt()->isInfo2Enabled()) { + if(Log::cat_rt()->isEnabled()) { Log::cat_rt()->out() << "GET_ROOT_SET_FROM_STACK_FRAME(" << class_get_name(method_get_class(method)) << "." << method_get_name(method) << ")" << ::std::endl; @@ -505,7 +553,7 @@ JIT_get_root_set_for_thread_dump(JIT_Han extern "C" JITEXPORT OpenExeJpdaError -get_native_location_for_bc(JIT_Handle jit, Method_Handle method, +get_native_location_for_bc(JIT_Handle jit, Method_Handle method, uint16 bc_pc, NativeCodePtr *native_pc) { #ifdef USE_FAST_PATH @@ -518,7 +566,7 @@ #endif DrlVMMethodDesc methDesc(method, jit); uint64* ncAddr = (uint64*) native_pc; - if (Jitrino::GetNativeLocationForBc(&methDesc, bc_pc, (uint64*)ncAddr)) { + if (Jitrino::GetNativeLocationForBc(&methDesc, bc_pc, ncAddr)) { return EXE_ERROR_NONE; } return EXE_ERROR_UNSUPPORTED; diff --git vm/jitrino/src/vm/drl/DrlVMInterface.cpp vm/jitrino/src/vm/drl/DrlVMInterface.cpp index 71e010c..15c7f85 100644 --- vm/jitrino/src/vm/drl/DrlVMInterface.cpp +++ vm/jitrino/src/vm/drl/DrlVMInterface.cpp @@ -25,8 +25,9 @@ #include <iostream> #include <assert.h> #include "DrlVMInterface.h" +#include "CompilationContext.h" #include "Log.h" -#include "Jitrino.h" +#include "JITInstanceContext.h" #include "jit_intf.h" @@ -79,6 +80,11 @@ flagTLSSuspendRequestOffset(){ return thread_get_suspend_request_offset(); } +uint32 +flagTLSThreadStateOffset() { + return thread_get_thread_state_flag_offset(); +} + ////////////////////////////////////////////////////////////////////////////// ///////////////////////// DrlVMTypeManager ///////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -116,6 +122,11 @@ DrlVMTypeManager::getSystemObjectVMTypeH } void* +DrlVMTypeManager::getSystemClassVMTypeHandle() { + return get_system_class_class(); +} + +void* DrlVMTypeManager::getSystemStringVMTypeHandle() { return get_system_string_class(); } @@ -142,13 +153,13 @@ const char* DrlVMTypeManager::getTypeNam } bool -DrlVMTypeManager::isArrayOfUnboxedElements(void* vmClassHandle) { - return type_info_is_unboxed(class_get_element_type_info((Class_Handle) vmClassHandle))?true:false; +DrlVMTypeManager::isArrayOfPrimitiveElements(void* vmClassHandle) { + return type_info_is_primitive(class_get_element_type_info((Class_Handle) vmClassHandle))?true:false; } bool DrlVMTypeManager::isEnumType(void* vmTypeHandle) { - return false; + return false; } bool @@ -171,6 +182,7 @@ DrlVMTypeManager::getMethodName(MethodDe return methodDesc->getName(); } + bool DrlVMTypeManager::isSystemStringType(void* vmTypeHandle) { // We should also be looking at namespace @@ -192,7 +204,7 @@ DrlVMTypeManager::isSystemObjectType(voi return true; const char* name = getTypeName(vmTypeHandle); if (systemObjectVMTypeHandle == NULL && strcmp(name,"Object") == 0) { - // Built-in System.String type + // Built-in System.Object type systemObjectVMTypeHandle = vmTypeHandle; return true; } @@ -200,6 +212,20 @@ DrlVMTypeManager::isSystemObjectType(voi } bool +DrlVMTypeManager::isSystemClassType(void* vmTypeHandle) { + // We should also be looking at namespace + if (vmTypeHandle == systemClassVMTypeHandle) + return true; + const char* name = getTypeName(vmTypeHandle); + if (systemClassVMTypeHandle == NULL && strcmp(name,"Class") == 0) { + // Built-in System.Class type + systemClassVMTypeHandle = vmTypeHandle; + return true; + } + return false; +} + +bool DrlVMTypeManager::isBeforeFieldInit(void* vmTypeHandle) { return class_is_before_field_init((Class_Handle) vmTypeHandle)?true:false; } @@ -223,7 +249,7 @@ DrlVMTypeManager::isSubClassOf(void* vmT uint32 DrlVMTypeManager::getUnboxedOffset(void* vmTypeHandle) { - assert(false); return 0; + assert(false); return 0; } uint32 @@ -233,7 +259,7 @@ DrlVMTypeManager::getBoxedSize(void * vm uint32 DrlVMTypeManager::getUnboxedSize(void* vmTypeHandle) { - assert(false); return 0; + assert(false); return 0; } uint32 @@ -315,7 +341,7 @@ NamedType* DrlVMMethodDesc::getParentType() { TypeManager& typeManager = compilationInterface->getTypeManager(); Class_Handle parentClassHandle = method_get_class(drlMethod); - if (class_is_primitive(parentClassHandle)) + if (class_is_primitive(parentClassHandle)) return typeManager.getValueType(parentClassHandle); return typeManager.getObjectType(parentClassHandle); } @@ -334,7 +360,7 @@ DrlVMMethodDesc::parseJavaHandlers(Excep void DrlVMMethodDesc::parseCliHandlers(ExceptionCallback& callback) { - assert(false); + assert(false); } @@ -368,7 +394,7 @@ #ifdef _IPF_ return 0; #else Method_Handle mh = getDrlVMMethod(); - return (uint32)mh; + return (POINTER_SIZE_INT)mh; #endif } @@ -412,7 +438,7 @@ NamedType* DrlVMFieldDesc::getParentType() { TypeManager& typeManager = compilationInterface->getTypeManager(); Class_Handle parentClassHandle = field_get_class(drlField); - if (class_is_primitive(parentClassHandle)) + if (class_is_primitive(parentClassHandle)) return typeManager.getValueType(parentClassHandle); return typeManager.getObjectType(parentClassHandle); } @@ -429,7 +455,7 @@ DrlVMFieldDesc::getOffset() { return field_get_offset(drlField); } else { - assert(false); return 0; + assert(false); return 0; } } @@ -471,19 +497,6 @@ DrlVMCompilationInterface::getTypeFromDr if (!pointedToType) return NULL; type = typeManager.getManagedPtrType(pointedToType); - } else if (type_info_is_unmanaged_pointer(typeHandle)) { - Type* pointedToType = NULL; - if (type_info_is_void(typeHandle)) { - // void* - pointedToType = typeManager.getVoidType(); - } else { - // T* - pointedToType = - getTypeFromDrlVMTypeHandle(type_info_get_type_info(typeHandle),false); - } - if (!pointedToType) - return NULL; - type = typeManager.getUnmanagedPtrType(pointedToType); } else if (type_info_is_void(typeHandle)) { // void return type type = typeManager.getVoidType(); @@ -492,7 +505,7 @@ DrlVMCompilationInterface::getTypeFromDr if (!classHandle) return NULL; type = typeManager.getObjectType(classHandle); - } else if (type_info_is_unboxed(typeHandle)) { + } else if (type_info_is_primitive(typeHandle)) { // value type Class_Handle valueTypeHandle = type_info_get_class(typeHandle); if (!valueTypeHandle) @@ -507,9 +520,6 @@ DrlVMCompilationInterface::getTypeFromDr type = typeManager.getArrayType(elemType); } else if (type_info_is_general_array(typeHandle)) { assert(0); - } else if (type_info_is_method_pointer(typeHandle)) { - // method pointer - assert(0); } else { // should not get here assert(0); @@ -522,12 +532,10 @@ VM_RT_SUPPORT DrlVMCompilationInterface: switch (runtimeHelperId) { case Helper_NewObj_UsingVtable: vmHelperId = VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE; break; case Helper_NewVector_UsingVtable: vmHelperId = VM_RT_NEW_VECTOR_USING_VTABLE; break; - case Helper_NewObj: vmHelperId = VM_RT_NEW_RESOLVED; break; - case Helper_NewVector: vmHelperId = VM_RT_NEW_VECTOR; break; case Helper_NewMultiArray: vmHelperId = VM_RT_MULTIANEWARRAY_RESOLVED; break; case Helper_LdInterface: vmHelperId = VM_RT_GET_INTERFACE_VTABLE_VER0; break; - case Helper_LdString: vmHelperId = VM_RT_LDC_STRING; break; - case Helper_ObjMonitorEnter: vmHelperId = VM_RT_MONITOR_ENTER_NO_EXC; break; + case Helper_LdRef: vmHelperId = VM_RT_LDC_STRING; break; + case Helper_ObjMonitorEnter: vmHelperId = VM_RT_MONITOR_ENTER_NON_NULL; break; case Helper_ObjMonitorExit: vmHelperId = VM_RT_MONITOR_EXIT_NON_NULL; break; case Helper_TypeMonitorEnter: vmHelperId = VM_RT_MONITOR_ENTER_STATIC; break; case Helper_TypeMonitorExit: vmHelperId = VM_RT_MONITOR_EXIT_STATIC; break; @@ -566,6 +574,8 @@ VM_RT_SUPPORT DrlVMCompilationInterface: case Helper_ConvStoI64: vmHelperId = VM_RT_F2L; break; case Helper_ConvDtoI32: vmHelperId = VM_RT_D2I; break; case Helper_ConvDtoI64: vmHelperId = VM_RT_D2L; break; + case Helper_MethodEntry: vmHelperId = VM_RT_JVMTI_METHOD_ENTER_CALLBACK; break; + case Helper_MethodExit: vmHelperId = VM_RT_JVMTI_METHOD_EXIT_CALLBACK; break; default: assert(0); } @@ -634,8 +644,8 @@ DrlVMCompilationInterface::getRuntimeHel case Helper_ShlI64: case Helper_ShrI64: case Helper_ShruI64: - case Helper_Throw_Lazy: - case Helper_Throw_LinkingException: + case Helper_Throw_Lazy: + case Helper_Throw_LinkingException: return CallingConvention_Drl; default: return CallingConvention_Stdcall; @@ -644,13 +654,13 @@ DrlVMCompilationInterface::getRuntimeHel bool DrlVMCompilationInterface::compileMethod(MethodDesc *method) { - if (Log::cat_root()->isInfo3Enabled()) { - Log::out() << "Jitrino requested compilation of " << - method->getParentType()->getName() << "::" << - method->getName() << method->getSignatureString() << ::std::endl; - } - JIT_Result res = vm_compile_method(getJitHandle(), ((DrlVMMethodDesc*)method)->getDrlVMMethod()); - return res == JIT_SUCCESS ? true : false; + if (Log::isEnabled()) { + Log::out() << "Jitrino requested compilation of " << + method->getParentType()->getName() << "::" << + method->getName() << method->getSignatureString() << ::std::endl; + } + JIT_Result res = vm_compile_method(getJitHandle(), ((DrlVMMethodDesc*)method)->getDrlVMMethod()); + return res == JIT_SUCCESS ? true : false; } void @@ -715,7 +725,7 @@ DrlVMCompilationInterface::resolveFieldB fh = class_get_instance_field_recursive(ch,index); ::std::cerr << "load field "<< class_get_name((Class_Handle) klass->getVMTypeHandle()) << "."; ::std::cerr << field_get_name(fh) << " as "; - (*fieldType)->print(::std::cerr); ::std::cerr << ::std::endl; + (*fieldType)->print(::std::cerr); ::std::cerr << ::std::endl; return getFieldDesc(fh); } @@ -788,7 +798,7 @@ DrlVMCompilationInterface::resolveNamedT Class_Handle ch = resolve_class(compileHandle,enclosingDrlVMClass,typeToken); if (!ch) return NULL; - if (class_is_primitive(ch)) + if (class_is_primitive(ch)) return typeManager.getValueType(ch); return typeManager.getObjectType(ch); } @@ -849,7 +859,7 @@ DrlVMCompilationInterface::loadStringObj // void* DrlVMCompilationInterface::loadToken(MethodDesc* enclosingMethodDesc,uint32 token) { - assert(false); return 0; + assert(false); return 0; } Type* @@ -859,6 +869,7 @@ DrlVMCompilationInterface::getConstantTy Java_Type drlType = (Java_Type)class_get_const_type(enclosingDrlVMClass,constantToken); switch (drlType) { case JAVA_TYPE_STRING: return typeManager.getSystemStringType(); + case JAVA_TYPE_CLASS: return typeManager.getSystemClassType(); case JAVA_TYPE_DOUBLE: return typeManager.getDoubleType(); case JAVA_TYPE_FLOAT: return typeManager.getSingleType(); case JAVA_TYPE_INT: return typeManager.getInt32Type(); @@ -954,6 +965,19 @@ bool DrlVMCompilationInterface::mayInlin return mayInline == TRUE; } +void DrlVMCompilationInterface::sendCompiledMethodLoadEvent(MethodDesc * methodDesc, + uint32 codeSize, void* codeAddr, uint32 mapLength, + AddrLocation* addrLocationMap, void* compileInfo) { + // VM-JIT interface function should be called here instead of logging + if (Log::isEnabled()) { + Log::out() << " ** Inlined method: " + << methodDesc->getName() << std::endl; + Log::out() << " ** Number of locations:" << mapLength + << std::endl; + } + +} + bool DrlVMDataInterface::areReferencesCompressed() { return (vm_references_are_compressed() != 0); } @@ -972,101 +996,28 @@ void DrlVMBinaryRewritingInterface::rewr ObjectType * DrlVMCompilationInterface::resolveSystemClass( const char * klassName ) { - Class_Handle cls = class_load_class_by_name_using_system_class_loader(klassName); - if( NULL == cls ) { - return NULL; - } - return getTypeManager().getObjectType(cls); + Class_Handle cls = class_load_class_by_name_using_system_class_loader(klassName); + if( NULL == cls ) { + return NULL; + } + return getTypeManager().getObjectType(cls); }; MethodPtrType * DrlVMCompilationInterface::resolveMethod( ObjectType* klass, const char * methodName, const char * methodSig) { - Class_Handle cls = (Class_Handle)klass->getVMTypeHandle(); - assert( NULL != cls ); - Method_Handle mh = class_lookup_method_recursively( cls, methodName, methodSig); - if( NULL == mh ) { - return NULL; - } - return getTypeManager().getMethodPtrType(getMethodDesc(mh)); + Class_Handle cls = (Class_Handle)klass->getVMTypeHandle(); + assert( NULL != cls ); + Method_Handle mh = class_lookup_method_recursively( cls, methodName, methodSig); + if( NULL == mh ) { + return NULL; + } + return getTypeManager().getMethodPtrType(getMethodDesc(mh)); }; JIT_Handle DrlVMCompilationInterface::getJitHandle() const { - return modeData->getJitHandle(); -} - - -MethodProfile* DrlProfilingInterface::getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role) const { - assert(type == ProfileType_EntryBackedge); - Method_Profile_Handle mpHandle = profileAccessInterface->get_method_profile(emHandle, pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); - if (mpHandle==0) { - return NULL; - } - uint32* eCounter = (uint32*)profileAccessInterface->eb_profiler_get_entry_counter_addr(mpHandle); - uint32* bCounter = (uint32*)profileAccessInterface->eb_profiler_get_backedge_counter_addr(mpHandle); - - DrlEntryBackedgeMethodProfile* p = new (mm) DrlEntryBackedgeMethodProfile(mpHandle, md, eCounter, bCounter); - return p; -} - -bool DrlProfilingInterface::hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role) const { - if (profileAccessInterface != NULL) { - Method_Profile_Handle mpHandle = profileAccessInterface->get_method_profile(emHandle, pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); - return mpHandle!=0; - } - return false; -} - -bool DrlProfilingInterface::enableProfiling(PC_Handle pc, JITProfilingRole role) { - assert(!profilingEnabled); //for M1 only - assert(profileAccessInterface->get_pc_type(emHandle, pc) == EM_PCTYPE_ENTRY_BACKEDGE); - JITModeData* jitMode = Jitrino::getJITModeData(jitHandle); - if (role == JITProfilingRole_GEN) { - profilingEnabled = jitMode->isJet(); - } else { - profilingEnabled = !jitMode->isJet(); - } - if (profilingEnabled) { - jitRole = role; - pcHandle = pc; - } - return profilingEnabled; -} - -bool DrlProfilingInterface::isProfilingEnabled(ProfileType pcType, JITProfilingRole role) const { - return profilingEnabled && jitRole == role; -} - -EntryBackedgeMethodProfile* DrlProfilingInterface::createEBMethodProfile(MemoryManager& mm, MethodDesc& md) { - assert(isProfilingEnabled(ProfileType_EntryBackedge, JITProfilingRole_GEN)); - Method_Profile_Handle mpHandle = profileAccessInterface->eb_profiler_create_profile(pcHandle, ((DrlVMMethodDesc&)md).getDrlVMMethod()); - assert(mpHandle!=0); - uint32* eCounter = (uint32*)profileAccessInterface->eb_profiler_get_entry_counter_addr(mpHandle); - uint32* bCounter = (uint32*)profileAccessInterface->eb_profiler_get_backedge_counter_addr(mpHandle); - - DrlEntryBackedgeMethodProfile* p = new (mm) DrlEntryBackedgeMethodProfile(mpHandle, md, eCounter, bCounter); - return p; + return getCompilationContext()->getCurrentJITContext()->getJitHandle(); } -uint32 DrlProfilingInterface::getEBProfilerMethodEntryThreshold() const { - assert(pcHandle!=NULL); - return profileAccessInterface->eb_profiler_get_entry_threshold(pcHandle); -} - -uint32 DrlProfilingInterface::getEBProfilerBackedgeThreshold() const { - assert(pcHandle!=NULL); - return profileAccessInterface->eb_profiler_get_backedge_threshold(pcHandle); -} - -bool DrlProfilingInterface::isEBProfilerInSyncMode() const { - assert(pcHandle!=NULL); - return profileAccessInterface->eb_profiler_is_in_sync_mode(pcHandle)!=0; -} - -PC_Callback_Fn* DrlProfilingInterface::getEBProfilerSyncModeCallback() const { - assert(pcHandle!=NULL); - assert(profileAccessInterface->eb_profiler_sync_mode_callback!=NULL); - return (PC_Callback_Fn*)profileAccessInterface->eb_profiler_sync_mode_callback; -} } //namespace Jitrino diff --git vm/jitrino/src/vm/drl/DrlVMInterface.h vm/jitrino/src/vm/drl/DrlVMInterface.h index cf3ab0f..37341c3 100644 --- vm/jitrino/src/vm/drl/DrlVMInterface.h +++ vm/jitrino/src/vm/drl/DrlVMInterface.h @@ -22,17 +22,17 @@ #ifndef _DRLVMINTERFACEIMPL_H_ #define _DRLVMINTERFACEIMPL_H_ -#include <stdio.h> -#include <stdlib.h> #include "Type.h" #include "VMInterface.h" -#include "open/em_profile_access.h" #include "jit_export.h" #include "jit_import.h" #include "jit_runtime_support.h" #include "jit_intf.h" #include "mkernel.h" +#include <stdio.h> +#include <stdlib.h> + namespace Jitrino { /** @@ -46,6 +46,7 @@ extern Mutex g_compileLock; class DrlVMCompilationInterface; uint32 flagTLSSuspendRequestOffset(); +uint32 flagTLSThreadStateOffset(); class DrlVMTypeManager : public TypeManager { public: @@ -57,6 +58,7 @@ public: // void* getBuiltinValueTypeVMTypeHandle(Type::Tag); void* getSystemObjectVMTypeHandle(); + void* getSystemClassVMTypeHandle(); void* getSystemStringVMTypeHandle(); void* getArrayVMTypeHandle(void* elemVMTypeHandle,bool isUnboxed); const char* getTypeName(void* vmTypeHandle); @@ -69,7 +71,7 @@ public: bool isArrayType(void* vmTypeHandle) { return class_is_array((Class_Handle)vmTypeHandle)?true:false; } - bool isArrayOfUnboxedElements(void* vmTypeHandle); + bool isArrayOfPrimitiveElements(void* vmTypeHandle); bool isEnumType(void* vmTypeHandle); bool isValueType(void* vmTypeHandle); bool isLikelyExceptionType(void* vmTypeHandle); @@ -85,10 +87,14 @@ public: } bool isSystemStringType(void* vmTypeHandle); bool isSystemObjectType(void* vmTypeHandle); + bool isSystemClassType(void* vmTypeHandle); bool isBeforeFieldInit(void* vmTypeHandle); bool needsInitialization(void* vmTypeHandle) { return class_needs_initialization((Class_Handle)vmTypeHandle)?true:false; } + bool isFinalizable(void* vmTypeHandle) { + return class_is_finalizable((Class_Handle)vmTypeHandle)?true:false; + } bool isInitialized(void* vmTypeHandle) { return class_is_initialized((Class_Handle)vmTypeHandle)?true:false; } @@ -112,14 +118,14 @@ public: } uint32 getVTableOffset() - { + { return object_get_vtable_offset(); - } + } - void* getTypeHandleFromAllocationHandle(void* vmAllocationHandle) - { - return allocation_handle_get_class((Allocation_Handle)vmAllocationHandle); - } + void* getTypeHandleFromAllocationHandle(void* vmAllocationHandle) + { + return allocation_handle_get_class((Allocation_Handle)vmAllocationHandle); + } bool isSubClassOf(void* vmTypeHandle1,void* vmTypeHandle2); @@ -132,28 +138,31 @@ public: FieldDesc* getUnboxedFieldDesc(void* vmTypeHandle,uint32 index); uint32 getArrayLengthOffset(); Type* getUnderlyingType(void* enumVMTypeHandle); + Type* getTypeFromPrimitiveDrlVMDataType(VM_Data_Type drlDataType) { - switch (drlDataType) { - case VM_DATA_TYPE_INT8: return getInt8Type(); - case VM_DATA_TYPE_UINT8: return getUInt8Type(); - case VM_DATA_TYPE_INT16: return getInt16Type(); - case VM_DATA_TYPE_UINT16: return getUInt16Type(); - case VM_DATA_TYPE_INT32: return getInt32Type(); - case VM_DATA_TYPE_UINT32: return getUInt32Type(); - case VM_DATA_TYPE_INT64: return getInt64Type(); - case VM_DATA_TYPE_UINT64: return getUInt64Type(); - case VM_DATA_TYPE_INTPTR: return getIntPtrType(); - case VM_DATA_TYPE_UINTPTR: return getUIntPtrType(); - case VM_DATA_TYPE_F8: return getDoubleType(); - case VM_DATA_TYPE_F4: return getSingleType(); - case VM_DATA_TYPE_BOOLEAN: return getBooleanType(); - case VM_DATA_TYPE_CHAR: return getCharType(); - default: assert(0); + switch (drlDataType) { + case VM_DATA_TYPE_INT8: return getInt8Type(); + case VM_DATA_TYPE_UINT8: return getUInt8Type(); + case VM_DATA_TYPE_INT16: return getInt16Type(); + case VM_DATA_TYPE_UINT16: return getUInt16Type(); + case VM_DATA_TYPE_INT32: return getInt32Type(); + case VM_DATA_TYPE_UINT32: return getUInt32Type(); + case VM_DATA_TYPE_INT64: return getInt64Type(); + case VM_DATA_TYPE_UINT64: return getUInt64Type(); + case VM_DATA_TYPE_INTPTR: return getIntPtrType(); + case VM_DATA_TYPE_UINTPTR: return getUIntPtrType(); + case VM_DATA_TYPE_F8: return getDoubleType(); + case VM_DATA_TYPE_F4: return getSingleType(); + case VM_DATA_TYPE_BOOLEAN: return getBooleanType(); + case VM_DATA_TYPE_CHAR: return getCharType(); + default: assert(0); } return NULL; } + private: void* systemObjectVMTypeHandle; + void* systemClassVMTypeHandle; void* systemStringVMTypeHandle; }; @@ -185,7 +194,7 @@ public: uint32 getId() {return id;} const char* getName() {return field_get_name(drlField);} const char* getSignatureString() { return field_get_descriptor(drlField); } - void printFullName(::std::ostream &os) { os<<getParentType()->getName()<<"::"<<field_get_name(drlField); } + void printFullName(::std::ostream &os) { os<<getParentType()->getName()<<"::"<<field_get_name(drlField); } NamedType* getParentType(); bool isPrivate() {return field_is_private(drlField)?true:false;} bool isStatic() {return field_is_static(drlField)?true:false;} @@ -237,7 +246,7 @@ public: uint32 getId() {return id;} const char* getName() {return method_get_name(drlMethod);} const char* getSignatureString() {return method_get_descriptor(drlMethod); } - void printFullName(::std::ostream& os) { + void printFullName(::std::ostream& os) { os<<getParentType()->getName()<<"::"<<getName()<<method_get_descriptor(drlMethod);} NamedType* getParentType(); bool isPrivate() {return method_is_private(drlMethod)?true:false;} @@ -361,22 +370,25 @@ class DrlVMCompilationInterface : public public: DrlVMCompilationInterface(Compile_Handle c, Method_Handle m, + JIT_Handle jit, MemoryManager& mm, - JITModeData* _modeData, - JIT_Flags flags) - : memManager(mm), fieldDescs(mm,32), methodDescs(mm,32), - dataInterface(), typeManager(mm) + OpenMethodExecutionParams& comp_params, + CompilationContext* cc) + : CompilationInterface(cc), memManager(mm), fieldDescs(mm,32), methodDescs(mm,32), + dataInterface(), typeManager(mm), compilation_params(comp_params) { - modeData = _modeData; - jitFlags = flags; - jitFlags.insert_write_barriers = false; - compilation_params.exe_do_code_mapping = false; compileHandle = c; nextMemberId = 0; typeManager.init(*this); - methodToCompile = getMethodDesc(m); + methodToCompile = NULL; + methodToCompile = getMethodDesc(m, jit); flushToZeroAllowed = !methodToCompile->isJavaByteCodes(); } + + void setCompilationContext(CompilationContext* cc) { + compilationContext = cc; + } + // returns the method to compile MethodDesc* getMethodToCompile() {return methodToCompile;} @@ -446,9 +458,9 @@ public: Type* getFieldType(MethodDesc* enclosingMethodDesc, uint32 entryCPIndex); const char* methodSignatureString(MethodDesc* enclosingMethodDesc, uint32 methodToken); - // resolve-by-name methods - virtual ObjectType * resolveSystemClass( const char * klassName ); - virtual MethodPtrType * resolveMethod( ObjectType * klass, const char * methodName, const char * methodSig); + // resolve-by-name methods + virtual ObjectType * resolveSystemClass( const char * klassName ); + virtual MethodPtrType * resolveMethod( ObjectType * klass, const char * methodName, const char * methodSig); void* loadStringObject(MethodDesc* enclosingMethod, uint32 stringToken); @@ -511,28 +523,40 @@ public: void setNotifyWhenMethodIsOverridden(MethodDesc * methodDesc, void * callbackData); void setNotifyWhenMethodIsRecompiled(MethodDesc * methodDesc, void * callbackData); - // - // accessors for dynamic profiling flags - // - bool isDynamicProfiling() { return jitFlags.dynamic_profile; } - uint32 getOptimizationLevel() { return ((uint32) jitFlags.opt_level); } - - - // write barriers stuff bool insertWriteBarriers() { - return jitFlags.insert_write_barriers; + return compilation_params.exe_insert_write_barriers; } bool isBCMapInfoRequired() { - return compilation_params.exe_do_code_mapping; + bool res = compilation_params.exe_do_code_mapping; + // exe_do_code_mapping should be used for different ti related byte code + // mapping calculations + // full byte code mapping could be enabled by IRBuilder flag now + // this method used to access to byte code low level maps and + // enables byte codes for stack traces only +// res = true; + return res; } void setBCMapInfoRequired(bool is_supported) { compilation_params.exe_do_code_mapping = is_supported; } + bool isCompileLoadEventRequired() { + // additional compilation param is needed to handle this event + return false; + } + + virtual void sendCompiledMethodLoadEvent(MethodDesc * methodDesc, + uint32 codeSize, void* codeAddr, uint32 mapLength, + AddrLocation* addrLocationMap, void* compileInfo); + + virtual OpenMethodExecutionParams& getCompilationParams() { + return compilation_params; + } + // should flush to zero be allowed for floating-point operations ? bool isFlushToZeroAllowed() { return flushToZeroAllowed; @@ -557,11 +581,11 @@ public: } VmCallingConvention getRuntimeHelperCallingConvention(RuntimeHelperId id); - bool compileMethod(MethodDesc *method); + bool compileMethod(MethodDesc *method); - void* getRuntimeMethodHandle(MethodDesc *method) { - return ((DrlVMMethodDesc*)method)->getDrlVMMethod(); - } + void* getRuntimeMethodHandle(MethodDesc *method) { + return ((DrlVMMethodDesc*)method)->getDrlVMMethod(); + } // // for internal use @@ -580,34 +604,35 @@ public: return fieldDesc; } DrlVMMethodDesc* getMethodDesc(Method_Handle method) { + return getMethodDesc(method, getJitHandle()); + } + + DrlVMMethodDesc* getMethodDesc(Method_Handle method, JIT_Handle jit) { assert(method); DrlVMMethodDesc* methodDesc = methodDescs.lookup(method); if (methodDesc == NULL) { methodDesc = new (memManager) - DrlVMMethodDesc(method,this,nextMemberId++,getJitHandle()); + DrlVMMethodDesc(method,this,nextMemberId++, jit); methodDescs.insert(method,methodDesc); } return methodDesc; } - JITModeData* getModeData() const {return modeData;} - JIT_Handle getJitHandle() const; private: Type* getTypeFromDrlVMTypeHandle(Type_Info_Handle); VM_RT_SUPPORT translateHelperId(RuntimeHelperId runtimeHelperId); + JIT_Handle getJitHandle() const; MemoryManager& memManager; - JITModeData* modeData; PtrHashTable<DrlVMFieldDesc> fieldDescs; PtrHashTable<DrlVMMethodDesc> methodDescs; DrlVMDataInterface dataInterface; DrlVMTypeManager typeManager; DrlVMMethodDesc* methodToCompile; Compile_Handle compileHandle; - JIT_Flags jitFlags; bool flushToZeroAllowed; uint32 nextMemberId; - OpenMethodExecutionParams compilation_params; + OpenMethodExecutionParams& compilation_params; }; class DrlVMGCInterface : public GCInterface { @@ -670,52 +695,6 @@ public: virtual void rewriteCodeBlock(Byte* codeBlock, Byte* newCode, size_t size); }; - -class DrlProfilingInterface : public ProfilingInterface { -public: - DrlProfilingInterface(EM_Handle _em, JIT_Handle _jit, EM_ProfileAccessInterface* emProfileAccess) - : emHandle(_em), pcHandle(NULL), jitHandle(_jit), profileAccessInterface(emProfileAccess), - jitRole(JITProfilingRole_USE), profilingEnabled(false){} - - virtual MethodProfile* getMethodProfile(MemoryManager& mm, ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const; - virtual bool hasMethodProfile(ProfileType type, MethodDesc& md, JITProfilingRole role=JITProfilingRole_USE) const; - - virtual bool enableProfiling(PC_Handle pc, JITProfilingRole role); - virtual bool isProfilingEnabled(ProfileType pcType, JITProfilingRole jitRole) const ; - - virtual EntryBackedgeMethodProfile* createEBMethodProfile(MemoryManager& mm, MethodDesc& md); - virtual uint32 getEBProfilerMethodEntryThreshold() const; - virtual uint32 getEBProfilerBackedgeThreshold() const; - virtual bool isEBProfilerInSyncMode() const; - virtual PC_Callback_Fn* getEBProfilerSyncModeCallback() const; - -private: - EM_Handle emHandle; - PC_Handle pcHandle; - JIT_Handle jitHandle; - EM_ProfileAccessInterface* profileAccessInterface; - //M1 specific -> only one profile supported: - JITProfilingRole jitRole; - bool profilingEnabled; -}; - -class DrlEntryBackedgeMethodProfile : public EntryBackedgeMethodProfile { -public: - DrlEntryBackedgeMethodProfile(Method_Profile_Handle mph, MethodDesc& md, uint32* _entryCounter, uint32 *_backedgeCounter) - : EntryBackedgeMethodProfile(mph, md), entryCounter(_entryCounter), backedgeCounter(_backedgeCounter){} - - virtual uint32 getEntryExecCount() const {return *entryCounter;} - virtual uint32 getBackedgeExecCount() const {return *backedgeCounter;} - virtual uint32* getEntryCounter() const {return entryCounter;} - virtual uint32* getBackedgeCounter() const {return backedgeCounter;} - -private: - uint32* entryCounter; - uint32* backedgeCounter; -}; - - - } //namespace Jitrino #endif // _DRLVMINTERFACEIMPL_H_ diff --git vm/port/include/apr_thread_ext.h vm/port/include/apr_thread_ext.h index 2233972..422d385 100644 --- vm/port/include/apr_thread_ext.h +++ vm/port/include/apr_thread_ext.h @@ -23,5 +23,6 @@ APR_DECLARE(apr_status_t) apr_thread_tim APR_DECLARE(apr_status_t) apr_thread_cancel(apr_thread_t *thread); +APR_DECLARE(apr_status_t) apr_get_thread_time(apr_thread_t *thread, unsigned long long* nanos_ptr); #endif /* APR_EXT_H */ diff --git vm/port/include/lil_code_generator.h vm/port/include/lil_code_generator.h index 8df6dcd..7665528 100644 --- vm/port/include/lil_code_generator.h +++ vm/port/include/lil_code_generator.h @@ -43,7 +43,7 @@ public: // The stub_name is for vtune support // Dump an ascii version of the compiled stub to stdout if dump_stub // If cs_stats is nonnull add the number of bytes of the compiled code to *cs_stats - NativeCodePtr compile(LilCodeStub* cs, const char* stub_name, bool dump_stub); + NativeCodePtr compile(LilCodeStub* cs); protected: LilCodeGenerator(); @@ -60,7 +60,7 @@ protected: // Each subclass of LilCodeGenerator should provide a platform-dependent // implementation of compile_main(). The memory area that holds the // compiled code should be allocated by calling allocate_memory(). - virtual NativeCodePtr compile_main(LilCodeStub* cs, size_t* stub_size, const char *stub_name, bool dump_stub) = 0; + virtual NativeCodePtr compile_main(LilCodeStub* cs, size_t* stub_size) = 0; }; #endif // _LIL_CODE_GENERATOR_H_ diff --git vm/port/include/m2n.h vm/port/include/m2n.h index b1ce66b..120e278 100644 --- vm/port/include/m2n.h +++ vm/port/include/m2n.h @@ -65,6 +65,11 @@ M2nFrame* m2n_get_last_frame(); VMEXPORT // temporary solution for interpreter unplug void m2n_set_last_frame(M2nFrame *); +// Set the most recent M2nFrame of given thread +// The caller must ensure the frame is on the thread's activation stack +VMEXPORT +void m2n_set_last_frame(VM_thread *, M2nFrame *); + // Get the most recent M2nFrame of the given thread VMEXPORT // temporary solution for interpreter unplug M2nFrame* m2n_get_last_frame(VM_thread *); @@ -99,15 +104,32 @@ frame_type m2n_get_frame_type(M2nFrame * // Sets type of noted m2n frame void m2n_set_frame_type(M2nFrame *, frame_type); +// Returns size of m2n frame +size_t m2n_get_size(); + // Push a special M2nFrame for managed code suspended by the OS in say // a signal handler or exception filter. // The frame can be popped by setting the last frame to a prior frame -// and then calling free on the frame. +void m2n_push_suspended_frame(M2nFrame* m2nf, Registers* regs); + +// Push a special M2nFrame for managed code suspended by the OS in say +// a signal handler or exception filter. +// The frame can be popped by setting the last frame to a prior frame +void m2n_push_suspended_frame(VM_thread* thread, M2nFrame* m2nf, Registers* regs); + +// Push a special M2nFrame for managed code suspended by the OS in say +// a signal handler or exception filter. The frame is allocated in the heap. +// It can be popped by setting the last frame to a prior frame +// and then calling free on the frame pointer. M2nFrame* m2n_push_suspended_frame(Registers *); +// Push a special M2nFrame for managed code suspended by the OS in +// signal handler or exception filter. The frame is allocated in the heap. +// The frame can be popped by setting the last frame to a prior frame +// and then calling free on the frame. +M2nFrame* m2n_push_suspended_frame(VM_thread *, Registers *); + // answers true if passed in m2n frame represents suspended frame bool m2n_is_suspended_frame(M2nFrame *); -// returns the the beginning address of specified frame -void * m2n_get_frame_base(M2nFrame *); #endif //!_M2N_H_ diff --git vm/port/include/port_env.h vm/port/include/port_env.h new file mode 100644 index 0000000..b55dde9 --- /dev/null +++ vm/port/include/port_env.h @@ -0,0 +1,38 @@ +/* +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ +#ifndef _PORT_ENV_H_ +#define _PORT_ENV_H_ + +#include "port_general.h" +#include <apr_pools.h> + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Returns all environment variable mappings as an array of KEY=VALUE strings. + */ + APR_DECLARE(char **) port_env_all(apr_pool_t* pool); + +#ifdef __cplusplus +} +#endif +#endif /*_PORT_ENV_H_*/ diff --git vm/port/include/port_timer.h vm/port/include/port_timer.h new file mode 100644 index 0000000..cbad080 --- /dev/null +++ vm/port/include/port_timer.h @@ -0,0 +1,44 @@ +/* +* Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ +#ifndef _PORT_TIMER_H_ +#define _PORT_TIMER_H_ + +#include "port_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * High resolution timer, in nanoseconds. + */ + typedef apr_int64_t apr_nanotimer_t; + + /** + * Returns the value of the system timer with the best possible accuracy. + * This value is not tied to the absolute time, but intended for precise + * measuring of elapsed time intervals. + */ + APR_DECLARE(apr_nanotimer_t) port_nanotimer(); + +#ifdef __cplusplus +} +#endif +#endif /*_PORT_TIMER_H_*/ diff --git vm/port/include/stack_iterator.h vm/port/include/stack_iterator.h old mode 100644 new mode 100755 index 5ded3ab..8fcc070 --- vm/port/include/stack_iterator.h +++ vm/port/include/stack_iterator.h @@ -18,6 +18,29 @@ * @version $Revision: 1.1.2.1.4.3 $ */ +/** + *@file + * Mechanism for iterating over stack frames + * of Java and native code. + * + * This stack iterator handle is a black box. + * + * The iteractor supports iterating over: + * <ul> + * <li>Managed code frames corresponding to Java + * code + * <li>Managed-to-native frames (M2N) for transferring + * data and control between managed and native frames + * + * Native frames iteration is not currently supported. To iterate over + * native frames, use OS-provided tools. + * </ul> + * This iterator uses the order from the most recently pushed frame + * to the first frame pushed. + * With the stack iterator, you can also resume a frame in the current thread and + * transfer execution and control to this frame. + */ + #ifndef _STACK_ITERATOR_H_ #define _STACK_ITERATOR_H_ @@ -25,97 +48,242 @@ #include "jit_export.h" #include "open/types.h" #include "vm_core_types.h" -// This module is for a "stack iterator" abstraction. -// A stack iterator allows other code to iterator over the managed and m2n -// frames of a thread in order from most recently pushed to first pushed. -// It also allows for resuming a frame in the current thread. - struct StackIterator; -// Create a new stack iterator for the current thread assuming the thread -// is currently in native code. +/** + * Creates a new stack iterator for the given thread. + * + * @note The function assumes that the thread is currently in native code. + */ StackIterator* si_create_from_native(); -// Create a new stack iterator for the given thread assuming it is currently -// in native code. Note that the thread can run concurrently with the stack -// iterator, but it should not pop (return past) the most recent M2nFrame at -// the time the iterator is called. Also note that creation is not atomic with -// respect to pushing/popping of m2n frames; the client should ensure that such -// operations are serialized. -StackIterator* si_create_from_native(VM_thread*); - -// Create a new stack iterator for a thread assuming it is currently suspended -// from managed code. See also note in previous function. The registers -// arguments contains the values of the registers at the point of suspension, -// is_ip_past is described in the JIT frame context structure, and the M2nFrame -// should be the one immediately prior to the suspended frame. -StackIterator* si_create_from_registers(Registers*, bool is_ip_past, M2nFrame*); - -// The implementation of stack iterators and m2n frames may not track all -// preserved registers needed for resuming a frame, but may instead track -// enough for root-set enumeration and stack walking. The following function -// and a corresponding addition stub generator for m2n frames allow all such -// registers to be tracked for exception propagation. Ensure that all -// preserved registers are transferred from the m2n frame to the iterator. -// This function should only be called when the iterator is at an M2nFrame -// that has all preserved registers saved. -void si_transfer_all_preserved_registers(StackIterator*); - -// Return if the iterator is past all the frames. -bool si_is_past_end(StackIterator*); - -// Goto the frame previous to the current one. -void si_goto_previous(StackIterator*); - -// Make a copy of a stack iterator -StackIterator* si_dup(StackIterator*); - -// Free the iterator. -void si_free(StackIterator*); - -// Return the ip for the current frame. -NativeCodePtr si_get_ip(StackIterator*); - -// Set the ip for the current frame -void si_set_ip(StackIterator*, NativeCodePtr, +/** + * Creates a new stack iterator for the given thread. + * + * The thread can run concurrently with the stack iterator, + * but it must not pop (return past) the most recent M2N frame when the iterator is called. + * + * Creation is not atomic with respect to pushing/popping of M2N frames. + * The client code must ensure that such operations are serialized. + * + * @param[in] thread - the pointer to the thread, the stack of which must be enumerated + * + * @note The function assumes that the given thread is currently in native code. + */ +StackIterator* si_create_from_native(VM_thread* thread); + +/** + * Creates a new stack iterator for the suspended thread. + * + * The thread can run concurrently with the stack iterator, + * but it must not pop (return past) the most recent M2N frame when the iterator is called. + * + * Creation is not atomic with respect to pushing/popping of M2N frames. + * The client code must ensure that such operations are serialized. + * + * @param[in] regs - values of the registers at the point of suspension + * @param[in] is_ip_past - indicate is ip past or not + * @param[in] m2nf - the pointer to the M2N frame that must be the one immediately + * prior to the suspended frame + * + * @note The function assumes that iterated thread is currently suspended from managed code. + */ +StackIterator* si_create_from_registers(Registers* regs, bool is_ip_past, M2nFrame* m2nf); + +/** + * Makes a copy of the given stack iterator. + * + * @param[in] si - the pointer to the stack iterator to be copied + */ +StackIterator* si_dup(StackIterator* si); + +/** + * Frees the stack iterator. + * + * @param[in] si - the pointer to the stack iterator to be freed + */ +void si_free(StackIterator* si); + +/** + * Ensures that all preserved registers are transferred from the M2N frame + * to the iterator. + * + * Depending on the platform, the implementation of stack iterators and M2N frames + * may not track all preserved registers required for resuming a frame, but may instead track + * enough for root set enumeration and stack walking. + * + * This function and the corresponding additional stub generator for M2N frames + * allow all registers to be tracked for exception propagation. + * + * @param[in] si - the poiter to the stack iterator that will contain all preserved + * registers + * + * @note Only call the function when the iterator is at an M2N frame + * that has all preserved registers saved. + */ +void si_transfer_all_preserved_registers(StackIterator* si); + +/** + * Checks whether the stack iterator has passed all the frames. + * + * @param[in] si - the poiter to a StackIterator which should be tested is past all + * the frames or not. + * @return <code>TRUE</code> if the transferred stack iterator has passed all the frames; + * otherwise, <code>FALSE</code>. + */ +bool si_is_past_end(StackIterator* si ); + +/** + * Goes to the frame previous to the current one. + * + * @param[in] si - the pointer to the stack iterator that will be iterated to the previous + * frame + */ +void si_goto_previous(StackIterator* si); + +/** + * Gets the instruction pointer for the current frame. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The instruction pointer for the current frame. + */ +NativeCodePtr si_get_ip(StackIterator* si); + +/** + * Sets the instruction pointer for the current frame. + * + * @param[in] si - the pointer to the stack iterator indicating + * the current frame + * @param[in] ip - the instruction pointer for the current frame + * @param[in] also_update_stack_itself - the flag indicating whether the function must update + * data on the stack or only in the iterator + * + * @return If <i>also_update_stack_itself</i> is <code>TRUE</code>, + * updates the instruction pointer in the stack; otherwise, the new + * value stored in the stack iterator only. + */ +void si_set_ip(StackIterator* si, NativeCodePtr ip, bool also_update_stack_itself = false); -// 20040713 Experimental: set the code chunk in the stack iterator -void si_set_code_chunk_info(StackIterator*, CodeChunkInfo*); +/** + * Sets the code chunk for the current frame of the stack indicated by the iterator. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * @param[in] cci - the pointer to CodeChunkInfo to be set for the current frame + * + * @note The function assumes that the thread is iterated in a managed frame. + */ +void si_set_code_chunk_info(StackIterator* si, CodeChunkInfo* cci); -// Return the code chunk information for the current frame. -// Returns NULL for M2nFrames. -CodeChunkInfo* si_get_code_chunk_info(StackIterator*); +/** + * Gets the code chunk information for the current frame. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The pointer to the code chunk information for managed frames and <code>NULL</code> + * for M2N frames. + */ +CodeChunkInfo* si_get_code_chunk_info(StackIterator* si); -// Return the JIT frame context for the current frame. This can be mutated to -// reflect changes in registers desired in transfer control. -JitFrameContext* si_get_jit_context(StackIterator*); +/** + * Gets the JIT frame context for the current frame. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The JIT frame context for the current frame. + */ +JitFrameContext* si_get_jit_context(StackIterator* si); -// Return if the current frame is an M2nFrame. -bool si_is_native(StackIterator*); +/** + * Checks whether the current frame is an M2N frame. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return <code>TRUE</code> if the current thread is an M2N frame; + * otherwise, <code>FALSE</code>. + */ +bool si_is_native(StackIterator* si); + +/** + * Gets the pointer to the M2N frame if the current frame is M2N. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The pointer to the the M2N frame if the current frame is M2N; otherwise, + * <code>NULL</code>. + */ +M2nFrame* si_get_m2n(StackIterator* si); -// Return the M2nFrame if the current frame is an M2nFrame. -// Should only be called if si_is_native is true. -M2nFrame* si_get_m2n(StackIterator*); +/** + * Gets the pointer to the value of the return register. + * + * If transfer control is called, the resumed frame will see this value. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return the pointer to the pointer to the return value. + */ +void** si_get_return_pointer(StackIterator* si); -// Set the return register appropriate for a pointer. If transfer control is -// subsequently called, the resumed frame will see this change. -// The argument points to the pointer to return. -void si_set_return_pointer(StackIterator*, void** return_value); +/** + * Sets the pointer to the value of the return register. + * + * If the transfer control is subsequently called, the resumed frame has data on this change. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * @param[in] return_value - the pointer to the pointer to the return value that will be set + */ +void si_set_return_pointer(StackIterator* si, void** return_value); -// Resume execution in the current frame of the iterator. -// Should only be called for an iterator on the current thread's frames. -// Does not return and frees the stack iterator. -void si_transfer_control(StackIterator*); +/** + * Thransfers control and resumes execution in the current frame of the iterator. + * Returns no values and frees the stack iterator. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @note This function must only be called for the iterator on the current thread's frames. + */ +void si_transfer_control(StackIterator* si); -// Copy the stack iterators current frame value into the given registers, so -// that resumption of these registers would transfer control to the current frame. -void si_copy_to_registers(StackIterator*, Registers*); +/** + * Copies the value of the stack iterators' current frame into the given registers. + * + * This way, resuming these registers transfers control to the current frame. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * @param[out] regs - the pointer to the registers where the registers' values + * from the stack iterator will be copied + */ +void si_copy_to_registers(StackIterator* si, Registers* regs); -// On architectures with register stacks, ensure that the register stack of -// the current thread is consistent with its backing store, as the backing -// store might have been modified by stack walking code. -// On other architectures do nothing. +/** + * Reloads registers from the register stack. + * + * + * @note On architectures with register stacks, ensure that the register stack of + * the current thread is consistent with its backing store. This is done because the backing + * store might have been modified by the stack walking code. + */ void si_reload_registers(); +/** + * Gets the method handle for the frame iterated by the stack iterator. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The method handle corresponding to the given stack iterator. + */ +Method_Handle si_get_method(StackIterator* si); + +/** + * Gets the number of inlined methods corresponding to the current frame + * iterated by stack iterator. + * + * @param[in] si - the pointer to the stack iterator indicating the current frame + * + * @return The number of inlined methods. + */ +uint32 si_get_inline_depth(StackIterator* si); + #endif //!_STACK_ITERATOR_H_ diff --git vm/port/src/disasm/linux/disasm.c vm/port/src/disasm/linux/disasm.c index 76f26e4..8cf0b46 100644 --- vm/port/src/disasm/linux/disasm.c +++ vm/port/src/disasm/linux/disasm.c @@ -137,10 +137,12 @@ static int disasm_sprint_default(void * } static int disasm_fprint_default(void * stream, const char * fmt, ...) { + + port_disassembler_t * disassembler = (port_disassembler_t *)stream; va_list args; va_start(args, fmt); - port_disassembler_t * disassembler = (port_disassembler_t *)stream; int required_length = apr_vsnprintf(NULL, 0, fmt, args); + va_end(args); // insure space if (required_length >= disassembler->num_bytes_total - disassembler->num_bytes_used) { @@ -150,10 +152,15 @@ static int disasm_fprint_default(void * } while (required_length >= disassembler->num_bytes_total - disassembler->num_bytes_used) { + apr_pool_clear(disassembler->user_pool); disassembler->num_bytes_total *= 2; + disassembler->real_stream = apr_palloc(disassembler->user_pool, + disassembler->num_bytes_total); } + va_start(args, fmt); apr_vsnprintf(disassembler->real_stream + disassembler->num_bytes_used, required_length + 1, fmt, args); + va_end(args); disassembler->num_bytes_used += required_length; return 0; } diff --git vm/port/src/encoder/ia32_em64t/dec_base.cpp vm/port/src/encoder/ia32_em64t/dec_base.cpp new file mode 100644 index 0000000..a797166 --- /dev/null +++ vm/port/src/encoder/ia32_em64t/dec_base.cpp @@ -0,0 +1,249 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander V. Astapchuk + * @version $Revision: $ + */ + +/** + * @file + * @brief Main decoding (disassembling) routines implementation. + */ + +#include "dec_base.h" + +bool DecoderBase::is_prefix(const unsigned char * bytes) +{ + unsigned char b0 = *bytes; + unsigned char b1 = *(bytes+1); + if (b0 == 0xF0) { // LOCK + return true; + } + if (b0==0xF2 || b0==0xF3) { // REPNZ/REPZ prefixes + if (b1 == 0x0F) { // .... but may be a part of SIMD opcode + return false; + } + return true; + } + if (b0 == 0x2E || b0 == 0x36 || b0==0x3E || b0==0x26 || b0==0x64 || b0==0x3E) { + // branch hints, segment prefixes + return true; + } + if (b0==0x66) { // operand-size prefix + if (b1 == 0x0F) { // .... but may be a part of SIMD opcode + return false; + } + return true; + } + if (b0==0x67) { // address size prefix + return true; + } + return false; +} + + +unsigned DecoderBase::decode(const void * addr, Inst * pinst) +{ + Inst tmp; + + const unsigned char * bytes = (unsigned char*)addr; + // Check prefix first + for (unsigned i=0; i<4; i++) { + if (!is_prefix(bytes)) { + break; + } + ++bytes; + } + + if (is_prefix(bytes)) { + // More than 4 prefixes together ? + assert(false); + return 0; + } + + // Load up to 4 prefixes + // for each Mnemonic + // for each opcodedesc + // if (raw_len == 0) memcmp(, raw_len) + // else check the mixed state which is one of the following: + // /digit /i /rw /rd /rb + + bool found = false; + const unsigned char * saveBytes = bytes; + for (unsigned mn=1; mn<Mnemonic_Count; mn++) { + bytes = saveBytes; + found=try_mn((Mnemonic)mn, &bytes, &tmp); + if (found) { + tmp.mn = (Mnemonic)mn; + break; + } + } + if (!found) { + assert(false); + return 0; + } + tmp.size = (unsigned)(bytes-(const unsigned char*)addr); + if (pinst) { + *pinst = tmp; + } + return tmp.size; +} + +bool DecoderBase::decode_aux(const EncoderBase::OpcodeDesc& odesc, unsigned aux, + const unsigned char ** pbuf, Inst * pinst) +{ + OpcodeByteKind kind = (OpcodeByteKind)(aux & OpcodeByteKind_KindMask); + unsigned byte = (aux & OpcodeByteKind_OpcodeMask); + unsigned data_byte = **pbuf; + switch (kind) { + case OpcodeByteKind_SlashR: + decodeModRM(odesc, pbuf, pinst); + return true; + case OpcodeByteKind_rb: + case OpcodeByteKind_rw: + case OpcodeByteKind_rd: + { + unsigned regid = data_byte - byte; + if (regid>7) { + return false; + } + ++*pbuf; + return true; + } + case OpcodeByteKind_cb: + pinst->offset = *(char*)*pbuf; + *pbuf += 1; + pinst->direct_addr = (void*)(pinst->offset + *pbuf); + return true; + case OpcodeByteKind_cw: + assert(false); // not an error, but not expected in current env + break; + case OpcodeByteKind_cd: + pinst->offset = *(int*)*pbuf; + *pbuf += 4; + pinst->direct_addr = (void*)(pinst->offset + *pbuf); + return true; + case OpcodeByteKind_SlashNum: + { + const ModRM& modrm = *(ModRM*)*pbuf; + if (modrm.reg != byte) { + return false; + } + decodeModRM(odesc, pbuf, pinst); + } + return true; + case OpcodeByteKind_ib: + *pbuf += 1; + return true; + case OpcodeByteKind_iw: + *pbuf += 2; + return true; + case OpcodeByteKind_id: + *pbuf += 4; + return true; + case OpcodeByteKind_plus_i: + { + unsigned regid = data_byte - byte; + if (regid>7) { + return false; + } + ++*pbuf; + return true; + } + case OpcodeByteKind_ZeroOpcodeByte: // cant be here + assert(false); + break; + default: + // unknown kind ? how comes ? + assert(false); + break; + } + return false; +} + +bool DecoderBase::try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst) { + const unsigned char * save_pbuf = *pbuf; + EncoderBase::OpcodeDesc * opcodes = EncoderBase::opcodes[mn]; + for (unsigned i=0; !opcodes[i].last; i++) { + const EncoderBase::OpcodeDesc& odesc = opcodes[i]; + *pbuf = save_pbuf; + if (odesc.opcode_len != 0) { + if (memcmp(*pbuf, odesc.opcode, odesc.opcode_len)) { + continue; + } + *pbuf += odesc.opcode_len; + } + if (odesc.aux0 != 0) { + + if (!decode_aux(odesc, odesc.aux0, pbuf, pinst)) { + continue; + } + if (odesc.aux1 != 0) { + if (!decode_aux(odesc, odesc.aux1, pbuf, pinst)) { + continue; + } + } + pinst->odesc = &opcodes[i]; + return true; + } + else { + // Can't have empty opcode + assert(odesc.opcode_len != 0); + pinst->odesc = &opcodes[i]; + return true; + } + } + return false; +} + +bool DecoderBase::decodeModRM(const EncoderBase::OpcodeDesc& odesc, + const unsigned char ** pbuf, Inst * pinst) +{ + const ModRM& modrm = *(ModRM*)*pbuf; + *pbuf += 1; + if (modrm.mod == 3) { + // we have only modrm. no sib, no disp. + return true; + } + const SIB& sib = *(SIB*)*pbuf; + // check whether we have a sib + if (modrm.rm == 4) { + // yes, we have SIB + *pbuf += 1; + } + + if (modrm.mod == 2) { + // have disp32 + *pbuf += 4; + } + else if (modrm.mod == 1) { + // have disp8 + *pbuf += 1; + } + else { + assert(modrm.mod == 0); + if (modrm.rm == 5) { + // have disp32 w/o sib + *pbuf += 4; + } + else if (modrm.rm == 4 && sib.base == 5) { + // have to analyze sib, special case without EBP: have disp32+SI + *pbuf += 4; + } + } + return true; +} + diff --git vm/port/src/encoder/ia32_em64t/dec_base.h vm/port/src/encoder/ia32_em64t/dec_base.h new file mode 100644 index 0000000..6bc9d40 --- /dev/null +++ vm/port/src/encoder/ia32_em64t/dec_base.h @@ -0,0 +1,68 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander V. Astapchuk + * @version $Revision: $ + */ + +/** + * @file + * @brief Main decoding (disassembling) routines and structures. + * + * @note Quick and rough implementation, subject for a change. + */ + +#ifndef __DEC_BASE_H_INCLUDED__ +#define __DEC_BASE_H_INCLUDED__ + + +#include "enc_base.h" +#include "enc_prvt.h" + +#define IF_CONDITIONAL (0x00000000) +#define IF_SYMMETRIC (0x00000000) +#define IF_BRANCH (0x00000000) + +struct Inst { + Mnemonic mn; + unsigned flags; + unsigned size; + int offset; + void * direct_addr; + const EncoderBase::OpcodeDesc * odesc; +}; + +inline bool is_jcc(Mnemonic mn) +{ + return Mnemonic_JO <= mn && mn<=Mnemonic_JG; +} + +class DecoderBase { +public: + static unsigned decode(const void * addr, Inst * pinst); +private: + static bool decodeModRM(const EncoderBase::OpcodeDesc& odesc, + const unsigned char ** pbuf, Inst * pinst); + static bool decode_aux(const EncoderBase::OpcodeDesc& odesc, + unsigned aux, const unsigned char ** pbuf, + Inst * pinst); + static bool try_mn(Mnemonic mn, const unsigned char ** pbuf, Inst * pinst); + + static bool is_prefix(const unsigned char * bytes); +}; + +#endif // ~ __DEC_BASE_H_INCLUDED__ + diff --git vm/port/src/encoder/ia32_em64t/enc_base.cpp vm/port/src/encoder/ia32_em64t/enc_base.cpp index 25276f8..a079a4f 100644 --- vm/port/src/encoder/ia32_em64t/enc_base.cpp +++ vm/port/src/encoder/ia32_em64t/enc_base.cpp @@ -21,23 +21,28 @@ #include "enc_base.h" #include <climits> #include <string.h> #include "enc_prvt.h" +#include <stdio.h> + +ENCODER_NAMESPACE_START + +//#define JET_PROTO + +#ifdef JET_PROTO +#include "dec_base.h" +#include "jvmti_dasm.h" +#endif + /** * @file * @brief Main encoding routines and structures. */ - -#ifdef PLATFORM_POSIX +#ifndef _WIN32 #define strcmpi strcasecmp #endif -#ifdef _EM64T_ -// no support in this release, thus no init needed -int EncoderBase::dummy = 0; -#else int EncoderBase::dummy = EncoderBase::buildTable(); -#endif const unsigned char EncoderBase::size_hash[OpndSize_64+1] = { // @@ -89,10 +94,9 @@ #endif 1<<2, // OpndKind_Memory=0x40 }; - char* EncoderBase::encode_aux(char* stream, unsigned aux, const Operands& opnds, const OpcodeDesc * odesc, - unsigned * pargsCount) + unsigned * pargsCount, Rex * prex) { const unsigned byte = aux; OpcodeByteKind kind = (OpcodeByteKind)(byte & OpcodeByteKind_KindMask); @@ -104,22 +108,33 @@ char* EncoderBase::encode_aux(char* stre // both a register operand and an r/m operand. { assert(opnds.count() > 1); - assert((odesc->opnds[0].kind & OpndKind_Mem) || - (odesc->opnds[1].kind & OpndKind_Mem)); + // not true anymore for MOVQ xmm<->r + //assert((odesc->opnds[0].kind & OpndKind_Mem) || + // (odesc->opnds[1].kind & OpndKind_Mem)); unsigned memidx = odesc->opnds[0].kind & OpndKind_Mem ? 0 : 1; unsigned regidx = memidx == 0 ? 1 : 0; memidx += *pargsCount; regidx += *pargsCount; ModRM& modrm = *(ModRM*)stream; if (opnds[memidx].is_mem()) { - stream = encodeModRM(stream, opnds, memidx, odesc); + stream = encodeModRM(stream, opnds, memidx, odesc, prex); } else { modrm.mod = 3; // 11 modrm.rm = getHWRegIndex(opnds[memidx].reg()); +#ifdef _EM64T_ + if (opnds[memidx].need_rex() && needs_rex_r(opnds[memidx].reg())) { + prex->b = 1; + } +#endif ++stream; } modrm.reg = getHWRegIndex(opnds[regidx].reg()); +#ifdef _EM64T_ + if (opnds[regidx].need_rex() && needs_rex_r(opnds[regidx].reg())) { + prex->r = 1; + } +#endif *pargsCount += 2; } break; @@ -136,11 +151,16 @@ char* EncoderBase::encode_aux(char* stre unsigned idx = *pargsCount; assert(opnds[idx].is_mem() || opnds[idx].is_reg()); if (opnds[idx].is_mem()) { - stream = encodeModRM(stream, opnds, idx, odesc); + stream = encodeModRM(stream, opnds, idx, odesc, prex); } else { modrm.mod = 3; // 11 modrm.rm = getHWRegIndex(opnds[idx].reg()); +#ifdef _EM64T_ + if (opnds[idx].need_rex() && needs_rex_r(opnds[idx].reg())) { + prex->b = 1; + } +#endif ++stream; } modrm.reg = (char)lowByte; @@ -156,7 +176,7 @@ char* EncoderBase::encode_aux(char* stre { unsigned idx = *pargsCount; const unsigned lowByte = (byte & OpcodeByteKind_OpcodeMask); - *stream = (char)lowByte + getRegIndex(opnds[idx].reg()); + *stream = (char)lowByte + getHWRegIndex(opnds[idx].reg()); ++stream; *pargsCount += 1; } @@ -164,6 +184,9 @@ char* EncoderBase::encode_aux(char* stre case OpcodeByteKind_ib>>8: case OpcodeByteKind_iw>>8: case OpcodeByteKind_id>>8: +#ifdef _EM64T_ + case OpcodeByteKind_io>>8: +#endif //_EM64T_ // ib, iw, id - A 1-byte (ib), 2-byte (iw), or 4-byte (id) // immediate operand to the instruction that follows the // opcode, ModR/M bytes or scale-indexing bytes. The opcode @@ -181,27 +204,37 @@ char* EncoderBase::encode_aux(char* stre *(unsigned short*)stream = (unsigned short)opnds[idx].imm(); stream += 2; } - else { - assert(kind == OpcodeByteKind_id); + else if (kind == OpcodeByteKind_id) { *(unsigned*)stream = (unsigned)opnds[idx].imm(); stream += 4; } +#ifdef _EM64T_ + else { + assert(kind == OpcodeByteKind_io); + *(long long*)stream = (long long)opnds[idx].imm(); + stream += 8; + } +#else + else { + assert(false); + } +#endif } break; case OpcodeByteKind_cb>>8: - assert(opnds.count() == 1 && opnds[*pargsCount].is_imm()); + assert(opnds[*pargsCount].is_imm()); *(unsigned char*)stream = (unsigned char)opnds[*pargsCount].imm(); stream += 1; *pargsCount += 1; break; case OpcodeByteKind_cw>>8: - assert(opnds.count() == 1 && opnds[*pargsCount].is_imm()); + assert(opnds[*pargsCount].is_imm()); *(unsigned short*)stream = (unsigned short)opnds[*pargsCount].imm(); stream += 2; *pargsCount += 1; break; case OpcodeByteKind_cd>>8: - assert(opnds.count() == 1 && opnds[*pargsCount].is_imm()); + assert(opnds[*pargsCount].is_imm()); *(unsigned*)stream = (unsigned)opnds[*pargsCount].imm(); stream += 4; *pargsCount += 1; @@ -221,6 +254,11 @@ char* EncoderBase::encode_aux(char* stre const unsigned lowByte = (byte & OpcodeByteKind_OpcodeMask); *(unsigned char*)stream = (unsigned char)lowByte + getHWRegIndex(opnds[*pargsCount].reg()); +#ifdef _EM64T_ + if (opnds[*pargsCount].need_rex() && needs_rex_r(opnds[*pargsCount].reg())) { + prex->b = 1; + } +#endif ++stream; *pargsCount += 1; } @@ -244,42 +282,100 @@ #ifdef _DEBUG } } #endif -#ifdef _EM64T_ - // No support for EM64T in this release - //assert(false); - *(unsigned char*)stream = 0xCC; - return stream+1; -#endif const OpcodeDesc * odesc = lookup(mn, opnds); - if (odesc->opcode_len==1) { - *(unsigned char*)stream = *(unsigned char*)&odesc->opcode; - } - else if (odesc->opcode_len==2) { - *(unsigned short*)stream = *(unsigned short*)&odesc->opcode; - } - else if (odesc->opcode_len==3) { - *(unsigned short*)stream = *(unsigned short*)&odesc->opcode; - *(unsigned char*)(stream+2) = odesc->opcode[2]; +#if !defined(_EM64T_) + bool copy_opcode = true; + Rex *prex = NULL; +#else + // We need rex if + // either of registers used as operand or address form is new extended register + // it's explicitly specified by opcode + // So, if we don't have REX in opcode but need_rex, then set rex here + // otherwise, wait until opcode is set, and then update REX + + bool copy_opcode = true; + unsigned char _1st = odesc->opcode[0]; + + Rex *prex = (Rex*)stream; + if (opnds.need_rex() && + ((_1st == 0x66) || (_1st == 0xF2 || _1st == 0xF3) && odesc->opcode[1] == 0x0F)) { + // Special processing + // + copy_opcode = false; + // + *(unsigned char*)stream = _1st; + ++stream; + // + prex = (Rex*)stream; + prex->dummy = 4; + prex->w = 0; + prex->b = 0; + prex->x = 0; + prex->r = 0; + ++stream; + // + memcpy(stream, &odesc->opcode[1], odesc->opcode_len-1); + stream += odesc->opcode_len-1; } - else if (odesc->opcode_len==4) { - *(unsigned*)stream = *(unsigned*)&odesc->opcode; + else if (_1st != 0x48 && opnds.need_rex()) { + prex = (Rex*)stream; + prex->dummy = 4; + prex->w = 0; + prex->b = 0; + prex->x = 0; + prex->r = 0; + ++stream; } - stream += odesc->opcode_len; +#endif // ifndef EM64T + if (copy_opcode) { + if (odesc->opcode_len==1) { + *(unsigned char*)stream = *(unsigned char*)&odesc->opcode; + } + else if (odesc->opcode_len==2) { + *(unsigned short*)stream = *(unsigned short*)&odesc->opcode; + } + else if (odesc->opcode_len==3) { + *(unsigned short*)stream = *(unsigned short*)&odesc->opcode; + *(unsigned char*)(stream+2) = odesc->opcode[2]; + } + else if (odesc->opcode_len==4) { + *(unsigned*)stream = *(unsigned*)&odesc->opcode; + } + stream += odesc->opcode_len; + } + unsigned argsCount = odesc->first_opnd; if (odesc->aux0) { - stream = encode_aux(stream, odesc->aux0, opnds, odesc, &argsCount); + stream = encode_aux(stream, odesc->aux0, opnds, odesc, &argsCount, prex); if (odesc->aux1) { - stream = encode_aux(stream, odesc->aux1, opnds, odesc, &argsCount); + stream = encode_aux(stream, odesc->aux1, opnds, odesc, &argsCount, prex); } } +#ifdef JET_PROTO + //saveStream + Inst inst; + unsigned len = DecoderBase::decode(saveStream, &inst); + if(inst.mn != mn) { + __asm { int 3 }; + } + if (len != (unsigned)(stream-saveStream)) { + __asm { int 3 }; + } + InstructionDisassembler idi(saveStream, (unsigned char)0xCC); + if(idi.get_length_with_prefix() != (int)len) { + __asm { int 3 }; + } +#endif + return stream; } char* EncoderBase::encodeModRM(char* stream, const Operands& opnds, - unsigned idx, const OpcodeDesc * odesc) + unsigned idx, const OpcodeDesc * odesc, + Rex * prex) { const Operand& op = opnds[idx]; assert(op.is_mem()); @@ -299,9 +395,21 @@ char* EncoderBase::encodeModRM(char* str if (base == RegName_Null && op.index() == RegName_Null) { assert(op.scale() == 0); // 'scale!=0' has no meaning without index // ... yes - only have disp + // On EM64T, the simply [disp] addressing means 'RIP-based' one - + // must have to use SIB to encode 'DS: based' +#ifdef _EM64T_ + modrm.mod = 0; // 00 - .. + modrm.rm = 4; // 100 - have SIB + + sib.base = 5; // 101 - none + sib.index = 4; // 100 - none + sib.scale = 0; // + ++stream; // bypass SIB +#else // ignore disp_fits8, always use disp32. modrm.mod = 0; modrm.rm = 5; +#endif *(unsigned*)stream = (unsigned)op.disp(); stream += 4; return stream; @@ -309,12 +417,12 @@ char* EncoderBase::encodeModRM(char* str const bool disp_fits8 = CHAR_MIN <= op.disp() && op.disp() <= CHAR_MAX; /*&& op.base() != RegName_Null - just checked above*/ - if (op.index() == RegName_Null && !equals(op.base(), REG_STACK)) { + if (op.index() == RegName_Null && getHWRegIndex(op.base()) != getHWRegIndex(REG_STACK)) { assert(op.scale() == 0); // 'scale!=0' has no meaning without index // ... luckily no SIB, only base and may be a disp // EBP base is a special case. Need to use [EBP] + disp8 form - if (op.disp() == 0 && !equals(op.base(), RegName_EBP)) { + if (op.disp() == 0 && getHWRegIndex(op.base()) != getHWRegIndex(RegName_EBP)) { modrm.mod = 0; // mod=00, no disp et all } else if (disp_fits8) { @@ -328,13 +436,16 @@ char* EncoderBase::encodeModRM(char* str stream += 4; } modrm.rm = getHWRegIndex(op.base()); + if (is_em64t_extra_reg(op.base())) { + prex->b = 1; + } return stream; } // cool, we do have SIB. ++stream; // bypass SIB in stream - // {E|R}SP cannot be scaled index + // {E|R}SP cannot be scaled index, however, R12 which has the same index in modrm - can assert(op.index() == RegName_Null || !equals(op.index(), REG_STACK)); // Only GPRegs can be encoded in the SIB @@ -362,10 +473,14 @@ char* EncoderBase::encodeModRM(char* str else if (sc == 4) { sib.scale = 2; } // SS=10 else if (sc == 8) { sib.scale = 3; } // SS=11 sib.index = getHWRegIndex(op.index()); + if (is_em64t_extra_reg(op.index())) { + prex->x = 1; + } + return stream; } - if (op.disp() == 0 && !equals(op.base(), RegName_EBP)) { + if (op.disp() == 0 && getHWRegIndex(op.base()) != getHWRegIndex(RegName_EBP)) { modrm.mod = 0; // mod=00, no disp } else if (disp_fits8) { @@ -382,9 +497,14 @@ char* EncoderBase::encodeModRM(char* str if (op.index() == RegName_Null) { assert(op.scale() == 0); // 'scale!=0' has no meaning without index // the only reason we're here without index, is that we have {E|R}SP - // as a base. Another possible reason - EBP without a disp - is - // handled above by adding a fake disp8 + // or R12 as a base. Another possible reason - EBP without a disp - + // is handled above by adding a fake disp8 +#ifdef _EM64T_ + assert(op.base() != RegName_Null && (equals(op.base(), REG_STACK) || + equals(op.base(), RegName_R12))); +#else // _EM64T_ assert(op.base() != RegName_Null && equals(op.base(), REG_STACK)); +#endif //_EM64T_ sib.scale = 0; // SS = 00 sib.index = 4; // SS + index=100 means 'no index' } @@ -395,11 +515,17 @@ char* EncoderBase::encodeModRM(char* str else if (sc == 4) { sib.scale = 2; } // SS=10 else if (sc == 8) { sib.scale = 3; } // SS=11 sib.index = getHWRegIndex(op.index()); + if (is_em64t_extra_reg(op.index())) { + prex->x = 1; + } // not an error by itself, but the usage of [index*1] instead // of [base] is discouraged assert(op.base() != RegName_Null || op.scale() != 1); } sib.base = getHWRegIndex(op.base()); + if (is_em64t_extra_reg(op.base())) { + prex->b = 1; + } return stream; } @@ -408,15 +534,15 @@ char * EncoderBase::nops(char * stream, // 1-byte NOP: - The True NOP (xchg EAX, EAX) static const unsigned char nop1 = 0x90; // 2-byte NOP: mov reg, reg - MOV EAX, EAX: 89 C0 - static const unsigned short nop2 = 0xC089; + static const unsigned short nop2 = 0x9090; // 3-byte NOP: lea reg, 0 (reg) (8-bit displacement) - // LEA EAX, reg+0x00 : 8D 40 00 - static const unsigned short nop3_01 = 0x408D; - static const unsigned char nop3_2 = 0x00; + static const unsigned short nop3_01 = 0x9090; + static const unsigned char nop3_2 = 0x90; // 6-byte NOP: lea reg, 0 (reg) (32-bit displacement) - // LEA EAX, reg+0x00000000: 8D 80 00000000 - static const unsigned short nop6_01 = 0x808D; - static const unsigned int nop6_2345 = 0x00000000; + static const unsigned short nop6_01 = 0x9090; + static const unsigned int nop6_2345 = 0x90909090; char * aligned = stream + howMany; @@ -487,11 +613,52 @@ static bool try_match(const EncoderBase: return true; } +// +//Subhash implementaion - may be useful in case of many misses during fast +//opcode lookup. +// + +#ifdef ENCODER_USE_SUBHASH +static unsigned subHash[32]; + +static unsigned find(Mnemonic mn, unsigned hash) +{ + unsigned key = hash % COUNTOF(subHash); + unsigned pack = subHash[key]; + unsigned _hash = pack & 0xFFFF; + if (_hash != hash) { + stat.miss(mn); + return EncoderBase::NOHASH; + } + unsigned _mn = (pack >> 24)&0xFF; + if (_mn != _mn) { + stat.miss(mn); + return EncoderBase::NOHASH; + } + unsigned idx = (pack >> 16) & 0xFF; + stat.hit(mn); + return idx; +} + +static void put(Mnemonic mn, unsigned hash, unsigned idx) +{ + unsigned pack = hash | (idx<<16) | (mn << 24); + unsigned key = hash % COUNTOF(subHash); + subHash[key] = pack; +} +#endif + const EncoderBase::OpcodeDesc * EncoderBase::lookup(Mnemonic mn, const Operands& opnds) { const unsigned hash = opnds.hash(); unsigned opcodeIndex = opcodesHashMap[mn][hash]; +#ifdef ENCODER_USE_SUBHASH + if (opcodeIndex == NOHASH) { + opcodeIndex = find(mn, hash); + } +#endif + if (opcodeIndex == NOHASH) { // fast-path did no work. try to lookup sequentially const OpcodeDesc * odesc = opcodes[mn]; @@ -521,6 +688,9 @@ EncoderBase::lookup(Mnemonic mn, const O } assert(found); opcodeIndex = idx; +#ifdef ENCODER_USE_SUBHASH + put(mn, hash, opcodeIndex); +#endif } assert(opcodeIndex != NOHASH); const OpcodeDesc * odesc = &opcodes[mn][opcodeIndex]; @@ -528,7 +698,7 @@ EncoderBase::lookup(Mnemonic mn, const O assert(odesc->roles.count == opnds.count()); #if !defined(_EM64T_) // tuning was done for IA32 only, so no size restriction on EM64T - assert(sizeof(OpcodeDesc)==128); + //assert(sizeof(OpcodeDesc)==128); #endif return odesc; } @@ -649,7 +819,7 @@ OpndKind getOpndKind(const char * kindSt * A mapping between register string representation and its RegName constant. */ static const struct { - char regstring[6]; + char regstring[7]; RegName regname; } @@ -705,11 +875,25 @@ #endif {"CL", RegName_CL}, {"DL", RegName_DL}, {"BL", RegName_BL}, +#if !defined(_EM64T_) {"AH", RegName_AH}, {"CH", RegName_CH}, {"DH", RegName_DH}, {"BH", RegName_BH}, - +#else + {"SPL", RegName_SPL}, + {"BPL", RegName_BPL}, + {"SIL", RegName_SIL}, + {"DIL", RegName_DIL}, + {"R8L", RegName_R8L}, + {"R9L", RegName_R9L}, + {"R10L", RegName_R10L}, + {"R11L", RegName_R11L}, + {"R12L", RegName_R12L}, + {"R13L", RegName_R13L}, + {"R14L", RegName_R14L}, + {"R15L", RegName_R15L}, +#endif {"ES", RegName_ES}, {"CS", RegName_CS}, {"SS", RegName_SS}, @@ -753,6 +937,17 @@ #endif {"XMM5", RegName_XMM5}, {"XMM6", RegName_XMM6}, {"XMM7", RegName_XMM7}, +#ifdef _EM64T_ + {"XMM8", RegName_XMM8}, + {"XMM9", RegName_XMM9}, + {"XMM10", RegName_XMM10}, + {"XMM11", RegName_XMM11}, + {"XMM12", RegName_XMM12}, + {"XMM13", RegName_XMM13}, + {"XMM14", RegName_XMM14}, + {"XMM15", RegName_XMM15}, +#endif + {"XMM0S", RegName_XMM0S}, {"XMM1S", RegName_XMM1S}, @@ -762,6 +957,16 @@ #endif {"XMM5S", RegName_XMM5S}, {"XMM6S", RegName_XMM6S}, {"XMM7S", RegName_XMM7S}, +#ifdef _EM64T_ + {"XMM8S", RegName_XMM8S}, + {"XMM9S", RegName_XMM9S}, + {"XMM10S", RegName_XMM10S}, + {"XMM11S", RegName_XMM11S}, + {"XMM12S", RegName_XMM12S}, + {"XMM13S", RegName_XMM13S}, + {"XMM14S", RegName_XMM14S}, + {"XMM15S", RegName_XMM15S}, +#endif {"XMM0D", RegName_XMM0D}, {"XMM1D", RegName_XMM1D}, @@ -771,7 +976,17 @@ #endif {"XMM5D", RegName_XMM5D}, {"XMM6D", RegName_XMM6D}, {"XMM7D", RegName_XMM7D}, - +#ifdef _EM64T_ + {"XMM8D", RegName_XMM8D}, + {"XMM9D", RegName_XMM9D}, + {"XMM10D", RegName_XMM10D}, + {"XMM11D", RegName_XMM11D}, + {"XMM12D", RegName_XMM12D}, + {"XMM13D", RegName_XMM13D}, + {"XMM14D", RegName_XMM14D}, + {"XMM15D", RegName_XMM15D}, +#endif + {"EFLGS", RegName_EFLAGS}, }; @@ -799,3 +1014,5 @@ RegName getRegName(const char * regname) } return RegName_Null; } + +ENCODER_NAMESPACE_END diff --git vm/port/src/encoder/ia32_em64t/enc_base.h vm/port/src/encoder/ia32_em64t/enc_base.h index ea58dad..1c6d0fe 100644 --- vm/port/src/encoder/ia32_em64t/enc_base.h +++ vm/port/src/encoder/ia32_em64t/enc_base.h @@ -28,12 +28,15 @@ #define __ENC_BASE_H_INCLUDED__ #include "enc_defs.h" + #include <stdlib.h> #include <assert.h> #include <memory.h> +ENCODER_NAMESPACE_START struct MnemonicInfo; struct OpcodeInfo; +struct Rex; /** * @brief Basic facilities for generation of processor's instructions. @@ -53,7 +56,7 @@ struct OpcodeInfo; * Interface is provided through static methods, no instances of EncoderBase * to be created. * - * @note Support for EM64T is dropped in this release. + * @todo RIP-based addressing on EM64T - it's not yet supported currently. */ class EncoderBase { public: @@ -212,7 +215,7 @@ public: * independent from arguments/sizes/etc (may include opcode size * prefix). */ - char opcode[4]; // 4 bytes + char opcode[5]; // 4 bytes unsigned opcode_len; // 4 unsigned aux0; // 4 unsigned aux1; // 4 @@ -230,10 +233,6 @@ public: */ OpndRolesDesc roles; // 16 /** - * @brief Only on EM64T - REX encoding or zero if no REX prefix. - */ - char rex; // 1 - /** * @brief If not zero, then this is final OpcodeDesc structure in * the list of opcodes for a given mnemonic. */ @@ -254,23 +253,10 @@ public: */ Mnemonic mn; /** - * @brief true if the operation affects flags. - */ - bool affectsFlags; - /** - * @brief true if the operation uses flags - i.e. conditional - * operations, ADC/SBB/etc. - */ - bool usesFlags; - /** - * @brief true if the operation is conditional - MOVcc/SETcc/Jcc/ETC. + * Various characteristics of mnemonic. + * @see MF_ */ - bool conditional; - /** - * @brief true if the operation is symmetric - its args can be - * swapped (ADD/MUL/etc). - */ - bool symmetric; + unsigned flags; /** * @brief Operation's operand's count and roles. * @@ -317,9 +303,22 @@ public: Operand(RegName reg) : m_kind(getRegKind(reg)), m_size(getRegSize(reg)), m_reg(reg) { - m_base = m_index = RegName_Null; - m_scale = 0; - m_disp = 0; + hash_it(); + } + /** + * @brief Creates register operand from given RegName and with the + * specified size and kind. + * + * Used to speedup Operand creation as there is no need to extract + * size and kind from the RegName. + * The provided size and kind must match the RegName's ones though. + */ + Operand(OpndSize sz, OpndKind kind, RegName reg) : m_kind(kind), + m_size(sz), + m_reg(reg) + { + assert(m_size == getRegSize(reg)); + assert(m_kind == getRegKind(reg)); hash_it(); } /** @@ -328,9 +327,6 @@ public: Operand(OpndSize size, long long ival) : m_kind(OpndKind_Imm), m_size(size), m_imm64(ival) { - m_base = m_index = RegName_Null; - m_scale = 0; - m_disp = 0; hash_it(); } /** @@ -339,9 +335,6 @@ public: Operand(int ival) : m_kind(OpndKind_Imm), m_size(OpndSize_32), m_imm64(ival) { - m_base = m_index = RegName_Null; - m_scale = 0; - m_disp = 0; hash_it(); } /** @@ -350,9 +343,6 @@ public: Operand(short ival) : m_kind(OpndKind_Imm), m_size(OpndSize_16), m_imm64(ival) { - m_base = m_index = RegName_Null; - m_scale = 0; - m_disp = 0; hash_it(); } @@ -362,9 +352,6 @@ public: Operand(char ival) : m_kind(OpndKind_Imm), m_size(OpndSize_8), m_imm64(ival) { - m_base = m_index = RegName_Null; - m_scale = 0; - m_disp = 0; hash_it(); } @@ -372,7 +359,7 @@ public: * @brief Creates memory operand. */ Operand(OpndSize size, RegName base, RegName index, unsigned scale, - int disp) : m_kind(OpndKind_Mem), m_size(size), m_imm64(0) + int disp) : m_kind(OpndKind_Mem), m_size(size) { m_base = base; m_index = index; @@ -385,7 +372,7 @@ public: * @brief Creates memory operand with only base and displacement. */ Operand(OpndSize size, RegName base, int disp) : - m_kind(OpndKind_Mem), m_size(size), m_imm64(0) + m_kind(OpndKind_Mem), m_size(size) { m_base = base; m_index = RegName_Null; @@ -409,6 +396,11 @@ public: */ unsigned hash(void) const { return m_hash; } // +#ifdef _EM64T_ + bool need_rex(void) const { return m_need_rex; } +#else + bool need_rex(void) const { return false; } +#endif /** * @brief Tests whether operand is memory operand. */ @@ -479,25 +471,35 @@ #endif void hash_it(void) { m_hash = size_hash[m_size] | kind_hash[m_kind]; +#ifdef _EM64T_ + m_need_rex = false; + if (is_reg() && is_em64t_extra_reg(m_reg)) { + m_need_rex = true; + } + else if (is_mem() && (is_em64t_extra_reg(m_base) || + is_em64t_extra_reg(m_index))) { + m_need_rex = true; + } +#endif } /** * @brief Initializes the instance with empty size and kind. */ - Operand() : m_kind(OpndKind_Null), m_size(OpndSize_Null) {} + Operand() : m_kind(OpndKind_Null), m_size(OpndSize_Null), m_need_rex(false) {} // general info - OpndKind m_kind; - OpndSize m_size; + OpndKind m_kind; + OpndSize m_size; // complex address form support - RegName m_base; - RegName m_index; - unsigned m_scale; - int m_disp; - // data + RegName m_base; + RegName m_index; + unsigned m_scale; union { - long long m_imm64; - RegName m_reg; + int m_disp; + RegName m_reg; + long long m_imm64; }; - unsigned m_hash; + unsigned m_hash; + bool m_need_rex; friend class EncoderBase::Operands; }; /** @@ -505,26 +507,25 @@ #endif */ class Operands { public: - Operands(void) : m_count(0) + Operands(void) { - m_hash = 0; + clear(); } - Operands(const Operand& op0) : m_count(1) + Operands(const Operand& op0) { - m_operands[0] = op0; - m_hash = op0.hash(); + clear(); + add(op0); } - - Operands(const Operand& op0, const Operand& op1) : m_count(2) + + Operands(const Operand& op0, const Operand& op1) { - m_operands[0] = op0; - m_operands[1] = op1; - m_hash = (op0.hash()<<HASH_BITS_PER_OPERAND) | op1.hash(); + clear(); + add(op0); add(op1); } Operands(const Operand& op0, const Operand& op1, const Operand& op2) - : m_count(0), m_hash(0) { + clear(); add(op0); add(op1); add(op2); } @@ -541,15 +542,22 @@ #endif assert(m_count < COUNTOF(m_operands)); m_hash = (m_hash<<HASH_BITS_PER_OPERAND) | op.hash(); m_operands[m_count++] = op; + m_need_rex = m_need_rex || op.m_need_rex; } +#ifdef _EM64T_ + bool need_rex(void) const { return m_need_rex; } +#else + bool need_rex(void) const { return false; } +#endif void clear(void) { - m_count = 0; m_hash = 0; + m_count = 0; m_hash = 0; m_need_rex = false; } private: - unsigned m_count; - Operand m_operands[COUNTOF( ((OpcodeDesc*)NULL)->opnds )]; - unsigned m_hash; + unsigned m_count; + Operand m_operands[COUNTOF( ((OpcodeDesc*)NULL)->opnds )]; + unsigned m_hash; + bool m_need_rex; }; public: #ifdef _DEBUG @@ -569,13 +577,13 @@ private: * @brief Encodes mod/rm byte. */ static char* encodeModRM(char* stream, const Operands& opnds, - unsigned idx, const OpcodeDesc * odesc); + unsigned idx, const OpcodeDesc * odesc, Rex * prex); /** * @brief Encodes special things of opcode description - '/r', 'ib', etc. */ static char* encode_aux(char* stream, unsigned aux, const Operands& opnds, const OpcodeDesc * odesc, - unsigned * pargsCount); + unsigned * pargsCount, Rex* prex); #ifdef _EM64T_ /** * @brief Returns true if the 'reg' argument represents one of the new @@ -584,7 +592,17 @@ #ifdef _EM64T_ * The 64 bits versions of 'old-fashion' registers, i.e. RAX are not * considered as 'extra'. */ - static inline bool is_em64t_extra_reg(const RegName reg) + static bool is_em64t_extra_reg(const RegName reg) + { + if (needs_rex_r(reg)) { + return true; + } + if (RegName_SPL <= reg && reg <= RegName_R15L) { + return true; + } + return false; + } + static bool needs_rex_r(const RegName reg) { if (RegName_R8 <= reg && reg <= RegName_R15) { return true; @@ -592,6 +610,18 @@ #ifdef _EM64T_ if (RegName_R8D <= reg && reg <= RegName_R15D) { return true; } + if (RegName_R8S <= reg && reg <= RegName_R15S) { + return true; + } + if (RegName_R8L <= reg && reg <= RegName_R15L) { + return true; + } + if (RegName_XMM8D <= reg && reg <= RegName_XMM15D) { + return true; + } + if (RegName_XMM8S <= reg && reg <= RegName_XMM15S) { + return true; + } return false; } /** @@ -604,6 +634,15 @@ #ifdef _EM64T_ */ static unsigned char getHWRegIndex(const RegName reg) { + if (getRegKind(reg) != OpndKind_GPReg) { + return getRegIndex(reg); + } + if (RegName_SPL <= reg && reg<=RegName_DIL) { + return getRegIndex(reg); + } + if (RegName_R8L<= reg && reg<=RegName_R15L) { + return getRegIndex(reg) - getRegIndex(RegName_R8L); + } return is_em64t_extra_reg(reg) ? getRegIndex(reg)-getRegIndex(RegName_R8D) : getRegIndex(reg); } @@ -612,6 +651,10 @@ #else { return getRegIndex(reg); } + static bool is_em64t_extra_reg(const RegName reg) + { + return false; + } #endif public: /** @@ -645,9 +688,6 @@ public: /** * @brief Array of available opcodes. */ -#if defined(__INTEL_COMPILER) || !defined(PLATFORM_POSIX) - __declspec(align(16)) -#endif static OpcodeDesc opcodes[Mnemonic_Count][MAX_OPCODES]; static int buildTable(void); @@ -663,4 +703,6 @@ #endif static int dummy; }; +ENCODER_NAMESPACE_END + #endif // ifndef __ENC_BASE_H_INCLUDED__ diff --git vm/port/src/encoder/ia32_em64t/enc_defs.h vm/port/src/encoder/ia32_em64t/enc_defs.h index 1db2c3c..f356831 100644 --- vm/port/src/encoder/ia32_em64t/enc_defs.h +++ vm/port/src/encoder/ia32_em64t/enc_defs.h @@ -20,6 +20,17 @@ #ifndef _ENCODER_DEFS_H_ #define _ENCODER_DEFS_H_ + +// Used to isolate experimental or being tuned encoder into a separate +// namespace so it can coexist with a stable one in the same bundle. +#ifdef ENCODER_ISOLATE + #define ENCODER_NAMESPACE_START namespace enc_ia32 { + #define ENCODER_NAMESPACE_END }; +#else + #define ENCODER_NAMESPACE_START + #define ENCODER_NAMESPACE_END +#endif + #include <assert.h> #ifndef COUNTOF @@ -49,6 +60,8 @@ #else #define MAX_REGS 8 #endif +ENCODER_NAMESPACE_START + /** * 'int_ptr' is a signed integer type which has the * same size as a pointer on the target platform. @@ -58,7 +71,7 @@ typedef long int_ptr; /** * A number of bytes 'eaten' by an ordinary PUSH/POP. */ -#define STACK_SLOT_SIZE (sizeof(long)) +#define STACK_SLOT_SIZE (sizeof(void*)) /** @@ -225,10 +238,26 @@ #endif //~_EM64T_ RegName_CL=REGNAME(OpndKind_GPReg,OpndSize_8,1), RegName_DL=REGNAME(OpndKind_GPReg,OpndSize_8,2), RegName_BL=REGNAME(OpndKind_GPReg,OpndSize_8,3), + // Used in enc_tabl.cpp RegName_AH=REGNAME(OpndKind_GPReg,OpndSize_8,4), +#if !defined(_EM64T_) RegName_CH=REGNAME(OpndKind_GPReg,OpndSize_8,5), RegName_DH=REGNAME(OpndKind_GPReg,OpndSize_8,6), RegName_BH=REGNAME(OpndKind_GPReg,OpndSize_8,7), +#else + RegName_SPL=REGNAME(OpndKind_GPReg,OpndSize_8,4), + RegName_BPL=REGNAME(OpndKind_GPReg,OpndSize_8,5), + RegName_SIL=REGNAME(OpndKind_GPReg,OpndSize_8,6), + RegName_DIL=REGNAME(OpndKind_GPReg,OpndSize_8,7), + RegName_R8L=REGNAME(OpndKind_GPReg,OpndSize_8,8), + RegName_R9L=REGNAME(OpndKind_GPReg,OpndSize_8,9), + RegName_R10L=REGNAME(OpndKind_GPReg,OpndSize_8,10), + RegName_R11L=REGNAME(OpndKind_GPReg,OpndSize_8,11), + RegName_R12L=REGNAME(OpndKind_GPReg,OpndSize_8,12), + RegName_R13L=REGNAME(OpndKind_GPReg,OpndSize_8,13), + RegName_R14L=REGNAME(OpndKind_GPReg,OpndSize_8,14), + RegName_R15L=REGNAME(OpndKind_GPReg,OpndSize_8,15), +#endif RegName_ES=REGNAME(OpndKind_SReg,OpndSize_16,0), RegName_CS=REGNAME(OpndKind_SReg,OpndSize_16,1), @@ -298,15 +327,16 @@ #endif // ~TESTING_ENCODER RegName_XMM5S=REGNAME(OpndKind_XMMReg,OpndSize_32,5), RegName_XMM6S=REGNAME(OpndKind_XMMReg,OpndSize_32,6), RegName_XMM7S=REGNAME(OpndKind_XMMReg,OpndSize_32,7), - - RegName_XMM8S=REGNAME(OpndKind_XMMReg,OpndSize_32,0), - RegName_XMM9S=REGNAME(OpndKind_XMMReg,OpndSize_32,1), - RegName_XMM10S=REGNAME(OpndKind_XMMReg,OpndSize_32,2), - RegName_XMM11S=REGNAME(OpndKind_XMMReg,OpndSize_32,3), - RegName_XMM12S=REGNAME(OpndKind_XMMReg,OpndSize_32,4), - RegName_XMM13S=REGNAME(OpndKind_XMMReg,OpndSize_32,5), - RegName_XMM14S=REGNAME(OpndKind_XMMReg,OpndSize_32,6), - RegName_XMM15S=REGNAME(OpndKind_XMMReg,OpndSize_32,7), +#ifdef _EM64T_ + RegName_XMM8S=REGNAME(OpndKind_XMMReg,OpndSize_32,8), + RegName_XMM9S=REGNAME(OpndKind_XMMReg,OpndSize_32,9), + RegName_XMM10S=REGNAME(OpndKind_XMMReg,OpndSize_32,10), + RegName_XMM11S=REGNAME(OpndKind_XMMReg,OpndSize_32,11), + RegName_XMM12S=REGNAME(OpndKind_XMMReg,OpndSize_32,12), + RegName_XMM13S=REGNAME(OpndKind_XMMReg,OpndSize_32,13), + RegName_XMM14S=REGNAME(OpndKind_XMMReg,OpndSize_32,14), + RegName_XMM15S=REGNAME(OpndKind_XMMReg,OpndSize_32,15), +#endif // ifdef _EM64T_ RegName_XMM0D=REGNAME(OpndKind_XMMReg,OpndSize_64,0), RegName_XMM1D=REGNAME(OpndKind_XMMReg,OpndSize_64,1), RegName_XMM2D=REGNAME(OpndKind_XMMReg,OpndSize_64,2), @@ -315,14 +345,16 @@ #endif // ~TESTING_ENCODER RegName_XMM5D=REGNAME(OpndKind_XMMReg,OpndSize_64,5), RegName_XMM6D=REGNAME(OpndKind_XMMReg,OpndSize_64,6), RegName_XMM7D=REGNAME(OpndKind_XMMReg,OpndSize_64,7), - RegName_XMM8D=REGNAME(OpndKind_XMMReg,OpndSize_64,0), - RegName_XMM9D=REGNAME(OpndKind_XMMReg,OpndSize_64,1), - RegName_XMM10D=REGNAME(OpndKind_XMMReg,OpndSize_64,2), - RegName_XMM11D=REGNAME(OpndKind_XMMReg,OpndSize_64,3), - RegName_XMM12D=REGNAME(OpndKind_XMMReg,OpndSize_64,4), - RegName_XMM13D=REGNAME(OpndKind_XMMReg,OpndSize_64,5), - RegName_XMM14D=REGNAME(OpndKind_XMMReg,OpndSize_64,6), - RegName_XMM15D=REGNAME(OpndKind_XMMReg,OpndSize_64,7), +#ifdef _EM64T_ + RegName_XMM8D=REGNAME(OpndKind_XMMReg,OpndSize_64,8), + RegName_XMM9D=REGNAME(OpndKind_XMMReg,OpndSize_64,9), + RegName_XMM10D=REGNAME(OpndKind_XMMReg,OpndSize_64,10), + RegName_XMM11D=REGNAME(OpndKind_XMMReg,OpndSize_64,11), + RegName_XMM12D=REGNAME(OpndKind_XMMReg,OpndSize_64,12), + RegName_XMM13D=REGNAME(OpndKind_XMMReg,OpndSize_64,13), + RegName_XMM14D=REGNAME(OpndKind_XMMReg,OpndSize_64,14), + RegName_XMM15D=REGNAME(OpndKind_XMMReg,OpndSize_64,15), +#endif // ifdef _EM64T_ #ifdef _HAVE_MMX_ RegName_MMX0=REGNAME(OpndKind_MMXReg,OpndSize_64,0), RegName_MMX1=REGNAME(OpndKind_MMXReg,OpndSize_64,1), @@ -481,6 +513,7 @@ Mnemonic_LOOPNE, Mnemonic_LOOPNZ = Mnemo Mnemonic_LAHF, // Load Flags into AH Mnemonic_MOV, // Move Mnemonic_MOVQ, // Move Quadword +Mnemonic_MOVD, // Move Double word Mnemonic_MOVSD, // Move Scalar Double-Precision Floating-Point Value Mnemonic_MOVSS, // Move Scalar Single-Precision Floating-Point Values Mnemonic_MOVSX, // Move with Sign-Extension @@ -527,14 +560,14 @@ Mnemonic_SETcc, Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left Mnemonic_SAR, // Unsigned shift right -Mnemonic_ROR, // rotate right +Mnemonic_ROR, // Rotate right Mnemonic_SHR, // Signed shift right Mnemonic_SHRD, // Double Precision Shift Right Mnemonic_SHLD, // Double Precision Shift Left Mnemonic_SBB, // Integer Subtraction with Borrow Mnemonic_SUB, // Subtract -Mnemonic_SUBSD, // Subtract Scalar Single-Precision Floating-Point Values +Mnemonic_SUBSD, // Subtract Scalar Double-Precision Floating-Point Values Mnemonic_SUBSS, // Subtract Scalar Single-Precision Floating-Point Values Mnemonic_TEST, // Logical Compare @@ -704,8 +737,10 @@ inline RegName getAliasReg(RegName reg, */ inline bool equals(RegName r0, RegName r1) { - assert(getRegKind(r0) == getRegKind(r1)); - return getRegIndex(r0) == getRegIndex(r1); + return getRegKind(r0) == getRegKind(r1) && + getRegIndex(r0) == getRegIndex(r1); } +ENCODER_NAMESPACE_END + #endif // ifndef _ENCODER_DEFS_H_ diff --git vm/port/src/encoder/ia32_em64t/enc_prvt.h vm/port/src/encoder/ia32_em64t/enc_prvt.h index 63e1675..e8cddaf 100644 --- vm/port/src/encoder/ia32_em64t/enc_prvt.h +++ vm/port/src/encoder/ia32_em64t/enc_prvt.h @@ -22,6 +22,7 @@ #define __ENC_PRVT_H_INCLUDED__ #include "enc_base.h" +ENCODER_NAMESPACE_START /* * @file * @brief Contains some definitions/constants and other stuff used by the @@ -149,6 +150,11 @@ #ifdef _EM64T_ #define RDX { OpndKind_GPReg, OpndSize_64, RegName_RDX } #endif +#define EDI {OpndKind_GPReg, OpndSize_32, RegName_EDI} +#ifdef _EM64T_ + #define RDI { OpndKind_GPReg, OpndSize_64, RegName_RDI } +#endif + #define r8 {OpndKind_GPReg, OpndSize_8, RegName_Null} #define r16 {OpndKind_GPReg, OpndSize_16, RegName_Null} #define r32 {OpndKind_GPReg, OpndSize_32, RegName_Null} @@ -202,7 +208,6 @@ #ifdef _EM64T_ #endif -#ifdef _EM64T_ /** * @brief Represents the REX part of instruction. */ @@ -214,7 +219,6 @@ struct Rex { unsigned char dummy : 4; // must be '0100'b unsigned int :24; }; -#endif /** * @brief Describes SIB (scale,index,base) byte. @@ -251,36 +255,58 @@ struct OpcodeInfo { }; /** -* @see same structure as EncoderBase::MnemonicDesc, but carries MnemonicInfo::OpcodeInfo[] -* instead of OpcodeDesc[]. -* Only used during prebuilding the encoding tables, thus it's hidden under -* the appropriate define. + * @defgroup MF_ Mnemonic flags */ -struct MnemonicInfo { + /** - * The mnemonic itself + * Operation has no special properties. */ - Mnemonic mn; +#define MF_NONE (0x00000000) /** - * true if the operation affects flags + * Operation affects flags */ - bool affectsFlags; +#define MF_AFFECTS_FLAGS (0x00000001) /** - * true if the operation analyzes flags - conditional operations, ADC/SBB/ETC + * Operation uses flags - conditional operations, ADC/SBB/ETC */ - bool usesFlags; +#define MF_USES_FLAGS (0x00000002) /** - * true if the operation is conditional - MOVcc/SETcc/Jcc/ETC + * Operation is conditional - MOVcc/SETcc/Jcc/ETC */ - bool conditional; +#define MF_CONDITIONAL (0x00000004) +/** + * Operation is symmetric - its args can be swapped (ADD/MUL/etc). + */ +#define MF_SYMMETRIC (0x00000008) +/** + * Operation is XOR-like - XOR, SUB - operations of 'arg,arg' is pure def, + * without use. + */ +#define MF_SAME_ARG_NO_USE (0x00000010) + +///@} // ~MNF + +/** + * @see same structure as EncoderBase::MnemonicDesc, but carries + * MnemonicInfo::OpcodeInfo[] instead of OpcodeDesc[]. + * Only used during prebuilding the encoding tables, thus it's hidden under + * the appropriate define. + */ +struct MnemonicInfo { + /** + * The mnemonic itself + */ + Mnemonic mn; /** - * true if operation is symmetric - its args can be swapped (ADD/MUL/etc). + * Various characteristics of mnemonic. + * @see MF_ */ - bool symmetric; + unsigned flags; /** - * Number of args/des/uses/roles for the operation. For the operations which - * may use different number of operands (i.e. IMUL/SHL) use the most common - * value, or leave '0' if you are sure this info is not required. + * Number of args/des/uses/roles for the operation. For the operations + * which may use different number of operands (i.e. IMUL/SHL) use the + * most common value, or leave '0' if you are sure this info is not + * required. */ EncoderBase::OpndRolesDesc roles; /** @@ -289,13 +315,14 @@ struct MnemonicInfo { const char * name; /** * Array of opcodes. - * The terminating opcode description always have OpcodeByteKind_LAST at - * the opcodes[i].opcode[0]. + * The terminating opcode description always have OpcodeByteKind_LAST + * at the opcodes[i].opcode[0]. * The size of '20' has nothing behind it, just counted the max * number of opcodes currently used. */ OpcodeInfo opcodes[20]; }; +ENCODER_NAMESPACE_END #endif // ~__ENC_PRVT_H_INCLUDED__ diff --git vm/port/src/encoder/ia32_em64t/enc_tabl.cpp vm/port/src/encoder/ia32_em64t/enc_tabl.cpp index 0b3a7f8..09b199d 100644 --- vm/port/src/encoder/ia32_em64t/enc_tabl.cpp +++ vm/port/src/encoder/ia32_em64t/enc_tabl.cpp @@ -26,6 +26,7 @@ #include <memory.h> #include <errno.h> #include <stdlib.h> + // need to use EM64T-specifics - new registers, defines from enc_prvt, etc... #if !defined(_EM64T_) #define UNDEF_EM64T @@ -46,6 +47,8 @@ #if !defined(_HAVE_MMX_) #define Mnemonic_PSUBQ Mnemonic_Null #endif +ENCODER_NAMESPACE_START + EncoderBase::MnemonicDesc EncoderBase::mnemonics[Mnemonic_Count]; EncoderBase::OpcodeDesc EncoderBase::opcodes[Mnemonic_Count][MAX_OPCODES]; @@ -97,15 +100,12 @@ I.e., TheManual reads for DEC: 3. Fill out the mnemonic, opcode parameters parts - BEGIN_MNEMONIC(DEC, true, false, false, false, DU ) + BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU) BEGIN_OPCODES() {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU }, {OpcodeInfo::em64t, {REX_W, 0xFF, _1}, {r_m64}, DU }, - true, false, false, false, DU: - ^ true - affects (sets) flags - ^ false*3 - does not use flags, not conditional, not symmetric - ^ DU - one argument, it's used and defined + DU here - one argument, it's used and defined 4. That's it, that simple ! @@ -114,7 +114,6 @@ perform data flow analysis. It also used Special cases are (see the table for details): LEA -SETcc Some FPU operations (i.e. FSTP) packed things (XORPD, XORPS, CVTDQ2PD, CVTTPD2DQ) @@ -296,22 +295,26 @@ unsigned short EncoderBase::getHash(cons } -#define BEGIN_MNEMONIC(mn, affflags, ulags, cond, symm, roles) \ - { Mnemonic_##mn, affflags, ulags, cond, symm, roles, #mn, +#define BEGIN_MNEMONIC(mn, flags, roles) \ + { Mnemonic_##mn, flags, roles, #mn, #define END_MNEMONIC() }, #define BEGIN_OPCODES() { #define END_OPCODES() { OpcodeInfo::all, {OpcodeByteKind_LAST} }} +//#define BEGIN_MNEMONIC(mn, affflags, ulags, cond, symm, roles) \ +// { Mnemonic_##mn, affflags, ulags, cond, symm, roles, #mn, + + static MnemonicInfo masterEncodingTable[] = { // // Null // -BEGIN_MNEMONIC(Null, false, false, false, false, N ) +BEGIN_MNEMONIC(Null, MF_NONE, N) BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(LAHF, false, true, false, false, D ) +BEGIN_MNEMONIC(LAHF, MF_USES_FLAGS, D) BEGIN_OPCODES() // TheManual says it's not always supported in em64t mode, thus excluding it {OpcodeInfo::ia32, {0x9F}, {EAX}, D }, @@ -357,62 +360,62 @@ #define DEFINE_ALU_OPCODES( opc_ext, opc {OpcodeInfo::all, {opcode_starts_from+3, _r}, {r32, r_m32}, def_use },\ {OpcodeInfo::em64t, {REX_W, opcode_starts_from+3, _r}, {r64, r_m64}, def_use }, -BEGIN_MNEMONIC(ADD, true, false, false, true, DU_U ) +BEGIN_MNEMONIC(ADD, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_0, 0x00, OxOO, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(OR, true, false, false, true, DU_U ) +BEGIN_MNEMONIC(OR, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_1, 0x08, 0x08, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(ADC, true, true, false, true, DU_U ) +BEGIN_MNEMONIC(ADC, MF_AFFECTS_FLAGS|MF_USES_FLAGS|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_2, 0x10, 0x10, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SBB, true, true, false, false, DU_U ) +BEGIN_MNEMONIC(SBB, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_3, 0x18, 0x18, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(AND, true, false, false, true, DU_U ) +BEGIN_MNEMONIC(AND, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_4, 0x20, 0x20, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SUB, true, false, false, false, DU_U ) +BEGIN_MNEMONIC(SUB, MF_AFFECTS_FLAGS|MF_SAME_ARG_NO_USE, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES(_5, 0x28, 0x28, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(XOR, true, false, false, true, DU_U ) +BEGIN_MNEMONIC(XOR, MF_AFFECTS_FLAGS|MF_SYMMETRIC|MF_SAME_ARG_NO_USE, DU_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES( _6, 0x30, 0x30, DU_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CMP, true, false, false, false, U_U ) +BEGIN_MNEMONIC(CMP, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() DEFINE_ALU_OPCODES( _7, 0x38, 0x38, U_U ) END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CMPXCHG, false, false, false, false, DU_DU ) +BEGIN_MNEMONIC(CMPXCHG, MF_NONE, DU_DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xB0, _r}, {r_m8, r8}, DU_DU }, {OpcodeInfo::all, {Size16, 0x0F, 0xB1, _r}, {r_m16, r16}, DU_DU }, {OpcodeInfo::all, {0x0F, 0xB1, _r}, {r_m32, r32}, DU_DU }, - {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r},{r_m64, r_m64}, DU_DU }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r},{r_m64, r64}, DU_DU }, END_OPCODES() END_MNEMONIC() @@ -420,19 +423,19 @@ #undef DEFINE_ALU_OPCODES // // // -BEGIN_MNEMONIC(ADDSD, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(ADDSD, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x58, _r}, {xmm64, xmm_m64}, DU_U}, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(ADDSS, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(ADDSS, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x58, _r}, {xmm32, xmm_m32}, DU_U}, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CALL, false, false, false, false, U ) +BEGIN_MNEMONIC(CALL, MF_NONE, U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xE8, cd}, {rel32}, U }, {OpcodeInfo::ia32, {0xFF, _2}, {r_m32}, U }, @@ -441,7 +444,7 @@ END_OPCODES() END_MNEMONIC() //TODO: Workaround. Actually, it's D_DU, but Jitrino's CG thinks it's D_U -BEGIN_MNEMONIC(CDQ, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CDQ, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0x99}, {DX, AX}, D_U }, {OpcodeInfo::all, {0x99}, {EDX, EAX}, D_U }, @@ -450,7 +453,7 @@ END_OPCODES() END_MNEMONIC() #define DEFINE_CMOVcc_MNEMONIC( cc ) \ - BEGIN_MNEMONIC(CMOV##cc, false, true, true, false, D_U ) \ + BEGIN_MNEMONIC(CMOV##cc, MF_USES_FLAGS|MF_CONDITIONAL, D_U ) \ BEGIN_OPCODES() \ {OpcodeInfo::all, {Size16, 0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r16, r_m16}, D_U }, \ {OpcodeInfo::all, {0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r32, r_m32}, D_U }, \ @@ -482,14 +485,14 @@ #undef DEFINE_CMOVcc_MNEMONIC *****************************************************************************/ // // double -> float -BEGIN_MNEMONIC(CVTSD2SS, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSD2SS, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x5A, _r}, {xmm32, xmm_m64}, D_U }, END_OPCODES() END_MNEMONIC() // double -> int32 -BEGIN_MNEMONIC(CVTSD2SI, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSD2SI, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x2D, _r}, {r32, xmm_m64}, D_U }, {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2D, _r}, {r64, xmm_m64}, D_U }, @@ -497,7 +500,7 @@ END_OPCODES() END_MNEMONIC() // double [truncated] -> int32 -BEGIN_MNEMONIC(CVTTSD2SI, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTTSD2SI, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x2C, _r}, {r32, xmm_m64}, D_U }, {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2C, _r}, {r64, xmm_m64}, D_U }, @@ -505,14 +508,14 @@ END_OPCODES() END_MNEMONIC() // float -> double -BEGIN_MNEMONIC(CVTSS2SD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSS2SD, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x5A, _r}, {xmm64, xmm_m32}, D_U }, END_OPCODES() END_MNEMONIC() // float -> int32 -BEGIN_MNEMONIC(CVTSS2SI, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSS2SI, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x2D, _r}, {r32, xmm_m32}, D_U}, {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2D, _r}, {r64, xmm_m32}, D_U}, @@ -520,7 +523,7 @@ END_OPCODES() END_MNEMONIC() // float [truncated] -> int32 -BEGIN_MNEMONIC(CVTTSS2SI, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTTSS2SI, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x2C, _r}, {r32, xmm_m32}, D_U}, {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2C, _r}, {r64, xmm_m32}, D_U}, @@ -528,7 +531,7 @@ END_OPCODES() END_MNEMONIC() // int32 -> double -BEGIN_MNEMONIC(CVTSI2SD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSI2SD, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m32}, D_U}, {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m64}, D_U}, @@ -536,7 +539,7 @@ END_OPCODES() END_MNEMONIC() // int32 -> float -BEGIN_MNEMONIC(CVTSI2SS, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTSI2SS, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m32}, D_U}, {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m64}, D_U}, @@ -547,7 +550,7 @@ END_MNEMONIC() // ~ SSE conversions // -BEGIN_MNEMONIC(DEC, true, false, false, false, DU ) +BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU }, @@ -561,14 +564,14 @@ END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(DIVSD, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(DIVSD, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x5E, _r}, {xmm64, xmm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(DIVSS, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(DIVSS, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x5E, _r}, {xmm32, xmm_m32}, DU_U }, END_OPCODES() @@ -578,100 +581,100 @@ END_MNEMONIC() ***** FPU operations ***** ****************************************************************************/ -BEGIN_MNEMONIC(FLDCW, false, false, false, false, U ) +BEGIN_MNEMONIC(FLDCW, MF_NONE, U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, _5}, {m16}, U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FNSTCW, false, false, false, false, D ) +BEGIN_MNEMONIC(FNSTCW, MF_NONE, D) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, _7}, {m16}, D }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FSTSW, false, false, false, false, N ) +BEGIN_MNEMONIC(FSTSW, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9B, 0xDF, 0xE0}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FCHS, false, false, false, false, DU ) +BEGIN_MNEMONIC(FCHS, MF_NONE, DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, 0xE0}, {FP0D}, DU }, {OpcodeInfo::all, {0xD9, 0xE0}, {FP0S}, DU }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FCLEX, false, false, false, false, N ) +BEGIN_MNEMONIC(FCLEX, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9B, 0xDB, 0xE2}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FNCLEX, false, false, false, false, N ) +BEGIN_MNEMONIC(FNCLEX, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xDB, 0xE2}, {}, N }, END_OPCODES() END_MNEMONIC() -//BEGIN_MNEMONIC(FDECSTP, false, false, false, false, N ) +//BEGIN_MNEMONIC(FDECSTP, MF_NONE, N) // BEGIN_OPCODES() // {OpcodeInfo::all, {0xD9, 0xF6}, {}, N }, // END_OPCODES() //END_MNEMONIC() -BEGIN_MNEMONIC(FILD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FILD, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xDF, _5}, {FP0D, m64}, D_U }, END_OPCODES() END_MNEMONIC() -//BEGIN_MNEMONIC(FINCSTP, false, false, false, false, N ) +//BEGIN_MNEMONIC(FINCSTP, MF_NONE, N) // BEGIN_OPCODES() // {OpcodeInfo::all, {0xD9, 0xF7}, {}, N }, // END_OPCODES() //END_MNEMONIC() -BEGIN_MNEMONIC(FIST, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FIST, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xDB, _2}, {m32, FP0S}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FISTP, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FISTP, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xDB, _3}, {m32, FP0S}, D_U }, {OpcodeInfo::all, {0xDF, _7}, {m64, FP0D}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FISTTP, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FISTTP, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xDD, _1}, {m64, FP0D}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FLD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FLD, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, _0}, {FP0S, m32}, D_U }, {OpcodeInfo::all, {0xDD, _0}, {FP0D, m64}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FPREM, false, false, false, false, N ) +BEGIN_MNEMONIC(FPREM, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, 0xF8}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FPREM1, false, false, false, false, N ) +BEGIN_MNEMONIC(FPREM1, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, 0xF5}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FST, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FST, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, _2}, {m32, FP0S}, D_U }, {OpcodeInfo::all, {0xDD, _2}, {m64, FP0D}, D_U }, @@ -683,7 +686,7 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(FSTP, false, false, false, false, D_U ) +BEGIN_MNEMONIC(FSTP, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xD9, _3}, {m32, FP0S}, D_U }, {OpcodeInfo::all, {0xDD, _3}, {m64, FP0D}, D_U }, @@ -699,16 +702,18 @@ END_MNEMONIC() // ~ FPU // -BEGIN_MNEMONIC(IDIV, true, false, false, false, DU_DU_U ) +BEGIN_MNEMONIC(IDIV, MF_AFFECTS_FLAGS, DU_DU_U) BEGIN_OPCODES() +#if !defined(_EM64T_) {OpcodeInfo::all, {0xF6, _7}, {AH, AL, r_m8}, DU_DU_U }, {OpcodeInfo::all, {Size16, 0xF7, _7}, {DX, AX, r_m16}, DU_DU_U }, +#endif {OpcodeInfo::all, {0xF7, _7}, {EDX, EAX, r_m32}, DU_DU_U }, {OpcodeInfo::em64t, {REX_W, 0xF7, _7}, {RDX, RAX, r_m64}, DU_DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(IMUL, true, false, false, false, D_DU_U ) +BEGIN_MNEMONIC(IMUL, MF_AFFECTS_FLAGS, D_DU_U) BEGIN_OPCODES() /*{OpcodeInfo::all, {0xF6, _5}, {AH, AL, r_m8}, D_DU_U }, {OpcodeInfo::all, {Size16, 0xF7, _5}, {DX, AX, r_m16}, D_DU_U }, @@ -729,7 +734,7 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MUL, true, false, false, false, U ) +BEGIN_MNEMONIC(MUL, MF_AFFECTS_FLAGS, U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF6, _4}, {r_m8}, U }, {OpcodeInfo::all, {Size16, 0xF7, _4}, {r_m16}, U }, @@ -738,7 +743,7 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(INC, true, false, false, false, DU ) +BEGIN_MNEMONIC(INC, MF_AFFECTS_FLAGS, DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0xFE, _0}, {r_m8}, DU }, {OpcodeInfo::all, {Size16, 0xFF, _0}, {r_m16}, DU }, @@ -749,17 +754,17 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(INT3, false, false, false, false, N ) +BEGIN_MNEMONIC(INT3, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xCC}, {}, N }, END_OPCODES() END_MNEMONIC() #define DEFINE_Jcc_MNEMONIC( cc ) \ - BEGIN_MNEMONIC(J##cc, false, true, true, false, U ) \ + BEGIN_MNEMONIC(J##cc, MF_USES_FLAGS|MF_CONDITIONAL, U ) \ BEGIN_OPCODES() \ {OpcodeInfo::all, {0x70 + ConditionMnemonic_##cc, cb }, { rel8 }, U }, \ - {OpcodeInfo::ia32, {0x0F, 0x80 + ConditionMnemonic_##cc, cw}, { rel16 }, U }, \ + {OpcodeInfo::ia32, {Size16, 0x0F, 0x80 + ConditionMnemonic_##cc, cw}, { rel16 }, U }, \ {OpcodeInfo::all, {0x0F, 0x80 + ConditionMnemonic_##cc, cd}, { rel32 }, U }, \ END_OPCODES() \ END_MNEMONIC() @@ -785,10 +790,10 @@ DEFINE_Jcc_MNEMONIC(NLE) #undef DEFINE_Jcc_MNEMONIC -BEGIN_MNEMONIC(JMP, false, false, false, false, U ) +BEGIN_MNEMONIC(JMP, MF_NONE, U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xEB, cb}, {rel8}, U }, - {OpcodeInfo::ia32, {0xE9, cw}, {rel16}, U }, + {OpcodeInfo::ia32, {Size16, 0xE9, cw}, {rel16}, U }, {OpcodeInfo::all, {0xE9, cd}, {rel32}, U }, {OpcodeInfo::ia32, {Size16, 0xFF, _4}, {r_m16}, U }, {OpcodeInfo::ia32, {0xFF, _4}, {r_m32}, U }, @@ -796,7 +801,7 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(LEA, false, false, false, false, D_U ) +BEGIN_MNEMONIC(LEA, MF_NONE, D_U ) BEGIN_OPCODES() /* A special case: the LEA instruction itself does not care about size of @@ -811,35 +816,35 @@ BEGIN_OPCODES() {OpcodeInfo::em64t, {0x8D, _r}, {r64, m}, D_U }, */ {OpcodeInfo::all, {0x8D, _r}, {r32, m8}, D_U }, - {OpcodeInfo::em64t, {0x8D, _r}, {r64, m8}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m8}, D_U }, {OpcodeInfo::all, {0x8D, _r}, {r32, m16}, D_U }, - {OpcodeInfo::em64t, {0x8D, _r}, {r64, m16}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m16}, D_U }, {OpcodeInfo::all, {0x8D, _r}, {r32, m32}, D_U }, - {OpcodeInfo::em64t, {0x8D, _r}, {r64, m32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m32}, D_U }, {OpcodeInfo::all, {0x8D, _r}, {r32, m64}, D_U }, - {OpcodeInfo::em64t, {0x8D, _r}, {r64, m64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m64}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(LOOP, true, true, false, false, DU_U) +BEGIN_MNEMONIC(LOOP, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xE2, cb}, {ECX, rel8}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(LOOPE, true, true, false, false, DU_U ) +BEGIN_MNEMONIC(LOOPE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xE1, cb}, {ECX, rel8}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(LOOPNE, true, true, false, false, DU_U ) +BEGIN_MNEMONIC(LOOPNE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xE0, cb}, {ECX, rel8}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOV, false, false, false, false, D_U) +BEGIN_MNEMONIC(MOV, MF_NONE, D_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x88, _r}, {r_m8,r8}, D_U }, @@ -865,14 +870,14 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(XCHG, false, false, false, false, DU_DU ) +BEGIN_MNEMONIC(XCHG, MF_NONE, DU_DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0x87, _r}, {r_m32,r32}, DU_DU }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOVQ, false, false, false, false, D_U ) +BEGIN_MNEMONIC(MOVQ, MF_NONE, D_U ) BEGIN_OPCODES() #ifdef _HAVE_MMX_ {OpcodeInfo::all, {0x0F, 0x6F, _r}, {mm64, mm_m64}, D_U }, @@ -880,6 +885,18 @@ #ifdef _HAVE_MMX_ #endif {OpcodeInfo::all, {0xF3, 0x0F, 0x7E }, {xmm64, xmm_m64}, D_U }, {OpcodeInfo::all, {0x66, 0x0F, 0xD6 }, {xmm_m64, xmm64}, D_U }, +// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r_m64}, D_U }, +// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r_m64, xmm64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r64, xmm64}, D_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(MOVD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x6E, _r}, {xmm32, r_m32}, D_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x7E, _r}, {r_m32, xmm32}, D_U }, END_OPCODES() END_MNEMONIC() @@ -888,31 +905,31 @@ END_MNEMONIC() // #ifdef _HAVE_MMX_ -BEGIN_MNEMONIC(EMMS, false, false, false, false, N ) +BEGIN_MNEMONIC(EMMS, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0x77}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(PADDQ, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(PADDQ, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xD4, _r}, {mm64, mm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(PAND, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(PAND, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xDB, _r}, {mm64, mm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(POR, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(POR, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xEB, _r}, {mm64, mm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(PSUBQ, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(PSUBQ, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xFB, _r}, {mm64, mm_m64}, DU_U }, END_OPCODES() @@ -920,7 +937,7 @@ END_MNEMONIC() #endif // ~_HAVE_MMX_ -BEGIN_MNEMONIC(PXOR, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(PXOR, MF_NONE, DU_U) BEGIN_OPCODES() #ifdef _HAVE_MMX_ {OpcodeInfo::all, {0x0F, 0xEF, _r}, {mm64, mm_m64}, DU_U }, @@ -930,53 +947,55 @@ END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOVSD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(MOVSD, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x10, _r}, {xmm64, xmm_m64}, D_U }, {OpcodeInfo::all, {0xF2, 0x0F, 0x11, _r}, {xmm_m64, xmm64}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOVSS, false, false, false, false, D_U ) +BEGIN_MNEMONIC(MOVSS, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x10, _r}, {xmm32, xmm_m32}, D_U }, {OpcodeInfo::all, {0xF3, 0x0F, 0x11, _r}, {xmm_m32, xmm32}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOVSX, false, false, false, false, D_U ) +BEGIN_MNEMONIC(MOVSX, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {Size16, 0x0F, 0xBE, _r}, {r16, r_m8}, D_U }, {OpcodeInfo::all, {0x0F, 0xBE, _r}, {r32, r_m8}, D_U }, - + {OpcodeInfo::all, {REX_W, 0x0F, 0xBE, _r}, {r64, r_m8}, D_U }, + {OpcodeInfo::all, {0x0F, 0xBF, _r}, {r32, r_m16}, D_U }, {OpcodeInfo::em64t, {REX_W, 0x0F, 0xBF, _r}, {r64, r_m16}, D_U }, + + {OpcodeInfo::em64t, {REX_W, 0x63, _r}, {r64, r_m32}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MOVZX, false, false, false, false, D_U ) +BEGIN_MNEMONIC(MOVZX, MF_NONE, D_U ) BEGIN_OPCODES() {OpcodeInfo::all, {Size16, 0x0F, 0xB6, _r}, {r16, r_m8}, D_U }, {OpcodeInfo::all, {0x0F, 0xB6, _r}, {r32, r_m8}, D_U }, - + {OpcodeInfo::all, {REX_W, 0x0F, 0xB6, _r}, {r64, r_m8}, D_U }, {OpcodeInfo::all, {0x0F, 0xB7, _r}, {r32, r_m16}, D_U }, - {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB7, _r}, {r64, r_m16}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MULSD, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(MULSD, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x59, _r}, {xmm64, xmm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(MULSS, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(MULSS, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x59, _r}, {xmm32, xmm_m32}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(NEG, true, false, false, false, DU ) +BEGIN_MNEMONIC(NEG, MF_AFFECTS_FLAGS, DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF6, _3}, {r_m8}, DU }, @@ -986,13 +1005,13 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(NOP, false, false, false, false, N ) +BEGIN_MNEMONIC(NOP, MF_NONE, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x90}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(NOT, true, false, false, false, DU ) +BEGIN_MNEMONIC(NOT, MF_AFFECTS_FLAGS, DU ) BEGIN_OPCODES() {OpcodeInfo::all, {0xF6, _2}, {r_m8}, DU }, {OpcodeInfo::all, {Size16, 0xF7, _2}, {r_m16}, DU }, @@ -1001,7 +1020,7 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(POP, false, false, false, false, D ) +BEGIN_MNEMONIC(POP, MF_NONE, D) BEGIN_OPCODES() {OpcodeInfo::all, {Size16, 0x8F, _0}, {r_m16}, D }, {OpcodeInfo::ia32, {0x8F, _0}, {r_m32}, D }, @@ -1013,13 +1032,13 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(POPFD, true, false, false, false, N ) +BEGIN_MNEMONIC(POPFD, MF_AFFECTS_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9D}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(PUSH, false, false, false, false, U ) +BEGIN_MNEMONIC(PUSH, MF_NONE, U ) BEGIN_OPCODES() {OpcodeInfo::all, {Size16, 0xFF, _6}, {r_m16}, U }, {OpcodeInfo::ia32, {0xFF, _6}, {r_m32}, U }, @@ -1029,40 +1048,31 @@ BEGIN_OPCODES() {OpcodeInfo::ia32, {0x50|rd }, {r32}, U }, {OpcodeInfo::em64t, {0x50|rd }, {r64}, U }, - {OpcodeInfo::all, {0x6A}, {imm8}, U }, - {OpcodeInfo::all, {0x68}, {imm16}, U }, - {OpcodeInfo::ia32, {0x68}, {imm32}, U }, + {OpcodeInfo::all, {0x6A}, {imm8}, U }, + {OpcodeInfo::all, {Size16, 0x68}, {imm16}, U }, + {OpcodeInfo::ia32, {0x68}, {imm32}, U }, // {OpcodeInfo::em64t, {0x68}, {imm64}, U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(PUSHFD, false, true, false, false, N ) +BEGIN_MNEMONIC(PUSHFD, MF_USES_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9C}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(RET, false, false, false, false, N ) +BEGIN_MNEMONIC(RET, MF_NONE, N) BEGIN_OPCODES() - {OpcodeInfo::all, {0xC3}, {}, N }, - {OpcodeInfo::all, {0xC2, iw}, {imm16}, U }, + {OpcodeInfo::all, {0xC3}, {}, N }, + {OpcodeInfo::all, {0xC2, iw}, {imm16}, U }, END_OPCODES() END_MNEMONIC() -// -// The very special case: actually, there are no instructions 'SETcc rm32' -// (only 'rm8'). The problem is that the Jitrino's InstCodeSelector generates -// such instructions. Changing the selector's bahaviour would be quite -// dangerous thus making this fake record here. -// See also Ia32::Encoder::buildHolder(), where the special case is processed -// is a special way. -// #define DEFINE_SETcc_MNEMONIC( cc ) \ - BEGIN_MNEMONIC(SET##cc, false, true, true, false, D ) \ + BEGIN_MNEMONIC(SET##cc, MF_USES_FLAGS|MF_CONDITIONAL, D) \ BEGIN_OPCODES() \ {OpcodeInfo::all, {0x0F, 0x90 + ConditionMnemonic_##cc}, {r_m8}, D }, \ - {OpcodeInfo::all, {0x0F, 0x90 + ConditionMnemonic_##cc}, {r_m32}, D }, \ END_OPCODES() \ END_MNEMONIC() @@ -1087,7 +1097,7 @@ DEFINE_SETcc_MNEMONIC(NLE) #undef DEFINE_SETcc_MNEMONIC #define DEFINE_SHIFT_MNEMONIC( nam, slash_num ) \ -BEGIN_MNEMONIC(nam, true, false, false, false, DU_U ) \ +BEGIN_MNEMONIC(nam, MF_AFFECTS_FLAGS, DU_U) \ BEGIN_OPCODES()\ /* {OpcodeInfo::all, {0xD0, slash_num}, {r_m8, const_1}, DU_U },*/\ {OpcodeInfo::all, {0xD2, slash_num}, {r_m8, CL}, DU_U },\ @@ -1114,34 +1124,34 @@ DEFINE_SHIFT_MNEMONIC(SHR, _5) DEFINE_SHIFT_MNEMONIC(ROR, _1) #undef DEFINE_SHIFT_MNEMONIC -BEGIN_MNEMONIC(SHLD, true, false, false, false, N ) -// todo: the def/use info is invalid +BEGIN_MNEMONIC(SHLD, MF_AFFECTS_FLAGS, N) +// TODO: the def/use info is worng BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xA5}, {r_m32, r32, CL}, DU_DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SHRD, true, false, false, false, N ) -// todo: the def/use info is invalid +BEGIN_MNEMONIC(SHRD, MF_AFFECTS_FLAGS, N) +// TODO: the def/use info is wrong BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0xAD}, {r_m32, r32, CL}, DU_DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SUBSD, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(SUBSD, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF2, 0x0F, 0x5C, _r}, {xmm64, xmm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SUBSS, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(SUBSS, MF_NONE, DU_U) BEGIN_OPCODES() {OpcodeInfo::all, {0xF3, 0x0F, 0x5C, _r}, {xmm32, xmm_m32}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(TEST, true, false, false, false, U_U ) +BEGIN_MNEMONIC(TEST, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() /* {OpcodeInfo::all, {0xA8, ib}, { AL, imm8}, U_U }, @@ -1164,66 +1174,66 @@ END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(UCOMISD, true, false, false, false, U_U ) +BEGIN_MNEMONIC(UCOMISD, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x66, 0x0F, 0x2E, _r}, {xmm64, xmm_m64}, U_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(UCOMISS, true, false, false, false, U_U ) +BEGIN_MNEMONIC(UCOMISS, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0x2E, _r}, {xmm32, xmm_m32}, U_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(COMISD, true, false, false, false, U_U ) +BEGIN_MNEMONIC(COMISD, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x66, 0x0F, 0x2F, _r}, {xmm64, xmm_m64}, U_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(COMISS, true, false, false, false, U_U ) +BEGIN_MNEMONIC(COMISS, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() {OpcodeInfo::all, {0x0F, 0x2F, _r}, {xmm32, xmm_m32}, U_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(XORPD, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(XORPD, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() //Note: they're actually 128 bits {OpcodeInfo::all, {0x66, 0x0F, 0x57, _r}, {xmm64, xmm_m64}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(XORPS, false, false, false, false, DU_U ) +BEGIN_MNEMONIC(XORPS, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U) BEGIN_OPCODES() //Note: they're actually 128 bits - {OpcodeInfo::all, {0x0F, 0x57, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x0F, 0x57, _r}, {xmm32, xmm_m32}, DU_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CVTDQ2PD, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTDQ2PD, MF_NONE, D_U ) BEGIN_OPCODES() //Note: they're actually 128 bits {OpcodeInfo::all, {0xF3, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CVTDQ2PS, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTDQ2PS, MF_NONE, D_U ) BEGIN_OPCODES() //Note: they're actually 128 bits {OpcodeInfo::all, {0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CVTTPD2DQ, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTTPD2DQ, MF_NONE, D_U ) BEGIN_OPCODES() //Note: they're actually 128 bits {OpcodeInfo::all, {0x66, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CVTTPS2DQ, false, false, false, false, D_U ) +BEGIN_MNEMONIC(CVTTPS2DQ, MF_NONE, D_U ) BEGIN_OPCODES() //Note: they're actually 128 bits {OpcodeInfo::all, {0xF3, 0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U }, @@ -1233,19 +1243,19 @@ END_MNEMONIC() // // String operations // -BEGIN_MNEMONIC(STD, true, false, false, false, N ) +BEGIN_MNEMONIC(STD, MF_AFFECTS_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xFD}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(CLD, true, false, false, false, N ) +BEGIN_MNEMONIC(CLD, MF_AFFECTS_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0xFC}, {}, N }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(SCAS, true, false, false, false, N ) +BEGIN_MNEMONIC(SCAS, MF_AFFECTS_FLAGS, N) // to be symmetric, this mnemonic must have either m32 or RegName_EAX // but as long, as Jitrino's CG does not use the mnemonic, leaving it // in its natural form @@ -1254,16 +1264,14 @@ BEGIN_OPCODES() END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(STOS, true, false, false, false, N) -// to be symmetric, this mnemonic must have either m32 or RegName_EAX -// but as long, as Jitrino's CG does not use the mnemonic, leaving it -// in its natural form +BEGIN_MNEMONIC(STOS, MF_AFFECTS_FLAGS, U_U) BEGIN_OPCODES() - {OpcodeInfo::all, {0xAB}, {}, N }, + {OpcodeInfo::all, {0xAB}, {EDI, EAX}, U_U }, + {OpcodeInfo::em64t, {REX_W, 0xAB}, {RDI, RAX}, U_U }, END_OPCODES() END_MNEMONIC() -BEGIN_MNEMONIC(WAIT, true, false, false, false, N ) +BEGIN_MNEMONIC(WAIT, MF_AFFECTS_FLAGS, N) BEGIN_OPCODES() {OpcodeInfo::all, {0x9B}, {}, N }, END_OPCODES() @@ -1274,8 +1282,12 @@ END_MNEMONIC() // }; // ~masterEncodingTable[] +ENCODER_NAMESPACE_END #include <algorithm> + +ENCODER_NAMESPACE_START + static bool mnemonic_info_comparator(const MnemonicInfo& one, const MnemonicInfo& two) { @@ -1307,10 +1319,7 @@ void EncoderBase::buildMnemonicDesc(cons { MnemonicDesc& mdesc = mnemonics[minfo->mn]; mdesc.mn = minfo->mn; - mdesc.affectsFlags = minfo->affectsFlags; - mdesc.usesFlags = minfo->usesFlags; - mdesc.conditional = minfo->conditional; - mdesc.symmetric = minfo->symmetric; + mdesc.flags = minfo->flags; mdesc.roles = minfo->roles; mdesc.name = minfo->name; @@ -1329,7 +1338,6 @@ void EncoderBase::buildMnemonicDesc(cons break; } odesc.last = 0; - odesc.rex = 0; #ifdef _EM64T_ if (oinfo.platf == OpcodeInfo::ia32) { continue; } #else @@ -1339,25 +1347,21 @@ #endif // fill out opcodes // unsigned j = 0; -#ifdef _EM64T_ - if (oinfo.opcode[0] == REX_W) { - odesc.rex = oinfo.opcode[0]; - ++j; - } - else { - odesc.opcode[0] = 0; - } -#endif odesc.opcode_len = 0; for(; oinfo.opcode[j]; j++) { unsigned opcod = oinfo.opcode[j]; unsigned kind = opcod&OpcodeByteKind_KindMask; - if(kind != 0 && kind != OpcodeByteKind_ZeroOpcodeByte) { + if (kind == OpcodeByteKind_REX_W) { + odesc.opcode[odesc.opcode_len++] = (unsigned char)0x48; + continue; + } + else if(kind != 0 && kind != OpcodeByteKind_ZeroOpcodeByte) { break; } unsigned lowByte = (opcod & OpcodeByteKind_OpcodeMask); odesc.opcode[odesc.opcode_len++] = (unsigned char)lowByte; } + assert(odesc.opcode_len<5); odesc.aux0 = odesc.aux1 = 0; if (oinfo.opcode[j] != 0) { odesc.aux0 = oinfo.opcode[j]; @@ -1394,6 +1398,7 @@ #endif if (sz==OpndSize_8) {imm_encode = ib; coff_encode=cb; } else if (sz==OpndSize_16) {imm_encode = iw; coff_encode=cw;} else if (sz==OpndSize_32) {imm_encode = id; coff_encode=cd; } + else if (sz==OpndSize_64) {imm_encode = io; coff_encode=0xCC; } else { assert(false); imm_encode=0xCC; coff_encode=0xCC; } if (odesc.aux1 == 0) { if (odesc.aux0==0) { @@ -1475,3 +1480,5 @@ #endif ++oindex; } } + +ENCODER_NAMESPACE_END diff --git vm/port/src/encoder/ia32_em64t/encoder.cpp vm/port/src/encoder/ia32_em64t/encoder.cpp index 0befc15..9f79ad6 100644 --- vm/port/src/encoder/ia32_em64t/encoder.cpp +++ vm/port/src/encoder/ia32_em64t/encoder.cpp @@ -130,8 +130,8 @@ const Mnemonic map_of_alu_opcode_2_mnemo const Mnemonic map_of_shift_opcode_2_mnemonic[] = { //shld_opc, shrd_opc, - // shl_opc, shr_opc, sar_opc, ror_opc, max_shift_opcode=6, - //n_shift = 6 + // shl_opc, shr_opc, sar_opc, ror_opc, max_shift_opcode=6, + // n_shift = 6 Mnemonic_SHLD, Mnemonic_SHRD, Mnemonic_SHL, Mnemonic_SHR, Mnemonic_SAR, Mnemonic_ROR }; diff --git vm/port/src/encoder/ia32_em64t/encoder.h vm/port/src/encoder/ia32_em64t/encoder.h index 728424a..731d342 100644 --- vm/port/src/encoder/ia32_em64t/encoder.h +++ vm/port/src/encoder/ia32_em64t/encoder.h @@ -313,7 +313,7 @@ public: M_Opnd(int32 disp, Reg_No rbase, Reg_No rindex, unsigned scale): RM_Opnd(Mem), m_disp(disp), m_scale(scale), m_index(rindex), m_base(rbase) {} M_Opnd(const M_Opnd & that) : RM_Opnd(Mem), - m_disp(that.m_disp.get_value()), m_scale(that.m_scale.get_value()), + m_disp((int)that.m_disp.get_value()), m_scale((int)that.m_scale.get_value()), m_index(that.m_index.reg_no()), m_base(that.m_base.reg_no()) {} // @@ -477,6 +477,11 @@ ENCODER_DECLARE_EXPORT char * mov(char * ENCODER_DECLARE_EXPORT char * movsx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf); ENCODER_DECLARE_EXPORT char * movzx( char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz = size_platf); +ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm); +ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm); +ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm); +ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm); + // sse mov ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl); ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd & mem, const XMM_Opnd & xmm, bool dbl); diff --git vm/port/src/encoder/ia32_em64t/encoder.inl vm/port/src/encoder/ia32_em64t/encoder.inl index 40bdc4b..f161494 100644 --- vm/port/src/encoder/ia32_em64t/encoder.inl +++ vm/port/src/encoder/ia32_em64t/encoder.inl @@ -1,6 +1,21 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @author Alexander V. Astapchuk - * @version $Revision: 1.1.2.3.4.1 $ + * @version $Revision$ */ #include <stdio.h> #include <assert.h> @@ -36,10 +51,14 @@ inline static Mnemonic map_shift(Shift_O return map_of_shift_opcode_2_mnemonic[shc]; } -inline static bool fit8( int64 val ) { +inline static bool fit8(int64 val) { return (CHAR_MIN <= val) && (val <= CHAR_MAX); } +inline static bool fit32(int64 val) { + return val == (int64)(int32)val; +} + inline static void add_r(EncoderBase::Operands & args, const R_Opnd & r, Opnd_Size sz) { RegName reg = map_reg(r.reg_no()); if (sz != n_size) { @@ -293,6 +312,34 @@ ENCODER_DECLARE_EXPORT char * mov(char * return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args); } +ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) { + EncoderBase::Operands args; + add_rm(args, rm, size_32); + add_xmm(args, xmm, false); + return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args); +} + +ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) { + EncoderBase::Operands args; + add_xmm(args, xmm, false); + add_rm(args, rm, size_32); + return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args); +} + +ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) { + EncoderBase::Operands args; + add_rm(args, rm, size_64); + add_xmm(args, xmm, true); + return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args); +} + +ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) { + EncoderBase::Operands args; + add_xmm(args, xmm, true); + add_rm(args, rm, size_64); + return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args); +} + ENCODER_DECLARE_EXPORT char * movsx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) { EncoderBase::Operands args; add_r(args, r, n_size); @@ -303,6 +350,9 @@ ENCODER_DECLARE_EXPORT char * movsx(char ENCODER_DECLARE_EXPORT char * movzx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) { EncoderBase::Operands args; add_r(args, r, n_size); + // movzx r64, r/m32 is not available on em64t + // mov r32, r/m32 should zero out upper bytes + assert(sz <= size_16); add_rm(args, rm, sz); return (char*)EncoderBase::encode(stream, Mnemonic_MOVZX, args); } @@ -510,6 +560,7 @@ ENCODER_DECLARE_EXPORT char * wait(char ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm) { EncoderBase::Operands args; assert(imm.get_size() == size_8); + args.add(RegName_ECX); add_imm(args, imm); return (char*)EncoderBase::encode(stream, Mnemonic_LOOP, args); } @@ -535,10 +586,28 @@ ENCODER_DECLARE_EXPORT char * jump(char return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args); } +/** + * @note On EM64T: if target lies beyond 2G (does not fit into 32 bit + * offset) then generates indirect jump using RAX (whose content is + * destroyed). + */ ENCODER_DECLARE_EXPORT char * jump(char * stream, char * target) { #ifdef _EM64T_ -//#error "unimplemented functionality !" - return NULL; + int64 offset = target - stream; + if (fit8(offset)) { + // sub 2 bytes for the short version + offset -= 2; + // use 8-bit signed relative form + return jump8(stream, Imm_Opnd(size_8, offset)); + } else if (fit32(offset)) { + // sub 5 bytes for the long version + offset -= 5; + // use 32-bit signed relative form + return jump32(stream, Imm_Opnd(size_32, offset)); + } + // need to use absolute indirect jump + stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64); + return jump(stream, rax_opnd, size_64); #else int32 offset = target - stream; if (fit8(offset)) { @@ -554,22 +623,11 @@ #else #endif } -/* -ENCODER_DECLARE_EXPORT char *jump(char * stream, int32 disp) { - // sub 2 bytes for the short version - disp -= 2; - if (fit8( disp )) { - // use 8-bit signed relative form - return jump8(stream, Imm_Opnd(size_8, disp)); - } - // use 32-bit signed relative form - disp -= 3; // 3 more bytes for the long version - return jump32(stream, Imm_Opnd(size_32, disp)); -} -*/ - // branch -ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cond, const Imm_Opnd & imm, InstrPrefix pref) { +ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cond, + const Imm_Opnd & imm, + InstrPrefix pref) +{ if (pref != no_prefix) { assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix); stream = prefix(stream, pref); @@ -581,7 +639,10 @@ ENCODER_DECLARE_EXPORT char * branch8(ch return (char*)EncoderBase::encode(stream, m, args); } -ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cond, const Imm_Opnd & imm, InstrPrefix pref) { +ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cond, + const Imm_Opnd & imm, + InstrPrefix pref) +{ if (pref != no_prefix) { assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix); stream = prefix(stream, pref); @@ -602,35 +663,41 @@ return branch8(stream, cc, Imm_Opnd(size } return branch32(stream, cc, Imm_Opnd(size_32, (int)offset), is_signed); } - -ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, int32 disp, InstrPrefix prefix) { -// sub 2 bytes for the short version -disp -= 2; -if (fit8(disp)) { -return branch8(stream, cc, Imm_Opnd(size_8, disp), prefix); -} -disp -= 4; // 4 more bytes for the long version -return branch32(stream, cc, Imm_Opnd(size_32, disp), prefix); -} */ // call -ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm) { +ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm) +{ EncoderBase::Operands args; add_imm(args, imm); return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args); } -ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm, Opnd_Size sz) { +ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm, + Opnd_Size sz) +{ EncoderBase::Operands args; add_rm(args, rm, sz); return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args); } -ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target) { +/** +* @note On EM64T: if target lies beyond 2G (does not fit into 32 bit +* offset) then generates indirect jump using RAX (whose content is +* destroyed). +*/ +ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target) +{ #ifdef _EM64T_ -//#error "unimplemented functionality !" - return NULL; + int64 offset = target - stream; + if (fit32(offset)) { + offset -= 5; // sub 5 bytes for this instruction + Imm_Opnd imm(size_32, offset); + return call(stream, imm); + } + // need to use absolute indirect call + stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64); + return call(stream, rax_opnd, size_64); #else int32 offset = target - stream; offset -= 5; // sub 5 bytes for this instruction @@ -640,12 +707,14 @@ #endif } // return instruction -ENCODER_DECLARE_EXPORT char * ret(char * stream) { +ENCODER_DECLARE_EXPORT char * ret(char * stream) +{ EncoderBase::Operands args; return (char*)EncoderBase::encode(stream, Mnemonic_RET, args); } -ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm) { +ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm) +{ EncoderBase::Operands args; // TheManual says imm can be 16-bit only //assert(imm.get_size() <= size_16); @@ -653,14 +722,16 @@ ENCODER_DECLARE_EXPORT char * ret(char * return (char*)EncoderBase::encode(stream, Mnemonic_RET, args); } -ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop) { +ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop) +{ // TheManual says it can only be imm16 EncoderBase::Operands args(EncoderBase::Operand(OpndSize_16, pop)); return (char*)EncoderBase::encode(stream, Mnemonic_RET, args); } // floating-point instructions -ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m, bool is_double) { +ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m, + bool is_double) { EncoderBase::Operands args; // a fake FP register as operand add_fp(args, 0, is_double); @@ -668,7 +739,9 @@ ENCODER_DECLARE_EXPORT char * fld(char * return (char*)EncoderBase::encode(stream, Mnemonic_FLD, args); } -ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem, bool is_long, bool pop_stk) { +ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem, + bool is_long, bool pop_stk) +{ EncoderBase::Operands args; if (pop_stk) { add_m(args, mem, is_long ? size_64 : size_32); @@ -683,18 +756,25 @@ ENCODER_DECLARE_EXPORT char * fist(char return (char*)EncoderBase::encode(stream, Mnemonic_FIST, args); } -ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m, bool is_double, bool pop_stk) { +ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m, + bool is_double, bool pop_stk) +{ EncoderBase::Operands args; add_m(args, m, is_double ? size_64 : size_32); // a fake FP register as operand add_fp(args, 0, is_double); - return (char*)EncoderBase::encode(stream, pop_stk ? Mnemonic_FSTP : Mnemonic_FST, args); + return (char*)EncoderBase::encode(stream, + pop_stk ? Mnemonic_FSTP : Mnemonic_FST, + args); } -ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk) { +ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk) +{ EncoderBase::Operands args; add_fp(args, i, true); - return (char*)EncoderBase::encode(stream, pop_stk ? Mnemonic_FSTP : Mnemonic_FST, args); + return (char*)EncoderBase::encode(stream, + pop_stk ? Mnemonic_FSTP : Mnemonic_FST, + args); } ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem) { @@ -709,18 +789,23 @@ ENCODER_DECLARE_EXPORT char * fnstcw(cha return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, args); } -ENCODER_DECLARE_EXPORT char * fnstsw(char * stream) { - return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, EncoderBase::Operands()); +ENCODER_DECLARE_EXPORT char * fnstsw(char * stream) +{ + return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, + EncoderBase::Operands()); } // string operations ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set) { EncoderBase::Operands args; - return (char*)EncoderBase::encode(stream, set ? Mnemonic_STD : Mnemonic_CLD, args); + return (char*)EncoderBase::encode(stream, + set ? Mnemonic_STD : Mnemonic_CLD, + args); } -ENCODER_DECLARE_EXPORT char * scas( char * stream, unsigned char prefix ) { - EncoderBase::Operands args; +ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix) +{ + EncoderBase::Operands args; if (prefix != no_prefix) { assert(prefix == prefix_repnz || prefix == prefix_repz); *stream = prefix; @@ -729,7 +814,8 @@ ENCODER_DECLARE_EXPORT char * scas( char return (char*)EncoderBase::encode(stream, Mnemonic_SCAS, args); } -ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix) { +ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix) +{ if (prefix != no_prefix) { assert(prefix == prefix_rep); *stream = prefix; @@ -743,9 +829,11 @@ ENCODER_DECLARE_EXPORT char * stos(char // Intrinsic FP math functions ENCODER_DECLARE_EXPORT char * fprem(char * stream) { - return (char*)EncoderBase::encode(stream, Mnemonic_FPREM, EncoderBase::Operands()); + return (char*)EncoderBase::encode(stream, Mnemonic_FPREM, + EncoderBase::Operands()); } ENCODER_DECLARE_EXPORT char * fprem1(char * stream) { - return (char*)EncoderBase::encode(stream, Mnemonic_FPREM1, EncoderBase::Operands()); + return (char*)EncoderBase::encode(stream, Mnemonic_FPREM1, + EncoderBase::Operands()); } diff --git vm/port/src/lil/em64t/pim/include/lil_code_generator_em64t.h vm/port/src/lil/em64t/pim/include/lil_code_generator_em64t.h index 287b664..e6a2b67 100644 --- vm/port/src/lil/em64t/pim/include/lil_code_generator_em64t.h +++ vm/port/src/lil/em64t/pim/include/lil_code_generator_em64t.h @@ -13,11 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ + * @version $Revision$ */ +/** + * Stack frame layout created by LIL CG on EM64T + * + * |--------------------------| + * | Extra inputs | + * |--------------------------| <--- previouse stack frame bottom + * | Return ip | + * |==========================| <--- current stack frame top + * | M2N frame | callee saved | + * |--------------------------| + * | GR inputs save area | + * |--------------------------| + * | FR inputs save area | + * |--------------------------| + * | Dynamicly allocated area | + * | (includes stack padding) | + * |--------------------------| + * | Extra outputs | + * |==========================| <--- current stack frame bottom + * + * Note: + * EM64T architecture requires stack frame bottom address + * to be aligned on 16 byte boundary (rsp % 16 == 0) + * + * Register usage: + * r12-r15 are used for lil local variables (l0-l3) + * r10-r11 are used for lil standard places (sp0-sp1) + */ #ifndef _LIL_CODE_GENERATOR_EM64T_ #define _LIL_CODE_GENERATOR_EM64T_ @@ -75,7 +104,7 @@ public: static const unsigned GR_SIZE = 8; // size of FR in bytes // TODO: Think about using FR_STACK_SIZE - static const unsigned FR_SIZE = 16; + static const unsigned FR_SIZE = 8; // offsets for the REG_MAP array static const unsigned STD_PLACES_OFFSET = 0; @@ -91,9 +120,9 @@ public: private: - LilCodeStub * cs; // the code stub - tl::MemoryPool & mem; // a memory manager - LilInstructionIterator iter; // instruction iterator + LilCodeStub * cs; // the code stub + tl::MemoryPool & mem; // a memory manager + LilInstructionIterator iter; // instruction iterator unsigned n_inputs; // total number of inputs unsigned n_gr_inputs; // total number of GRs reserved for inputs @@ -103,23 +132,22 @@ private: unsigned n_gr_outputs; // total number of GRs reserved for outputs unsigned n_fr_outputs; // total number of FRs reserved for outputs + unsigned stk_m2n_size; // size reserved for the m2n frame unsigned stk_input_gr_save_size; // size reserved for saving GR inputs unsigned stk_input_fr_save_size; // size reserved for saving FR inputs - unsigned stk_alloc_size; // size of allocatable memory on the stack - unsigned stk_m2n_size; // size reserved for the m2n frame - unsigned stk_output_size; // bytes needed for outgoing params on the stack - unsigned stk_size; // total size of the memory stack frame (in bytes) + unsigned stk_alloc_size; // size of allocatable memory on the stack + unsigned stk_output_size; // bytes needed for outgoing params on the stack + unsigned stk_size; // total size of the memory stack frame (in bytes) - Method_Handle m2n_method; // method handle of the m2n frame - frame_type m2n_frame_type; // m2n frame type + Method_Handle m2n_method; // method handle of the m2n frame + frame_type m2n_frame_type; // m2n frame type - bool m2n_handles; // true if m2n contains local handles - bool does_normal_calls; // true if the stub contains "normal" calls - bool does_tail_calls; // true if the stub contains tail calls + bool m2n_handles; // true if m2n contains local handles + bool does_normal_calls; // true if the stub contains "normal" calls + bool does_tail_calls; // true if the stub contains tail calls bool calls_unmanaged_code; // true if the stub calls calls code with a calling convention other than managed - bool has_m2n; // true if the stub contains push_m2n/pop_m2n instructions - bool save_inputs; // true if inputs are accessed after a normal call - bool uses_returns; // true if return value is ever accessed + bool has_m2n; // true if the stub contains push_m2n/pop_m2n instructions + bool save_inputs; // true if inputs are accessed after a normal call public: @@ -166,7 +194,7 @@ public: /** * an association between register number and index in the REG_MAP array */ - static const unsigned get_index_in_map(const Reg_No reg) { + static unsigned get_index_in_map(const Reg_No reg) { static const unsigned INDEX_MAP[] = { // rax_reg, rbx_reg, rcx_reg, GR_RETURNS_OFFSET, GR_LOCALS_OFFSET + 5, GR_OUTPUTS_OFFSET + 3, @@ -252,13 +280,6 @@ public: } /** - * if returns are ever accessed - */ - bool is_uses_returns() const { - return uses_returns; - } - - /** * true if type represents floating point value */ bool is_fp_type(LilType t) const { @@ -286,6 +307,11 @@ public: return m2n_handles; } + // returns the offset of the start of the m2n frame + unsigned get_m2n_offset() const { + return get_input_gr_save_offset() + stk_input_gr_save_size; + } + // returns the offset of the start of the gr input register save space unsigned get_input_gr_save_offset() const { return get_input_fr_save_offset() + stk_input_fr_save_size; @@ -298,11 +324,6 @@ public: // returns the offset of the first "allocatable" byte unsigned get_alloc_start_offset() const { - return get_m2n_offset() + stk_m2n_size; - } - - // returns the offset of the start of the m2n frame - unsigned get_m2n_offset() const { return get_output_offset() + stk_output_size; } @@ -354,7 +375,7 @@ private: // arbitrary stubs should not access inputs assert(!lil_sig_is_arbitrary(lil_cs_get_sig(cs))); // check if we use inputs after normal call - if (does_normal_calls && !lvalue) { + if (does_normal_calls) { save_inputs = true; } break; @@ -363,11 +384,6 @@ private: save_inputs = true; } break; - case LVK_Ret: - if (!lvalue) { - uses_returns = true; - } - break; default:; } } @@ -511,6 +527,10 @@ private: void in2out(LilSig * sig) { assert(!lil_sig_is_arbitrary(lil_cs_get_sig(cs))); + // check if we need to save inputs + if (does_normal_calls) { + save_inputs = true; + } out(sig); } @@ -561,25 +581,25 @@ public: LcgEM64TLocKind kind; int64 addr; // register number or SP-relative offset - LcgEM64TLoc(LcgEM64TLocKind k, int64 a): kind(k), addr(a) {}\ + LcgEM64TLoc(LcgEM64TLocKind k, int64 a): kind(k), addr(a) {} - void * operator new(size_t sz, tl::MemoryPool & m) { - return m.alloc(sz); - } - - void operator delete (void * p, tl::MemoryPool & m) {} - - bool operator==(const LcgEM64TLoc & loc) { - return (kind == loc.kind && addr == loc.addr); - } - - bool operator!=(const LcgEM64TLoc& loc) { - return (kind != loc.kind || addr != loc.addr); - } + bool operator==(const LcgEM64TLoc & loc) const { + return (kind == loc.kind && addr == loc.addr); + } + + bool operator!=(const LcgEM64TLoc & loc) { + return (kind != loc.kind || addr != loc.addr); + } + void * operator new(size_t sz, tl::MemoryPool & m) { + return m.alloc(sz); + } + + void operator delete (void * p, tl::MemoryPool & m) {} + private: LcgEM64TLoc(LcgEM64TLoc &); // disable copying - LcgEM64TLoc &operator=(LcgEM64TLoc &); // disable copying + LcgEM64TLoc & operator=(LcgEM64TLoc &); // disable copying }; class LilCodeGeneratorEM64T : public LilCodeGenerator { @@ -588,7 +608,7 @@ class LilCodeGeneratorEM64T : public Lil LilCodeGeneratorEM64T(); protected: - NativeCodePtr compile_main(LilCodeStub* , size_t*, const char*, bool); + NativeCodePtr compile_main(LilCodeStub* , size_t*); }; #endif // _LIL_CODE_GENERATOR_EM64T_ diff --git vm/port/src/lil/em64t/pim/lil_code_generator_em64t.cpp vm/port/src/lil/em64t/pim/lil_code_generator_em64t.cpp index 20bf488..9a9a0b7 100644 --- vm/port/src/lil/em64t/pim/lil_code_generator_em64t.cpp +++ vm/port/src/lil/em64t/pim/lil_code_generator_em64t.cpp @@ -65,8 +65,6 @@ LcgEM64TContext::LcgEM64TContext(LilCode calls_unmanaged_code = false; has_m2n = false; save_inputs = false; - uses_returns = false; - /* 2) SCAN THE CODE STUB FOR THE INFORMATION */ @@ -100,7 +98,7 @@ LcgEM64TContext::LcgEM64TContext(LilCode /* 4) INITILIZE STACK INFORMATION */ if (has_m2n) { - stk_m2n_size = get_size_of_m2n(); + stk_m2n_size = m2n_get_size(); } else { // preserve space for callee-saves registers stk_m2n_size = lil_cs_get_max_locals(stub) * GR_SIZE; @@ -113,21 +111,26 @@ LcgEM64TContext::LcgEM64TContext(LilCode stk_input_fr_save_size = n_fr_inputs * FR_SIZE; } - // stk_alloc_size & stk_output_size has been initialized during phase 3) - // so just align - stk_alloc_size = align_16(stk_alloc_size); - stk_output_size = align_16(stk_output_size); - - // determine the size of the stack frame stk_size = + stk_m2n_size + // memory for m2n frame stk_input_gr_save_size + // GR input spill space stk_input_fr_save_size + // FR input spill space - stk_alloc_size + // memory for dynamic allocation - stk_m2n_size + // memory for m2n frame + stk_alloc_size + // memory for dynamic allocation stk_output_size; // outputs on the stack + + // allign stack + if (stk_size % 16 == 0) { + stk_size += 8; + stk_alloc_size +=8; + } } +/** + * Implementation notes: + * 1) Current implementation doesn't correctly processes back branches when + * input arguments are accessed + */ class LcgEM64TCodeGen: public LilInstructionVisitor { static const size_t MAX_CODE_LENGTH = 1024; // maximum length of the generated code @@ -149,8 +152,6 @@ class LcgEM64TCodeGen: public LilInstruc const LcgEM64TLoc * rsp_loc; // location denoting rsp register bool take_inputs_from_stack; // true if inputs were preserved on the stack // and should be taken from that location - uint32 current_rsp_offset; // number of bytes to the current position of rsp from - // the bottom of activation frame unsigned current_alloc; // keeps track of memory allocation private: @@ -172,7 +173,7 @@ private: // registers in the following order: // ret, std0, std1, out0, out1, out2, out3, out4, out5 unsigned cur_tmp_reg = 0; - if (!context.is_uses_returns()) { + if (lil_ic_get_ret_type(ic) == LT_Void) { if (cur_tmp_reg == get_num_used_reg()) { _reg_no = context.get_reg_from_map(LcgEM64TContext::GR_RETURNS_OFFSET).reg_no(); // should be rax ++get_num_used_reg(); @@ -251,9 +252,9 @@ private: /* assert(n < context.get_num_fr_locals()); if (does_normal_calls) { - return new(mem) LcgEM64TLoc(LLK_FStk, context.get_local_fr_offset() + n * FR_SIZE); + return new(mem) LcgEM64TLoc(LLK_FStk, context.get_local_fr_offset() + n * FR_SIZE); else { - return new(mem) LcgEM64TLoc(LLK_Fr, LcgEM64TContext::FR_LOCALS_OFFSET + n); + return new(mem) LcgEM64TLoc(LLK_Fr, LcgEM64TContext::FR_LOCALS_OFFSET + n); } */ } @@ -300,16 +301,12 @@ #endif LilType t; unsigned fp_param_cnt = 0; unsigned gp_param_cnt = 0; - unsigned fp_param_size = 0; - unsigned gp_param_size = 0; for (unsigned i = 0; i < n; i++) { t = lil_sig_get_arg_type(lil_cs_get_sig(cs), i); if (context.is_fp_type(t)) { ++fp_param_cnt; - fp_param_size += get_num_bytes_on_stack(t); } else { ++gp_param_cnt; - gp_param_size += get_num_bytes_on_stack(t); } } @@ -320,8 +317,8 @@ #endif if (fp_param_cnt < LcgEM64TContext::MAX_FR_OUTPUTS) { if (take_inputs_from_stack) { // compute rsp-relative offset of the bottom of FR save area - int32 offset = context.get_input_fr_save_offset() + - n * LcgEM64TContext::FR_SIZE - current_rsp_offset; + int32 offset = context.get_input_fr_save_offset() + + fp_param_cnt * LcgEM64TContext::FR_SIZE; return new(mem) LcgEM64TLoc(LLK_FStk, offset); } else { return new(mem) LcgEM64TLoc(LLK_Fr, @@ -335,19 +332,19 @@ #endif ? (fp_param_cnt - LcgEM64TContext::MAX_FR_OUTPUTS) * LcgEM64TContext::FR_SIZE : 0; // compute rsp-relative offset of the top of the activation frame - int32 offset = context.get_stk_size() - current_rsp_offset; + int32 offset = context.get_stk_size(); // skip rip offset += LcgEM64TContext::GR_SIZE; // skip size allocated for preceding inputs offset += gp_on_stack + fp_on_stack ; return new(mem) LcgEM64TLoc(LLK_FStk, offset); } - } else { + } else { // if (context.is_fp_type(t)) if (gp_param_cnt < LcgEM64TContext::MAX_GR_OUTPUTS) { if (take_inputs_from_stack) { // compute rsp-relative offset of the bottom of GR save area int32 offset = context.get_input_gr_save_offset() + - n * LcgEM64TContext::GR_SIZE - current_rsp_offset; + gp_param_cnt * LcgEM64TContext::GR_SIZE; return new(mem) LcgEM64TLoc(LLK_GStk, offset); } else { return new(mem) LcgEM64TLoc(LLK_Gr, @@ -361,7 +358,7 @@ #endif ? (fp_param_cnt - LcgEM64TContext::MAX_FR_OUTPUTS) * LcgEM64TContext::FR_SIZE : 0; // compute rsp-relative offset of the top of the activation frame - int32 offset = context.get_stk_size() - current_rsp_offset; + int32 offset = context.get_stk_size(); // skip rip offset += LcgEM64TContext::GR_SIZE; // skip size allocated for preceding inputs @@ -379,16 +376,12 @@ #endif LilType t; unsigned fp_param_cnt = 0; unsigned gp_param_cnt = 0; - unsigned fp_param_size = 0; - unsigned gp_param_size = 0; for (unsigned i = 0; i < n; i++) { t = lil_sig_get_arg_type(out_sig, i); if (context.is_fp_type(t)) { ++fp_param_cnt; - gp_param_size += get_num_bytes_on_stack(t); } else { ++gp_param_cnt; - fp_param_size += get_num_bytes_on_stack(t); } } @@ -406,7 +399,7 @@ #endif unsigned fp_on_stack = fp_param_cnt > LcgEM64TContext::MAX_FR_OUTPUTS ? (fp_param_cnt - LcgEM64TContext::MAX_FR_OUTPUTS) * LcgEM64TContext::FR_SIZE : 0; - int32 offset = gp_on_stack + fp_on_stack - current_rsp_offset; + int32 offset = gp_on_stack + fp_on_stack; return new(mem) LcgEM64TLoc(LLK_FStk, offset); } } else { @@ -420,7 +413,7 @@ #endif unsigned fp_on_stack = fp_param_cnt > LcgEM64TContext::MAX_FR_OUTPUTS ? (fp_param_cnt - LcgEM64TContext::MAX_FR_OUTPUTS) * LcgEM64TContext::FR_SIZE : 0; - int32 offset = gp_on_stack + fp_on_stack - current_rsp_offset; + int32 offset = gp_on_stack + fp_on_stack; return new(mem) LcgEM64TLoc(LLK_GStk, offset); } } @@ -456,15 +449,18 @@ #endif return get_output(index, out_sig); } case LVK_Local: { - LilType t = is_lvalue - ? lil_instruction_get_dest_type(cs, inst, ic) - : lil_ic_get_local_type(ic, index); - return context.is_fp_type(t) ? get_fp_local(index) : get_gp_local(index); + //LilType t = is_lvalue + // ? lil_instruction_get_dest_type(cs, inst, ic) + // : lil_ic_get_local_type(ic, index); + //return context.is_fp_type(t) ? get_fp_local(index) : get_gp_local(index); + // no support for fp locals + return get_gp_local(index); } case LVK_Ret: { - LilType t = is_lvalue - ? lil_instruction_get_dest_type(cs, inst, ic) - : lil_ic_get_ret_type(ic); + //LilType t = is_lvalue + // ? lil_instruction_get_dest_type(cs, inst, ic) + // : lil_ic_get_ret_type(ic); + LilType t = lil_ic_get_ret_type(ic); return context.is_fp_type(t) ? new(mem) LcgEM64TLoc(LLK_Fr, LcgEM64TContext::FR_RETURNS_OFFSET) : new(mem) LcgEM64TLoc(LLK_Gr, LcgEM64TContext::GR_RETURNS_OFFSET); @@ -524,7 +520,6 @@ #endif inline void adjust_stack_pointer(int32 offset) { if (offset != 0) { buf = alu(buf, add_opc, rsp_opnd, get_imm_opnd(offset), size_64); - current_rsp_offset += offset; } } @@ -536,45 +531,57 @@ #endif // move between two register or stack locations void move_rm(const LcgEM64TLoc* dest, const LcgEM64TLoc* src) { - if (dest == src) { + if (*dest == *src) { return; // nothing to be done } if (dest->kind == LLK_Gr || dest->kind == LLK_GStk) { - assert(src->kind == LLK_Gr || src->kind == LLK_GStk); - if (dest->kind == LLK_Gr) { - buf = mov(buf, get_r_opnd(dest), get_rm_opnd(src), size_64); - return; - } - // dest->kind != LLK_Gr - if (src->kind == LLK_Gr) { - buf = mov(buf, get_m_opnd(dest), get_r_opnd(src), size_64); + if (src->kind == LLK_Gr || src->kind == LLK_GStk) { + if (dest->kind == LLK_Gr) { + buf = mov(buf, get_r_opnd(dest), get_rm_opnd(src), size_64); + return; + } + // dest->kind != LLK_Gr + if (src->kind == LLK_Gr) { + buf = mov(buf, get_m_opnd(dest), get_r_opnd(src), size_64); + return; + } + // src->kind != LLK_Gr + // use temporary register + Tmp_GR_Opnd tmp_reg(context, ic); + buf = mov(buf, tmp_reg, get_m_opnd(src), size_64); + buf = mov(buf, get_m_opnd(dest), tmp_reg, size_64); + } else { // src->kind == LLK_Fr || src->kind == LLK_FStk + // src->kind == LLK_Fr supported only + assert(src->kind == LLK_Fr); + buf = movq(buf, get_rm_opnd(dest), get_xmm_r_opnd(src)); return; } - // src->kind != LLK_Gr - // use temporary register - Tmp_GR_Opnd tmp_reg(context, ic); - buf = mov(buf, tmp_reg, get_m_opnd(src), size_64); - buf = mov(buf, get_m_opnd(dest), tmp_reg, size_64); - } else { //dest->kind == LLK_Fr || dest->kind == LLK_FStk - assert(src->kind == LLK_Fr || src->kind == LLK_FStk); - if (dest->kind == LLK_Fr) { + } else { // dest->kind == LLK_Fr || dest->kind == LLK_FStk + if (src->kind == LLK_Fr || src->kind == LLK_FStk) { + if (dest->kind == LLK_Fr) { + if (src->kind == LLK_Fr) { + buf = sse_mov(buf, get_xmm_r_opnd(dest), get_xmm_r_opnd(src), true); + } else { + buf = sse_mov(buf, get_xmm_r_opnd(dest), get_m_opnd(src), true); + } + return; + } + // dest->kind != LLK_Gr if (src->kind == LLK_Fr) { - buf = sse_mov(buf, get_xmm_r_opnd(dest), get_xmm_r_opnd(src), true); - } else { - buf = sse_mov(buf, get_xmm_r_opnd(dest), get_m_opnd(src), true); + buf = sse_mov(buf, get_m_opnd(dest), get_xmm_r_opnd(src), true); + return; } + // src->kind != LLK_Gr + // use temporary register + Tmp_FR_Opnd tmp_reg(ic); + buf = sse_mov(buf, tmp_reg, get_m_opnd(src), true); + buf = sse_mov(buf, get_m_opnd(dest), tmp_reg, true); + } else { // src->kind == LLK_Gr || src->kind == LLK_GStk + // dest->kind == LLK_Fr supported only + assert(dest->kind == LLK_Fr); + buf = movq(buf, get_xmm_r_opnd(dest), get_rm_opnd(src)); return; } - // dest->kind != LLK_Gr - if (src->kind == LLK_Fr) { - buf = sse_mov(buf, get_m_opnd(dest), get_xmm_r_opnd(src), true); - return; - } - // src->kind != LLK_Gr - // use temporary register - Tmp_FR_Opnd tmp_reg(ic); - buf = sse_mov(buf, tmp_reg, get_m_opnd(src), true); - buf = sse_mov(buf, get_m_opnd(dest), tmp_reg, true); } } @@ -589,7 +596,12 @@ #endif void shift_op_rm_imm(const LcgEM64TLoc * dest, const LcgEM64TLoc * src, int32 imm_val) { const Imm_Opnd & imm = get_imm_opnd(imm_val); if (src->kind == LLK_Gr) { - buf = shift(buf, shl_opc, get_rm_opnd(dest), get_r_opnd(src), imm); + if (dest->kind == LLK_Gr) { + buf = mov(buf, get_r_opnd(dest), get_r_opnd(src), size_64); + } else { + buf = mov(buf, get_m_opnd(dest), get_r_opnd(src), size_64); + } + buf = shift(buf, shl_opc, get_rm_opnd(dest), imm); return; } // src->kind != LLK_Gr @@ -601,7 +613,8 @@ #endif // dest->kind != LLK_Gr Tmp_GR_Opnd tmp_reg(context, ic); buf = mov(buf, tmp_reg, get_m_opnd(src), size_64); - buf = shift(buf, shl_opc, get_m_opnd(dest), tmp_reg, imm); + buf = shift(buf, shl_opc, tmp_reg, imm); + buf = mov(buf, get_m_opnd(dest), tmp_reg); } // subtract op where the first op is immediate @@ -619,7 +632,7 @@ #endif assert(dest->kind == LLK_Gr || dest->kind == LLK_GStk); assert(src->kind == LLK_Gr || src->kind == LLK_GStk); const Imm_Opnd & imm = get_imm_opnd(imm_val); - if (dest == src) { + if (*dest == *src) { buf = alu(buf, alu_opc, get_rm_opnd(dest), imm, size_64); return; } @@ -631,8 +644,8 @@ #endif } // dest->kind != LLK_Gr if (src->kind == LLK_Gr) { - buf = alu(buf, alu_opc, get_r_opnd(src), imm, size_64); buf = mov(buf, get_m_opnd(dest), get_r_opnd(src), size_64); + buf = alu(buf, alu_opc, get_m_opnd(dest), imm, size_64); return; } // src->kind == LLK_Gr @@ -648,7 +661,7 @@ #endif assert(src1->kind == LLK_Gr || src1->kind == LLK_GStk); assert(src2->kind == LLK_Gr || src2->kind == LLK_GStk); - if (dest == src1) { + if (*dest == *src1) { if (dest->kind == LLK_Gr) { buf = alu(buf, alu_opc, get_r_opnd(dest), get_rm_opnd(src2)); return; @@ -693,7 +706,7 @@ #endif case LO_SgMul: { const Imm_Opnd & imm = get_imm_opnd(imm_val); if (dest->kind == LLK_Gr) { - if (dest == src) { + if (*dest == *src) { buf = imul(buf, get_r_opnd(dest), imm); } else { buf = imul(buf, get_r_opnd(dest), get_rm_opnd(src), imm); @@ -796,7 +809,9 @@ #endif buf = movzx(buf, dest_reg, get_rm_opnd(src), size_16); break; case LO_Zx4: - buf = movzx(buf, dest_reg, get_rm_opnd(src), size_32); + // movzx r64, r/m32 is not available on em64t + // mov r32, r/m32 should zero out upper bytes + buf = mov(buf, dest_reg, get_rm_opnd(src), size_32); break; default: ASSERT(0, "Unexpected operation"); // control should never reach this point @@ -811,14 +826,15 @@ #endif const M_Opnd & get_effective_addr(LilVariable * base, unsigned scale, LilVariable * index, int64 offset, const R_Opnd & tmp_reg) { - const bool is_offset32 = fit32(offset); void * const M_Index_Opnd_mem = mem.alloc(sizeof(M_Index_Opnd)); // handle special case - if (is_offset32 && base == NULL && (index == NULL || scale == 0)) { - return *(new(M_Index_Opnd_mem) M_Index_Opnd(n_reg, n_reg, offset, 0)); + if (base == NULL && (index == NULL || scale == 0)) { + buf = mov(buf, tmp_reg, Imm_Opnd(size_64, offset)); + return *(new(M_Index_Opnd_mem) M_Index_Opnd(tmp_reg.reg_no(), n_reg, 0, 0)); } // initialize locations + const bool is_offset32 = fit32(offset); const LcgEM64TLoc * base_loc = base != NULL ? get_var_loc(base, false) : NULL; const LcgEM64TLoc * index_loc = index != NULL && scale != 0 ? get_var_loc(index, false) : NULL; const bool is_base_in_mem = base_loc != NULL && base_loc->kind == LLK_GStk; @@ -853,7 +869,7 @@ #endif const LcgEM64TLoc * ret_loc = new(mem) LcgEM64TLoc(LLK_Gr, LcgEM64TContext::get_index_in_map(tmp_reg.reg_no())); if (index_loc != NULL) { - int32 shift = scale / 2; + int32 shift = scale / 4 + 1; bin_op_rm_imm(LO_Shl, ret_loc, index_loc, shift); if (base_loc != NULL) { bin_op_rm_rm(LO_Add, ret_loc, ret_loc, base_loc); @@ -884,42 +900,33 @@ #endif return *(new(M_Index_Opnd_mem) M_Base_Opnd(get_r_opnd(ret_loc).reg_no(), (uint32)offset)); } - // sets up the stack frame - void save_callee_saves() { + // sets up stack frame + void prolog() { + // push callee-saves registers on the stack if (lil_cs_get_max_locals(cs) > 0) { assert(context.get_stk_size() != 0); - // compute the rsp-relative offset of the top of m2n frame - int32 offset = context.get_m2n_offset() + context.get_stk_m2n_size() - - current_rsp_offset; - // adjust rsp if required - adjust_stack_pointer(offset); - // push callee-saves registers on the stack for (unsigned i = 0; i < lil_cs_get_max_locals(cs); i++) { const LcgEM64TLoc * loc = get_gp_local(i); assert(loc->kind == LLK_Gr); - assert(LcgEM64TContext::GR_SIZE == 8); buf = push(buf, get_r_opnd(loc), size_64); - current_rsp_offset -= LcgEM64TContext::GR_SIZE; } } + adjust_stack_pointer(lil_cs_get_max_locals(cs) * LcgEM64TContext::GR_SIZE - + context.get_stk_size()); } // unsets the stack frame - void restore_callee_saves() { + void epilog() { + adjust_stack_pointer(context.get_stk_size() - + lil_cs_get_max_locals(cs) * LcgEM64TContext::GR_SIZE); + if (lil_cs_get_max_locals(cs) > 0) { assert(context.get_stk_size() != 0); - // compute the rsp-relative offset of the last callee-saves register - int32 offset = (int32)(context.get_m2n_offset() + context.get_stk_m2n_size() - - lil_cs_get_max_locals(cs) * LcgEM64TContext::GR_SIZE - current_rsp_offset); - // adjust rsp if required - adjust_stack_pointer(offset); // pop callee-saves registers from the stack for (int i = lil_cs_get_max_locals(cs) - 1; i >= 0; i--) { const LcgEM64TLoc * loc = get_gp_local(i); assert(loc->kind == LLK_Gr); - assert(LcgEM64TContext::GR_SIZE == 8); buf = pop(buf, get_r_opnd(loc), size_64); - current_rsp_offset += LcgEM64TContext::GR_SIZE; } } } @@ -930,27 +937,27 @@ #endif return; } - // check the rsp position - assert(context.get_input_gr_save_offset() + - context.get_stk_input_gr_save_size() - current_rsp_offset == 0); + // compute the rsp-relative offset of the top of the GR save area + int32 offset = (int32)context.get_input_gr_save_offset() + + context.get_stk_input_gr_save_size(); // store GR inputs to the computed locations for (int i = context.get_num_gr_inputs() - 1; i >= 0; i--) { const R_Opnd & r_opnd = LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_OUTPUTS_OFFSET + i); - assert(LcgEM64TContext::GR_SIZE == 8); - buf = push(buf, r_opnd, size_64); - current_rsp_offset -= LcgEM64TContext::GR_SIZE; + offset -= LcgEM64TContext::GR_SIZE; + const M_Opnd dest(rsp_reg, offset); + buf = mov(buf, dest, r_opnd); } // compute the rsp-relative offset of the top of the FR save area - int32 fr_offset = (int32)context.get_input_fr_save_offset() + - context.get_stk_input_fr_save_size() - current_rsp_offset; + offset = (int32)context.get_input_fr_save_offset() + + context.get_stk_input_fr_save_size(); // store FR inputs to the computed locations for (int i = context.get_num_fr_inputs() - 1; i >= 0; i--) { const XMM_Opnd & r_opnd = LcgEM64TContext::get_xmm_reg_from_map(LcgEM64TContext::FR_OUTPUTS_OFFSET + i); - const M_Opnd dest(rsp_reg, fr_offset); + offset -= LcgEM64TContext::FR_SIZE; + const M_Opnd dest(rsp_reg, offset); buf = sse_mov(buf, dest, r_opnd, true); - fr_offset -= LcgEM64TContext::FR_SIZE; } } @@ -961,25 +968,24 @@ #endif return; } // compute the rsp-relative offset of the bottom of the FR save area - int32 fr_offset = (int32)context.get_input_fr_save_offset() - current_rsp_offset; + int32 offset = (int32)context.get_input_fr_save_offset(); // restore FR inputs - for (unsigned i = 0; i < context.get_num_inputs(); i++) { + for (unsigned i = 0; i < context.get_num_fr_inputs(); i++) { const XMM_Opnd & r_opnd = LcgEM64TContext::get_xmm_reg_from_map(LcgEM64TContext::FR_OUTPUTS_OFFSET + i); - const M_Opnd src(rsp_reg, fr_offset); + const M_Opnd src(rsp_reg, offset); buf = sse_mov(buf, r_opnd, src, true); - fr_offset += LcgEM64TContext::FR_SIZE; + offset += LcgEM64TContext::FR_SIZE; } // compute the rsp-relative offset of the bottom of the GR save area - int32 gr_offset = (int32)context.get_input_gr_save_offset() - current_rsp_offset; - adjust_stack_pointer(gr_offset); + offset = (int32)context.get_input_gr_save_offset(); // restore GR inputs for (unsigned i = 0; i < context.get_num_gr_inputs(); i++) { const R_Opnd & r_opnd = LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_OUTPUTS_OFFSET + i); - assert(LcgEM64TContext::GR_SIZE == 8); - buf = pop(buf, r_opnd, size_64); - current_rsp_offset += LcgEM64TContext::GR_SIZE; + const M_Opnd src(rsp_reg, offset); + buf = mov(buf, r_opnd, src, size_64); + offset += LcgEM64TContext::GR_SIZE; } } @@ -1008,12 +1014,12 @@ public: LcgEM64TCodeGen(LilCodeStub * cs, LcgEM64TContext & c, tl::MemoryPool & m): buf_beg((char *)m.alloc(MAX_CODE_LENGTH)), buf(buf_beg), labels(&m, buf_beg), cs(cs), context(c), mem(m), iter(cs, true), ic(NULL), inst(NULL), - rsp_loc(new(m) LcgEM64TLoc(LLK_Gr, rsp_reg)), take_inputs_from_stack(false), - current_rsp_offset(context.get_stk_size()), current_alloc(0) { + rsp_loc(new(m) LcgEM64TLoc(LLK_Gr, LcgEM64TContext::RSP_OFFSET)), take_inputs_from_stack(false), + current_alloc(0) { // emit entry code - move_inputs(); - save_callee_saves(); + prolog(); + move_inputs(); // go through the instructions while (!iter.at_end()) { @@ -1064,7 +1070,7 @@ public: } void alloc(LilVariable * var, unsigned sz) { - int32 alloc_offset = context.get_alloc_start_offset() + current_alloc - current_rsp_offset; + int32 alloc_offset = context.get_alloc_start_offset() + current_alloc; // the actual size allocated will always be a multiple of 8 current_alloc += align_8(sz); // var = sp + alloc_offset @@ -1181,33 +1187,35 @@ public: void ts(LilVariable * var) { const LcgEM64TLoc * var_loc = get_var_loc(var, true); assert(var_loc->kind == LLK_Gr || var_loc->kind == LLK_GStk); + if (var_loc->kind == LLK_Gr) { buf = m2n_gen_ts_to_register(buf, &get_r_opnd(var_loc), - lil_cs_get_max_locals(cs), lil_ic_get_num_std_places(ic), - context.is_uses_returns() ? 1 : 0, true); + lil_ic_get_num_locals(ic), lil_cs_get_max_locals(cs), + lil_ic_get_num_std_places(ic), lil_ic_get_ret_type(ic) == LT_Void ? 0 : 1); } else { const Tmp_GR_Opnd tmp(context, ic); buf = m2n_gen_ts_to_register(buf, &tmp, - lil_cs_get_max_locals(cs), lil_ic_get_num_std_places(ic), - context.is_uses_returns() ? 1 : 0, true); + lil_ic_get_num_locals(ic), lil_cs_get_max_locals(cs), + lil_ic_get_num_std_places(ic), lil_ic_get_ret_type(ic) == LT_Void ? 0 : 1); buf = mov(buf, get_m_opnd(var_loc), tmp, size_64); } + take_inputs_from_stack = true; } void handles(LilOperand * op) { if (lil_operand_is_immed(op)) { buf = m2n_gen_set_local_handles_imm(buf, - context.get_m2n_offset() - current_rsp_offset, &get_imm_opnd(op)); + context.get_m2n_offset(), &get_imm_opnd(op)); } else { const LcgEM64TLoc * loc = get_op_loc(op, false); if (loc->kind == LLK_Gr) { - buf = m2n_gen_set_local_handles_r(buf, context.get_m2n_offset() - - current_rsp_offset, &get_r_opnd(loc)); + buf = m2n_gen_set_local_handles_r(buf, + context.get_m2n_offset(), &get_r_opnd(loc)); } else { const Tmp_GR_Opnd tmp(context, ic); - buf = m2n_gen_set_local_handles_r(buf, context.get_m2n_offset() - - current_rsp_offset, &tmp); + buf = m2n_gen_set_local_handles_r(buf, + context.get_m2n_offset(), &tmp); buf = mov(buf, get_m_opnd(loc), tmp, size_64); } } @@ -1253,7 +1261,13 @@ public: assert(size != n_size); if (ext == LLX_Zero) { - buf = movzx(buf, *dest_reg, addr, size); + // movzx r64, r/m32 is not available on em64t + // mov r32, r/m32 should zero out upper bytes + if (size == size_32) { + buf = mov(buf, *dest_reg, addr, size); + } else { + buf = movzx(buf, *dest_reg, addr, size); + } } else { buf = movsx(buf, *dest_reg, addr, size); } @@ -1477,12 +1491,10 @@ move_to_destination: void call(LilOperand * target, LilCallKind kind) { switch (kind) { case LCK_TailCall: { - // restore callee_saves registers from the stack - restore_callee_saves(); // restore input FR & GR unmove_inputs(); - // old stacked arguments should become visible - assert(current_rsp_offset == context.get_stk_size()); + // unwind current stack frame + epilog(); // jump (instead of calling) if (lil_operand_is_immed(target)) { // check if we can perform relative call @@ -1518,8 +1530,6 @@ move_to_destination: } case LCK_Call: case LCK_CallNoRet: { - // rsp should point to the bottom of the activation frame before issuing call - adjust_stack_pointer(-current_rsp_offset); if (lil_operand_is_immed(target)) { // check if we can perform relative call int64 target_value = lil_operand_get_immed(target); @@ -1560,8 +1570,8 @@ move_to_destination: } void ret() { - restore_callee_saves(); - adjust_stack_pointer(context.get_stk_size() - current_rsp_offset); + // unwind current stack frame + epilog(); buf = ::ret(buf); } @@ -1570,13 +1580,11 @@ move_to_destination: void push_m2n(Method_Handle method, frame_type current_frame_type, bool handles) { take_inputs_from_stack = true; - // rsp-relative offset of the bottom of the m2n frame - int32 offset = context.get_m2n_offset() - current_rsp_offset; + // rsp-relative offset of the top of the m2n frame + int32 offset = context.get_m2n_offset() + context.get_stk_m2n_size(); buf = m2n_gen_push_m2n(buf, method, current_frame_type, handles, lil_cs_get_max_locals(cs), lil_ic_get_num_std_places(ic), offset); - - current_rsp_offset = context.get_m2n_offset(); } void m2n_save_all() { @@ -1585,11 +1593,8 @@ move_to_destination: void pop_m2n() { buf = m2n_gen_pop_m2n(buf, context.m2n_has_handles(), lil_cs_get_max_locals(cs), // TODO: FIXME: need to define proper return registers to be preserved - context.get_m2n_offset() - current_rsp_offset, 1); + context.get_m2n_offset(), 1); // after m2n_gen_pop_m2n rsp points to the last callee-saves register - // set current rsp offset - current_rsp_offset = context.get_m2n_offset() + context.get_stk_m2n_size() - - lil_cs_get_max_locals(cs) * LcgEM64TContext::GR_SIZE; } void print(char * str, LilOperand * o) { @@ -1616,8 +1621,7 @@ #endif // STUB_DEBUG LilCodeGeneratorEM64T::LilCodeGeneratorEM64T(): LilCodeGenerator() {} -NativeCodePtr LilCodeGeneratorEM64T::compile_main(LilCodeStub * cs, size_t * stub_size, - const char* stub_name, bool dump_stubs) { +NativeCodePtr LilCodeGeneratorEM64T::compile_main(LilCodeStub * cs, size_t * stub_size) { // start a memory manager tl::MemoryPool m; // get context @@ -1629,11 +1633,6 @@ NativeCodePtr LilCodeGeneratorEM64T::com NativeCodePtr buffer = allocate_memory(*stub_size); codegen.copy_stub(buffer); -#ifndef NDEBUG - if (dump_stubs) { - dump((char *)buffer, stub_name, *stub_size); - } -#endif return buffer; } diff --git vm/port/src/lil/em64t/pim/m2n_em64t.cpp vm/port/src/lil/em64t/pim/m2n_em64t.cpp old mode 100644 new mode 100755 index 18a5da8..24eba62 --- vm/port/src/lil/em64t/pim/m2n_em64t.cpp +++ vm/port/src/lil/em64t/pim/m2n_em64t.cpp @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ + * @version $Revision$ */ #include <string.h> @@ -29,6 +30,9 @@ #include "encoder.h" #include "m2n_em64t_internal.h" #include "lil_code_generator_em64t.h" +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" + /* Generic Interface */ void m2n_null_init(M2nFrame * m2n){ @@ -43,6 +47,10 @@ M2nFrame* m2n_get_last_frame(VM_thread * return thread->last_m2n_frame; } +void m2n_set_last_frame(VM_thread* thread, M2nFrame * lm2nf) { + thread->last_m2n_frame = lm2nf; +} + void m2n_set_last_frame(M2nFrame * lm2nf) { p_TLS_vmthread->last_m2n_frame = lm2nf; } @@ -75,21 +83,41 @@ frame_type m2n_get_frame_type(M2nFrame * return m2nf->current_frame_type; } -void m2n_set_frame_type(M2nFrame * m2nf, frame_type m2nf_type) { +void m2n_set_frame_type(M2nFrame * m2nf, frame_type m2nf_type) +{ m2nf->current_frame_type = m2nf_type; } -M2nFrame * m2n_push_suspended_frame(Registers * regs) { - M2nFrame * m2nf = (M2nFrame *)STD_MALLOC(sizeof(M2nFrame)); +void m2n_push_suspended_frame(M2nFrame* m2nf, Registers* regs) +{ + m2n_push_suspended_frame(p_TLS_vmthread, m2nf, regs); +} + +void m2n_push_suspended_frame(VM_thread* thread, M2nFrame* m2nf, Registers* regs) +{ + assert(m2nf); m2nf->p_lm2nf = (M2nFrame**)1; m2nf->method = NULL; m2nf->local_object_handles = NULL; + m2nf->current_frame_type = FRAME_UNKNOWN; - m2nf->rip = regs->rip; + m2nf->rip = (POINTER_SIZE_INT)regs->get_ip(); m2nf->regs = regs; - m2nf->prev_m2nf = m2n_get_last_frame(); - m2n_set_last_frame(m2nf); + m2nf->prev_m2nf = m2n_get_last_frame(thread); + m2n_set_last_frame(thread, m2nf); +} + +M2nFrame* m2n_push_suspended_frame(Registers* regs) +{ + return m2n_push_suspended_frame(p_TLS_vmthread, regs); +} + +M2nFrame* m2n_push_suspended_frame(VM_thread* thread, Registers* regs) +{ + M2nFrame* m2nf = (M2nFrame*)STD_MALLOC(sizeof(M2nFrame)); + assert(m2nf); + m2n_push_suspended_frame(thread, m2nf, regs); return m2nf; } @@ -99,8 +127,7 @@ bool m2n_is_suspended_frame(M2nFrame * m } void * m2n_get_frame_base(M2nFrame * m2nf) { - // regs should be last field in the M2nFrame structure - return &m2nf->regs; + return &m2nf->rip; } /* Internal Interface */ @@ -108,48 +135,56 @@ void * m2n_get_frame_base(M2nFrame * m2n // rsp should point to the bottom of the activation frame since push may occur // inputs should be preserved outside if required since we do a call // num_std_need_to_save registers will be preserved -char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg, unsigned num_callee_saves, - unsigned num_std_need_to_save, unsigned num_ret_need_to_save, - bool use_callee_saves) { +char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg, + unsigned num_callee_saves_used, + unsigned num_callee_saves_max, + unsigned num_std_need_to_save, + unsigned num_ret_need_to_save) { + // we can't preserve rax and return value on it at the same time + assert (num_ret_need_to_save == 0 || reg != &rax_opnd); #ifdef PLATFORM_POSIX // preserve std places unsigned i; unsigned num_std_saved = 0; // use calle-saves registers first - if (use_callee_saves) { while (num_std_saved < num_std_need_to_save && - (i = num_callee_saves + num_std_saved) < LcgEM64TContext::MAX_GR_LOCALS) { - buf = mov(buf, LcgEM64TContext::get_reg_from_map( + (i = num_callee_saves_used + num_std_saved) < num_callee_saves_max) { + buf = mov(buf, + LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i), - LcgEM64TContext::get_reg_from_map(LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); ++num_std_saved; } - } // if we still have not preserved std places save them on the stack while (num_std_saved < num_std_need_to_save) { - buf = push(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); + buf = push(buf, + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), + size_64); ++num_std_saved; } assert(num_std_saved == num_std_need_to_save); // preserve returns unsigned num_ret_saved = 0; - if (use_callee_saves) { while (num_ret_saved < num_ret_need_to_save && - (i = num_callee_saves + num_std_saved + num_ret_saved) < LcgEM64TContext::MAX_GR_LOCALS) { - buf = mov(buf, LcgEM64TContext::get_reg_from_map( + (i = num_callee_saves_used + num_std_saved + num_ret_saved) < num_callee_saves_max) { + buf = mov(buf, + LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i), - LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), size_64); ++num_ret_saved; } - } // if we still have not preserved returns save them on the stack while (num_ret_saved < num_ret_need_to_save) { - buf = push(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::GR_RETURNS_OFFSET + num_std_saved), size_64); + buf = push(buf, + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::GR_RETURNS_OFFSET + num_std_saved), + size_64); ++num_ret_saved; } assert(num_ret_saved == num_ret_need_to_save); @@ -161,52 +196,44 @@ #ifdef PLATFORM_POSIX buf = mov(buf, *reg, rax_opnd, size_64); } - // restore returns & std places - if (use_callee_saves) { - // restore from the stack first - i = num_callee_saves + num_std_saved; - while (num_ret_saved > 0 && i + num_ret_saved > LcgEM64TContext::MAX_GR_LOCALS) { + // restore returns from the stack + i = num_callee_saves_used + num_std_saved; + while (num_ret_saved > 0 && i + num_ret_saved > num_callee_saves_max) { --num_ret_saved; - buf = pop(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), size_64); + buf = pop(buf, + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), + size_64); } - while (num_std_saved > 0 && num_callee_saves + num_std_saved > LcgEM64TContext::MAX_GR_LOCALS) { + // restore std places from the stack + while (num_std_saved > 0 && num_callee_saves_used + num_std_saved > num_callee_saves_max) { --num_std_saved; - buf = pop(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); + buf = pop(buf, + LcgEM64TContext::get_reg_from_map( + LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), + size_64); } - // restore from callee-saves registers - i = num_callee_saves + num_std_saved; + // restore returns from callee-saves registers + i = num_callee_saves_used + num_std_saved; while (num_ret_saved > 0) { --num_ret_saved; - buf = mov(buf, LcgEM64TContext::get_reg_from_map( + buf = mov(buf, + LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i + num_ret_saved), size_64); } + // restore std places from callee-saves registers while (num_std_saved > 0) { --num_std_saved; - buf = mov(buf, LcgEM64TContext::get_reg_from_map( + buf = mov(buf, + LcgEM64TContext::get_reg_from_map( LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::GR_LOCALS_OFFSET + num_callee_saves + num_std_saved), + LcgEM64TContext::GR_LOCALS_OFFSET + num_callee_saves_used + num_std_saved), size_64); } - } else { - // restore all returns from the stack - while (num_ret_saved > 0) { - --num_ret_saved; - buf = pop(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), size_64); - } - // restore all std places from the stack - while (num_std_saved > 0) { - --num_std_saved; - buf = pop(buf, LcgEM64TContext::get_reg_from_map( - LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); - } - } #else //!PLATFORM_POSIX buf = prefix(buf, fs_prefix); buf = mov(buf, *reg, M_Opnd(0x14), size_64); @@ -216,13 +243,13 @@ #endif //!PLATFORM_POSIX char * m2n_gen_set_local_handles_r(char * buf, unsigned bytes_to_m2n, const R_Opnd * src_reg) { unsigned offset_local_handles = (unsigned)(uint64) &((M2nFrame*)0)->local_object_handles; - buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n+offset_local_handles), *src_reg, size_64); + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n + offset_local_handles), *src_reg, size_64); return buf; } char * m2n_gen_set_local_handles_imm(char * buf, unsigned bytes_to_m2n, const Imm_Opnd * imm) { unsigned offset_local_handles = (unsigned)(uint64)&((M2nFrame*)0)->local_object_handles; - buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n+offset_local_handles), *imm, size_64); + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n + offset_local_handles), *imm, size_64); return buf; } @@ -233,57 +260,62 @@ char * m2n_gen_push_m2n(char * buf, Meth bool handles, unsigned num_callee_saves, unsigned num_std_need_to_save, - int32 bytes_to_m2n) { - //adjust stack pointer if required - bytes_to_m2n += get_size_of_m2n() - num_callee_saves * LcgEM64TContext::GR_SIZE; - if (bytes_to_m2n != 0) { - buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(bytes_to_m2n), size_64); - } - + int32 bytes_to_m2n_top) { + // skip callee-saves registers + bytes_to_m2n_top -= num_callee_saves * LcgEM64TContext::GR_SIZE; // TODO: check if it makes sense to save all callee-saves registers here //store rest of callee-saves registers for (unsigned i = num_callee_saves; i < LcgEM64TContext::MAX_GR_LOCALS; i++) { - buf = push(buf, + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + buf = mov(buf, + M_Base_Opnd(rsp_reg, bytes_to_m2n_top), LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_LOCALS_OFFSET + i), - size_64); + size_64); } - - // TODO: check if we can skip pushing current_frame_type, method and local handles - // store current frame type - if (method == NULL && current_frame_type == FRAME_UNKNOWN) { - buf = alu(buf, sub_opc, rsp_opnd, - Imm_Opnd(3 * LcgEM64TContext::GR_SIZE), size_64); + // store current_frame_type + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + assert(fit32(current_frame_type)); + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), + Imm_Opnd(size_32, current_frame_type), size_64); + // store a method associated with the current m2n frame + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + if (fit32((int64)method)) { + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), + Imm_Opnd(size_32, (int64)method), size_64); } else { - // TODO: FIXME: we can use push imm32 if operand is fit to 32 bits - buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)current_frame_type), size_64); - buf = push(buf, rax_opnd, size_64); - // store a method associated with the current m2n frame - buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)method), size_64); - buf = push(buf, rax_opnd, size_64); - // store local object handles - buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)0), size_64); - buf = push(buf, rax_opnd, size_64); + buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (int64)method), size_64); + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), rax_opnd); } + // store local object handles + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), + Imm_Opnd(size_64, (int64)0), size_64); // move pointer to the current VM_Thread structure to rax - buf = m2n_gen_ts_to_register(buf, &rax_opnd, num_callee_saves, num_std_need_to_save, 0, true); - + buf = m2n_gen_ts_to_register(buf, &rax_opnd, + num_callee_saves, LcgEM64TContext::MAX_GR_LOCALS, + num_std_need_to_save, 0); + // shift to the last_m2n_frame field int32 last_m2n_frame_offset = (int32)(int64)&((VM_thread*)0)->last_m2n_frame; - buf = alu(buf, add_opc, rax_opnd, Imm_Opnd(last_m2n_frame_offset), size_64); + buf = alu(buf, add_opc, rax_opnd, Imm_Opnd(size_32, last_m2n_frame_offset), size_64); // store pointer to pointer to last m2n frame - buf = push(buf, rax_opnd, size_64); + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), rax_opnd, size_64); // save pointer to the previous m2n frame - buf = push(buf, M_Base_Opnd(rax_reg, 0), size_64); + bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; + buf = mov(buf, r9_opnd, M_Base_Opnd(rax_reg, 0)); + buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), r9_opnd, size_64); // update last m2n frame of the current thread - buf = mov(buf, M_Base_Opnd(rax_reg, 0), rsp_opnd, size_64); + buf = lea(buf, r9_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_top)); + buf = mov(buf, M_Base_Opnd(rax_reg, 0), r9_opnd, size_64); return buf; } char * m2n_gen_pop_m2n(char * buf, bool handles, unsigned num_callee_saves, - unsigned bytes_to_m2n, unsigned num_preserve_ret) { - assert (num_preserve_ret <= 2); - unsigned handles_offset = 2 * LcgEM64TContext::GR_SIZE + bytes_to_m2n; + int32 bytes_to_m2n_bottom, unsigned num_preserve_ret) { + assert (num_preserve_ret <= 2); + unsigned handles_offset = 2 * LcgEM64TContext::GR_SIZE + bytes_to_m2n_bottom; if (handles) { if (num_preserve_ret > 0) { // Save return value @@ -311,23 +343,23 @@ char * m2n_gen_pop_m2n(char * buf, bool } } - if (bytes_to_m2n > 0) { - buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(bytes_to_m2n), size_64); - } // pop prev_m2nf - buf = pop(buf, r10_opnd, size_64); + buf = mov(buf, r10_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); + bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; // pop p_lm2nf - buf = pop(buf, r11_opnd, size_64); + buf = mov(buf, r11_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); + bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(r11_reg, 0), r10_opnd, size_64); // skip local_object_handles, method, current_frame_type - buf = alu(buf, add_opc, rsp_opnd, - Imm_Opnd(3 * LcgEM64TContext::GR_SIZE), size_64); + bytes_to_m2n_bottom += 3 * LcgEM64TContext::GR_SIZE; // restore part of callee-saves registers for (int i = LcgEM64TContext::MAX_GR_LOCALS - 1; i >= (int)num_callee_saves; i--) { - buf = pop(buf, + buf = mov(buf, LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_LOCALS_OFFSET + i), + M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); + bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; } return buf; } diff --git vm/port/src/lil/em64t/pim/m2n_em64t_internal.h vm/port/src/lil/em64t/pim/m2n_em64t_internal.h index 72697c2..1d694fc 100644 --- vm/port/src/lil/em64t/pim/m2n_em64t_internal.h +++ vm/port/src/lil/em64t/pim/m2n_em64t_internal.h @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.3 $ + * @version $Revision$ */ #ifndef _M2N_EM64T_INTERNAL_H_ @@ -30,6 +31,8 @@ #include "m2n.h" #include "open/types.h" #include "encoder.h" +const unsigned m2n_sizeof_m2n_frame = 96; + typedef struct M2nFrame M2nFrame; /** @@ -65,19 +68,23 @@ struct M2nFrame { /** * returns size of m2n frame in bytes */ -inline const size_t get_size_of_m2n() { - // omit regs & rip +inline size_t m2n_get_size() { + // omit regs return sizeof(M2nFrame) - 16; } -// Generate code to put the thread local storage pointer into a given register -// It destroys outputs. -char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg, unsigned num_callee_saves, - unsigned num_std_need_to_save, unsigned num_ret_need_to_save, - bool use_callee_saves); +/** + * Generate code to put the thread local storage pointer into a given register. + * It destroys outputs. + */ +char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg, + unsigned num_callee_saves_used, unsigned num_callee_saves_max, + unsigned num_std_need_to_save, unsigned num_ret_need_to_save); -// Generate code to set the local handles of an M2nFrame -// The M2nFrame is located bytes_to_m2n above rsp, and src_reg has the address of the frames. +/** + * Generate code to set the local handles of an M2nFrame. + * The M2nFrame is located bytes_to_m2n above rsp, and src_reg has the address of the frames. + */ char * m2n_gen_set_local_handles_r(char * buf, unsigned bytes_to_m2n, const R_Opnd * src_reg); char * m2n_gen_set_local_handles_imm(char * buf, unsigned bytes_to_m2n, const Imm_Opnd * imm); @@ -88,19 +95,27 @@ char * m2n_gen_set_local_handles_imm(cha * The order for callee saves is r12, r13, r14, r15, rbp, rbx. * It destroys returns (rax) and outputs. * After the sequence, rsp points to the M2nFrame. - * handles: indicates whether the stub will want local handles or not - * bytes_to_m2n: number of bytes to the beginning of m2n frame relative to the current rsp value. - * negative value means that current rsp is above m2n bottom + * + * @param handles Indicates whether the stub will want local handles or not + * @param bytes_to_m2n_top Number of bytes to the beginning of m2n frame relative to the current rsp value. + Negative value means that current rsp is above m2n bottom. */ char * m2n_gen_push_m2n(char * buf, Method_Handle method, frame_type current_frame_type, bool handles, - unsigned num_callee_saves, unsigned num_std_need_to_save, int32 bytes_to_m2n); + unsigned num_callee_saves, unsigned num_std_need_to_save, int32 bytes_to_m2n_top); -// Generate code to pop an M2nFrame off the stack. -// num_callee_saves: the number of callee saves registers to leave on the stack as at the entry to push_m2n. -// bytes_to_m2n: the number of bytes between rsp and the bottom of the M2nFrame. -// preserve_ret: the number of return registers to preserve, 0 means none, 1 means rax, 2 means rax & rdx. -// handles: as for push_m2n, frees the handles if true. +/** + * Generate code to pop an M2nFrame off the stack. + * @param num_callee_saves Number of callee saves registers to leave + * on the stack as at the entry to push_m2n. + * @param bytes_to_m2n_bottom Number of bytes between rsp and the bottom of the M2nFrame. + * @param preserve_ret Number of return registers to preserve, 0 means none, + * 1 means rax, 2 means rax & rdx. + * @param handles As for push_m2n, frees the handles if true. + */ char * m2n_gen_pop_m2n(char * buf, bool handles, unsigned num_callee_saves, - unsigned bytes_to_m2n, unsigned preserve_ret); + int32 bytes_to_m2n_bottom, unsigned preserve_ret); + +// returns top of the specified frame on the stack (it should point to return ip) +void * m2n_get_frame_base(M2nFrame *); #endif // _M2N_EM64T_INTERNAL_H_ diff --git vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp index 485c3d7..7025186 100644 --- vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp +++ vm/port/src/lil/em64t/pim/stack_iterator_em64t.cpp @@ -30,14 +30,10 @@ #include "m2n_em64t_internal.h" #include "nogc.h" #include "interpreter.h" // for ASSERT_NO_INTERPRETER -#include "cxxlog.h" - -#ifndef NDEBUG -#include "vm_stats.h" #include "dump.h" -extern bool dump_stubs; -#endif +#include "vm_stats.h" +#include "cxxlog.h" // see stack_iterator_ia32.cpp struct StackIterator { @@ -88,7 +84,7 @@ static void init_context_from_registers( // Goto the managed frame immediately prior to m2nfl static void si_unwind_from_m2n(StackIterator * si) { #ifdef VM_STATS - vm_stats_total.num_unwind_native_frames_all++; + VM_Statistics::get_vm_stats().num_unwind_native_frames_all++; #endif M2nFrame * current_m2n_frame = si->m2n_frame; @@ -111,7 +107,7 @@ #endif // rsp is implicitly address just beyond the frame, // callee saves registers in M2nFrame - si->jit_frame_context.rsp = (uint64) m2n_get_frame_base(current_m2n_frame); + si->jit_frame_context.rsp = (uint64)((uint64*) m2n_get_frame_base(current_m2n_frame) + 1); si->jit_frame_context.p_rbp = ¤t_m2n_frame->rbp; si->jit_frame_context.p_rip = ¤t_m2n_frame->rip; @@ -141,8 +137,7 @@ static transfer_control_stub_type gen_tr return addr; } - // FIXME: check real size of the stub - const int STUB_SIZE = 1; + const int STUB_SIZE = 68; char * stub = (char *)malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); char * ss = stub; @@ -153,15 +148,14 @@ #endif // // ************* LOW LEVEL DEPENDENCY! *************** // This code sequence must be atomic. The "atomicity" effect is achieved by - // changing the esp at the very end of the sequence. + // changing the rsp at the very end of the sequence. // rdx holds the pointer to the stack iterator (skip return ip) - ss = mov(ss, rdx_opnd, M_Base_Opnd(rsp_reg, GR_STACK_SIZE)); + ss = mov(ss, rdx_opnd, rdi_opnd); //M_Base_Opnd(rsp_reg, GR_STACK_SIZE)); // restore eax (return value) ss = get_reg(ss, rax_opnd, rdx_reg, (int64)&((StackIterator*)0)->jit_frame_context.p_rax); - // Restore callee saves registers ss = get_reg(ss, r15_opnd, rdx_reg, (int64)&((StackIterator*)0)->jit_frame_context.p_r15); @@ -173,7 +167,8 @@ #endif (int64)&((StackIterator*)0)->jit_frame_context.p_r12); ss = get_reg(ss, rbx_opnd, rdx_reg, (int64)&((StackIterator*)0)->jit_frame_context.p_rbx); - + ss = get_reg(ss, rbp_opnd, rdx_reg, + (int64)&((StackIterator*)0)->jit_frame_context.p_rbp); // cut the stack ss = mov(ss, rsp_opnd, M_Base_Opnd(rdx_reg, (int64)&((StackIterator *)0)->jit_frame_context.rsp)); @@ -185,11 +180,9 @@ #endif addr = (transfer_control_stub_type)stub; assert(ss-stub <= STUB_SIZE); -#ifndef NDEBUG - if (dump_stubs) { - dump(stub, "getaddress__transfer_control", ss-stub); - } -#endif + + DUMP_STUB(stub, "getaddress__transfer_control", ss-stub); + return addr; } diff --git vm/port/src/lil/ia32/pim/include/lil_code_generator_ia32.h vm/port/src/lil/ia32/pim/include/lil_code_generator_ia32.h index 7b82a1e..f32ffeb 100644 --- vm/port/src/lil/ia32/pim/include/lil_code_generator_ia32.h +++ vm/port/src/lil/ia32/pim/include/lil_code_generator_ia32.h @@ -31,7 +31,7 @@ class LilCodeGeneratorIa32 : public LilC LilCodeGeneratorIa32(); protected: - NativeCodePtr compile_main(LilCodeStub* , size_t*, const char*, bool); + NativeCodePtr compile_main(LilCodeStub* , size_t*); }; #endif // _LIL_CODE_GENERATOR_IA32_ diff --git vm/port/src/lil/ia32/pim/lil_code_generator_ia32.cpp vm/port/src/lil/ia32/pim/lil_code_generator_ia32.cpp index 84202dc..48e40c6 100644 --- vm/port/src/lil/ia32/pim/lil_code_generator_ia32.cpp +++ vm/port/src/lil/ia32/pim/lil_code_generator_ia32.cpp @@ -34,10 +34,6 @@ #include "m2n_ia32_internal.h" #include "vm_threads.h" #include "encoder.h" -#ifndef NDEBUG -#include "dump.h" -#endif - // Strategy: // Up to 2 standard places // Up to 4 32-bit quantities can be used as locals @@ -1464,17 +1460,13 @@ static void main_pass(LilCodeStub* cs, t } -NativeCodePtr LilCodeGeneratorIa32::compile_main(LilCodeStub* cs, size_t* stub_size, const char *stub_name, bool dump_stub) +NativeCodePtr LilCodeGeneratorIa32::compile_main(LilCodeStub* cs, size_t* stub_size) { LcgIa32PrePassInfo* data; tl::MemoryPool mem; size_t size = pre_pass(cs, &mem, &data); NativeCodePtr buf = allocate_memory(size); main_pass(cs, &mem, buf, data, stub_size); -#ifndef NDEBUG - if (dump_stub) - dump((char *)buf, stub_name, *stub_size); -#endif return buf; } diff --git vm/port/src/lil/ia32/pim/m2n_ia32.cpp vm/port/src/lil/ia32/pim/m2n_ia32.cpp old mode 100644 new mode 100755 index b2e507e..dbe967f --- vm/port/src/lil/ia32/pim/m2n_ia32.cpp +++ vm/port/src/lil/ia32/pim/m2n_ia32.cpp @@ -56,6 +56,12 @@ void m2n_set_last_frame(M2nFrame* lm2nf) p_TLS_vmthread->last_m2n_frame = lm2nf; } +VMEXPORT +void m2n_set_last_frame(VM_thread* thread, M2nFrame* lm2nf) +{ + thread->last_m2n_frame = lm2nf; +} + VMEXPORT // temporary solution for interpreter unplug M2nFrame* m2n_get_previous_frame(M2nFrame* lm2nf) { @@ -101,19 +107,40 @@ void m2n_set_frame_type(M2nFrame* m2nf, m2nf->current_frame_type = m2nf_type; } -M2nFrame* m2n_push_suspended_frame(Registers* regs) +size_t m2n_get_size() { + return sizeof(M2nFrame); +} + +void m2n_push_suspended_frame(M2nFrame* m2nf, Registers* regs) +{ + m2n_push_suspended_frame(p_TLS_vmthread, m2nf, regs); +} + +void m2n_push_suspended_frame(VM_thread* thread, M2nFrame* m2nf, Registers* regs) { - M2nFrame* m2nf = (M2nFrame*)STD_MALLOC(sizeof(M2nFrame)); assert(m2nf); m2nf->p_lm2nf = (M2nFrame**)1; m2nf->method = NULL; m2nf->local_object_handles = NULL; + m2nf->current_frame_type = FRAME_UNKNOWN; m2nf->eip = regs->eip; m2nf->regs = regs; - m2nf->prev_m2nf = m2n_get_last_frame(); - m2n_set_last_frame(m2nf); + m2nf->prev_m2nf = m2n_get_last_frame(thread); + m2n_set_last_frame(thread, m2nf); +} + +M2nFrame* m2n_push_suspended_frame(Registers* regs) +{ + return m2n_push_suspended_frame(p_TLS_vmthread, regs); +} + +M2nFrame* m2n_push_suspended_frame(VM_thread* thread, Registers* regs) +{ + M2nFrame* m2nf = (M2nFrame*)STD_MALLOC(sizeof(M2nFrame)); + assert(m2nf); + m2n_push_suspended_frame(thread, m2nf, regs); return m2nf; } diff --git vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp index d2b15db..922a762 100644 --- vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp +++ vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Intel, Pavel Afremov - * @version $Revision: 1.1.2.1.4.4 $ + * @version $Revision$ */ @@ -32,10 +33,7 @@ #include "interpreter.h" #include "clog.h" -#ifndef NDEBUG #include "dump.h" -extern bool dump_stubs; -#endif // Invariants: // Native frames: @@ -64,7 +62,7 @@ struct StackIterator { static void si_unwind_from_m2n(StackIterator* si) { #ifdef VM_STATS - vm_stats_total.num_unwind_native_frames_all++; + VM_Statistics::get_vm_stats().num_unwind_native_frames_all++; #endif M2nFrame* m2nfl = si->m2nfl; @@ -155,10 +153,9 @@ #endif addr = (transfer_control_stub_type)stub; assert(ss-stub <= stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__transfer_control", ss - stub); -#endif + + DUMP_STUB(stub, "getaddress__transfer_control", ss - stub); + return addr; } @@ -327,6 +324,11 @@ M2nFrame* si_get_m2n(StackIterator* si) return si->m2nfl; } +void** si_get_return_pointer(StackIterator* si) +{ + return (void**) si->c.p_eax; +} + void si_set_return_pointer(StackIterator* si, void** return_value) { si->c.p_eax = (uint32*)return_value; diff --git vm/port/src/lil/ipf/pim/include/lil_code_generator_ipf.h vm/port/src/lil/ipf/pim/include/lil_code_generator_ipf.h index 52d7762..2235846 100644 --- vm/port/src/lil/ipf/pim/include/lil_code_generator_ipf.h +++ vm/port/src/lil/ipf/pim/include/lil_code_generator_ipf.h @@ -36,7 +36,7 @@ public: LilCodeGeneratorIpf(); protected: - NativeCodePtr compile_main(LilCodeStub* , size_t*, const char*, bool); + NativeCodePtr compile_main(LilCodeStub* , size_t*); }; #endif // _LIL_CODE_GENERATOR_IPF_ diff --git vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp index 24fc59c..9776362 100644 --- vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp +++ vm/port/src/lil/ipf/pim/lil_code_generator_ipf.cpp @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Intel, Evgueni Brevnov, Ivan Volosyuk - * @version $Revision: 1.1.2.1.4.4 $ + * @version $Revision$ */ #include <assert.h> @@ -2111,7 +2112,7 @@ LilCodeGeneratorIpf::LilCodeGeneratorIpf { } -NativeCodePtr LilCodeGeneratorIpf::compile_main(LilCodeStub* cs, size_t* stub_size, const char* stub_name, bool dump_stubs) { +NativeCodePtr LilCodeGeneratorIpf::compile_main(LilCodeStub* cs, size_t* stub_size) { // start a memory manager tl::MemoryPool m; @@ -2133,11 +2134,7 @@ NativeCodePtr LilCodeGeneratorIpf::compi emitter.copy((char*)buffer); flush_hw_cache((Byte*)buffer, *stub_size); sync_i_cache(); - -#ifndef NDEBUG - if (dump_stubs) - dump((char *)buffer, stub_name, *stub_size); -#endif + return buffer; } // compile_main diff --git vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp index dbddd2f..693a5b8 100644 --- vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp +++ vm/port/src/lil/ipf/pim/stack_iterator_ipf.cpp @@ -13,19 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @author Intel, Pavel Afremov - * @version $Revision: 1.1.2.2.4.3 $ + * @version $Revision$ */ - #define LOG_DOMAIN "port.old" #include "cxxlog.h" +#include <ostream.h> +#include <pthread.h> +#include <signal.h> #include <assert.h> -#include <ostream> using namespace std; + +#include "open/types.h" #include "jit_intf_cpp.h" #include "m2n.h" #include "m2n_ipf_internal.h" @@ -33,21 +37,12 @@ #include "method_lookup.h" #include "nogc.h" #include "vm_ipf.h" #include "vm_threads.h" -#include "vm_stats.h" -#include "open/types.h" #include "stack_iterator.h" #include "stub_code_utils.h" #include "root_set_enum_internal.h" - - -#include <pthread.h> -#include <signal.h> - -#ifndef NDEBUG #include "dump.h" -extern bool dump_stubs; -#endif +#include "vm_stats.h" // Invariants: // Note that callee saves and stacked registers below means both the pointers and the corresponding nat bits in nats_lo and nats_hi @@ -138,7 +133,7 @@ static void si_setup_stacked_registers(S static void si_unwind_from_m2n(StackIterator* si) { #ifdef VM_STATS - vm_stats_total.num_unwind_native_frames_all++; + VM_Statistic::get_vm_stats().num_unwind_native_frames_all++; #endif // First setup the stack registers for the m2n frame si->bsp = m2n_get_bsp(si->m2nfl); @@ -318,10 +313,8 @@ static transfer_control_stub_type gen_tr flush_hw_cache((Byte*)fp.addr, stub_size); sync_i_cache(); -#ifndef NDEBUG - if (dump_stubs) - dump((char *)fp.addr, "transfer_control_stub (non-LIL)", stub_size); -#endif + DUMP_STUB(fp.addr, "transfer_control_stub (non-LIL)", stub_size); + fp.gp = get_vm_gp_value(); return (transfer_control_stub_type)&fp; @@ -332,7 +325,7 @@ #endif StackIterator* si_create_from_native() { - tmn_suspend_disable_recursive(); + hythread_suspend_disable(); // Allocate iterator StackIterator* res = (StackIterator*)STD_MALLOC(sizeof(StackIterator)); assert(res); @@ -347,7 +340,7 @@ StackIterator* si_create_from_native() res->m2nfl = m2n_get_last_frame(); res->ip = 0; res->c.p_eip = &res->ip; - tmn_suspend_enable_recursive(); + hythread_suspend_enable(); return res; } @@ -365,43 +358,46 @@ StackIterator* si_create_from_native(VM_ } else { assert(thread->suspend_request > 0); - TRACE2("SIGNALLING", "thread state before " << thread << " " << thread->t[0] << " " << thread->t[1] << " " << thread->suspended_state); - //if (thread->suspended_state == NOT_SUSPENDED) - { - TRACE2("SIGNALLING", "sending SIGUSR2 to thread " << thread); - assert(thread->thread_id != 0); - - if (sem_init(&thread->suspend_self, 0, 0) != 0) { - DIE("sem_init() failed" << strerror(errno)); - } + TRACE2("SIGNALLING", "thread state before " << thread << " " << + thread->t[0] << " " << thread->t[1] << " " << thread->suspended_state); + //if (thread->suspended_state == NOT_SUSPENDED) { + TRACE2("SIGNALLING", "sending SIGUSR2 to thread " << thread); + assert(thread->thread_id != 0); + + if (sem_init(&thread->suspend_self, 0, 0) != 0) { + DIE("sem_init() failed" << strerror(errno)); + } thread->t[0] = NOT_VALID; thread->t[1] = NOT_VALID; + + TRACE2("SIGNALLING", "BEFORE KILL thread = " << thread << " killing " << thread->thread_id); - TRACE2("SIGNALLING", "BEFORE KILL thread = " << thread << " killing " << thread->thread_id); if (pthread_kill(thread->thread_id, SIGUSR2) != 0) { DIE("pthread_kill(" << thread->thread_id << ", SIGUSR2) failed :" << strerror(errno)); - } - si_reload_registers(); - TRACE2("SIGNALLING", "BEFORE WAIT thread = " << thread); - int ret; - do - { - ret = sem_wait(&thread->suspend_self); - TRACE2("SIGNALLING", "sem_wait " << (&thread->suspend_self) << - " exited, errno = " << errno); - } - while((ret != 0) && (errno == EINTR)); - TRACE2("SIGNALLING", "AFTER WAIT thread = " << thread); - sem_destroy(&thread->suspend_self); + } + + si_reload_registers(); + + TRACE2("SIGNALLING", "BEFORE WAIT thread = " << thread); + + int ret; + do { + ret = sem_wait(&thread->suspend_self); + TRACE2("SIGNALLING", "sem_wait " << (&thread->suspend_self) << + " exited, errno = " << errno); + } while((ret != 0) && (errno == EINTR)); + + TRACE2("SIGNALLING", "AFTER WAIT thread = " << thread); + + sem_destroy(&thread->suspend_self); assert(thread->suspended_state == SUSPENDED_IN_SIGNAL_HANDLER); thread->suspended_state = NOT_SUSPENDED; - // assert(thread->t[0] != NOT_VALID); - // assert(thread->t[1] != NOT_VALID); - - } - TRACE2("SIGNALLING", "thread state after " << thread << " " << thread->t[0] << " " << thread->t[1] << " " << m2n_get_last_frame(thread)); -} + // assert(thread->t[0] != NOT_VALID); + // assert(thread->t[1] != NOT_VALID); + } + + TRACE2("SIGNALLING", "thread state after " << thread << " " << thread->t[0] << " " << thread->t[1] << " " << m2n_get_last_frame(thread)); TRACE2("SIGNALLING", "stack iterator: create from native, rnat, bsp/bspstore " << thread->t[0] << " " << thread->t[1]); @@ -427,13 +423,13 @@ #elif defined (PLATFORM_NT) // Get the bspstore and rnat values of another thread from the OS. // Hopefully this will also flush the RSE of the other stack enough for our purposes. -static void get_bsp_and_rnat_from_os(VM_thread* p_thr, uint64** bspstore, uint64* rnat) -{ - VmRegisterContext context; - context.setFlag(VmRegisterContext::CF_FloatingPoint); - context.setFlag(VmRegisterContext::CF_Integer); - context.setFlag(VmRegisterContext::CF_Control); - context.getBspAndRnat(p_thr, bspstore, rnat); +static void get_bsp_and_rnat_from_os(VM_thread * thread, uint64 ** bspstore, uint64 * rnat) { + CONTEXT ctx; + ctx.ContextFlags |= CONTEXT_INTEGER; + BOOL UNREF stat = GetThreadContext(thread->thread_handle, &ctx)); + assert(stat); + *bspstore = (uint64*)ctx.RsBSPSTORE; + *rnat = ctx->RsRNAT; } StackIterator* si_create_from_native(VM_thread* thread) @@ -462,7 +458,7 @@ StackIterator* si_create_from_native(VM_ } #else -#error +#error Stack iterator is not implemented for the given platform #endif // On IPF stack iterators must be created from threads (suspended) in native code. diff --git vm/port/src/lil/lil.cpp vm/port/src/lil/lil.cpp index fc11919..fae4a89 100644 --- vm/port/src/lil/lil.cpp +++ vm/port/src/lil/lil.cpp @@ -691,6 +691,7 @@ static bool lil_parse_address(const char if (!lil_parse_number(src, va, &n)) return false; } else { i->u.ldst.is_index = false; + i->u.ldst.scale = 0; } i->u.ldst.offset = sign * (POINTER_SIZE_SINT) n; if (!lil_parse_kw(src, ":")) return false; diff --git vm/port/src/lil/lil_code_generator.cpp vm/port/src/lil/lil_code_generator.cpp old mode 100644 new mode 100755 index ad5345e..bb9d817 --- vm/port/src/lil/lil_code_generator.cpp +++ vm/port/src/lil/lil_code_generator.cpp @@ -22,6 +22,7 @@ #include "nogc.h" #include "jvmti_direct.h" #include "environment.h" +#include "compile.h" #include "jit_intf.h" #include "lil.h" @@ -52,17 +53,16 @@ LilCodeGenerator::LilCodeGenerator() { } -NativeCodePtr LilCodeGenerator::compile(LilCodeStub* cs, const char* name, bool dump_stub) +NativeCodePtr LilCodeGenerator::compile(LilCodeStub* cs) { size_t stub_size; - NativeCodePtr stub = compile_main(cs, &stub_size, name, dump_stub); + NativeCodePtr stub = compile_main(cs, &stub_size); lil_cs_set_code_size(cs, stub_size); + compile_add_dynamic_generated_code_chunk("unknown", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk(name, stub, stub_size); - jvmti_send_dynamic_code_generated_event(name, stub, stub_size); - } + jvmti_send_dynamic_code_generated_event("unknown", stub, stub_size); return stub; } diff --git vm/port/src/lil/pim/stack_iterator.cpp vm/port/src/lil/pim/stack_iterator.cpp new file mode 100755 index 0000000..94cf175 --- /dev/null +++ vm/port/src/lil/pim/stack_iterator.cpp @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ + + +#include "interpreter.h" +#include "jit_intf_cpp.h" +#include "m2n.h" +#include "stack_iterator.h" + +Method_Handle si_get_method(StackIterator* si) +{ + ASSERT_NO_INTERPRETER + CodeChunkInfo* cci = si_get_code_chunk_info(si); + if (cci) + return cci->get_method(); + else + return m2n_get_method(si_get_m2n(si)); +} + +uint32 si_get_inline_depth(StackIterator* si) +{ + // + // Here we assume that JIT data blocks can store only InlineInfo + // A better idea is to extend JIT_Data_Block with some type information + // Example: + // + // enum JIT_Data_Block_Type { InlineInfo, Empty } + // + // struct JIT_Data_Block { + // JIT_Data_Block *next; + // JIT_Data_Block_Type type; + // char bytes[1]; + // }; + // + // void *Method::allocate_JIT_data_block(size_t size, JIT *jit, JIT_Data_Block_Type) + // + + ASSERT_NO_INTERPRETER + CodeChunkInfo* cci = si_get_code_chunk_info(si); + if ( cci != NULL && cci->has_inline_info()) { + return cci->get_jit()->get_inline_depth( + cci->get_inline_info(), + (POINTER_SIZE_INT)si_get_ip(si) - (POINTER_SIZE_INT)cci->get_code_block_addr()); + } + return 0; +} diff --git vm/port/src/misc/linux/env.c vm/port/src/misc/linux/env.c new file mode 100644 index 0000000..ef0c56c --- /dev/null +++ vm/port/src/misc/linux/env.c @@ -0,0 +1,27 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ + +#include "port_env.h" + +extern char** environ; + +APR_DECLARE(char **) port_env_all(apr_pool_t* pool){ + return environ; +} diff --git vm/port/src/misc/linux/timer.c vm/port/src/misc/linux/timer.c new file mode 100644 index 0000000..f49c1dc --- /dev/null +++ vm/port/src/misc/linux/timer.c @@ -0,0 +1,46 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ + +#include <sys/time.h> +#include "port_timer.h" + +static apr_nanotimer_t initNanoTime() { + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + return (apr_nanotimer_t)tv.tv_sec; +} + + +APR_DECLARE(apr_nanotimer_t) port_nanotimer() +{ + static apr_nanotimer_t init_sec = 0; + struct timeval tv; + struct timezone tz; + if (!init_sec) { + init_sec = initNanoTime(); + } + + gettimeofday(&tv, &tz); + + return (apr_nanotimer_t) + (((apr_nanotimer_t)tv.tv_sec - init_sec) * 1E9 + (apr_nanotimer_t)tv.tv_usec * 1E3); +} diff --git vm/port/src/misc/win/env.c vm/port/src/misc/win/env.c new file mode 100644 index 0000000..2def0f1 --- /dev/null +++ vm/port/src/misc/win/env.c @@ -0,0 +1,27 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ + +#include <stdlib.h> +#include "port_env.h" + +APR_DECLARE(char **) port_env_all(apr_pool_t* pool){ + //TBD _wenviron support + return _environ; +} diff --git vm/port/src/misc/win/timer.c vm/port/src/misc/win/timer.c new file mode 100644 index 0000000..c43fef4 --- /dev/null +++ vm/port/src/misc/win/timer.c @@ -0,0 +1,57 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ + +#include <time.h> +#include <windows.h> + +#include "port_timer.h" + +#undef LOG_DOMAIN +#define LOG_DOMAIN "port.timer" +#include "clog.h" + +static LARGE_INTEGER frequency; + +static BOOL initNanoTime() { + if (QueryPerformanceFrequency(&frequency)) { + return TRUE; + } else { + TRACE(("QueryPerformanceFrequency failed: %u", GetLastError())); + return FALSE; + } +} + +APR_DECLARE(apr_nanotimer_t) port_nanotimer() +{ + static BOOL hires_supported; + static BOOL init = FALSE; + if (!init) { + hires_supported = initNanoTime(); + } + if(hires_supported){ + LARGE_INTEGER count; + if (QueryPerformanceCounter(&count)) { + return (apr_nanotimer_t)((double)count.QuadPart / frequency.QuadPart * 1E9); + } else { + TRACE(("QueryPerformanceCounter failed: %u", GetLastError())); + } + } + return (apr_nanotimer_t)(GetTickCount() * 1E6); +} diff --git vm/port/src/thread/linux/apr_thread_ext.c vm/port/src/thread/linux/apr_thread_ext.c index a98d15d..cbe00d2 100644 --- vm/port/src/thread/linux/apr_thread_ext.c +++ vm/port/src/thread/linux/apr_thread_ext.c @@ -1,6 +1,7 @@ #include "apr_thread_ext.h" //#include "apr_arch_threadproc.h" #include <pthread.h> +#define __USE_XOPEN2K 1 #include <semaphore.h> int convert_priority(apr_int32_t priority); @@ -57,6 +58,9 @@ static void init_thread_yield_other () { APR_DECLARE(apr_status_t) apr_thread_yield_other(apr_thread_t* thread) { apr_status_t status; pthread_t *os_thread; + struct timespec timeout; + timeout.tv_sec = 1; + timeout.tv_nsec = 0; pthread_mutex_lock(&yield_other_mutex); if (!yield_other_init_flag) { @@ -68,8 +72,12 @@ APR_DECLARE(apr_status_t) apr_thread_yie pthread_mutex_unlock(&yield_other_mutex); return status; } - if(!(pthread_kill(*os_thread, SIGUSR2))) { - sem_wait(&yield_other_sem); + if((pthread_kill(*os_thread, SIGUSR2))) { + } else + { + // let's do timed wait to workaroud missed signals + // sem_wait(&yield_other_sem); + sem_timedwait(&yield_other_sem,&timeout); } pthread_mutex_unlock(&yield_other_mutex); return APR_SUCCESS; @@ -128,6 +136,37 @@ APR_DECLARE(apr_status_t) apr_thread_tim return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_get_thread_time(apr_thread_t *thread, unsigned long long* nanos_ptr) +{ + clockid_t clock_id; + pthread_t *os_thread; + struct timespec tp; + apr_status_t status; + int res; + if (!thread) + return APR_DETACH; + status = apr_os_thread_get((apr_os_thread_t**)&os_thread, thread); + if(status!=APR_SUCCESS) + { + return status; + } + + res = pthread_getcpuclockid(*os_thread, &clock_id); + if (0 != res) + { + return APR_ENOTIME; + } + res = clock_gettime(clock_id, &tp); + + if (0 != res) + { + return APR_ENOTIME; + } + + *nanos_ptr = tp.tv_sec * 1000000000ULL + tp.tv_nsec; + return APR_SUCCESS; +} + APR_DECLARE(apr_status_t) apr_thread_cancel(apr_thread_t *thread) { apr_os_thread_t *os_thread; apr_status_t status = apr_os_thread_get(&os_thread, thread); diff --git vm/port/src/thread/win/apr_thread_ext.c vm/port/src/thread/win/apr_thread_ext.c index d345133..e148bea 100644 --- vm/port/src/thread/win/apr_thread_ext.c +++ vm/port/src/thread/win/apr_thread_ext.c @@ -103,6 +103,23 @@ APR_DECLARE(apr_status_t) apr_thread_tim return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_get_thread_time(apr_thread_t *thread, unsigned long long* nanos_ptr) +{ + HANDLE *os_thread; + apr_status_t status; + FILETIME creation_time, exit_time, kernel_time, user_time; + if (status = apr_os_thread_get(&((apr_os_thread_t *)os_thread), thread)!=APR_SUCCESS) { + return status; + } + GetThreadTimes(os_thread, &creation_time, + &exit_time, &kernel_time, + &user_time); + + *nanos_ptr=(Int64ShllMod32((&user_time)->dwHighDateTime, 32)|(&user_time)->dwLowDateTime);//*100; + // *nanos_ptr = user_time * 100; // convert to nanos + return APR_SUCCESS; +} + APR_DECLARE(apr_status_t) apr_thread_cancel(apr_thread_t *thread) { HANDLE *os_thread; apr_status_t status; diff --git vm/tests/kernel/java/lang/Class1_5Test.java vm/tests/kernel/java/lang/Class1_5Test.java new file mode 100644 index 0000000..1908e1e --- /dev/null +++ vm/tests/kernel/java/lang/Class1_5Test.java @@ -0,0 +1,524 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/* + * Created on 28.05.2005 + * + * This Class1_5Test class is used to test the extention of the + * Core API Class class to 1.5 + * + */ + +@Documented +@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME) +@Target(value=java.lang.annotation.ElementType.TYPE) +@interface zzz { + public int id() default 777; + public String date() default "[unimplemented]"; +} + +public class Class1_5Test extends TestCase { + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + /** + * + */ + public void test_isAnonymousClass_V() { + class e {};//Class1_5Test$1e.class + assertFalse("Non-anonymous class is indicated as anonymous!", + (new e()).getClass().isAnonymousClass()); + assertTrue("anonymous class is indicated as non-anonymous!", + (new e() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}).getClass().isAnonymousClass()); + } + + /** + * + */ + enum x{aaa;}; + public void test_isEnum_V() { + class e {}; + assertFalse("Non-enum class is indicated as enum!", e.class.isEnum()); + assertTrue("enum class is indicated as non-enum!", x.class.isEnum()); + } + + /** + * + */ + public void test_isLocalClass_V() { + class e {}; + assertFalse("Non-local class is indicated as local!", + x.class.isLocalClass()); + assertTrue("local class is indicated as non-local!", + e.class.isLocalClass()); + } + + /** + * + */ + public void test_isMemberClass_V() { + class e {}; + assertFalse("Non-member class is indicated as member!", + e.class.isMemberClass()); + assertTrue("member class is indicated as non-member!", + x.class.isMemberClass()); + } + + /** + * + */ + public void test_isSynthetic_V() { + class e {}; + assertFalse("Non-synthetic class is indicated as synthetic!", + e.class.isSynthetic()); + //assertTrue("synthetic class is indicated as non-synthetic!", + // (new e() { int i; }).getClass().isSynthetic()); + } + + /** + * + */ + public void test_isAnnotation_V() { + class e {}; + assertFalse("Non-annotation class is indicated as annotation!", + e.class.isAnnotation()); + assertTrue("annotation class is indicated as non-annotation!", + zzz.class.isAnnotation()); + } + + /** + * + */ + public void test_isAnnotationPresent_Cla() { + class e {}; + assertFalse("zzz annotation is not presented for e class!", + e.class.isAnnotationPresent(zzz.class)); + assertFalse("zzz annotation is not presented for zzz class!", + zzz.class.isAnnotationPresent(zzz.class)); + assertTrue("Target annotation is presented for zzz class!", + zzz.class.isAnnotationPresent(java.lang.annotation + .Target.class)); + assertTrue("Documented annotation is presented for zzz class!", + zzz.class.isAnnotationPresent(java.lang.annotation + .Documented.class)); + assertTrue("Retention annotation is presented for zzz class!", + zzz.class.isAnnotationPresent(java.lang.annotation + .Retention.class)); + } + + /** + * + */ +// enum xx{A(77),B(55),C(33);xx(int i) {this.value = i;}}; + enum xx{A,B,C;}; + public void test_getEnumConstants_V() { + //assertTrue("FAILED: test_getEnumConstants_V.check001: Non-enum class is indicated as enum!", xx.class.getEnumConstants()[0].value() == 77); + assertTrue("The first constant should be xx.A!", + xx.class.getEnumConstants()[0] == xx.A); + assertTrue("The second constant should not be xx.A!", + xx.class.getEnumConstants()[1] != xx.A); + assertTrue("The third constant should be xx.C!", + xx.class.getEnumConstants()[2] == xx.C); + } + + /** + * + */ + class e {}; + //class gg {class gga {class ggb {class ggc {}; class ggg {public int id() {class f {};class ff {};class ff2 {public void vd() {Object ooo = new e() { int i; };}};return 999;}};};};}; + public class gg { + public class gga { + public gga(){}; + public class ggb { + public ggb(){}; + class ggc {}; + public class ggg { + public ggg(){}; + public Object id() { + class f {}; + class ff {}; + class ff2 { + public Object vd() { + Object ooo = new e() { int i; int m1(){vd(); return i+m2();}; int m2(){return i+m1();}}; + return ooo; + } + public Object vd2() { + return vd()==null?vd3():vd(); + } + public Object vd3() { + return vd()==null?vd2():vd(); + } + }; + return new ff2(); + } + }; + public Object gggO() { + return new ggg(); + } + }; + public Object ggbO() { + return new ggb(); + } + }; + public Object ggaO() { + new e() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}; + return new gga(); + } + }; + public void test_getSimpleName_V() { + class e {}; + try { + //########################################################################################################## + //########################################################################################################## + //\\assertTrue("FAILED: test_getSimpleName_V.check001: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1 should be empty!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1").getSimpleName().equals("")); + //\\assertTrue("FAILED: test_getSimpleName_V.check002: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2 should be ff2!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2").getSimpleName().equals("ff2")); + // to avoid bug of local classes naming in org.eclipse.jdt.core.JDTCompilerAdapter + // ("Class1_5Test$1ff2" instead of "Class1_5Test$gg$gga$ggb$ggg$1ff2") + try { + Object o1, o2, o3, o4, o5; + o1 = new gg(); + o2 = o1.getClass().getMethod("ggaO").invoke(o1/*, null*/); + o3 = o2.getClass().getMethod("ggbO").invoke(o2/*, null*/); + o4 = o3.getClass().getMethod("gggO").invoke(o3/*, null*/); + //\\assertTrue("FAILED: test_getSimpleName_V.check001: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1 should be empty!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1").getSimpleName().equals("")); + assertTrue("check001: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1 should be empty!", (o5 = o4.getClass().getMethod("id").invoke(o4/*, null*/)).getClass().getMethod("vd").invoke(o5/*, null*/).getClass().getSimpleName().equals("")); + //\\assertTrue("check002: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2 should be ff2!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2").getSimpleName().equals("ff2")); + assertTrue("check002: Simple name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2 should be ff2!", (o5 = o4.getClass().getMethod("id").invoke(o4/*, null*/)).getClass().getMethod("vd").invoke(o5/*, null*/).getClass().getEnclosingClass().getSimpleName().equals("ff2")); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + fail("exception check001"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + fail("exception check002"); + } catch (java.lang.reflect.InvocationTargetException e) { + e.printStackTrace(); + fail("exception check003"); + } + //########################################################################################################## + //########################################################################################################## + assertTrue("check003: Simple name for " + + "java.lang.Class1_5Test$gg$gga$ggb$ggc should be ggc!", + Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggc") + .getSimpleName().equals("ggc")); + assertTrue("check004: Simple name for " + + "java.lang.Class1_5Test$1 should be empty!", + Class.forName("java.lang.Class1_5Test$1") + .getSimpleName().equals("")); + Class c = (new Object() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}).getClass(); + assertTrue("check005: Simple name for " + + "\"(new Object() { int i; })\" should be empty!", + c.getSimpleName().equals("")); + c = (new e() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}).getClass(); + assertTrue("check006: Simple name for " + + "\"(new e() { int i; })\" should be empty!", + c.getSimpleName().equals("")); + assertTrue("check007: Simple name for " + + "java.lang.Class1_5Test$1e should be e!", + e.class.getSimpleName().equals("e")); + } catch (Exception e) { + e.printStackTrace(); + fail("check008: Error of the class loading!"); + } + } + + /** + * + */ + public void test_getEnclosingClass_V() { + class e {}; + try { + //########################################################################################################## + //########################################################################################################## + // to avoid bug of local classes naming in org.eclipse.jdt.core.JDTCompilerAdapter + // ("Class1_5Test$1ff2" instead of "Class1_5Test$gg$gga$ggb$ggg$1ff2") + try { + Object o1, o2, o3, o4, o5; + o1 = new gg(); + o2 = o1.getClass().getMethod("ggaO").invoke(o1/*, null*/); + o3 = o2.getClass().getMethod("ggbO").invoke(o2/*, null*/); + o4 = o3.getClass().getMethod("gggO").invoke(o3/*, null*/); + //\\//\\if(!(o5 = o4.getClass().getMethod("id").invoke(o4/*, null*/)).getClass().getMethod("vd").invoke(o5/*, null*/).getClass().getName().equals("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1")) fail("test_3, case 019 FAILED"); + if(!(o5 = o4.getClass().getMethod("id").invoke(o4/*, null*/)).getClass().getMethod("vd").invoke(o5/*, null*/).getClass().getName().matches("java\\.lang\\.Class1_5Test.*1ff2\\$1")) fail("test_3, case 019 FAILED"); + if(!(o5 = o4.getClass().getMethod("id").invoke(o4/*, null*/)).getClass().getMethod("vd").invoke(o5/*, null*/).getClass().getEnclosingClass().getName().matches("java\\.lang\\.Class1_5Test.*1ff2")) fail("test_3, case 019 FAILED"); + //if(!(o = gg.gga.ggb.ggg.class.getMethod("id").invoke(java.lang.Class1_5Test.gg.gga.ggb.ggg.class.newInstance(), null)).getClass().getMethod("vd").invoke(o, null).getClass().getName().equals("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1")) fail("test_3, case 019 FAILED"); + //\\//\\assertTrue("FAILED: test_getEnclosingClass_V.check001: Simple name of enclosing class for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1 should be ff2!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1").getEnclosingClass().getSimpleName().equals("ff2")); + assertTrue("check001: Simple name of enclosing class for " + + "java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1" + + " should be ff2!", + (o5 = o4.getClass().getMethod("id") + .invoke(o4/*, null*/)).getClass() + .getMethod("vd").invoke(o5/*, null*/) + .getClass().getEnclosingClass() + .getSimpleName().equals("ff2")); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + fail("check003"); + } catch(IllegalAccessException e) { + e.printStackTrace(); + fail("check004"); + } catch(java.lang.reflect.InvocationTargetException e) { + e.printStackTrace(); + fail("check005"); + } + //########################################################################################################## + //########################################################################################################## + } catch (Exception e) { + e.printStackTrace(); + assertTrue("check002: Error of the class loading!", false); + } + } + + /** + * + */ + public void test_getDeclaredAnnotations_V() { + assertFalse("Target annotation is presented for zzz class!", + zzz.class.getDeclaredAnnotations()[0].toString() + .indexOf("java.lang.annotation.Documented") == -1); + assertFalse("Documented annotation is presented for zzz class!", + zzz.class.getDeclaredAnnotations()[1].toString() + .indexOf("java.lang.annotation.Retention") == -1); + assertFalse("Retention annotation is presented for zzz class!", + zzz.class.getDeclaredAnnotations()[2].toString() + .indexOf("java.lang.annotation.Target") == -1); + } + + /** + * + */ + @zzz() enum www{aaa;}; + public void test_Annotations_V() { + assertFalse("zzz annotation is presented for www enum!", + www.class.getAnnotations()[0].toString() + .indexOf("java.lang.zzz") == -1); + assertEquals("Only one annotation is presented in enum www!", + 1, + www.class.getAnnotations().length); + } + + /** + * + */ + public void test_getCanonicalName_V() { + class e {}; + try { + //########################################################################################################## + //########################################################################################################## + // to avoid bug of local classes naming in org.eclipse.jdt.core.JDTCompilerAdapter + // ("Class1_5Test$1ff2" instead of "Class1_5Test$gg$gga$ggb$ggg$1ff2") + //\\//\\assertTrue("FAILED: test_getCanonicalName_V.check001: Canonical name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1 should be null!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1").getCanonicalName() == null); + //\\//\\assertTrue("FAILED: test_getCanonicalName_V.check002: Canonical name for java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2 should be null!", Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2").getCanonicalName() == null); + try { + Object o1, o2, o3, o4, o5; + o1 = new gg(); + o2 = o1.getClass().getMethod("ggaO").invoke(o1/*, null*/); + o3 = o2.getClass().getMethod("ggbO").invoke(o2/*, null*/); + o4 = o3.getClass().getMethod("gggO").invoke(o3/*, null*/); + assertNull("check001: Canonical name for " + + "java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2$1" + + "should be null!", + (o5 = o4.getClass().getMethod("id") + .invoke(o4/*, null*/)).getClass() + .getMethod("vd").invoke(o5/*, null*/) + .getClass().getCanonicalName()); + assertNull("check002: Canonical name for " + + "java.lang.Class1_5Test$gg$gga$ggb$ggg$1ff2" + + "should be null!", + (o5 = o4.getClass().getMethod("id") + .invoke(o4/*, null*/)).getClass() + .getMethod("vd").invoke(o5/*, null*/) + .getClass().getEnclosingClass() + .getCanonicalName()); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + fail("exception check001"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + fail("exception check002"); + } catch (java.lang.reflect.InvocationTargetException e) { + e.printStackTrace(); + fail("exception check003"); + } + //########################################################################################################## + //########################################################################################################## + assertEquals("check003: incorrrect canonical name for " + + "java.lang.Class1_5Test$gg$gga$ggb$ggc:", + "java.lang.Class1_5Test.gg.gga.ggb.ggc", + Class.forName("java.lang.Class1_5Test$gg$gga$ggb$ggc") + .getCanonicalName()); + assertNull("check004: Canonical name for " + + "java.lang.Class1_5Test$1 should be null!", + Class.forName("java.lang.Class1_5Test$1") + .getCanonicalName()); + Class c = (new Object() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}).getClass(); + assertNull("check005: Canonical name for " + + "\"(new Object() { int i; })\" should be null!", + c.getCanonicalName()); + c = (new e() { int i; int m1(){return i+m2();}; int m2(){return i+m1();}}).getClass(); + assertNull("check006: Canonical name for " + + "\"(new e() { int i; })\" should be null!", + c.getCanonicalName()); + assertNull("check007: Canonical name for " + + "java.lang.Class1_5Test$1e should be null!", + e.class.getCanonicalName()); + } catch (Exception e){ + fail("check008: Error of the class loading!"); + } + } + + /** + * + */ + public void test_getAnnotation_Cla() { + class e {}; + assertNull("zzz annotation is not presented in e class!", + e.class.getAnnotation(zzz.class)); + assertNull("zzz annotation is not presented in zzz class!", + zzz.class.getAnnotation(zzz.class)); + assertFalse("Target annotation is presented in zzz class!", + zzz.class.getAnnotation(java.lang.annotation.Target.class) + .toString().indexOf("java.lang.annotation.Target") == -1); + assertFalse("Documented annotation is presented in zzz class!", + zzz.class.getAnnotation(java.lang.annotation.Documented.class) + .toString().indexOf("java.lang.annotation.Documented") == -1); + assertFalse("Retention annotation is presented in zzz class!", + zzz.class.getAnnotation(java.lang.annotation.Retention.class) + .toString().indexOf("java.lang.annotation.Retention") == -1); + } + + /** + * + */ + public void test_cast_Cla() { + class e {}; + class ee extends e {}; + class eee extends ee {}; + try { + ee.class.cast((Object)new eee()); + } catch (ClassCastException _) { + fail("Object of eee can be casted to Object of ee class!"); + } + try { + eee.class.cast((Object)new e()); + fail("Object of e cannott be casted to Object of eee class"); + } catch (ClassCastException _) { + return; + } + } + + /** + * + */ + public void test_asSubclass_Cla() { + class e {}; + class ee extends e {}; + class eee extends ee {}; + try { + eee.class.asSubclass(ee.class); + } catch (ClassCastException _) { + fail("eee class can be casted to represent a subclass of ee!"); + } + try { + e.class.asSubclass(eee.class); + fail("e class cannot be casted to represent a subclass of eee!"); + } catch (ClassCastException _) { + return; + } + } + + /** + * + */ + public void test_getEnclosingMethod_V() { + class e {}; + class ee extends e {}; + class eee extends ee {}; + assertFalse("ee class is declared within " + "" + + "test_getEnclosingMethod_V method!", + eee.class.getEnclosingMethod().toString() + .indexOf("test_getEnclosingMethod_V") == -1); + } + + /** + * + */ + public void test_getEnclosingConstructor_V() { + class eklmn { + eklmn() { + class ee { + }; + assertFalse("ee class is declared within eklmn constructor!", + ee.class.getEnclosingConstructor().toString() + .indexOf("eklmn") == -1); + } + }; + new eklmn(); + } + + /** + * + */ + public void test_getGenericSuperclass_V() { + class e1 {}; + class e2 extends e1 {}; + class e3 extends e2 {}; + assertFalse("e2 is generic superclass for e3!", + e3.class.getGenericSuperclass().toString() + .indexOf("e2") == -1); + } + + /** + * + */ + interface e1 {}; + interface e2 extends e1 {}; + public void test_getGenericInterfaces_V() { + class e3 implements e2 {}; + assertFalse("e2 is genericaly implemented by e3!", + e3.class.getGenericInterfaces()[0].toString() + .indexOf("e2") == -1); + } + + /** + * + */ + public void test_getTypeParameters_V() { + class e3<T1, T2> implements e2 {}; + assertFalse("T1 is type parameter for e3!", + e3.class.getTypeParameters()[0].toString() + .indexOf("T1") == -1); + assertFalse("T2 is type parameter for e3!", + e3.class.getTypeParameters()[1].toString() + .indexOf("T2") == -1); + } + } diff --git vm/tests/kernel/java/lang/Class5Test.java vm/tests/kernel/java/lang/Class5Test.java new file mode 100644 index 0000000..c3a56e5 --- /dev/null +++ vm/tests/kernel/java/lang/Class5Test.java @@ -0,0 +1,227 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.List; + +import notfound.MissingAntn; + +import org.apache.harmony.lang.AnnotatedElementTestFrame; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn; + +/** + * Test of the {@link java.lang.reflect.AnnotatedElement AnnotatedElement} + * functionality in {@link java.lang.Class java.lang.Class} class. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class Class5Test extends AnnotatedElementTestFrame { + + public static void main(String[] args) { + junit.textui.TestRunner.run(Class5Test.class); + } + + @TagAntn interface First {} + + protected @Override AnnotatedElement getElement1() throws Throwable { + return First.class; + } + + protected @Override AnnotatedElement getElement2() throws Throwable { + @TagAntn @ValAntn class Second {} + return Second.class; + } + + protected @Override AnnotatedElement getElement3() throws Throwable { + return Third.class; + } + + protected @Override AnnotatedElement getElement4() throws Throwable { + @MissingAntn class Fourth {} + return Fourth.class; + } + + protected @Override AnnotatedElement getElement5() throws Throwable { + @MissingClassValAntn class X {} + return X.class; + } + + protected @Override AnnotatedElement getElement6() throws Throwable { + @MissingTypeAntn class X {} + return X.class; + } + + /** + * For Class instances, getAnnotations() must return + * annotations declared + inherited from superclasses. + */ + public void testGetAnnotationsInherited() throws Throwable { + Annotation[] an = C4.class.getDeclaredAnnotations(); + assertNotNull("declared in C4", an); + assertEquals("number of Declared Annotations in C4", 1, an.length); + assertSame("declared in C4", TagAntn.class, an[0].annotationType()); + + Annotation[] an2 = C4.class.getAnnotations(); + assertNotNull("all in C4", an2); + assertEquals("number of all Annotations in C4", 3, an2.length); + + List<Class> la = Arrays.asList(new Class[] { + an2[0].annotationType(), an2[1].annotationType(), + an2[2].annotationType()}); + assertTrue("1st annotation", la.contains(SuperTagAntn.class)); + assertTrue("2nd annotation", la.contains(TagAntn.class)); + assertTrue("3rd annotation", la.contains(SuperValAntn.class)); + } + + /** + * For Class instances, getAnnotations() + * must not return annotations inherited from superinterfaces. + */ + public void testGetAnnotationsInherited2() throws Throwable { + Annotation[] an = I3.class.getAnnotations(); + assertNotNull("all in I3", an); + assertEquals("number of Annotations in I3", 1, an.length); + assertSame("annotation of I3", TagAntn.class, an[0].annotationType()); + + Annotation[] an2 = CI1.class.getAnnotations(); + assertNotNull("all in CI1", an2); + assertEquals("number of all Annotations in CI1", 1, an2.length); + assertSame("annotation of CI1", ValAntn.class, an2[0].annotationType()); + + Annotation[] an3 = CI2.class.getAnnotations(); + assertNotNull("all in CI2", an3); + assertEquals("number of all Annotations in CI2", 1, an3.length); + assertSame("annotation of CI2", SuperValAntn.class, an3[0].annotationType()); + assertSame("annotation value of CI2", CI2.class, + ((SuperValAntn)an3[0]).value()); + } + + /** + * For Class instances, annotations inherited from a superclass + * may be overriden by descendants. + * In this case getAnnotations() must return + * annotations declared + non-overriden inherited. + */ + public void testGetAnnotationsInheritedOverriden() throws Throwable { + Annotation[] an = C6.class.getDeclaredAnnotations(); + assertNotNull("declared in C6", an); + assertEquals("number of Declared Annotations in C6", 1, an.length); + assertSame("declared in C6", SuperValAntn.class, an[0].annotationType()); + + Annotation[] an2 = C6.class.getAnnotations(); + assertNotNull("all in C6", an2); + assertEquals("number of all Annotations in C6", 2, an2.length); + + List<Class> la = Arrays.asList(new Class[] { + an2[0].annotationType(), an2[1].annotationType(), }); + assertTrue("C6 1st annotation", la.contains(SuperTagAntn.class)); + assertTrue("C6 2rd annotation", la.contains(SuperValAntn.class)); + + Annotation[] an3 = C7.class.getAnnotations(); + assertNotNull("declared in C7", an3); + assertEquals("number of all Annotations in C7", 2, an3.length); + + List<Class> la3 = Arrays.asList(new Class[] { + an3[0].annotationType(), an3[1].annotationType(), }); + assertTrue("C7 1st annotation", la3.contains(SuperTagAntn.class)); + assertTrue("C7 2rd annotation", la3.contains(SuperValAntn.class)); + } + + /** + * For Class instances, isAnnotationPresent() must account for + * annotations declared + inherited from superclasses. + */ + public void testIsAnnotationPresentInherited() throws Throwable { + assertTrue("case 1", C4.class.isAnnotationPresent(SuperTagAntn.class)); + assertTrue("case 2", C4.class.isAnnotationPresent(SuperValAntn.class)); + assertTrue("case 3", C4.class.isAnnotationPresent(TagAntn.class)); + assertTrue("case 4", C6.class.isAnnotationPresent(SuperTagAntn.class)); + assertTrue("case 5", C6.class.isAnnotationPresent(SuperValAntn.class)); + assertTrue("case 6", C5.class.isAnnotationPresent(SuperTagAntn.class)); + } + + /** + * For Class instances, isAnnotationPresent() must not account for + * non-inheritable annotations from superclasses. + */ + public void testIsAnnotationPresentInherited_Negative() throws Throwable { + assertFalse("case 1", C4.class.isAnnotationPresent(ValAntn.class)); + assertFalse("case 2", C4.class.isAnnotationPresent(None.class)); + assertFalse("case 3", C5.class.isAnnotationPresent(TagAntn.class)); + assertFalse("case 4", C6.class.isAnnotationPresent(TagAntn.class)); + assertFalse("case 5", C6.class.isAnnotationPresent(ValAntn.class)); + assertFalse("case 6", C5.class.isAnnotationPresent(None.class)); + } + + /** + * For Class instances, getAnnotation() must account for + * annotations declared + inherited from superclasses. + */ + public void testGetAnnotationInherited() throws Throwable { + SuperValAntn an = C5.class.getAnnotation(SuperValAntn.class); + assertNotNull(an); + assertSame("value of inherited annotation", C3.class, an.value()); + } + + /** + * For Class instances, annotations inherited from a superclass + * may be overriden by descendants. + * In this case getAnnotation() must return latest overriden annotation. + */ + public void testGetAnnotationInheritedOverriden() throws Throwable { + SuperValAntn an = C6.class.getAnnotation(SuperValAntn.class); + assertNotNull("overriden in C6", an); + assertSame("value of overriden annotation in C6", C6.class, an.value()); + + SuperValAntn an2 = C7.class.getAnnotation(SuperValAntn.class); + assertNotNull("overriden in C7", an2); + assertSame("value of overriden annotation in C7", C6.class, an2.value()); + } +} + +@interface Third {} + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@interface SuperTagAntn {} + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@interface SuperValAntn { + Class value(); +} + +@SuperTagAntn class C1 {} +@ValAntn class C2 extends C1 {} +@SuperValAntn(C3.class) class C3 extends C2 {} +@TagAntn class C4 extends C3 {} +class C5 extends C4 {} +@SuperValAntn(C6.class) class C6 extends C5 {} +class C7 extends C6 {} + +@SuperTagAntn interface I1 {} +@SuperValAntn(I2.class) interface I2 {} +@TagAntn interface I3 extends I1, I2 {} +@ValAntn class CI1 implements I3 {} +@SuperValAntn(CI2.class) class CI2 extends CI1 {} diff --git vm/tests/kernel/java/lang/ClassAnnotationsTest.java vm/tests/kernel/java/lang/ClassAnnotationsTest.java new file mode 100644 index 0000000..3f90b15 --- /dev/null +++ vm/tests/kernel/java/lang/ClassAnnotationsTest.java @@ -0,0 +1,2510 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +/** + * Area for supposed testing: + * - member, local, annonymous, enums, interfaces; + * - fields, + * - methods + * - constructors + * - packages + * - accessible objects + **/ + +import java.lang.annotation.Annotation; + +import junit.framework.TestCase; + +/* + * Created on April 03, 2006 + * + * This ClassHierarchyTest class is used to test the Core API Class class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(value=RetentionPolicy.RUNTIME) +@interface iat{ + abstract String author() default "Zapreyev"; +}; +@Retention(value=RetentionPolicy.RUNTIME) +@interface j{}; +@Retention(value=RetentionPolicy.SOURCE) +@interface k{}; +@Retention(value=RetentionPolicy.CLASS) +@interface l{}; + +@SuppressWarnings(value={"all"}) public class ClassAnnotationsTest extends TestCase { + @iat public class MC1 { + @iat public class MC1_1 { + @iat public class MC1_1_1 { + @iat public class MC1_1_1_1 { + @iat public class MC1_1_1_1_1 { + @iat public class MC1_1_1_1_1_1 { + @iat public class MC1_1_1_1_1_1_1 { + }; + }; + }; + }; + }; + }; + }; + + @Retention(value=RetentionPolicy.RUNTIME) + @interface anna{ + abstract String author() default "Zapreyev"; + }; + @iat public class MC002<X, Y, Z> { + @iat public class MC002_1<X1, Y1, Z1> { + @iat public class MC002_1_1<X2, Y2, Z2> { + @iat public class MC002_1_1_1<X3, Y3, Z3> { + @iat public class MC002_1_1_1_1<X4, Y4, Z4> { + @iat public class MC002_1_1_1_1_1<X5, Y5, Z5> { + @iat public class MC002_1_1_1_1_1_1<X6, Y6, Z6> { + }; + }; + }; + }; + }; + }; + }; + + @Retention(value=RetentionPolicy.RUNTIME) + @interface ii{ + abstract String author() default "Zapreyev"; + @Retention(value=RetentionPolicy.RUNTIME) + @interface iii{ + abstract String author() default "Zapreyev"; + }; + }; + @iat interface MI1 { + @iat interface MI1_1 { + @iat interface MI1_1_1 { + @iat interface MI1_1_1_1 { + @iat interface MI1_1_1_1_1 { + @iat interface MI1_1_1_1_1_1 { + @iat interface MI1_1_1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String author() default "Zapreyev"; + }; + }; + }; + }; + }; + }; + }; + }; + + @iat interface MI002<X, Y, Z> { + @iat interface MI002_1<X1, Y1, Z1> { + @iat interface MI002_1_1<X2, Y2, Z2> { + @iat interface MI002_1_1_1<X3, Y3, Z3> { + @iat interface MI002_1_1_1_1<X4, Y4, Z4> { + @iat interface MI002_1_1_1_1_1<X5, Y5, Z5> { + @iat interface MI002_1_1_1_1_1_1<X6, Y6, Z6> { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String author() default "Zapreyev"; + }; + }; + }; + }; + }; + }; + }; + }; + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA7 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String authorSurname() default "Zapreyev"; + abstract String[] authorFullName() default {"Zapreyev", "Serguei", "Stepanovich"}; + }; + abstract String author() default "Zapreyev 2"; + }; + abstract String author() default "Zapreyev 3"; + }; + abstract String author() default "Zapreyev 4"; + }; + abstract String author() default "Zapreyev 5"; + }; + abstract String author() default "Zapreyev 6"; + }; + abstract String author() default "Zapreyev 7"; + }; + abstract String author() default "Zapreyev 8"; + }; + + /** + * + */ + public void test_0() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void inMeth( + @MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + //authorSurname="1", + authorFullName="2" + ) Class p1 + ){}; + void inMeth2(){inMeth(int.class); inMeth3();}; + void inMeth3(){inMeth(int.class); inMeth2();}; + }; + Annotation aa[][] = null; + try{ + java.lang.reflect.Method am[] = LC111.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("inMeth")) { + aa = am[i].getParameterAnnotations(); + } + } + } catch (/*NoSuchMethod*/Exception e) { + fail("test_4, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + for(int k = 0; k < aa[i].length; k++) { + if( i == 0 ) { + try{ + java.lang.reflect.Method am[] = ((MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } + } + if (flg != 11) fail("test_4, case 017 FAILED"); + }catch(Exception _){ + fail("test_4, case 018 FAILED"); + } + //System.out.println("<<<"+aa[i][k].toString()+">>>"); + if(!((MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname().equals("Zapreyev")) fail("test_4, case 038 FAILED: "+((MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname()); + if(!((MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[0].equals("2")) fail("test_4, case 038 FAILED: "+((MA7.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()); + } + } + } + } + + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA1_1_1_1_1_1_1 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String authorSurname() default "Zapreyev"; + abstract String[] authorFullName() default {"Zapreyev", "Serguei", "Stepanovich"}; + + public class Prltr{} + public class Brg{} + public class Krstnn{} + public class Arstcrt{} + public class Clrc{} + abstract Class socialClass() default Prltr.class; + abstract Class[] socialClasses() default {Prltr.class, Brg.class, Krstnn.class, Arstcrt.class, Clrc.class}; + + int primitive() default 777; + @Retention(value=RetentionPolicy.RUNTIME) + @interface internalAnnotation { + boolean attr1() default true ? false : true; + byte attr2() default (byte) 256; + char attr3() default 'Z'; + double attr4() default Double.MAX_VALUE; + float attr5() default Float.MIN_VALUE; + int attr6() default 777; + long attr7() default Long.MAX_VALUE + Long.MIN_VALUE; + short attr8() default (short)32655; + abstract MA1_1_1_1_1 itself() default @MA1_1_1_1_1; + }; + abstract MA1_1_1_1_1_1_1 blackMarker() default @MA1_1_1_1_1_1_1; + abstract internalAnnotation[] whiteMarkers() default {@internalAnnotation(attr1 = true, attr7 = -1L), @internalAnnotation, @internalAnnotation()}; + //abstract int[] whiteMarkers2() default 6 | 13; + public static enum ME1 { + F_S(2),M_S(3),C_S(4),CL_S(1); + ME1(int value) { + this.value = value; + } + private final int value;int m1(){return value+m2();};int m2(){return value+m1();}; + public static enum E1_ {G_A_T0, P_T0, V_T0, W_T0; + public static enum E1_1 {G_A_T1, P_T1, V_T1, W_T1; + public static enum E1_2 {G_A_T2, P_T2, V_T2, W_T2; + public static enum E1_3 {G_A_T3, P_T3, V_T3, W_T3; + public static enum E1_4 {G_A_T4, P_T4, V_T4, W_T4; + public static enum E1_5 {G_A_T5, P_T5, V_T5, W_T5; + }; + }; + }; + }; + }; + }; + }; + + abstract ME1 constant() default ME1.M_S; + abstract ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5[] constants() default {ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5, ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5, ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5}; + }; + abstract String author() default "Zapreyev 2"; + }; + abstract String author() default "Zapreyev 3"; + }; + abstract String author() default "Zapreyev 4"; + }; + abstract String author() default "Zapreyev 5"; + }; + abstract String author() default "Zapreyev 6"; + }; + abstract String author() default "Zapreyev 7"; + }; + abstract String author() default "Zapreyev 8"; + }; +////////////////////////////////////////////////////////////////////////////////////////////// + @iat class MC003 {}; + @iat(author = "Serguei S. Zapreyev") class InternalX {}; + @j class InternalO {}; + static { + @iat class Internal2 {}; + } + + /** + * + */ + @j class MC004 {}; + public void test_1() { + @j class LC1 {}; + if(!MC004.class.getDeclaredAnnotations()[0].annotationType().equals(j.class)) fail("test_1, case 1 FAILED: "+MC004.class.getDeclaredAnnotations()[0].annotationType().equals(j.class)); + if(MC004.class.getDeclaredAnnotations()[0].hashCode()!=0) fail("test_1, case 002 FAILED: "+MC004.class.getDeclaredAnnotations()[0].hashCode()); + if(!MC004.class.getDeclaredAnnotations()[0].equals(LC1.class.getDeclaredAnnotations()[0])) fail("test_1, case 003 FAILED: "+MC004.class.getDeclaredAnnotations()[0]+"|"+LC1.class.getDeclaredAnnotations()[0]); + if(!MC004.class.getDeclaredAnnotations()[0].toString().equals("@java.lang.j()")) fail("test_1, case 004 FAILED: "+MC004.class.getDeclaredAnnotations()[0].toString()); + } + + /** + * + */ + public void test_2() { + if(!MC003.class.getDeclaredAnnotations()[0].annotationType().equals(iat.class)) fail("test_2, case 1 FAILED: "+MC003.class.getDeclaredAnnotations()[0].annotationType().equals(iat.class)); + if(!MC003.class.getDeclaredAnnotations()[0].annotationType().getSimpleName().equals("iat")) fail("test_2, case 002 FAILED: "+MC003.class.getDeclaredAnnotations()[0].annotationType().getSimpleName().equals("i")); + if(MC003.class.getAnnotation(iat.class)==null) fail("test_2, case 003 FAILED: "+MC003.class.getAnnotation(iat.class)); + if(!MC003.class.isAnnotationPresent(iat.class)) fail("test_2, case 004 FAILED: "+MC003.class.isAnnotationPresent(iat.class)); + if(MC003.class.isAnnotation()) fail("test_2, case 005 FAILED: "+MC003.class.isAnnotation()); + } + +// METHOD: //////////////////////////////////////////////////////////////////////////////////////////////// + /** + * checks starting from Method.getDeclaredAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_3() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC1 {}; + Annotation ia = LC1.class.getDeclaredAnnotations()[0]; + Annotation aa[] = null; + try{ + aa = ClassAnnotationsTest.class.getMethod("test_3").getDeclaredAnnotations(); + if(aa.length!=1) fail("test_3, case 0 FAILED: "+aa.length); + //System.out.println(aa[0]); + if(aa[0].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=Zapreyev 2\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_3, case 1 FAILED: "+aa[0].toString()); +/**/ if(!ClassAnnotationsTest.class.getMethod("test_3").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_3, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); +/**/ if(ClassAnnotationsTest.class.getMethod("test_3").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_3, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); +/**/ if(ClassAnnotationsTest.class.getMethod("test_3").getParameterAnnotations().length!=0) fail("test_3, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_3").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_3, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_3, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_3, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_3, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_3, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_3, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_3, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_3, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_3, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_3, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_3, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_3, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_3, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_3, case 017 FAILED"); + }catch(Exception _){ + fail("test_3, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_3, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_3, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_3, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_3, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_3, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_3, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_3, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_3, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_3, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_3, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_3, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_3, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_3, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_3, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_3, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_3, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_3, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_3, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_3, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_3, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_3, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_3, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_3, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("Zapreyev 2")) fail("test_3, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_3, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_3, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_3, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + + /** + * checks starting from Method.getAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_3_1() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC1 {}; + Annotation ia = LC1.class.getDeclaredAnnotations()[0]; + Annotation aa[] = null; + try{ + aa = ClassAnnotationsTest.class.getMethod("test_3_1").getAnnotations(); + if(aa.length!=1) fail("test_3, case 0 FAILED: "+aa.length); + if(aa[0].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=Zapreyev 2\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_3_1, case 1 FAILED: "+aa[0].toString()); +/**/ if(!ClassAnnotationsTest.class.getMethod("test_3_1").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_3_1, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); +/**/ if(ClassAnnotationsTest.class.getMethod("test_3_1").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_3_1, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); +/**/ if(ClassAnnotationsTest.class.getMethod("test_3_1").getParameterAnnotations().length!=0) fail("test_3_1, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_3_1").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_3_1, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_3_1, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_3_1, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_3_1, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_3_1, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_3_1, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_3_1, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_3_1, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_3_1, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_3_1, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_3_1, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_3_1, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_3_1, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_3_1, case 017 FAILED"); + }catch(Exception _){ + fail("test_3_1, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_3_1, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_3_1, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_3_1, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_3_1, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_3_1, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_3_1, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_3_1, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_3_1, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_3_1, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_3_1, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_3_1, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_3_1, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_3_1, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_3_1, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_3_1, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_3_1, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_3_1, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_3_1, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_3_1, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_3_1, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_3_1, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_3_1, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_3_1, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("Zapreyev 2")) fail("test_3_1, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_3_1, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_3_1, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_3_1, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + + /** + * checks starting from Method.getParameterAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_4() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void inMeth( + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + blackMarker=@MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author="AUTHOR"), + constants={MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5} + ) Class p1, + @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="S&S&Z") Class p2, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1 Class p3, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="Serguei Stepanovich") Class p4, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii Class p5 + ){}; + void inMeth2(){inMeth(int.class, int.class, int.class, int.class, int.class); inMeth3();}; + void inMeth3(){inMeth(int.class, int.class, int.class, int.class, int.class); inMeth2();}; + }; + Annotation ia = LC111.class.getDeclaredAnnotations()[0]; + Annotation aa[][] = null; + try{ + java.lang.reflect.Method am[] = LC111.class.getDeclaredMethods(); + //System.out.println(am.length); + for (int i = 0; i < am.length; i++) { + //System.out.println(am[i].toString()); + + if (am[i].getName().equals("inMeth")) { + aa = am[i].getParameterAnnotations(); + if(!am[i].getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class).annotationType().equals(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_6_1, case 02 FAILED: "+aa.length); + if(am[i].getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_6_1, case 03 FAILED: "+aa.length); + try{am[i].getAnnotation((Class)null); fail("test_6_1, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!am[i].isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_6_1, case 04 FAILED: "+aa.length); + if(am[i].isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_6_1, case 05 FAILED: "+aa.length); + try{am[i].isAnnotationPresent((Class)null); fail("test_6_1, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + } + } + //aa = LC111.class.getMethod("inMeth").getParameterAnnotations(); + if(aa.length!=5) fail("test_4, case 0 FAILED: "+aa.length); + } catch (/*NoSuchMethod*/Exception e) { + fail("test_4, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + for(int k = 0; k < aa[i].length; k++) { + Class cuCla = aa[i][k].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + if( i == 4 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k!=0) { + fail("test_4, case 038 FAILED "); + } + } + if( i == 3 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k!=0) { + fail("test_4, case 038 FAILED "); + } + if (k==0) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author().equals("Serguei Stepanovich")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author()); + } + } + if( i == 2 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k!=0) { + fail("test_4, case 038 FAILED "); + } + } + if( i == 1 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k==0) { + if(!((MA1)aa[i][k]).author().equals("Zapreyev 8")) fail("test_4, case 038 FAILED: "+((MA1)aa[i][k]).author()); + } + if (k==1) { + if(!((MA1.MA1_1)aa[i][k]).author().equals("Zapreyev 7")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1)aa[i][k]).author()); + } + if (k==2) { + if(!((MA1.MA1_1.MA1_1_1)aa[i][k]).author().equals("Zapreyev 6")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1)aa[i][k]).author()); + } + if (k==3) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i][k]).author().equals("Zapreyev 5")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i][k]).author()); + } + if (k==4) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author().equals("S&S&Z")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author()); + } + } + if( i == 0 ) { + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_4, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_4, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_4, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_4, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_4, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_4, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_4, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_4, case 017 FAILED"); + }catch(Exception _){ + fail("test_4, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_4, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_4, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_4, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_4, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_4, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_4, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_4, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_4, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_4, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_4, case 028 FAILED"); + //System.out.println("1XXX>>> >>> >>>>"+MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()); + //System.out.println("1XXX>>> >>> >>>>"+MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue().getClass()); + //System.out.println("1XXX>>> >>> >>>>"+MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue().getClass().getSuperclass()); + //System.out.println("1XXX>>> >>> >>>>"+MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue().getClass().getInterfaces()[0]); + //System.out.println("2XXX>>> >>> >>>>"); + System.out.println((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()); + //System.out.println("3XXX>>> >>> >>>>"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_4, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_4, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_4, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_4, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_4, case 033 FAILED"); + } + if(aa[i][k].annotationType() != ia.annotationType()) fail("test_4, case 034 FAILED: "+aa[i][k].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i][k].equals((Object) ia)) fail("test_4, case 035 FAILED: "+aa[i][k].equals((Object) ia)); + if(aa[i][k].hashCode() == ia.hashCode()) fail("test_4, case 036 FAILED: "+Integer.toString(aa[i][k].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i][k].toString().equals(ia.toString())) fail("test_4, case 037 FAILED: "+aa[i][k].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname().equals("Zapreyev")) fail("test_4, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[2].equals("Stepanovich")) fail("test_4, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClass().getSimpleName().equals("Prltr")) fail("test_4, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_4, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).blackMarker().author().equals("AUTHOR")) fail("test_4, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_4, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_4, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[3]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[4]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5) fail("test_4, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[2]); + } + } + } + } + + /** + * checks for Method.getParameterAnnotations() for regional conditions + */ + public void test_4_1() { + class LC111 { + public void inMeth( + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + blackMarker=@MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author="AUTHOR"), + constants={MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5} + ) Class p1, + @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="S&S&Z") Class p2, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1 Class p3, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="Serguei Stepanovich") Class p4, + Class p5 + ){}; + void inMeth2(){inMeth(int.class, int.class, int.class, int.class, int.class); inMeth3(int.class, int.class, int.class, int.class);}; + void inMeth3(@k @l Class p1, @k Class p2, Class p3, @l Class p4){inMeth(int.class, int.class, int.class, int.class, int.class); inMeth2();}; + }; + Annotation aa[][] = null; + try{ + java.lang.reflect.Method am[] = LC111.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("inMeth")) { + aa = am[i].getParameterAnnotations(); + if (!(aa instanceof Annotation[][] && aa.length == 5)) fail("test_4_1, case 001 FAILED: "+aa.length); + if (!(aa[0] instanceof Annotation[] && aa[0].length == 1)) fail("test_4_1, case 002 FAILED: "+aa[0].length); + if (!(aa[1] instanceof Annotation[] && aa[1].length == 5)) fail("test_4_1, case 003 FAILED: "+aa[1].length); + if (!(aa[2] instanceof Annotation[] && aa[2].length == 1)) fail("test_4_1, case 004 FAILED: "+aa[2].length); + if (!(aa[3] instanceof Annotation[] && aa[3].length == 1)) fail("test_4_1, case 005 FAILED: "+aa[3].length); + if (!(aa[4] instanceof Annotation[] && aa[4].length == 0)) fail("test_4_1, case 006 FAILED: "+aa[4].length); + } + if (am[i].getName().equals("inMeth2")) { + aa = am[i].getParameterAnnotations(); + if (!(aa instanceof Annotation[][] && aa.length == 0)) fail("test_4_1, case 007 FAILED: "+aa.length); + } + if (am[i].getName().equals("inMeth3")) { + aa = am[i].getParameterAnnotations(); + if (!(aa.length == 4)) fail("test_4_1, case 005 FAILED: "+aa.length); + if (!(aa[0] instanceof Annotation[] && aa[0].length == 0)) fail("test_4_1, case 008 FAILED: "+aa[0].length); + if (!(aa[1] instanceof Annotation[] && aa[1].length == 0)) fail("test_4_1, case 009 FAILED: "+aa[1].length); + if (!(aa[2] instanceof Annotation[] && aa[2].length == 0)) fail("test_4_1, case 010 FAILED: "+aa[2].length); + if (!(aa[3] instanceof Annotation[] && aa[3].length == 0)) fail("test_4_1, case 011 FAILED: "+aa[3].length); + } + } + } catch (/*NoSuchMethod*/Exception e) { + fail("test_4_1, case 012 FAILED: "+e.toString()); + } + } + + /** + * checks for nulls + */ + @anna public void test_5() { + try{ + try{ + new ClassAnnotationsTest().getClass().getMethod("test_5").isAnnotationPresent((Class)null); + fail("test_5, case 1 FAILED: NullPointerException should rise."); + } catch (NullPointerException _) { + } + try{ + new ClassAnnotationsTest().getClass().getMethod("test_5").getAnnotation((Class)null); + fail("test_5, case 002 FAILED: NullPointerException should rise."); + } catch (NullPointerException _) { + } + } catch (NoSuchMethodException e) { + fail("test_5, case 003 FAILED: "+e.toString()); + } + } + +// CONSTRUCTOR: //////////////////////////////////////////////////////////////////////////////////////////////// + /** + * checks starting from Constructor.getDeclaredAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_6() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public LC111(){}; + }; + Annotation ia = LC111.class.getDeclaredAnnotations()[0]; + Annotation aa[] = null; + try{ + //aa = LC111.class.getConstructor().getDeclaredAnnotations(); + aa = LC111.class.getDeclaredConstructors()[0].getDeclaredAnnotations(); + if(aa.length!=1) fail("test_6, case 0 FAILED: "+aa.length); + //System.out.println(aa[0]); + //System.out.println(aa[0].toString()); + if(aa[0].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=Zapreyev 2\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_6, case 1 FAILED: "+aa[0].toString()); + /**/ if(!ClassAnnotationsTest.class.getMethod("test_6").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_6, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_6").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_6, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_6").getParameterAnnotations().length!=0) fail("test_6, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_6").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_6, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_6, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_6, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_6, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_6, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_6, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_6, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_6, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_6, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_6, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_6, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_6, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_6, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_6, case 017 FAILED"); + }catch(Exception _){ + fail("test_6, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_6, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_6, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_6, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_6, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_6, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_6, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_6, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_6, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_6, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_6, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_6, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_6, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_6, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_6, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_6, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_6, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_6, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_6, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_6, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_6, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_6, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_6, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_6, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("Zapreyev 2")) fail("test_6, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_6, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_6, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_6, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + + /** + * checks starting from Constructor.getAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_6_1() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 public LC111(){}; + }; + Annotation ia = LC111.class.getDeclaredAnnotations()[0]; + Annotation aa[] = null; + try{ + aa = LC111.class.getDeclaredConstructors()[0].getAnnotations(); + if(!LC111.class.getDeclaredConstructors()[0].getAnnotation(MA1.MA1_1.MA1_1_1.class).annotationType().equals(MA1.MA1_1.MA1_1_1.class)) fail("test_6_1, case 02 FAILED: "+aa.length); + if(LC111.class.getDeclaredConstructors()[0].getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_6_1, case 03 FAILED: "+aa.length); + try{LC111.class.getDeclaredConstructors()[0].getAnnotation((Class)null); fail("test_6_1, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!LC111.class.getDeclaredConstructors()[0].isAnnotationPresent(MA1.class)) fail("test_6_1, case 04 FAILED: "+aa.length); + if(LC111.class.getDeclaredConstructors()[0].isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_6_1, case 05 FAILED: "+aa.length); + try{LC111.class.getDeclaredConstructors()[0].isAnnotationPresent((Class)null); fail("test_6_1, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(aa.length!=4) fail("test_6, case 0 FAILED: "+aa.length); + if(aa[0].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=Zapreyev 2\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_6_1, case 1 FAILED: "+aa[0].toString()); + /**/ if(!ClassAnnotationsTest.class.getMethod("test_6_1").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_6_1, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_6_1").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_6_1, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_6_1").getParameterAnnotations().length!=0) fail("test_6_1, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_6_1").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_6_1, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + if (i == 1) { + try{ + if(((MA1)aa[i]).getClass().getMethod("author").getDefaultValue()!=null) fail("test_6_1, case 025 FAILED"); + if(!((String)MA1.class.getMethod("author").getDefaultValue()).equals("Zapreyev 8")) fail("test_6_1, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 027 FAILED"); + } + } + if (i == 0) { + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_6_1, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_6_1, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_6_1, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_6_1, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_6_1, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_6_1, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_6_1, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_6_1, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_6_1, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_6_1, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_6_1, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_6_1, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_6_1, case 017 FAILED"); + }catch(Exception _){ + fail("test_6_1, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_6_1, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_6_1, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_6_1, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_6_1, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_6_1, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_6_1, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_6_1, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_6_1, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_6_1, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_6_1, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_6_1, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_6_1, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_6_1, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_6_1, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_6_1, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_6_1, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_6_1, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_6_1, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_6_1, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("Zapreyev 2")) fail("test_6_1, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_6_1, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_6_1, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_6_1, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + } + + /** + * checks starting from Constructor.getParameterAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_7() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public LC111( + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + blackMarker=@MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author="AUTHOR"), + constants={MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5} + ) Class p1, + @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1 @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="S&S&Z") Class p2, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1 Class p3, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="Serguei Stepanovich") Class p4, + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii Class p5 + ){}; + }; + //Annotation ia = LC111.class.getDeclaredAnnotations()[0]; + Annotation ia = new LC111(int.class, int.class, int.class, int.class, int.class).getClass().getDeclaredAnnotations()[0]; + Annotation aa[][] = null; + try{ + for (int i = 0; i < LC111.class.getDeclaredConstructors().length; i++) { +// System.out.println(">>> >>> >>>"+LC111.class.getDeclaredConstructors()[i]); + } + java.lang.reflect.Constructor ac = LC111.class.getDeclaredConstructors()[0]; //LC111.class.getConstructor(Class.class, Class.class, Class.class, Class.class, Class.class); + if(!ac.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class).annotationType().equals(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_7, case 02 FAILED: "+aa.length); + if(ac.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_7, case 03 FAILED: "+aa.length); + try{ac.getAnnotation((Class)null); fail("test_7, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!ac.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_7, case 04 FAILED: "+aa.length); + if(ac.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_7, case 05 FAILED: "+aa.length); + try{ac.isAnnotationPresent((Class)null); fail("test_7, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + aa = ac.getParameterAnnotations(); + if(aa.length!=5) fail("test_7, case 0 FAILED: "+aa.length); + } catch (/*NoSuchMethod*/Exception e) { + e.printStackTrace(); + fail("test_7, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + for(int k = 0; k < aa[i].length; k++) { + Class cuCla = aa[i][k].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + if( i == 4 ) { + + if (k!=0) { + fail("test_7, case 038 FAILED "); + } + } + if( i == 3 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k!=0) { + fail("test_7, case 038 FAILED "); + } + if (k==0) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author().equals("Serguei Stepanovich")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author()); + } + } + if( i == 2 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k!=0) { + fail("test_7, case 038 FAILED "); + } + } + if( i == 1 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if (k==0) { + if(!((MA1)aa[i][k]).author().equals("Zapreyev 8")) fail("test_7, case 038 FAILED: "+((MA1)aa[i][k]).author()); + } + if (k==1) { + if(!((MA1.MA1_1)aa[i][k]).author().equals("Zapreyev 7")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1)aa[i][k]).author()); + } + if (k==2) { + if(!((MA1.MA1_1.MA1_1_1)aa[i][k]).author().equals("Zapreyev 6")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1)aa[i][k]).author()); + } + if (k==3) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i][k]).author().equals("Zapreyev 5")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i][k]).author()); + } + if (k==4) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author().equals("S&S&Z")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i][k]).author()); + } + } + if( i == 0 ) { + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_7, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_7, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_7, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_7, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_7, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_7, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_7, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_7, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_7, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_7, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_7, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_7, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_7, case 017 FAILED"); + }catch(Exception _){ + fail("test_7, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_7, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_7, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_7, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_7, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_7, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_7, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_7, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_7, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_7, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_7, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_7, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_7, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_7, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_7, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_7, case 033 FAILED"); + } + if(aa[i][k].annotationType() != ia.annotationType()) fail("test_7, case 034 FAILED: "+aa[i][k].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i][k].equals((Object) ia)) fail("test_7, case 035 FAILED: "+aa[i][k].equals((Object) ia)); + if(aa[i][k].hashCode() == ia.hashCode()) fail("test_7, case 036 FAILED: "+Integer.toString(aa[i][k].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i][k].toString().equals(ia.toString())) fail("test_7, case 037 FAILED: "+aa[i][k].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname().equals("Zapreyev")) fail("test_7, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[2].equals("Stepanovich")) fail("test_7, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClass().getSimpleName().equals("Prltr")) fail("test_7, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_7, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).blackMarker().author().equals("AUTHOR")) fail("test_7, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_7, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_7, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[3]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[4]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5) fail("test_7, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i][k]).constants()[2]); + } + } + } + } + +// FIELD: //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * checks starting from Field.getDeclaredAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_8() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + blackMarker=@MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author="AUTHOR"), + constants={MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5} + ) + @MA1 + @MA1.MA1_1 + @MA1.MA1_1.MA1_1_1 + @MA1.MA1_1.MA1_1_1.MA1_1_1_1 + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="S&S&Z") + public int fld; + int m1(){return fld+m2();}; + int m2(){return fld+m1();}; + }; + Annotation ia = LC111.class.getDeclaredAnnotations()[0]; + Annotation aa[] = null; + try{ + java.lang.reflect.Field af = LC111.class.getDeclaredField("fld"); + aa = af.getDeclaredAnnotations(); + if(aa.length!=6) fail("test_8, case 01 FAILED: "+aa.length); + if(!af.getAnnotation(MA1.MA1_1.MA1_1_1.class).annotationType().equals(MA1.MA1_1.MA1_1_1.class)) fail("test_8, case 02 FAILED: "+aa.length); + if(af.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_8, case 03 FAILED: "+aa.length); + try{af.getAnnotation((Class)null); fail("test_8, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!af.isAnnotationPresent(MA1.class)) fail("test_8, case 04 FAILED: "+aa.length); + if(af.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_8, case 05 FAILED: "+aa.length); + try{af.isAnnotationPresent((Class)null); fail("test_8, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + } catch (/*NoSuchMethod*/Exception e) { + fail("test_8, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + if( i == 5 ) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i]).author().equals("S&S&Z")) fail("test_8, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i]).author()); + } + if( i == 4 ) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i]).author().equals("Zapreyev 5")) fail("test_8, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i]).author()); + } + if( i == 3 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1.MA1_1.MA1_1_1)aa[i]).author().equals("Zapreyev 6")) fail("test_8, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1)aa[i]).author()); + } + if( i == 2 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1.MA1_1)aa[i]).author().equals("Zapreyev 7")) fail("test_8, case 038 FAILED: "+((MA1.MA1_1)aa[i]).author()); + } + if( i == 1 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1)aa[i]).author().equals("Zapreyev 8")) fail("test_8, case 038 FAILED: "+((MA1)aa[i]).author()); + } + if( i == 0 ) { + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_8, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_8, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_8, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_8, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_8, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_8, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_8, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_8, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_8, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_8, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_8, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_8, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_8, case 017 FAILED"); + }catch(Exception _){ + fail("test_8, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_8, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_8, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_8, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_8, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_8, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_8, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_8, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_8, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_8, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_8, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_8, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_8, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_8, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_8, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_8, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_8, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_8, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_8, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_8, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_8, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_8, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_8, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_8, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("AUTHOR")) fail("test_8, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_8, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_8, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[3]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[4]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5) fail("test_8, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + } + + /** + * checks starting from Field.getAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_9() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) class LC111 { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii( + blackMarker=@MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author="AUTHOR"), + constants={MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5, MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5} + ) + @MA1 + @MA1.MA1_1 + @MA1.MA1_1.MA1_1_1 + @MA1.MA1_1.MA1_1_1.MA1_1_1_1 + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1(author="S&S&Z") + public int fld; + int m1(){return fld+m2();}; + int m2(){return fld+m1();}; + }; + Annotation ia = LC111.class.getAnnotations()[0]; + Annotation aa[] = null; + try{ + java.lang.reflect.Field af = LC111.class.getDeclaredField("fld"); + aa = af.getDeclaredAnnotations(); + if(aa.length!=6) fail("test_9, case 0 FAILED: "+aa.length); + if(!af.getAnnotation(MA1.MA1_1.MA1_1_1.class).annotationType().equals(MA1.MA1_1.MA1_1_1.class)) fail("test_9, case 02 FAILED: "+aa.length); + if(af.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_9, case 03 FAILED: "+aa.length); + try{af.getAnnotation((Class)null); fail("test_9, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!af.isAnnotationPresent(MA1.class)) fail("test_9, case 04 FAILED: "+aa.length); + if(af.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_9, case 05 FAILED: "+aa.length); + try{af.isAnnotationPresent((Class)null); fail("test_9, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + } catch (/*NoSuchMethod*/Exception e) { + fail("test_9, case 005 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + if( i == 5 ) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i]).author().equals("S&S&Z")) fail("test_9, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1)aa[i]).author()); + } + if( i == 4 ) { + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i]).author().equals("Zapreyev 5")) fail("test_9, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1)aa[i]).author()); + } + if( i == 3 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1.MA1_1.MA1_1_1)aa[i]).author().equals("Zapreyev 6")) fail("test_9, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1)aa[i]).author()); + } + if( i == 2 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1.MA1_1)aa[i]).author().equals("Zapreyev 7")) fail("test_9, case 038 FAILED: "+((MA1.MA1_1)aa[i]).author()); + } + if( i == 1 ) { + //System.out.println(i+"|"+k+"|"+cuCla.getCanonicalName()); + if(!((MA1)aa[i]).author().equals("Zapreyev 8")) fail("test_9, case 038 FAILED: "+((MA1)aa[i]).author()); + } + if( i == 0 ) { + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_9, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_9, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_9, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_9, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_9, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_9, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_9, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_9, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_9, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_9, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_9, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_9, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_9, case 017 FAILED"); + }catch(Exception _){ + fail("test_9, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_9, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_9, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_9, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_9, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_9, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_9, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_9, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_9, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_9, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_9, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_9, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_9, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_9, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_9, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_9, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_9, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(aa[i].equals((Object) ia)) fail("test_9, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_9, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_9, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_9, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_9, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_9, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_9, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("AUTHOR")) fail("test_9, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_9, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_9, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[3]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[4]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5) fail("test_9, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + } + +// CLASS: //////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * checks starting from Class.getDeclaredAnnotations() + */ + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(primitive=777) public void test_10() { + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 class LC111 { + public LC111(){}; + }; + Annotation ia = null; //LC111.class.getDeclaredAnnotations()[0]; + try { + ia = ClassAnnotationsTest.class.getMethod("test_10").getAnnotations()[0]; + } catch (NoSuchMethodException e) { + fail("test_10, case 000 FAILED: "+e.toString()); + } + Annotation aa[] = null; + if(!LC111.class.getAnnotation(MA1.MA1_1.MA1_1_1.class).annotationType().equals(MA1.MA1_1.MA1_1_1.class)) fail("test_10, case 02 FAILED: "+aa.length); + if(LC111.class.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_10, case 03 FAILED: "+aa.length); + try{LC111.class.getAnnotation((Class)null); fail("test_10, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!LC111.class.isAnnotationPresent(MA1.class)) fail("test_10, case 04 FAILED: "+aa.length); + if(LC111.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_10, case 05 FAILED: "+aa.length); + try{LC111.class.isAnnotationPresent((Class)null); fail("test_10, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + aa = LC111.class.getDeclaredAnnotations(); + if(aa.length!=4) fail("test_6, case 0 FAILED: "+aa.length); + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + //if (i == 1) { + if (cuCla.getSimpleName().equals("MA1")) { + try{ + if(((MA1)aa[i]).getClass().getMethod("author").getDefaultValue()!=null) fail("test_10, case 025 FAILED"); + if(!((String)MA1.class.getMethod("author").getDefaultValue()).equals("Zapreyev 8")) fail("test_10, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_10, case 027 FAILED"); + } + } + //if (i == 0) { + if (cuCla.getSimpleName().equals("iiii")) { + try{ + if(aa[i].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=UNKNOWN\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_10, case 1 FAILED: "+aa[0].toString()); + /**/ if(!ClassAnnotationsTest.class.getMethod("test_10").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_10, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_10").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_10, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_10").getParameterAnnotations().length!=0) fail("test_10, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_10").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_10, case 005 FAILED: "+e.toString()); + } + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_10, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_10, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_10, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_10, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_10, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_10, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_10, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_10, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_10, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_10, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_10, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_10, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_10, case 017 FAILED"); + }catch(Exception _){ + fail("test_10, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_10, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_10, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_10, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_10, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_10, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_10, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_10, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_10, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_10, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_10, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_10, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_10, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_10, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_10, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_10, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_10, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(!aa[i].annotationType().getSimpleName().equals(ia.annotationType().getSimpleName())) fail("test_10, case 035_1 FAILED: "+aa[i].annotationType().getSimpleName().equals(ia.annotationType().getSimpleName())); + if(aa[i].equals((Object) ia)) fail("test_10, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_10, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_10, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_10, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_10, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_10, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_10, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("UNKNOWN")) fail("test_10, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_10, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_10, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_10, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + } + + /** + * checks starting from Class.getAnnotations() + */ + @Retention(value=RetentionPolicy.RUNTIME) + @interface ia1{ + abstract String author() default "Zapreyev"; + @Retention(value=RetentionPolicy.RUNTIME) + @interface ia2{ + abstract String author() default "Zapreyev"; + }; + }; + @Retention(value=RetentionPolicy.RUNTIME) + @interface ca1{ + abstract String author1() default "Zapreyev1"; + @Retention(value=RetentionPolicy.RUNTIME) + @interface ca2{ + abstract String author2() default "Zapreyev2"; + @Retention(value=RetentionPolicy.CLASS) + @interface ca3{ + abstract String author3() default "Zapreyev3"; + @Retention(value=RetentionPolicy.SOURCE) + @interface ca4{ + abstract String author4() default "Zapreyev4"; + @Retention(value=RetentionPolicy.RUNTIME) + //@interface ca5<T extends Class>{ //...\tiger-dev\vm\tests\kernel\java\lang\ClassAnnotationsTest.java:2142: @interface may not have type parameters + @interface ca5{ + @ca4 @ca3 @ca2 @ca1 abstract String author51() default "Zapreyev51"; + //abstract T author52(); //...tiger-dev\vm\tests\kernel\java\lang\ClassAnnotationsTest.java:2144: invalid type for annotation member + }; + }; + }; + }; + }; + @ia1 @ia1.ia2 interface LI111 { + }; + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii public void test_11() { + @ca1 @ca1.ca2 @ca1.ca2.ca3 @ca1.ca2.ca3.ca4 @ca1.ca2.ca3.ca4.ca5 class LC222 implements ia1 { + public String author() {return "Hello, it's me!";} + public Class annotationType() {return (Class)null;} + public int hasCode() {return 777;} + public boolean equals() {return false;} + public void invokeAll() {if (this.hashCode()==777) this.equals(); this.annotationType(); this.author(); this.invokeInvokeAll();} + public void invokeInvokeAll() {this.invokeAll();} + }; + + Annotation an1 = LC222.class.getAnnotation(ca1.ca2.ca3.ca4.ca5.class); + if(!an1.annotationType().equals(ca1.ca2.ca3.ca4.ca5.class)) fail("test_11, case 02 FAILED: "+an1.annotationType()); + if(!LC222.class.getAnnotation(ca1.ca2.ca3.ca4.ca5.class).annotationType().equals(ca1.ca2.ca3.ca4.ca5.class)) fail("test_11, case 02 FAILED: "+an1.annotationType()); + try{ + if(((ca1.ca2.ca3.ca4.ca5)an1).getClass().getMethod("author51").getDefaultValue()!=null) fail("test_11, case 019 FAILED"); + if(!((String)ca1.ca2.ca3.ca4.ca5.class.getMethod("author51").getDefaultValue()).equals("Zapreyev51")) fail("test_11, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_11, case 021 FAILED"); + } + + + @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii(blackMarker = @MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1(author = "UNKNOWN")) @MA1 @MA1.MA1_1 @MA1.MA1_1.MA1_1_1 class LC111 extends LC222 implements LI111 { + public LC111(){}; + }; + Annotation ia = null; //LC111.class.getDeclaredAnnotations()[0]; + try { + ia = ClassAnnotationsTest.class.getMethod("test_11").getAnnotations()[0]; + } catch (NoSuchMethodException e) { + fail("test_11, case 000 FAILED: "+e.toString()); + } + Annotation aa[] = null; + if(!LC111.class.getAnnotation(MA1.MA1_1.MA1_1_1.class).annotationType().equals(MA1.MA1_1.MA1_1_1.class)) fail("test_11, case 02 FAILED: "+aa.length); + if(LC111.class.getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.class)!=null) fail("test_11, case 03 FAILED: "+aa.length); + try{LC111.class.getAnnotation((Class)null); fail("test_11, case 03_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + if(!LC111.class.isAnnotationPresent(MA1.class)) fail("test_11, case 04 FAILED: "+aa.length); + if(LC111.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.class)) fail("test_11, case 05 FAILED: "+aa.length); + try{LC111.class.isAnnotationPresent((Class)null); fail("test_11, case 05_1 FAILED: "+aa.length);} catch (NullPointerException e) {} + aa = LC111.class.getAnnotations(); + if(aa.length!=4) fail("test_6, case 0 FAILED: "+aa.length); + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + //if (i == 1) { + if (cuCla.getSimpleName().equals("MA1")) { + try{ + if(((MA1)aa[i]).getClass().getMethod("author").getDefaultValue()!=null) fail("test_11, case 025 FAILED"); + if(!((String)MA1.class.getMethod("author").getDefaultValue()).equals("Zapreyev 8")) fail("test_11, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_11, case 027 FAILED"); + } + } + //if (i == 0) { + if (cuCla.getSimpleName().equals("iiii")) { + try{ + if(aa[i].toString().replaceAll("Enum\\:","").replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\(", ""). + replaceFirst("blackMarker=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\(author=UNKNOWN\\)",""). + replaceFirst("constants=\\[W_T5, V_T5, G_A_T5\\]",""). + replaceFirst("authorSurname=Zapreyev",""). + replaceFirst("socialClass=class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("primitive=777",""). + replaceFirst("socialClasses=\\[",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Prltr",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Brg",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Krstnn",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Arstcrt",""). + replaceFirst("class java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$Clrc",""). + replaceFirst("whiteMarkers=\\[",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\$MA1_1_1_1_1_1\\$MA1_1_1_1_1_1_1\\$iiii\\$internalAnnotation\\(",""). + replaceFirst("attr7=-1",""). + replaceFirst("attr1=true",""). + replaceFirst("attr2=0",""). + replaceFirst("attr5=1\\.4E-45",""). + replaceFirst("attr6=777",""). + replaceFirst("attr3=Z",""). + replaceFirst("attr4=1\\.7976931348623157E308",""). + replaceFirst("itself=\\@java\\.lang\\.ClassAnnotationsTest\\$MA1\\$MA1_1\\$MA1_1_1\\$MA1_1_1_1\\$MA1_1_1_1_1\\(author=Zapreyev 4\\)",""). + replaceFirst("attr8=32655",""). + replaceFirst("authorFullName=\\[Zapreyev, Serguei, Stepanovich\\]",""). + replaceFirst("constant=M_S",""). + replaceFirst("attr1=false",""). + replaceFirst("attr1=false",""). + replaceAll(" ",""). + replaceAll("\\)",""). + replaceAll("\\]",""). + replaceAll("\\,","").length()!=0) fail("test_11, case 1 FAILED: "+aa[0].toString()); + /**/ if(!ClassAnnotationsTest.class.getMethod("test_11").isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)) fail("test_11, case 002 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_11").getAnnotation(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class) == null) fail("test_11, case 003 FAILED: "+MC003.class.isAnnotationPresent(MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class)); + /**/ if(ClassAnnotationsTest.class.getMethod("test_11").getParameterAnnotations().length!=0) fail("test_11, case 004 FAILED: "+ClassAnnotationsTest.class.getMethod("test_11").getParameterAnnotations().length); + } catch (NoSuchMethodException e) { + fail("test_11, case 005 FAILED: "+e.toString()); + } + while (cuCla != null) { + //System.out.println(name[j]); + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_11, case 005 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_11, case 006 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_11, case 007 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassAnnotationsTest")) fail("test_11, case 008 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_11, case 009 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_11, case 010 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_11, case 011 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_11, case 012 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_11, case 013 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_11, case 014 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_11, case 015 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_11, case 016 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + try{ + java.lang.reflect.Method am[] = ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getDeclaredMethods(); + long flg = 0; + for (int ii = 0; ii < am.length - 1; ii++){ + //System.out.println(am[ii].getName()); + if(am[ii].getName().equals("authorSurname")){ + flg += 1; + } else if(am[ii].getName().equals("authorFullName")){ + flg += 10; + } else if(am[ii].getName().equals("socialClass")){ + flg += 100; + } else if(am[ii].getName().equals("socialClasses")){ + flg += 1000; + } else if(am[ii].getName().equals("primitive")){ + flg += 10000; + } else if(am[ii].getName().equals("blackMarker")){ + flg += 100000; + } else if(am[ii].getName().equals("whiteMarkers")){ + flg += 1000000; + } else if(am[ii].getName().equals("constant")){ + flg += 10000000; + } else if(am[ii].getName().equals("constants")){ + flg += 100000000; + } else if(am[ii].getName().equals("toString")){ + flg += 1000000000; + } else if(am[ii].getName().equals("hashCode")){ + flg += 10000000000L; + } else if(am[ii].getName().equals("equals")){ + flg += 100000000000L; + } + } + if (flg != 111111111111L) fail("test_11, case 017 FAILED"); + }catch(Exception _){ + fail("test_11, case 018 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("primitive").getDefaultValue()!=null) fail("test_11, case 019 FAILED"); + if(((Integer)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("primitive").getDefaultValue()).intValue()!=777) fail("test_11, case 020 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_11, case 021 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("socialClass").getDefaultValue()!=null) fail("test_11, case 022 FAILED"); + if(!((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName().equals("java.lang.ClassAnnotationsTest$MA1$MA1_1$MA1_1_1$MA1_1_1_1$MA1_1_1_1_1$MA1_1_1_1_1_1$MA1_1_1_1_1_1_1$iiii$Prltr")) fail("test_11, case 023 FAILED: "+((Class)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("socialClass").getDefaultValue()).getName()); + }catch(NoSuchMethodException _){ + fail("test_11, case 024 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("authorSurname").getDefaultValue()!=null) fail("test_11, case 025 FAILED"); + if(!((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSurname").getDefaultValue()).equals("Zapreyev")) fail("test_11, case 026 FAILED: "+((String)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("authorSername").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_11, case 027 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("blackMarker").getDefaultValue()!=null) fail("test_11, case 028 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue()).getClass().getSimpleName().equals("MA1_1_1_1_1_1_1")) fail("test_11, case 029 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1)MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("blackMarker").getDefaultValue())); + }catch(NoSuchMethodException _){ + fail("test_11, case 030 FAILED"); + } + try{ + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).getClass().getMethod("whiteMarkers").getDefaultValue()!=null) fail("test_11, case 031 FAILED"); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.internalAnnotation[])MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.class.getMethod("whiteMarkers").getDefaultValue()).length != 3) fail("test_11, case 032 FAILED"); + }catch(NoSuchMethodException _){ + fail("test_11, case 033 FAILED"); + } + if(aa[i].annotationType() != ia.annotationType()) fail("test_11, case 034 FAILED: "+aa[i].annotationType().toString()+"|"+ia.annotationType().toString()); + if(!aa[i].annotationType().getSimpleName().equals(ia.annotationType().getSimpleName())) fail("test_11, case 035_1 FAILED: "+aa[i].annotationType().getSimpleName().equals(ia.annotationType().getSimpleName())); + if(aa[i].equals((Object) ia)) fail("test_11, case 035 FAILED: "+aa[i].equals((Object) ia)); + if(aa[i].hashCode() == ia.hashCode()) fail("test_11, case 036 FAILED: "+Integer.toString(aa[i].hashCode())+"|"+Integer.toString(ia.hashCode())); + if(aa[i].toString().equals(ia.toString())) fail("test_11, case 037 FAILED: "+aa[i].toString()+"|"+ia.toString()); + //System.out.println(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname().equals("Zapreyev")) fail("test_11, case 038 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorSurname()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0].equals("Zapreyev") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1].equals("Serguei") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2].equals("Stepanovich")) fail("test_11, case 039 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).authorFullName()[2]); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName().equals("Prltr")) fail("test_11, case 040 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClass().getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName().equals("Prltr") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName().equals("Brg") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName().equals("Krstnn") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName().equals("Arstcrt") || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName().equals("Clrc")) fail("test_11, case 041 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[0].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[1].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[2].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[3].getSimpleName()+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).socialClasses()[4].getSimpleName()); + if(!((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author().equals("UNKNOWN")) fail("test_11, case 042 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).blackMarker().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()!=true || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()!=(byte) 256 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()!='Z' || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()!=Double.MAX_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()!=Float.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()!=777 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()!=Long.MAX_VALUE + Long.MIN_VALUE || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()!=32655 || + !((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author().equals("Zapreyev 4")) fail("test_11, case 043 FAILED: "+Boolean.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr1()) +"|"+ + Byte.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr2()) +"|"+ + Character.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr3()) +"|"+ + Double.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr4()) +"|"+ + Float.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr5()) +"|"+ + Integer.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr6()) +"|"+ + Long.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr7()) +"|"+ + Short.toString(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].attr8()) +"|"+ + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).whiteMarkers()[0].itself().author()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.M_S) fail("test_11, case 044 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constant()); + if(((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.W_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.V_T5 || + ((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]!=MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii.ME1.E1_.E1_1.E1_2.E1_3.E1_4.E1_5.G_A_T5) fail("test_11, case 045 FAILED: "+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[0]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[1]+"|"+((MA1.MA1_1.MA1_1_1.MA1_1_1_1.MA1_1_1_1_1.MA1_1_1_1_1_1.MA1_1_1_1_1_1_1.iiii)aa[i]).constants()[2]); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassGenericsTest.java vm/tests/kernel/java/lang/ClassGenericsTest.java new file mode 100644 index 0000000..b640aa1 --- /dev/null +++ vm/tests/kernel/java/lang/ClassGenericsTest.java @@ -0,0 +1,1155 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +/** + * Area for supposed testing: top, member, local, enums, interfaces + * - fields, + * - methods + * - constructors + */ + +import java.lang.reflect.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import junit.framework.TestCase; + +/* + * Created on April 03, 2006 + * + * This ClassGenericsTest class is used to test the Core API Class, Method, Constructor, Field classes + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +@Retention(value=RetentionPolicy.RUNTIME) +@interface igt{ + abstract String author() default "Zapreyev"; +}; + +@SuppressWarnings(value={"unchecked"}) public class ClassGenericsTest<X> extends TestCase { + @igt class Mc001 {}; + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + /** + * getTypeParameters(), getGenericInterfaces(), getGenericSuperclass() of non-generalized member class + */ + public void test_1() { + if(Mc001.class.getTypeParameters().length!=0) fail("test_1, case 001 FAILED: "+Mc001.class.getTypeParameters()); + if(Mc001.class.getGenericInterfaces().length!=0) fail("test_1, case 002 FAILED: "+Mc001.class.getGenericInterfaces()); + if(!Mc001.class.getGenericSuperclass().equals(Object.class)) fail("test_1, case 003 FAILED: "+Mc001.class.getGenericSuperclass()); + } + + /** + * getTypeParameters(), getGenericInterfaces(), getGenericSuperclass() of generalized member class + */ + @igt interface MI001<T0 extends java.io.Serializable> {}; + @igt interface MI002<T1 extends MI001> {}; + @igt interface MI003<T2> extends MI001 {}; + @igt interface MI004<T2> /*extends MI001<MI001>*/ { + @igt interface MI005<T21, T22> /*extends MI003<MI002>*/ { + }; + }; + @igt(author="Serguei Stepanovich Zapreyev") public class Mc002<T3 extends ClassGenericsTest> { + @igt public class Mc004<T5 extends ClassGenericsTest> { + }; + }; + @igt class Mc003<T4 extends Thread &java.io.Serializable &Cloneable> extends java.lang.ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest> implements MI002<MI003<java.io.Serializable>>, MI003<MI003<Cloneable>>, MI004/*<Cloneable>*/.MI005<Type, Type> {}; + /**/@igt class Mc007\u0391<T7 extends Thread &java.io.Serializable &Cloneable> {}; + /**/@igt class Mc008\u0576\u06C0\u06F10<T8 extends Mc007\u0391 &java.io.Serializable &Cloneable> extends java.lang.ClassGenericsTest<? super Mc007\u0391>.Mc002<ClassGenericsTest> implements MI002<MI003<java.io.Serializable>>, MI003<MI003<Cloneable>>, MI004.MI005<Mc007\u0391, Type> {}; + /**/@igt class Mc010\u0576\u06C0\u06F10 {}; + /**/@igt interface MI010\u0576\u06C0\u06F10 {}; + /**/@igt class MC011\u0576\u06C0\u06F10 extends Mc010\u0576\u06C0\u06F10 implements MI010\u0576\u06C0\u06F10 {}; + public void test_2() { + //ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> f1; + Type ap[]; + TypeVariable tv; + Type ab[]; + Type ai[]; + Type aa[]; + Type aa2[]; + Type oc; + WildcardType wc; + Type aa3[]; + + ap = Mc003.class.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 001 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_2, case 002 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc003")) fail("test_2, case 003 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 004 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 005 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 006 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc003.class.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 007 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI002")) fail("test_2, case 008 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 009 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 010 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 011 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 012 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 013 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 014 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 015 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 016 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 017 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 018 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 019 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 020 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 021 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI004$MI005")) fail("test_2, case 022 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest$MI004")) fail("test_2, case 023 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 002 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 024 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 025 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc003.class.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_2, case 026 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((Class)((ParameterizedType)Mc003.class.getGenericSuperclass()).getRawType()).equals(Mc002.class)) fail("test_2, case 027 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((igt)((Class)((ParameterizedType)Mc003.class.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author().equals("Serguei Stepanovich Zapreyev")) fail("test_2, case 028 FAILED: "+((igt)((Class)((ParameterizedType)Mc003.class.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author()); + aa = ((ParameterizedType)Mc003.class.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 029 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 030 FAILED: "+aa[0]); + oc = ((ParameterizedType)Mc003.class.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_2, case 031 FAILED: "+Mc003.class.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_2, case 032 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 033 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 034 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 035 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 036 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 037 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + ap = Mc007\u0391.class.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 038 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T7")) fail("test_2, case 039 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc007\u0391")) fail("test_2, case 040 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 041 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 042 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 043 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc007\u0391.class.getGenericInterfaces(); + if(ai.length!=0) fail("test_2, case 001 FAILED: "+ap.length); + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc007\u0391.class.getGenericSuperclass() instanceof java.lang.Object)) fail("test_2, case 044 FAILED: "+Mc003.class.getGenericSuperclass()); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + ap = Mc008\u0576\u06C0\u06F10.class.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 045 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T8")) fail("test_2, case 046 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc008\u0576\u06C0\u06F10")) fail("test_2, case 047 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.ClassGenericsTest$Mc007\u0391")) fail("test_2, case 048 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 049 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 050 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc008\u0576\u06C0\u06F10.class.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 051 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI002")) fail("test_2, case 052 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 053 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 054 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 055 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 056 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 057 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 058 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 059 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 060 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 061 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_2, case 062 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 063 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 064 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 065 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI004$MI005")) fail("test_2, case 066 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest$MI004")) fail("test_2, case 067 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 068 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest$Mc007\u0391")) fail("test_2, case 069 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 070 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_2, case 071 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass()).getRawType()).equals(Mc002.class)) fail("test_2, case 072 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((igt)((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author().equals("Serguei Stepanovich Zapreyev")) fail("test_2, case 073 FAILED: "+((igt)((Class)((ParameterizedType)Mc003.class.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author()); + aa = ((ParameterizedType)Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 074 FAILED: "+aa.length);System.out.println(aa[0]); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest")) fail("test_2, case 075 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + oc = ((ParameterizedType)Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_2, case 076 FAILED: "+Mc003.class.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_2, case 077 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 078 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 079 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Mc007\u0391.class)) fail("test_2, case 080 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 081 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 082 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + //if (RuntimeAdditionalSupport1.openingFlag) { + ap = MC011\u0576\u06C0\u06F10.class.getTypeParameters(); + if(ap.length!=0) fail("test_2, case 083 FAILED: "+ap.length); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = MC011\u0576\u06C0\u06F10.class.getGenericInterfaces(); + if(ai.length!=1) fail("test_2, case 084 FAILED: "+ai.length); + if(!((Class)ai[0]).getName().equals("java.lang.ClassGenericsTest$MI010\u0576\u06C0\u06F10")) fail("test_2, case 085 FAILED: "+((Class)ai[0]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!((Class)MC011\u0576\u06C0\u06F10.class.getGenericSuperclass()).getName().equals("java.lang.ClassGenericsTest$Mc010\u0576\u06C0\u06F10")) fail("test_2, case 086 FAILED: "+((Class)Mc008\u0576\u06C0\u06F10.class.getGenericSuperclass()).getName()); + //} + + } + + /** + * getGenericType() of generalized type fields + */ + class Mc005 extends Thread implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + public Mc003<Mc005> fld0; + public ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> f0; + public X f111; + public ClassGenericsTest f112; + public void test_3() { + Type ft = null; + try{ + ft = java.lang.ClassGenericsTest.class.getField("fld0").getGenericType(); + //{boolean b = true; if(b) return;} + }catch(NoSuchFieldException e){ + fail("test_3, case 001 FAILED: "); + } + Type oc1 = (ParameterizedType)ft; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc003.class)) fail("test_3, case 002 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if (RuntimeAdditionalSupport1.openingFlag) { + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_3, case 003 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + } + Type aa0[] = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 004 FAILED: "+aa0.length); + if(!((ParameterizedType)aa0[0]).getRawType().equals(Mc005.class)) fail("test_3, case 005 FAILED: "+(/*(Class)*/aa0[0])); + if(!((ParameterizedType)aa0[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_3, case 006 FAILED: "+(/*(Class)*/aa0[0])); + + Class c = (Class)((ParameterizedType)ft).getRawType(); + + Type ap[] = c.getTypeParameters(); + if(ap.length!=1) fail("test_3, case 007 FAILED: "+ap.length); + TypeVariable tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_3, case 008 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc003")) fail("test_3, case 009 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + Type ab[] = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_3, case 010 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_3, case 011 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_3, case 012 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + Type ai[] = c.getGenericInterfaces(); + if(ai.length!=3) fail("test_3, case 013 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI002")) fail("test_3, case 014 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 015 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + Type aa[] = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 016 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_3, case 017 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 018 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + Type aa2[] = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_3, case 019 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_3, case 020 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_3, case 021 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 022 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 023 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI003")) fail("test_3, case 024 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 025 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_3, case 026 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_3, case 027 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest$MI004$MI005")) fail("test_3, case 028 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest$MI004")) fail("test_3, case 029 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_3, case 030 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_3, case 031 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_3, case 032 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(c.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_3, case 033 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((Class)((ParameterizedType)c.getGenericSuperclass()).getRawType()).equals(Mc002.class)) fail("test_3, case 034 FAILED: "+Mc003.class.getGenericSuperclass()); + if(!((igt)((Class)((ParameterizedType)c.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author().equals("Serguei Stepanovich Zapreyev")) fail("test_3, case 035 FAILED: "+((igt)((Class)((ParameterizedType)Mc003.class.getGenericSuperclass()).getRawType()).getAnnotations()[0]).author()); + aa = ((ParameterizedType)c.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 029 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 036 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + Type oc = ((ParameterizedType)c.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_3, case 037 FAILED: "+Mc003.class.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_3, case 038 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 039 FAILED: "+aa.length); + WildcardType wc = (WildcardType)aa[0]; + Type aa3[] = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_3, case 040 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_3, case 041 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_3, case 042 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_3, case 043 FAILED: "+((Class)aa3[0])); + + ////////////////////////////////////////////////////////////////////////////////////////////// + try{ + ft = java.lang.ClassGenericsTest.class.getField("f0").getGenericType(); + }catch(NoSuchFieldException e){ + fail("test_3, case 044 FAILED: "); + } + oc1 = (ParameterizedType)ft; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.Mc004.class)) fail("test_3, case 045 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>")) fail("test_3, case 046 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 047 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_3, case 048 FAILED: "+(/*(Class)*/aa0[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.class)) fail("test_3, case 049 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 050 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_3, case 051 FAILED: "+(/*(Class)*/aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>")) fail("test_3, case 052 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_3, case 053 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 054 FAILED: "+aa0.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_3, case 055 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_3, case 056 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_3, case 057 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_3, case 058 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// + try{ + ft = java.lang.ClassGenericsTest.class.getField("f111").getGenericType(); + }catch(NoSuchFieldException e){ + fail("test_3, case 059 FAILED: "); + } + tv = (TypeVariable)ft; + if(!tv.getName().equals("X")) fail("test_3, case 060 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest")) fail("test_3, case 061 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_3, case 062 FAILED: "+((Class)ab[0]).getName()); + } + + /** + * getGenericType() of non-generalized fields + */ + public void test_4() { + Type ft = null; + try{ + ft = java.lang.ClassGenericsTest.class.getField("f112").getGenericType(); + }catch(NoSuchFieldException e){ + fail("test_4, case 001 FAILED: "); + } + if(!((Class)ft).getName().equals("java.lang.ClassGenericsTest")) fail("test_4, case 002 FAILED: "+((Class)ft).getName()); + } + + /** + * getGenericExceptionTypes(), getGenericParameterTypes(), getGenericReturnType(), getTypeParameters(), toGenericString() of generalized method + */ + class Mc009\u0576\u06C0\u06F1 extends Throwable + implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + +/* + */ @igt(author="*****") public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> void foo1For_5(UuUuU a1) throws UuUuU, java.io.IOException {} +/* + */ public <\u0391 extends Throwable, TM1, TM2, TM3, TM4, TM5, TM6, TM7> X foo2For_5() throws \u0391, java.io.IOException {X f = null; return f;} +/* + */ public <\u0576\u06C0\u06F1 extends Throwable, \u0576\u06C0\u06F11 extends Throwable, \u0576\u06C0\u06F12 extends Throwable, \u0576\u06C0\u06F13 extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> TM2 foo3For_5(\u0576\u06C0\u06F1[] BAAB, TM1 a1, TM2 a2, ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> a3) throws \u0576\u06C0\u06F1, Throwable, \u0576\u06C0\u06F13, \u0576\u06C0\u06F12, \u0576\u06C0\u06F11, java.lang.ClassGenericsTest.Mc009\u0576\u06C0\u06F1 {TM2 f = null; return f;} +/* + */ public Mc003<Mc005> foo4For_5(ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<?> a1, @igt(author="Czar") Mc003<Mc005> a2, @igt(author="President") Mc003<Mc005> ... a3) {return a2;} +///* + */ public void foo4For_5(ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<?> a1, @igt(author="Czar") Mc003<Mc005> a2, @igt(author="President") Mc003<Mc005> ... a3) {} +/* - */ public ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> foo5For_5(X a1, Class<Type> a2, ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> a3) {return a3;} + public void test_5() { + Type rt; + TypeVariable tv; + ParameterizedType oc1; + Type aa0[]; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + Type aa3[]; + GenericArrayType gat; + WildcardType wc; + Method m = null; + try{ + //m = ClassGenericsTest.class.getMethod("foo1For_5"); + java.lang.reflect.Method am[] = ClassGenericsTest.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo1For_5")) { + m = am[i]; + } + } + //if(aa.length!=5) fail("test_5, case 0 FAILED: "+aa.length); + + if(!((igt)m.getAnnotation(igt.class)).author().equals("*****")) fail("test_3, case 001 FAILED: "+((igt)m.getAnnotation(igt.class)).author()); + } catch (Exception e) { + fail("test_5, case 002 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + if(!((Class)rt).getName().equals("void")) fail("test_5, case 003 FAILED: "+((Class)rt).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_5, case 004 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("UuUuU")) fail("test_5, case 005 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 006 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 007 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 008 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_5, case 009 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 010 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 011 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 012 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_5, case 013 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 014 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=3) fail("test_5, case 015 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 016 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_5, case 017 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_5, case 018 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_5, case 019 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("UuUuU")) fail("test_5, case 020 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_5, case 021 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("UuUuU")) fail("test_5, case 022 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_5, case 023 FAILED: "+((Class)aet[1]).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo2For_5")) { + m = am[i]; + } + } + //if(!((igt)m.getAnnotation(igt.class)).author().equals("*****")) fail("test_3, case 003 FAILED: "+((igt)m.getAnnotation(igt.class)).author()); + } catch (Exception e) { + fail("test_5, case 024 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + tv = ((TypeVariable)rt); + if(!tv.getName().equals("X")) fail("test_5, case 025 FAILED: "+((Class)rt).getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest")) fail("test_5, case 026 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=8) fail("test_5, case 027 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("\u0391")) fail("test_5, case 028 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 028 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 030 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 031 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_5, case 032 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 033 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 034 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 035 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_5, case 036 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 037 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 038 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 039 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[3]; + if(!tv.getName().equals("TM3")) fail("test_5, case 040 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 041 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 042 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 043 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[4]; + if(!tv.getName().equals("TM4")) fail("test_5, case 044 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 045 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 046 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 047 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[5]; + if(!tv.getName().equals("TM5")) fail("test_5, case 048 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 049 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 050 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 051 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[6]; + if(!tv.getName().equals("TM6")) fail("test_5, case 052 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 053 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 054 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 055 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[7]; + if(!tv.getName().equals("TM7")) fail("test_5, case 056 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo2For_5")) fail("test_5, case 057 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 058 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 059 FAILED: "+((Class)ab[0]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=0) fail("test_5, case 060 FAILED: "+ap.length); + //tv = (TypeVariable)ap[0]; + //if(!tv.getName().equals("UuUuU")) fail("test_5, case 003 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_5, case 061 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("\u0391")) fail("test_5, case 062 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_5, case 063 FAILED: "+((Class)aet[1]).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo3For_5")) { + m = am[i]; + } + } + //if(!((igt)m.getAnnotation(igt.class)).author().equals("*****")) fail("test_3, case 003 FAILED: "+((igt)m.getAnnotation(igt.class)).author()); + } catch (Exception e) { + fail("test_5, case 064 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + tv = ((TypeVariable)rt); + if(!tv.getName().equals("TM2")) fail("test_5, case 065 FAILED: "+((Class)rt).getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 066 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=6) fail("test_5, case 067 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_5, case 068 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 069 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 070 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 071 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("\u0576\u06C0\u06F11")) fail("test_5, case 072 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 073 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 074 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 075 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("\u0576\u06C0\u06F12")) fail("test_5, case 076 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 077 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 001 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 078 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[3]; + if(!tv.getName().equals("\u0576\u06C0\u06F13")) fail("test_5, case 079 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 080 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 081 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 082 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[4]; + if(!tv.getName().equals("TM1")) fail("test_5, case 083 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 084 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 085 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 086 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[5]; + if(!tv.getName().equals("TM2")) fail("test_5, case 087 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 088 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=3) fail("test_5, case 089 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 090 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_5, case 091 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_5, case 092 FAILED: "+((Class)ab[0]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=4) fail("test_5, case 093 FAILED: "+ap.length); + gat = (GenericArrayType)ap[0]; + tv = (TypeVariable)gat.getGenericComponentType(); + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_5, case 094 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 095 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)ap[1]; + if(!tv.getName().equals("TM1")) fail("test_5, case 096 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 097 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)ap[2]; + if(!tv.getName().equals("TM2")) fail("test_5, case 098 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 099 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + oc1 = (ParameterizedType)ap[3]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.Mc004.class)) fail("test_5, case 100 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>")) fail("test_5, case 101 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 102 FAILED: "+aa0.length); + //System.out.println(aa0[0]); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_5, case 103 FAILED: "+(aa0[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.class)) fail("test_5, case 104 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 105 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_5, case 106 FAILED: "+(aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>")) fail("test_5, case 107 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_5, case 108 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 109 FAILED: "+aa0.length); + wc = (WildcardType)aa0[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_5, case 110 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 111 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_5, case 112 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_5, case 113 FAILED: "+((Class)aa3[0])); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=6) fail("test_5, case 114 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_5, case 115 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 116 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + if(!((Class)aet[1]).getName().equals("java.lang.Throwable")) fail("test_5, case 117 FAILED: "+((Class)aet[1]).getName()); + tv = (TypeVariable)aet[2]; + if(!tv.getName().equals("\u0576\u06C0\u06F13")) fail("test_5, case 118 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 119 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)aet[3]; + if(!tv.getName().equals("\u0576\u06C0\u06F12")) fail("test_5, case 120 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 121 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)aet[4]; + if(!tv.getName().equals("\u0576\u06C0\u06F11")) fail("test_5, case 122 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo3For_5")) fail("test_5, case 123 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + + if(!((Class)aet[5]).getName().equals("java.lang.ClassGenericsTest$Mc009\u0576\u06C0\u06F1")) fail("test_5, case 1231 FAILED: "+((Class)rt).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo4For_5")) { + m = am[i]; + } + } + //if(!((igt)m.getAnnotation(igt.class)).author().equals("*****")) fail("test_3, case 003 FAILED: "+((igt)m.getAnnotation(igt.class)).author()); + } catch (Exception e) { + fail("test_5, case 124 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + oc1 = (ParameterizedType)rt; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc003.class)) fail("test_5, case 125 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if (RuntimeAdditionalSupport1.openingFlag) { + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_5, case 126 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + } + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_2, case 127 FAILED: "+aa0.length); + if(!((ParameterizedType)aa0[0]).getRawType().equals(Mc005.class)) fail("test_5, case 128 FAILED: "+(aa0[0])); + if(!((ParameterizedType)aa0[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_5, case 129 FAILED: "+(aa0[0])); + + //Class c = (Class)((ParameterizedType)ft).getRawType(); + Class c = (Class)(oc1).getRawType(); + + ap = c.getTypeParameters(); + if(ap.length!=1) fail("test_5, case 130 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_5, case 131 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc003")) fail("test_5, case 132 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 133 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_5, case 134 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_5, case 135 FAILED: "+((Class)ab[2]).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=0) fail("test_5, case 136 FAILED: "+atp.length); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=3) fail("test_5, case 137 FAILED: "+ap.length); + oc1 = (ParameterizedType)ap[0]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.Mc004.class)) fail("test_5, case 138 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>")) fail("test_5, case 139 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 140 FAILED: "+aa0.length); + + wc = (WildcardType)aa0[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=0) fail("test_5, case 141 FAILED: "+aa3.length); + //if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 050 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_5, case 142 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_5, case 143 FAILED: "+((Class)aa3[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.class)) fail("test_5, case 144 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 145 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_5, case 146 FAILED: "+(aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>")) fail("test_5, case 147 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_5, case 148 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_5, case 149 FAILED: "+aa0.length); + wc = (WildcardType)aa0[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_5, case 150 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 151 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_5, case 152 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_5, case 153 FAILED: "+((Class)aa3[0])); + /// + + oc1 = (ParameterizedType)ap[1]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc003.class)) fail("test_5, case 154 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if (RuntimeAdditionalSupport1.openingFlag) { + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_5, case 155 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + } + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_2, case 156 FAILED: "+aa0.length); + if(!((ParameterizedType)aa0[0]).getRawType().equals(Mc005.class)) fail("test_5, case 157 FAILED: "+(aa0[0])); + if(!((ParameterizedType)aa0[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_5, case 158 FAILED: "+(aa0[0])); + + c = (Class)(oc1).getRawType(); + + ap = c.getTypeParameters(); + if(ap.length!=1) fail("test_5, case 159 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_5, case 160 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc003")) fail("test_5, case 161 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 162 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_5, case 163 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_5, case 164 FAILED: "+((Class)ab[2]).getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=0) fail("test_5, case 165 FAILED: "+aet.length); + /////// + if (RuntimeAdditionalSupport1.openingFlag) { + if(!m.toGenericString().equals("public transient java.lang.ClassGenericsTest<X>.Mc003<java.lang.ClassGenericsTest<X>.Mc005> java.lang.ClassGenericsTest.foo4For_5(java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>.Mc004<?>,java.lang.ClassGenericsTest<X>.Mc003<java.lang.ClassGenericsTest<X>.Mc005>,java.lang.ClassGenericsTest<X>.Mc003<java.lang.ClassGenericsTest<X>.Mc005>[])")) fail("test_5, case 166 FAILED: |"+m.toGenericString()+"|"); + } + } + + /** + * getGenericExceptionTypes(), getGenericParameterTypes(), getGenericReturnType(), getTypeParameters(), toGenericString() of non-generalized method + */ + public void foo1For_5_5(int a1) throws java.io.IOException {} + public void test_5_5() { + Type rt; + Type ap[]; + Type aet[]; + Type atp[]; + Method m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo1For_5_5")) { + m = am[i]; + } + } + } catch (Exception e) { + fail("test_5_5, case 001 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + if(!((Class)rt).getName().equals("void")) fail("test_5_5, case 002 FAILED: "+((Class)rt).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=0) fail("test_5_5, case 003 FAILED: "+atp.length); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_5_5, case 004 FAILED: "+ap.length); + if(!((Class)ap[0]).getName().equals("int")) fail("test_5_5, case 005 FAILED: "+((Class)ap[0]).getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=1) fail("test_5_5, case 006 FAILED: "+ap.length); + if(!((Class)aet[0]).getName().equals("java.io.IOException")) fail("test_5_5, case 007 FAILED: "+((Class)aet[0]).getName()); + /////// + if(!m.toGenericString().equals("public void java.lang.ClassGenericsTest.foo1For_5_5(int) throws java.io.IOException")) fail("test_5_5, case 008 FAILED: |"+m.toGenericString()+"|"); + } + + /** + * getGenericExceptionTypes(), getGenericParameterTypes(), getGenericReturnType(), getTypeParameters(), toGenericString() of generalized constructor + */ + class MC006{ +/* + */ @igt(author="*****") public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> MC006(UuUuU a1) throws UuUuU, java.io.IOException {} +/* + */ public <\u0391 extends Throwable, TM1, TM2, TM3, TM4, TM5, TM6, TM7> MC006() throws \u0391, java.io.IOException {} +/* + */ public <\u0576\u06C0\u06F1 extends Throwable, \u0576\u06C0\u06F11 extends Throwable, \u0576\u06C0\u06F12 extends Throwable, \u0576\u06C0\u06F13 extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> MC006(\u0576\u06C0\u06F1[] BAAB, TM1 a1, TM2 a2, ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> a3) throws \u0576\u06C0\u06F1, Throwable, \u0576\u06C0\u06F13, \u0576\u06C0\u06F12, \u0576\u06C0\u06F11 {} +/* + */ public MC006(ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<?> a1, @igt(author="Czar") Mc003<Mc005> a2, @igt(author="President") Mc003<Mc005> ... a3) {} +/* - */ public MC006(X a1, Class<Type> a2, ClassGenericsTest<? super Class>.Mc002<ClassGenericsTest>.Mc004<ClassGenericsTest> a3) {} + } + + public void test_6() { + TypeVariable tv; + ParameterizedType oc1; + Type aa0[]; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + GenericArrayType gat; + Constructor<ClassGenericsTest.MC006> m = null; + try{ + //for(int i = 0; i <ClassGenericsTest.MC006.class.getDeclaredConstructors().length; i++ ) { + // System.out.println(ClassGenericsTest.MC006.class.getDeclaredConstructors()[i]); + //} + m = ClassGenericsTest.MC006.class.getConstructor(new Class[]{ClassGenericsTest.class, Throwable.class}); + if(!(m.getAnnotation(igt.class)).author().equals("*****")) fail("test_6, case 001 FAILED: "+((igt)m.getAnnotation(igt.class)).author()); + } catch (Exception e) { + fail("test_6, case 002 FAILED: "+e.toString()); + } + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_6, case 004 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("UuUuU")) fail("test_6, case 005 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 006 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 007 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 008 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_6, case 009 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 010 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 011 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 012 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_6, case 013 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 014 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=3) fail("test_6, case 015 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_6, case 016 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 017 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 018 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_6, case 019 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("UuUuU")) fail("test_6, case 020 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_6, case 021 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("UuUuU")) fail("test_6, case 022 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_6, case 023 FAILED: "+((Class)aet[1]).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + m = ClassGenericsTest.MC006.class.getConstructor(new Class[]{ClassGenericsTest.class}); + } catch (Exception e) { + fail("test_6, case 024 FAILED: "+e.toString()); + } + /////// + atp = m.getTypeParameters(); + if(atp.length!=8) fail("test_6, case 027 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("\u0391")) fail("test_6, case 028 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 028 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 030 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 031 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_6, case 032 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 033 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 034 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 035 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_6, case 036 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 037 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 038 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 039 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[3]; + if(!tv.getName().equals("TM3")) fail("test_6, case 040 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 041 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 042 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 043 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[4]; + if(!tv.getName().equals("TM4")) fail("test_6, case 044 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 045 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 046 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 047 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[5]; + if(!tv.getName().equals("TM5")) fail("test_6, case 048 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 049 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 050 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 051 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[6]; + if(!tv.getName().equals("TM6")) fail("test_6, case 052 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 053 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 054 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 055 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[7]; + if(!tv.getName().equals("TM7")) fail("test_6, case 056 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 057 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 058 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 059 FAILED: "+((Class)ab[0]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=0) fail("test_6, case 060 FAILED: "+ap.length); + //tv = (TypeVariable)ap[0]; + //if(!tv.getName().equals("UuUuU")) fail("test_6, case 003 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_6, case 061 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("\u0391")) fail("test_6, case 062 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_6, case 063 FAILED: "+((Class)aet[1]).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + m = ClassGenericsTest.MC006.class.getConstructor(new Class[]{java.lang.ClassGenericsTest.class,java.lang.Throwable[].class,java.lang.Object.class,java.lang.Thread.class,java.lang.ClassGenericsTest.Mc002.Mc004.class}); + } catch (Exception e) { + fail("test_6, case 064 FAILED: "+e.toString()); + } + /////// + atp = m.getTypeParameters(); + if(atp.length!=6) fail("test_6, case 067 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_6, case 068 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 069 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 070 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 071 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("\u0576\u06C0\u06F11")) fail("test_6, case 072 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 073 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 074 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 075 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("\u0576\u06C0\u06F12")) fail("test_6, case 076 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 077 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 001 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 078 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[3]; + if(!tv.getName().equals("\u0576\u06C0\u06F13")) fail("test_6, case 079 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 080 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 081 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 082 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[4]; + if(!tv.getName().equals("TM1")) fail("test_6, case 083 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 084 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 085 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 086 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[5]; + if(!tv.getName().equals("TM2")) fail("test_6, case 087 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 088 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=3) fail("test_6, case 089 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_6, case 090 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_6, case 091 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_6, case 092 FAILED: "+((Class)ab[0]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=4) fail("test_6, case 093 FAILED: "+ap.length); + gat = (GenericArrayType)ap[0]; + tv = (TypeVariable)gat.getGenericComponentType(); + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_6, case 094 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 095 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)ap[1]; + if(!tv.getName().equals("TM1")) fail("test_6, case 096 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 097 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)ap[2]; + if(!tv.getName().equals("TM2")) fail("test_6, case 098 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 099 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + oc1 = (ParameterizedType)ap[3]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.Mc004.class)) fail("test_6, case 100 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>")) fail("test_6, case 101 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 102 FAILED: "+aa0.length); + //System.out.println(aa0[0]); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_6, case 103 FAILED: "+(aa0[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.class)) fail("test_6, case 104 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 105 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_6, case 106 FAILED: "+(aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>")) fail("test_6, case 107 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_6, case 108 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 109 FAILED: "+aa0.length); + WildcardType wc = (WildcardType)aa0[0]; + Type aa3[] = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_6, case 110 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 111 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_6, case 112 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_6, case 113 FAILED: "+((Class)aa3[0])); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=5) fail("test_6, case 114 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("\u0576\u06C0\u06F1")) fail("test_6, case 115 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 116 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + if(!((Class)aet[1]).getName().equals("java.lang.Throwable")) fail("test_6, case 117 FAILED: "+((Class)aet[1]).getName()); + tv = (TypeVariable)aet[2]; + if(!tv.getName().equals("\u0576\u06C0\u06F13")) fail("test_6, case 118 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 119 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)aet[3]; + if(!tv.getName().equals("\u0576\u06C0\u06F12")) fail("test_6, case 120 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 121 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + tv = (TypeVariable)aet[4]; + if(!tv.getName().equals("\u0576\u06C0\u06F11")) fail("test_6, case 122 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$MC006")) fail("test_6, case 123 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m = null; + try{ + m = ClassGenericsTest.MC006.class.getConstructor(new Class[]{java.lang.ClassGenericsTest.class,java.lang.ClassGenericsTest.Mc002.Mc004.class,java.lang.ClassGenericsTest.Mc003.class,java.lang.ClassGenericsTest.Mc003[].class}); + } catch (Exception e) { + fail("test_6, case 124 FAILED: "+e.toString()); + } + /////// + atp = m.getTypeParameters(); + if(atp.length!=0) fail("test_6, case 136 FAILED: "+atp.length); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=3) fail("test_6, case 137 FAILED: "+ap.length); + oc1 = (ParameterizedType)ap[0]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.Mc004.class)) fail("test_6, case 138 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>")) fail("test_6, case 139 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 140 FAILED: "+aa0.length); + + wc = (WildcardType)aa0[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=0) fail("test_6, case 141 FAILED: "+aa3.length); + //if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 050 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_6, case 142 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_6, case 143 FAILED: "+((Class)aa3[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.Mc002.class)) fail("test_6, case 144 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 145 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest.class)) fail("test_6, case 146 FAILED: "+(aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest<? super java.lang.Class>")) fail("test_6, case 147 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest.class)) fail("test_6, case 148 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_6, case 149 FAILED: "+aa0.length); + wc = (WildcardType)aa0[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_6, case 150 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 151 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_6, case 152 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_6, case 153 FAILED: "+((Class)aa3[0])); + /// + + oc1 = (ParameterizedType)ap[1]; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest.Mc003.class)) fail("test_6, case 154 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if (RuntimeAdditionalSupport1.openingFlag) { + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_6, case 155 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + } + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_2, case 156 FAILED: "+aa0.length); + if(!((ParameterizedType)aa0[0]).getRawType().equals(Mc005.class)) fail("test_6, case 157 FAILED: "+(aa0[0])); + if(!((ParameterizedType)aa0[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest<X>")) fail("test_6, case 158 FAILED: "+(aa0[0])); + + Class c = (Class)(oc1).getRawType(); + + ap = c.getTypeParameters(); + if(ap.length!=1) fail("test_6, case 159 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_6, case 160 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest$Mc003")) fail("test_6, case 161 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_6, case 162 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_6, case 163 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_6, case 164 FAILED: "+((Class)ab[2]).getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=0) fail("test_6, case 165 FAILED: "+ap.length); + /////// + if (RuntimeAdditionalSupport1.openingFlag) { + if(!m.toGenericString().equals("public transient java.lang.ClassGenericsTest$MC006(java.lang.ClassGenericsTest<? super java.lang.Class>.Mc002<java.lang.ClassGenericsTest>.Mc004<?>,java.lang.ClassGenericsTest<X>.Mc003<java.lang.ClassGenericsTest<X>.Mc005>,java.lang.ClassGenericsTest<X>.Mc003<java.lang.ClassGenericsTest<X>.Mc005>[])")) fail("test_6, case 166 FAILED: |"+m.toGenericString()+"|"); + } +//java.lang.ClassGenericsTest.class,java.lang.Object.class,java.lang.Class.class,java.lang.ClassGenericsTest$Mc002$Mc004.class + } + + /** + * getGenericExceptionTypes(), getGenericParameterTypes(), getGenericReturnType(), getTypeParameters(), toGenericString() of non-generalized constructor + */ + class MC014{ + public MC014(float a1) throws java.io.IOException {} + } + public void test_6_6() { + Type ap[]; + Type aet[]; + Type atp[]; + Constructor m = null; + m = null; + try{ + m = ClassGenericsTest.MC014.class.getConstructor(new Class[]{java.lang.ClassGenericsTest.class,float.class}); + } catch (Exception e) { + fail("test_6_5, case 001 FAILED: "+e.toString()); + } + atp = m.getTypeParameters(); + if(atp.length!=0) fail("test_6_5, case 002 FAILED: "+atp.length); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=2) fail("test_6_5, case 003 FAILED: "+ap.length); + if(!((Class)ap[0]).getName().equals("java.lang.ClassGenericsTest")) fail("test_6_5, case 004 FAILED: "+((Class)ap[0]).getName()); + if(!((Class)ap[1]).getName().equals("float")) fail("test_6_5, case 005 FAILED: "+((Class)ap[0]).getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=1) fail("test_6_5, case 006 FAILED: "+ap.length); + if(!((Class)aet[0]).getName().equals("java.io.IOException")) fail("test_6_5, case 007 FAILED: "+((Class)aet[0]).getName()); + /////// + if(!m.toGenericString().equals("public java.lang.ClassGenericsTest$MC014(java.lang.ClassGenericsTest,float) throws java.io.IOException")) fail("test_6_5, case 008 FAILED: |"+m.toGenericString()+"|"); + + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassGenericsTest2.java vm/tests/kernel/java/lang/ClassGenericsTest2.java new file mode 100644 index 0000000..27b18d6 --- /dev/null +++ vm/tests/kernel/java/lang/ClassGenericsTest2.java @@ -0,0 +1,324 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +/** + * Area for supposed testing is arrays returning mrthods for: + * - classes, interfaces + * - methods + * - constructors + **/ + +import java.lang.reflect.*; + +import junit.framework.TestCase; + +/* + * Created on May 02, 2006 + * + * This ClassGenericsTest2 class is used to test the Core API Class, Method, Constructor classes + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +@SuppressWarnings(value={"unchecked"}) public class ClassGenericsTest2<X> extends TestCase { + class Mc201 {}; + + interface MI201<T0 extends java.io.Serializable> {}; + interface MI202<T1 extends MI201> {}; + interface MI203<T2> extends MI201 {}; + interface MI204<T2> { + interface MI205<T21, T22> { + }; + }; + public class Mc202<T3 extends ClassGenericsTest2> { + public class Mc204<T5 extends ClassGenericsTest2> { + }; + }; + class Mc203<T4 extends Thread &java.io.Serializable &Cloneable> extends java.lang.ClassGenericsTest2<? super Class>.Mc202<ClassGenericsTest2> implements MI202<MI203<java.io.Serializable>>, MI203<MI203<Cloneable>>, MI204.MI205<Type, Type> {}; + /** + * check immutability for results of getTypeParameters(), getGenericInterfaces() methods of generalized member class + * and the attendant reflect implementation methods for WildcardType(getLowerBounds(), getUpperBounds()), + * TypeVariable(getBounds()), ParameterizedType(getActualTypeArguments()) + */ + public void test_2() { + Type ap[]; + TypeVariable tv; + Type ab[]; + Type ai[]; + Type aa[]; + Type aa2[]; + Type oc; + WildcardType wc; + Type aa3[]; + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc203.class.getInterfaces(); +//--- + ai[0] = null; + ai = Mc203.class.getInterfaces(); + if(ai.length!=3) fail("test_2, case 001 FAILED: "+ai.length); + if(!((Class)ai[0]).getName().equals("java.lang.ClassGenericsTest2$MI202")) fail("test_2, case 002 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + + ap = Mc203.class.getTypeParameters(); + tv = (TypeVariable)ap[0]; + ab = tv.getBounds(); +//--- + ab[0] = null; + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 003 FAILED: "+((Class)ab[0]).getName()); +//--- + ap[0] = null; + ap = Mc203.class.getTypeParameters(); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_2, case 004 FAILED: "+tv.getName()); +//--- + ap = null; + ap = Mc203.class.getTypeParameters(); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_2, case 005 FAILED: "+tv.getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// +//--- + ai = Mc203.class.getGenericInterfaces(); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + aa[0] = null; + aa[1] = null; + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 006 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 007 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 008 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + ai[2] = null; + ai = Mc203.class.getGenericInterfaces(); + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest2$MI204$MI205")) fail("test_2, case 009 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest2$MI204")) fail("test_2, case 010 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + aa2[0] = null; + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 009 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 011 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 012 FAILED: "+aa.length); + aa[0] = null; + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest2$MI203")) fail("test_2, case 013 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest2")) fail("test_2, case 014 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + ai[1] = null; + ai = Mc203.class.getGenericInterfaces(); + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest2$MI203")) fail("test_2, case 015 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest2")) fail("test_2, case 016 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + aa2[0] = null; + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 017 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 018 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + aa[0] = null; + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 019 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest2$MI203")) fail("test_2, case 020 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest2")) fail("test_2, case 021 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); +//--- + ai = Mc203.class.getGenericInterfaces(); + ai[0] = null; + ai = Mc203.class.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 022 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest2$MI202")) fail("test_2, case 023 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest2")) fail("test_2, case 024 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + + ai = Mc203.class.getInterfaces(); + ai[0] = null; + ai = Mc203.class.getInterfaces(); + if(ai.length!=3) fail("test_2, case 025 FAILED: "+ai.length); + if(!((Class)ai[0]).getName().equals("java.lang.ClassGenericsTest2$MI202")) fail("test_2, case 026 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + aa = ((ParameterizedType)Mc203.class.getGenericSuperclass()).getActualTypeArguments(); + aa[0] = null; + aa = ((ParameterizedType)Mc203.class.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 027 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest2")) fail("test_2, case 028 FAILED: "+((Class)aa[0]).getName()); +//--- + oc = ((ParameterizedType)Mc203.class.getGenericSuperclass()).getOwnerType(); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + aa[0] = null; + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 029 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; +//--- + aa3 = wc.getLowerBounds(); + aa3[0] = null; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 030 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 031 FAILED: "+((Class)aa3[0])); +//--- + aa3 = wc.getUpperBounds(); + aa3[0] = null; + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 032 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 033 FAILED: "+((Class)aa3[0])); + } + + /** + * check immutability for results of getGenericExceptionTypes(), getGenericParameterTypes(), getTypeParameters() of generalized method + * and the attendant reflect implementation methods for WildcardType(getLowerBounds(), getUpperBounds()), + * TypeVariable(getBounds()), ParameterizedType(getActualTypeArguments()) + */ + class Mc205 extends Thread implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + class Mc209 extends Throwable implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> void foo1For_5(UuUuU a1) throws UuUuU, java.io.IOException {} + public void test_5() { + TypeVariable tv; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + Method m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest2.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo1For_5")) { + m = am[i]; + } + } + } catch (Exception e) { + fail("test_5, case 001 FAILED: "+e.toString()); + } + /////// + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_5, case 002 FAILED: "+atp.length); +//--- + atp[2] = null; + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_5, case 003 FAILED: "+atp.length); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_5, case 004 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 005 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); +//--- + ab[1] = null; + ab = tv.getBounds(); + if(ab.length!=3) fail("test_5, case 006 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 007 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 008 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 009 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_5, case 010 FAILED: "+ap.length); +//--- + ap[0] = null; + ap = m.getGenericParameterTypes(); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("UuUuU")) fail("test_5, case 011 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_5, case 012 FAILED: "+ap.length); +//--- + aet[0] = null; + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_5, case 013 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("UuUuU")) fail("test_5, case 014 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_5, case 015 FAILED: "+((Class)aet[1]).getName()); + } + + /** + * check immutability for results of getGenericExceptionTypes(), getGenericParameterTypes(), getTypeParameters() of generalized constructor + * and the attendant reflect implementation methods for WildcardType(getLowerBounds(), getUpperBounds()), + * TypeVariable(getBounds()), ParameterizedType(getActualTypeArguments()) + */ + class MC006{ + public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> MC006(UuUuU a1) throws UuUuU, java.io.IOException {} + } + + public void test_6() { + TypeVariable tv; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + Constructor m = null; + try{ + m = ClassGenericsTest2.MC006.class.getConstructor(new Class[]{ClassGenericsTest2.class, Throwable.class}); + } catch (Exception e) { + fail("test_6, case 001 FAILED: "+e.toString()); + } + /////// + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_6, case 002 FAILED: "+atp.length); +//--- + atp[2] = null; + atp = m.getTypeParameters(); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_6, case 003 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest2$MC006")) fail("test_6, case 004 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); +//--- + ab[1] = null; + ab = tv.getBounds(); + if(ab.length!=3) fail("test_6, case 005 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_6, case 006 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 007 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 008 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_6, case 009 FAILED: "+ap.length); +//--- + ap[0] = null; + ap = m.getGenericParameterTypes(); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("UuUuU")) fail("test_6, case 010 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_6, case 011 FAILED: "+ap.length); +//--- + aet[0] = null; + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_6, case 012 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("UuUuU")) fail("test_6, case 013 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_6, case 014 FAILED: "+((Class)aet[1]).getName()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassGenericsTest3.java vm/tests/kernel/java/lang/ClassGenericsTest3.java new file mode 100644 index 0000000..5e59e73 --- /dev/null +++ vm/tests/kernel/java/lang/ClassGenericsTest3.java @@ -0,0 +1,455 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +/** + * Area for supposed testing is arrays returning mrthods for: + * - classes, interfaces + * - methods + * - constructors + **/ + +import java.lang.reflect.*; + +import junit.framework.TestCase; + +/* + * Created on May 03, 2006 + * + * This ClassGenericsTest3 class is used to test the Core API Class, Method, Constructor classes + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +@SuppressWarnings(value={"all"}) public class ClassGenericsTest3<$X$> extends TestCase { + class $Mc3$01 {}; + + interface $MI3$01<$T$0 extends java.io.Serializable> {}; + interface $MI3$02<_T$_1$ extends $MI3$01> {}; + interface $MI3$03<T2$> extends $MI3$01 {}; + interface $MI3$04<T$2> { + interface $MI3$05<_T$21_, _$T22> { + }; + }; + public class $Mc3$02<$_T3_$ extends ClassGenericsTest3> { + public class $Mc3$04<T5 extends ClassGenericsTest3> { + }; + }; + public class $Mc4$<_> { + public class $Mc5<_> { + }; + public class Mc5<_> { + }; + }; + public interface $Mi4$<_> { + public interface $$$$$Mi5<_> { + }; + public interface $$$$Mi5<_> { + }; + public interface $$$Mi5<_> { + }; + public interface $$Mi5<_> { + }; + public interface $Mi5<_> { + }; + public interface Mi5<_> { + }; + public interface Mi5$<_> { + }; + }; + public interface $Mi4<_> { +/* //compiler errors are risen here: + public interface $$Mi5<_> { + }; + public interface $Mi5<_> { + }; + public interface Mi5<_> { + }; + public interface Mi5$<_> { + }; +*/ + }; + //class C1<$_T4_$_ extends $Mc4$.$Mc5 &$Mi4$.$Mi5 &$Mi4$.Mi5 &$Mi4$> extends $Mc4$<? super Class>.Mc5<Class> implements $Mi4$<$Mi4$.$Mi5<java.io.Serializable>>, $Mi4$.Mi5$<Cloneable>, $Mi4$.Mi5 {}; + //class C1<$_T4_$_ extends $Mc4$<Integer>.$Mc5<Integer> &$Mi4$.$Mi5 &$Mi4$.Mi5 &$Mi4$> extends $Mc4$<Float>.Mc5<Class> implements $Mi4$.Mi5 {}; + class C1<$_T4_$_ extends $Mc4$<Integer>.$Mc5<Integer> &$Mi4$.$$$$$Mi5 &$Mi4$.$$$$Mi5 &$Mi4$.$$$Mi5 &$Mi4$.$$Mi5 &$Mi4$.$Mi5 &$Mi4$.Mi5 &$Mi4$> implements $Mi4$.Mi5 {}; + public void test_0() { + Type ap[]; + TypeVariable tv; + Type ab[]; + ap = $Mc4$.class.getTypeParameters(); + ap = $Mc4$.$Mc5.class.getTypeParameters(); + ap = $Mc4$.Mc5.class.getTypeParameters(); + ap = $Mi4$.class.getTypeParameters(); + ap = $Mi4$.$Mi5.class.getTypeParameters(); + ap = $Mi4$.Mi5.class.getTypeParameters(); + ap = C1.class.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 001 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("$_T4_$_")) fail("test_2, case 002 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$C1")) fail("test_2, case 003 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$Mc4$$$Mc5")) fail("test_2, case 004 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + //if(RuntimeAdditionalSupport1.openingFlag || RuntimeAdditionalTest0.os.equals("Lin")) { + if(true) { + // is it a bug?: +/*???*/ //if(!((ParameterizedType)ab[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest3$$Mc4$<java.lang.Integer>.$Mc5<java.lang.Integer>")) fail("test_2, case 005 FAILED: "+((ParameterizedType)ab[0]).getOwnerType().toString()); +/*???*/ if(!((ParameterizedType)ab[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest3<$X$>.$Mc4$<java.lang.Integer>")) fail("test_2, case 005 FAILED: "+((ParameterizedType)ab[0]).getOwnerType().toString()); + } else { + // but it is the bug in eclipse compiler?: + if(!((ParameterizedType)ab[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest3.$Mc4$<java.lang.Integer>")) fail("test_2, case 005 FAILED: "+((ParameterizedType)ab[0]).getOwnerType().toString()); + } + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_2, case 006 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[2]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$$$$$Mi5") || !((Class)ab[2]).getSimpleName().equals("$$$$Mi5")) fail("test_2, case 006 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[3]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$$$$Mi5") || !((Class)ab[3]).getSimpleName().equals("$$$Mi5")) fail("test_2, case 006 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[4]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$$$Mi5") || !((Class)ab[4]).getSimpleName().equals("$$Mi5")) fail("test_2, case 006 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[5]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$$Mi5") || !((Class)ab[5]).getSimpleName().equals("$Mi5")) fail("test_2, case 006 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[6]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$$Mi5") || !((Class)ab[6]).getSimpleName().equals("Mi5")) fail("test_2, case 007 FAILED: "+((Class)ab[2]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[7]).getName().equals("java.lang.ClassGenericsTest3$$Mi4$")) fail("test_2, case 008 FAILED: "+((Class)ab[7]).getName()); + } + class $Mc3$03<$_T4_$_ extends Thread &java.io.Serializable &Cloneable> extends java.lang.ClassGenericsTest3<? super Class>.$Mc3$02<ClassGenericsTest3> implements $MI3$02<$MI3$03<java.io.Serializable>>, $MI3$03<$MI3$03<Cloneable>>, $MI3$04.$MI3$05<Type, Type> {}; + /** + * use "$" symbol in identifiers for generalized member class + */ + public void test_2() { + Type ap[]; + TypeVariable tv; + Type ab[]; + Type ai[]; + Type aa[]; + Type aa2[]; + Type oc; + WildcardType wc; + Type aa3[]; + ap = $Mc3$03.class.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 001 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("$_T4_$_")) fail("test_2, case 002 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$$Mc3$03")) fail("test_2, case 003 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 004 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 005 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 006 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = $Mc3$03.class.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 007 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$02")) fail("test_2, case 008 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_2, case 009 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 010 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_2, case 011 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_2, case 012 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 013 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 014 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_2, case 015 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_2, case 016 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 017 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_2, case 018 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_2, case 019 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 020 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 021 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$04$$MI3$05")) fail("test_2, case 022 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$04")) fail("test_2, case 023 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 002 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 024 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 025 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!($Mc3$03.class.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_2, case 026 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + if(!((Class)((ParameterizedType)$Mc3$03.class.getGenericSuperclass()).getRawType()).equals($Mc3$02.class)) fail("test_2, case 027 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + aa = ((ParameterizedType)$Mc3$03.class.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 029 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest3")) fail("test_2, case 030 FAILED: "+((Class)aa[0]).getName()); + oc = ((ParameterizedType)$Mc3$03.class.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).equals(java.lang.ClassGenericsTest3.class)) fail("test_2, case 031 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_2, case 032 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 033 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 034 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 035 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 036 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 037 FAILED: "+((Class)aa3[0])); + } + + /** + * use "$" symbol in identifiers for generalized type fields + */ + class $Mc3$05 extends Thread implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + public $Mc3$03<$Mc3$05> fld0; + public ClassGenericsTest3<? super Class>.$Mc3$02<ClassGenericsTest3>.$Mc3$04<ClassGenericsTest3> f0; + public $X$ f111; + public ClassGenericsTest3 f112; + public void test_3() { + Type ft = null; + try{ + ft = java.lang.ClassGenericsTest3.class.getField("fld0").getGenericType(); + //{boolean b = true; if(b) return;} + }catch(NoSuchFieldException e){ + fail("test_3, case 001 FAILED: "); + } + Type oc1 = (ParameterizedType)ft; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest3.$Mc3$03.class)) fail("test_3, case 002 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if (RuntimeAdditionalSupport1.openingFlag) { + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest3<$X$>")) fail("test_3, case 003 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + } + Type aa0[] = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 004 FAILED: "+aa0.length); + if(!((ParameterizedType)aa0[0]).getRawType().equals($Mc3$05.class)) fail("test_3, case 005 FAILED: "+(/*(Class)*/aa0[0])); + if(!((ParameterizedType)aa0[0]).getOwnerType().toString().equals("java.lang.ClassGenericsTest3<$X$>")) fail("test_3, case 006 FAILED: "+(/*(Class)*/aa0[0])); + + Class c = (Class)((ParameterizedType)ft).getRawType(); + + Type ap[] = c.getTypeParameters(); + if(ap.length!=1) fail("test_3, case 007 FAILED: "+ap.length); + TypeVariable tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("$_T4_$_")) fail("test_3, case 008 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$$Mc3$03")) fail("test_3, case 009 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + Type ab[] = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_3, case 010 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_3, case 011 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_3, case 012 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + Type ai[] = c.getGenericInterfaces(); + if(ai.length!=3) fail("test_3, case 013 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$02")) fail("test_3, case 014 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 015 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + Type aa[] = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 016 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_3, case 017 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 018 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + Type aa2[] = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_3, case 019 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_3, case 020 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_3, case 021 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 022 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 023 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$03")) fail("test_3, case 024 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 025 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_3, case 026 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_3, case 027 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$04$$MI3$05")) fail("test_3, case 028 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("java.lang.ClassGenericsTest3$$MI3$04")) fail("test_3, case 029 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_3, case 030 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_3, case 031 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_3, case 032 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(c.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_3, case 033 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + if(!((Class)((ParameterizedType)c.getGenericSuperclass()).getRawType()).equals($Mc3$02.class)) fail("test_3, case 034 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + aa = ((ParameterizedType)c.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 029 FAILED: "+aa.length);System.out.println(aa[0]); + if(!((Class)aa[0]).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 036 FAILED: "+((Class)aa[0]).getName()); + Type oc = ((ParameterizedType)c.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).equals(java.lang.ClassGenericsTest3.class)) fail("test_3, case 037 FAILED: "+$Mc3$03.class.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_3, case 038 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_3, case 039 FAILED: "+aa.length); + WildcardType wc = (WildcardType)aa[0]; + Type aa3[] = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_3, case 040 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_3, case 041 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_3, case 042 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_3, case 043 FAILED: "+((Class)aa3[0])); + + ////////////////////////////////////////////////////////////////////////////////////////////// + try{ + ft = java.lang.ClassGenericsTest3.class.getField("f0").getGenericType(); + }catch(NoSuchFieldException e){ + fail("test_3, case 044 FAILED: "); + } + oc1 = (ParameterizedType)ft; + if(!((Class)((ParameterizedType)oc1).getRawType()).equals(java.lang.ClassGenericsTest3.$Mc3$02.$Mc3$04.class)) fail("test_3, case 045 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((ParameterizedType)oc1).getOwnerType().toString().equals("java.lang.ClassGenericsTest3<? super java.lang.Class>.$Mc3$02<java.lang.ClassGenericsTest3>")) fail("test_3, case 046 FAILED: "+((ParameterizedType)oc1).getOwnerType().toString()); + aa0 = ((ParameterizedType)oc1).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 047 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest3.class)) fail("test_3, case 048 FAILED: "+(/*(Class)*/aa0[0])); + + if(!((Class)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest3.$Mc3$02.class)) fail("test_3, case 049 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + aa0 = ((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 050 FAILED: "+aa0.length); + if(!((Class)aa0[0]).equals(ClassGenericsTest3.class)) fail("test_3, case 051 FAILED: "+(/*(Class)*/aa0[0])); + if(!((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType().toString().equals("java.lang.ClassGenericsTest3<? super java.lang.Class>")) fail("test_3, case 052 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + if(!((Class)((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getRawType()).equals(java.lang.ClassGenericsTest3.class)) fail("test_3, case 053 FAILED: "+((Class)((ParameterizedType)oc1).getRawType())); + + aa0 = ((ParameterizedType)((ParameterizedType)((ParameterizedType)oc1).getOwnerType()).getOwnerType()).getActualTypeArguments(); + if(aa0.length!=1) fail("test_3, case 054 FAILED: "+aa0.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_3, case 055 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_3, case 056 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_3, case 057 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_3, case 058 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// + try{ + ft = java.lang.ClassGenericsTest3.class.getField("f111").getGenericType(); + }catch(NoSuchFieldException e){ + fail("test_3, case 059 FAILED: "); + } + tv = (TypeVariable)ft; + if(!tv.getName().equals("$X$")) fail("test_3, case 060 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3")) fail("test_3, case 061 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_3, case 062 FAILED: "+((Class)ab[0]).getName()); + } + + /** + * use "$" symbol in identifiers for generalized method + */ + class $Mc3$09 extends Throwable implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 0L; + }; + public <U$uUuU_ extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> void foo1For_5(U$uUuU_ a1) throws U$uUuU_, java.io.IOException {} + public void test_5() { + Type rt; + TypeVariable tv; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + Method m = null; + try{ + java.lang.reflect.Method am[] = ClassGenericsTest3.class.getDeclaredMethods(); + for (int i = 0; i < am.length; i++) { + if (am[i].getName().equals("foo1For_5")) { + m = am[i]; + } + } + } catch (Exception e) { + fail("test_5, case 001 FAILED: "+e.toString()); + } + rt = m.getGenericReturnType(); + if(!((Class)rt).getName().equals("void")) fail("test_5, case 003 FAILED: "+((Class)rt).getName()); + /////// + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_5, case 004 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_5, case 005 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 006 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 007 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_5, case 008 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_5, case 009 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 010 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_5, case 011 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_5, case 012 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_5, case 013 FAILED: "+tv.getName()); + if(!((Method)tv.getGenericDeclaration()).getName().equals("foo1For_5")) fail("test_5, case 014 FAILED: "+((Method)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=3) fail("test_5, case 015 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_5, case 016 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_5, case 017 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_5, case 018 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_5, case 019 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_5, case 020 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_5, case 021 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_5, case 022 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_5, case 023 FAILED: "+((Class)aet[1]).getName()); + } + + /** + * use "$" symbol in identifiers for generalized constructor + */ + class $Mc3$06{ + public <U$uUuU_ extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable &$MI3$01> $Mc3$06(U$uUuU_ a1) throws U$uUuU_, java.io.IOException {} + } + + public void test_6() { + TypeVariable tv; + Type ap[]; + Type ab[]; + Type aet[]; + Type atp[]; + Constructor m = null; + try{ + m = ClassGenericsTest3.$Mc3$06.class.getConstructor(new Class[]{ClassGenericsTest3.class, Throwable.class}); + } catch (Exception e) { + fail("test_6, case 001 FAILED: "+e.toString()); + } + atp = m.getTypeParameters(); + if(atp.length!=3) fail("test_6, case 004 FAILED: "+atp.length); + tv = (TypeVariable)atp[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_6, case 005 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$$Mc3$06")) fail("test_6, case 006 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 007 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Throwable")) fail("test_6, case 008 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[1]; + if(!tv.getName().equals("TM1")) fail("test_6, case 009 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$$Mc3$06")) fail("test_6, case 010 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=1) fail("test_6, case 011 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Object")) fail("test_6, case 012 FAILED: "+((Class)ab[0]).getName()); + tv = (TypeVariable)atp[2]; + if(!tv.getName().equals("TM2")) fail("test_6, case 013 FAILED: "+tv.getName()); + if(!((Constructor)tv.getGenericDeclaration()).getName().equals("java.lang.ClassGenericsTest3$$Mc3$06")) fail("test_6, case 014 FAILED: "+((Constructor)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(ab.length!=4) fail("test_6, case 015 FAILED: "+ab.length); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_6, case 016 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_6, case 017 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_6, case 018 FAILED: "+((Class)ab[2]).getName()); + if(!((Class)ab[3]).getName().equals("java.lang.ClassGenericsTest3$$MI3$01")) fail("test_6, case 0181 FAILED: "+((Class)ab[2]).getName()); + /////// + ap = m.getGenericParameterTypes(); + if(ap.length!=1) fail("test_6, case 019 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_6, case 020 FAILED: "+tv.getName()); + /////// + aet = m.getGenericExceptionTypes(); + if(aet.length!=2) fail("test_6, case 021 FAILED: "+ap.length); + tv = (TypeVariable)aet[0]; + if(!tv.getName().equals("U$uUuU_")) fail("test_6, case 022 FAILED: "+tv.getName()); + if(!((Class)aet[1]).getName().equals("java.io.IOException")) fail("test_6, case 023 FAILED: "+((Class)aet[1]).getName()); + } +} diff --git vm/tests/kernel/java/lang/ClassGenericsTest4.java vm/tests/kernel/java/lang/ClassGenericsTest4.java new file mode 100644 index 0000000..a197245 --- /dev/null +++ vm/tests/kernel/java/lang/ClassGenericsTest4.java @@ -0,0 +1,799 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.lang.reflect.*; +import java.io.File; +import java.io.FileOutputStream; + +import org.apache.harmony.test.TestResources; + +import junit.framework.TestCase; + +/* + * Created on May 03-06, 2006 + * + * This ClassGenericsTest4 class is used to test the Core API Class, Method, + * Constructor classes + * + */ + +@SuppressWarnings(value={"all"}) public class ClassGenericsTest4<$X$> extends TestCase { + class $Mc3$01 {}; + + interface $MI3$01<$T$0 extends java.io.Serializable> {}; + interface $MI3$02<_T$_1$ extends $MI3$01> {}; + interface $MI3$03<T2$> extends $MI3$01 {}; + interface $MI3$04<T$2> { + interface $MI3$05<_T$21_, _$T22> { + }; + }; + public class $Mc3$02<$_T3_$ extends ClassGenericsTest4> { + public class $Mc3$04<T5 extends ClassGenericsTest4> { + }; + }; + public class $Mc4$<_> { + public class $Mc5<_> { + }; + public class Mc5<_> { + }; + }; + public interface $Mi4$<_> { + public interface $$$$$Mi5<_> { + }; + public interface $$$$Mi5<_> { + }; + public interface $$$Mi5<_> { + }; + public interface $$Mi5<_> { + }; + public interface $Mi5<_> { + }; + public interface Mi5<_> { + }; + public interface Mi5$<_> { + }; + }; + public interface $Mi4<_> { +/* //XXX's compiler errors are risen here: + public interface $$Mi5<_> { + }; + public interface $Mi5<_> { + }; + public interface Mi5<_> { + }; + public interface Mi5$<_> { + }; +*/ + }; + + /** + * processing generalized local classes + */ + public void test_1() throws Exception { + class $Mc3$01<T> {}; + class $Mc3$02<$_T3_$ extends ClassGenericsTest4> { + class $Mc3$04<T5 extends $Mc3$01<$Mi4<Cloneable>> &$Mi4$.$$$$$Mi5 &$Mi4$.$$$$Mi5 &$Mi4$.$$$Mi5 &$Mi4$.$$Mi5 &$Mi4$.$Mi5 &$Mi4$.Mi5 &$Mi4$, T6 extends $Mc3$01<$Mi4<? super Cloneable>> &$Mi4$.$$$$$Mi5, T7 extends $Mc3$01<$Mi4<? extends java.io.Serializable>> &$Mi4$.$$$$$Mi5> implements $Mi4$.$$$$$Mi5 ,$Mi4$.$$$$Mi5 ,$Mi4$.$$$Mi5 ,$Mi4$.$$Mi5 ,$Mi4$.$Mi5 ,$Mi4$.Mi5 ,$Mi4$ { + }; + }; + if(!$Mc3$01.class.getName().equals("java.lang.ClassGenericsTest4$1$Mc3$01")) fail("test_1, case 001 FAILED: "+$Mc3$01.class.getName()); + if(!$Mc3$01.class.getSimpleName().equals("$Mc3$01")) fail("test_1, case 002 FAILED: "+$Mc3$01.class.getSimpleName()); + if($Mc3$01.class.getCanonicalName() != null) fail("test_1, case 0021 FAILED: "+$Mc3$01.class.getCanonicalName()); + Type at[] = $Mc3$01.class.getTypeParameters(); + TypeVariable tv = (TypeVariable)at[0]; + if(!tv.getName().equals("T")) fail("test_1, case 003 FAILED: "+tv.getName()); + Class cc = (Class)tv.getBounds()[0]; + if(!cc.getName().equals("java.lang.Object")) fail("test_1, case 004 FAILED: "+cc.getName()); + + if(!$Mc3$02.class.getName().equals("java.lang.ClassGenericsTest4$1$Mc3$02")) fail("test_1, case 005 FAILED: "+$Mc3$02.class.getName()); + if(!$Mc3$02.class.getSimpleName().equals("$Mc3$02")) fail("test_1, case 006 FAILED: "+$Mc3$02.class.getSimpleName()); + if($Mc3$02.class.getCanonicalName() != null) fail("test_1, case 007 FAILED: "+$Mc3$02.class.getCanonicalName()); + at = $Mc3$02.class.getTypeParameters(); + tv = (TypeVariable)at[0]; + if(!tv.getName().equals("$_T3_$")) fail("test_1, case 008 FAILED: "+tv.getName()); + cc = (Class)tv.getBounds()[0]; + if(!cc.getName().equals("java.lang.ClassGenericsTest4")) fail("test_1, case 009 FAILED: "+cc.getName()); + + if(!$Mc3$02.$Mc3$04.class.getName().equals("java.lang.ClassGenericsTest4$1$Mc3$02$$Mc3$04")) fail("test_1, case 010 FAILED: "+$Mc3$02.$Mc3$04.class.getName()); + if(!$Mc3$02.$Mc3$04.class.getSimpleName().equals("$Mc3$04")) fail("test_1, case 011 FAILED: "+$Mc3$02.$Mc3$04.class.getSimpleName()); + if($Mc3$02.$Mc3$04.class.getCanonicalName() != null) fail("test_1, case 012 FAILED: "+$Mc3$02.$Mc3$04.class.getCanonicalName()); + Type ab[] = null;ParameterizedType pt = null; if(RuntimeAdditionalSupport1.openingFlag) { +try{ at = $Mc3$02.$Mc3$04.class.getTypeParameters(); + tv = (TypeVariable)at[0]; + if(!tv.getName().equals("T5")) fail("test_1, case 0121 FAILED: "+tv.getName()); + /*Type*/ ab/*[]*/ = tv.getBounds(); + /*ParameterizedType*/ pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$1$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<java.lang.Cloneable>>")) fail("test_1, case 013 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$1$Mc3$01")) fail("test_1, case 014 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 015 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 016 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[2]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$Mi5") || !((Class)ab[2]).getSimpleName().equals("$$$$Mi5")) fail("test_1, case 017 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[3]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$Mi5") || !((Class)ab[3]).getSimpleName().equals("$$$Mi5")) fail("test_1, case 018 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[4]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$Mi5") || !((Class)ab[4]).getSimpleName().equals("$$Mi5")) fail("test_1, case 019 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[5]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$Mi5") || !((Class)ab[5]).getSimpleName().equals("$Mi5")) fail("test_1, case 020 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[6]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$Mi5") || !((Class)ab[6]).getSimpleName().equals("Mi5")) fail("test_1, case 021 FAILED: "+((Class)ab[2]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[7]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$")) fail("test_1, case 022 FAILED: "+((Class)ab[7]).getName()); + + tv = (TypeVariable)at[1]; + if(!tv.getName().equals("T6")) fail("test_1, case 023 FAILED: "+tv.getName()); + ab = tv.getBounds(); + pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$1$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<? super java.lang.Cloneable>>")) fail("test_1, case 024 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$1$Mc3$01")) fail("test_1, case 025 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 026 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 027 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + + tv = (TypeVariable)at[2]; + if(!tv.getName().equals("T7")) fail("test_1, case 028 FAILED: "+tv.getName()); + ab = tv.getBounds(); + pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$1$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<? extends java.io.Serializable>>")) fail("test_1, case 029 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$1$Mc3$01")) fail("test_1, case 030 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 031 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 032 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + + at = $Mc3$02.$Mc3$04.class.getGenericInterfaces(); + + if(!((Class)at[0]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)at[0]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 033 FAILED: "+((Class)at[0]).getName()+"|"+((Class)at[0]).getSimpleName()); + if(!((Class)at[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$Mi5") || !((Class)at[1]).getSimpleName().equals("$$$$Mi5")) fail("test_1, case 034 FAILED: "+((Class)at[1]).getName()+"|"+((Class)at[1]).getSimpleName()); + if(!((Class)at[2]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$Mi5") || !((Class)at[2]).getSimpleName().equals("$$$Mi5")) fail("test_1, case 035 FAILED: "+((Class)at[2]).getName()+"|"+((Class)at[2]).getSimpleName()); + if(!((Class)at[3]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$Mi5") || !((Class)at[3]).getSimpleName().equals("$$Mi5")) fail("test_1, case 036 FAILED: "+((Class)at[3]).getName()+"|"+((Class)at[3]).getSimpleName()); + if(!((Class)at[4]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$Mi5") || !((Class)at[4]).getSimpleName().equals("$Mi5")) fail("test_1, case 037 FAILED: "+((Class)at[4]).getName()+"|"+((Class)at[4]).getSimpleName()); + if(!((Class)at[5]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$Mi5") || !((Class)at[5]).getSimpleName().equals("Mi5")) fail("test_1, case 038 FAILED: "+((Class)at[5]).getName()+"|"+((Class)at[5]).getSimpleName()); + if(!((Class)at[6]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$")) fail("test_1, case 039 FAILED: "+((Class)at[6]).getName()); +} catch (java.lang.reflect.GenericSignatureFormatError e) {System.out.println("ClassGenericsTest4.test_1.XXX_case_1 is excluded temporarily because the used compiler generates incorrect signature which leads to the case falure.");} +} + Class ac[] = new Class[3]; + meth(ac); + if(!ac[0].getName().equals("java.lang.ClassGenericsTest4$2$Mc3$01")) fail("test_1, case 040 FAILED: "+ac[0].getName()); + if(!ac[0].getSimpleName().equals("$Mc3$01")) fail("test_1, case 041 FAILED: "+ac[0].getSimpleName()); + if(ac[0].getCanonicalName() != null) fail("test_1, case 042 FAILED: "+ac[0].getCanonicalName()); + at = ac[0].getTypeParameters(); + tv = (TypeVariable)at[0]; + if(!tv.getName().equals("T")) fail("test_1, case 043 FAILED: "+tv.getName()); + cc = (Class)tv.getBounds()[0]; + if(!cc.getName().equals("java.lang.Object")) fail("test_1, case 044 FAILED: "+cc.getName()); + + if(!ac[1].getName().equals("java.lang.ClassGenericsTest4$2$Mc3$02")) fail("test_1, case 045 FAILED: "+ac[1].getName()); + if(!ac[1].getSimpleName().equals("$Mc3$02")) fail("test_1, case 046 FAILED: "+ac[1].getSimpleName()); + if(ac[1].getCanonicalName() != null) fail("test_1, case 047 FAILED: "+ac[1].getCanonicalName()); + at = ac[1].getTypeParameters(); + tv = (TypeVariable)at[0]; + if(!tv.getName().equals("$_T3_$")) fail("test_1, case 048 FAILED: "+tv.getName()); + cc = (Class)tv.getBounds()[0]; + if(!cc.getName().equals("java.lang.ClassGenericsTest4")) fail("test_1, case 049 FAILED: "+cc.getName()); + + if(!ac[2].getName().equals("java.lang.ClassGenericsTest4$2$Mc3$02$$Mc3$04")) fail("test_1, case 050 FAILED: "+ac[2].getName()); + if(!ac[2].getSimpleName().equals("$Mc3$04")) fail("test_1, case 051 FAILED: "+ac[2].getSimpleName()); + if(ac[2].getCanonicalName() != null) fail("test_1, case 052 FAILED: "+ac[2].getCanonicalName()); +if(RuntimeAdditionalSupport1.openingFlag) { +try{ at = ac[2].getTypeParameters(); + tv = (TypeVariable)at[0]; + if(!tv.getName().equals("T5")) fail("test_1, case 053 FAILED: "+tv.getName()); + ab = tv.getBounds(); + pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$2$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<java.lang.Cloneable>>")) fail("test_1, case 054 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$2$Mc3$01")) fail("test_1, case 055 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 056 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 057 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[2]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$Mi5") || !((Class)ab[2]).getSimpleName().equals("$$$$Mi5")) fail("test_1, case 058 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[3]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$Mi5") || !((Class)ab[3]).getSimpleName().equals("$$$Mi5")) fail("test_1, case 059 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[4]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$Mi5") || !((Class)ab[4]).getSimpleName().equals("$$Mi5")) fail("test_1, case 060 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[5]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$Mi5") || !((Class)ab[5]).getSimpleName().equals("$Mi5")) fail("test_1, case 061 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[6]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$Mi5") || !((Class)ab[6]).getSimpleName().equals("Mi5")) fail("test_1, case 062 FAILED: "+((Class)ab[2]).getName()+"|"+((Class)ab[2]).getSimpleName()); + if(!((Class)ab[7]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$")) fail("test_1, case 063 FAILED: "+((Class)ab[7]).getName()); + + tv = (TypeVariable)at[1]; + if(!tv.getName().equals("T6")) fail("test_1, case 064 FAILED: "+tv.getName()); + ab = tv.getBounds(); + pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$2$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<? super java.lang.Cloneable>>")) fail("test_1, case 065 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$2$Mc3$01")) fail("test_1, case 066 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 067 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 068 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + + tv = (TypeVariable)at[2]; + if(!tv.getName().equals("T7")) fail("test_1, case 069 FAILED: "+tv.getName()); + ab = tv.getBounds(); + pt = (ParameterizedType)ab[0]; + if(!pt.toString().equals("java.lang.ClassGenericsTest4$2$Mc3$01<java.lang.ClassGenericsTest4.$Mi4<? extends java.io.Serializable>>")) fail("test_1, case 070 FAILED: "+tv.getName()); + + if(!((Class)((ParameterizedType)ab[0]).getRawType()).getName().equals("java.lang.ClassGenericsTest4$2$Mc3$01")) fail("test_1, case 071 FAILED: "+((Class)((ParameterizedType)ab[0]).getRawType()).getName()); + if(((ParameterizedType)ab[0]).getOwnerType()!=null) fail("test_1, case 072 FAILED: "+((ParameterizedType)ab[0]).getOwnerType()); + if(!((Class)ab[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)ab[1]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 073 FAILED: "+((Class)ab[1]).getName()+"|"+((Class)ab[2]).getSimpleName()); + + at = ac[2].getGenericInterfaces(); + + if(!((Class)at[0]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$$Mi5") || !((Class)at[0]).getSimpleName().equals("$$$$$Mi5")) fail("test_1, case 074 FAILED: "+((Class)at[0]).getName()+"|"+((Class)at[0]).getSimpleName()); + if(!((Class)at[1]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$$Mi5") || !((Class)at[1]).getSimpleName().equals("$$$$Mi5")) fail("test_1, case 075 FAILED: "+((Class)at[1]).getName()+"|"+((Class)at[1]).getSimpleName()); + if(!((Class)at[2]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$$Mi5") || !((Class)at[2]).getSimpleName().equals("$$$Mi5")) fail("test_1, case 076 FAILED: "+((Class)at[2]).getName()+"|"+((Class)at[2]).getSimpleName()); + if(!((Class)at[3]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$$Mi5") || !((Class)at[3]).getSimpleName().equals("$$Mi5")) fail("test_1, case 077 FAILED: "+((Class)at[3]).getName()+"|"+((Class)at[3]).getSimpleName()); + if(!((Class)at[4]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$$Mi5") || !((Class)at[4]).getSimpleName().equals("$Mi5")) fail("test_1, case 078 FAILED: "+((Class)at[4]).getName()+"|"+((Class)at[4]).getSimpleName()); + if(!((Class)at[5]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$$Mi5") || !((Class)at[5]).getSimpleName().equals("Mi5")) fail("test_1, case 079 FAILED: "+((Class)at[5]).getName()+"|"+((Class)at[5]).getSimpleName()); + if(!((Class)at[6]).getName().equals("java.lang.ClassGenericsTest4$$Mi4$")) fail("test_1, case 080 FAILED: "+((Class)at[6]).getName()); +} catch (java.lang.reflect.GenericSignatureFormatError e) {System.out.println("ClassGenericsTest4.test_1.XXX_case_2 is excluded temporarily because the used compiler generates incorrect signature which leads to the case falure.");} +} + } + public void meth(Class ac[]) { + class $Mc3$01<T> {}; + class $Mc3$02<$_T3_$ extends ClassGenericsTest4> { + class $Mc3$04<T5 extends $Mc3$01<$Mi4<Cloneable>> &$Mi4$.$$$$$Mi5 &$Mi4$.$$$$Mi5 &$Mi4$.$$$Mi5 &$Mi4$.$$Mi5 &$Mi4$.$Mi5 &$Mi4$.Mi5 &$Mi4$, T6 extends $Mc3$01<$Mi4<? super Cloneable>> &$Mi4$.$$$$$Mi5, T7 extends $Mc3$01<$Mi4<? extends java.io.Serializable>> &$Mi4$.$$$$$Mi5> implements $Mi4$.$$$$$Mi5 ,$Mi4$.$$$$Mi5 ,$Mi4$.$$$Mi5 ,$Mi4$.$$Mi5 ,$Mi4$.$Mi5 ,$Mi4$.Mi5 ,$Mi4$ { + }; + }; + ac[0] = $Mc3$01.class; + ac[1] = $Mc3$02.class; + ac[2] = $Mc3$02.$Mc3$04.class; + } + + /** + * checks for cases when generalized classes have been loaded by another class loader + */ + public void test_2 () throws Exception { + ClassLoader ld = TestResources.getLoader(); + Class temp = ld.loadClass("org.apache.harmony.lang.generics.TemplateSet"); + Class ac[] = temp.getDeclaredClasses(); + Type ap[]; + TypeVariable tv; + Type ab[]; + Type ai[]; + Type aa[]; + Type aa2[]; + Type oc; + WildcardType wc; + Type aa3[]; + + Class Mc003 = null; + for(int i = 0; i < ac.length; i ++){ + if(ac[i].getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc003")) { + Mc003 = ac[i]; + } + } + ap = Mc003.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 001 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T4")) fail("test_2, case 002 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc003")) fail("test_2, case 003 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 004 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 005 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 006 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc003.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 007 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI002")) fail("test_2, case 008 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 009 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 010 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 011 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 012 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 013 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 014 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 015 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 016 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 017 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 018 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 019 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 020 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 021 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI004$MI005")) fail("test_2, case 022 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI004")) fail("test_2, case 023 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 002 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 024 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 025 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc003.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_2, case 026 FAILED: "+Mc003.getGenericSuperclass()); + if(!((Class)((ParameterizedType)Mc003.getGenericSuperclass()).getRawType()).getSimpleName().equals("Mc002")) fail("test_2, case 027 FAILED: "+Mc003.getGenericSuperclass()); + if(!((Class)((ParameterizedType)Mc003.getGenericSuperclass()).getRawType()).getAnnotations()[0].annotationType().getSimpleName().equals("igt")) fail("test_2, case 028 FAILED: "+((Class)((ParameterizedType)Mc003.getGenericSuperclass()).getRawType()).getAnnotations()[0].annotationType().getSimpleName()); + aa = ((ParameterizedType)Mc003.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 029 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 030 FAILED: "+((Class)aa[0]).getName()); + oc = ((ParameterizedType)Mc003.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 031 FAILED: "+Mc003.getGenericSuperclass()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_2, case 032 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 033 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 034 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Class.class)) fail("test_2, case 035 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 036 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 037 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + Class Mc007\u0391 = null; + for(int i = 0; i < ac.length; i ++){ + if(ac[i].getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc007\u0391")) { + Mc007\u0391 = ac[i]; + } + } + ap = Mc007\u0391.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 038 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T7")) fail("test_2, case 039 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc007\u0391")) fail("test_2, case 040 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("java.lang.Thread")) fail("test_2, case 041 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 042 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 043 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc007\u0391.getGenericInterfaces(); + if(ai.length!=0) fail("test_2, case 001 FAILED: "+ap.length); + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc007\u0391.getGenericSuperclass() instanceof java.lang.Object)) fail("test_2, case 044 FAILED: "+Mc007\u0391.getGenericSuperclass()); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + Class Mc008\u0576\u06C0\u06F10 = null; + for(int i = 0; i < ac.length; i ++){ + if(ac[i].getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc008\u0576\u06C0\u06F10")) { + Mc008\u0576\u06C0\u06F10 = ac[i]; + } + } + ap = Mc008\u0576\u06C0\u06F10.getTypeParameters(); + if(ap.length!=1) fail("test_2, case 045 FAILED: "+ap.length); + tv = (TypeVariable)ap[0]; + if(!tv.getName().equals("T8")) fail("test_2, case 046 FAILED: "+tv.getName()); + if(!((Class)tv.getGenericDeclaration()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc008\u0576\u06C0\u06F10")) fail("test_2, case 047 FAILED: "+((Class)tv.getGenericDeclaration()).getName()); + ab = tv.getBounds(); + if(!((Class)ab[0]).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc007\u0391")) fail("test_2, case 048 FAILED: "+((Class)ab[0]).getName()); + if(!((Class)ab[1]).getName().equals("java.io.Serializable")) fail("test_2, case 049 FAILED: "+((Class)ab[1]).getName()); + if(!((Class)ab[2]).getName().equals("java.lang.Cloneable")) fail("test_2, case 050 FAILED: "+((Class)ab[2]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = Mc008\u0576\u06C0\u06F10.getGenericInterfaces(); + if(ai.length!=3) fail("test_2, case 051 FAILED: "+ai.length); + if(!((Class)((ParameterizedType)ai[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI002")) fail("test_2, case 052 FAILED: "+((Class)((ParameterizedType)ai[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 053 FAILED: "+((Class)((ParameterizedType)ai[0]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[0]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 054 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 055 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 056 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.io.Serializable + if(aa2.length!=1) fail("test_2, case 057 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.io.Serializable")) fail("test_2, case 058 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[1]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 059 FAILED: "+((Class)((ParameterizedType)ai[1]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[1]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 060 FAILED: "+((Class)((ParameterizedType)ai[1]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[1]).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 061 FAILED: "+aa.length); + if(!((Class)((ParameterizedType)aa[0]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI003")) fail("test_2, case 062 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)((ParameterizedType)aa[0]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 063 FAILED: "+((Class)((ParameterizedType)aa[0]).getOwnerType()).getName()); + aa2 = ((ParameterizedType)aa[0]).getActualTypeArguments(); //java.lang.Cloneable + if(aa2.length!=1) fail("test_2, case 064 FAILED: "+aa.length); + if(!((Class)aa2[0]).getName().equals("java.lang.Cloneable")) fail("test_2, case 065 FAILED: "+((Class)((ParameterizedType)aa2[0]).getRawType()).getName()); + + if(!((Class)((ParameterizedType)ai[2]).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI004$MI005")) fail("test_2, case 066 FAILED: "+((Class)((ParameterizedType)ai[2]).getRawType()).getName()); + if(!((Class)((ParameterizedType)ai[2]).getOwnerType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI004")) fail("test_2, case 067 FAILED: "+((Class)((ParameterizedType)ai[2]).getOwnerType()).getName()); + aa = ((ParameterizedType)ai[2]).getActualTypeArguments(); + if(aa.length!=2) fail("test_2, case 068 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc007\u0391")) fail("test_2, case 069 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + if(!((Class)aa[1]).getName().equals("java.lang.reflect.Type")) fail("test_2, case 070 FAILED: "+((Class)((ParameterizedType)aa[1]).getRawType()).getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!(Mc008\u0576\u06C0\u06F10.getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType)) fail("test_2, case 071 FAILED: "+Mc008\u0576\u06C0\u06F10.getGenericSuperclass()); + if(!((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getRawType()).getSimpleName().equals("Mc002")) fail("test_2, case 072 FAILED: "+((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getRawType())); + if(!((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getRawType()).getAnnotations()[0].annotationType().getSimpleName().equals("igt")) fail("test_2, case 073 FAILED: "+((Class)((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getRawType()).getAnnotations()[0].annotationType().getSimpleName()); + aa = ((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 074 FAILED: "+aa.length); + if(!((Class)aa[0]).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 075 FAILED: "+((Class)((ParameterizedType)aa[0]).getRawType()).getName()); + oc = ((ParameterizedType)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getOwnerType(); + if(!((Class)((ParameterizedType)oc).getRawType()).getName().equals("org.apache.harmony.lang.generics.TemplateSet")) fail("test_2, case 076 FAILED: "+((Class)((ParameterizedType)oc).getRawType()).getName()); + if(((ParameterizedType)oc).getOwnerType()!=null) fail("test_2, case 077 FAILED: "+((ParameterizedType)oc).getOwnerType()); + aa = ((ParameterizedType)oc).getActualTypeArguments(); + if(aa.length!=1) fail("test_2, case 078 FAILED: "+aa.length); + wc = (WildcardType)aa[0]; + aa3 = wc.getLowerBounds(); + if(aa3.length!=1) fail("test_2, case 079 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Mc007\u0391)) fail("test_2, case 080 FAILED: "+((Class)aa3[0])); + aa3 = wc.getUpperBounds(); + if(aa3.length!=1) fail("test_2, case 081 FAILED: "+aa3.length); + if(!((Class)aa3[0]).equals(Object.class)) fail("test_2, case 082 FAILED: "+((Class)aa3[0])); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + Class MC011\u0576\u06C0\u06F10 = null; + for(int i = 0; i < ac.length; i ++){ + if(ac[i].getName().equals("org.apache.harmony.lang.generics.TemplateSet$MC011\u0576\u06C0\u06F10")) { + MC011\u0576\u06C0\u06F10 = ac[i]; + } + } + ap = MC011\u0576\u06C0\u06F10.getTypeParameters(); + if(ap.length!=0) fail("test_2, case 083 FAILED: "+ap.length); + ////////////////////////////////////////////////////////////////////////////////////////////// + ai = MC011\u0576\u06C0\u06F10.getGenericInterfaces(); + if(ai.length!=1) fail("test_2, case 084 FAILED: "+ai.length); + if(!((Class)ai[0]).getName().equals("org.apache.harmony.lang.generics.TemplateSet$MI010\u0576\u06C0\u06F10")) fail("test_2, case 085 FAILED: "+((Class)ai[0]).getName()); + ////////////////////////////////////////////////////////////////////////////////////////////// + if(!((Class)MC011\u0576\u06C0\u06F10.getGenericSuperclass()).getName().equals("org.apache.harmony.lang.generics.TemplateSet$Mc010\u0576\u06C0\u06F10")) fail("test_2, case 086 FAILED: "+((Class)Mc008\u0576\u06C0\u06F10.getGenericSuperclass()).getName()); + } + + /** + * spoiled signature + */ + public void test_3 () throws Exception { + + final String RESOURCE_PATH = "test.resource.path"; + ClassLoader ld = TestResources.getLoader(); + + String path = System.getProperty(RESOURCE_PATH); + + /* + * package org.apache.harmony.lang.generics; + * import java.lang.reflect.TypeVariable; + * public class BadSignatureTemplate<$X$> { + * + * public TypeVariable[] test_1() throws Exception { + * class $Mc3$01<T> {}; + * class $Mc3$02<$_T3_$ extends Class> { + * class $Mc3$04<T5 extends $Mc3$01<Cloneable>> { + * }; + * }; + * return $Mc3$02.$Mc3$04.class.getTypeParameters(); + * } + * } + */ + /* + * package org.apache.harmony.lang.generics; + * import junit.framework.TestCase; + * public class BadSignatureTemplate<$X$> extends TestCase { + * public void test_1() throws Exception { + * class $Mc3$01<T> {}; + * class $Mc3$02<$_T3_$ extends Class> { + * class $Mc3$04<T5 extends $Mc3$01<Cloneable>> { + * }; + * }; + * $Mc3$02.$Mc3$04.class.getTypeParameters(); + * } + * } + */ + byte BadSignatureTemplate[] = { + /**/ + -54,-2,-70,-66,0,0,0,49,0,32,10,0,5,0,18,7,0,20,10,0,24,0,25,7,0, + 26,7,0,27,1,0,6,60,105,110,105,116,62,1,0,3,40,41,86,1,0,4,67,111,100, + 101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,6,116,101,115, + 116,95,49,1,0,35,40,41,91,76,106,97,118,97,47,108,97,110,103,47,114,101,102,108,101, + 99,116,47,84,121,112,101,86,97,114,105,97,98,108,101,59,1,0,10,69,120,99,101,112,116, + 105,111,110,115,7,0,28,1,0,9,83,105,103,110,97,116,117,114,101,1,0,42,60,36,88, + 36,58,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,62,76,106,97,118, + 97,47,108,97,110,103,47,79,98,106,101,99,116,59,1,0,10,83,111,117,114,99,101,70,105, + 108,101,1,0,25,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101, + 46,106,97,118,97,12,0,6,0,7,7,0,29,1,0,70,111,114,103,47,97,112,97,99,104, + 101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66, + 97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99,51, + 36,48,50,36,36,77,99,51,36,48,52,1,0,7,36,77,99,51,36,48,50,1,0,12,73, + 110,110,101,114,67,108,97,115,115,101,115,1,0,7,36,77,99,51,36,48,52,7,0,30,12, + 0,31,0,11,1,0,53,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98, + 106,101,99,116,1,0,19,106,97,118,97,47,108,97,110,103,47,69,120,99,101,112,116,105,111, + 110,1,0,62,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97, + 110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84, + 101,109,112,108,97,116,101,36,49,36,77,99,51,36,48,50,1,0,15,106,97,118,97,47,108, + 97,110,103,47,67,108,97,115,115,1,0,17,103,101,116,84,121,112,101,80,97,114,97,109,101, + 116,101,114,115,0,33,0,4,0,5,0,0,0,0,0,2,0,1,0,6,0,7,0,1,0, + 8,0,0,0,29,0,1,0,1,0,0,0,5,42,-73,0,1,-79,0,0,0,1,0,9,0, + 0,0,6,0,1,0,0,0,5,0,1,0,10,0,11,0,2,0,8,0,0,0,31,0,1, + 0,1,0,0,0,7,19,0,2,-74,0,3,-80,0,0,0,1,0,9,0,0,0,6,0,1, + 0,0,0,13,0,12,0,0,0,4,0,1,0,13,0,3,0,14,0,0,0,2,0,15,0, + 16,0,0,0,2,0,17,0,22,0,0,0,18,0,2,0,19,0,0,0,21,0,0,0,2, + 0,19,0,23,0,0, + /**/ + /* + -54,-2,-70,-66,0,0,0,49,0,32,10,0,5,0,17,7,0,19,10,0,23,0,24,7,0, + 25,7,0,26,1,0,6,60,105,110,105,116,62,1,0,3,40,41,86,1,0,4,67,111,100, + 101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,6,116,101,115, + 116,95,49,1,0,10,69,120,99,101,112,116,105,111,110,115,7,0,27,1,0,9,83,105,103, + 110,97,116,117,114,101,1,0,50,60,36,88,36,58,76,106,97,118,97,47,108,97,110,103,47, + 79,98,106,101,99,116,59,62,76,106,117,110,105,116,47,102,114,97,109,101,119,111,114,107,47, + 84,101,115,116,67,97,115,101,59,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0,25, + 66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,46,106,97,118,97, + 12,0,6,0,7,7,0,28,1,0,70,111,114,103,47,97,112,97,99,104,101,47,104,97,114, + 109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103, + 110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99,51,36,48,50,36,36, + 77,99,51,36,48,52,1,0,7,36,77,99,51,36,48,50,1,0,12,73,110,110,101,114,67, + 108,97,115,115,101,115,1,0,7,36,77,99,51,36,48,52,7,0,29,12,0,30,0,31,1, + 0,53,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103, + 47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109, + 112,108,97,116,101,1,0,24,106,117,110,105,116,47,102,114,97,109,101,119,111,114,107,47,84, + 101,115,116,67,97,115,101,1,0,19,106,97,118,97,47,108,97,110,103,47,69,120,99,101,112, + 116,105,111,110,1,0,62,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,36,49,36,77,99,51,36,48,50,1,0,15,106,97,118, + 97,47,108,97,110,103,47,67,108,97,115,115,1,0,17,103,101,116,84,121,112,101,80,97,114, + 97,109,101,116,101,114,115,1,0,35,40,41,91,76,106,97,118,97,47,108,97,110,103,47,114, + 101,102,108,101,99,116,47,84,121,112,101,86,97,114,105,97,98,108,101,59,0,33,0,4,0, + 5,0,0,0,0,0,2,0,1,0,6,0,7,0,1,0,8,0,0,0,29,0,1,0,1, + 0,0,0,5,42,-73,0,1,-79,0,0,0,1,0,9,0,0,0,6,0,1,0,0,0,6, + 0,1,0,10,0,7,0,2,0,8,0,0,0,36,0,1,0,1,0,0,0,8,19,0,2, + -74,0,3,87,-79,0,0,0,1,0,9,0,0,0,10,0,2,0,0,0,16,0,7,0,17, + 0,11,0,0,0,4,0,1,0,12,0,3,0,13,0,0,0,2,0,14,0,15,0,0,0, + 2,0,16,0,21,0,0,0,18,0,2,0,18,0,0,0,20,0,0,0,2,0,18,0,22, + 0,0, + */ + }; + +byte BadSignatureTemplate$1$Mc3$02[] = { + /* + -54,-2,-70,-66,0,0,0,49,0,31,9,0,3,0,22,10,0,4,0,23,7,0,24,7,0, + 25,1,0,7,36,77,99,51,36,48,50,1,0,12,73,110,110,101,114,67,108,97,115,115,101, + 115,7,0,26,1,0,7,36,77,99,51,36,48,52,1,0,6,116,104,105,115,36,48,1,0, + 55,76,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103, + 47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109, + 112,108,97,116,101,59,1,0,6,60,105,110,105,116,62,1,0,58,40,76,111,114,103,47,97, + 112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105, + 99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,59,41, + 86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108, + 101,1,0,9,83,105,103,110,97,116,117,114,101,1,0,44,60,36,95,84,51,95,36,58,76, + 106,97,118,97,47,108,97,110,103,47,67,108,97,115,115,59,62,76,106,97,118,97,47,108,97, + 110,103,47,79,98,106,101,99,116,59,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0, + 25,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,46,106,97,118, + 97,1,0,15,69,110,99,108,111,115,105,110,103,77,101,116,104,111,100,7,0,27,12,0,28, + 0,29,12,0,9,0,10,12,0,11,0,30,1,0,62,111,114,103,47,97,112,97,99,104,101, + 47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97, + 100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99,51,36, + 48,50,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,1,0,70,111, + 114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101, + 110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97, + 116,101,36,49,36,77,99,51,36,48,50,36,36,77,99,51,36,48,52,1,0,53,111,114,103, + 47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101, + 114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101, + 1,0,6,116,101,115,116,95,49,1,0,35,40,41,91,76,106,97,118,97,47,108,97,110,103, + 47,114,101,102,108,101,99,116,47,84,121,112,101,86,97,114,105,97,98,108,101,59,1,0,3, + 40,41,86,0,32,0,3,0,4,0,0,0,1,16,16,0,9,0,10,0,0,0,1,0,0, + 0,11,0,12,0,1,0,13,0,0,0,38,0,2,0,2,0,0,0,10,42,43,-75,0,1, + 42,-73,0,2,-79,0,0,0,1,0,14,0,0,0,10,0,2,0,0,0,9,0,9,0,11, + 0,4,0,15,0,0,0,2,0,16,0,17,0,0,0,2,0,18,0,19,0,0,0,4,0, + 20,0,21,0,6,0,0,0,18,0,2,0,3,0,0,0,5,0,0,0,7,0,3,0,8, + 0,0, + */ + /**/ + -54,-2,-70,-66,0,0,0,49,0,30,9,0,3,0,22,10,0,4,0,23,7,0,24,7,0, + 25,1,0,7,36,77,99,51,36,48,50,1,0,12,73,110,110,101,114,67,108,97,115,115,101, + 115,7,0,26,1,0,7,36,77,99,51,36,48,52,1,0,6,116,104,105,115,36,48,1,0, + 55,76,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103, + 47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109, + 112,108,97,116,101,59,1,0,6,60,105,110,105,116,62,1,0,58,40,76,111,114,103,47,97, + 112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105, + 99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,59,41, + 86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108, + 101,1,0,9,83,105,103,110,97,116,117,114,101,1,0,44,60,36,95,84,51,95,36,58,76, + 106,97,118,97,47,108,97,110,103,47,67,108,97,115,115,59,62,76,106,97,118,97,47,108,97, + 110,103,47,79,98,106,101,99,116,59,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0, + 25,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,46,106,97,118, + 97,1,0,15,69,110,99,108,111,115,105,110,103,77,101,116,104,111,100,7,0,27,12,0,28, + 0,29,12,0,9,0,10,12,0,11,0,29,1,0,62,111,114,103,47,97,112,97,99,104,101, + 47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97, + 100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99,51,36, + 48,50,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,1,0,70,111, + 114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101, + 110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97, + 116,101,36,49,36,77,99,51,36,48,50,36,36,77,99,51,36,48,52,1,0,53,111,114,103, + 47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101, + 114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101, + 1,0,6,116,101,115,116,95,49,1,0,3,40,41,86,0,32,0,3,0,4,0,0,0,1, + 16,16,0,9,0,10,0,0,0,1,0,0,0,11,0,12,0,1,0,13,0,0,0,38,0, + 2,0,2,0,0,0,10,42,43,-75,0,1,42,-73,0,2,-79,0,0,0,1,0,14,0,0, + 0,10,0,2,0,0,0,11,0,9,0,13,0,4,0,15,0,0,0,2,0,16,0,17,0, + 0,0,2,0,18,0,19,0,0,0,4,0,20,0,21,0,6,0,0,0,18,0,2,0,3, + 0,0,0,5,0,0,0,7,0,3,0,8,0,0, + /**/ + }; + + byte BadSignatureTemplate$1$Mc3$02$$Mc3$04[] = { + /* + -54,-2,-70,-66,0,0,0,49,0,28,9,0,3,0,20,10,0,4,0,21,7,0,22,7,0, + 24,1,0,6,116,104,105,115,36,49,7,0,25,1,0,7,36,77,99,51,36,48,50,1,0, + 12,73,110,110,101,114,67,108,97,115,115,101,115,1,0,64,76,111,114,103,47,97,112,97,99, + 104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47, + 66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99, + 51,36,48,50,59,1,0,6,60,105,110,105,116,62,1,0,67,40,76,111,114,103,47,97,112, + 97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99, + 115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36, + 77,99,51,36,48,50,59,41,86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117, + 109,98,101,114,84,97,98,108,101,1,0,9,83,105,103,110,97,116,117,114,101,7,0,26,1, + 0,7,36,77,99,51,36,48,49,1,0,110,60,84,53,58,76,111,114,103,47,97,112,97,99, + 104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47, + 66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,46,49,36,77,99, + 51,36,48,49,60,76,106,97,118,97,47,108,97,110,103,47,67,108,111,110,101,97,98,108,101, + 59,62,59,62,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,1,0,10, + 83,111,117,114,99,101,70,105,108,101,1,0,25,66,97,100,83,105,103,110,97,116,117,114,101, + 84,101,109,112,108,97,116,101,46,106,97,118,97,12,0,5,0,9,12,0,10,0,27,1,0, + 70,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47, + 103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112, + 108,97,116,101,36,49,36,77,99,51,36,48,50,36,36,77,99,51,36,48,52,1,0,7,36, + 77,99,51,36,48,52,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116, + 1,0,62,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110, + 103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101, + 109,112,108,97,116,101,36,49,36,77,99,51,36,48,50,1,0,62,111,114,103,47,97,112,97, + 99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115, + 47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77, + 99,51,36,48,49,1,0,3,40,41,86,0,32,0,3,0,4,0,0,0,1,16,16,0,5, + 0,9,0,0,0,1,0,0,0,10,0,11,0,1,0,12,0,0,0,34,0,2,0,2,0, + 0,0,10,42,43,-75,0,1,42,-73,0,2,-79,0,0,0,1,0,13,0,0,0,6,0,1, + 0,0,0,10,0,3,0,14,0,0,0,2,0,17,0,18,0,0,0,2,0,19,0,8,0, + 0,0,26,0,3,0,6,0,0,0,7,0,0,0,15,0,0,0,16,0,0,0,3,0,6, + 0,23,0,0, + */ + /**/ + -54,-2,-70,-66,0,0,0,49,0,28,9,0,3,0,20,10,0,4,0,21,7,0,22,7,0, + 24,1,0,6,116,104,105,115,36,49,7,0,25,1,0,7,36,77,99,51,36,48,50,1,0, + 12,73,110,110,101,114,67,108,97,115,115,101,115,1,0,64,76,111,114,103,47,97,112,97,99, + 104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47, + 66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77,99, + 51,36,48,50,59,1,0,6,60,105,110,105,116,62,1,0,67,40,76,111,114,103,47,97,112, + 97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99, + 115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36, + 77,99,51,36,48,50,59,41,86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117, + 109,98,101,114,84,97,98,108,101,1,0,9,83,105,103,110,97,116,117,114,101,7,0,26,1, + 0,7,36,77,99,51,36,48,49,1,0,110,60,84,53,58,76,111,114,103,47,97,112,97,99, + 104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47, + 66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,46,49,36,77,99, + 51,36,48,49,60,76,106,97,118,97,47,108,97,110,103,47,67,108,111,110,101,97,98,108,101, + 59,62,59,62,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,1,0,10, + 83,111,117,114,99,101,70,105,108,101,1,0,25,66,97,100,83,105,103,110,97,116,117,114,101, + 84,101,109,112,108,97,116,101,46,106,97,118,97,12,0,5,0,9,12,0,10,0,27,1,0, + 70,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47, + 103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112, + 108,97,116,101,36,49,36,77,99,51,36,48,50,36,36,77,99,51,36,48,52,1,0,7,36, + 77,99,51,36,48,52,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116, + 1,0,62,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110, + 103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101, + 109,112,108,97,116,101,36,49,36,77,99,51,36,48,50,1,0,62,111,114,103,47,97,112,97, + 99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115, + 47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,36,49,36,77, + 99,51,36,48,49,1,0,3,40,41,86,0,32,0,3,0,4,0,0,0,1,16,16,0,5, + 0,9,0,0,0,1,0,0,0,10,0,11,0,1,0,12,0,0,0,34,0,2,0,2,0, + 0,0,10,42,43,-75,0,1,42,-73,0,2,-79,0,0,0,1,0,13,0,0,0,6,0,1, + 0,0,0,12,0,3,0,14,0,0,0,2,0,17,0,18,0,0,0,2,0,19,0,8,0, + 0,0,26,0,3,0,6,0,0,0,7,0,0,0,15,0,0,0,16,0,0,0,3,0,6, + 0,23,0,0, + /**/ + }; + + byte BadSignatureTemplate$1$Mc3$01[] = { + /* + -54,-2,-70,-66,0,0,0,49,0,28,9,0,3,0,18,10,0,4,0,19,7,0,20,7,0, + 23,1,0,6,116,104,105,115,36,48,1,0,55,76,111,114,103,47,97,112,97,99,104,101,47, + 104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100, + 83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,59,1,0,6,60,105,110,105, + 116,62,1,0,58,40,76,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,59,41,86,1,0,4,67,111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,9,83,105,103,110,97,116,117,114,101, + 1,0,40,60,84,58,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,62, + 76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,1,0,10,83,111,117,114, + 99,101,70,105,108,101,1,0,25,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112, + 108,97,116,101,46,106,97,118,97,1,0,15,69,110,99,108,111,115,105,110,103,77,101,116,104, + 111,100,7,0,24,12,0,25,0,26,12,0,5,0,6,12,0,7,0,27,1,0,62,111,114, + 103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110, + 101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116, + 101,36,49,36,77,99,51,36,48,49,1,0,7,36,77,99,51,36,48,49,1,0,12,73,110, + 110,101,114,67,108,97,115,115,101,115,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98, + 106,101,99,116,1,0,53,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,1,0,6,116,101,115,116,95,49,1,0,35,40,41,91, + 76,106,97,118,97,47,108,97,110,103,47,114,101,102,108,101,99,116,47,84,121,112,101,86,97, + 114,105,97,98,108,101,59,1,0,3,40,41,86,0,32,0,3,0,4,0,0,0,1,16,16, + 0,5,0,6,0,0,0,1,0,0,0,7,0,8,0,1,0,9,0,0,0,34,0,2,0, + 2,0,0,0,10,42,43,-75,0,1,42,-73,0,2,-79,0,0,0,1,0,10,0,0,0,6, + 0,1,0,0,0,8,0,4,0,11,0,0,0,2,0,12,0,13,0,0,0,2,0,14,0, + 15,0,0,0,4,0,16,0,17,0,22,0,0,0,10,0,1,0,3,0,0,0,21,0,0, + */ + /**/ + -54,-2,-70,-66,0,0,0,49,0,27,9,0,3,0,18,10,0,4,0,19,7,0,20,7,0, + 23,1,0,6,116,104,105,115,36,48,1,0,55,76,111,114,103,47,97,112,97,99,104,101,47, + 104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100, + 83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116,101,59,1,0,6,60,105,110,105, + 116,62,1,0,58,40,76,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,59,41,86,1,0,4,67,111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,9,83,105,103,110,97,116,117,114,101, + 1,0,40,60,84,58,76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,62, + 76,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,59,1,0,10,83,111,117,114, + 99,101,70,105,108,101,1,0,25,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112, + 108,97,116,101,46,106,97,118,97,1,0,15,69,110,99,108,111,115,105,110,103,77,101,116,104, + 111,100,7,0,24,12,0,25,0,26,12,0,5,0,6,12,0,7,0,26,1,0,62,111,114, + 103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121,47,108,97,110,103,47,103,101,110, + 101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117,114,101,84,101,109,112,108,97,116, + 101,36,49,36,77,99,51,36,48,49,1,0,7,36,77,99,51,36,48,49,1,0,12,73,110, + 110,101,114,67,108,97,115,115,101,115,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98, + 106,101,99,116,1,0,53,111,114,103,47,97,112,97,99,104,101,47,104,97,114,109,111,110,121, + 47,108,97,110,103,47,103,101,110,101,114,105,99,115,47,66,97,100,83,105,103,110,97,116,117, + 114,101,84,101,109,112,108,97,116,101,1,0,6,116,101,115,116,95,49,1,0,3,40,41,86, + 0,32,0,3,0,4,0,0,0,1,16,16,0,5,0,6,0,0,0,1,0,0,0,7,0, + 8,0,1,0,9,0,0,0,34,0,2,0,2,0,0,0,10,42,43,-75,0,1,42,-73,0, + 2,-79,0,0,0,1,0,10,0,0,0,6,0,1,0,0,0,10,0,4,0,11,0,0,0, + 2,0,12,0,13,0,0,0,2,0,14,0,15,0,0,0,4,0,16,0,17,0,22,0,0, + 0,10,0,1,0,3,0,0,0,21,0,0, + /**/ + }; + path = path+File.separator+"org"+File.separator+"apache"+File.separator+"harmony"+File.separator+"lang"+File.separator+"generics"; + File f0 = new File(path); + f0.mkdir(); + File f2 = new File(path+File.separator+"BadSignatureTemplate.class"); + f2.createNewFile(); + System.out.println(path+File.separator+"BadSignatureTemplate.class"); + FileOutputStream fos = new FileOutputStream(f2); + fos.write(BadSignatureTemplate); + fos.flush(); + fos.close(); + f2 = new File(path+File.separator+"BadSignatureTemplate$1$Mc3$02.class"); + f2.createNewFile(); + fos = new FileOutputStream(f2); + fos.write(BadSignatureTemplate$1$Mc3$02); + fos.flush(); + fos.close(); + f2 = new File(path+File.separator+"BadSignatureTemplate$1$Mc3$02$$Mc3$04.class"); + f2.createNewFile(); + fos = new FileOutputStream(f2); + fos.write(BadSignatureTemplate$1$Mc3$02$$Mc3$04); + fos.flush(); + fos.close(); + f2 = new File(path+File.separator+"BadSignatureTemplate$1$Mc3$01.class"); + f2.createNewFile(); + fos = new FileOutputStream(f2); + fos.write(BadSignatureTemplate$1$Mc3$01); + fos.flush(); + fos.close(); + + Class temp = ld.loadClass("org.apache.harmony.lang.generics.BadSignatureTemplate"); + /*Class ac[] = */temp.getDeclaredClasses(); + + + Method m = null; + try{ + java.lang.reflect.Method am[] = temp.getDeclaredMethods(); + for (int ii = 0; ii < am.length; ii++) { + if (am[ii].getName().equals("test_1")) { + m = am[ii]; + } + } + m.getName(); + } catch (Exception e) { + fail("test_3, case 001 FAILED: "+e.toString()); + } + try{ + Object o = temp.newInstance(); + Object o2 = o.getClass().getDeclaredMethod("test_1").invoke(o, (Object[])null); + fail("test_3, case 002 FAILED: GenericSignatureFormatError should be risen."); + System.out.println(((TypeVariable[])o2)[0].getName()); + System.out.println(((ParameterizedType)((TypeVariable[])o2)[0].getBounds()[0]).toString()); + } catch (java.lang.reflect.InvocationTargetException e) { + if (!(e.getCause() instanceof java.lang.reflect.GenericSignatureFormatError)) { + fail("test_3, case 003 FAILED: GenericSignatureFormatError should be risen."); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassGenericsTest5.java vm/tests/kernel/java/lang/ClassGenericsTest5.java new file mode 100644 index 0000000..b65b990 --- /dev/null +++ vm/tests/kernel/java/lang/ClassGenericsTest5.java @@ -0,0 +1,126 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on June 03, 2006 + * + * This ClassGenericsTest5 class is used to test the Core API Class, Method, + * Field, Constructor classes + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. Do clear should I use "$" instead of "." in the commented fragments? + * ############################################################################### + * ############################################################################### + */ + +public class ClassGenericsTest5/*<X>*/ extends TestCase { + + static class B1 { + public Object foo() { return null;} + public Object bar(int i, Object... o) { return null;} + public Object bar2(int i, Object[][][] o) { return null;} + public Object bar3(int i, int[][][] ai1, int... ai2) { return null;} + public <X> Object bar4(int i, int[][][] ai1, OneParamType<Void[][][]>[] ai00, OneParamType<X[][][]> ai0, Object... ai2) { return null;} + public static void main1(String... s){} + public static void main2(String[] s){} + } + + static class B2 extends B1 { + public String foo() { return "";} + public String bar(int i, Object... o) { return "";} + public String bar2(int i, Object[][][] o) { return "";} + public Object bar3(int i, int[][][] ai1, int... ai2) { return null;} + } + + static abstract class OneParamType<X> { + } + static abstract class C { + protected abstract <T extends Throwable> + OneParamType<? extends T> go(T t) throws T, Error; + protected abstract <T extends Throwable> + OneParamType<? extends String> go2(T t) throws T, Error; + } + + static abstract strictfp class CC { + protected <T extends Throwable & Comparable<Throwable>> CC(T num, OneParamType<? super T> l) throws T, Error {} + } + + /** + * few checks for signatured methods + */ + public void test_1() throws Exception { + //if(!C.class.getDeclaredMethod("go2",Throwable.class).toGenericString().equals("protected abstract <T> java.lang.ClassGenericsTest5$OneParamType<? extends java.lang.String> java.lang.ClassGenericsTest5$C.go2(T) throws T,java.lang.Error")) + // fail("test_1, case 001 FAILED: "+C.class.getDeclaredMethod("go2",Throwable.class).toGenericString()); + if(!C.class.getDeclaredMethod("go2",Throwable.class).toGenericString().equals("protected abstract <T> java.lang.ClassGenericsTest5.OneParamType<? extends java.lang.String> java.lang.ClassGenericsTest5$C.go2(T) throws T,java.lang.Error")) + fail("test_1, case 001 FAILED: "+C.class.getDeclaredMethod("go2",Throwable.class).toGenericString()); + + if(!C.class.getDeclaredMethod("go2",Throwable.class).getTypeParameters()[0].toString().equals("T")) + fail("test_1, case 002 FAILED: "+C.class.getDeclaredMethod("go2",Throwable.class).getTypeParameters()[0].toString()); + + if(!B2.class.getDeclaredMethod("bar",int.class, Object[].class).toGenericString().equals("public java.lang.String java.lang.ClassGenericsTest5$B2.bar(int,java.lang.Object[])")) + fail("test_1, case 003 FAILED: "+B2.class.getDeclaredMethod("bar",int.class, Object[].class).toGenericString()); + + if(!B2.class.getDeclaredMethod("bar",int.class, Object[].class).getParameterTypes()[1].toString().equals("class [Ljava.lang.Object;")) + fail("test_1, case 004 FAILED: "+B2.class.getDeclaredMethod("bar",int.class, Object[].class).getParameterTypes()[1].toString()); + + if(!B2.class.getDeclaredMethod("bar2",int.class, Object[][][].class).toGenericString().equals("public java.lang.String java.lang.ClassGenericsTest5$B2.bar2(int,java.lang.Object[][][])")) + fail("test_1, case 005 FAILED: "+B2.class.getDeclaredMethod("bar2",int.class, Object[][][].class).toGenericString()); + + if(!B2.class.getDeclaredMethod("bar3",int.class, int[][][].class, int[].class).toGenericString().equals("public java.lang.Object java.lang.ClassGenericsTest5$B2.bar3(int,int[][][],int[])")) + fail("test_1, case 006 FAILED: "+B2.class.getDeclaredMethod("bar3",int.class, int[][][].class, int[].class).toGenericString()); + + int res = 0; + java.lang.reflect.Method[] ms = B1.class.getDeclaredMethods(); + for(int i = 0; i < ms.length; i++){ + //if(ms[i].toGenericString().equals("public <X> java.lang.Object java.lang.ClassGenericsTest5$B1.bar4(int,int[][][],java.lang.ClassGenericsTest5$OneParamType<java.lang.Void[][][]>[],java.lang.ClassGenericsTest5$OneParamType<X[][][]>,java.lang.Object[])")) res += 1; + if(ms[i].toGenericString().equals("public <X> java.lang.Object java.lang.ClassGenericsTest5$B1.bar4(int,int[][][],java.lang.ClassGenericsTest5.OneParamType<java.lang.Void[][][]>[],java.lang.ClassGenericsTest5.OneParamType<X[][][]>,java.lang.Object[])")) res += 1; + if(ms[i].toGenericString().equals("public java.lang.Object java.lang.ClassGenericsTest5$B1.bar3(int,int[][][],int[])")) res += 10; + if(ms[i].toGenericString().equals("public java.lang.Object java.lang.ClassGenericsTest5$B1.bar2(int,java.lang.Object[][][])")) res += 100; + if(ms[i].toGenericString().equals("public java.lang.Object java.lang.ClassGenericsTest5$B1.bar(int,java.lang.Object[])")) res += 1000; + if(ms[i].toGenericString().equals("public java.lang.Object java.lang.ClassGenericsTest5$B1.foo()")) res += 10000; + if(ms[i].toGenericString().equals("public static void java.lang.ClassGenericsTest5$B1.main2(java.lang.String[])")) res += 100000; + if(ms[i].toGenericString().equals("public static void java.lang.ClassGenericsTest5$B1.main1(java.lang.String[])")) res += 1000000; + } + if(res!=1111111) fail("test_1, case 007 FAILED: "+"The uncoincedence has been detected!"); + + //if(!B1.class.getDeclaredMethod("bar4",int.class, int[][][].class, OneParamType[].class, OneParamType.class, Object[].class).toGenericString().equals("public <X> java.lang.Object java.lang.ClassGenericsTest5$B1.bar4(int,int[][][],java.lang.ClassGenericsTest5$OneParamType<java.lang.Void[][][]>[],java.lang.ClassGenericsTest5$OneParamType<X[][][]>,java.lang.Object[])")) + // fail("test_1, case 008 FAILED: "+B1.class.getDeclaredMethod("bar4",int.class, int[][][].class, OneParamType[].class, OneParamType.class, Object[].class).toGenericString()); + if(!B1.class.getDeclaredMethod("bar4",int.class, int[][][].class, OneParamType[].class, OneParamType.class, Object[].class).toGenericString().equals("public <X> java.lang.Object java.lang.ClassGenericsTest5$B1.bar4(int,int[][][],java.lang.ClassGenericsTest5.OneParamType<java.lang.Void[][][]>[],java.lang.ClassGenericsTest5.OneParamType<X[][][]>,java.lang.Object[])")) + fail("test_1, case 008 FAILED: "+B1.class.getDeclaredMethod("bar4",int.class, int[][][].class, OneParamType[].class, OneParamType.class, Object[].class).toGenericString()); + + java.lang.reflect.Method mmm=B1.class.getDeclaredMethod("bar4",int.class, int[][][].class, OneParamType[].class, OneParamType.class, Object[].class); + if(!(mmm.getGenericParameterTypes()[1] instanceof java.lang.reflect.GenericArrayType)) fail("test_1, case 009 FAILED: "+(mmm.getGenericParameterTypes()[1] instanceof java.lang.reflect.GenericArrayType)); + if(!(mmm.getGenericParameterTypes()[2] instanceof java.lang.reflect.GenericArrayType)) fail("test_1, case 010 FAILED: "+(mmm.getGenericParameterTypes()[2] instanceof java.lang.reflect.GenericArrayType)); + if((mmm.getGenericParameterTypes()[3] instanceof java.lang.reflect.GenericArrayType)) fail("test_1, case 011 FAILED: "+(mmm.getGenericParameterTypes()[3] instanceof java.lang.reflect.GenericArrayType)); + + //if(!CC.class.getDeclaredConstructor(Throwable.class,OneParamType.class).toGenericString().equals("protected strictfp <T> java.lang.ClassGenericsTest5$CC(T,java.lang.ClassGenericsTest5$OneParamType<? super T>) throws T,java.lang.Error")) fail("test_1, case 012 FAILED: "+CC.class.getDeclaredConstructor(Throwable.class,OneParamType.class).toGenericString()); + if(!CC.class.getDeclaredConstructor(Throwable.class,OneParamType.class).toGenericString().equals("protected strictfp <T> java.lang.ClassGenericsTest5$CC(T,java.lang.ClassGenericsTest5.OneParamType<? super T>) throws T,java.lang.Error")) + fail("test_1, case 012 FAILED: "+CC.class.getDeclaredConstructor(Throwable.class,OneParamType.class).toGenericString()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassHierarchyTest.java vm/tests/kernel/java/lang/ClassHierarchyTest.java new file mode 100644 index 0000000..9c906a6 --- /dev/null +++ vm/tests/kernel/java/lang/ClassHierarchyTest.java @@ -0,0 +1,1274 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +/** + * Areas for supposed testing a classes' hierarchy + * and new 1.5 getEnclosingClass, getEnumConstants, isEnum, asSubclass, + * getEnclosingMethod, getEnclosingConstructor, isMemberClass, isLocalClass, + * isAnonymousClass, isSynthetic, getCanonicalName, getSimpleName methods: + * I. member, inner, nested, local, annonymous, proxy, synthetic classes; + * different packages classes; + * casting, naming, IS...ing, GET...ing, enums, ...; + * II. member interfaces; + * III. the same for annotations and annotated; + * IV. the same for enums; + * V. the same for generalized. + **/ + +import java.lang.annotation.Annotation; + +import junit.framework.TestCase; + +/* + * Created on April 03, 2006 + * + * This ClassHierarchyTest class is used to test the Core API 1.5 Class class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.GenericDeclaration; + +@Retention(value=RetentionPolicy.RUNTIME) +@interface i{ + abstract String author() default "Zapreyev"; +}; + +@SuppressWarnings(value={"unchecked"}) public class ClassHierarchyTest extends TestCase { + @i public class MC001 { + @i public class MC001_01 { + @i public class MC001_01_01 { + @i public class MC001_01_01_01 { + @i public class MC001_01_01_01_01 { + @i public class MC001_01_01_01_01_01 { + @i public class MC001_01_01_01_01_01_01 { + }; + }; + }; + }; + }; + }; + }; + + @Retention(value=RetentionPolicy.RUNTIME) + @interface anna{ + abstract String author() default "Zapreyev"; + }; + @i public class MC002<X, Y, Z> { + @i public class MC002_01<X1, Y1, Z1> { + @i public class MC002_01_01<X2, Y2, Z2> { + @i public class MC002_01_01_01<X3, Y3, Z3> { + @i public class MC002_01_01_01_01<X4, Y4, Z4> { + @i public class MC002_01_01_01_01_01<X5, Y5, Z5> { + @i public class MC002_01_01_01_01_01_01<X6, Y6, Z6> { + }; + }; + }; + }; + }; + }; + }; + + @Retention(value=RetentionPolicy.RUNTIME) + @interface ii{ + abstract String author() default "Zapreyev"; + @Retention(value=RetentionPolicy.RUNTIME) + @interface iii{ + abstract String author() default "Zapreyev"; + }; + }; + @i interface MI001 { + @i interface MI001_01 { + @i interface MI001_01_01 { + @i interface MI001_01_01_01 { + @i interface MI001_01_01_01_01 { + @i interface MI001_01_01_01_01_01 { + @i interface MI001_01_01_01_01_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String author() default "Zapreyev"; + }; + }; + }; + }; + }; + }; + }; + }; + + @i interface MI002<X, Y, Z> { + @i interface MI002_01<X1, Y1, Z1> { + @i interface MI002_01_01<X2, Y2, Z2> { + @i interface MI002_01_01_01<X3, Y3, Z3> { + @i interface MI002_01_01_01_01<X4, Y4, Z4> { + @i interface MI002_01_01_01_01_01<X5, Y5, Z5> { + @i interface MI002_01_01_01_01_01_01<X6, Y6, Z6> { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String author() default "Zapreyev"; + }; + }; + }; + }; + }; + }; + }; + }; + + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01_01_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01_01_01_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface MA001_01_01_01_01_01_01 { + @Retention(value=RetentionPolicy.RUNTIME) + @interface iiii{ + abstract String author() default "Zapreyev 1"; + }; + abstract String author() default "Zapreyev 2"; + }; + abstract String author() default "Zapreyev 3"; + }; + abstract String author() default "Zapreyev 4"; + }; + abstract String author() default "Zapreyev 5"; + }; + abstract String author() default "Zapreyev 6"; + }; + abstract String author() default "Zapreyev 7"; + }; + abstract String author() default "Zapreyev 8"; + }; + +//=================================================================================================== +//=================================================================================================== +//=================================================================================================== + +///////////////////////// I: + /** + * member classes + */ + public void test_1() { + if(!MC001.class.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_1, case 004 FAILED: "+MC001.class.getEnclosingClass()); + if(MC001.class.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+MC001.class.getEnumConstants()); + if(MC001.class.isEnum()) fail("test_1, case 000 FAILED: "+MC001.class.isEnum()); + try{MC001.class.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+MC001.class.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(MC001.class.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+MC001.class.getEnclosingMethod()); + if(MC001.class.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+MC001.class.getEnclosingConstructor()); + if(!MC001.class.isMemberClass()) fail("test_1, case 017 FAILED: "+MC001.class.isMemberClass()); + if(MC001.class.isLocalClass()) fail("test_1, case 018 FAILED: "+MC001.class.isLocalClass()); + if(MC001.class.isAnonymousClass()) fail("test_1, case 019 FAILED: "+MC001.class.isAnonymousClass()); + if(MC001.class.isSynthetic()) fail("test_1, case 020 FAILED: "+MC001.class.isSynthetic()); + if(!MC001.class.getCanonicalName().equals("java.lang.ClassHierarchyTest.MC001")) fail("test_1, case 021 FAILED: "+MC001.class.getCanonicalName()); + if(!MC001.class.getSimpleName().equals("MC001")) fail("test_1, case 022 FAILED: "+MC001.class.getSimpleName()); + } + + /** + * member interface + */ + public void test_1_1() { + if(!MI001.class.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_1, case 004 FAILED: "+MI001.class.getEnclosingClass()); + if(MI001.class.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+MI001.class.getEnumConstants()); + if(MI001.class.isEnum()) fail("test_1, case 000 FAILED: "+MI001.class.isEnum()); + try{MI001.class.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+MI001.class.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(MI001.class.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+MI001.class.getEnclosingMethod()); + if(MI001.class.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+MI001.class.getEnclosingConstructor()); + if(!MI001.class.isMemberClass()) fail("test_1, case 017 FAILED: "+MI001.class.isMemberClass()); + if(MI001.class.isLocalClass()) fail("test_1, case 018 FAILED: "+MI001.class.isLocalClass()); + if(MI001.class.isAnonymousClass()) fail("test_1, case 019 FAILED: "+MI001.class.isAnonymousClass()); + if(MI001.class.isSynthetic()) fail("test_1, case 020 FAILED: "+MI001.class.isSynthetic()); + if(!MI001.class.getCanonicalName().equals("java.lang.ClassHierarchyTest.MI001")) fail("test_1, case 021 FAILED: "+MI001.class.getCanonicalName()); + if(!MI001.class.getSimpleName().equals("MI001")) fail("test_1, case 022 FAILED: "+MI001.class.getSimpleName()); + } + + /** + * deeply nested member classes + */ + public void test_2() { + Class cuCla = MC001.MC001_01.MC001_01_01.MC001_01_01_01.MC001_01_01_01_01.MC001_01_01_01_01_01.MC001_01_01_01_01_01_01.class; + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + + /** + * deeply nested member interfaces + */ + public void test_2_1() { + Class cuCla = MI001.MI001_01.MI001_01_01.MI001_01_01_01.MI001_01_01_01_01.MI001_01_01_01_01_01.MI001_01_01_01_01_01_01.class; + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + + /** + * unnested local class + */ + public void test_3() { + @i class LC001 {}; + if(!LC001.class.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_3, case 004 FAILED: "+LC001.class.getEnclosingClass()); + if(LC001.class.getEnumConstants()!=null) fail("test_3, case 009 FAILED: "+LC001.class.getEnumConstants()); + if(LC001.class.isEnum()) fail("test_3, case 000 FAILED: "+LC001.class.isEnum()); + try{LC001.class.asSubclass(ClassHierarchyTest.class); fail("test_3, case 011 FAILED: "+LC001.class.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!LC001.class.getEnclosingMethod().getName().equals("test_3")) fail("test_3, case 013 FAILED: "+LC001.class.getEnclosingMethod().getName()); + if(LC001.class.getEnclosingConstructor()!=null) fail("test_3, case 014 FAILED: "+LC001.class.getEnclosingConstructor()); + if(LC001.class.isMemberClass()) fail("test_3, case 017 FAILED: "+LC001.class.isMemberClass()); + if(!LC001.class.isLocalClass()) fail("test_3, case 018 FAILED: "+LC001.class.isLocalClass()); + if(LC001.class.isAnonymousClass()) fail("test_3, case 019 FAILED: "+LC001.class.isAnonymousClass()); + if(LC001.class.isSynthetic()) fail("test_3, case 020 FAILED: "+LC001.class.isSynthetic()); + if(LC001.class.getCanonicalName()!=null) fail("test_3, case 021 FAILED: "+LC001.class.getCanonicalName()); + if(!LC001.class.getSimpleName().equals("LC001")) fail("test_3, case 022 FAILED: "+LC001.class.getSimpleName()); + } + + /** + * local ClassHierarchyTest$1$LC003$1A.class (1) + * anonymous ClassHierarchyTest$1$LC003$1.class (2) + * member of anonymous ClassHierarchyTest$1$LC003$1$A.class (3) + * local ClassHierarchyTest$1$LC003$1AAA.class (4) + */ + static int f = 0; + static Object ooo = null; + public void test_4() { // now it is a class access control bug, so, closed for a while + // It's strange that if we use javac instead of ecj + // then we have no such problem + // <<< A member of the "class java.lang.ClassHierarchyTest$1" with "" modifiers can not be accessed from the "class java.lang.ClassHierarchyTest">>> + // so it should be investigated. + @i + class LC002 { + } + ; + class $LC003 { + public Class value() { + class A extends $LC003 { // (1) + } + ; + Object o = new LC002() { // (2) + class A { // (3) + } + Class m1() { + return A.class; + } + Class m2() { + return m3() == null? m1():m3(); + } + Class m3() { + return m2(); + } + }; + ooo = o; + if (f < 1) { + f += 1; + return A.class; + } + f += 1; + return o.getClass(); + } + + public Class value2() { + class AAA { // (4) + } + ; + return AAA.class; + } + } + class X$1Y { + } + class X { + Class m2() { + class Y { // it has "X$2Y" name!!! So, compiler provides the + // difference with the previous "X$1Y" + } + return Y.class; + } + Class m4() { + return m5() == null? m2():m5(); + } + Class m5() { + return m4(); + } + } + Class cuCla = new $LC003().value(); // ClassHierarchyTest$1$LC003$1A.class (1) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value")) fail("test_4, case 013 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 017 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 020 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("A")) fail("test_4, case 022 FAILED: "+cuCla.getSimpleName()); + + cuCla = new $LC003().value(); // ClassHierarchyTest$1$LC003$1.class (2) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 023 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 024 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 025 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 026 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value")) fail("test_4, case 027 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 028 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 029 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_4, case 030 FAILED: "+cuCla.isLocalClass()); + if(!cuCla.isAnonymousClass()) fail("test_4, case 031 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 032 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 033 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("")) fail("test_4, case 034 FAILED: "+cuCla.getSimpleName()); + + cuCla = new $LC003().value2(); // ClassHierarchyTest$1$LC003$1AAA.class (4) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 035 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 036 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 037 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 038 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value2")) fail("test_4, case 039 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 040 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 041 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 042 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 043 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 044 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 045 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("AAA")) fail("test_4, case 046 FAILED: "+cuCla.getSimpleName()); + + try { + cuCla = (Class) new $LC003().value().getDeclaredMethod("m1").invoke(ooo, (Object[])null); // ClassHierarchyTest$1$LC003$1$A.class (3) + Class tc = Class.forName("java.lang.ClassHierarchyTest$1$LC003$1"); + if(!cuCla.getEnclosingClass().equals(tc)) fail("test_4, case 047 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 048 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 049 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 050 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_4, case 051 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 052 FAILED: "+cuCla.getEnclosingConstructor()); + if(!cuCla.isMemberClass()) fail("test_4, case 053 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_4, case 054 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 055 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 056 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 057 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("A")) fail("test_4, case 058 FAILED: "+cuCla.getSimpleName()); + } catch(ClassNotFoundException e) { + fail(e.getMessage()); + } catch(IllegalAccessException e) { + fail(e.getMessage()); + } catch(IllegalArgumentException e) { + fail(e.getMessage()); + } catch(java.lang.reflect.InvocationTargetException e) { + fail(e.getMessage()); + } catch(NoSuchMethodException e) { + fail(e.getMessage()); + } + + cuCla = X$1Y.class; // ClassHierarchyTest$1X$1Y.class (3) + if(!cuCla.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_4, case 059 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 060 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 061 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 062 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("test_4")) fail("test_4, case 063 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 064 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 065 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 066 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 067 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 068 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 069 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("X$1Y")) fail("test_4, case 070 FAILED: "+cuCla.getSimpleName()); + + try { + cuCla = (Class) X.class.getDeclaredMethod("m2").invoke(new X(), (Object[])null); // ClassHierarchyTest$1$LC003$1$A.class (3) + if(!cuCla.getEnclosingClass().equals(X.class)) fail("test_4, case 071 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 072 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 073 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 074 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("m2")) fail("test_4, case 075 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 076 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 077 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 078 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 079 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 080 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 081 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("Y")) fail("test_4, case 082 FAILED: "+cuCla.getSimpleName()); + } catch(IllegalAccessException e) { + fail(e.getMessage()); + } catch(IllegalArgumentException e) { + fail(e.getMessage()); + } catch(java.lang.reflect.InvocationTargetException e) { + fail(e.getMessage()); + } catch(NoSuchMethodException e) { + fail(e.getMessage()); + } + } + + /** + * Constructor's local class + */ + public void test_4_1() { + @i class LC001 { + public Class c; + public LC001() { + @i class LC001_01 { + } + c = LC001_01.class; + } + }; + LC001 lc = new LC001(); + if(!lc.c.getEnclosingClass().getName().equals("java.lang.ClassHierarchyTest$2LC001")) fail("test_3, case 004 FAILED: "+lc.c.getEnclosingClass().getName()); + if(lc.c.getEnumConstants()!=null) fail("test_3, case 009 FAILED: "+lc.c.getEnumConstants()); + if(lc.c.isEnum()) fail("test_3, case 000 FAILED: "+lc.c.isEnum()); + try{lc.c.asSubclass(ClassHierarchyTest.class); fail("test_3, case 011 FAILED: "+lc.c.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(lc.c.getEnclosingMethod()!=null) fail("test_3, case 013 FAILED: "+lc.c.getEnclosingMethod().getName()); + if(!lc.c.getEnclosingConstructor().getName().equals("java.lang.ClassHierarchyTest$2LC001")) fail("test_3, case 014 FAILED: "+lc.c.getEnclosingConstructor()); + if(lc.c.isMemberClass()) fail("test_3, case 017 FAILED: "+lc.c.isMemberClass()); + if(!lc.c.isLocalClass()) fail("test_3, case 018 FAILED: "+lc.c.isLocalClass()); + if(lc.c.isAnonymousClass()) fail("test_3, case 019 FAILED: "+lc.c.isAnonymousClass()); + if(lc.c.isSynthetic()) fail("test_3, case 020 FAILED: "+lc.c.isSynthetic()); + if(lc.c.getCanonicalName()!=null) fail("test_3, case 021 FAILED: "+lc.c.getCanonicalName()); + if(!lc.c.getSimpleName().equals("LC001_01")) fail("test_3, case 022 FAILED: "+lc.c.getSimpleName()); + } + + /** + * proxy class + */ + public void test_5() { + class LIH implements java.lang.reflect.InvocationHandler { + public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable + { + return null; + } + } + Class cuCla = java.lang.reflect.Proxy.newProxyInstance(java.io.Serializable.class.getClassLoader(), + new Class[] { java.io.Serializable.class }, + new LIH()).getClass(); + + if(cuCla.getEnclosingClass()!=null) fail("test_5, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_5, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_5, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_5, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_5, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_5, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_5, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_5, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_5, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_5, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().replaceFirst("\\$Proxy", "").matches("\\d+")) fail("test_5, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().replaceFirst("\\$Proxy", "").matches("\\d+")) fail("test_5, case 022 FAILED: "+cuCla.getSimpleName()); + } + +///////////////////////// II: + /** + * member interfaces + */ + public void test_6() { + if(!MI001.class.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_1, case 004 FAILED: "+MI001.class.getEnclosingClass()); + if(MI001.class.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+MI001.class.getEnumConstants()); + if(MI001.class.isEnum()) fail("test_1, case 000 FAILED: "+MI001.class.isEnum()); + try{MI001.class.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+MI001.class.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(MI001.class.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+MI001.class.getEnclosingMethod()); + if(MI001.class.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+MI001.class.getEnclosingConstructor()); + if(!MI001.class.isMemberClass()) fail("test_1, case 017 FAILED: "+MI001.class.isMemberClass()); + if(MI001.class.isLocalClass()) fail("test_1, case 018 FAILED: "+MI001.class.isLocalClass()); + if(MI001.class.isAnonymousClass()) fail("test_1, case 019 FAILED: "+MI001.class.isAnonymousClass()); + if(MI001.class.isSynthetic()) fail("test_1, case 020 FAILED: "+MI001.class.isSynthetic()); + if(!MI001.class.getCanonicalName().equals("java.lang.ClassHierarchyTest.MI001")) fail("test_1, case 021 FAILED: "+MI001.class.getCanonicalName()); + if(!MI001.class.getSimpleName().equals("MI001")) fail("test_1, case 022 FAILED: "+MI001.class.getSimpleName()); + } + + /** + * deeply nested member interfaces + */ + public void test_7() { + Class cuCla = MI001.MI001_01.MI001_01_01.MI001_01_01_01.MI001_01_01_01_01.MI001_01_01_01_01_01.MI001_01_01_01_01_01_01.class; + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + +///////////////////////// III: + /** + * member annotations as interfaces + */ + @MA001 @MA001.MA001_01 @MA001.MA001_01.MA001_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01.MA001_01_01_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01.MA001_01_01_01_01_01_01.iiii public void test_8() { + Class cuCla = MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01.MA001_01_01_01_01_01_01.class; + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + + /** + * member annotations as annotations + */ + @MA001 @MA001.MA001_01 @MA001.MA001_01.MA001_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01.MA001_01_01_01_01_01_01 @MA001.MA001_01.MA001_01_01.MA001_01_01_01.MA001_01_01_01_01.MA001_01_01_01_01_01.MA001_01_01_01_01_01_01.iiii public void test_9() { + Annotation aa[] = null; + try{ + aa = ClassHierarchyTest.class.getMethod("test_9").getAnnotations(); + } catch (NoSuchMethodException e) { + fail("test_9, case 009 FAILED: "+e.toString()); + } + for (int i = 0; i < aa.length; i++) { + Class cuCla = aa[i].annotationType(); + String caNa = cuCla.getCanonicalName(); + String name[] = caNa.split("\\."); + int j = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[j])) fail("test_9, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_9, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_9, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_9, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_9, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_9, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_9, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_9, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_9, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_9, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_9, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[j])) fail("test_9, case 022 FAILED: "+cuCla.getSimpleName()); + j--; + cuCla = cuCla.getEnclosingClass(); + } + } + } + +///////////////////////// IV: + /** + * member enums + */ + public static enum ME001 { + F_S(2),M_S(3),C_S(4),CL_S(1); + ME001(int value) { + cccccc1 = ME001_01_.class; + this.value = value; + } + private final int value; + public static Class cccc2; + public Class ccccc3; + public Class cccccc1; + { + class XXXX{}; + ccccc3 = ME001_01_.class; + } + public int value() { + class XXX{}; + cccc2 = ME001_01_.class; + return value; + } + public static enum ME001_01_ {G_A_T, P_T, V_T, W_T; + public static enum ME001_01_1 {G_A_T, P_T, V_T, W_T; + public static enum ME001_01_2 {G_A_T, P_T, V_T, W_T; + public static enum ME001_01_3 {G_A_T, P_T, V_T, W_T; + public static enum ME001_01_4 {G_A_T, P_T, V_T, W_T; + public static enum ME001_01_5 {G_A_T, P_T, V_T, W_T; + private final int value = 0; + public int value() { + return value; + } + public static Class pop() { + class XXX{}; + return XXX.class; + } + }; + }; + }; + }; + }; + }; + }; + public static enum ME001_01_ {G_A_T, P_T, V_T, W_T}; + public void test_10() { + //Class cuCla = ME001.cccc2; - null + //Class cuCla = new ME001(77).cccccc1; + Class cuCla = ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.class; + if(!cuCla.getEnclosingClass().equals(java.lang.ClassHierarchyTest.ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.class)) fail("test_1, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()==null) fail("test_1, case 009 FAILED: "+cuCla.getEnumConstants()); + ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5 ae[] = (ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5[])cuCla.getEnumConstants(); + for (int i = 0; i < ae.length; i++) { + if (!ae[i].equals(ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.G_A_T) && + !ae[i].equals(ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.P_T) && + !ae[i].equals(ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.V_T) && + !ae[i].equals(ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.W_T)) { + fail("test_1, case 001 FAILED: "+ae[i]+" is not this enum's constant"); + } + } + if(!cuCla.isEnum()) fail("test_1, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.class); fail("test_1, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(!cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_1, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_1, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_1, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest.ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5")) fail("test_1, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("ME001_01_5")) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + + if (RuntimeAdditionalSupport1.openingFlag) { + cuCla = ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.pop(); + if(!cuCla.getEnclosingClass().equals(java.lang.ClassHierarchyTest.ME001.ME001_01_.ME001_01_1.ME001_01_2.ME001_01_3.ME001_01_4.ME001_01_5.class)) fail("test_1, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_1, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("pop")) fail("test_1, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_1, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_1, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_1, case 020 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_1, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("XXX")) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + } + + } + +///////////////////////// V: + /** + * casting + */ + interface XXX{}; + enum tmp15$ implements XXX { + PENNY(1),NICKEL(5),DIME(10),QUARTER(25); + tmp15$(int value) {this.value = value;} + private final int value; + public int value() { + return value; + } + enum yyy$1$2$3 {WHITE, GREY, BLACK}; + } + static Object obj; + public void test_11() { + class A { + } + class B extends A { + } + class $tmp15 { + } + class $tmp16 { + } + try { + Object o = new $tmp16(); + tmp15$.class.cast(o); + tmp15$ x = (tmp15$) o; obj = x; + fail("test_11, case 001 FAILED: ClassCastException should be risen"); + } catch (ClassCastException e) { + } + try { + Object o = new $tmp16(); + tmp15$ i = (tmp15$) o; obj = i; + fail("test_11, case 002 FAILED: ClassCastException should be risen"); + } catch (ClassCastException e) { + } + class CC<T extends Number> { + } + CC<Integer> io = new CC<Integer>(); + CC<Float> fo = new CC<Float>(); + fo.getClass().cast(io); + class Str { + } + class CCC<T extends Str & java.io.Serializable> { + } + class CCCc<T1 extends Str & java.io.Serializable, T2> { + } + class Xx extends Str implements java.io.Serializable {static final long serialVersionUID = 0; + } + class Yy extends Str implements java.io.Serializable {static final long serialVersionUID = 0; + } + CCC<?> io2 = new CCC<Xx>(); + CCC<? extends Str> fo2 = new CCC<Yy>(); + if (!io2.getClass().getName().equals("java.lang.ClassHierarchyTest$1CCC")) { + fail("test_11, case 003 FAILED: "+io2.getClass().getName()); + } + if (!fo2.getClass().cast(io2).getClass().getName().equals("java.lang.ClassHierarchyTest$1CCC")) { + fail("test_11, case 004 FAILED: "+io2.getClass().getName()); + } + CCCc<Xx, Yy> fo3 = new CCCc<Xx, Yy>(); + Object o = new CCCc<Yy, Yy>(); + try { + // fo3 = (CCCc<Xx,Yy>) new CCCc<Yy,Yy>(); // inconvertible types: found : CCCc<Yy,Yy> - required: CCCc<Xx,Yy> + fo3 = (CCCc<Xx, Yy>) o; // but it is run (look just above)! + // so, it's expected the exceptions will risen while running deeply + fo3.getClass().cast(new CCCc<Yy, Yy>()); // so, looks like our cast() implementation is not worse + } catch (Exception e) { + fail("test_11, case 005 FAILED: "+e.toString()); + } + try { + Object ooo = (Object) fo2; + if (fo3.getClass().isAssignableFrom(fo2.getClass())) { + fail("test_11, case 006 FAILED"); + } + if (ooo instanceof CCCc) { + fail("test_11, case 007 FAILEDn"); + } + fo3.getClass().cast(fo2); + fail("test_11, case 008 FAILED: ClassCastException should be risen"); + } catch (ClassCastException e) { + //e.printStackTrace(); + } + try { + Object o1 = new CCCc<Xx, Yy>(); + Object o2 = new CCCc<Xx, Yy>(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 009 FAILED: ClassCastException should not be risen"); + } + try { + Object o1 = new CCCc<Xx, Xx>(); + Object o2 = new CCCc<Xx, Yy>(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 010 FAILED: ClassCastException should notbe risen"); + } + try { + Object o1 = new CCCc<Xx, Xx>(); + Object o2 = new CCCc<Yy, Yy>(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 011 FAILED: ClassCastException should not be risen"); + } + try { + Object o1 = new CCCc<Xx, Xx>(); + Object o2 = new CCCc<Yy, Xx>(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 012 FAILED: ClassCastException should not be risen"); + } + try { + Object o1 = new CCCc(); + Object o2 = new CCCc<Xx, Yy>(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 013 FAILED: ClassCastException should not be risen"); + } + try { + Object o1 = new CCCc<Xx, Yy>(); + Object o2 = new CCCc(); + Object o3 = o1.getClass().cast(o2);obj = o3; + Object o4 = o2.getClass().cast(o1);obj = o4; + Object o5 = o2.getClass().cast(null);obj = o5; + Class cuCla1 = o1.getClass(); + Class cuCla2 = o2.getClass(); + Class cuCla3 = cuCla1.asSubclass(cuCla2);obj = cuCla3; + } catch (ClassCastException e) { + fail("test_11, case 014 FAILED: ClassCastException should not be risen"); + } + + class Str2 { + } + class CCC2<T extends Str & java.io.Serializable> { + } + class CCCc2<T1 extends Str & java.io.Serializable, T2> { + } + class Xx2 extends Str implements java.io.Serializable {static final long serialVersionUID = 0; + } + class Yy2 extends Str implements java.io.Serializable {static final long serialVersionUID = 0; + } + CCC2<? extends Str> fo22 = new CCC2<Yy2>(); + CCCc2<Xx2, Yy2> fo33 = new CCCc2<Xx2, Yy2>(); + Object o2 = new CCCc2<Yy, Yy>(); + try { + fo33 = (CCCc2<Xx2, Yy2>) o2; + fo33.getClass().cast(new CCCc2<Yy2, Yy2>()); + try { + fo33.getClass().cast(new CCCc<Yy2, Yy2>()); + fail("test_11, case 015 FAILED: ClassCastException should be risen"); + } catch (ClassCastException e) { + } + fo33.getClass().cast(new CCCc2<Yy, Yy>()); + } catch (Exception e) { + e.printStackTrace(); + fail("test_11, case 016 FAILED: "+e.toString()); + } + try { + fo33.getClass().cast(fo22); + fail("test_11, case 017 FAILED: ClassCastException should be risen"); + } catch (ClassCastException e) { + //e.printStackTrace(); + } + + } + + /** + * generalized member class + */ + @anna public void test_12() { + Class cuCla = new MC002<Object, java.lang.reflect.Proxy, MC002<Integer, Void, Character>.MC002_01<Integer, Void, Character>.MC002_01_01<Integer, Void, Character>.MC002_01_01_01<Integer, Void, Character>.MC002_01_01_01_01<Integer, Void, Character>.MC002_01_01_01_01_01<Integer, Void, Character>.MC002_01_01_01_01_01_01<Integer, Void, Character>>().getClass(); + if(!cuCla.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_1, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_1, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(!cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_1, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_1, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_1, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest.MC002")) fail("test_1, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("MC002")) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + + if(cuCla.getGenericInterfaces().length != 0) fail("test_1, case 022 FAILED: "+cuCla.getGenericInterfaces().length); + if(!((Class)cuCla.getGenericSuperclass()).getName().equals("java.lang.Object")) fail("test_1, case 022 FAILED: "+((Class)cuCla.getGenericSuperclass()).getName()); + if(cuCla.getTypeParameters().length == 0) fail("test_1, case 022 FAILED: "+cuCla.getTypeParameters().length); + /* !!! */ System.out.println(111); + + Annotation aaa = null; + try{aaa = ClassHierarchyTest.class.getMethod("test_12").getAnnotations()[0];}catch(NoSuchMethodException e){fail("test_1, case 022 FAILED: Internal Error");} + try{if(cuCla.cast(aaa) == null) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName());}catch(Exception e){/*e.printStackTrace();*/} + + if(cuCla.getAnnotation(aaa.annotationType()) != null) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + if(cuCla.getAnnotations().length == 0) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + if(cuCla.getDeclaredAnnotations().length == 0) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + if(cuCla.isAnnotation()) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + if(cuCla.isAnnotationPresent(aaa.annotationType())) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + } + + /** + * generalized member interface + */ +//Commented because of the drlvm issue + public void te_st_12_1() { // it is eclipse's bug + // It's strange that if we use javac instead of ecj + // then we have no such problem + // <<< java.lang.NoClassDefFoundError: Ajava/lang/ClassHierarchyTest$1xxx: class name in class data does not match class name passed>>> + // so it should be investigated. + + + // The wollowing crashes bvm: + //class x implements MI002.MI002_01.MI002_01_01.MI002_01_01_01.MI002_01_01_01_01.MI002_01_01_01_01_01.MI002_01_01_01_01_01_01<java.io.Serializable, java.lang.reflect.Type, java.lang.reflect.InvocationHandler> {}; + //Class cuCla = (Class)x.class.getGenericInterfaces()[0]; + class xxx implements MI002.MI002_01.MI002_01_01.MI002_01_01_01.MI002_01_01_01_01.MI002_01_01_01_01_01.MI002_01_01_01_01_01_01<java.io.Serializable, java.lang.reflect.Type, java.lang.reflect.InvocationHandler> {}; + Class cuCla = (Class)((java.lang.reflect.ParameterizedType)xxx.class.getGenericInterfaces()[0]).getRawType(); + if(!cuCla.getEnclosingClass().equals(MI002.MI002_01.MI002_01_01.MI002_01_01_01.MI002_01_01_01_01.MI002_01_01_01_01_01.class)) fail("test_1, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_1, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_1, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_1, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_1, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_1, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(!cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_1, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_1, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_1, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest.MI002.MI002_01.MI002_01_01.MI002_01_01_01.MI002_01_01_01_01.MI002_01_01_01_01_01.MI002_01_01_01_01_01_01")) fail("test_1, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("MI002_01_01_01_01_01_01")) fail("test_1, case 022 FAILED: "+cuCla.getSimpleName()); + } + + /** + * deeply nested generalized member classes + */ + public void test_13() { + Class cuCla = new MC002<Object, java.lang.reflect.Proxy, MC002<Integer, Void, Character>.MC002_01<Integer, Void, Character>.MC002_01_01<Integer, Void, Character>.MC002_01_01_01<Integer, Void, Character>.MC002_01_01_01_01<Integer, Void, Character>.MC002_01_01_01_01_01<Integer, Void, Character>.MC002_01_01_01_01_01_01<Integer, Void, Character>>().getClass(); + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + + /** + * deeply nested generalized member interfaces + */ +//Commented because of the drlvm issue + public void te_st_13_1() { // it is eclipse's bug + // It's strange that if we use javac instead of ecj + // then we have no such problem + // <<< java.lang.NoClassDefFoundError: Ajava/lang/ClassHierarchyTest$1xxx: class name in class data does not match class name passed>>> + // so it should be investigated. + //Class cuCla = MI001.MI001_01.MI001_01_01.MI001_01_01_01.MI001_01_01_01_01.MI001_01_01_01_01_01.MI001_01_01_01_01_01_01.class; + class xxx implements MI002.MI002_01.MI002_01_01.MI002_01_01_01.MI002_01_01_01_01.MI002_01_01_01_01_01.MI002_01_01_01_01_01_01<java.io.Serializable, java.lang.reflect.Type, java.lang.reflect.InvocationHandler> {}; + Class cuCla = (Class)((java.lang.reflect.ParameterizedType)xxx.class.getGenericInterfaces()[0]).getRawType(); + String caNa = cuCla.getCanonicalName(); + //String name[] = caNa.split("\\$"); + String name[] = caNa.split("\\."); + int i = name.length - 1; + while (cuCla != null) { + if(cuCla.getEnclosingClass() != null && cuCla.getEnclosingClass().getSimpleName().equals(name[i])) fail("test_2, case 002 FAILED: "+cuCla.getEnclosingClass().getSimpleName()); + if(cuCla.getEnumConstants()!=null) fail("test_2, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_2, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ); if(!cuCla.getCanonicalName().equals("java.lang.ClassHierarchyTest")) fail("test_2, case 011 FAILED: "+ cuCla.asSubclass( cuCla.getEnclosingClass() != null ? cuCla.getEnclosingClass() : cuCla ));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_2, case 013 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_2, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.getEnclosingClass() != null && !cuCla.isMemberClass()) fail("test_1, case 017 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_2, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_2, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_2, case 020 FAILED: "+cuCla.isSynthetic()); + if(!cuCla.getCanonicalName().equals(caNa)) fail("test_2, case 021 FAILED: "+cuCla.getCanonicalName()); + caNa = caNa.substring(0, caNa.lastIndexOf('.')); + if(!cuCla.getSimpleName().equals(name[i])) fail("test_2, case 022 FAILED: "+cuCla.getSimpleName()); + i--; + cuCla = cuCla.getEnclosingClass(); + } + } + + /** + * unnested generalized local class + */ + public <T0> void test_14() { + @i class LC000<T1 extends T0> { + + } + //@i class LC001<T1 extends T0 &java.io.Serializable &java.lang.reflect.Type &java.lang.reflect.GenericDeclaration> { + @i class LC001<T1 extends LC000 &java.io.Serializable &java.lang.reflect.Type &GenericDeclaration> { + java.lang.reflect.TypeVariable<?>[] getTypeParameters() { + return (java.lang.reflect.TypeVariable<?>[])null; + } + }; + new LC001().getTypeParameters(); + if(!LC001.class.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_3, case 004 FAILED: "+LC001.class.getEnclosingClass()); + if(LC001.class.getEnumConstants()!=null) fail("test_3, case 009 FAILED: "+LC001.class.getEnumConstants()); + if(LC001.class.isEnum()) fail("test_3, case 000 FAILED: "+LC001.class.isEnum()); + try{LC001.class.asSubclass(ClassHierarchyTest.class); fail("test_3, case 011 FAILED: "+LC001.class.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!LC001.class.getEnclosingMethod().getName().equals("test_14")) fail("test_3, case 013 FAILED: "+LC001.class.getEnclosingMethod().getName()); + if(LC001.class.getEnclosingConstructor()!=null) fail("test_3, case 014 FAILED: "+LC001.class.getEnclosingConstructor()); + if(LC001.class.isMemberClass()) fail("test_3, case 017 FAILED: "+LC001.class.isMemberClass()); + if(!LC001.class.isLocalClass()) fail("test_3, case 018 FAILED: "+LC001.class.isLocalClass()); + if(LC001.class.isAnonymousClass()) fail("test_3, case 019 FAILED: "+LC001.class.isAnonymousClass()); + if(LC001.class.isSynthetic()) fail("test_3, case 020 FAILED: "+LC001.class.isSynthetic()); + if(LC001.class.getCanonicalName()!=null) fail("test_3, case 021 FAILED: "+LC001.class.getCanonicalName()); + if(!LC001.class.getSimpleName().equals("LC001")) fail("test_3, case 022 FAILED: "+LC001.class.getSimpleName()); + } + + /** + * generalized local ClassHierarchyTest$1$LC003$1A.class (1) + * generalized anonymous ClassHierarchyTest$1$LC003$1.class (2) + * generalized member of anonymous ClassHierarchyTest$1$LC003$1$A.class (3) + * generalized local ClassHierarchyTest$1$LC003$1AAA.class (4) + */ + static int f2 = 0; + static Object ooo2 = null; + public <T0 extends MC002> void test_15() { // it is eclipse's bug + // It's strange that if we use javac instead of ecj + // then we have no such problem + // <<< java.lang.NoClassDefFoundError: Ajava/lang/ClassHierarchyTest$1xxx: class name in class data does not match class name passed>>> + // so it should be investigated. + @i + class LC002<T1 extends T0> { + } + ; + class $LC003<T2 extends ClassHierarchyTest &java.lang.reflect.ParameterizedType> { + public Class value() { + class A<T3 extends T2> extends $LC003 { // (1) + } + ; + Object o = new LC002<T0>() { // (2) + class A<T5, T6, T7, T8, T9> { // (3) + } + Class m1() { + return A.class; + } + Class m2() { + return m1() == null? m3():m1(); + } + Class m3() { + return m2() == null? m1():m2(); + } + }; + ooo2 = o; + if (f2 < 1) { + f2 += 1; + return A.class; + } + f2 += 1; + return o.getClass(); + } + + public Class value2() { + class AAA<T10> { // (4) + } + ; + return AAA.class; + } + } + class X$1Y<T11> { + } + class X<T12, T13 extends ClassHierarchyTest> { + Class m2() { + class Y<T121, T131> { // it has "X$2Y" name!!! So, compiler provides the + // difference with the previous "X$1Y" + } + return Y.class; + } + } + new X().m2(); + Class cuCla = new $LC003().value(); // ClassHierarchyTest$1$LC003$1A.class (1) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 004 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 009 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 000 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 011 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value")) fail("test_4, case 013 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 014 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 017 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 018 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 019 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 020 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 021 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("A")) fail("test_4, case 022 FAILED: "+cuCla.getSimpleName()); + + cuCla = new $LC003().value(); // ClassHierarchyTest$1$LC003$1.class (2) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 023 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 024 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 025 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 026 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value")) fail("test_4, case 027 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 028 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 029 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_4, case 030 FAILED: "+cuCla.isLocalClass()); + if(!cuCla.isAnonymousClass()) fail("test_4, case 031 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 032 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 033 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("")) fail("test_4, case 034 FAILED: "+cuCla.getSimpleName()); + + cuCla = new $LC003().value2(); // ClassHierarchyTest$1$LC003$1AAA.class (4) + if(!cuCla.getEnclosingClass().equals($LC003.class)) fail("test_4, case 035 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 036 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 037 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 038 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("value2")) fail("test_4, case 039 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 040 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 041 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 042 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 043 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 044 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 045 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("AAA")) fail("test_4, case 046 FAILED: "+cuCla.getSimpleName()); + + try { + cuCla = (Class) new $LC003().value().getDeclaredMethod("m1").invoke(ooo2, (Object[])null); // ClassHierarchyTest$1$LC003$1$A.class (3) + Class tc = Class.forName("java.lang.ClassHierarchyTest$2$LC003$1"); + if(!cuCla.getEnclosingClass().equals(tc)) fail("test_4, case 047 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 048 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 049 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 050 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(cuCla.getEnclosingMethod()!=null) fail("test_4, case 051 FAILED: "+cuCla.getEnclosingMethod()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 052 FAILED: "+cuCla.getEnclosingConstructor()); + if(!cuCla.isMemberClass()) fail("test_4, case 053 FAILED: "+cuCla.isMemberClass()); + if(cuCla.isLocalClass()) fail("test_4, case 054 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 055 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 056 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 057 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("A")) fail("test_4, case 058 FAILED: "+cuCla.getSimpleName()); + } catch(ClassNotFoundException e) { + fail(e.getMessage()); + } catch(IllegalAccessException e) { + fail(e.getMessage()); + } catch(IllegalArgumentException e) { + fail(e.getMessage()); + } catch(java.lang.reflect.InvocationTargetException e) { + fail(e.getMessage()); + } catch(NoSuchMethodException e) { + fail(e.getMessage()); + } + + cuCla = X$1Y.class; // ClassHierarchyTest$1X$1Y.class (3) + if(!cuCla.getEnclosingClass().equals(ClassHierarchyTest.class)) fail("test_4, case 059 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 060 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 061 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 062 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("test_15")) fail("test_4, case 063 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 064 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 065 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 066 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 067 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 068 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 069 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("X$1Y")) fail("test_4, case 070 FAILED: "+cuCla.getSimpleName()); + + try { + cuCla = (Class) X.class.getDeclaredMethod("m2").invoke(new X(), (Object[])null); // ClassHierarchyTest$1$LC003$1$A.class (3) + if(!cuCla.getEnclosingClass().equals(X.class)) fail("test_4, case 071 FAILED: "+cuCla.getEnclosingClass()); + if(cuCla.getEnumConstants()!=null) fail("test_4, case 072 FAILED: "+cuCla.getEnumConstants()); + if(cuCla.isEnum()) fail("test_4, case 073 FAILED: "+cuCla.isEnum()); + try{cuCla.asSubclass(ClassHierarchyTest.class); fail("test_4, case 074 FAILED: "+cuCla.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(!cuCla.getEnclosingMethod().getName().equals("m2")) fail("test_4, case 075 FAILED: "+cuCla.getEnclosingMethod().getName()); + if(cuCla.getEnclosingConstructor()!=null) fail("test_4, case 076 FAILED: "+cuCla.getEnclosingConstructor()); + if(cuCla.isMemberClass()) fail("test_4, case 077 FAILED: "+cuCla.isMemberClass()); + if(!cuCla.isLocalClass()) fail("test_4, case 078 FAILED: "+cuCla.isLocalClass()); + if(cuCla.isAnonymousClass()) fail("test_4, case 079 FAILED: "+cuCla.isAnonymousClass()); + if(cuCla.isSynthetic()) fail("test_4, case 080 FAILED: "+cuCla.isSynthetic()); + if(cuCla.getCanonicalName()!=null) fail("test_4, case 081 FAILED: "+cuCla.getCanonicalName()); + if(!cuCla.getSimpleName().equals("Y")) fail("test_4, case 082 FAILED: "+cuCla.getSimpleName()); + } catch(IllegalAccessException e) { + fail(e.getMessage()); + } catch(IllegalArgumentException e) { + fail(e.getMessage()); + } catch(java.lang.reflect.InvocationTargetException e) { + fail(e.getMessage()); + } catch(NoSuchMethodException e) { + fail(e.getMessage()); + } + } + + /** + * Constructor's generalized local class + */ + public <T0> void test_16() { + @i class LC000<T1 extends T0> { + + } + @i class LC001<T1 extends LC000 &java.io.Serializable &java.lang.reflect.Type &GenericDeclaration> { + public Class c; + java.lang.reflect.TypeVariable<?>[] getTypeParameters() { + return (java.lang.reflect.TypeVariable<?>[])null; + } + public <T2 extends T0, T3 extends T1, T4 extends LC000<T0>>LC001() { + @i class LC001_01 { + } + c = LC001_01.class; + } + }; + LC001 lc = new LC001(); + lc.getTypeParameters(); + if(!lc.c.getEnclosingClass().getName().equals("java.lang.ClassHierarchyTest$4LC001")) fail("test_3, case 004 FAILED: "+lc.c.getEnclosingClass().getName()); + if(lc.c.getEnumConstants()!=null) fail("test_3, case 009 FAILED: "+lc.c.getEnumConstants()); + if(lc.c.isEnum()) fail("test_3, case 000 FAILED: "+lc.c.isEnum()); + try{lc.c.asSubclass(ClassHierarchyTest.class); fail("test_3, case 011 FAILED: "+lc.c.asSubclass(ClassHierarchyTest.class));}catch(Exception e){/*e.printStackTrace();*/} + if(lc.c.getEnclosingMethod()!=null) fail("test_3, case 013 FAILED: "+lc.c.getEnclosingMethod().getName()); + if(!lc.c.getEnclosingConstructor().getName().equals("java.lang.ClassHierarchyTest$4LC001")) fail("test_3, case 014 FAILED: "+lc.c.getEnclosingConstructor()); + if(lc.c.isMemberClass()) fail("test_3, case 017 FAILED: "+lc.c.isMemberClass()); + if(!lc.c.isLocalClass()) fail("test_3, case 018 FAILED: "+lc.c.isLocalClass()); + if(lc.c.isAnonymousClass()) fail("test_3, case 019 FAILED: "+lc.c.isAnonymousClass()); + if(lc.c.isSynthetic()) fail("test_3, case 020 FAILED: "+lc.c.isSynthetic()); + if(lc.c.getCanonicalName()!=null) fail("test_3, case 021 FAILED: "+lc.c.getCanonicalName()); + if(!lc.c.getSimpleName().equals("LC001_01")) fail("test_3, case 022 FAILED: "+lc.c.getSimpleName()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassLoaderTest.java vm/tests/kernel/java/lang/ClassLoaderTest.java new file mode 100644 index 0000000..633508a --- /dev/null +++ vm/tests/kernel/java/lang/ClassLoaderTest.java @@ -0,0 +1,2204 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; + +import org.apache.harmony.test.TestResources; + +import junit.framework.TestCase; + +/* + * Created on 02.04.2006 + * + * This ClassLoaderTest class is used to test the Core API + * java.lang.ClassLoader class + * + */ + +@SuppressWarnings(value={"all"}) public class ClassLoaderTest extends TestCase { + + static String vendor = System.getProperty("java.vm.vendor"); + + class TestClassLoader extends ClassLoader { + // Use only for top level classes + + public Class<?> findClass(String name) { + String nm = name.substring(1, name.length()); + byte[] b = loadClassData(nm); + return defineClass(nm, b, 0, b.length); + } + + private byte[] loadClassData(String name) { + //return new byte[0]; + //System.out.println("loadClassData: "+ name); + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + //System.out.println("loadClassData: "+ nm); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public TestClassLoader() { + super(); + } + + public TestClassLoader(ClassLoader cl) { + super(cl); + } + } + + /** + * + */ + public void test_ClassLoader_V() { + assertTrue("Error1", + new TestClassLoader().getParent() == TestClassLoader + .getSystemClassLoader()); + } + + /** + * + */ + public void test_ClassLoader_Cla() { + TestClassLoader tcl = new TestClassLoader(); + assertTrue("Error1", + new TestClassLoader((ClassLoader) tcl).getParent() == tcl); + } + + /** + * + */ + public void test_clearAssertionStatus_V() { + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).clearAssertionStatus(); + + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + cl.clearAssertionStatus(); + try { + Class c = cl.loadClass("javax.xml.transform.stream.StreamResult"); + try { + c.newInstance(); // to be initialized + } catch (Exception _) { + //System.out.println("(test_clearAssertionStatus_V)Exception + // 1"); + } + assertTrue("Error1:", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); // "this method is not + // guaranteed to return the + // actual assertion status" + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 1"); + } + } + + /** + * + */ +//Commented because of the drlvm issue +// public void te_st_defineClass_BArr_I_I() { + public void test_defineClass_BArr_I_I() { + class LCL extends ClassLoader { + // only for special case + + public Class findClass(String name) { + String nm = name.substring(1, name.length()); + byte[] b = loadClassData(nm); + if (nm.endsWith("SAXTransformerFactory")) { + return defineClass(b, 0, b.length); // ALL RIGHT + } else if (nm.endsWith("SAXSource")) { + return defineClass(b, 10, b.length - 20); // ClassFormatError + } else if (nm.endsWith("SAXResult")) { + return defineClass(b, 0, b.length + 20); // IndexOutOfBoundsException + } + return null; + } + + private byte[] loadClassData(String name) { + //System.out.println("loadClassData: "+ name); + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + //System.out.println("loadClassData: "+ nm); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public LCL() { + super(); + } + + public LCL(ClassLoader cl) { + super(cl); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + try { + Class c = tcl + .loadClass("#javax.xml.transform.sax.SAXTransformerFactory"); + assertTrue("Error1", c != null); + } catch (ClassNotFoundException _) { + } + + // TEST CASE #2: + try { + Class c = tcl.loadClass("#javax.xml.transform.sax.SAXSource"); + fail("Error2: "); + } catch (ClassFormatError _) { + } catch (ClassNotFoundException e) { + fail("Error3: " + e.toString()); + } + + // TEST CASE #3: + try { + Class c = tcl.loadClass("#javax.xml.transform.sax.SAXResult"); + fail("Error4: "); + } catch (IndexOutOfBoundsException _) { + } catch (ClassNotFoundException e) { + fail("Error5: " + e.toString()); + } + } + + /** + * + */ + public void test_defineClass_Str_BArr_I_I() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + String nm = name.substring(1, name.length()); + byte[] b = loadClassData(nm); + if (nm.endsWith("SAXTransformerFactory")) { + return defineClass(nm, b, 0, b.length); // ALL RIGHT + } else if (nm.endsWith("SAXSource")) { + return defineClass(nm, b, 10, b.length - 20); // ClassFormatError + } else if (nm.endsWith("SAXResult")) { + return defineClass(nm, b, 0, b.length + 20); // IndexOutOfBoundsException + } else if (nm.endsWith("DOMResult")) { + return defineClass(nm + "XXX", b, 0, b.length); // NoClassDefFoundError + } else if (nm.endsWith("Calendar")) { + return defineClass(nm, b, 0, b.length); // SecurityException + } + return null; + } + + private byte[] loadClassData(String name) { + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + try { + Class c = tcl + .loadClass("#javax.xml.transform.sax.SAXTransformerFactory"); + assertTrue("Error1", c != null); + } catch (ClassNotFoundException _) { + } + + // TEST CASE #2: + try { + tcl.loadClass("#javax.xml.transform.sax.SAXSource"); + fail("Error2: "); + } catch (ClassFormatError _) { + } catch (ClassNotFoundException e) { + fail("Error3: " + e.toString()); + } + + // TEST CASE #3: + try { + tcl.loadClass("#javax.xml.transform.sax.SAXResult"); + fail("Error4: "); + } catch (IndexOutOfBoundsException _) { + } catch (ClassNotFoundException e) { + fail("Error5: " + e.toString()); + } + + // TEST CASE #4: + try { + tcl.loadClass("#javax.xml.transform.dom.DOMResult"); + fail("Error6: "); + } catch (NoClassDefFoundError _) { + } catch (ClassNotFoundException e) { + fail("Error7: " + e.toString()); + } + + // TEST CASE #5: + try { + tcl.loadClass("#java.util.Calendar"); + fail("Error8: "); + } catch (SecurityException _) { + } catch (ClassNotFoundException e) { + fail("Error9: " + e.toString()); + } + } + + /** + * + */ + public void test_defineClass_Str_BArr_I_I_Pro() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + String nm = name.substring(1, name.length()); + //java.security.ProtectionDomain pd = new + // java.security.ProtectionDomain(new CodeSource(new + // java.net.URL(""), new java.security.cert.Certificate[]{} ), + // new PermissionCollection()); + java.security.ProtectionDomain pd = Void.class + .getProtectionDomain(); + byte[] b = loadClassData(nm); + if (nm.endsWith("SAXTransformerFactory")) { + return defineClass(nm, b, 0, b.length, pd); // ALL RIGHT + } else if (nm.endsWith("SAXSource")) { + return defineClass(nm, b, 10, b.length - 20, pd); // ClassFormatError + } else if (nm.endsWith("SAXResult")) { + return defineClass(nm, b, 0, b.length + 20, pd); // IndexOutOfBoundsException + } else if (nm.endsWith("DOMResult")) { + return defineClass(nm + "XXX", b, 0, b.length, pd); // NoClassDefFoundError + } else if (nm.endsWith("Calendar")) { + return defineClass(nm, b, 0, b.length, pd); // SecurityException + } else if (nm.endsWith("TimeZone")) { + return defineClass(nm, b, 0, b.length, + (java.security.ProtectionDomain) null); // SecurityException + } + return null; + } + + private byte[] loadClassData(String name) { + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + try { + Class c = tcl + .loadClass("#javax.xml.transform.sax.SAXTransformerFactory"); + assertTrue("Error1", c.getProtectionDomain().equals( + Void.class.getProtectionDomain())); + } catch (ClassNotFoundException _) { + } + + // TEST CASE #2: + try { + tcl.loadClass("#javax.xml.transform.sax.SAXSource"); + fail("Error2: "); + } catch (ClassFormatError _) { + } catch (ClassNotFoundException e) { + fail("Error3: " + e.toString()); + } + + // TEST CASE #3: + try { + tcl.loadClass("#javax.xml.transform.sax.SAXResult"); + fail("Error4: "); + } catch (IndexOutOfBoundsException _) { + } catch (ClassNotFoundException e) { + fail("Error5: " + e.toString()); + } + + // TEST CASE #4: + try { + tcl.loadClass("#javax.xml.transform.dom.DOMResult"); + fail("Error6: "); + } catch (NoClassDefFoundError _) { + } catch (ClassNotFoundException e) { + fail("Error7: " + e.toString()); + } + + // TEST CASE #5: + try { + tcl.loadClass("#java.util.Calendar"); + fail("Error8: "); + } catch (SecurityException _) { + } catch (ClassNotFoundException e) { + fail("Error9: " + e.toString()); + } + + // TEST CASE #5: + try { + tcl.loadClass("#java.util.TimeZona"); + fail("Error10: "); + } catch (NullPointerException _) { + } catch (ClassNotFoundException e) { + fail("Error11: " + e.toString()); + } + } + + /** + * + */ + public void test_definePackage_Str_Str_Str_Str_Str_Str_Str_Str_URL() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + String nm = name.substring(1, name.length()); + byte[] b = loadClassData(nm); + if (nm.endsWith("AudioFileReader") + || nm.endsWith("AudioFileWriter")) { + return defineClass(b, 0, b.length); // ALL RIGHT + } + return null; + } + + private byte[] loadClassData(String name) { + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + try { + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + cl.definePackage("javax.swing.filechooser", "ZSSspecTitle", + "ZSSspecVersion", "ZSSspecVendor", "ZSSimplTitle", + "ZSSimplVersion", "ZSSimplVendor", new java.net.URL( + "http://intel.com/")); + try { + Class c1 = cl.loadClass("javax.swing.filechooser.FileFilter"); + Class c2 = cl.loadClass("javax.swing.filechooser.FileView"); + try { + c1.newInstance(); // to be initialized + c2.newInstance(); // to be initialized + } catch (Exception _) { + } + //assertTrue("Error1", c1.getPackage().equals(c2.getPackage()) + // ); + assertTrue("Error1", cl.getPackage("javax.swing.filechooser") + .getName().equals("javax.swing.filechooser")); + assertTrue("Error2 " + + cl.getPackage("javax.swing.filechooser") + .getSpecificationTitle(), cl.getPackage( + "javax.swing.filechooser").getSpecificationTitle() + .equals("ZSSspecTitle")); + assertTrue("Error3", cl.getPackage("javax.swing.filechooser") + .getSpecificationVersion().equals("ZSSspecVersion")); + assertTrue("Error4", cl.getPackage("javax.swing.filechooser") + .getSpecificationVendor().equals("ZSSspecVendor")); + assertTrue("Error5", cl.getPackage("javax.swing.filechooser") + .getImplementationTitle().equals("ZSSimplTitle")); + assertTrue("Error6", cl.getPackage("javax.swing.filechooser") + .getImplementationVersion().equals("ZSSimplVersion")); + assertTrue("Error7", cl.getPackage("javax.swing.filechooser") + .getImplementationVendor().equals("ZSSimplVendor")); + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 1"); + } + + } catch (java.net.MalformedURLException _) { + } + + // TEST CASE #2: + try { + tcl.definePackage("javax.swing.filechooser", "ZSSspecTitle", + "ZSSspecVersion", "ZSSspecVendor", "ZSSimplTitle", + "ZSSimplVersion", "ZSSimplVendor", new java.net.URL( + "http://intel.com/")); + fail("Error8"); + } catch (java.lang.IllegalArgumentException _) { + // CORRECT ! + } catch (java.net.MalformedURLException _) { + fail("Error9"); + } + + // TEST CASE #3: + try { + tcl.definePackage("javax.swing.plaf.basic", "ZSSspecTitle", + "ZSSspecVersion", "ZSSspecVendor", "ZSSimplTitle", + "ZSSimplVersion", "ZSSimplVendor", new java.net.URL( + "http://intel.com/")); + + tcl.loadClass("#javax.swing.plaf.basic.BasicBorders"); + tcl.loadClass("#javax.swing.plaf.basic.BasicArrowButton"); + assertTrue("Error10", tcl.getPackage("javax.swing.plaf.basic") + .getName().equals("javax.swing.plaf.basic")); + } catch (ClassNotFoundException _) { + } catch (java.net.MalformedURLException _) { + } + } + + /** + * + */ + public void test_findClass_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + try { + tcl.loadClass("#javax.swing.plaf.basic.BasicBorders"); + fail("Error1"); + } catch (ClassNotFoundException _) { + } catch (Throwable _) { + fail("Error2"); + } + + // TEST CASE #2: + try { + tcl.loadClass(null); + fail("Error3"); + } catch (NullPointerException _) { + } catch (Throwable _) { + fail("Error4"); + } + + // TEST CASE #3: + try { + tcl.loadClass("java.lang.Object"); + } catch (ClassNotFoundException _) { + } catch (Throwable e) { + fail("Error6 " + e.toString()); + } + } + + /** + * + */ + public void test_findLibrary_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + + // TEST CASE #1: + if (vendor.equals("Intel DRL")) { + tcl.findLibrary(System.mapLibraryName("java")); + } + + // TEST CASE #2: + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + if (vendor.equals("Intel DRL")) { + cl.findLibrary(System.mapLibraryName("lang")); + } + + // TEST CASE #3: + tcl.findLibrary(null); + } + + /** + * + */ + public void test_findLoadedClass_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + String nm = name.substring(1, name.length()); + if (nm.endsWith("JPEGImageReadParamXXX")) { + byte[] b = loadClassData("j" + + (nm.replaceAll("JPEGImageReadParamXXX", + "JPEGImageReadParam"))); + return defineClass(b, 0, b.length); // ALL RIGHT + } + byte[] b = loadClassData(nm); + if (nm.endsWith("IIOImage")) { + return defineClass(b, 0, b.length); // ALL RIGHT + } + return null; + } + + private byte[] loadClassData(String name) { + String nm = name.replace('.', '/'); + java.io.InputStream is = this.getClass().getResourceAsStream( + "/" + nm + ".class"); + try { + int len = is.available(); + byte ab[] = new byte[len]; + is.read(ab); + return ab; + } catch (java.io.IOException _) { + } + return null; + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: + try { tcl.loadClass("#org.apache.harmony.lang.generics.TemplateSet"); + assertTrue("Error1", tcl.findLoadedClass("org.apache.harmony.lang.generics.TemplateSet") + .getName().equals("org.apache.harmony.lang.generics.TemplateSet")); + //tcl.loadClass("#javax.imageio.IIOImage"); + //assertTrue("Error1", tcl.findLoadedClass("javax.imageio.IIOImage") + // .getName().equals("javax.imageio.IIOImage")); + } catch (ClassNotFoundException _) { + } catch (Throwable e) { + fail("Error2: " + e.toString()); + } + + // TEST CASE #2: + try { + assertTrue("Error1", cl.findLoadedClass(null) == null); + } catch (NullPointerException _) { + } catch (Throwable e) { + fail("Error4: " + e.toString()); + } + try { + assertTrue("Error1", tcl.findLoadedClass(null) == null); + } catch (NullPointerException _) { + } catch (Throwable e) { + fail("Error4: " + e.toString()); + } + + // TEST CASE #3: + try { + if (cl.findLoadedClass("java.lang.Object") != null) // XXX: Here we + // differ of others. Is it + // absolutely + // acceptible + // and + // correct??? + assertTrue("Error5", cl.findLoadedClass("java.lang.Object") + .getName().equals("java.lang.Object")); + } catch (Throwable e) { + fail("Error6: " + e.toString()); + } + + // TEST CASE #5: + try { + cl.findLoadedClass("void"); + } catch (Throwable e) { + fail("Error10: " + e.toString()); + } + + // // TEST CASE #8: + // try { + // //Class c = + // Class.forName("[[[Ljavax.imageio.plugins.jpeg.JPEGImageReadParam;", + // true, tcl); + // Class c = + // Class.forName("javax.imageio.plugins.jpeg.JPEGImageReadParamXXX", + // true, tcl); + // ///Class c = + // tcl.loadClass("#javax.imageio.plugins.jpeg.JPEGImageReadParam"); + // System.out.println(c); + // tcl.findLoadedClass("javax.imageio.plugins.jpeg.JPEGImageReadParam"); + // assertTrue("Error7", + // tcl.findLoadedClass("javax.imageio.plugins.jpeg.JPEGImageReadParam").getName().equals("javax.imageio.plugins.jpeg.JPEGImageReadParam")); + // ///fail("Error11"); + // } catch (Throwable e) { + // fail("Error12: " + e.toString()); + // } + + + } + + /** + * + */ + public void test_findLoadedClass_Str_2() { + // TEST CASE #4: + try { + Class c = Class.forName("java.lang.ClassLoaderTest$7LCL", true, + ClassLoader.getSystemClassLoader()); + assertTrue("Error7", ClassLoader.getSystemClassLoader() + .findLoadedClass("java.lang.ClassLoaderTest$7LCL") + .getName().equals("java.lang.ClassLoaderTest$7LCL")); + } catch (Throwable e) { + fail("Error8: " + e.toString()); + } + + // TEST CASE #6: + try { + Class c = Class.forName("[B", true, ClassLoader + .getSystemClassLoader()); + assertTrue("Error7", ClassLoader.getSystemClassLoader() + .findLoadedClass("[B") == null); // if the element type is a primitive type, then the array class has no class loader + } catch (Throwable e) { + fail("Error12: " + e.toString()); + } + + // TEST CASE #6_1: + try { + ClassLoader ld = TestResources.getLoader(); + Class c = Class.forName("[Lorg.apache.harmony.lang.generics.TemplateSet;", true, ld); + assertTrue("Error7_1", ld + .findLoadedClass("[Lorg.apache.harmony.test.TestResources;") == null); // according the deligate loading model + } catch (Throwable e) { + fail("Error12_1: " + e.toString()); + } + + // TEST CASE #6_2: + try { + try { + Class c = Class.forName("I", true, ClassLoader + .getSystemClassLoader()); // If name denotes a primitive type or void, an attempt will be made to + // locate a user-defined class in the unnamed package whose name is name. + // Therefore, this method cannot be used to obtain any of the Class + // objects representing primitive types or void. + assertTrue("Error7_2", ClassLoader.getSystemClassLoader() + .findLoadedClass("I") == null); + } catch (ClassNotFoundException e) { + //System.out.println("I1: "+e.toString()); + } + try { + Class c = Class.forName("int", true, ClassLoader + .getSystemClassLoader()); // If name denotes a primitive type or void, an attempt will be made to + // locate a user-defined class in the unnamed package whose name is name. + // Therefore, this method cannot be used to obtain any of the Class + // objects representing primitive types or void. + assertTrue("Error7_2", ClassLoader.getSystemClassLoader() + .findLoadedClass("int") == null); + } catch (ClassNotFoundException e) { + //System.out.println("I2: "+e.toString()); + } + try { + ClassLoader ld = TestResources.getLoader(); + //ClassLoader ld = ClassLoader.getSystemClassLoader(); + //System.out.println("I3: "+int.class.getName()+"|"+int.class.getClassLoader()); + Class c = ld.loadClass("int"); + assertTrue("Error7_2", ld.findLoadedClass("int") == null); + } catch (ClassNotFoundException e) { + //System.out.println("I4: "+e.toString()); + } + } catch (Throwable e) { + fail("Error12_2: " + e.toString()); + } + + // TEST CASE #7: + try { + Class c = Class.forName("[[[Ljava.lang.Object;", false, ClassLoader + .getSystemClassLoader()); + ClassLoader.getSystemClassLoader().findLoadedClass( + "[[[Ljava.lang.Object;"); + assertTrue("Error7", ClassLoader.getSystemClassLoader() + .findLoadedClass("[[[Ljava.lang.Object;") == null); + } catch (Throwable e) { + fail("Error12: " + e.toString()); + } + + try{ + // "public class bbb{} // (javac 1.5)": + byte[] clazz = {-54,-2,-70,-66,0,0,0,49,0,13,10,0,3,0,10,7,0,11,7,0,12,1,0,6,60,105,110,105,116, + 62,1,0,3,40,41,86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101, + 114,84,97,98,108,101,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0,8,98,98,98, + 46,106,97,118,97,12,0,4,0,5,1,0,3,98,98,98,1,0,16,106,97,118,97,47,108,97,110,103, + 47,79,98,106,101,99,116,0,33,0,2,0,3,0,0,0,0,0,1,0,1,0,4,0,5,0,1,0,6,0,0,0,29,0, + 1,0,1,0,0,0,5,42,-73,0,1,-79,0,0,0,1,0,7,0,0,0,6,0,1,0,0,0,1,0,1,0,8,0,0,0,2,0,9}; + FileOutputStream fos; + fos = new FileOutputStream(new File(System.getProperty("java.ext.dirs")+File.separator+"classes"+File.separator+"bbb.class")); + for (int i = 0; i < clazz.length; i++) { + fos.write((byte)clazz[i]); + } + fos.flush(); + fos.close(); + } catch (IOException e) { + System.out.println("TEST test_findLoadedClass_Str, CASE #10, DIDN'T RUN"+e.toString()); + } + + // TEST CASE #9 + try{ + ClassLoader chain = ClassLoader.getSystemClassLoader(); + while (chain.getParent()!=null) { + chain = chain.getParent(); + } + Class c = Class.forName("bbb", false, chain); // loading via the Capital ClassLoader + assertTrue(chain.findLoadedClass("bbb").getName().equals("bbb")); + } catch (ClassNotFoundException e) { + System.out.println("TEST test_findLoadedClass_Str, CASE #10, DIDN'T RUN"+e.toString()); + } catch (Exception e) { + fail("TEST test_findLoadedClass_Str, CASE #9, FAILED"+e.toString()); + } + + // TEST CASE #10 + class LCL2 extends ClassLoader { + public Class findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public LCL2() { + super(); + } + } + + LCL2 tcl2 = new LCL2(); + + try{ + Class c = Class.forName("bbb", false, tcl2); + ClassLoader chain = tcl2; + while (chain.getParent() != null) { + if (chain.findLoadedClass("bbb")!=null && chain.findLoadedClass("bbb").getName().equals("bbb")) { + //System.out.println("TEST PASSED"); + return; + } + chain = chain.getParent(); + } + assertTrue(chain.findLoadedClass("bbb")!=null && chain.findLoadedClass("bbb").getName().equals("bbb")); + } catch (ClassNotFoundException e) { + System.out.println("TEST test_findLoadedClass_Str, CASE #10, DIDN'T RUN"); + } catch (Exception e) { + fail("TEST test_findLoadedClass_Str, CASE #10, FAILED(2)"); + } + } + + /** + * + */ + public void test_findLoadedClass_Str_3() { + + class testCL extends ClassLoader { + public int res = 0; + + public testCL() { + super(); + res = 0; + } + + public Class loadClass(String nm) throws ClassNotFoundException { + if ("java.lang.ClassLoaderTest$1a3".equals(nm)) { + res += 1; + } + return super.loadClass(nm); + } + + public Class fndLoadedClass(String nm) { + return super.findLoadedClass(nm); + } + } + class a3 extends ClassLoader { + public a3() { + super(); + } + + public void main(String[] args) { + try { + new a3().test(args); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + public int test(String[] args) throws Exception { + testCL cl = new testCL(); + for (int i = 0; i < 10; i++) { + int t = (this.callClass(cl)).intValue(); + if (t != 104) { + // System.out.println("Test failed step "+i+": method result = "+t); + return 105; + } + } + assertTrue(cl.fndLoadedClass("java.lang.ClassLoaderTest$1a3") + .getName().equals("java.lang.ClassLoaderTest$1a3")); + return 104; + } + + private Integer callClass(testCL cLoader) throws Exception { + Class cls = Class.forName("java.lang.ClassLoaderTest$1a3", + true, cLoader); + Method mm = cls.getMethod("test", (Class[])null); + return (Integer) mm.invoke(this, new Object[0]); + } + + public int test() { + return 104; + } + } + new a3().main(new String[] { "" }); + } + + + /** + * + */ + public void test_findResource_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + return null; + } + + public java.net.URL findResource(String name) { + String nm = name.replace('.', '/'); + return this.getClass().getResource("/" + nm + ".class"); + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + // TEST CASE #2: + assertTrue("Error1", tcl.findResource("java.lang.Class") != null); + + // TEST CASE #2: + try { + assertTrue("Error2", ClassLoader.getSystemClassLoader() + .findResources("java.lang.Class") != null); + } catch (java.io.IOException _) { + fail("Error3"); + } + } + + /** + * + */ + public void test_findResources_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + return null; + } + + public java.util.Enumeration<URL> findResources(String name) + throws java.io.IOException { + return super.findResources(name); + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + // TEST CASE #1: + try { + assertTrue("Error1", tcl.findResources("java.lang.Class") != null); + } catch (java.io.IOException _) { + fail("Error2"); + } + + // TEST CASE #2: + try { + ClassLoader.getSystemClassLoader().findResource("java.lang.Class"); + } catch (Exception _) { + fail("Error3"); + } + } + + /** + * + */ + public void test_findSystemClass_Str() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) { + return null; + } + + public LCL() { + super(); + } + } + + LCL tcl = new LCL(); + // TEST CASE #1: + try { + assertTrue("Error1", tcl.findSystemClass("java.lang.Class") != null); + } catch (ClassNotFoundException _) { + fail("Error2"); + } + + // TEST CASE #2: + try { + ClassLoader.getSystemClassLoader().findSystemClass( + "java.lang.Class"); + } catch (ClassNotFoundException _) { + fail("Error3"); + } + + // TEST CASE #3: + try { + ClassLoader.getSystemClassLoader().getSystemClassLoader() + .getSystemClassLoader().findSystemClass("java.lang.Class"); + } catch (ClassNotFoundException _) { + fail("Error4"); + } + + // TEST CASE #4: + try { + ClassLoader.getSystemClassLoader().findSystemClass(null); + fail("Error5"); + } catch (ClassNotFoundException _) { + fail("Error6"); + } catch (NullPointerException _) { + } + } + + /** + * + */ + public void test_getPackage_Str() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: + try { + cl.getPackage(null); + fail("Error1"); + } catch (NullPointerException _) { + } + + // TEST CASE #2: + assertTrue("Error1", cl.getPackage("UNEXISTED.Unknown.Package") == null); + + // TEST CASE #3: + try { + cl.definePackage("javax", "ZSSspecTitle1", "ZSSspecVersion1", + "ZSSspecVendor1", "ZSSimplTitle1", "ZSSimplVersion1", + "ZSSimplVendor1", new java.net.URL( + "http://intel.com/")); + cl.definePackage("javax.imageio", "ZSSspecTitle2", + "ZSSspecVersion2", "ZSSspecVendor2", "ZSSimplTitle2", + "ZSSimplVersion2", "ZSSimplVendor2", new java.net.URL( + "http://intel.com/")); + try { + Class c1 = cl.loadClass("javax.imageio.ImageIO"); + try { + c1.newInstance(); // to be initialized + } catch (Exception _) { + } + assertTrue("Error1", cl.getPackage("javax.imageio").getName() + .equals("javax.imageio")); + assertTrue("Error2", cl.getPackage("javax.imageio") + .getSpecificationTitle().equals("ZSSspecTitle2")); + assertTrue("Error3", cl.getPackage("javax.imageio") + .getSpecificationVersion().equals("ZSSspecVersion2")); + assertTrue("Error4", cl.getPackage("javax.imageio") + .getSpecificationVendor().equals("ZSSspecVendor2")); + assertTrue("Error5", cl.getPackage("javax.imageio") + .getImplementationTitle().equals("ZSSimplTitle2")); + assertTrue("Error6", cl.getPackage("javax.imageio") + .getImplementationVersion().equals("ZSSimplVersion2")); + assertTrue("Error7", cl.getPackage("javax.imageio") + .getImplementationVendor().equals("ZSSimplVendor2")); + assertTrue("Error8", cl.getPackage("javax").getName().equals( + "javax")); + assertTrue("Error9", cl.getPackage("javax") + .getSpecificationTitle().equals("ZSSspecTitle1")); + assertTrue("Error10", cl.getPackage("javax") + .getSpecificationVersion().equals("ZSSspecVersion1")); + assertTrue("Error11", cl.getPackage("javax") + .getSpecificationVendor().equals("ZSSspecVendor1")); + assertTrue("Error12", cl.getPackage("javax") + .getImplementationTitle().equals("ZSSimplTitle1")); + assertTrue("Error13", cl.getPackage("javax") + .getImplementationVersion().equals("ZSSimplVersion1")); + assertTrue("Error14", cl.getPackage("javax") + .getImplementationVendor().equals("ZSSimplVendor1")); + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 1"); + } + } catch (java.net.MalformedURLException _) { + } + } + + /** + * + */ + public void test_getPackages_V() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public LCL() { + super(); + } + + public LCL(ClassLoader cl) { + super(cl); + } + } + ClassLoader cl = ClassLoader.getSystemClassLoader(); + int loadersNumber = 11; //20; + int pkgsPerLoader = 21; //30; + ClassLoader acl[] = new ClassLoader[loadersNumber]; + ClassLoader prevcl = new LCL(cl); + + // TEST CASE #1: + for (int i = 0; i < loadersNumber; i++) { + acl[i] = new LCL(prevcl); + prevcl = acl[i]; + } + for (int i = 0; i < loadersNumber; i++) { + for (int j = 0; j < pkgsPerLoader; j++) { + try { + String curLable = Integer.toString(i) + "_" + + Integer.toString(j); + acl[i].definePackage(curLable, "ZSSspecTitle" + curLable, + "ZSSspecVersion" + curLable, "ZSSspecVendor" + + curLable, "ZSSimplTitle" + curLable, + "ZSSimplVersion" + curLable, "ZSSimplVendor" + + curLable, new java.net.URL( + "http://intel.com/")); + } catch (java.net.MalformedURLException _) { + } + } + } + int res = 0; + int prevLen = 0; + int tmp = 0; + for (int i = 0; i < loadersNumber; i++) { + assertTrue("Error1", (tmp = acl[i].getPackages().length) > prevLen); + prevLen = tmp; + for (int j = 0; j < acl[i].getPackages().length; j++) { + if (acl[i].getPackages()[j].getName().equals( + Integer.toString(i) + "_" + + Integer.toString(pkgsPerLoader - 1))) { + res++; + assertTrue( + "Error2", + acl[i].getPackages()[j] + .getSpecificationTitle() + .equals( + "ZSSspecTitle" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + assertTrue( + "Error3", + acl[i].getPackages()[j] + .getSpecificationVersion() + .equals( + "ZSSspecVersion" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + assertTrue( + "Error4", + acl[i].getPackages()[j] + .getSpecificationVendor() + .equals( + "ZSSspecVendor" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + assertTrue( + "Error5", + acl[i].getPackages()[j] + .getImplementationTitle() + .equals( + "ZSSimplTitle" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + assertTrue( + "Error6", + acl[i].getPackages()[j] + .getImplementationVersion() + .equals( + "ZSSimplVersion" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + assertTrue( + "Error7", + acl[i].getPackages()[j] + .getImplementationVendor() + .equals( + "ZSSimplVendor" + + Integer.toString(i) + + "_" + + Integer + .toString(pkgsPerLoader - 1))); + break; + } + } + } + assertTrue("Error8", res == loadersNumber); + } + + /** + * + */ + public void test_getParent_V() { + class LCL extends ClassLoader { + // only for special case + + public Class<?> findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + public LCL() { + super(); + } + + public LCL(ClassLoader cl) { + super(cl); + } + } + ClassLoader cl = ClassLoader.getSystemClassLoader(); + int loadersNumber = 1000; + ClassLoader acl[] = new ClassLoader[loadersNumber]; + ClassLoader prevcl = cl; + + // TEST CASE #1: + for (int i = 0; i < loadersNumber; i++) { + acl[i] = new LCL(prevcl); + prevcl = acl[i]; + } + for (int i = loadersNumber - 1; i > -1; i--) { + if (i != 0) { + assertTrue("Error1", acl[i].getParent().equals(acl[i - 1])); + } else { + assertTrue("Error2", acl[i].getParent().equals(cl)); + } + } + } + + /** + * + */ + public void test_getResource_Str() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: +// Commented because of the drlvm issue. +// try { +// cl.getResource(null); +// fail("Error1: NullPointerException is not thrown for null argument"); +// } catch (NullPointerException _) { +// } + + // TEST CASE #2: + assertTrue("Error1: unexpected:" + + cl.getResource("java/lang/Class.class").toString(), cl + .getResource("java/lang/Class.class").toString().indexOf( + "java/lang/Class.class") != -1); + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + assertTrue("Error1", cl.getResource(s) + .toString().indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + assertTrue("Error1", cl.getResource(afn[j]) + .toString().indexOf(afn[j]) != -1); + return; + } + } + } + } + } + } + + /** + * + */ + public void test_getResourceAsStream_Str() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: +// Commented because of the drlvm issue. +// try { +// cl.getResourceAsStream(null); +// fail("Error1: NullPointerException is not thrown for null argument"); +// } catch (NullPointerException _) { +// } + + // TEST CASE #2: + byte magic[] = new byte[4]; + try { + cl.getResourceAsStream("java/lang/Class.class").read(magic); + assertTrue("Error1", new String(magic).equals(new String( + new byte[] { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, + (byte) 0xBE }))); + } catch (java.io.IOException _) { + } + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + magic = new byte[4]; + try { + cl.getResourceAsStream(s).read(magic); + assertTrue( + "Error1", + new String(magic) + .equals(new String( + new byte[] { + (byte) 0xCA, + (byte) 0xFE, + (byte) 0xBA, + (byte) 0xBE }))); + } catch (java.io.IOException _) { + } + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + try { + assertTrue("Error1", cl.getResourceAsStream( + afn[j]).available() >= 0); + } catch (java.io.IOException _) { + } + return; + } + } + } + } + } + } + + /** + * + */ + public void test_getResources_Str() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: + try { + cl.getResources(null); + assertTrue("Error1", + cl.getResources(null).hasMoreElements() == false); + } catch (NullPointerException _) { + } catch (java.io.IOException _) { + } + + // TEST CASE #2: + try { + assertTrue("Error2: unexpected:" + + cl.getResources("java/lang/ClassLoader.class") + .nextElement(), ((java.net.URL) cl.getResources( + "java/lang/ClassLoader.class").nextElement()).toString() + .indexOf("java/lang/ClassLoader.class") != -1); + //java.util.Enumeration e = + // cl.getResources("java/lang/ClassLoader.class"); + //assertTrue("Error2: unexpected:" + // + cl.getResources("/meta-inf/Manifest.mf").nextElement(), + // ((java.net.URL)cl.getResources("/meta-inf/Manifest.mf").nextElement()).toString().indexOf( + // "/meta-inf/Manifest.mf") != -1); + //e = cl.getResources("/meta-inf/Manifest.mf"); + //System.out.println(e.nextElement()); + //System.out.println(e.nextElement()); + //System.out.println(e.nextElement()); + } catch (java.io.IOException _) { + } + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + assertTrue("Error3", ((java.net.URL) cl + .getResources(s).nextElement()) + .toString().indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + try { + assertTrue("Error4", ((java.net.URL) cl + .getResources(afn[j]).nextElement()) + .toString().indexOf(afn[j]) != -1); + return; + } catch (java.io.IOException _) { + } + } + } + } + } + } + } + + /** + * + */ + public void test_getSystemClassLoader_V() { + // TEST CASE #1: + try { + String jscl = System.getProperty("java.system.class.loader"); + if (jscl != null && jscl != "") { + assertTrue("Error1", ClassLoader.getSystemClassLoader() + .getClass().getName().equals(jscl)); + } + java.util.Properties pl = System.getProperties(); + pl.setProperty("java.system.class.loader", + "java.lang.ClassLoaderTest$TestClassLoader"); + System.setProperties(pl); + jscl = System.getProperty("java.system.class.loader"); + if (jscl != null && jscl != "") { + assertTrue("Error1 " + + ClassLoader.getSystemClassLoader().getClass() + .getName(), !ClassLoader.getSystemClassLoader() + .getClass().getName().equals(jscl)); + } + } catch (NullPointerException _) { + } + } + + /** + * + */ + public void test_getSystemResource_Str() { + ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: +// Commented because of the drlvm issue. +// try { +// ClassLoader.getSystemResource(null); +// fail("Error1: NullPointerException is not thrown for null argument"); +// } catch (NullPointerException _) { +// } + + // TEST CASE #2: + assertTrue("Error1: unexpected:" + + ClassLoader.getSystemResource("java/lang/Void.class") + .toString(), ClassLoader.getSystemResource( + "java/lang/Void.class").toString().indexOf( + "java/lang/Void.class") != -1); + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + assertTrue("Error1", ClassLoader + .getSystemResource(s).toString() + .indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + assertTrue("Error1", ClassLoader.getSystemResource( + afn[j]).toString().indexOf(afn[j]) != -1); + return; + } + } + } + } + } + } + + /** + * + */ + public void test_getSystemResourceAsStream_Str() { + ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: +// Commented because of the drlvm issue. +// try { +// ClassLoader.getSystemResourceAsStream(null); +// fail("Error1: NullPointerException is not thrown for null argument"); +// } catch (NullPointerException _) { +// } + + // TEST CASE #2: + byte magic[] = new byte[4]; + try { + ClassLoader.getSystemResourceAsStream( + "java/lang/reflect/Method.class").read(magic); + assertTrue("Error1", new String(magic).equals(new String( + new byte[] { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, + (byte) 0xBE }))); + } catch (java.io.IOException _) { + } + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + magic = new byte[4]; + try { + ClassLoader.getSystemResourceAsStream(s) + .read(magic); + assertTrue( + "Error1", + new String(magic) + .equals(new String( + new byte[] { + (byte) 0xCA, + (byte) 0xFE, + (byte) 0xBA, + (byte) 0xBE }))); + } catch (java.io.IOException _) { + } + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + try { + assertTrue("Error1", ClassLoader + .getSystemResourceAsStream(afn[j]) + .available() >= 0); + } catch (java.io.IOException _) { + } + return; + } + } + } + } + } + } + + /** + * + */ + public void test_getSystemResources_Str() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + // TEST CASE #1: + try { + ClassLoader.getSystemResources(null); + assertTrue("Error1", + cl.getResources(null).hasMoreElements() == false); + } catch (NullPointerException _) { + } catch (java.io.IOException _) { + } + + // TEST CASE #2: + try { + assertTrue( + "Error2: unexpected:" + + ClassLoader.getSystemResources( + "java/lang/ClassLoader.class") + .nextElement(), + ((java.net.URL) ClassLoader.getSystemResources( + "java/lang/ClassLoader.class").nextElement()) + .toString().indexOf("java/lang/ClassLoader.class") != -1); + } catch (java.io.IOException _) { + } + + // TEST CASE #3: + if (vendor.equals("Intel DRL")) { + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + assertTrue("Error3", + ((java.net.URL) ClassLoader + .getSystemResources(s) + .nextElement()).toString() + .indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + try { + assertTrue("Error4", + ((java.net.URL) ClassLoader + .getSystemResources(afn[j]) + .nextElement()).toString() + .indexOf(afn[j]) != -1); + return; + } catch (java.io.IOException _) { + } + } + } + } + } + } + } + + /** + * + */ + public void test_loadClass_Str() { + class LC1 { + class LC2 { + class LC3 { + class LC4 { + class LC5 { + class LC6 { + class LC7 { + class LC8 { + class LC9 { + class LC10 { + class LC11 { + class LC12 { + class LC13 { + class LC14 { + class LC15 { + class LC16 { + class LC17 { + class LC18 { + class LC19 { + class LC20 + extends + LC19 { + class LC21 { + public LC21() { + System.out + .println("1 LC21"); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + //TestClassLoader tcl = new TestClassLoader(); + ClassLoader tcl = ClassLoader.getSystemClassLoader(); + try { + Class c = ((ClassLoader) tcl) + .loadClass("java.lang.ClassLoaderTest$1LC1$LC2$LC3$LC4$LC5$LC6$LC7$LC8$LC9$LC10$LC11$LC12$LC13$LC14$LC15$LC16$LC17$LC18$LC19$LC20$LC21"); + c.newInstance(); + fail("Error1 "); + } catch (ClassNotFoundException _) { + fail("Error2"); + } catch (InstantiationException e) { + } catch (Exception e) { + fail("Error3"); + } + } + + /** + * + */ + public void test_loadClass_Str_Z() { + class LC1 { + class LC2 { + class LC3 { + class LC4 { + class LC5 { + class LC6 { + class LC7 { + class LC8 { + class LC9 { + class LC10 { + class LC11 { + class LC12 { + class LC13 { + class LC14 { + class LC15 { + class LC16 { + class LC17 { + class LC18 { + class LC19 { + class LC20 + extends + LC19 { + class LC21 { + public LC21() { + System.out + .println("2 LC21"); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + + public LC1() { + System.out.println("1"); + } + } + String longName = "java.lang.ClassLoaderTest$2LC1$LC2$LC3$LC4$LC5$LC6$LC7$LC8$LC9$LC10$LC11$LC12$LC13$LC14$LC15$LC16$LC17$LC18$LC19$LC20$LC21"; + TestClassLoader tcl = new TestClassLoader(); + ClassLoader cl = ClassLoader.getSystemClassLoader(); + String pices[] = longName.split("\\$"); + String curClNm = pices[0] + "$" + pices[1]; + Class c; + for (int i = 2; i < pices.length; i++) { + curClNm = curClNm + "$" + pices[i]; + try { + if (i % 2 == 0) { + c = ((ClassLoader) tcl).loadClass(curClNm, true); + } else { + c = cl.loadClass(curClNm, true); + } + try { + c.newInstance(); + } catch (Exception e) { + } + } catch (ClassNotFoundException _) { + fail("Error1: " + curClNm); + } catch (Exception e) { + fail("Error2 " + e.toString()); + } + } + } + + /** + * + */ + Class tmpCl; + + int tmpI; + + public void test_loadClass_Str_Z_1() { + class LC1 { + class LC2 { + class LC3 { + class LC4 { + class LC5 { + class LC6 { + class LC7 { + class LC8 { + class LC9 { + class LC10 { + class LC11 { + class LC12 { + class LC13 { + class LC14 { + class LC15 { + class LC16 { + class LC17 { + class LC18 { + class LC19 { + class LC20 + extends + LC19 { + class LC21 { + public LC21() { + System.out + .println("3 LC21"); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + + public LC2() { + System.out.println("1"); + } + } + + public LC1() { + System.out.println("1"); + } + } + class ConcurentLoader extends Thread { + public String clN; + + public ClassLoader l; + + public void run() { + try { + if (clN.length() == tmpI) { + tmpCl = ((ClassLoader) l).loadClass(clN, false); + } else { + ((ClassLoader) l).loadClass(clN, false); + } + } catch (ClassNotFoundException _) { + fail("Error1"); + } + } + } + String longName = "java.lang.ClassLoaderTest$3LC1$LC2$LC3$LC4$LC5$LC6$LC7$LC8$LC9$LC10$LC11$LC12$LC13$LC14$LC15$LC16$LC17$LC18$LC19$LC20$LC21"; + tmpI = longName.length(); + TestClassLoader tcl = new TestClassLoader(); + ClassLoader cl = ClassLoader.getSystemClassLoader(); + String pices[] = longName.split("\\$"); + String curClNm = pices[0] + "$" + pices[1]; + ConcurentLoader[] thr = new ConcurentLoader[pices.length]; + for (int i = 2; i < pices.length; i++) { + curClNm = curClNm + "$" + pices[i]; + try { + thr[i] = new ConcurentLoader(); + thr[i].clN = curClNm; + if (i % 2 == 0) { + thr[i].l = ((ClassLoader) tcl); + } else { + thr[i].l = ((ClassLoader) cl); + } + } catch (Exception e) { + fail("Error2 " + e.toString()); + } + } + for (int i = 2; i < pices.length; i++) { + thr[i].start(); + } + for (int i = 2; i < pices.length; i++) { + try { + thr[i].join(); + } catch (InterruptedException e) { + fail("Error2 "); + } + } + try { + tmpCl.newInstance(); + } catch (InstantiationException e) { + //System.out.println("Warning: "+e.toString()); + //try { + // Class.forName(longName).newInstance(); + //} catch (Exception ee) { + // System.out.println("Warning: "+ee.toString()); + // try { + // Class.forName("java.lang.ClassLoaderTest$3$LC1").newInstance(); + // } catch (Exception eee) { + // System.out.println("Warning: "+eee.toString()); + // } + //} + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_resolveClass_Cla() { + + // TEST CASE #1: + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).resolveClass(int.class); + + // TEST CASE #2: + try { + ClassLoader.getSystemClassLoader().resolveClass(null); + } catch (NullPointerException _) { + } + + // TEST CASE #2: + try { + Number i[][][] = new Number[1][2][3]; + ClassLoader.getSystemClassLoader().resolveClass(i.getClass()); + } catch (NullPointerException _) { + } + } + + /** + * + */ + public void test_setClassAssertionStatus_Str_Z() { + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).setClassAssertionStatus(";^)", true); + + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + cl.setClassAssertionStatus("javax.xml.transform.sax.SAXSource", true); + try { + Class c = cl.loadClass("javax.xml.transform.sax.SAXSource"); + try { + c.newInstance(); // to be initialized + } catch (Exception _) { + } + assertTrue("Error1:", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); // "this method is not + // guaranteed to return the + // actual assertion status" + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 1"); + } + + ((ClassLoader) tcl).setClassAssertionStatus( + "javax.xml.transform.sax.SAXTransformerFactory", true); + try { + Class c = tcl + .loadClass("#javax.xml.transform.sax.SAXTransformerFactory"); + assertTrue("Error2", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); + } catch (ClassNotFoundException _) { + } + ((ClassLoader) tcl).setClassAssertionStatus( + "javax.xml.transform.sax.SAXTransformerFactory", false); + try { + Class c = tcl + .loadClass("javax.xml.transform.sax.SAXTransformerFactory"); + assertTrue("Error3", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException"); + } + ((ClassLoader) tcl).setClassAssertionStatus( + "javax.xml.transform.sax.SAXTransformerFactory", true); + ((ClassLoader) tcl).setClassAssertionStatus( + "javax.xml.transform.sax.SAXTransformerFactory", false); + + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + cl.setClassAssertionStatus( + "[Ljavax.xml.transform.sax.SAXTransformerFactory;", true); + try { + //Class c = + // Class.forName("[Ljavax.xml.transform.sax.SAXTransformerFactory;", + // false, cl); + // //try { + // // Object o = c.newInstance(); // to be initialized + // //} catch(Exception e) {System.out.println("Exception 2:"+e);} + //assertTrue("Error4:", c.desiredAssertionStatus() == + // c.desiredAssertionStatus() ); // "this method is not guaranteed + // to return the actual assertion status" + Class c = Class.forName( + "[Ljavax.xml.transform.sax.SAXTransformerFactory;", true, + cl); + assertTrue("Error5:", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); // "this method is not + // guaranteed to return the + // actual assertion status" + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 2"); + } + } + + /** + * + */ + public void test_setDefaultAssertionStatus_Z() { + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).setDefaultAssertionStatus(true); + ((ClassLoader) tcl).setDefaultAssertionStatus(false); + ((ClassLoader) tcl).setDefaultAssertionStatus(true); + ((ClassLoader) tcl).setDefaultAssertionStatus(false); + } + + /** + * + */ + public void test_setPackageAssertionStatus_Str_Z() { + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).setPackageAssertionStatus(":^(", true); + + ClassLoader cl = Class.class.getClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + cl.setPackageAssertionStatus("javax.xml.transform.stream", true); + try { + Class c = cl.loadClass("javax.xml.transform.stream.StreamSource"); + try { + c.newInstance(); // to be initialized + } catch (Exception _) { + //System.out.println("(test_setPackageAssertionStatus_Str_Z)Exception + // 1"); + } + assertTrue("Error1:", c.desiredAssertionStatus() == c + .desiredAssertionStatus()); // "this method is not + // guaranteed to return the + // actual assertion status" + } catch (ClassNotFoundException _) { + System.out.println("ClassNotFoundException 1"); + } + + ((ClassLoader) tcl).setPackageAssertionStatus( + "javax.xml.transform.sax", true); + ((ClassLoader) tcl).setPackageAssertionStatus( + "javax.xml.transform.sax", false); + ((ClassLoader) tcl).setPackageAssertionStatus("", true); + ((ClassLoader) tcl).setPackageAssertionStatus("", false); + } + + /** + * + */ + public void test_setSigners_Cla_ObjArr() { + + // TEST CASE #1: + TestClassLoader tcl = new TestClassLoader(); + ((ClassLoader) tcl).setSigners(int.class, (Object[]) null); + + // TEST CASE #2: + ((ClassLoader) tcl).setSigners(int.class, new Object[] { null }); + + // TEST CASE #3: + try { + ((ClassLoader) tcl).setSigners(null, new Object[] { "" }); + fail("Error1"); + } catch (NullPointerException _) { + } + + // TEST CASE #4: + ClassLoader.getSystemClassLoader().setSigners(int.class, + (Object[]) null); + + // TEST CASE #5: + ClassLoader.getSystemClassLoader().setSigners(int.class, + new Object[] { null }); + + // TEST CASE #6: + try { + ClassLoader.getSystemClassLoader().setSigners(null, + new Object[] { "" }); + fail("Error1"); + } catch (NullPointerException _) { + } + + // TEST CASE #7: + ClassLoader.getSystemClassLoader().setSigners(int.class, + (Object[]) null); + + // TEST CASE #8: + Number i[][][] = new Number[1][2][3]; + ClassLoader.getSystemClassLoader().setSigners(i.getClass(), + (Object[]) null); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassLoaderTestLoad.java vm/tests/kernel/java/lang/ClassLoaderTestLoad.java new file mode 100644 index 0000000..2bd8247 --- /dev/null +++ vm/tests/kernel/java/lang/ClassLoaderTestLoad.java @@ -0,0 +1,37 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +public class ClassLoaderTestLoad extends TestCase { + + public void test1() { + try { + for (int i = 0; i < 100; i++) { + ClassLoader.getSystemClassLoader() + .loadClass("java.lang.Object", true); + } + } catch (ClassNotFoundException e) { + fail(e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestDesiredAssertionStatus.java vm/tests/kernel/java/lang/ClassTestDesiredAssertionStatus.java new file mode 100644 index 0000000..bb3ad42 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestDesiredAssertionStatus.java @@ -0,0 +1,41 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: desiredAssertionStatus + */ +public class ClassTestDesiredAssertionStatus extends TestCase { + + /** + * default assertion status must be false. + */ + public void test1() { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + scl.setDefaultAssertionStatus(true); + scl.clearAssertionStatus(); + assertFalse(ClassTestDesiredAssertionStatus.class + .desiredAssertionStatus()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestForName.java vm/tests/kernel/java/lang/ClassTestForName.java new file mode 100644 index 0000000..c114d71 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestForName.java @@ -0,0 +1,152 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: forName + */ +@SuppressWarnings(value={"all"}) public class ClassTestForName extends TestCase { + + /** + * This test case checks two cases. First, a class must be sucessfully + * loaded by bootstrup class loader. Second, this class instance must be the + * same as previously loaded. + */ + public void test1() { + try { + final String name = "java.lang.Object"; + Class c = Class.forName(name); + assertSame("Objects differ", Object.class, c); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * This test case checks two cases. First, a class must be sucessfully + * loaded by user-defined class loader. Second, this class instance must be + * the same as previously loaded. + */ + public void test2() { + try { + final String name = ClassTestForName.class.getName(); + Class c = Class.forName(name); + assertSame("Objects differ", ClassTestForName.class, c); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * This test case checks two cases. First, an array class must be + * sucessfully loaded by bootstrup class loader. Second, this class instance + * must be the same as previously loaded. + */ + public void test3() { + try { + Object[] array = new Object[0]; + final String name = array.getClass().getName(); + Class c = Class.forName(name); + assertSame("Objects differ", array.getClass(), c); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * This test case checks whether a class loaded by forName() method is the + * same as a class loaded by loadClass() method through the same class + * loader. + */ + public void test4() { + try { + final String name = getClass().getName() + "$InnerHelper"; + ClassLoader cLoader = ClassLoader.getSystemClassLoader(); + Class c1 = Class.forName(name, true, cLoader); + Class c2 = cLoader.loadClass(name); + assertSame("Objects differ", c1, c2); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Simple reference type and array type must be loaded by the same class + * loader. + */ + public void test5() { + try { + final String name = getClass().getName() + "$InnerHelper"; + Class c1 = Class.forName(name); + Class c2 = Class.forName("[[L" + name + ";"); + assertSame("Objects differ", c1.getClassLoader(), c2.getClassLoader()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * class names must be delimited by dotes not by any over delimiter. + */ + public void test6() { + try { + final String name = "java/lang/Object"; + Class.forName(name); + } catch (ClassNotFoundException e) { + return; + } + fail("ClassNotFoundException exception expected"); + } + + /** + * primitive types can not be loaded by forName() method. + */ + public void test7() { + try { + final String name = Integer.TYPE.getName(); + Class.forName(name); + } catch (ClassNotFoundException e) { + return; + } + fail("ClassNotFoundException exception expected"); + } + + /** + * primitive types can not be loaded by forName() method. + */ + public void test8() { + try { + Class c = new int[0].getClass(); + assertSame("Objects differ", c, Class.forName(c.getName())); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Helper class. + */ + private static class InnerHelper { + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetClassLoader.java vm/tests/kernel/java/lang/ClassTestGetClassLoader.java new file mode 100644 index 0000000..cd48b85 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetClassLoader.java @@ -0,0 +1,46 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getClassLoader + */ +public class ClassTestGetClassLoader extends TestCase { + + /** + * Classes from API class library must be loaded by bootstrap class loader. + * + */ + public void test1() { + assertNull(Class.class.getClassLoader()); + } + + /** + * null must be returned for the primitive types. + * + */ + public void test2() { + assertNull(Integer.TYPE.getClassLoader()); + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetClasses.java vm/tests/kernel/java/lang/ClassTestGetClasses.java new file mode 100644 index 0000000..9c48c77 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetClasses.java @@ -0,0 +1,65 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * tested class: java.lang.Class + * tested method: GetClasses + * + * @author Evgueni V. Brevnov + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/** + * @tested class: java.lang.Class + * @tested method: getClasses + */ +public class ClassTestGetClasses extends TestCase { + + /** + * java.lang.Class class does not declare any public inner class. + * + */ + public void test1() { + Class[] classes = Class.class.getClasses(); + assertNotNull("Unexpected null", classes); + assertEquals("array length:", 0, classes.length); + } + /** + * Only public inner class must be returned. + * + */ + public void test2() { + Class[] classes = ClassTestGetClasses.class.getClasses(); + assertNotNull("Unexpected null", classes); + assertEquals("There must be one class in the list", 1, classes.length); + assertSame("Objects differ", Helper1.class, classes[0]); + } + + public class Helper1 { + public class Inner { + } + } + + protected class Helper2 { + } + + class Helper3 { + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetComponentType.java vm/tests/kernel/java/lang/ClassTestGetComponentType.java new file mode 100644 index 0000000..53afec8 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetComponentType.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getComponentType + */ +public class ClassTestGetComponentType extends TestCase { + + /** + * if class is not an array than null value must be returned + * + */ + public void test1() { + assertNull(Class.class.getComponentType()); + } + + /** + * checks component type for array of the primitive types + * + */ + public void test2() { + Class c = new int[0].getClass(); + assertSame(Integer.TYPE, c.getComponentType()); + } + + /** + * checks component type for array of the reference types + * + */ + public void test3() { + Class c = new Object[0].getClass(); + assertSame(Object.class, c.getComponentType()); + } + + /** + * the component of multidimensional array is an array which has one + * dimensional less. + * + */ + public void test4() { + try { + Class c = new int[0][0].getClass(); + assertSame(Class.forName("[I"), c.getComponentType()); + } catch (Exception e) { + fail(e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetConstructor.java vm/tests/kernel/java/lang/ClassTestGetConstructor.java new file mode 100644 index 0000000..9d5e51a --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetConstructor.java @@ -0,0 +1,155 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getConstructor + */ +public class ClassTestGetConstructor extends TestCase { + + /** + * The java.lang.Class class has no public constructotrs. + * NoSuchMethodException exception must be thrown. + * + */ + public void test1() { + try { + Class.class.getConstructor(new Class [] {null}); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * Public constructor which takes an integer parameter must be reflected. + * + */ + public void test2() { + try { + Constructor c = Integer.class + .getConstructor(new Class[] {Integer.TYPE}); + assertNotNull("Unexpected null", c); + assertSame("Objects differ", Integer.TYPE, c.getParameterTypes()[0]); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Public constructor which takes a parameter of the java.lang.String type + * must be reflected. + * + */ + public void test3() { + try { + Constructor c = Integer.class + .getConstructor(new Class[] {String.class}); + assertNotNull("Unexpected null", c); + assertSame("Objects differ", String.class, c.getParameterTypes()[0]); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Verify parametrized type + */ + public void test3_java5() { + try { + Constructor<Integer> c = Integer.class + .getConstructor(new Class[] {String.class}); + assertNotNull("Unexpected null", c); + assertSame("Objects differ", String.class, c.getParameterTypes()[0]); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Default constructor which takes no parameters must be returned. + * + */ + public void test4() { + try { + Constructor c = getClass().getConstructor(new Class[0]); + assertNotNull("Unexpected null", c); + assertEquals("array length:", 0, c.getParameterTypes().length); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Default constructor which takes no parameters must be returned. + * + */ + public void test5() { + try { + Constructor c = Inner.class.getConstructor(new Class[0]); + assertNotNull("Unexpected null", c); + assertEquals("array length:", 0, c.getParameterTypes().length); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Public constructors of the super class must not be returned. + * + */ + public void test6() { + try { + Inner.class.getConstructor(new Class[] {String.class}); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * Only public constructors must be returned. + * + */ + public void test7() { + try { + Inner2.class.getConstructor(new Class[] {null}); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + public static class Inner extends Throwable { + private static final long serialVersionUID = 0L; + } + + private static class Inner2 { + + Inner2() { + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetConstructors.java vm/tests/kernel/java/lang/ClassTestGetConstructors.java new file mode 100644 index 0000000..ea9e94f --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetConstructors.java @@ -0,0 +1,108 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getConstructors + */ +public class ClassTestGetConstructors extends TestCase { + + /** + * The java.lang.Class class has no public constructotrs. + */ + public void test1() { + Constructor[] cs = Class.class.getConstructors(); + assertNotNull("Unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * The primitive types don't declare public constructors. + */ + public void test2() { + Constructor[] cs = Integer.TYPE.getConstructors(); + assertNotNull("Unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * The arrays don't declare public constructors. + */ + public void test3() { + Constructor[] cs = new int[0].getClass().getConstructors(); + assertNotNull("Unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * The java.lang.Integer class must have two public constructors. One takes + * integer parameter another takes parameter of the java.lang.String type. + */ + public void test4() { + Constructor[] cs = Integer.class.getConstructors(); + assertEquals("Assert 0: array length:", 2, cs.length); + Class[] args = cs[0].getParameterTypes(); + assertEquals("Assert 1: array length:", 1, args.length); + if (Integer.TYPE == args[0]) { + args = cs[1].getParameterTypes(); + assertEquals("Assert 2: array length:", 1, args.length); + assertSame("Assert 3: Objects differ:", String.class, args[0]); + } else { + assertSame("Assert 4: Objects differ:", String.class, args[0]); + args = cs[1].getParameterTypes(); + assertEquals("Assert 5: array length:", 1, args.length); + assertSame("Assert 6: Objects differ:", Integer.TYPE, args[0]); + } + } + + /** + * The getConstructors() method must not return public constructors of the + * super class. Default constructor which takes no parameters must be + * returned. + */ + public void test5() { + Constructor[] cs = getClass().getConstructors(); + assertNotNull("Unexpected null", cs); + assertEquals("Assert 0: array length:", 1, cs.length); + assertEquals("Assert 1: array length:", 0, cs[0].getParameterTypes().length); + } + + /** + * The getConstructors() method must not return public constructors of the + * super class. Default constructor which takes no parameters must be + * returned. + */ + public void test6() { + Constructor[] cs = Inner.class.getConstructors(); + assertNotNull("Unexpected null", cs); + assertEquals("Assert 0: array length:", 1, cs.length); + assertEquals("Assert 1: array length:", 0, cs[0].getParameterTypes().length); + } + + public static class Inner extends Throwable { + private static final long serialVersionUID = 0L; + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredClasses.java vm/tests/kernel/java/lang/ClassTestGetDeclaredClasses.java new file mode 100644 index 0000000..32db815 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredClasses.java @@ -0,0 +1,98 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.util.Arrays; +import java.util.HashSet; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredClasses + */ +public class ClassTestGetDeclaredClasses extends TestCase { + + /** + * The getDeclaredClasses() method must return all inner classes and + * interfaces including protected, package private and private members. + * + */ + public void test1() { + Class[] cs = ClassTestGetDeclaredClasses.class.getDeclaredClasses(); + HashSet<Class> set = new HashSet<Class>(Arrays.asList(cs)); + assertTrue("Helper1 is not in the list", set.contains(Helper1.class)); + assertTrue("Helper2 is not in the list", set.contains(Helper2.class)); + assertTrue("Helper3 is not in the list", set.contains(Helper3.class)); + assertTrue("Helper4 is not in the list", set.contains(Helper4.class)); + assertFalse("Helper1.Inner1 is not in the list", + set.contains(Helper1.Inner1.class)); + } + + /** + * The members declared in the super class must not be reflected by + * getDeclaredClasses() method. + * + */ + public void test2() { + Class[] cs = Helper3.class.getDeclaredClasses(); + assertNotNull("List of classes should not be null", cs); + assertEquals("There should be one class in the list", 1, cs.length); + assertSame("Incorrect class returned", Helper3.Inner2.class, cs[0]); + } + + /** + * An empty array must be returned for the classes that represent + * primitive types. + * + */ + public void test3() { + Class[] cs = Void.TYPE.getDeclaredClasses(); + assertNotNull("Array should not be null"); + assertEquals("Array must be empty", 0, cs.length); + } + + /** + * An empty array must be returned for classes that represent arrays. + * + */ + public void test4() { + Class[] cs = new Object[0].getClass().getDeclaredClasses(); + assertNotNull("Array should not be null", cs); + assertEquals("Array must be empty", 0, cs.length); + } + + public class Helper1 { + class Inner1 { + } + } + + protected interface Helper2 { + } + + class Helper3 extends Helper1 { + class Inner2 { + } + } + + private class Helper4 { + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructor.java vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructor.java new file mode 100644 index 0000000..ea8c742 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructor.java @@ -0,0 +1,126 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredConstructor + */ +public class ClassTestGetDeclaredConstructor extends TestCase { + + /** + * Public constructor which takes an integer parameter must be reflected. + */ + public void test1() { + try { + Constructor c = Integer.class + .getDeclaredConstructor(new Class[] { Integer.TYPE }); + assertNotNull("unexpected null", c); + assertSame("objects differ:", + Integer.TYPE, c.getParameterTypes()[0]); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Verify parametrized type + */ + public void test1_java5() { + try { + Constructor<Integer> c = Integer.class + .getDeclaredConstructor(new Class[] { Integer.TYPE }); + assertNotNull("unexpected null", c); + assertSame("objects differ:", + Integer.TYPE, c.getParameterTypes()[0]); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Only default constructor which takes no parameters must be returned. + */ + public void test2() { + try { + Constructor c = Inner.class.getDeclaredConstructor(new Class[0]); + assertNotNull("unexpected null", c); + assertEquals("array length:", 0, c.getParameterTypes().length); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Public constructors of the super class must not be returned. + */ + public void test3() { + try { + Inner.class.getDeclaredConstructor(new Class[] { String.class }); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + + } + + /** + * Private constructor which takes no parameters must be reflected. + */ + public void test4() { + try { + Constructor c = Inner2.class.getDeclaredConstructor((Class[]) null); + assertNotNull("unexpected null", c); + assertEquals("array length:", 0, c.getParameterTypes().length); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Private constructor which takes no parameters must be reflected. + */ + public void test5() { + try { + Constructor c = PrivateConstructor.class + .getDeclaredConstructor((Class[]) null); + assertNotNull("unexpected null", c); + assertEquals("array length:", 0, c.getParameterTypes().length); + } catch (Exception e) { + fail(e.toString()); + } + } + + private static class Inner extends Throwable { + private static final long serialVersionUID = 0L; + } + + public static class Inner2 { + + private Inner2() { + } + } + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructors.java vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructors.java new file mode 100644 index 0000000..f0a8454 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredConstructors.java @@ -0,0 +1,119 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Constructor; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredConstructors + */ +public class ClassTestGetDeclaredConstructors extends TestCase { + + /** + * The primitive types don't declare constructors. + */ + public void test1() { + Constructor[] cs = Integer.TYPE.getDeclaredConstructors(); + assertNotNull("unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * The arrays don't declare constructors. + */ + public void test2() { + Constructor[] cs = new int[0].getClass().getDeclaredConstructors(); + assertNotNull("unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * Only default constructor which takes no parameters must be returned. + * Constructors of the super class must not be returned. + */ + public void test3() { + Constructor[] cs = ClassTestGetDeclaredConstructors.class + .getDeclaredConstructors(); + assertNotNull("unexpected null", cs); + assertEquals("array length:", 1, cs.length); + assertEquals("array length:", 0, cs[0].getParameterTypes().length); + } + + /** + * Only default constructor which takes no parameters must be returned. + * Constructors of the super class must not be returned. + */ + public void test4() { + Constructor[] cs = Inner.class + .getDeclaredConstructors(); + assertNotNull("unexpected null", cs); + assertEquals("Constructors length:", 1, cs.length); + assertEquals("Parameters length:", 0, cs[0].getParameterTypes().length); + } + + /** + * The getDeclaredConstructors() method must return protected, package + * private and private constructors. + */ + public void test5() { + Constructor[] cs = Inner2.class.getDeclaredConstructors(); + assertEquals("Constructors length:", 2, cs.length); + Class[] args = cs[0].getParameterTypes(); + if (args.length == 0) { + args = cs[1].getParameterTypes(); + assertEquals("Assert 0: args length:", 1, args.length); + assertSame("objects differ:", String.class, args[0]); + } else { + assertEquals("Assert 1: args length:", 1, args.length); + assertSame("objects differ:", String.class, args[0]); + args = cs[1].getParameterTypes(); + assertEquals("Assert 2: args length:", 0, args.length); + } + } + + /** + * The interfaces can not define constructors. + */ + public void test6() { + Constructor[] cs = Inner3.class.getDeclaredConstructors(); + assertNotNull("unexpected null", cs); + assertEquals("array length:", 0, cs.length); + } + + static class Inner extends Throwable { + private static final long serialVersionUID = 0L; + } + + public static class Inner2 { + + public Inner2(String s) { + } + + private Inner2() { + } + } + + public static interface Inner3 { + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredField.java vm/tests/kernel/java/lang/ClassTestGetDeclaredField.java new file mode 100644 index 0000000..8c3d856 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredField.java @@ -0,0 +1,148 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredField + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetDeclaredField extends TestCase { + + /** + * the length field should not be reflected. + */ + public void test1() { + try { + final String name = "length"; + Class c = new int[0].getClass(); + c.getDeclaredField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + /** + * if name is null NullPoinerexception exception should be thrown. + */ + public void test2() { + try { + final String name = null; + getClass().getDeclaredField(name); + } catch (NullPointerException e) { + return; + } catch (NoSuchFieldException e) { + } + fail("NullPointerException exception expected"); + } + + /** + * checks whether public field is reflected + */ + public void test3() { + try { + final String name = "i"; + Field f = A.class.getDeclaredField(name); + assertEquals("incorrect name", name, f.getName()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * checks whether private field is reflected + */ + public void test4() { + try { + final String name = "s"; + Field f = A.class.getDeclaredField(name); + assertEquals("incorrect name", name, f.getName()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B redefines field s of A class. Field of B class should be + * reflected in this case. + */ + public void test5() { + try { + final String name = "s"; + Field f = B.class.getDeclaredField(name); + assertEquals("incorrect name", name, f.getName()); + assertSame("objects differ", B.class, f.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B does not define field i. So an NoSuchFieldException exception + * should be thrown even if its super class defines field with this name. + */ + public void test6() { + try { + final String name = "i"; + B.class.getDeclaredField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + /** + * Class B does not define field j. So an NoSuchFieldException exception + * should be thrown even if its super interface defines field with this name. + */ + public void test7() { + try { + final String name = "j"; + B.class.getDeclaredField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + private static class A { + + public final static int i = 0; + + private String s; + } + + interface I { + + public final static int i = 0; + + public final static int j = 1; + } + + private class B extends A implements I { + + String s; + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredFields.java vm/tests/kernel/java/lang/ClassTestGetDeclaredFields.java new file mode 100644 index 0000000..9839603 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredFields.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredFields + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetDeclaredFields extends TestCase { + + private String s; + + /** + * Void.TYPE class does not declare methods members. + * + */ + public void test1() { + Field[] fs = Void.TYPE.getDeclaredFields(); + assertNotNull("null expected", fs); + assertEquals("array length:", 0, fs.length); + } + + /** + * Arrays do not declare field members. + * + */ + public void test2() { + Field[] fs = new int[0].getClass().getDeclaredFields(); + assertNotNull("null expected", fs); + assertEquals("array length:", 0, fs.length); + } + + /** + * Fields of the super class should not be reflected. + * + */ + public void test3() { + Field[] fs = getClass().getDeclaredFields(); + assertNotNull("null expected", fs); + assertEquals("array length:", 1, fs.length); + assertEquals("incorrect name", "s", fs[0].getName()); + assertSame("objects differ", getClass(), fs[0].getDeclaringClass()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredMethod.java vm/tests/kernel/java/lang/ClassTestGetDeclaredMethod.java new file mode 100644 index 0000000..772a685 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredMethod.java @@ -0,0 +1,138 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredMethod + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetDeclaredMethod extends TestCase { + + /** + * Private method method1 should be reflected by getDeclaredMethod() method. + */ + public void test1() { + try { + final String name = "method1"; + Method m = A.class.getDeclaredMethod(name, (Class[]) null); + assertNotNull("null expected", m); + assertEquals("incorrect name", name, m.getName()); + assertSame("objects differ", A.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Attempt to retrieve public method declared in the super class. + */ + public void test2() { + try { + String methodName = "wait"; + getClass().getDeclaredMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * if name is null NullPointerException should be thrown. + */ + public void test3() { + try { + String methodName = null; + getClass().getDeclaredMethod(methodName, (Class[]) null); + } catch (NullPointerException e) { + return; + } catch (NoSuchMethodException e) { + } + fail("NullPointerException exception expected"); + } + + /** + * NoSuchMethodException should be thrown if name is equal to "<cinit>" + */ + public void test4() { + try { + String methodName = "<cinit>"; + A.class.getDeclaredMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * NoSuchMethodException should be thrown if name is equal to "<init>" + */ + public void test5() { + try { + String methodName = "<init>"; + A.class.getDeclaredMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * if a class contains the method with the same name and parameters as its + * super class then the method of this class should be reflected. + */ + public void test6() { + try { + String methodName = "toString"; + Method m = A.class.getMethod(methodName, new Class[] {}); + assertEquals("incorrect name", methodName, m.getName()); + assertSame("objects differ", A.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Helper inner class. + */ + private static class A { + + static int i; + + static { + i = 0; + } + + public A() { + i = 0; + } + + private void method1() { + } + + public String toString() { + return null; + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaredMethods.java vm/tests/kernel/java/lang/ClassTestGetDeclaredMethods.java new file mode 100644 index 0000000..8719c36 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaredMethods.java @@ -0,0 +1,81 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredMethods + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetDeclaredMethods extends TestCase { + + /** + * Void.TYPE class does not declare methods. + */ + public void test1() { + Method[] ms = Void.TYPE.getDeclaredMethods(); + assertNotNull("null expected", ms); + assertEquals("array length:", 0, ms.length); + } + + /** + * Arrays do not declare methods. + */ + public void test2() { + Method[] ms = new int[0].getClass().getDeclaredMethods(); + assertNotNull("null expected", ms); + assertEquals("array length:", 0, ms.length); + } + + /** + * This test case checks several statements. The methods of the super class + * should not be included in resulting array as well as the <clinit> + * method. Only private method with "method1" name should be returned. + */ + public void test3() { + Method[] ms = A.class.getDeclaredMethods(); + assertNotNull("null expected", ms); + assertEquals("array length:", 1, ms.length); + assertEquals("incorrect name", "method1", ms[0].getName()); + } + + /** + * Helper inner class. + */ + private static class A { + + static int i; + + static { + i = 0; + } + + public A() { + i = 0; + } + + private void method1() { + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaresClasses.java vm/tests/kernel/java/lang/ClassTestGetDeclaresClasses.java new file mode 100644 index 0000000..1c436e9 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaresClasses.java @@ -0,0 +1,98 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.util.Arrays; +import java.util.HashSet; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredClasses + */ +public class ClassTestGetDeclaresClasses extends TestCase { + + /** + * The getDeclaredClasses() method must return all inner classes and + * interfaces including protected, package private and private members. + * + */ + public void test1() { + Class[] cs = ClassTestGetDeclaresClasses.class.getDeclaredClasses(); + HashSet<Class> set = new HashSet<Class>(Arrays.asList(cs)); + assertTrue("Helper1 has not been found", set.contains(Helper1.class)); + assertTrue("Helper2 has not been found", set.contains(Helper2.class)); + assertTrue("Helper3 has not been found", set.contains(Helper3.class)); + assertTrue("Helper4 has not been found", set.contains(Helper4.class)); + assertFalse("Helper1.Inner1 has not been found", + set.contains(Helper1.Inner1.class)); + } + + /** + * The members declared in the super class must not be reflected by + * getDeclaredClasses() method. + * + */ + public void test2() { + Class[] cs = Helper3.class.getDeclaredClasses(); + assertNotNull("null expected", cs); + assertEquals("array length:", 1, cs.length); + assertSame("objects differ", Helper3.Inner2.class, cs[0]); + } + + /** + * An empty array must be returned for the classes that represent + * primitive types. + * + */ + public void test3() { + Class[] cs = Void.TYPE.getDeclaredClasses(); + assertNotNull("null expected", cs); + assertEquals("array length:", 0, cs.length); + } + + /** + * An empty array must be returned for classes that represent arrays. + * + */ + public void test4() { + Class[] cs = new Object[0].getClass().getDeclaredClasses(); + assertNotNull("null expected", cs); + assertEquals("array length:", 0, cs.length); + } + + public class Helper1 { + class Inner1 { + } + } + + protected interface Helper2 { + } + + class Helper3 extends Helper1 { + class Inner2 { + } + } + + private class Helper4 { + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetDeclaringClass.java vm/tests/kernel/java/lang/ClassTestGetDeclaringClass.java new file mode 100644 index 0000000..d38fa35 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetDeclaringClass.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaringClass + */ +public class ClassTestGetDeclaringClass extends TestCase { + + /** + * Declaring class of the primitive types should be null. + * + */ + public void test1() { + Class c = Integer.TYPE.getDeclaringClass(); + assertNull("null expected", c); + } + + /** + * Declaring class of the arrays should be null. + * + */ + public void test2() { + Class c = new int[0].getClass().getDeclaringClass(); + assertNull("null expected", c); + } + + /** + * The chain of inner classes and interfaces. + * + */ + public void test3 () { + Class c = Inner1.Inner2.Inner3.class.getDeclaringClass(); + assertSame("objects differ", Inner1.Inner2.class, c); + c = c.getDeclaringClass(); + assertSame("objects differ", Inner1.class, c); + c = c.getDeclaringClass(); + assertSame("objects differ", getClass(), c); + c = c.getDeclaringClass(); + assertNull("null expected", c); + } + + private interface Inner1 { + public interface Inner2 { + class Inner3 { + } + } + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetField.java vm/tests/kernel/java/lang/ClassTestGetField.java new file mode 100644 index 0000000..adf6120 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetField.java @@ -0,0 +1,191 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getDeclaredField + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetField extends TestCase { + + /** + * the length field should not be reflected. + */ + public void test1() { + try { + final String name = "length"; + Class c = new int[0].getClass(); + c.getField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + /** + * if name is null NullPoinerexception exception should be thrown. + */ + public void test2() { + try { + final String name = null; + getClass().getField(name); + } catch (NullPointerException e) { + return; + } catch (NoSuchFieldException e) { + } + fail("NullPointerException exception expected"); + } + + /** + * checks whether public field is reflected + */ + public void test3() { + try { + final String name = "i"; + Field f = A.class.getField(name); + assertEquals("incorrect name", name, f.getName()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Private field should not be reflected. + */ + public void test4() { + try { + final String name = "s"; + A.class.getField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + /** + * Class B redefines field s of A class. Field of the B class should be + * reflected in this case. + */ + public void test5() { + try { + final String name = "s"; + Field f = B.class.getField(name); + assertEquals("incorrect name", name, f.getName()); + assertSame("objects differ", B.class, f.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B does not define field k. But its super interface J defines field + * with such name. The field of the super interface should be returned. + */ + public void test6() { + try { + final String name = "k"; + Field f = B.class.getField(name); + assertNotNull("unexpected null", f); + assertEquals("incorrect name", name, f.getName()); + assertSame("objects differ", J.class, f.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B does not define field i. But its super interface I and super + * class A define field with such name. The field of the super interface + * should be returned. + */ + public void test7() { + try { + final String name = "i"; + Field f = B.class.getField(name); + assertNotNull("unexpected null", f); + assertEquals("incorrect name", name, f.getName()); + assertSame("objects differ", I.class, f.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B does not define field j. But its super class A defines field with + * such name. The field of the super class should be returned. + */ + public void test8() { + try { + final String name = "j"; + Field f = B.class.getField(name); + assertNotNull("unexpected null", f); + assertEquals("incorrect name", name, f.getName()); + assertSame("objects differ", A.class, f.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Class B does not define field o. Its super class A defines field with + * such name. Sice this field has private accessibility an + * NoSuchFieldException exception should be thrown. + */ + public void test9() { + try { + final String name = "o"; + B.class.getField(name); + } catch (NoSuchFieldException e) { + return; + } + fail("NoSuchFieldException exception expected"); + } + + private static class A { + + public final static int i = 0; + + public final static int j = 1; + + Object o; + + private String s; + } + + interface I { + + public final static int i = 0; + } + + interface J extends I { + + int k = 0; + } + + private class B extends A implements J { + + public String s; + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetFields.java vm/tests/kernel/java/lang/ClassTestGetFields.java new file mode 100644 index 0000000..a44c845 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetFields.java @@ -0,0 +1,118 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getFields + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetFields extends TestCase { + + /** + * Void.TYPE class does not declare fields. + */ + public void test1() { + Field[] fs = Void.TYPE.getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 0, fs.length); + } + + /** + * Arrays do not declare fields. + */ + public void test2() { + Field[] fs = new int[0].getClass().getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 0, fs.length); + } + + /** + * Every field of interface should be reflected. + */ + public void test3() { + Field[] fs = I.class.getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 1, fs.length); + } + + /** + * Every field of interface and its super interfaces should be reflected. + */ + public void test4() { + Field[] fs = J.class.getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 2, fs.length); + } + + /** + * Only public fields should be reflected. + */ + public void test5() { + Field[] fs = A.class.getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 3, fs.length); + } + + /** + * All fields of this class, its super interfaces and super classes should + * be included in resulting array. Each field should appear only once. + */ + public void test6() { + Field[] fs = B.class.getFields(); + assertNotNull("unexpected null", fs); + assertEquals("array length", 6, fs.length); + } + + private static class A implements I { + + public final static int i = 0; + + public final static int j = 1; + + Object o; + + private String s; + } + + interface I { + + int i = 0; + } + + interface J extends I { + + int k = 0; + } + + interface L extends I { + } + + private class B extends A implements L, J { + + public int k; + + public String s; + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetInterfaces.java vm/tests/kernel/java/lang/ClassTestGetInterfaces.java new file mode 100644 index 0000000..952f70f --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetInterfaces.java @@ -0,0 +1,65 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getInterfaces + */ +public class ClassTestGetInterfaces extends TestCase { + + /** + * Class.getInterfaces() method must return all interfaces declared in the + * implements clause and must not return super interfaces these interfaces. + * + */ + public void test1() { + Class[] interfaces = c2.class.getInterfaces(); + assertEquals("array length:", interfaces.length, 1); + assertEquals("names differ:", interfaces[0].getName(), i3.class.getName()); + } + + private interface i1 { + int i = 0; + + int j = 0; + } + + private interface i2 { + int i = 1; + + int k = 1; + } + + private interface i3 extends i2, i1 { + int k = 2; + } + + private class c1 implements i1 { + int i = 3; + } + + private class c2 extends c1 implements i3 { + public int j = 4; + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetMethod.java vm/tests/kernel/java/lang/ClassTestGetMethod.java new file mode 100644 index 0000000..d19d706 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetMethod.java @@ -0,0 +1,190 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getMethod + */ +public class ClassTestGetMethod extends TestCase { + + /** + * "method1" method has public accessibility so it should be accessible + * through Class.getMethod() method. + */ + public void test1() { + try { + Method m = A.class.getMethod("method1", (Class[]) null); + assertEquals("incorrect name", "method1", m.getName()); + assertSame("objects differ", A.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * "method2" method has protected accessibility so it shouldn't be returned + * by Class.getMethod() method. NoSuchMethodException exception expected. + */ + public void test2() { + try { + A.class.getMethod("method2", (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * Attempt to retrieve public method declared in the super class. + */ + public void test3() { + try { + String methodName = "wait"; + Method m = getClass().getMethod(methodName, (Class[]) null); + assertEquals("incorrect name", methodName, m.getName()); + assertSame("objects differ", Object.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * if name is null NullPointerException should be thrown. + */ + public void test4() { + try { + String methodName = null; + getClass().getMethod(methodName, (Class[]) null); + } catch (NullPointerException e) { + return; + } catch (NoSuchMethodException e) { + } + fail("NullPointerException exception expected"); + } + + /** + * NoSuchMethodException should be thrown if name is equal to " <cinit>" + */ + public void test5() { + try { + String methodName = "<cinit>"; + A.class.getMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * NoSuchMethodException should be thrown if name is equal to " <init>" + */ + public void test6() { + try { + String methodName = "<init>"; + A.class.getMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e) { + return; + } + fail("NoSuchMethodException exception expected"); + } + + /** + * if a class contains the method with the same name and parameters as its + * super class then the method of this class should be reflected. + */ + public void test7() { + try { + String methodName = "toString"; + Method m = A.class.getMethod(methodName, new Class[] {}); + assertEquals("incorrect name", methodName, m.getName()); + assertSame("objects differ", A.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * if the super class of this class contains the method with the same + * descriptor as super interface of this class then the method of the super + * class should be reflected. + */ + public void test8() { + try { + String methodName = "equals"; + Method m = A.class.getMethod(methodName, + new Class[] { Object.class }); + assertEquals("incorrect name", methodName, m.getName()); + assertSame("objects differ", Object.class, m.getDeclaringClass()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * the getMethod() method should thow the NoSuchMethodException even if the + * arguments contain nulls. + */ + public void testBug537() { + final String methodName = "testBug537"; + try { + getClass().getMethod(methodName, new Class [] {null}); + } catch (NoSuchMethodException e) { + return; + } + fail("The NoSuchMethodException exception excpected"); + } + + interface I { + + boolean equals(Object obj); + } + + /** + * Helper inner class. + */ + private static class A implements I { + + static int i; + + static { + i = 0; + } + + public A() { + i = 0; + } + + public void method1() { + } + + protected void method2() { + } + + public String toString() { + return null; + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetMethods.java vm/tests/kernel/java/lang/ClassTestGetMethods.java new file mode 100644 index 0000000..e210bb5 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetMethods.java @@ -0,0 +1,119 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getMethods + */ +@SuppressWarnings(value={"all"}) public class ClassTestGetMethods extends TestCase { + + /** + * Void.TYPE class does not declare methods. + */ + public void test1() { + Method[] ms = Void.TYPE.getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 0, ms.length); + } + + /** + * An array should inherit all public member methods of the Object class. + */ + public void test2() { + Method[] ms = new int[0].getClass().getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 9, ms.length); + } + + /** + * Only the public member methods should be returned. + */ + public void test3() { + Method[] ms = A.class.getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 10, ms.length); + } + + /** + * All member methods of the interface should be returned. Note that it does + * not include methods of the Object class. + */ + public void test4() { + Method[] ms = I.class.getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 1, ms.length); + } + + /** + * All member methods of the interface and its super interface should be + * returned. Note that it does not include methods of the Object class. + */ + public void test5() { + Method[] ms = J.class.getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 2, ms.length); + } + + /** + * Complex case. All public member methods of this class, its super classes + * and its super interfaces should be returned. Note that each member method + * appear only once in a resulting array. + */ + public void test6() { + Method[] ms = B.class.getMethods(); + assertNotNull("unexpected null", ms); + assertEquals("array length:", 11, ms.length); + } + + private static class A { + + public void m1() { + } + + private void m2() { + } + } + + interface I { + + public void m1(); + } + + interface J extends I { + + void m2(); + } + + private class B extends A implements I, J { + + public void m2() { + } + + private int m3() { + return 0; + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetModifiers.java vm/tests/kernel/java/lang/ClassTestGetModifiers.java new file mode 100644 index 0000000..1d57e11 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetModifiers.java @@ -0,0 +1,103 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.lang.reflect.Modifier; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getModifiers + */ +public class ClassTestGetModifiers extends TestCase { + + /** + * If the class represents a primitive type, then its public and final + * modifiers should be on as well as its protected, private and interface + * modifiers should be off. + */ + public void test1() { + int mod = Byte.TYPE.getModifiers(); + assertTrue("public:", Modifier.isPublic(mod)); + assertTrue("final:", Modifier.isFinal(mod)); + assertFalse("protected", Modifier.isProtected(mod)); + assertFalse("private", Modifier.isPrivate(mod)); + assertFalse("interface", Modifier.isInterface(mod)); + } + + /** + * If the class represents an array, then its final modifier should be on + * and its interface modifier should be off. Whether an array class has + * public, protected, package private or private modifier determines by the + * modifier of its component type. + */ + public void test2() { + int mod = new int[0].getClass().getModifiers(); + assertTrue("public:", Modifier.isPublic(mod)); + assertTrue("final:", Modifier.isFinal(mod)); + assertFalse("interface", Modifier.isInterface(mod)); + } + + /** + * If the class represents an array, then its final modifier should be on + * and its interface modifier should be off. Whether an array class has + * public, protected, package private or private modifier determines by the + * modifier of its component type. + */ + public void test3() { + int mod = new I[0].getClass().getModifiers(); + assertTrue("private", Modifier.isPrivate(mod)); + assertTrue("final", Modifier.isFinal(mod)); + assertFalse("interface", Modifier.isInterface(mod)); + } + + /** + * An interface should always has abstract and interface modifiers on. + */ + public void test4() { + int mod = I.class.getModifiers(); + assertTrue("private", Modifier.isPrivate(mod)); + assertTrue("interface", Modifier.isInterface(mod)); + assertTrue("abstract", Modifier.isAbstract(mod)); + } + + /** + * Checks whether a Boolean class is public and final. + */ + public void test5() { + int mod = Boolean.class.getModifiers(); + assertEquals("should be public final", + Modifier.PUBLIC | Modifier.FINAL, mod); + } + + /** + * Checks whether a ClassLoader class is public and abstract. + */ + public void test6() { + int mod = ClassLoader.class.getModifiers(); + assertEquals("should be public abstract", + Modifier.PUBLIC | Modifier.ABSTRACT, mod); + } + + private interface I { + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetName.java vm/tests/kernel/java/lang/ClassTestGetName.java new file mode 100644 index 0000000..e69a449 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetName.java @@ -0,0 +1,78 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getName + */ +public class ClassTestGetName extends TestCase { + + /** + * Check the name of the primitive type. + */ + public void test1() { + final String name = Character.TYPE.getName(); + assertEquals("char", name); + } + + /** + * Check the name of the void type. + */ + public void test2() { + final String name = Void.TYPE.getName(); + assertEquals("void", name); + } + + /** + * Check the name of the primitive type. + */ + public void test3() { + final String name = boolean.class.getName(); + assertEquals("boolean", name); + } + + /** + * Check the name of the reference type. + */ + public void test4() { + final String name = Boolean.class.getName(); + assertEquals("java.lang.Boolean", name); + } + + /** + * Check the name of an array of the primitive types. + */ + public void test5() { + final String name = new int[0][0].getClass().getName(); + assertEquals("[[I", name); + } + + /** + * Check the name of an array of the reference types. + */ + public void test6() { + final String name = new Boolean[0][0].getClass().getName(); + assertEquals("[[Ljava.lang.Boolean;", name); + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetPackage.java vm/tests/kernel/java/lang/ClassTestGetPackage.java new file mode 100644 index 0000000..4aa6d4f --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetPackage.java @@ -0,0 +1,50 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getPackage + */ +public class ClassTestGetPackage extends TestCase { + + /** + * retrives a package for the class which was loaded by bootstrap class + * loader. + */ + public void test1() { + Package p = Object.class.getPackage(); + assertNotNull("unexpected null", p); + assertEquals("incorrect name", "java.lang", p.getName()); + } + + /** + * retrives a package for the class which was loaded by user-defined class + * loader. + */ + public void test2() { + Package p = ClassTestGetPackage.class.getPackage(); + assertNotNull("unexpected null", p); + assertEquals("incorrect name", "java.lang", p.getName()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetProtectionDomain.java vm/tests/kernel/java/lang/ClassTestGetProtectionDomain.java new file mode 100644 index 0000000..d0d619b --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetProtectionDomain.java @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.security.AllPermission; +import java.security.ProtectionDomain; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getProtectionDomain + */ +public class ClassTestGetProtectionDomain extends TestCase { + + /** + * Checks protection domain for the class which was loaded by bootstrap + * class loader. + */ + public void test1() { + ProtectionDomain pd = Object.class.getProtectionDomain(); + assertNotNull("unexpected null", pd); + assertNull("null expected", pd.getCodeSource()); + assertTrue("AllPermission expected", + pd.getPermissions().implies(new AllPermission())); + } + + /** + * Checks that protection domain is not null. + */ + public void test2() { + ProtectionDomain pd = getClass().getProtectionDomain(); + assertNotNull("unexpected null", pd); + assertNull("null expected", pd.getCodeSource()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetResource.java vm/tests/kernel/java/lang/ClassTestGetResource.java new file mode 100644 index 0000000..893f2ee --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetResource.java @@ -0,0 +1,201 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + * This ClassTestGetResource class ("Software") is furnished under license and + * may only be used or copied in accordance with the terms of that license. + * + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on 03.02.2006 + * + * This ClassTestGetResource class is used to test the Core API + * java.lang.Class.getResource method + * + */ +public class ClassTestGetResource extends TestCase { + + static String vendor = System.getProperty("java.vm.vendor"); + + /** + * prepending by package name. + */ + public void test1() { + assertTrue("Error1: unexpected:" + + Void.class.getResource("Class.class").toString(), + Void.class.getResource("Class.class").toString().indexOf( + "Class.class") != -1); + } + + /** + * unchanging. + */ + public void test2() { + assertTrue("Error1", + Void.class.getResource( + "/" + + Class.class.getPackage().getName().replace( + '.', '/') + "/Class.class").toString() + .indexOf("Class.class") != -1); + } + + /** + * in java.ext.dirs. + */ + public void test3() { + //System.out.println(System.getProperties()); + if (vendor.equals("Intel DRL")) {// to test for others + // -Djava.ext.dirs=<some non-empty path list> argument should be + // passed for ij.exe for real check + String as[] = System.getProperty("java.ext.dirs").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File dir = new File(as[i]); + if (dir.exists() && dir.isDirectory()) { + String afn[] = dir.list(); + File aff[] = dir.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + /**/System.out.println("test3 "+afn[j]); + try { + assertTrue("Error1", + Void.class.getResource("/" + afn[j]) + .toString().indexOf(afn[j]) != -1); + return; + }catch(Throwable e){ + System.out.println(e.toString()); } + } + } + } + } + } + } + + /** + * in java.class.path. + */ + public void test4() { + if (vendor.equals("Intel DRL")) {// to test for others + // -cp <some non-empty path list> or -Djava.class.path=<some + // non-empty path list> arguments should be passed for ij.exe for + // real check + String as[] = System.getProperty("java.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isDirectory()) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + //System.out.println("test4 "+afn[j]); + assertTrue("Error1", + Void.class.getResource("/" + afn[j]) + .toString().indexOf(afn[j]) != -1); + return; + } + } + } else if (f.exists() && f.isFile() + && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + //System.out.println("test4 "+s); + assertTrue("Error1", Void.class.getResource( + "/" + s).toString().indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } + } + } + } + + /** + * via -Xbootclasspath (vm.boot.class.path). + */ + public void test5() { + //System.out.println("|"+System.getProperty("sun.boot.class.path")+"|"); + //System.out.println("|"+System.getProperty("vm.boot.class.path")+"|"); + if (vendor.equals("Intel DRL")) {// to test for others + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + //System.out.println("test5 "+s); + assertTrue("Error1", Void.class.getResource( + "/" + s).toString().indexOf(s) != -1); + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + //System.out.println("test5 "+afn[j]); + assertTrue("Error1", + Void.class.getResource("/" + afn[j]) + .toString().indexOf(afn[j]) != -1); + return; + } + } + } + } + } + } + + /** + * The method throws NullPointerException if argument is null + */ +//Commented because 6793 bug isn't fixed + public void te_st6() { + try { + Void.class.getResource(null); + fail("Error1: NullPointerException is not thrown for null argument"); // #6793 + } catch (NullPointerException _) { + } + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetResourceAsStream.java vm/tests/kernel/java/lang/ClassTestGetResourceAsStream.java new file mode 100644 index 0000000..7414c84 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetResourceAsStream.java @@ -0,0 +1,215 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + * This ClassTestGetResourceAsStream class ("Software") is furnished under license and + * may only be used or copied in accordance with the terms of that license. + * + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on 03.02.2006 + * + * This ClassTestGetResourceAsStream class is used to test the Core API + * java.lang.Class.getResourceAsStream method + * + */ +public class ClassTestGetResourceAsStream extends TestCase { + + static String vendor = System.getProperty("java.vm.vendor"); + + /** + * The method throws NullPointerException if argument is null + */ +//Commented because 6793 bug isn't fixed + public void te_st1() { + try { + Void.class.getResourceAsStream(null); + fail("Error1: NullPointerException is not thrown for null argument"); + } catch (NullPointerException _) { + } + } + + /** + * prepending by package name. + */ + public void test2() { + byte magic[] = new byte[4]; + try { + Void.class.getResourceAsStream("Class.class").read(magic); + //System.out.println(Integer.toString(0xff&magic[0], 16)); + assertTrue("Error1", new String(magic).equals(new String(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}))); + } catch (java.io.IOException _) {} + } + + /** + * unchanging. + */ + public void test3() { + byte magic[] = new byte[4]; + try { + Void.class.getResourceAsStream("/" + + Class.class.getPackage().getName().replace( + '.', '/') + "/Class.class").read(magic); + assertTrue("Error1", new String(magic).equals(new String(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}))); + } catch (java.io.IOException _) {} + } + + /** + * in java.ext.dirs. + */ + public void test4() { + //System.out.println(System.getProperties()); + if (vendor.equals("Intel DRL")) {// to test for others + // -Djava.ext.dirs=<some non-empty path list> argument should be + // passed for ij.exe for real check + String as[] = System.getProperty("java.ext.dirs").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File dir = new File(as[i]); + if (dir.exists() && dir.isDirectory()) { + String afn[] = dir.list(); + File aff[] = dir.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + //System.out.println("test4 "+afn[j]); + try { + assertTrue("Error1", + Void.class.getResourceAsStream("/" + afn[j]) + .available() >= 0); + return; + }catch(java.io.IOException _){ }catch(Throwable e){ + System.out.println(e.toString()); } + //return; + } + } + } + } + } + } + + /** + * in java.class.path. + */ + public void test5() { + if (vendor.equals("Intel DRL")) {// to test for others + // -cp <some non-empty path list> or -Djava.class.path=<some + // non-empty path list> arguments should be passed for ij.exe for + // real check + String as[] = System.getProperty("java.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isDirectory()) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + /**/System.out.println("test5 "+afn[j]); + try { + assertTrue("Error1", + Void.class.getResourceAsStream("/" + afn[j]) + .available() >= 0); + }catch(java.io.IOException _){} + return; + } + } + } else if (f.exists() && f.isFile() + && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + //System.out.println("test4 "+s); + byte magic[] = new byte[4]; + try { + Void.class.getResourceAsStream("/" + s).read(magic); + assertTrue("Error1", new String(magic).equals(new String(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}))); + } catch (java.io.IOException _) {} + return; + } + } + } catch (java.io.IOException _) { + } + } + } + } + } + + /** + * via -Xbootclasspath (vm.boot.class.path). + */ + public void test6() { + //System.out.println("|"+System.getProperty("sun.boot.class.path")+"|"); + //System.out.println("|"+System.getProperty("vm.boot.class.path")+"|"); + if (vendor.equals("Intel DRL")) {// to test for others + // -Xbootclasspath[/a /p]:<some non-empty path list> or + // -D{vm/sun}.boot.class.path=<some non-empty path list> arguments + // should be passed for ij.exe for real check + String as[] = System.getProperty( + (vendor.equals("Intel DRL") ? "vm" : "sun") + + ".boot.class.path").split( + System.getProperty("path.separator")); + for (int i = 0; i < as.length; i++) { + File f = new File(as[i]); + if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { + try { + java.util.jar.JarFile jf = new java.util.jar.JarFile(f); + for (java.util.Enumeration e = jf.entries(); e + .hasMoreElements();) { + String s = e.nextElement().toString(); + if (s.endsWith(".class")) { + //System.out.println("test5 "+s); + byte magic[] = new byte[4]; + try { + Void.class.getResourceAsStream("/" + s).read(magic); + assertTrue("Error1", new String(magic).equals(new String(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}))); + } catch (java.io.IOException _) {} + return; + } + } + } catch (java.io.IOException _) { + } + } else if (f.exists() && f.isDirectory() && false) { + String afn[] = f.list(); + File aff[] = f.listFiles(); + for (int j = 0; j < aff.length; j++) { + if (aff[j].isFile()) { + //System.out.println("test5 "+afn[j]); + try { + assertTrue("Error1", + Void.class.getResourceAsStream("/" + afn[j]) + .available() >= 0); + }catch(java.io.IOException _){} + return; + } + } + } + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestGetSigners.java vm/tests/kernel/java/lang/ClassTestGetSigners.java new file mode 100644 index 0000000..d450a97 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetSigners.java @@ -0,0 +1,37 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getSigners + */ +public class ClassTestGetSigners extends TestCase { + + /** + * primitive types cannot have signers. + */ + public void test1() { + assertNull("null expected", void.class.getSigners()); + } +} diff --git vm/tests/kernel/java/lang/ClassTestGetSuperclass.java vm/tests/kernel/java/lang/ClassTestGetSuperclass.java new file mode 100644 index 0000000..56d3833 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestGetSuperclass.java @@ -0,0 +1,78 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: getSuperclass + */ +public class ClassTestGetSuperclass extends TestCase { + + /** + * Super class of the Object class is null. + */ + public void test1() { + Class c = Object.class.getSuperclass(); + assertNull("null expected", c); + } + + /** + * Super class of the primitive class is null. + */ + public void test2() { + Class c = Character.TYPE.getSuperclass(); + assertNull("null expected", c); + } + + /** + * Super class of the interface is null. + */ + public void test3() { + Class c = Cloneable.class.getSuperclass(); + assertNull("null expected", c); + } + + /** + * Super class of the array class is the Object class. + */ + public void test4() { + Class c = new Cloneable[0].getClass().getSuperclass(); + assertSame("objects differ", Object.class, c); + } + + /** + * Verify parametrized type. + */ + public void test4_java5() { + Class<? super java.io.FileReader> c = java.io.InputStreamReader.class.getSuperclass(); + assertSame("objects differ", java.io.Reader.class, c); + } + + /** + * Super class of the this class is the TestCase class. + */ + public void test5() { + Class c = getClass().getSuperclass(); + assertSame("objects differ", TestCase.class, c); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestIsArray.java vm/tests/kernel/java/lang/ClassTestIsArray.java new file mode 100644 index 0000000..09dc9d6 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestIsArray.java @@ -0,0 +1,85 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: isArray + */ +public class ClassTestIsArray extends TestCase { + + /** + * The Object class does not represent array. + */ + public void test1() { + assertFalse(Object.class.isArray()); + } + + /** + * The primitive class does not represent array. + */ + public void test2() { + assertFalse(Character.TYPE.isArray()); + } + + /** + * The interface does not represent array. + */ + public void test3() { + assertFalse(Cloneable.class.isArray()); + } + + /** + * Array of interfaces. + */ + public void test4() { + assertTrue(new Cloneable[0].getClass().isArray()); + } + + public void test5() { + assertTrue(new int[0].getClass().isArray()); + } + + /** + * Array of primitive types. + */ + public void test6() { + try { + assertTrue(Class.forName("[[I").isArray()); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Array of recference types. + */ + public void test7() { + try { + assertTrue(Class.forName("[Ljava.lang.Object;").isArray()); + } catch (Exception e) { + fail(e.toString()); + } + } + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestIsAssignableFrom.java vm/tests/kernel/java/lang/ClassTestIsAssignableFrom.java new file mode 100644 index 0000000..fadc4ca --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestIsAssignableFrom.java @@ -0,0 +1,122 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.io.Serializable; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: isAssignableFrom + */ +public class ClassTestIsAssignableFrom extends TestCase { + + /** + * if argument is null an NullPoinerException should be thrown. + */ + public void test1() { + try { + getClass().isAssignableFrom(null); + } catch (NullPointerException e) { + return; + } + fail("NullPointerException exception expected"); + } + + /** + * checks identity primitive conversion. + */ + public void test2() { + assertTrue("Assert 0:", Integer.TYPE.isAssignableFrom(int.class)); + assertTrue("Assert 1:", int.class.isAssignableFrom(Integer.TYPE)); + } + + /** + * checks widening refernce conversion for primitive type. + */ + public void test3() { + assertFalse(Object.class.isAssignableFrom(Character.TYPE)); + } + + /** + * Classes that represent primitive types aren't assignable from + * corresponding wrapper types as well as vice versa. + */ + public void test4() { + assertFalse("Assert 0:", Integer.class.isAssignableFrom(Integer.TYPE)); + assertFalse("Assert 1:", Integer.TYPE.isAssignableFrom(Integer.class)); + } + + /** + * The Serializable interface is super interface of the Boolean class. So it + * should be assignable from the Boolean class. But not vice versa. + */ + public void test5() { + assertTrue("Assert 0:", Serializable.class.isAssignableFrom(Boolean.class)); + assertFalse("Assert 1:", Boolean.class.isAssignableFrom(Serializable.class)); + } + + /** + * Each array has the Object class as its super class. + */ + public void test6() { + assertTrue(Object.class.isAssignableFrom(new int[0].getClass())); + } + + /** + * The isAssignable() method should not perform widening primitive + * conversion. + */ + public void test7() { + assertFalse("Assert 0:", double.class.isAssignableFrom(int.class)); + assertFalse("Assert 1:", int.class.isAssignableFrom(double.class)); + } + + /** + * if a class represents array the isAssignable() method should work with + * array's components. But this method should not perform widening primitive + * conversion. + */ + public void test8() { + assertFalse("Assert 0:", new double[0].getClass(). + isAssignableFrom(new int[0].getClass())); + assertFalse("Assert 1:", new int[0].getClass(). + isAssignableFrom(new double[0].getClass())); + } + + /** + * if a class represents array the isAssignable() method should work with + * array's components. So the Object[] class is assignable from the String[] + * class as well as the Object class is assignable from the String class. + */ + public void test9() { + assertTrue(new Object[0].getClass(). + isAssignableFrom(new String[0].getClass())); + } + + /** + * The Object class is assignable from any reference type. + */ + public void test10() { + assertTrue(Object.class.isAssignableFrom(getClass())); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestIsInstance.java vm/tests/kernel/java/lang/ClassTestIsInstance.java new file mode 100644 index 0000000..2d5eddb --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestIsInstance.java @@ -0,0 +1,104 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.io.Serializable; +import java.security.Permission; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: isInstance + */ +public class ClassTestIsInstance extends TestCase { + + /** + * the isInstance() method returns false if argument is null. + */ + public void test1() { + assertFalse(Object.class.isInstance(null)); + } + + /** + * the isInstance() method returns false if this class represetnts primitive + * type. + */ + public void test2() { + assertFalse("Assert 0:", Integer.TYPE.isInstance(new Integer(1))); + assertFalse("Assert 1:", int.class.isInstance(new Integer(1))); + } + + /** + * checks widening refernce conversion. + */ + public void test3() { + assertTrue(Object.class.isInstance(new Character('a'))); + } + + /** + * The Serializable interface is super interface of the Boolean class. So + * the Boolean class is instance of the Serializable interface. + */ + public void test4() { + assertTrue(Serializable.class.isInstance(new Boolean(true))); + } + + /** + * Each array has the Object class as its super class. + */ + public void test5() { + assertTrue(Object.class.isInstance(new int[0])); + } + + /** + * Array of primitive types is not an instance of array of objects. + */ + public void test6() { + assertFalse(new Object[0].getClass().isInstance(new int[0])); + } + + /** + * the isInstance() method returns false if this class represetnts an array + * of primitive types. + */ + public void test7() { + assertFalse("Assert 0:", new double[0].getClass().isInstance(new int[0])); + assertFalse("Assert 1:", new int[0].getClass().isInstance(new double[0])); + } + + /** + * checks whether array components can be converted by widening reference + * conversion. + */ + public void test8() { + assertTrue("Assert 0:", new Object[0].getClass().isInstance(new String[0])); + assertFalse("Assert 1:", new String[0].getClass().isInstance(new Object[0])); + } + + /** + * The Permission class is super class of the RuntimePermission class. + */ + public void test9() { + Object o = new RuntimePermission("createClassLoader"); + assertTrue(Permission.class.isInstance(o)); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestIsInterface.java vm/tests/kernel/java/lang/ClassTestIsInterface.java new file mode 100644 index 0000000..034bfa3 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestIsInterface.java @@ -0,0 +1,51 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: isInterface + */ +public class ClassTestIsInterface extends TestCase { + + /** + * The Cloneable class represents an interface. + */ + public void test1() { + assertTrue(Cloneable.class.isInterface()); + } + + /** + * This class is not an interface. + */ + public void test2() { + assertFalse(getClass().isInterface()); + } + + /** + * Abstract ClassLoader class is not an interface. + */ + public void test3() { + assertFalse(ClassLoader.class.isInterface()); + } +} diff --git vm/tests/kernel/java/lang/ClassTestIsPrimitive.java vm/tests/kernel/java/lang/ClassTestIsPrimitive.java new file mode 100644 index 0000000..c55d7a0 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestIsPrimitive.java @@ -0,0 +1,58 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: isPrimitive + */ +public class ClassTestIsPrimitive extends TestCase { + + /** + * The Float.TYPE class represents the primitive type. + */ + public void test1() { + assertTrue(Float.TYPE.isPrimitive()); + } + + /** + * The void class represents the primitive type. + */ + public void test2() { + assertTrue(void.class.isPrimitive()); + } + + /** + * checks that the Integer class does not represent a primitive type. + */ + public void test3() { + assertFalse(Integer.class.isPrimitive()); + } + + /** + * array of primitive types is not the primitive type. + */ + public void test4() { + assertFalse(new int[0].getClass().isPrimitive()); + } +} diff --git vm/tests/kernel/java/lang/ClassTestNewInstance.java vm/tests/kernel/java/lang/ClassTestNewInstance.java new file mode 100644 index 0000000..bfdf65b --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestNewInstance.java @@ -0,0 +1,142 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: newInstance + */ +public class ClassTestNewInstance extends TestCase { + + /** + * Attempt to create an abstract class. InstantiationException exception + * must be thrown in this case. + */ + public void test1() { + try { + ClassTestNewInstance.AbstractClassPublicConstructor.class + .newInstance(); + } catch (InstantiationException e) { + return; + } catch (Exception e) { + } + fail("InstantiationException exception expected"); + } + + /** + * Attempt to create a class with a private constructor. + * IllegalAccessException must be thrown in this case. + */ + public void test2() { + try { + java.lang.PrivateConstructor.class.newInstance(); + } catch (IllegalAccessException e) { + return; + } catch (Exception e) { + } + fail("IllegalAccessException exception expected"); + } + + /** + * Attempt to create aclass which throws an exception. + * InstantiationException must be thrown in this case. + */ + public void test3() { + try { + ClassTestNewInstance.ExceptionThrowner.class.newInstance(); + } catch (InstantiationException e) { + return; + } catch (Exception e) { + } + fail("InstantiationException exception expected"); + } + + /** + * This is normal use of newInstance method. No exceptions must be thrown. + * The reated object must have correct type. + */ + public void test4() { + try { + Object o = ClassTestNewInstance.class.newInstance(); + assertTrue("Wrong type", o instanceof ClassTestNewInstance); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Attempt to instantiate an object of the primitive type. + */ + public void test5() { + try { + Character.TYPE.newInstance(); + } catch (InstantiationException e) { + return; + } catch (Exception e) { + } + fail("InstantiationException exception expected"); + } + + /** + * Attempt to instantiate an object of the primitive type. + */ + public void test6() { + try { + new int[0].getClass().newInstance(); + } catch (InstantiationException e) { + return; + } catch (Exception e) { + } + fail("InstantiationException exception expected"); + } + + public void testBug521() { + try { + Class cls = Class.forName(Inner.class.getName()); + cls.newInstance(); + } catch (Exception e) { + fail(e.toString()); + } + } + + /** + * Helper inner class. + */ + private abstract class AbstractClassPublicConstructor { + + public AbstractClassPublicConstructor() { + } + } + + /** + * Helper inner class. + */ + private class ExceptionThrowner { + + public ExceptionThrowner() throws Exception { + throw new Exception("This class cannot be instatiated"); + } + } + + static class Inner {} +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ClassTestToString.java vm/tests/kernel/java/lang/ClassTestToString.java new file mode 100644 index 0000000..8c1a2b3 --- /dev/null +++ vm/tests/kernel/java/lang/ClassTestToString.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.io.Serializable; +import java.security.Permission; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Class + * tested method: toString + */ +public class ClassTestToString extends TestCase { + + /** + * only the class name should be returned in the case of primitive type. + */ + public void test1() { + assertEquals(void.class.toString(), void.class.toString()); + } + + /** + * The string "interface" should be followed by the class name if this class + * represents an interface. + */ + public void test2() { + assertEquals("interface " + Cloneable.class.getName(), Cloneable.class + .toString()); + } + + /** + * The string "class" should be followed by the class name + * if this is a class. + */ + public void test3() { + assertEquals("class " + Class.class.getName(), Class.class.toString()); + } + + /** + * The string "class" should be followed by the class name + * if this is a class. + */ + public void test4() { + Serializable[] c = new Permission[0]; + assertEquals("class " + c.getClass().getName(), c.getClass().toString()); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/InheritableThreadLocalSupport.java vm/tests/kernel/java/lang/InheritableThreadLocalSupport.java new file mode 100644 index 0000000..b76a541 --- /dev/null +++ vm/tests/kernel/java/lang/InheritableThreadLocalSupport.java @@ -0,0 +1,116 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Elena Semukhina + * @version $Revision$ + */ + +package java.lang; + +public class InheritableThreadLocalSupport extends Thread { + + static Object localO = null; + static Integer localI = null; + static Integer newLocalI = new Integer(10); + + public boolean parentInheritableLocalObjectOK = false; + public boolean childInheritableLocalObjectOK = false; + public boolean grandChildInheritableLocalObjectOK = false; + public boolean parentInheritableLocalIntegerOK = false; + public boolean childInheritableLocalIntegerOK = false; + public boolean grandChildInheritableLocalIntegerOK = false; + + static InheritableThreadLocal<Object> itlo = new InheritableThreadLocal<Object>() { + + protected synchronized Object initialValue() { + localO = new Object(); + return localO; + } + }; + + static InheritableThreadLocal<Integer> itli = new InheritableThreadLocal<Integer>() { + + protected synchronized Integer initialValue() { + localI = new Integer(5); + return localI; + } + + protected synchronized Integer childValue(Integer parentValue) { + return new Integer(parentValue.intValue() * 2); + } + }; + + public void run() { + Object valO = itlo.get(); + if (valO.equals(localO)) { + parentInheritableLocalObjectOK = true; + } + Integer valI = itli.get(); + if (valI.equals(localI)) { + parentInheritableLocalIntegerOK = true; + } + Child child = new Child(); + child.start(); + try { + child.join(); + } catch (InterruptedException ie) { + return; + } + childInheritableLocalObjectOK = child.childInheritableLocalObjectOK; + grandChildInheritableLocalObjectOK = child.grandChildInheritableLocalObjectOK; + childInheritableLocalIntegerOK = child.childInheritableLocalObjectOK; + grandChildInheritableLocalIntegerOK = child.grandChildInheritableLocalObjectOK; + } +} + + class Child extends InheritableThreadLocalSupport { + + public void run() { + Object valO = itlo.get(); + if (valO.equals(localO)) { + childInheritableLocalObjectOK = true; + } + Integer valI = itli.get(); + if (valI.intValue() == newLocalI.intValue()) { + childInheritableLocalIntegerOK = true; + } + GrandChild gChild = new GrandChild(); + gChild.start(); + try { + gChild.join(); + } catch (InterruptedException ie) { + return; + } + grandChildInheritableLocalObjectOK = gChild.grandChildInheritableLocalObjectOK; + grandChildInheritableLocalIntegerOK = gChild.grandChildInheritableLocalIntegerOK; + } + } + + class GrandChild extends InheritableThreadLocalSupport { + + public void run() { + Object valO = itlo.get(); + if (valO.equals(localO)) { + grandChildInheritableLocalObjectOK = true; + } + Integer valI = itli.get(); + if (valI.equals(newLocalI)) { + grandChildInheritableLocalIntegerOK = true; + } + } + } + diff --git vm/tests/kernel/java/lang/InheritableThreadLocalTest.java vm/tests/kernel/java/lang/InheritableThreadLocalTest.java new file mode 100644 index 0000000..cc65fbb --- /dev/null +++ vm/tests/kernel/java/lang/InheritableThreadLocalTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Elena Semukhina + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +public class InheritableThreadLocalTest extends TestCase { + + public void testInheritableThreadLocal(){ + InheritableThreadLocalSupport t = new InheritableThreadLocalSupport(); + t.start(); + try { + t.join(); + } catch (InterruptedException ie) { + fail("thread interrupted"); + } + assertTrue("Wrong local Object value in parent", + t.parentInheritableLocalObjectOK); + assertTrue("Wrong inheritable local Object value in child", + t.childInheritableLocalObjectOK); + assertTrue("Wrong inheritable local Object value in grandchild", + t.grandChildInheritableLocalObjectOK); + assertTrue("Wrong local Integer value in parent", + t.parentInheritableLocalIntegerOK); + assertTrue("Wrong inheritable local Integer value in child", + t.childInheritableLocalIntegerOK); + assertTrue("Wrong inheritable local Integer value in grandchild", + t.grandChildInheritableLocalIntegerOK); + + } +} diff --git vm/tests/kernel/java/lang/ObjectTest.java vm/tests/kernel/java/lang/ObjectTest.java new file mode 100644 index 0000000..13231a4 --- /dev/null +++ vm/tests/kernel/java/lang/ObjectTest.java @@ -0,0 +1,361 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Roman S. Bushmanov + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; +import java.util.*; + +/** + * Unit test for java.lang.Object class. + */ + +public class ObjectTest extends TestCase { + + private Object obj1 = new Object(); + + private Object obj2 = new Object(); + + private Object obj3 = obj1; + + public void testGetClass1() { + assertEquals("java.lang.Object", obj1.getClass().getName()); + } + + public void testGetClass2() { + Object o = new Boolean(true); + assertEquals("java.lang.Boolean", o.getClass().getName()); + } + + /** + * Verify 1.5 getClass() + */ + public void testGetClass3() { + Object o = new Boolean(true); + Class<? extends Object> c = o.getClass(); + assertEquals("java.lang.Boolean", c.getName()); + } + + /** + * Verify 1.5 getClass() + */ + public void testGetClass4() { + AbstractMap<Integer, String> hm = new HashMap<Integer, String>(); + Class<? extends AbstractMap> c = hm.getClass(); + assertEquals("java.util.HashMap", c.getName()); + } + + public void testHashCode1() { + assertEquals("Hash code for the same object must be the same!", + obj1.hashCode(), obj3.hashCode()); + } + + public void testEquals1() { + assertTrue("Equilvalence relation must be reflexive!", + obj1.equals(obj1)); + } + + public void testEguals2() { + assertFalse("Different objects must be not equal!", obj1.equals(obj2)); + } + + public void testClone1() { + try { + ObjectDescendant o = new ObjectDescendant(); + o.testClone(); + } catch (CloneNotSupportedException e) { + return; + } + fail("CloneNotSupported exception must be thrown if an object " + + "doesn't implement Cloneabe interface!"); + } + + public void testClone2() { + try { + CloneableObjectDescendant o = new CloneableObjectDescendant(1, obj1); + CloneableObjectDescendant clone = (CloneableObjectDescendant) o + .testClone(); + assertEquals("Assert 0:", 1, clone.getPrimitiveVal()); + assertEquals("Assert 1:", obj1, clone.getReferenceVal()); + } catch (CloneNotSupportedException e) { + fail("Should not throw CloneNotSupported exception!"); + } + } + + public void testToString() { + Object o = new int[0]; + assertEquals("[I@" + Integer.toHexString(o.hashCode()), o.toString()); + } + + public void testNotifyAll() { + Object o = new Object(); + //create and start two test threads + TestThread t1 = new TestThread1(o); + TestThread t2 = new TestThread1(o); + t1.start(); + t2.start(); + //wait until both threads are started + for (int i = 0; !(t1.flag && t2.flag) && i < 60; i++) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + fail("The main thread was interrupted."); + } + } + assertTrue("Test threads did not start for a long time!", + t1.flag && t2.flag); + //now both test threads in the wait set of object o + //notify both waiting threads + synchronized (o) { + o.notifyAll(); + } + //wait until both threads are notified + for (int i = 0; t1.flag || t2.flag && i < 60; i++) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + fail("The main thread was interrupted."); + } + } + assertFalse("At least one of two test threads is not notified " + + "for a long time!", + t1.flag || t2.flag); + } + + public void testNotify1() { + Object o = new Object(); + try { + o.notify(); + } catch (IllegalMonitorStateException e) { + return; + } + fail("An IllegalMonitorStateException should be thrown!"); + } + + public void testNotify() { + Object o = new Object(); + //create and start two test threads + TestThread t1 = new TestThread1(o); + TestThread t2 = new TestThread1(o); + t1.start(); + t2.start(); + //wait until both threads are started + for (int i = 0; !(t1.flag && t2.flag) && i < 60; i++) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + fail("The main thread was interrupted."); + } + } + assertTrue("Test threads did not start for a long time!", + t1.flag && t2.flag); + //now both test threads wait for object o + //notify one of two waiting threads + synchronized (o) { + o.notify(); + } + //wait until one of two threads is notified + for (int i = 0; t1.flag && t2.flag && i < 60; i++) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + fail("The main thread was interrupted."); + } + } + for (int i = 0; t1.flag && t2.flag && i < 60; i++) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + fail("The main thread was interrupted."); + } + } + assertFalse("None of two test threads is notified for a long time!", + t1.flag && t2.flag); + assertFalse("Both test threads were notified instead of one!", + !t1.flag && !t2.flag); + } + + public void testWaitlongint() { + long millis = 500; + int nanos = 500; + long start = 0; + long finish = 0; + synchronized (obj1) { + try { + start = System.currentTimeMillis(); + obj1.wait(millis, nanos); + finish = System.currentTimeMillis(); + } catch (InterruptedException e) { + fail("The main thread was interrupted!"); + } + } + assertTrue("Current thread hasn't sleep enough!", + finish - start + 1 > millis); + } + + public void testWaitlongint1() { + try { + obj1.wait(500, 1000000); + } catch (IllegalArgumentException e) { + return; + } catch (InterruptedException e) { + fail("The main thread was interrupted!"); + } + fail("An IllegalArgumentException must be thrown!"); + } + + public void testWaitlong() { + long timeout = 500; + long start = 0; + long finish = 0; + Object o = new Object(); + synchronized (o) { + try { + start = System.currentTimeMillis(); + o.wait(timeout); + finish = System.currentTimeMillis(); + } catch (InterruptedException e) { + fail("The main thread was interrupted!"); + } + } + // the sleeping time is more or less equal to timeout + // so we allow 10% less time (there was bug filed on this issue) + assertTrue("Current thread hasn't slept enough!", + finish - start + 1 > timeout - timeout/10); + } + + public void testWait() { + TestThread t = new TestThread() { + public void run() { + try { + (new Object()).wait(); + } catch (InterruptedException e) { + } catch (IllegalMonitorStateException e) { + flag = true; + } + } + }; + t.start(); + int i = 0; + while (t.isAlive() && i < 300) { + try { + t.join(10); + i++; + } catch (Exception e) { + fail("The main thread was interrupted!"); + } + } + assertTrue("An IllegalMonitorStateException must be thrown " + + "in test thread!", t.flag); + if (t.isAlive()) { + fail("thread has not finished!"); + } + } + + public void testWait1() { + final Object o = new Object(); + TestThread t = new TestThread() { + public void run() { + try { + synchronized (o) { + o.wait(); + } + } catch (InterruptedException e) { + flag = true; + } + } + }; + t.start(); + for (int i = 0; !t.isAlive() && i < 60; i++) { + try { + Thread.sleep(50); + } catch (Exception e) { + fail("The main thread was interrupted!"); + } + } + assertTrue("thread must be alive", t.isAlive()); + t.interrupt(); + for (int i = 0; !t.flag && i < 300; i++) { + try { + t.join(10); + } catch (Exception e) { + fail("The main thread was interrupted!"); + } + } + assertTrue("An InterruptedException must be thrown in test thread!", + t.flag); + } + + private class ObjectDescendant { + void testClone() throws CloneNotSupportedException { + clone(); + } + } + + private class CloneableObjectDescendant implements Cloneable { + + private int primitiveField = -1; + + private Object objectField = null; + + CloneableObjectDescendant(int primitiveVal, Object referenceVal) { + primitiveField = primitiveVal; + objectField = referenceVal; + } + + int getPrimitiveVal() { + return primitiveField; + } + + Object getReferenceVal() { + return objectField; + } + + Object testClone() throws CloneNotSupportedException { + return clone(); + } + } + + private class TestThread extends Thread { + boolean srop = false; + boolean flag = false; + } + + private class TestThread1 extends TestThread { + + private Object lock; + + TestThread1(Object lock) { + this.lock = lock; + } + + public void run() { + try { + synchronized (lock) { + flag = true; + lock.wait(); + } + flag = false; + } catch (InterruptedException e) { + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/Package5Test.java vm/tests/kernel/java/lang/Package5Test.java new file mode 100644 index 0000000..6b7e744 --- /dev/null +++ vm/tests/kernel/java/lang/Package5Test.java @@ -0,0 +1,121 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +import java.lang.annotation.Annotation; +import java.lang.pkg3.Pkg3Antn; +import java.lang.pkg3.pkg31.Pkg31Antn; +import java.lang.reflect.AnnotatedElement; + +import org.apache.harmony.lang.AnnotatedElementTestFrame; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class Package5Test extends AnnotatedElementTestFrame { + + public static void main(String[] args) { + junit.textui.TestRunner.run(Package5Test.class); + } + + static { + try { + Class.forName("java.lang.pkg1.Bogus"); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Class.forName("java.lang.pkg2.Bogus"); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Class.forName("java.lang.pkg4.Bogus"); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Class.forName("java.lang.pkg5.Bogus"); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Class.forName("java.lang.pkg6.Bogus"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected @Override AnnotatedElement getElement1() throws Throwable { + Package p = Package.getPackage("java.lang.pkg1"); + assertNotNull("failed to get annotated pkg1", p); + return p; + } + + protected @Override AnnotatedElement getElement2() throws Throwable { + Package p = Package.getPackage("java.lang.pkg2"); + assertNotNull("failed to get annotated pkg2", p); + return p; + } + + protected @Override AnnotatedElement getElement3() throws Throwable { + Package p = Package.getPackage("java.lang"); + assertNotNull("failed to get package", p); + return p; + } + + protected @Override AnnotatedElement getElement4() throws Throwable { + Package p = Package.getPackage("java.lang.pkg4"); + assertNotNull("failed to get annotated pkg5", p); + return p; + } + + protected @Override AnnotatedElement getElement5() throws Throwable { + Package p = Package.getPackage("java.lang.pkg5"); + assertNotNull("failed to get annotated pkg5", p); + return p; + } + + protected @Override AnnotatedElement getElement6() throws Throwable { + Package p = Package.getPackage("java.lang.pkg6"); + assertNotNull("failed to get annotated pkg6", p); + return p; + } + + /** + * Package should not be awared of annotations of nested + * or "super" packages. + */ + public void testNoInheritance() throws Throwable { + Class.forName("java.lang.pkg3.Bogus"); + Class.forName("java.lang.pkg3.pkg31.Bogus"); + Package pkg3 = Package.getPackage("java.lang.pkg3"); + assertNotNull("pkg3", pkg3); + Annotation[] an = pkg3.getAnnotations(); + assertNotNull("all in pkg3", an); + assertEquals("number of Annotations in pkg3", 1, an.length); + assertNotNull("annotation of pkg3", pkg3.getAnnotation(Pkg3Antn.class)); + + Package pkg31 = Package.getPackage("java.lang.pkg3.pkg31"); + assertNotNull("pkg31", pkg31); + Annotation[] an2 = pkg31.getAnnotations(); + assertNotNull("all in pkg31", an2); + assertEquals("number of Annotations in pkg31", 1, an2.length); + assertTrue("annotation of pkg31", pkg31.isAnnotationPresent(Pkg31Antn.class)); + } +} diff --git vm/tests/kernel/java/lang/PackageAccessible.java vm/tests/kernel/java/lang/PackageAccessible.java new file mode 100644 index 0000000..3e6d730 --- /dev/null +++ vm/tests/kernel/java/lang/PackageAccessible.java @@ -0,0 +1,36 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +public class PackageAccessible { + + public PackageAccessible() { + } + + static public Object getProtectedClassInstance() { + return new PackageAccessible.A(); + } + + static class A { + public A() { + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/PackageTest.java vm/tests/kernel/java/lang/PackageTest.java new file mode 100644 index 0000000..f35131b --- /dev/null +++ vm/tests/kernel/java/lang/PackageTest.java @@ -0,0 +1,308 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on 02.02.2006 + * + * This PackageTest class is used to test the Core API java.lang.Package + * class + * + */ + +public class PackageTest extends TestCase { + + static String vendor = System.getProperty("java.vm.vendor"); + + /** + * + */ + public void test_getImplementationTitle_V() { + //System.out.println("test_getImplementationTitle_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getImplementationTitle(); + if (s == null) + return; + if (vendor.equals("Sun Microsystems Inc.")) { + assertEquals("Error1: unexpected title:", + "Java Runtime Environment", s); + } else if (vendor.equals("BEA Systems, Inc.")) { + assertEquals("Error2: unexpected title:", "...", s); + } else if (vendor.equals("Intel DRL")) { + assertEquals("Error3: unexpected title:", "...", s); + } + } + + /** + * + */ + public void test_getImplementationVendor_V() { + //System.out.println("test_getImplementationVendor_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getImplementationVendor(); + if (s == null) + return; // XXX:It's not explained by spec + if (vendor.equals("Sun Microsystems Inc.")) { + assertEquals("Error1: unexpected vendor:", + "Sun Microsystems, Inc.", s); + } else if (vendor.equals("BEA Systems, Inc.")) { + assertEquals("Error2: unexpected vendor:", "...", s); + } else if (vendor.equals("Intel DRL")) { + assertEquals("Error3: unexpected vendor:", "...", s); + } + } + + /** + * + */ + public void test_getImplementationVersion_V() { + //System.out.println("test_getImplementationVersion_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getImplementationVersion(); + if (s == null) + return; + assertTrue("unexpected implementation version: " + s, + s.matches("[[0-9]._]+")); + } + + /** + * + */ + public void test_getName_V() { + //System.out.println("test_getName_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getName(); + assertEquals("unexpected name", "java.lang", s); + } + + /** + * + */ + public void test_getPackage_Str_1() { + //System.out.println("test_getPackage_Str_1"); + assertNull("null expected", + Package.getPackage("ABSOLUTELY.UNKNOWN.PACKAGE")); + } + + /** + * + */ + public void test_getPackage_Str_2() { + //System.out.println("test_getPackage_Str_2"); + try { + Package.getPackage((String)null); + fail("NullPointerException should be thrown"); + } catch (NullPointerException _) { + return; + } + } + + /** + * + */ + public void test_getPackage_Str_3() { + //System.out.println("test_getPackage_Str"); + Package p = Package.getPackage("java.lang"); + if (p == null) + return; + String s = p.getName(); + assertEquals("unexpected package", "java.lang", s); + } + + /** + * + */ + public void test_getPackages_V() { + //System.out.println("test_getPackages_V"); + Package ap[] = Package.getPackages(); + for (int i = 0; i < ap.length; i++) { + if (ap[i].getName().indexOf("java.lang") != -1) + return; + } + fail("at least java.lang should be returned"); + } + + /** + * + */ + public void test_getSpecificationTitle_V() { + //System.out.println("test_getSpecificationTitle_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getSpecificationTitle(); + if (s == null) + return; + String specName = System.getProperty("java.specification.name"); + assertEquals("unexpected specification title:", specName, s); + } + + /** + * + */ + public void test_getSpecificationVendor_V() { + //System.out.println("test_getSpecificationVendor_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getSpecificationVendor(); + if (s == null) + return; + assertEquals("unexpected specification vendor:", + "Sun Microsystems, Inc.", s); + } + + /** + * + */ + public void test_getSpecificationVersion_V() { + //System.out.println("test_getSpecificationVersion_V"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getSpecificationVersion(); + if (s == null) + return; + assertTrue("unexpected specification version: " + s, + s.matches("([0-9]+?\\.)\\*?[0-9]+?")); + } + + /** + * + */ + public void test_hashCode_V() { + //System.out.println("test_hashCode_V"); + Package p1 = java.lang.Character.class.getPackage(); + Package p2 = java.io.File.class.getPackage(); + if (p1 == null || p2 == null) + return; + assertTrue("hash codes should differ", p1.hashCode() != p2.hashCode()); + } + + /** + * + */ +// Commented because of the drvm issue. + public void te_st_isCompatibleWith_Str_1() { + //System.out.println("test_isCompatibleWith_Str_1"); + Package p = Package.getPackage("java.lang"); + if (p == null) + return; + try { + p.isCompatibleWith(""); + } catch (NumberFormatException _) { + } catch (Throwable e) { + fail("unexpected error: " + e.toString()); + } + } + + /** + * + */ + public void test_isCompatibleWith_Str_2() { + //System.out.println("test_isCompatibleWith_Str_2"); + Package p = java.lang.Character.class.getPackage(); + if (p == null) + return; + String s = p.getSpecificationVersion(); + if (s == null) + return; + try { + assertTrue("should be compatible with its own spec version", + p.isCompatibleWith(s)); + } catch (NumberFormatException _) { + fail("wrong version format"); + } + } + + /** + * + */ + public void test_isSealed_V() { + //System.out.println("test_isSealed_V"); + Package p1 = java.lang.Character.class.getPackage(); + Package p2 = java.lang.Void.class.getPackage(); + if (p1 == null || p2 == null) + return; + assertEquals("values should be equal", p1.isSealed(), p2.isSealed()); + } + + /** + * + */ + public void test_isSealed_URL_1() { + //System.out.println("test_isSealed_URL_1"); + try { + Package p1 = java.lang.Character.class.getPackage(); + Package p2 = java.lang.Void.class.getPackage(); + if (p1 == null || p2 == null) + return; + java.net.URL url = new java.net.URL("http://intel.com/"); + assertEquals("values should be equal", + p1.isSealed(url), p2.isSealed(url)); + } catch (java.net.MalformedURLException _) { + fail("unexpected MalformedURLException"); + } + } + + /** + * + */ +// Commented because of the drvm issue. + public void te_st_isSealed_URL_2() { + //System.out.println("test_isSealed_URL_2"); + try { + Package p = Package.getPackage("java.lang"); + if (p == null) + return; + p.isSealed((java.net.URL) null); + fail("NullPointerException has not been thrown"); + } catch (NullPointerException _) { + return; + } + } + + /** + * + */ + public void test_toString_V() { + //System.out.println("test_toString_V"); + Package p = PackageTest.class.getPackage(); + if (p == null) + return; + //assertTrue("Error1"+p.toString(), p.toString().equals("package "+" + // "+p.getName()+", "+p.getSpecificationTitle()+", + // "+p.getImplementationVersion())); + assertTrue("unexpected: package name must be printed: " + p.toString(), + p.toString().indexOf("package " + p.getName()) != -1); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/PrivateConstructor.java vm/tests/kernel/java/lang/PrivateConstructor.java new file mode 100644 index 0000000..3452e8a --- /dev/null +++ vm/tests/kernel/java/lang/PrivateConstructor.java @@ -0,0 +1,27 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +public class PrivateConstructor { + + private PrivateConstructor() { + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ProtectedConstructor.java vm/tests/kernel/java/lang/ProtectedConstructor.java new file mode 100644 index 0000000..63d0ef9 --- /dev/null +++ vm/tests/kernel/java/lang/ProtectedConstructor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov, Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +public class ProtectedConstructor { + + int j; + + protected ProtectedConstructor() { + j = -2; + } +} diff --git vm/tests/kernel/java/lang/RuntimeAdditionalSupport1.java vm/tests/kernel/java/lang/RuntimeAdditionalSupport1.java new file mode 100644 index 0000000..d5ac9fb --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalSupport1.java @@ -0,0 +1,43 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; +/* + * Created on 03.29.2006 + * + * This RuntimeAdditionalSupport1Test class is used to support + * RuntimeAdditionalSupport2Test + */ + +public class RuntimeAdditionalSupport1 extends TestCase { + public static boolean openingFlag = false; // to avoid tests failures because of 1.5 eclipse compiler bugs + public static void main(String[] args) { + Runtime.getRuntime().exit(Integer.parseInt(args[0])); + } + + /** + * stupid test to cheat the tutor + */ + public void test_1() { + } +} diff --git vm/tests/kernel/java/lang/RuntimeAdditionalSupport2.java vm/tests/kernel/java/lang/RuntimeAdditionalSupport2.java new file mode 100644 index 0000000..e788f58 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalSupport2.java @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; +/* + * Created on 03.29.2006 + * + * This RuntimeAdditionalSupport2Test class is used to support + * RuntimeAdditionalSupport2Test + */ + +public class RuntimeAdditionalSupport2 extends TestCase { + public static void main(String[] args) throws java.io.IOException { + System.out.println("!!! RuntimeAdditionalSupport2Test started !!!"); + System.out.flush(); + System.err.println("!!!!!!"); + System.err.flush(); + while(true){ + int c = System.in.read(); + ((java.io.OutputStream)System.out).write(c); + } + } + protected void finalize() throws Throwable { + super.finalize(); + System.out.println("!!! RuntimeAdditionalSupport2Test finished !!!"); + System.out.flush(); + } + + /** + * stupid test to cheat the tutor + */ + public void test_1() { + } +} diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest0.java vm/tests/kernel/java/lang/RuntimeAdditionalTest0.java new file mode 100644 index 0000000..ef8787c --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest0.java @@ -0,0 +1,624 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest0 extends TestCase { + public static String os; + + public static String cm = null; + public static String javaStarter = "java"; + public static String catStarter = null; + public static String treeStarter = null; + public static String psStarter = null; + public static String killStarter = null; + static { + if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) { + os = "Win"; + String pathList = System.getProperty("java.library.path"); + String[] paths = pathList.split(File.pathSeparator); + int ind1; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + File asf = new java.io.File(paths[ind1] + File.separator + + "cmd.exe"); + if (asf.exists()) { + cm = paths[ind1] + File.separator + "cmd.exe"; + break; + } + asf = new java.io.File(paths[ind1] + File.separator + + "cat.exe"); + if (asf.exists()) { + catStarter = paths[ind1] + File.separator + "cat.exe"; + break; + } + asf = new java.io.File(paths[ind1] + File.separator + + "tree.com"); + if (asf.exists()) { + treeStarter = paths[ind1] + File.separator + "tree.com"; + break; + } + asf = new java.io.File(paths[ind1] + File.separator + + "ps.exe"); + if (asf.exists()) { + psStarter = paths[ind1] + File.separator + "ps.exe"; + break; + } + asf = new java.io.File(paths[ind1] + File.separator + + "kill.exe"); + if (asf.exists()) { + killStarter = paths[ind1] + File.separator + "kill.exe"; + break; + } + } + + if (cm == null) { + if (new java.io.File((cm = "C:\\WINNT\\system32\\cmd.exe")) + .exists()) { + } else if (new java.io.File( + (cm = "C:\\WINDOWS\\system32\\cmd.exe")).exists()) { + } else { + cm = "cmd.exe"; + System.out + .println("### WARNING: cmd.exe hasn't been found! Please, set the path to cmd.exe via java.library.path property."); + } + } + + if (catStarter == null) { + if (new java.io.File((catStarter = "C:\\WINNT\\system32\\cat.exe")) + .exists()) { + } else if (new java.io.File( + (catStarter = "C:\\WINDOWS\\system32\\cat.exe")).exists()) { + } else if (new java.io.File( + (catStarter = "C:\\CygWin\\bin\\cat.exe")).exists()) { + } else { + cm = "cat.exe"; + System.out + .println("### WARNING: cat.exe hasn't been found! Please, set the path to cat.exe via java.library.path property."); + } + } + + if (treeStarter == null) { + if (new java.io.File((treeStarter = "C:\\WINNT\\system32\\tree.com")) + .exists()) { + } else if (new java.io.File( + (treeStarter = "C:\\WINDOWS\\system32\\tree.com")).exists()) { + } else { + treeStarter = "tree.com"; + System.out + .println("### WARNING: tree.com hasn't been found! Please, set the path to tree.com via java.library.path property."); + } + } + + if (psStarter == null) { + if (new java.io.File((psStarter = "C:\\WINNT\\system32\\ps.exe")) + .exists()) { + } else if (new java.io.File( + (psStarter = "C:\\WINDOWS\\system32\\ps.exe")).exists()) { + } else if (new java.io.File( + (psStarter = "C:\\CygWin\\bin\\ps.exe")).exists()) { + } else { + psStarter = "ps.exe"; + System.out + .println("### WARNING: ps.exe hasn't been found! Please, set the path to ps.exe via java.library.path property."); + } + } + + if (killStarter == null) { + if (new java.io.File((killStarter = "C:\\WINNT\\system32\\kill.exe")) + .exists()) { + } else if (new java.io.File( + (killStarter = "C:\\WINDOWS\\system32\\kill.exe")).exists()) { + } else if (new java.io.File( + (killStarter = "C:\\CygWin\\bin\\kill.exe")).exists()) { + } else { + killStarter = "kill.exe"; + System.out + .println("### WARNING: kill.exe hasn't been found! Please, set the path to kill.exe via java.library.path property."); + } + } + + javaStarter = "java"; + } else if (System.getProperty("os.name").toLowerCase().indexOf("linux") != -1) { + os = "Lin"; + cm = "/bin/sh"; + try { + Process proc = null; + try { + proc = Runtime.getRuntime().exec(new String[]{"find", "/usr", "-name", "java"}); + } catch (java.io.IOException e) { proc = Runtime.getRuntime().exec(new String[]{"/usr/bin/find", "/usr", "-name", "java"}); + } + java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader( + proc.getInputStream())); String rV; + while((rV = br.readLine())!=null && !rV.endsWith("/jre/bin/java")) { + } if(rV!=null) { + javaStarter = "/usr/jrockit-j2sdk1.4.2_04/jre/bin/java"; + javaStarter = "/usr/lib/java/jre/bin/java"; + javaStarter = rV; + } else { /* + String pathList = System.getProperty("java.library.path"); + String[] paths = pathList.split(File.pathSeparator); + int ind1; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + File asf = new java.io.File(paths[ind1] + File.separator + + "java"); + if (asf.exists()) { + javaStarter = paths[ind1] + File.separator + "java"; + break; + } + } */ + javaStarter = "/usr/lib/java/jre/bin/java"; // last hope :) + } System.out.println(javaStarter); } catch (java.io.IOException e) { + System.out + .println("### WARNING: Some needed external java hasn't been found! A lot of RuntimeAdditionalTest* can fail due to this reason!"); + //System.out + // .println("### WARNING: java hasn't been found! You can set the path to java, for example, via java.library.path property."); + } + try { + Process proc = null; + try { + proc = Runtime.getRuntime().exec(new String[]{"find", "/usr", "-name", "tree"}); + } catch (java.io.IOException e) { proc = Runtime.getRuntime().exec(new String[]{"/usr/bin/find", "/usr", "-name", "tree"}); + } + java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader( + proc.getInputStream())); String rV; + while((rV = br.readLine())!=null && !rV.endsWith("/bin/tree")) { + } if(rV!=null) { + treeStarter = rV; + } else { treeStarter = "/usr/bin/tree"; // last hope + } System.out.println(treeStarter); } catch (java.io.IOException e) { + System.out + .println("### WARNING: tree command hasn't been found! A lot of RuntimeAdditionalTest* can fail due to this reason!"); + } + try { + Process proc = null; + try { + proc = Runtime.getRuntime().exec(new String[]{"find", "/usr", "-name", "cat"}); + } catch (java.io.IOException e) { proc = Runtime.getRuntime().exec(new String[]{"/usr/bin/find", "/usr", "-name", "cat"}); + } + java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader( + proc.getInputStream())); String rV; + while((rV = br.readLine())!=null && !rV.endsWith("/bin/cat")) { + } if(rV!=null) { + catStarter = rV; + } else { catStarter = "/bin/cat"; // last hope + } System.out.println(catStarter); } catch (java.io.IOException e) { + System.out + .println("### WARNING: tree command hasn't been found! A lot of RuntimeAdditionalTest* can fail due to this reason!"); + } + try { + Process proc = null; + try { + proc = Runtime.getRuntime().exec(new String[]{"find", "/usr", "-name", "ps"}); + } catch (java.io.IOException e) { proc = Runtime.getRuntime().exec(new String[]{"/usr/bin/find", "/usr", "-name", "ps"}); + } + java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader( + proc.getInputStream())); String rV; + while((rV = br.readLine())!=null && !rV.endsWith("/bin/ps")) { + } if(rV!=null) { + psStarter = rV; + } else { psStarter = "/bin/ps"; // last hope + } //psStarter = "/bin/ps"; // last hope + System.out.println(psStarter); } catch (java.io.IOException e) { + System.out + .println("### WARNING: tree command hasn't been found! A lot of RuntimeAdditionalTest* can fail due to this reason!"); + } + try { + Process proc = null; + try { + proc = Runtime.getRuntime().exec(new String[]{"find", "/usr", "-name", "kill"}); + } catch (java.io.IOException e) { proc = Runtime.getRuntime().exec(new String[]{"/usr/bin/find", "/usr", "-name", "kill"}); + } + java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader( + proc.getInputStream())); String rV; + while((rV = br.readLine())!=null && !rV.endsWith("/bin/kill")) { + } if(rV!=null) { + killStarter = rV; + } else { killStarter = "/bin/kill"; // last hope + } System.out.println(killStarter); } catch (java.io.IOException e) { + System.out + .println("### WARNING: tree command hasn't been found! A lot of RuntimeAdditionalTest* can fail due to this reason!"); + } + } else { + os = "Unk"; + } + + } + + private static File seekFileInDirsHierarchic(File dirToFind, + String extension, int size) { + File af[] = dirToFind.listFiles(); + if (af == null) + return null; + File dirs[] = new File[af.length]; + File res = null; + int j = 0; + int i = 0; + try { + for (i = 0; i < af.length; i++) { + if (af[i].isFile() && af[i].getName().endsWith(extension) && af[i].getName().indexOf(" ") == -1 + && af[i].length() > size && (1.5 * size) > af[i].length()) { + return af[i]; + } else if (af[i].isDirectory()) { + dirs[j++] = af[i]; + } + } + for (i = 0; i < j; i++) { + if ((res = seekFileInDirsHierarchic(dirs[i], extension, size)) != null) { + return res; + } + } + } catch (NullPointerException e) { + e.printStackTrace(); + } + return null; + } + + public static String textFile; + static int fileLength = 7000/(os.equals("Lin")?2:1); //10000; //50000; + static { + File f = null; + if (os.equals("Win")) { + if ((f = seekFileInDirsHierarchic(new File("C:\\Program Files"), + ".txt", fileLength)) != null) { + textFile = f.getAbsolutePath(); + } + } else if (os.equals("Lin")) { + if ((f = seekFileInDirsHierarchic(new File("/opt"), ".txt", fileLength)) != null) { + textFile = f.getAbsolutePath(); + } + if (textFile == null) { + if ((f = seekFileInDirsHierarchic(new File("/usr"), ".txt", + fileLength)) != null) { + textFile = f.getAbsolutePath(); + } + } + } else { + textFile = null; + } + if (textFile == null) + System.out + .println("### WARNING: *.txt file hasn't been found! Tests aren't able for correct run."); + System.out.println(textFile); + } + + public static String libFile; + static { + File f = null; + if (os.equals("Win")) { + if ((f = seekFileInDirsHierarchic(new File("C:\\Program Files"), + ".dll", fileLength)) != null) { + libFile = f.getAbsolutePath(); + } + } else if (os.equals("Lin")) { + if ((f = seekFileInDirsHierarchic(new File("/opt"), ".so", fileLength)) != null) { + libFile = f.getAbsolutePath(); + } + if (libFile == null) { + if ((f = seekFileInDirsHierarchic(new File("/usr"), ".so", + fileLength)) != null) { + libFile = f.getAbsolutePath(); + } + } + if (libFile == null) { + if ((f = seekFileInDirsHierarchic(new File("/lib"), ".so", + fileLength)) != null) { + libFile = f.getAbsolutePath(); + } + } + } else { + libFile = null; + } + if (libFile == null) + System.out + .println("### WARNING: *.dll|so file hasn't been found! Tests aren't able for correct run."); + System.out.println(libFile); + } + + /* + * static String exeFile; static { File f = null; if (os.equals("Win")) { if + * ((f = seekFileInDirsHierarchic(new File("C:\\Program Files"), ".exe", + * fileLength)) != null ) { exeFile = f.getAbsolutePath(); } } else if + * (os.equals("Lin")){ if ((f = seekFileInDirsHierarchic(new File("/opt"), + * ".exe", fileLength)) != null ) { exeFile = f.getAbsolutePath(); } if (exeFile == + * null) { if ((f = seekFileInDirsHierarchic(new File("/usr"), ".exe", + * fileLength)) != null ) { exeFile = f.getAbsolutePath(); } } } else { exeFile = + * null; } if (exeFile == null) System.out.println("### WARNING: *.exe file + * hasn't been found! Tests aren't able for correct run."); + * System.out.println(exeFile); } + */ + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + /** + * using the InputStream.read, OutputStream.write; chain of Process.waitFor, + * Process.destroy, Process.waitFor, Process.exitValue + */ + public void test_1() { + System.out.println("==test_1==="); + String cmnd = null; + if (os.equals("Win")) { + cmnd = cm + " /C date"; + } else if (os.equals("Lin")) { + cmnd = "sh -c \"sh -version\""; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + if (os.equals("Win")) { + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + java.io.OutputStream os = pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + if (is.available() < 1) { + fail("ERROR (test_1): input stream is empty(1)."); + } + int ia = is.available(); + byte[] bb = new byte[ia]; + is.read(bb); + String r1 = new String(bb); + if (r1.indexOf("The current date is") == -1 + || r1.indexOf("Enter the new date") == -1) { + fail("ERROR (test_1): unexpected message(1)."); + } + for (int ii = 0; ii < ia; ii++) { + bb[ii] = (byte) 0; + } + + os.write('x'); + os.write('x'); + os.write('-'); + os.write('x'); + os.write('x'); + os.write('-'); + os.write('x'); + os.write('x'); + os.write('\n'); + os.flush(); + + try { + Thread.sleep(2000); + } catch (Exception e) { + } + if (is.available() < 1) { + fail("ERROR (test_1): input stream is empty(2)."); + } + ia = is.available(); + byte[] bbb = new byte[ia]; + is.read(bbb); + r1 = new String(bbb); + if (r1.indexOf("The system cannot accept the date entered") == -1 + && r1.indexOf("Enter the new date") == -1) { + fail("ERROR (test_1): unexpected message(2)."); + } + os.write('\n'); + try { + pi3.exitValue(); + } catch (IllegalThreadStateException e) { + os.flush(); + try { + pi3.waitFor(); + } catch (InterruptedException ee) { + } + } + /*System.out.println(*/pi3.waitFor()/*)*/; + pi3.destroy(); + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_1): unexpected exception."); + } + } else if (os.equals("Lin")) { + try { + //Process pi3 = Runtime.getRuntime().exec("sh -c \"sh + // -version\""); + Process pi3 = Runtime.getRuntime().exec("sh -c date"); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + try { + Thread.sleep(1000); + } catch (Exception e) { + } + if (is.available() < 1) { + fail("ERROR (test_1): input stream is empty(1)."); + } + int ia = is.available(); + byte[] bb = new byte[ia]; + is.read(bb); + String r1 = new String(bb); + if (r1.indexOf("S") == -1 && r1.indexOf("M") == -1 + && r1.indexOf("T") == -1 && r1.indexOf("W") == -1 + && r1.indexOf("F") == -1) { + fail("ERROR (test_1): unexpected message(1)." + r1); + } + for (int ii = 0; ii < ia; ii++) { + bb[ii] = (byte) 0; + } + + Process pi4 = Runtime.getRuntime().exec("sh -c sh"); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + pi4.getInputStream(); + + try { + Thread.sleep(1000); + } catch (Exception e) { + } + try { + pi4.exitValue(); + fail("ERROR (test_1): process should exist."); + } catch (IllegalThreadStateException e) { + } + os4.write('e'); + os4.write('x'); + os4.write('i'); + os4.write('t'); + os4.write('\n'); + os4.flush(); + try { + Thread.sleep(1000); + } catch (Exception e) { + } + try { + pi4.exitValue(); + } catch (IllegalThreadStateException e) { + fail("ERROR (test_1): process should be destroyed."); + } + /*System.out.println(*/pi4.waitFor()/*)*/; + pi4.destroy(); + /*System.out.println(*/pi4.waitFor()/*)*/; + /*System.out.println(*/pi4.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_1): unexpected exception."); + } + } + } + ////////////// Common additional service: /////////////// + static java.io.DataOutputStream ps = null; + static { + try{ + //String str = ":>"; + File fff = null; + //fff = new java.io.File("C:\\IJE\\orp\\ZSS\\___ttttt"+System.getProperty("java.vm.name")+".txt"); + //fff = new java.io.File("/nfs/ins/proj/drl/coreapi/ZSS/DRL_VM/___ttttt"+System.getProperty("java.vm.name")+".txt"); + fff = new File(System.getProperty("java.io.tmpdir")+File.separator+"_messageOf_"+((System.getProperty("java.vm.name").indexOf("DRL")!=-1)?System.getProperty("java.vm.name"):"XXX")+"_"+System.getProperty("user.name")+".txt"); + fff.createNewFile(); + ps = new java.io.DataOutputStream(new java.io.FileOutputStream(fff)); + //ps.writeBytes(System.getProperties().toString()); + //new Throwable().printStackTrace(ps); + }catch(Throwable e){ + //if(System.getProperty("java.vm.name").indexOf("DRL")!=-1){int i=0,j=0; i=i/j;} + } + } + + static void doMessage(String mess){ + //ps.println(mess); + try { + ps.writeBytes(mess); + } catch (java.io.IOException ee) {} + } + + static void killCat() { + try{ + //String cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C ps -Ws":RuntimeAdditionalTest0.cm + " -c \"ps -ef\""; + //String cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?"C:\\CygWin\\bin\\ps -Ws":RuntimeAdditionalTest0.cm + " -c \"ps -ef\""; + //String cmnd1 = RuntimeAdditionalTest0.psStarter+(RuntimeAdditionalTest0.os.equals("Win")?" -Ws":" -ef"); + /**/String cmnd1 = RuntimeAdditionalTest0.psStarter+(RuntimeAdditionalTest0.os.equals("Win")?" -Ws":" -U "+System.getProperty("user.name")); + Process pi5 = Runtime.getRuntime().exec(cmnd1); + BufferedReader br = new BufferedReader(new InputStreamReader(pi5 + .getInputStream())); + boolean flg = true; + String procValue = null; + while (!br.ready()) {} + while ((procValue = br.readLine()) != null) { +RuntimeAdditionalTest0.doMessage("9:"+procValue+"\n"); if (procValue.indexOf("cat") != -1 /*&& (RuntimeAdditionalTest0.os.equals("Win")?true:procValue.indexOf(System.getProperty("user.name")) != -1)*/) { + flg = false; + break; + } + } + if (!flg) { + String as[] = procValue.split(" "); +RuntimeAdditionalTest0.doMessage("XX:"+procValue+"\n"); for (int i = 0; i < as.length; i++) { + if(as[i].matches("\\d+")){ + //cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C kill "+as[i]:RuntimeAdditionalTest0.cm + " -c \"kill "+as[i]+"\""; + //cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?"C:\\WINNT\\system32\\kill "+as[i]:RuntimeAdditionalTest0.cm + " -c \"kill "+as[i]+"\""; + cmnd1 = RuntimeAdditionalTest0.killStarter+(RuntimeAdditionalTest0.os.equals("Win")?"":" -9")+" "+as[i]; +RuntimeAdditionalTest0.doMessage("XXX:"+cmnd1+"\n"); Runtime.getRuntime().exec(cmnd1); + Thread.sleep(3000); + } + } + } + }catch(Exception e){ + fail("ERROR killCat: unexpected exception: "+e.toString()); + } + } + + static void killTree() { + try{ + //String cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C ps -Ws":RuntimeAdditionalTest0.cm + " -c \"ps -ef\""; + //String cmnd1 = RuntimeAdditionalTest0.psStarter+(RuntimeAdditionalTest0.os.equals("Win")?" -Ws":" -ef"); + /**/String cmnd1 = RuntimeAdditionalTest0.psStarter+(RuntimeAdditionalTest0.os.equals("Win")?" -Ws":" -U "+System.getProperty("user.name")); + Process pi5 = Runtime.getRuntime().exec(cmnd1); + BufferedReader br = new BufferedReader(new InputStreamReader(pi5 + .getInputStream())); + boolean flg = true; + String procValue = null; + while (!br.ready()) {} + while ((procValue = br.readLine()) != null) { + if (procValue.indexOf("tree") != -1 /*&& (RuntimeAdditionalTest0.os.equals("Win")?true:procValue.indexOf(System.getProperty("user.name")) != -1)*/) { + flg = false; + break; + } + } + if (!flg) { + String as[] = procValue.split(" "); + for (int i = 0; i < as.length; i++) { + if(as[i].matches("\\d+")){ + //cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C kill "+as[i]:RuntimeAdditionalTest0.cm + " -c \"kill "+as[i]+"\""; + cmnd1 = RuntimeAdditionalTest0.killStarter+(RuntimeAdditionalTest0.os.equals("Win")?"":" -9")+" "+as[i]; + Runtime.getRuntime().exec(cmnd1); + Thread.sleep(3000); + } + } + } + }catch(Exception e){ + fail("ERROR killTree: unexpected exception: "+e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest1.java vm/tests/kernel/java/lang/RuntimeAdditionalTest1.java new file mode 100644 index 0000000..ff71d3d --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest1.java @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest1 extends TestCase { + /** + * destroy java process then chain of Process.waitFor, Process.exitValue, + * Process.exitValue + */ + public void test_2() { + System.out.println("==test_2==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_2): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.destroy(); + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_2): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest10.java vm/tests/kernel/java/lang/RuntimeAdditionalTest10.java new file mode 100644 index 0000000..a7105e8 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest10.java @@ -0,0 +1,208 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. should be adopted for linux + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest10 extends TestCase { + /** + * read, write info using streams of two process (cat <->java) using the + * "exitValue - IllegalThreadStateException" loop to try to read p1-out to + * write p2-in and to read p2-out again to calculate bytes to check their + * equality + */ + public void test_11() { + System.out.println("==test_11==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\IJE\\orp\\ZSS\\___LOG.1\""; + cmnd1 = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.textFile + "\""; + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\Documents and Settings\\All + // Users\\Documents\\My Pictures\\Sample Pictures\\Winter.jpg\""; + //cmnd2 = RuntimeAdditionalTest0.cm+" /C cat"; + //\\//\\cmnd2 = "java -cp + // \""+System.getProperty("java.class.path")+"\" RuntimeAdditionalSupport2"; +// cmnd2 = "java " +// + (System.getProperty("java.class.path").length() > 0 ? "-cp " +// + System.getProperty("java.class.path") +// : "") + " klazz2"; + String ttt = System.getProperty("vm.boot.class.path") +(System.getProperty("java.class.path").length() > 0 ? + File.pathSeparator + System.getProperty("java.class.path") : ""); + cmnd2 = RuntimeAdditionalTest0.javaStarter+" -Xbootclasspath/a:" + ttt + " -cp " + ttt + " java.lang.RuntimeAdditionalSupport2"; + // System.out.println(cmnd2); + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"cat -v /lib/ld.so\""; + //\\//\\cmnd1 = "cat -v /lib/ld.so"; + cmnd1 = "/bin/cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + //cmnd2 = "sh -c cat"; + //\\//\\cmnd2 = "java -cp + // \""+System.getProperty("java.class.path")+"\" RuntimeAdditionalSupport2"; +// cmnd2 = "java " +// + (System.getProperty("java.class.path").length() > 0 ? "-cp " +// + System.getProperty("java.class.path") +// : "") + " RuntimeAdditionalSupport2"; + String ttt = System.getProperty("vm.boot.class.path") +(System.getProperty("java.class.path").length() > 0 ? + File.pathSeparator + System.getProperty("java.class.path") : ""); + cmnd2 = RuntimeAdditionalTest0.javaStarter+" -Xbootclasspath/a:" + ttt + " -cp " + ttt + " java.lang.RuntimeAdditionalSupport2"; + //System.out.println(cmnd2); return; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + Process pi3 = null; + Process pi4 = null; + try { + pi3 = Runtime.getRuntime().exec(cmnd1); + pi4 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + while (is4.available() == 0) { + } + Thread.sleep(1000); + byte[] bbb5 = new byte[is4.available()]; + is4.read(bbb5); + //System.out.println(new String(bbb5)); + int c1 = 0; + int c2 = 0; + //int s1 = 0; + //int s2 = 0; + while (true) { + try { + while ((is.available()) != 0) { + os4.write(/*s1 = */is.read()); + c1++; + os4.write(10); + c1++; + try { + os4.flush(); + } catch (java.io.IOException e) { + } + /* System.out.println(Character.toString((char)( s2 =*/ is4 + .read()/* ))) */; + /* System.out.println(Character.toString((char)( s2 =*/ is4 + .read()/* ))) */; + c2 += 2; + /* + * while ((is4.available()) != 0) { c2++; + * System.out.println(Character.toString((char)(s2=is4.read()))); + * System.out.println(s1+"|"+s2); try { + * Thread.sleep(1000); } catch (Exception e) { } } + */ + } + //System.out.println(7777777); + pi3.exitValue(); + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + while (true) { + try { + while ((is4.available()) != 0) { + c2++; + /* System.out.println(Character.toString((char) */is4 + .read()/* )) */; + } + //System.out.println(888888); + if (c2 == c1) { + if ((is4.available()) == 0) { + //System.out.println("test_11 PASSED."); + } else { + fail("test_11 FAILED."); + } + try { + pi4.exitValue(); + } catch (IllegalThreadStateException e) { + pi4.destroy(); + return; + } + } else if (is4.available() == 0) { + int i = 0; + for (; i < 500; i++) { + if (is4.available() != 0) { + break; + } + try { + Thread.sleep(10); + } catch (Exception e) { + } + } + //System.out.println(i); + if (i == 500 && is4.available() == 0) { + //System.out.println(c1+"|"+c2); + try { + pi4.exitValue(); + } catch (IllegalThreadStateException e) { + pi4.destroy(); + } + fail("test_11 FAILED."); + } + } + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_11): unexpected exception."); + } + try { + pi3.exitValue(); + } catch (IllegalThreadStateException e) { + pi3.destroy(); + } + try { + pi4.exitValue(); + } catch (IllegalThreadStateException e) { + pi4.destroy(); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest11.java vm/tests/kernel/java/lang/RuntimeAdditionalTest11.java new file mode 100644 index 0000000..d23a59a --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest11.java @@ -0,0 +1,135 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest11 extends TestCase { + + /** + * read, write info using streams of two process (cat jpg/so <->cat) using + * the "exitValue - IllegalThreadStateException" loop to try to read p1-out + * to write p2-in and to read p2-out again + */ + public void test_11_1() { + System.out.println("==test_11_1==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\Documents and Settings\\All + // Users\\Documents\\My Pictures\\Sample Pictures\\Winter.jpg\""; + //cmnd1 = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.libFile + "\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + cmnd1 = RuntimeAdditionalTest0.catStarter + " \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"cat -v /lib/ld.so\""; + //\\//\\cmnd1 = "cat -v /lib/ld.so"; + //cmnd1 = "cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + //cmnd2 = "sh -c cat"; + //cmnd1 = RuntimeAdditionalTest0.catStarter + " -v \"" + RuntimeAdditionalTest0.textFile + "\""; + cmnd1 = "/bin/sh -c \"cat " + RuntimeAdditionalTest0.textFile + "\""; + cmnd1 = "/bin/cat \"" + RuntimeAdditionalTest0.textFile + "\""; + cmnd1 = "/bin/cat " + RuntimeAdditionalTest0.textFile; + //cmnd1 = "/usr/bin/pr " + RuntimeAdditionalTest0.textFile; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd1);RuntimeAdditionalTest0.doMessage(cmnd1+"\n");//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + //if(System.getProperty("java.vm.name").indexOf("DRL")!=-1){RuntimeAdditionalTest0.killCat();int i=0,j=0; i=i/j;} + //Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + //try { + // Thread.sleep(2000); + //} catch (Exception e) { + //} + //pi3.getOutputStream(); + //pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + ///**/RuntimeAdditionalTest0.doMessage("1:"+cmnd1+"\n"); while ((is.available()) == 0) {RuntimeAdditionalTest0.doMessage("1\n");}//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int ia; + int ia3 = 0; + while (true) {RuntimeAdditionalTest0.doMessage(Integer.toString(is.available(), 10)+"1\n"); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); +//System.out.println(new String(bbb)); //RuntimeAdditionalTest0.doMessage("2:"+new String(bbb)+"\n"); os4.write(bbb); + int ia2 = 0; + while (ia != is4.available()) { +/////////////////////////////////////////////////////////////////////////////////////// /**/ os4.flush(); //NU, JRK POGODI! /////////////////////////////////////////////////////////////////////////////////////// + ia2++; + if (ia2 > 5) { System.out.println("Warning (test_11): something wrong in the test - to investigate."); + //RuntimeAdditionalTest0.killCat(); break;//return; } + } + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); +System.out.println("zz|"+new String(bbb4)+"|zz"); //\\//\\System.out.println(new String(bbb4)); } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + if(ia3++>100){RuntimeAdditionalTest0.killCat();return;} + continue; + } + } } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_11): unexpected exception."); + } + RuntimeAdditionalTest0.killCat(); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest12.java vm/tests/kernel/java/lang/RuntimeAdditionalTest12.java new file mode 100644 index 0000000..8f79811 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest12.java @@ -0,0 +1,186 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest12 extends TestCase { + /** + * read, write info using streams of two process (cat txt/so <->cat) using + * the "exitValue - IllegalThreadStateException" loop to try to read p1-out + * to write p2-in and to read p2-out again + */ + public void test_12() { + System.out.println("==test_12==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd1 = RuntimeAdditionalTest0.cm+" /C cat + // \"C:\\IJE\\orp\\ZSS\\___LOG2.DO_VM_CLEAN no\""; + cmnd1 = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.textFile + "\""; + cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"cat -v /lib/ld.so\""; + //\\//\\cmnd1 = "cat -v /lib/ld.so"; + cmnd1 = "/bin/cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = "/bin/sh -c cat"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + Process pi3 = null; + Process pi4 = null; + java.io.OutputStream os = null; + java.io.InputStream es = null; + java.io.InputStream is = null; + java.io.OutputStream os4 = null; + java.io.InputStream es4 = null; + java.io.InputStream is4 = null; + try { + //Process pi3 = Runtime.getRuntime().exec(cmnd+" /C cat + // \"C:\\Documents and Settings\\All Users\\Documents\\My + // Pictures\\Sample Pictures\\Winter.jpg\""); + pi3 = Runtime.getRuntime().exec(cmnd1); + pi4 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + os = pi3.getOutputStream(); + es = pi3.getErrorStream(); + is = pi3.getInputStream(); + os4 = pi4.getOutputStream(); + es4 = pi4.getErrorStream(); + is4 = pi4.getInputStream(); + + int ia; + while (true) { + while ((ia = is.available()) != 0) { + ///System.out.println(111); + byte[] bbb = new byte[ia]; + is.read(bbb); + ///System.out.println(111.1); + os4.write(bbb); + int ia2 = 0; + while (ia != is4.available()) { + os4.flush(); + //System.out.println(111.3); + ia2++; + if (ia2 > 10000) { + fail("ERROR (test_12): something wrong in the test - to investigate."); + } + } + ///System.out.println(111.2); + while ((ia = is4.available()) != 0) { + ///System.out.println(222); + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + ///System.out.println(333); + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + //System.out.println(444); + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_12): unexpected exception."); + } + if (!RuntimeAdditionalSupport1.openingFlag) { // to remember about the issue in Process.destroy() implementation + try{ + os.close(); + es.close(); + is.close(); + os4.close(); + es4.close(); + is4.close(); + pi3.destroy(); + pi4.destroy(); + pi3.exitValue(); + pi4.exitValue(); + cmnd1 = RuntimeAdditionalTest0.cm + " /C ps -ef"; + Process pi5 = Runtime.getRuntime().exec(cmnd1); + BufferedReader br = new BufferedReader(new InputStreamReader(pi5 + .getInputStream())); + boolean flg = true; + String procValue = null; + while ((procValue = br.readLine()) != null) { + if (procValue.indexOf("cat") != -1) { + System.out.println(111); + flg = false; + break; + } + } + if (flg) { + return; + } + String as[] = procValue.split(" "); + for (int i = 0; i < as.length; i++) { + if(as[i].matches("\\d+")){ + System.out.println(222); + cmnd1 = RuntimeAdditionalTest0.cm + " /C kill "+as[i]; + Runtime.getRuntime().exec(cmnd1); + Thread.sleep(3000); + } + } + }catch(Exception e){ + fail("ERROR (test_14): unexpected exception: "+e.toString()); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest13.java vm/tests/kernel/java/lang/RuntimeAdditionalTest13.java new file mode 100644 index 0000000..5d943c9 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest13.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest13 extends TestCase { + /** + * creation of process for incorrect command should lead to IOException then + * get Streams of such process should lead to NPE + */ + public void test_13() { + System.out.println("==test_13==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_13): unknown operating system."); + } + Process pi3 = null; + try { + String cmnd = "XjavaX"; + pi3 = Runtime.getRuntime().exec(cmnd); + } catch (Exception eeee) { + try { + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + } catch (NullPointerException e) { + return; + } + } + fail("FAILED: test_13"); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest14.java vm/tests/kernel/java/lang/RuntimeAdditionalTest14.java new file mode 100644 index 0000000..93e2c4a --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest14.java @@ -0,0 +1,77 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest14 extends TestCase { + /** + * reading the streams after destroy + */ + public void test_14() { + System.out.println("==test_14==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_14): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + pi3.destroy(); + Thread.sleep(5000); + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_14): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest15.java vm/tests/kernel/java/lang/RuntimeAdditionalTest15.java new file mode 100644 index 0000000..80c6a29 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest15.java @@ -0,0 +1,100 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; +import java.io.IOException; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest15 extends TestCase { + /** + * creation and destroying a lot of jvm-processes getting their streams + */ + public void test_15() { + System.out.println("==test_15==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_15): unknown operating system."); + } + int ia = 0; + String cmnd = RuntimeAdditionalTest0.javaStarter; + while (ia++ < 5/*100*//*300*//*3000*/) { + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + Process pi32 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + Process pi33 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + Process pi34 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + Process pi35 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + Process pi36 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + pi3.getInputStream(); + pi3.destroy(); + pi32.destroy(); + pi33.destroy(); + pi34.destroy(); + pi35.destroy(); + pi36.destroy(); + Thread.sleep(50); + pi3.getOutputStream(); + pi3.getErrorStream(); + is = pi3.getInputStream(); + try { + is.available(); + } catch (IOException _) { + } + } catch (Exception eeee) { + System.out.println("=="+ia+"==="); + eeee.printStackTrace(); + if (ia == 1) fail("ERROR (test_15): unexpected exception just at the first java invocation."); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest16.java vm/tests/kernel/java/lang/RuntimeAdditionalTest16.java new file mode 100644 index 0000000..8fb190c --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest16.java @@ -0,0 +1,81 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest16 extends TestCase { + /** + * creation, getting streams, waiting the finish for lots of echo-process + */ + public void test_16() { + System.out.println("==test_16==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + cmnd = RuntimeAdditionalTest0.cm + " /C \"echo 777\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + cmnd = "sh -c \"echo 777\""; + } else { + fail("WARNING (test_1): unknown operating system."); + } + int ia = 0; + //while (ia < (Integer.MAX_VALUE - (Integer.MAX_VALUE / 300) * 2)) { + // ia += Integer.MAX_VALUE / 300; + while (ia < 70/*100*/) { + ia += 1; + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + while (true) { + try { + Thread.sleep(50); + pi3.exitValue(); + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + is.available(); + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_16): unexpected exception."); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest17.java vm/tests/kernel/java/lang/RuntimeAdditionalTest17.java new file mode 100644 index 0000000..fc4169a --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest17.java @@ -0,0 +1,78 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest17 extends TestCase { + /** + * in loop: creation of echo-process, touch its streams via available and + * flush, destroy the process and touch streams again + */ + public void test_17() { + System.out.println("==test_17==="); + int ia = 0; + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + cmnd = RuntimeAdditionalTest0.cm + " /C \"echo 777\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "/bin/sh -c \"echo 777\""; + cmnd = "/bin/echo 777"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + while (ia++ < 600/*1000*//*10000*/) { + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + java.io.OutputStream os = pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + is.available(); + es.available(); + os.flush(); + pi3.destroy(); + is.available(); + es.available(); + os.flush(); + } catch (Exception eeee) { + System.out.println("=="+ia+"==="); + eeee.printStackTrace(); + if(ia==1) fail("ERROR (test_17): unexpected exception."); + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest18.java vm/tests/kernel/java/lang/RuntimeAdditionalTest18.java new file mode 100644 index 0000000..b800fb5 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest18.java @@ -0,0 +1,101 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest18 extends TestCase { + /** + * read jvm output, destroy, exitValue, exitValue and, maybe, read again + */ + public void test_18() { + System.out.println("==test_18==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_18): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + pi3.destroy(); + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_18): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest19.java vm/tests/kernel/java/lang/RuntimeAdditionalTest19.java new file mode 100644 index 0000000..cf09072 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest19.java @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest19 extends TestCase { + /** + * destroy jvm process, "destroy" again, exitValue, exitValue + */ + public void test_19() { + System.out.println("==test_19==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_19): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.destroy(); + Thread.sleep(5000); + pi3.destroy(); + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_19): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest2.java vm/tests/kernel/java/lang/RuntimeAdditionalTest2.java new file mode 100644 index 0000000..12d4379 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest2.java @@ -0,0 +1,94 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest2 extends TestCase { + /** + * 1. destroy java process then Process.exitValue 2. waitFor java process + * then Process.exitValue, Process.exitValue 3. destroy "java -version" + * process then Process.exitValue, Process.exitValue + */ + public void test_3() { + System.out.println("==test_3==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_3): unknown operating system."); + } + Process pi3 = null; + try { + + String cmnd = RuntimeAdditionalTest0.javaStarter; + pi3 = Runtime.getRuntime().exec(cmnd); + pi3.destroy(); + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + //eeee.printStackTrace(); + while (true) { + try { + /*System.out.println(=ntln("XXX: " + */pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + } + /*System.out.println("YYY: " + */pi3.exitValue()/*)*/; + try { + + String cmnd = RuntimeAdditionalTest0.javaStarter; + pi3 = Runtime.getRuntime().exec(cmnd); + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_3): unexpected exception."); + } + try { + + String cmnd = RuntimeAdditionalTest0.javaStarter+" -version"; + pi3 = Runtime.getRuntime().exec(cmnd); + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_3): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest20.java vm/tests/kernel/java/lang/RuntimeAdditionalTest20.java new file mode 100644 index 0000000..7e01a61 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest20.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest20 extends TestCase { + /** + * wait for finish of jvm process then destroy it then exitValue, exitValue + */ + public void test_20() { + System.out.println("==test_20==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_20): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + while (true) { + try { + Thread.sleep(50); + pi3.exitValue(); + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + pi3.destroy(); + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_20): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest21.java vm/tests/kernel/java/lang/RuntimeAdditionalTest21.java new file mode 100644 index 0000000..b7cf73c --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest21.java @@ -0,0 +1,91 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest21 extends TestCase { + /** + * wait for finish of jvm process then get and read its err, then exitValue + */ + public void test_21() { + System.out.println("==test_21==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_21): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + while (true) { + try { + Thread.sleep(50); + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + is.available(); + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_21): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest22.java vm/tests/kernel/java/lang/RuntimeAdditionalTest22.java new file mode 100644 index 0000000..4b3f5f0 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest22.java @@ -0,0 +1,92 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest22 extends TestCase { + /** + * get jvm process' streams, wait for finish of the process then read err + * stream, then exitValue + */ + public void test_22() { + System.out.println("==test_22==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_22): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + pi3.getInputStream(); + while (true) { + try { + Thread.sleep(50); + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + es.available(); + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_22): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest23.java vm/tests/kernel/java/lang/RuntimeAdditionalTest23.java new file mode 100644 index 0000000..d90dd99 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest23.java @@ -0,0 +1,91 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest23 extends TestCase { + /** + * get jvm process' streams, wait for finish of the process then read input + * stream, then exitValue + */ + public void test_23() { + System.out.println("==test_23==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_23): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + while (true) { + try { + Thread.sleep(50); + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_23): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest24.java vm/tests/kernel/java/lang/RuntimeAdditionalTest24.java new file mode 100644 index 0000000..f7abcda --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest24.java @@ -0,0 +1,83 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest24 extends TestCase { + /** + * get jvm process' streams, "waitFor" finish of the process then read input + * stream, then exitValue + */ + public void test_24() { + System.out.println("==test_24==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_24): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + /*System.out.println(*/pi3.waitFor()/*)*/; + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_24): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest25.java vm/tests/kernel/java/lang/RuntimeAdditionalTest25.java new file mode 100644 index 0000000..4fa3bf2 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest25.java @@ -0,0 +1,87 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest25 extends TestCase { + /** + * get jvm process' streams, waitFor finish of the process, waitFor, + * exitValue, destroy, waitFor then read err stream, then exitValue + */ + public void test_25() { + System.out.println("==test_25==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_25): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + pi3.getInputStream(); + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.waitFor()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + pi3.destroy(); + /*System.out.println(*/pi3.waitFor()/*)*/; + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_25): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest26.java vm/tests/kernel/java/lang/RuntimeAdditionalTest26.java new file mode 100644 index 0000000..06c9264 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest26.java @@ -0,0 +1,85 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest26 extends TestCase { + /** + * get jvm process' streams, destroy, waitFor finish of the process then + * read err stream, then exitValue + */ + public void test_26() { + System.out.println("==test_26==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_26): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + /*System.out.println(*/pi3.waitFor()/*)*/; + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + pi3.getInputStream(); + pi3.destroy(); + /*System.out.println(*/pi3.waitFor()/*)*/; + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_26): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest27.java vm/tests/kernel/java/lang/RuntimeAdditionalTest27.java new file mode 100644 index 0000000..59f3aad --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest27.java @@ -0,0 +1,86 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest27 extends TestCase { + /** + * get jvm process' streams, waitFor finish of the process then read err + * stream, then exitValue + */ + public void test_27() { + System.out.println("==test_27==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_27): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + /*System.out.println(*/pi3.waitFor()/*)*/; + pi3.destroy(); + Thread.sleep(100); + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + pi3.getInputStream(); + /*System.out.println(*/pi3.waitFor()/*)*/; + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_27): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest28.java vm/tests/kernel/java/lang/RuntimeAdditionalTest28.java new file mode 100644 index 0000000..da188e1 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest28.java @@ -0,0 +1,95 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest28 extends TestCase { + /** + * wait for (via exitValue loop) finish of the java process then destroy, + * get jvm process' streams, read err stream, then exitValue + */ + public void test_28() { + System.out.println("==test_28==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_28): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + while (true) { + try { + Thread.sleep(50); + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + pi3.destroy(); + Thread.sleep(100); + pi3.getOutputStream(); + java.io.InputStream es = pi3.getErrorStream(); + pi3.getInputStream(); + /*System.out.println(*/pi3.waitFor()/*)*/; + int ia; + while (true) { + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = es.available()) != 0) { + byte[] bbb = new byte[ia]; + es.read(bbb); + //System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_28): unexpected exception."); + } + } + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest29.java vm/tests/kernel/java/lang/RuntimeAdditionalTest29.java new file mode 100644 index 0000000..6e74a32 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest29.java @@ -0,0 +1,101 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest29 extends TestCase { + /** + * create tree-process, get streams, read input stream, then exitValue + */ + public void test_29() { + System.out.println("==test_29==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + cmnd = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"tree /lib\""; + //cmnd = "/usr/bin/tree /lib"; + //cmnd = "/usr/bin/tree /bin"; + cmnd = RuntimeAdditionalTest0.treeStarter+" /bin"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + + int ia; + int num = 0; + while (true) { + while ((ia = is.available()) != 0) { + num += ia; + if (num > 5000) { + pi3.destroy(); + } + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + //System.out.println(ia); + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_29): unexpected exception."); + } + RuntimeAdditionalTest0.killTree(); } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest3.java vm/tests/kernel/java/lang/RuntimeAdditionalTest3.java new file mode 100644 index 0000000..62bcb61 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest3.java @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest3 extends TestCase { + /** + * exitValue java process to catch the IllegalThreadStateException + */ + public void test_4() { + System.out.println("==test_4==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_4): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + /*System.out.println(Integer.toString(*/pi3.exitValue()/*))*/; + } catch (IllegalThreadStateException eeee) { + //System.out.println("PASSED: test_4"); + return; + } catch (java.io.IOException eeee) { + eeee.printStackTrace(); + fail("WARNING: test_4 didn't work"); + } + fail("FAILED: test_4"); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest30.java vm/tests/kernel/java/lang/RuntimeAdditionalTest30.java new file mode 100644 index 0000000..277e63f --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest30.java @@ -0,0 +1,108 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest30 extends TestCase { + /** + * create tree(/bin for lin)-process, get streams, read input stream + * partialy, destroy process, read the rest then exitValue + */ + public void test_30() { + System.out.println("==test_30==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + cmnd = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"tree /lib\""; + //cmnd = "/usr/bin/tree /lib"; + ///**/cmnd = "/usr/bin/tree /bin"; + /**/cmnd = RuntimeAdditionalTest0.treeStarter+" /bin"; + //cmnd = "/usr/bin/tree /"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + + int ia; + //int num = 0; + while (true) { + while ((ia = is.available()) != 0) { + //num += ia; + //if (num > 5000) { + // pi3.destroy(); + //} + byte[] bbb = new byte[ia]; + is.read(bbb); + ///* //\\//\\ */System.out.println(new String(bbb)); + ///* //\\//\\ */System.out + // .println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " + // + ia); + //Thread.sleep(1000); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + //\\//\\System.out.println(ia); + //Thread.sleep(1000); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_30): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest31.java vm/tests/kernel/java/lang/RuntimeAdditionalTest31.java new file mode 100644 index 0000000..b941cfa --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest31.java @@ -0,0 +1,105 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest31 extends TestCase { + /** + * create tree(/lib for lin)-process, get streams, read input stream + * partialy, destroy process, read the rest then exitValue + */ + public void test_30_1() { + System.out.println("==test_30_1==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + cmnd = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"tree /lib\""; + //cmnd = "/usr/bin/tree /lib"; + cmnd = RuntimeAdditionalTest0.treeStarter+" /bin"; + //cmnd = "/usr/bin/tree /bin"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + + int ia; + int num = 0; + while (true) { + while ((ia = is.available()) != 0) { + num += ia; + if (num > 5000) { + pi3.destroy(); + } + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + //\\//\\System.out.println(ia); + //Thread.sleep(1000); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + //\\//\\System.out.println(ia); + //Thread.sleep(1000); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_30): unexpected exception."); + } + RuntimeAdditionalTest0.killTree(); } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest32.java vm/tests/kernel/java/lang/RuntimeAdditionalTest32.java new file mode 100644 index 0000000..d45c79b --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest32.java @@ -0,0 +1,115 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest32 extends TestCase { + /** + * create tree(/bin for lin)-process, get streams, read input stream + * partialy, destroy process, read (trying to destroy + * repeatedly-intermediately) the rest then exitValue + */ + public void test_31() { + System.out.println("==test_31==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + cmnd = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"tree /lib\""; + //cmnd = "/usr/bin/tree /lib"; + //cmnd = "/usr/bin/tree /bin"; + cmnd = RuntimeAdditionalTest0.treeStarter+" /bin"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + + int ia; + int num = 0; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + //\\//\\System.out.println(ia); + //Thread.sleep(1000); + num += ia; + if (num > 5000) { + pi3.destroy(); + break; + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + //\\//\\System.out.println(ia); + //Thread.sleep(1000); + num += ia; + if (num > 10000) { + pi3.destroy(); + break; + } + } + break; + } catch (IllegalThreadStateException e) { + if (num > 10000) { + pi3.destroy(); + break; + } + } + } + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_31): unexpected exception."); + } + RuntimeAdditionalTest0.killTree(); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest33.java vm/tests/kernel/java/lang/RuntimeAdditionalTest33.java new file mode 100644 index 0000000..03e4228 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest33.java @@ -0,0 +1,156 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest33 extends TestCase { + /** + * create two cat-process, multi_byte-read from one multi_byte-write (using + * flushing) to another and multi_byte-read there again + */ + public void test_32() { + System.out.println("==test_32==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\Documents and Settings\\All + // Users\\Documents\\My Pictures\\Sample Pictures\\Winter.jpg\""; + cmnd1 = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c sh -c \"cat -v /lib/ld.so\""; + //cmnd1 = "cat -v /lib/ld.so"; + //\\//\\cmnd1 = "cat -v /bin/echo"; + cmnd1 = "cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = "sh -c cat"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + + Process pi3 = Runtime.getRuntime().exec(cmnd1); + //Process pi3 = Runtime.getRuntime().exec(cmnd+" /C cat + // \"C:\\IJE\\orp\\ZSS\\___LOG2.DO_VM_CLEAN no\""); + //Process pi3 = Runtime.getRuntime().exec(cmnd+" /C tree"); + Process pi4 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while (ia != is4.available()) { + os4.flush(); + } + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_32): unexpected exception."); + } + try{ + //cmnd1 = RuntimeAdditionalTest0.cm + " /C ps -ef"; + cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C ps -Ws":RuntimeAdditionalTest0.cm + " -c \"ps -ef\""; + Process pi5 = Runtime.getRuntime().exec(cmnd1); + BufferedReader br = new BufferedReader(new InputStreamReader(pi5 + .getInputStream())); + boolean flg = true; + String procValue = null; + while ((procValue = br.readLine()) != null) { + if (procValue.indexOf("cat") != -1) { + System.out.println(111); + flg = false; + break; + } + } + if (flg) { + return; + } + String as[] = procValue.split(" "); + for (int i = 0; i < as.length; i++) { + if(as[i].matches("\\d+")){ + System.out.println(222); + cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C kill "+as[i]:RuntimeAdditionalTest0.cm + " -c \"kill "+as[i]+"\""; + Runtime.getRuntime().exec(cmnd1); + Thread.sleep(3000); + } + } + }catch(Exception e){ + fail("ERROR (test_32): unexpected exception: "+e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest34.java vm/tests/kernel/java/lang/RuntimeAdditionalTest34.java new file mode 100644 index 0000000..14b99fc --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest34.java @@ -0,0 +1,110 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest34 extends TestCase { + /** + * creat two cat-process, one_byte-read from one one_byte-write (using + * flushing) to another and one_byte-read there again + */ + public void test_33() { // it, maybe, hangs the test set run + System.out.println("==test_33==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c \"tree /lib\""; + //cmnd1 = "/usr/bin/tree /lib"; + //cmnd1 = "/usr/bin/tree /bin"; + //cmnd2 = "sh -c cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" /bin"; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + Process pi3 = Runtime.getRuntime().exec(cmnd1); + Process pi4 = Runtime.getRuntime().exec(cmnd2); + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int b1; + //int b2; + while (true) { + while ((is.available()) != 0) { + b1 = is.read(); + os4.write(b1); + while ((is4.available()) != 0) { + /*b2 =*/ is4.read(); + ///* if (b1!=b2) */System.out.print(Character + // .toString((char) b2)); + } + } + try { + pi3.exitValue(); + while ((is.available()) != 0) { + b1 = is.read(); + os4.write(b1); + while ((is4.available()) != 0) { + /*b2 =*/ is4.read(); + //\\//\\System.out.print(Character.toString((char)b2)); + } + } + break; + } catch (IllegalThreadStateException e) { + Thread.sleep(20); + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_33): unexpected exception."); + } + RuntimeAdditionalTest0.killCat(); } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest35.java vm/tests/kernel/java/lang/RuntimeAdditionalTest35.java new file mode 100644 index 0000000..f3a0dc5 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest35.java @@ -0,0 +1,189 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest35 extends TestCase { + /** + * creat two cat-process, multi_byte-read from one multi_byte-write (using + * flushing) to another and multi_byte-read there again wait finish of both + * processes after the reading using "exitValue-destroy" loops + */ + public void test_34() { // it can hang the test set run + System.out.println("==test_34==="); + Process pi3 = null; + Process pi4 = null; + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd1 = RuntimeAdditionalTest0.cm+" /C cat \"C:\\Documents and Settings\\All + // Users\\Documents\\My Pictures\\Sample Pictures\\Winter.jpg\""; + cmnd1 = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c sh -c \"cat -v /lib/ld.so\""; + //cmnd1 = "cat -v /lib/ld.so"; + //\\//\\cmnd1 = "cat -v /bin/echo"; + cmnd1 = "cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + cmnd2 = "sh -c cat"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + + /* Process */pi3 = Runtime.getRuntime().exec(cmnd1); + //Process pi3 = Runtime.getRuntime().exec(cmnd+" /C cat + // \"C:\\IJE\\orp\\ZSS\\___LOG2.DO_VM_CLEAN no\""); + //Process pi3 = Runtime.getRuntime().exec(cmnd+" /C tree"); + /* Process */pi4 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while (ia != is4.available()) { + os4.flush(); + } + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_34): unexpected exception."); + } + int i = 0; + while (true) { + try { + i++; + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + try { + pi3.destroy(); + Thread.sleep(10); + } catch (Exception ee) { + } + continue; + } + } + + i = 0; + while (true) { + try { + i++; + /*System.out.println(*/pi4.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + try { + pi4.destroy(); + Thread.sleep(10); + } catch (Exception ee) { + } + continue; + } + } + try{ + //cmnd1 = RuntimeAdditionalTest0.cm + " /C ps -ef"; + cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C ps -Ws":RuntimeAdditionalTest0.cm + " -c \"ps -ef\""; + Process pi5 = Runtime.getRuntime().exec(cmnd1); + BufferedReader br = new BufferedReader(new InputStreamReader(pi5 + .getInputStream())); + boolean flg = true; + String procValue = null; + while ((procValue = br.readLine()) != null) { + if (procValue.indexOf("cat") != -1) { + System.out.println(111); + flg = false; + break; + } + } + if (flg) { + return; + } + String as[] = procValue.split(" "); + for (int ii = 0; ii < as.length; ii++) { + if(as[ii].matches("\\d+")){ + System.out.println(222); + cmnd1 = RuntimeAdditionalTest0.os.equals("Win")?RuntimeAdditionalTest0.cm + " /C kill "+as[i]:RuntimeAdditionalTest0.cm + " -c \"kill "+as[i]+"\""; + Runtime.getRuntime().exec(cmnd1); + Thread.sleep(3000); + } + } + }catch(Exception e){ + fail("ERROR (test_34): unexpected exception: "+e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest36.java vm/tests/kernel/java/lang/RuntimeAdditionalTest36.java new file mode 100644 index 0000000..0fe53b2 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest36.java @@ -0,0 +1,115 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest36 extends TestCase { + /** + * check the process exit code has a waited value + */ + public void test_35() { // it can hang the test set run + System.out.println("==test_35==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + cmnd = RuntimeAdditionalTest0.cm + " /C "; + try { + //for (int i = 0; i < Short.MAX_VALUE / 30; i++) { + //for (int i = 0; i < Short.MAX_VALUE / 100; i++) { + for (int i = 0; i < Short.MAX_VALUE / 150; i++) { + Process pi3 = Runtime.getRuntime() + .exec( + cmnd + "\"exit " + + Integer.toString(i - 500) + "\""); + int j = pi3.waitFor(); + /*System.out.println("sent " + Integer.toString(i - 500) + + " | received " + pi3.waitFor());*/ + if (j != (i - 500)) { + fail("ERROR(test_35): exiValue " + pi3.exitValue() + + " should be " + (i - 500)); + } + } + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_35): unexpected exception."); + } + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + try { + for (int i = 500; i < Short.MAX_VALUE / 100/*30*/; i++) { + //Process pi3 = Runtime.getRuntime().exec("java RuntimeAdditionalSupport1 " + + // Integer.toString(i-500)); + //\\//\\Process pi3 = Runtime.getRuntime().exec("java -cp + // \""+System.getProperty("java.class.path")+"\" RuntimeAdditionalSupport1 " + + // Integer.toString(i-500)); +// Process pi3 = Runtime +// .getRuntime() +// .exec( +// "java " +// + (System.getProperty( +// "java.class.path").length() > 0 ? "-cp " +// + System +// .getProperty("java.class.path") +// : "") + " RuntimeAdditionalSupport1 " +// + Integer.toString(i - 500)); + String ttt = System.getProperty("vm.boot.class.path") +(System.getProperty("java.class.path").length() > 0 ? + File.pathSeparator + System.getProperty("java.class.path") : ""); + Process pi3 = Runtime + .getRuntime() + .exec( + "java -Xbootclasspath/a:" + ttt + " -cp " + ttt + " java.lang.RuntimeAdditionalSupport1 " + + Integer.toString(i - 500)); + int j = pi3.waitFor(); + /*System.out.println("sent " + Integer.toString(i - 500) + + " | received " + pi3.waitFor() + " (" + j + ")" + + ((i - 500) & 0xFF));*/ + if (j != ((i - 500) & 0xFF)) { + fail("ERROR(test_35): exiValue " + pi3.exitValue() + + " should be " + ((i - 500) & 0xFF)); + } + } + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_35): unexpected exception."); + } + } else { + fail("WARNING (test_1): unknown operating system."); + } + } + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest37.java vm/tests/kernel/java/lang/RuntimeAdditionalTest37.java new file mode 100644 index 0000000..4902f3c --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest37.java @@ -0,0 +1,89 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest37 extends TestCase { + /** + * check an environment variable appears correctly if exec(..., env, ...) is + * used + */ + public void test_36_1() { + System.out.println("==test_36==="); + String command = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + command = RuntimeAdditionalTest0.cm + + " /C \"echo %Z_S_S_2%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //command = "sh -c \"echo $Z_S_S_2\""; + //command = "echo $Z_S_S_2"; + command = "/usr/bin/env"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + String procValue = null; + try { + Process proc = Runtime.getRuntime().exec(command, + new String[] { "Z_S_S_2=S_O_M_E_T_H_I_N_G" }); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + boolean flg = true; + while ((procValue = br.readLine()) != null) { + //if (procValue.indexOf("Z_S_S_2=S_O_M_E_T_H_I_N_G") != -1) { + if (procValue.indexOf(RuntimeAdditionalTest0.os.equals("Win")?"S_O_M_E_T_H_I_N_Gx":"S_O_M_E_T_H_I_N_G") != -1) { + //System.out.println(procValue); + flg = false; + return; + } + System.out + .println("WARNING (test_36): should it be only singl line in env after such exec? (" + + procValue + ")"); + } + if (flg) { + fail("ERROR (test_36): Z_S_S_2 var should be present and assingned correctly."); + } + } catch (IOException e) { + e.printStackTrace(); + fail("ERROR (test_36): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest38.java vm/tests/kernel/java/lang/RuntimeAdditionalTest38.java new file mode 100644 index 0000000..f92b6c4 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest38.java @@ -0,0 +1,158 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest38 extends TestCase { + /** + * check possibility of big env array defining via exec(..., env, ...) and + * long file name via exec(..., file) + */ + public void test_36() { + System.out.println("==test_36==="); + String command = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + command = RuntimeAdditionalTest0.cm + + " /C \"echo %Z_S_S_2%xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //command = "sh -c \"echo $Z_S_S_2\""; + //command = "echo $Z_S_S_2"; + command = "/usr/bin/env"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + String procValue = null; + try { + Process proc = Runtime.getRuntime().exec(command, + new String[] { "Z_S_S_2=S_O_M_E_T_H_I_N_G" }); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + //procValue = br.readLine(); + boolean flg = true; + while ((procValue = br.readLine()) != null) { + //if (procValue.indexOf("Z_S_S_2=S_O_M_E_T_H_I_N_G") != -1) { + if (procValue.indexOf(RuntimeAdditionalTest0.os.equals("Win")?"S_O_M_E_T_H_I_N_Gx":"S_O_M_E_T_H_I_N_G") != -1) { + flg = false; + break; + } + System.out + .println("WARNING (test_36): should it be only singl line in env after such exec? (" + + procValue + ")"); + } + if (flg) { + fail("ERROR (test_36): Z_S_S_2 var should be present and assingned correctly."); + } + } catch (IOException e) { + e.printStackTrace(); + fail("ERROR (test_36): unexpected exception."); + } + try { + String ts = "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"; + String ts2 = "Z_S_S_2=S_O_M_E_T_H_I_N_G"; + Process proc = Runtime.getRuntime().exec( + command, + new String[] { ts2, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, + ts, ts, ts, ts, ts, ts, ts2, ts, ts, ts, ts, ts, + ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts2, + ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, + ts, ts, ts, ts2, ts, ts, ts, ts, ts, ts, ts, ts, + ts, ts, ts, ts, ts, ts, ts, ts, ts2, ts, ts, ts, + ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, + ts2, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, + ts, ts, ts, ts, ts, ts2, ts, ts, ts, ts, ts, ts, + ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts2, ts, + ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, ts, + ts, ts, ts2, ts, ts, ts, ts, ts, + // ts, + }, + new File("." + File.separator + ".." + File.separator + + ".." + File.separator + ".." + File.separator + + ".." + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + //+ File.separator + ".." + File.separator + //+ File.separator + ".." + File.separator + ".." + //+ File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator + ".." + + File.separator + ".." + File.separator)); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + procValue = br.readLine(); + } catch (java.io.IOException e) { + e.printStackTrace(); + fail("ERROR (test_36): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest39.java vm/tests/kernel/java/lang/RuntimeAdditionalTest39.java new file mode 100644 index 0000000..3e0d739 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest39.java @@ -0,0 +1,138 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. The following issue should be investigated: * if we have uncommented "BUG: DRL is hanging here"-marked lines then the test fails on DRLVM on LINUX. * So, it looks like the bug in DRLVM ("writing into the input stream of unwaiting process spoils the receiving * its output"). + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest39 extends TestCase { + /** + * creat two cat-process, multi_byte-read from one multi_byte-write (using + * flushing) to another and multi_byte-read there again disturb this process + * by writing some unwaited info + */ + public void test_37() { + System.out.println("==test_37==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c \"tree /lib\""; + //cmnd1 = "/usr/bin/tree /lib"; + //cmnd1 = "/usr/bin/tree /bin"; + //cmnd2 = "sh -c cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" /bin"; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + + Process pi3 = Runtime.getRuntime().exec(cmnd1); + //Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + try { + Thread.sleep(2000); + } catch (Exception e) { + } + java.io.OutputStream os = pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + while ((is.available()) == 0) {RuntimeAdditionalTest0.doMessage("1\n");}//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + //RuntimeAdditionalTest0.doMessage("2\n"); Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + int ia; + int ia3=0; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// os.write(bbb); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !!!!!!!!!!! BUG: DRL is hanging here !!!!!!! +// // write into the unwaiting +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + os4.write(bbb); + int ia2 = 0; + //while (ia != is4.available()) { + // os4.flush(); + // ia2++; + // if (ia2 > 100) { + // System.out.println("Warning (test_37): something wrong? We are waiting about the same number of bytes as were written."); // break; + // } + //} + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// os.write(bbb4); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !!!!!!!!!!! BUG: DRL is hanging here !!!!!!! +// // write into the unwaiting +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //\\//\\System.out.println(new String(bbb4)); + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + if(ia3++>1000) break; + continue; + } + } + RuntimeAdditionalTest0.killTree(); + RuntimeAdditionalTest0.killCat(); + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_37): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest4.java vm/tests/kernel/java/lang/RuntimeAdditionalTest4.java new file mode 100644 index 0000000..0a197a2 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest4.java @@ -0,0 +1,62 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest4 extends TestCase { + /** + * sleep till finish of "java <unexisting_class>" process then exitValue, + * exitValue not to catch any exceptions + */ + public void test_5() { + System.out.println("==test_5==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_5): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter+" MAIN"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + Thread.sleep(10000/*15000*/); + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_5): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest40.java vm/tests/kernel/java/lang/RuntimeAdditionalTest40.java new file mode 100644 index 0000000..26ee835 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest40.java @@ -0,0 +1,303 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest40 extends TestCase { + /** + * create thread with two cat-process multi_byte-interconnected create two + * thread waiting these processes correspondingly interrupt the last two + * process to provide InterruptedException rising + */ + class thread1 extends Thread { + public void run() { + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + //cmnd1 = "C:\\WINNT\\system32\\tree.com \"C:\\Documents and Settings\""; + /**/cmnd1 = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + //cmnd2 = "C:\\CygWin\\bin\\cat.exe"; + /**/cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "/usr/bin/tree /"; + /**/cmnd1 = RuntimeAdditionalTest0.treeStarter+" /"; + //cmnd1 = "/usr/bin/tree /lib"; + //cmnd1 = "/usr/bin/tree /bin"; + //cmnd2 = "/bin/sh -c cat"; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + //System.out.println("thread1: 1"); + //**/RuntimeAdditionalTest0.doMessage("thread1: 1\n"); + ppp3 = Runtime.getRuntime().exec(cmnd1); + ppp4 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + ppp3.getOutputStream(); + ppp3.getErrorStream(); + java.io.InputStream is = ppp3.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String procValue = null; + //**/RuntimeAdditionalTest0.doMessage(cmnd1); + java.io.OutputStream os4 = ppp4.getOutputStream(); + ppp4.getErrorStream(); + java.io.InputStream is4 = ppp4.getInputStream(); + //**/System.out.println("thread1: 2"); + //**/RuntimeAdditionalTest0.doMessage("thread1: 2\n"); + + int ia; + int ii = 0; + while (true) { + while ((ia = is.available()) != 0) { + //**/RuntimeAdditionalTest0.doMessage("XXXXXXXXXXXXXX1!\n"); + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + //**/RuntimeAdditionalTest0.doMessage("XXXXXXXXXXXXXX2!\n"); + while (ia != is4.available()) { + os4.flush(); + } + //**/RuntimeAdditionalTest0.doMessage("XXXXXXXXXXXXXX3!\n"); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + //**/RuntimeAdditionalTest0.doMessage("XXXXXXXXXXXXXX4!\n"); + ii++; + //if (ii % 500 == 0) System.out.println("thread1: 3"); + flg = true; //#################################################### + try { + Thread.sleep(20); + } catch (Exception e) { + } + } + try { + //**/System.out.println("thread1: 4"); + //**/RuntimeAdditionalTest0.doMessage("thread1: 4\n"); + ppp3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + os4.write(bbb); + while ((ia = is4.available()) != 0) { + byte[] bbb4 = new byte[ia]; + is4.read(bbb4); + //\\//\\System.out.println(new String(bbb4)); + } + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_38, thread1): unexpected exception."); + } + } + + protected void finalize() throws Throwable { + super.finalize(); + //System.out.println("thread1: finalize"); + //**/RuntimeAdditionalTest0.doMessage("thread1: finalize\n"); + System.out.flush(); + } + } + + class thread2 extends Thread { + public void run() { + //System.out.println("thread2: 1"); + //**/RuntimeAdditionalTest0.doMessage("thread2: 1\n"); + while (ppp3 == null) { + try { + Thread.sleep(10); + } catch (Exception _) { + } + } + //System.out.println("thread2: 2"); + //**/RuntimeAdditionalTest0.doMessage("thread2: 2\n"); + try { + ppp3.waitFor(); + } catch (InterruptedException _) { + flg2 = true; + //System.out.println("InterruptedException 2"); + //**/RuntimeAdditionalTest0.doMessage("InterruptedException 2\n"); + } + //System.out.println("thread2: 3"); + //**/RuntimeAdditionalTest0.doMessage("thread2: 3\n"); + } + + protected void finalize() throws Throwable { + super.finalize(); + //**/System.out.println("thread2: finalize"); + //**/RuntimeAdditionalTest0.doMessage("thread2: finalize\n"); + System.out.flush(); + } + } + + class thread3 extends Thread { + public void run() { + //System.out.println("thread3: 1"); + //**/RuntimeAdditionalTest0.doMessage("thread3: 1\n"); + while (ppp4 == null) { + try { + Thread.sleep(10); + } catch (Exception _) { + } + } + //System.out.println("thread3: 2"); + //**/RuntimeAdditionalTest0.doMessage("thread3: 2\n"); + try { + ppp4.waitFor(); + } catch (InterruptedException _) { + flg3 = true; + //System.out.println("InterruptedException 3"); + } + //System.out.println("thread3: 3"); + //**/RuntimeAdditionalTest0.doMessage("thread3: 3\n"); + } + + protected void finalize() throws Throwable { + super.finalize(); + //System.out.println("thread2: finalize"); + //**/RuntimeAdditionalTest0.doMessage("thread2: finalize\n"); + System.out.flush(); + } + } + + static Process ppp3 = null; + + static Process ppp4 = null; + + static boolean flg = false; + + static boolean flg2 = false; + + static boolean flg3 = false; + + public void test_38() { + System.out.println("==test_38==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_2): unknown operating system."); + } + Runtime.runFinalizersOnExit(true); + Thread t1 = null; + Thread t2 = null; + Thread t3 = null; + try { + t1 = new thread1(); + t1.start(); + while (!flg) { + try { + Thread.sleep(10); + } catch (Exception _) { + } + } + t2 = new thread2(); + t2.start(); + try { + Thread.sleep(100); + } catch (Exception _) { + } + t3 = new thread3(); + t3.start(); + try { + Thread.sleep(100); + } catch (Exception _) { + } + t2.interrupt(); + //System.out.println("== interrupt t2 ==="); + //**/RuntimeAdditionalTest0.doMessage("== interrupt t2 ===\n"); + //t2.join(); + t3.interrupt(); + //System.out.println("== interrupt t3 ==="); + //**/RuntimeAdditionalTest0.doMessage("== interrupt t3 ===\n"); + //t3.join(); + ppp3.destroy(); + ppp4.destroy(); + t1.interrupt(); + t3.join(); + t2.join(); + t1.join(); + //try{Thread.sleep(5000);}catch(Exception _){} + //System.out.println("== joined ==="); + //**/RuntimeAdditionalTest0.doMessage("== joined ===\n"); + } catch (Exception e) { + e.printStackTrace(); + try { + ppp3.waitFor(); + } catch (InterruptedException ee) { + ee.printStackTrace(); + try { + ppp4.waitFor(); + } catch (InterruptedException eee) { + eee.printStackTrace(); + //System.out.println(flg2 + "." + flg3); + //**/RuntimeAdditionalTest0.doMessage(Boolean.valueOf(flg2) + "." + Boolean.valueOf(flg3)); + return; + } + } + } + if (!(flg2 && flg3)) { + ppp3.destroy(); + ppp4.destroy(); + t1.interrupt(); + //t1.destroy(); + t2.interrupt(); + //t2.destroy(); + t3.interrupt(); + //t3.destroy(); + fail("ERROR (test_38): InterruptedException should be risen."); + } else { + System.out.println("############################"); + System.out.println("## test_38 PASSED anyway. ##"); + System.out.println("############################"); + } + RuntimeAdditionalTest0.killCat(); } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest41.java vm/tests/kernel/java/lang/RuntimeAdditionalTest41.java new file mode 100644 index 0000000..53fe54c --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest41.java @@ -0,0 +1,175 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest41 extends TestCase { + /** + * create tree-process and cat-process, organize their one_byte-interconnection using flushing + */ + public void test_39() { System.out.println("==test_39==="); + String tds = System.getProperty("java.io.tmpdir")+File.separator+System.getProperty("user.name")+"_"+System.getProperty("user.name")+"_"+System.getProperty("user.name"); File fff = new File(tds); fff.mkdir(); + fff.deleteOnExit(); for(int ind = 0; ind < 300; ind++){ + (fff = new File(tds+File.separator+System.getProperty("user.name")+Integer.toString(ind, 10))).mkdir(); + fff.deleteOnExit(); } + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + ///**/cmnd1 = "C:\\WINNT\\system32\\tree.com \"C:\\Documents and Settings\\All Users\""; + ///**/cmnd1 = "C:\\WINNT\\system32\\tree.com \""+tds+"\""; + /**/cmnd1 = RuntimeAdditionalTest0.treeStarter+" \""+tds+"\""; + /**/System.out.println(cmnd1); + ///**/cmnd2 = "C:\\CygWin\\bin\\cat.exe"; + /**/cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c \"tree /lib\""; + //cmnd1 = "/usr/bin/tree /lib"; + //cmnd1 = "/usr/bin/tree /bin"; + //cmnd2 = "sh -c cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" /bin"; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_39): unknown operating system."); + } + try { + + //Process pi3 = Runtime.getRuntime().exec(cmnd1); + //Process pi4 = Runtime.getRuntime().exec(cmnd2); + Process pi3 = Runtime.getRuntime().exec(cmnd1); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + while ((is.available()) == 0) {} //System.out.println("control point 1"); + /**/RuntimeAdditionalTest0.doMessage("control point 1"); + Process pi4 = Runtime.getRuntime().exec(cmnd2); + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int b1; + int ia; + int ii = 0; +MMM: while (true) { + //System.out.println("control point 2"); + while ((ia = is.available()) != 0) { + //System.out.println("control point 3"); + if (RuntimeAdditionalTest0.os.equals("Win")) { + b1=is.read(); os4.write(b1); + os4.write(10); + os4.flush(); + //System.out.println("control point 4"); + while ((ia = is4.available()) != 2) { /**/RuntimeAdditionalTest0.doMessage(Integer.toString(ia, 10)+"\n"); + try{ + pi3.exitValue(); + if(ii > 300+300*System.getProperty("user.name").length()) + break MMM; + }catch(IllegalThreadStateException _){ + continue; + } + break; + } + //System.out.println("control point 5 "+ii); + if (ia > 2) { + byte[] bb = new byte[ia]; + is4.read(bb); + if(ii<200)fail("ERROR (test_39): flush() problem."); + } + if (is4.available()>0) /**/System.out.print(Character.toString((char)/**/is4.read()/**/))/**/; + if (is4.available()>0) is4.read(); + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + os4.write(is.read()); + os4.write(10); + os4.flush(); + while ((ia = is4.available()) == 0) {} //due to our available() impl + /*System.out.print(Character.toString((char)*/is4 + .read()/*))*/; + while ((ia = is4.available()) == 0) {} //due to our available() impl + is4.read(); + try { + Thread.sleep(10); + } catch (Exception e) { + } + if (is4.available() > 0) { + byte[] bb = new byte[ia]; + is4.read(bb); + fail("ERROR (test_39): flush() problem."); + } + } + ii++; + if (ii > 2000) { + break MMM;//return; + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + os4.write(is.read()); + if ((ia = is4.available()) == 0) { + os4.flush(); + if (is4.available() != 1) { + fail("ERROR (test_39): 3."); + } + } else if (ia > 1) { + fail("ERROR (test_39): 4."); + } + is4.read(); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + try { + pi4.exitValue(); + } catch (IllegalThreadStateException e) { + pi4.destroy(); + } + + RuntimeAdditionalTest0.killCat(); RuntimeAdditionalTest0.killTree(); } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_39): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest42.java vm/tests/kernel/java/lang/RuntimeAdditionalTest42.java new file mode 100644 index 0000000..48a21c3 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest42.java @@ -0,0 +1,176 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest42 extends TestCase { + /** + * create tree-process and cat-process, organize their multi_byte-interconnection using flushing + */ + public void test_40() { + System.out.println("==test_40==="); + //String cmnd = null; + String cmnd1 = null; + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd1 = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + //cmnd2 = RuntimeAdditionalTest0.cm + " /C cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd1 = "sh -c \"tree /lib\""; + //cmnd1 = "/usr/bin/tree /lib"; + //cmnd1 = "/usr/bin/tree /bin"; + //cmnd2 = "sh -c cat"; + cmnd1 = RuntimeAdditionalTest0.treeStarter+" /bin"; + cmnd2 = RuntimeAdditionalTest0.catStarter; + } else { + fail("WARNING (test_40): unknown operating system."); + } + try { + + Process pi3 = Runtime.getRuntime().exec(cmnd1); + //Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + while ((is.available()) == 0) {RuntimeAdditionalTest0.doMessage("1\n");}//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + //RuntimeAdditionalTest0.doMessage("2\n"); Process pi4 = Runtime.getRuntime().exec(cmnd2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + java.io.OutputStream os4 = pi4.getOutputStream(); + pi4.getErrorStream(); + java.io.InputStream is4 = pi4.getInputStream(); + + int ia; + int ii = 0; + int ia3=0; + int ia4=0; + while (true) { + while ((ia = is.available()) != 0) { + if (RuntimeAdditionalTest0.os.equals("Win")) { + //System.out.println(1); + byte[] bb = new byte[5]; + is.read(bb, 1, 2); + bb[3] = 10; + os4.write(bb, 1, 3); + os4.flush(); + while ((ia = is4.available()) != 3) {/*System.out.println(3+"|"+ia);*/ if(ia4++>10000){ + ia4 = 0; System.out.println("Warning (test_40): something wrong? We are waiting 3 bytes here as were written."); break; + } + } + if (ia > 3) { + byte[] bbb = new byte[ia]; + is4.read(bbb); + //fail("ERROR (test_40): flush() problem."); + System.out.println("Warning (test_40): flush() problem has been detected! We are waiting 3 bytes here as were written."); } + if(is4.available()!=0)/*System.out.print(Character + .toString((char) */is4.read()/*))*/; + if(is4.available()!=0)/*System.out.print(Character + .toString((char) */is4.read()/*))*/; + if(is4.available()!=0) is4.read(); + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //System.out.println(1); + byte[] bb = new byte[5]; + is.read(bb, 1, 2); + bb[3] = 10; + os4.write(bb, 1, 3); + os4.flush(); + while ((ia = is4.available()) == 0) {/*System.out.println(3+"|"+ia);*/ + } //due to our available() impl + try { + Thread.sleep(100); + } catch (Exception e) { + } + // System.out.println(ia); + // System.out.println(is4.available()); + /*System.out.println(*/is4.read(bb, 1, 3)/*)*/; + // System.out.println(new String(bb, 1, 3)); + ///**/System.out.print(Character.toString((char)/**/is4.read()/**/))/**/; + //while((ia = is4.available()) == 0) {System.out.println(3+"|"+ia);} //due to our available() impl + ///**/System.out.print(Character.toString((char)/**/is4.read()/**/))/**/; + //while((ia = is4.available()) == 0) {System.out.println(3+"|"+ia);} //due to our available() impl + //is4.read(); + // System.out.println(is4.available()); + if (is4.available() > 0) { + byte[] bbb = new byte[ia]; + is4.read(bbb); + fail("ERROR (test_40): flush() problem.|" + + new String(bbb) + "|"); + } + + try { + Thread.sleep(10); + } catch (Exception e) { + } + ii++; + if (ii > 1500) { + return; + } + } + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + os4.write(is.read()); + if ((ia = is4.available()) == 0) { + os4.flush(); + if (is4.available() != 1) { + fail("ERROR (test_40): 3."); + } + } else if (ia > 1) { + fail("ERROR (test_40): 4."); + } + is4.read(); + } + break; + } catch (IllegalThreadStateException e) { + if(ia3++>1000) break; + continue; + } + } + RuntimeAdditionalTest0.killTree(); + RuntimeAdditionalTest0.killCat(); + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_40): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest43.java vm/tests/kernel/java/lang/RuntimeAdditionalTest43.java new file mode 100644 index 0000000..7a8f841 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest43.java @@ -0,0 +1,359 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. should be adopted for linux + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest43 extends TestCase { + /** + * create thread to write and read its streams + * slightly investigate is the buffering implemented for out + * (and what about in?) + */ + class thread11 extends Thread { + public void run() { + String cmnd2 = null; + if (RuntimeAdditionalTest0.os.equals("Win") || RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd2 = "java -cp \""+System.getProperty("java.class.path")+"\" RuntimeAdditionalSupport2"; + //cmnd2 = "java "+(System.getProperty("java.class.path").length() > 0 ? "-cp \""+System.getProperty("java.class.path")+"\"":"")+" RuntimeAdditionalSupport2"; +// cmnd2 = "java " +// + (System.getProperty("java.class.path").length() > 0 ? "-cp " +// + System.getProperty("java.class.path") +// : "") + " RuntimeAdditionalSupport2"; + String ttt = System.getProperty("vm.boot.class.path") +(System.getProperty("java.class.path").length() > 0 ? + File.pathSeparator + System.getProperty("java.class.path") : ""); + cmnd2 = RuntimeAdditionalTest0.javaStarter+" -Xbootclasspath/a:" + ttt + " -cp " + ttt + " java.lang.RuntimeAdditionalSupport2"; + /**/System.out.println("|" + cmnd2 + "|"); + } else { + fail("WARNING (test_41): unknown operating system."); + } + try { + /**/System.out.println("thread11: 1"); + ppp44 = Runtime.getRuntime().exec(cmnd2); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + try { + ppp44.exitValue(); + System.out + .println("WARNING (test_41): java-pipe does not work."); + } catch (IllegalThreadStateException e) { + } + java.io.OutputStream os4 = ppp44.getOutputStream(); + ppp44.getErrorStream(); + java.io.InputStream is4 = ppp44.getInputStream(); + /**/System.out.println("thread11: 2"); + + int ia; + while (true && !flg33) { + if (flg22) { + flg22 = false; + if (stage2 == 0) { + /**/System.out.println("thread11: stage1 - 1"); + os4.write('Z'); + os4.write(10); + stage1 = 1; + flg0 = true; + } else if (stage2 == 1) { + /**/System.out.println("thread11: stage1 - 2"); + os4.flush(); + stage1 = 2; + flg0 = true; + } else if (stage2 == 2) { + /**/System.out.println("thread11: stage1 - 3"); + os4.write('Z'); + os4.write('S'); + os4.write('S'); + os4.write(10); + os4.flush(); + stage1 = 3; + flg0 = true; + } else if (stage2 == 3) { + /**/System.out.println("thread11: stage1 - 4"); + byte[] bbb = new byte[] { 'S', 'e', 'r', 'g', 'u', + 'e', 'i', ' ', 'S', 't', 'e', 'p', 'a', + 'n', 'o', 'v', 'i', 'c', 'h' }; + stage1 = 4; + flg0 = true; + int iii = 0; + while (count < 5 && !flg33) { + while (iii < 1000/*0*/) { + ///**/System.out.println(count+"|"+flg3); + os4.write(bbb); + os4.write(10); + iii++; + try { + Thread.sleep(2); + } catch (Exception e) { + } + } + } + stage1 = 5; + flg0 = true; + os4.write(3); + while ((ia = is4.available()) != 0) { + bbb = new byte[ia]; + is4.read(bbb); + count++; + try { + Thread.sleep(2); + } catch (Exception e) { + } + } + /**/System.out.println("------------------------------------"); + ppp44.destroy(); + ppp44.waitFor(); + /**/System.out.println("------------------------------------"); + break; + } + } + try { + Thread.sleep(20); + } catch (Exception e) { + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_41, thread11): unexpected exception."); + } + } + + protected void finalize() throws Throwable { + super.finalize(); + /**/System.out.println("thread11: finalize"); + System.out.flush(); + } + } + + class thread22 extends Thread { + public void run() { + if (RuntimeAdditionalTest0.os.equals("Win") || RuntimeAdditionalTest0.os.equals("Lin")) { + } else { + fail("WARNING (test_41): unknown operating system."); + } + try { + /**/System.out.println("thread22: 1"); + try { + Thread.sleep(3000); + } catch (Exception e) { + } + java.io.OutputStream os4 = ppp44.getOutputStream(); + java.io.InputStream es4 = ppp44.getErrorStream(); + java.io.InputStream is4 = ppp44.getInputStream(); + /**/System.out.println("thread22: 2"); + ///\\\while (es4.available() == 0) {} + byte[] bbb5 = new byte[is4.available()]; + is4.read(bbb5); + /**/System.out.println(new String(bbb5)); + ///\\\while (is4.available() == 0) {} + /**/System.out.println("thread22: 21"); + Thread.sleep(100); + bbb5 = new byte[is4.available()]; + is4.read(bbb5); + /**/System.out.println(new String(bbb5)); + /**/System.out.println("thread22: 22"); + + //special test case (zero array): + byte[] bbb6 = new byte[0]; + is4.read(bbb6); + os4.write(bbb6); + /**/System.out.println("thread22: 23"); + + flg22 = true; + int ia; + while (true) { + if (flg0) { + int ii = 0; + flg0 = false; + if (stage1 == 1) { + /**/System.out.println("thread22: stage2 - 1"); + while ((ia = es4.available()) == 0 && ii < 500) { + ii++; + try { + Thread.sleep(1); + } catch (Exception e) { + } + } + if ((ia = is4.available()) != 0) { + System.out + .println("ERROR (test_41, thread22): Nothing should be readable before flush."); + /**/System.out.println(ia); + while (is4.available() != 0) { + os4.flush(); + /*System.out.println("=" + */is4.available()/*)*/; + /*System.out.println("|" + + Character.toString((char) */is4 + .read()/*) + "|")*/; + } + System.out + .println("######################################################"); + System.out + .println("## test_41 WARNING: unbuffered stream is diagnosed. ##"); + System.out + .println("######################################################"); + flg33 = true; + return; + } + stage2 = 1; + flg22 = true; + } else if (stage1 == 2) { + /**/System.out.println("thread22: stage2 - 2"); + if ((ia = is4.available()) != 2 + && is4.read() != 'Z' && is4.read() != 10) { + System.out + .println("ERROR (test_41, thread22): Z'10' should be to read."); + flg33 = true; + return; + } + stage2 = 2; + flg22 = true; + } else if (stage1 == 3) { + /**/System.out.println("thread22: stage2 - 3"); + if ((ia = is4.available()) != 4 + && is4.read() != 'Z' && is4.read() != 'S' + && is4.read() != 'S' && is4.read() != 10) { + System.out + .println("ERROR (test_41, thread22): ZSS'10' should be to read."); + //ppp44.destroy(); + flg33 = true; + return; + } + stage2 = 3; + flg22 = true; + } else if (stage1 == 4) { + /**/System.out.println("thread22: stage2 - 4"); + while ((ia = is4.available()) != 0 || stage1 != 5) { + /**/System.out.println("thread22 length of reading: "+ia); + byte[] bbb = new byte[ia]; + is4.read(bbb); + count++; + try { + Thread.sleep(2); + } catch (Exception e) { + } + } + try { + Thread.sleep(1000); + } catch (Exception e) { + } + /**/System.out.println("thread22: " + count); + System.out.println("#####################"); + System.out.println("## test_41 PASSED. ##"); + System.out.println("#####################"); + flg33 = true; + return; + } + } + try { + Thread.sleep(20); + } catch (Exception e) { + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_41, thread22): unexpected exception."); + } + } + + protected void finalize() throws Throwable { + super.finalize(); + /**/System.out.println("thread22: finalize"); + System.out.flush(); + } + } + + static Process ppp44 = null; + + static int count = 0; + + static int stage1 = 0; + + static int stage2 = 0; + + static boolean flg0 = false; + + static boolean flg22 = false; + + static boolean flg33 = false; + + public void test_41() { + System.out.println("==test_41==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_41): unknown operating system."); + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + return; + } + + Runtime.runFinalizersOnExit(true); + Thread t1 = null; + Thread t2 = null; + try { + t1 = new thread11(); + t1.start(); + t2 = new thread22(); + t2.start(); + //t2.join(); + //t1.join(); + while (!flg33) { + try { + Thread.sleep(10); + } catch (Exception e) { + } + } + try { + Thread.sleep(1000); + } catch (Exception e) { + } + ppp44.destroy(); + ppp44.waitFor(); + /**/System.out.println("== joined ==="); + } catch (Exception e) { + e.printStackTrace(); + try { + ppp44.destroy(); + } catch (Exception eee) { + eee.printStackTrace(); + return; + } + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest5.java vm/tests/kernel/java/lang/RuntimeAdditionalTest5.java new file mode 100644 index 0000000..cb8771b --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest5.java @@ -0,0 +1,68 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest5 extends TestCase { + /** + * destroy java process then "exitValue - IllegalThreadStateException" loop + * until the process disappearing + */ + public void test_6() { + System.out.println("==test_6==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_6): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + pi3.destroy(); + while (true) { + try { + /*System.out.println(*/pi3.exitValue()/*)*/; + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_6): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest6.java vm/tests/kernel/java/lang/RuntimeAdditionalTest6.java new file mode 100644 index 0000000..20dc79e --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest6.java @@ -0,0 +1,65 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest6 extends TestCase { + /** + * destroy java process, sleep to be fully aware of process disapearing then + * exitValue, exitValue not receiving the IllegalThreadStateException + */ + public void test_7() { + System.out.println("==test_7==="); + if (RuntimeAdditionalTest0.os.equals("Unk")) { + fail("WARNING (test_7): unknown operating system."); + } + try { + String cmnd = RuntimeAdditionalTest0.javaStarter; + Process pi3 = Runtime.getRuntime().exec(cmnd); + //System.out.println(111); + pi3.destroy(); + //System.out.println(222); + Thread.sleep(5000); + /*System.out.println(*/pi3.exitValue()/*)*/; + /*System.out.println(*/pi3.exitValue()/*)*/; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_7): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest7.java vm/tests/kernel/java/lang/RuntimeAdditionalTest7.java new file mode 100644 index 0000000..074e3b2 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest7.java @@ -0,0 +1,94 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest7 extends TestCase { + /** + * read the result of tree process using the "exitValue - + * IllegalThreadStateException" loop to try to read all outed data + */ + public void test_8() { + System.out.println("==test_8==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm + " /C tree \"C:\\Documents and Settings\""; + cmnd = RuntimeAdditionalTest0.treeStarter+" \"C:\\Documents and Settings\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"tree /lib\""; + //cmnd = "/usr/bin/tree /lib"; + cmnd = RuntimeAdditionalTest0.treeStarter+" /lib"; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + //try { + // Thread.sleep(2000); + //} catch (Exception e) { + //} + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_8): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest8.java vm/tests/kernel/java/lang/RuntimeAdditionalTest8.java new file mode 100644 index 0000000..af0412f --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest8.java @@ -0,0 +1,96 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest8 extends TestCase { + /** + * read the result of "cat <txt-file>" process using the "exitValue - + * IllegalThreadStateException" loop to try to read all outed data + */ + public void test_9() { + System.out.println("==test_9==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd = RuntimeAdditionalTest0.cm+" /C cat \"C:\\IJE\\orp\\ZSS\\___LOG2.DO_VM_CLEAN + // no\""; + cmnd = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.textFile + "\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"cat -v /lib/ld.so\""; + //\\//\\cmnd = "cat -v /lib/ld.so"; + cmnd = "cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + } else { + fail("WARNING (test_1): unknown operating system."); + } + + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + //try { + // Thread.sleep(2000); + //} catch (Exception e) { + //} + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_9): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeAdditionalTest9.java vm/tests/kernel/java/lang/RuntimeAdditionalTest9.java new file mode 100644 index 0000000..2d6a1d5 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeAdditionalTest9.java @@ -0,0 +1,97 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +/* + * Created on March 29, 2006 + * + * This RuntimeAdditionalTest class is used to test the Core API Runtime class + * + */ + +/** + * ############################################################################### + * ############################################################################### + * TODO: 1. + * ############################################################################### + * ############################################################################### + */ + +public class RuntimeAdditionalTest9 extends TestCase { + /** + * read the result of "cat <binary(win-jpg/lin-so)-file>" process using the + * "exitValue - IllegalThreadStateException" loop to try to read all outed + * data + */ + public void test_10() { + System.out.println("==test_10==="); + String cmnd = null; + if (RuntimeAdditionalTest0.os.equals("Win")) { + //cmnd = RuntimeAdditionalTest0.cm+" /C cat \"C:\\WINNT\\system32\\cmd.exe\""; + //\\//\\cmnd = RuntimeAdditionalTest0.cm+" /C cat \"C:\\Documents and Settings\\All + // Users\\Documents\\My Pictures\\Sample Pictures\\Winter.jpg\""; + cmnd = RuntimeAdditionalTest0.cm + " /C cat \"" + RuntimeAdditionalTest0.libFile + "\""; + } else if (RuntimeAdditionalTest0.os.equals("Lin")) { + //cmnd = "sh -c \"cat -v /lib/ld.so\""; + //\\//\\cmnd = "cat -v /lib/ld.so"; + cmnd = "cat -v \"" + RuntimeAdditionalTest0.libFile + "\""; + } else { + fail("WARNING (test_1): unknown operating system."); + } + try { + Process pi3 = Runtime.getRuntime().exec(cmnd); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + + int ia; + while (true) { + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + try { + pi3.exitValue(); + while ((ia = is.available()) != 0) { + byte[] bbb = new byte[ia]; + is.read(bbb); + //\\//\\System.out.println(new String(bbb)); + } + break; + } catch (IllegalThreadStateException e) { + continue; + } + } + + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("ERROR (test_10): unexpected exception."); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/RuntimeTest.java vm/tests/kernel/java/lang/RuntimeTest.java new file mode 100644 index 0000000..69985f9 --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeTest.java @@ -0,0 +1,418 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on January 5, 2005 + * + * This RuntimeTest class is used to test the Core API Runtime class + * + */ + + +/** + * ############################################################################### + * ############################################################################### + * REMINDER("XXX") LIST: + * 1. [Jun 11, 2005] test_availableProcessors, test_freeMemory, test_gc, test_runFinalization, + * test_runFinalizersOnExit fail on "ORP+our Runtime+CLASSPATH API" platform + * because the availableProcessors, freeMemory, runFinalization (runFinalizersOnExit?) + * methods aren't correctly supported yet in orp/drl_natives/src + * 2. [Jun 11, 2005] test_maxMemory, test_totalMemory fail on "ORP+CLASSPATH API" platform + * because the maxMemory + * method isn't correctly supported yet in orp/drl_natives/src: + * (Exception: java.lang.UnsatisfiedLinkError: Error compiling method java/lang/Runtime.maxMemory()J) + * 3. [Jun 11, 2005] test_availableProcessors fails on "ORP+CLASSPATH API" platform + * because the availableProcessors + * method isn't correctly supported yet in orp/drl_natives/src: + * (Exception: java.lang.UnsatisfiedLinkError: Error compiling method java/lang/Runtime.availableProcessors()I) + * ############################################################################### + * ############################################################################### + **/ + +public class RuntimeTest extends TestCase { + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + /** + * + */ + public void test_availableProcessors() { + /**/System.out.println("test_availableProcessors"); + int fR = Runtime.getRuntime().availableProcessors(); + int sR = Runtime.getRuntime().availableProcessors(); + assertEquals("Runtime.availableProcessors method should return the " + + "same value during this test running as a rule!", + fR, sR); + assertTrue("Runtime.availableProcessors method should return " + + "a value greater than 0!(" + fR + "|" + + Runtime.getRuntime().availableProcessors()+ ")", + fR > 0); + //XXX: the next case may be to compare with the bringing via Runtime.exec(...).getOutputStream()... + } + + /** + * + */ + public void test_freeMemory() { + /**/System.out.println("test_freeMemory"); + long r1 = Runtime.getRuntime().freeMemory(); + assertTrue("Runtime.freeMemory method must not return negative value!", + r1 >= 0); + try { + String stmp = ""; + for (int ind = 0; ind < 100; ind++) { + stmp += "0123456789"; + } + while (true) { + stmp += stmp; + if (r1 > Runtime.getRuntime().freeMemory()) + break; + + } + } catch (OutOfMemoryError e) { + fail("Runtime.freeMemory method should be sensitive to huge " + + "memory allocating!"); + } + } + + /** + * + */ + public void test_gc() { + /**/System.out.println("test_gc"); + long r1=Runtime.getRuntime().freeMemory(); + long r2; + long r4; + String[] sa = new String[(int)r1/50000]; + int ind1=0; + try { + String stmp = ""; + for (int ind2=0; ind2<100/* 1000 */; ind2++) { + stmp += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; + } + for (ind1=0; ind1 <(int)r1/50000; ind1++) { + sa[ind1]=""+stmp; + } + + r2=Runtime.getRuntime().freeMemory(); + for (ind1=0; ind1 <(int)r1/50000; ind1++) { + sa[ind1]=null; + Runtime.getRuntime().gc(); + try {Thread.sleep(20);} catch (Exception e) {} + } + sa=null; + try {Thread.sleep(1000);} catch (Exception e) {} + Runtime.getRuntime().gc(); + try {Thread.sleep(1000);} catch (Exception e) {} + r4=Runtime.getRuntime().freeMemory(); + + //assertTrue( "FAILED: gc.check001: Runtime.gc method should initiate garbage collecting!("+r4+">"+r2+"?)", r4>r2 /*r4-r2>49999*/); + if( r4 <= r2 ) { + System.out.println("WARNNING: RuntimeTest.test_gc " + + "check001: It would be better if Runtime.gc method" + + " could initiate garbage collecting! " + + "(Here we have " + r4 + " !> " + r2 + " .)"); + } + } catch (OutOfMemoryError e) { + System.out.println("WARNNING: test_gc did not check " + + "Runtime.gc method due to the technical reason !"); + } + } + + /** + * + */ + public void test_getLocalizedInputStream() { + /**/System.out.println("test_getLocalizedInputStream"); + byte[] bt = new byte[9]; + int res = 0; + java.io.InputStream is = Runtime.getRuntime().getLocalizedInputStream( + new java.io.StringBufferInputStream( + "\u005a\u0061\u0070\u0072\u0065\u0079\u0065\u0076")); + try { + res = is.read(bt); + } + catch(Exception e) { + fail("Runtime.getLocalizedInputStream method should return " + + "correct input stream!"); + } + assertEquals("Incorrect number of bytes returned by InputStream!", + 8, res); + //assertTrue("FAILED: getLocalizedInputStream.check003: Runtime.getLocalizedInputStream method should return correct input stream ("+new String(bt)+")!", new String(bt).indexOf("Zapreyev")==0); + } + + /** + * + */ + public void test_getLocalizedOutputStream() { + /**/System.out.println("test_getLocalizedOutputStream"); + byte[] bt1 = {0x5a, 0x61, 0x70, 0x72, 0x65, 0x79, 0x65, 0x76}; + byte[] bt2 = new byte[9]; + java.io.PipedInputStream pis = new java.io.PipedInputStream(); + java.io.OutputStream os = null; + try { + os = Runtime.getRuntime().getLocalizedOutputStream( + new java.io.PipedOutputStream(pis)); + } catch (Exception e) { + fail("check001: unexpected exception " + e); + } + try { + os.write(bt1); + } catch (Exception e) { + fail("check002: unexpected exception " + e); + } + try { + pis.read(bt2); + } catch (Exception e) { + fail("check003: unexpected exception " + e); + } + assertTrue("Incorrect bytes written by outputStream: " + new String(bt2) + + ")!", + new String(bt2).indexOf("Zapreyev") == 0); + } + + /** + * + */ + public void test_getRuntime() { + /**/System.out.println("test_getRuntime"); + Runtime r1 = Runtime.getRuntime(); + assertNotNull("Runtime.getRuntime method must not return null!", r1); + for (int ind2 = 0; ind2 < 1000; ind2++) { + assertSame( + "Runtime.getRuntime() should always return the same value!", + r1, Runtime.getRuntime()); + } + } + + /** + * + */ + public void test_load() { + /**/System.out.println("test_load"); + String jLP = null; + String jlp = System.getProperty("java.library.path"); + String vblp = System.getProperty("vm.boot.library.path"); + jLP = (jlp != null && jlp.length() != 0 ? jlp : "") + + (vblp != null && vblp.length() != 0 ? File.pathSeparator + + vblp : ""); + if (jLP.length() == 0) { + fail("empty java.library.path!"); + } + String[] paths = jLP.split(File.pathSeparator); + String ext = (System.getProperty("os.name").indexOf("indows") != -1) + ? ".dll" + : ".so"; + int ind1; + int ind2; + File[] asf = null; + for (ind1 = 0; ind1 < paths.length; ind1++) { + asf = new java.io.File(paths[ind1]).listFiles(); + if (asf != null) { + for (ind2 = 0; ind2 < asf.length; ind2++) { + if (asf[ind2].getName().indexOf(ext) != -1) { + try { + Runtime.getRuntime().load( + asf[ind2].getCanonicalPath()); + return; + } catch (UnsatisfiedLinkError e) { + continue; + } catch (Throwable e) { + continue; + } + } + } + } + } + fail("Runtime.loadLibrary method has not loaded a dynamic library!"); + } + + /** + * + */ + public void test_loadLibrary() { + /**/System.out.println("test_loadLibrary"); + String jLP = null; + String jlp = System.getProperty("java.library.path"); + String vblp = System.getProperty("vm.boot.library.path"); + jLP = (jlp != null && jlp.length() != 0 ? jlp : "") + + (vblp != null && vblp.length() != 0 + ? File.pathSeparator + vblp + : ""); + if (jLP.length() == 0) { + fail("empty java.library.path!"); + } + String[] paths = jLP.split(File.pathSeparator); + String ext = (System.getProperty("os.name").indexOf("indows") != -1 + ? ".dll" + :".so"); + int ind1; + int ind2; + File[] asf = null; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + asf = new java.io.File(paths[ind1]).listFiles(); + if (asf != null) { + for (ind2 = 0; ind2 < asf.length; ind2++) { + if (asf[ind2].getName().indexOf(ext) != -1) { + String libName = asf[ind2].getName(); + if (ext.equals(".dll")) { + libName = libName.substring(0, libName.length() - 4); + } else { + libName = libName.substring(3, libName.length() - 3); + } + try { + Runtime.getRuntime().loadLibrary(libName); + return; + } catch (UnsatisfiedLinkError e) { + continue; + } catch (Throwable e) { + continue; + } + + } + } + } + } + fail("Runtime.loadLibrary method has not loaded a dynamic library!"); + } + + /** + * + */ + public void test_maxMemory() { + /**/System.out.println("test_maxMemory"); + long r1 = Runtime.getRuntime().freeMemory(); + long r2 = Runtime.getRuntime().maxMemory(); + assertTrue("Runtime.maxMemory method must not return negative value!", + r2 >= 0); + assertTrue( + "Runtime.maxMemory must be greater than Runtime.freeMemory!", + r2 >= r1); + for (int ind2 = 0; ind2 < 1000; ind2++) { + //assertSame("Runtime.maxMemory() must always return the same value!", + // r2, Runtime.getRuntime().maxMemory()); + assertTrue( "FAILED: test_maxMemory: Runtime.maxMemory method should return same value each time!", r2==Runtime.getRuntime().maxMemory()); + } + } + + /** + * + */ + public void test_totalMemory() { + /**/System.out.println("test_totalMemory"); + long r1 = Runtime.getRuntime().freeMemory(); + long r2 = Runtime.getRuntime().maxMemory(); + long r3 = Runtime.getRuntime().totalMemory(); + assertTrue("Runtime.totalMemory() should not return negative value!", + r3 >= 0); + assertTrue( + "Runtime.totalMemory() should be greater than " + + "Runtime.freeMemory()!", + r3 >= r1); + assertTrue( + "Runtime.totalMemory() should be smaller than " + + "Runtime.maxMemory()!", + r2 >= r3); + for (int ind2 = 0; ind2 < 1000; ind2++) { + assertTrue("Runtime.totalMemory, Runtime.freeMemory, " + + "Runtime.maxMemory should correlate correctly!", + Runtime.getRuntime().freeMemory() <= Runtime.getRuntime() + .totalMemory() + && Runtime.getRuntime().maxMemory() >= Runtime + .getRuntime().totalMemory()); + } + } + + /** + * + */ + public void test_traceInstructions() { + /**/System.out.println("test_traceInstructions"); + java.util.Random r = new java.util.Random(); + try { + for (int ind2 = 0; ind2 < 1000; ind2++) { + Runtime.getRuntime() + .traceInstructions((r.nextInt(10) % 2) == 0); + Integer.toString(ind2); + } + } catch (Throwable e) { + fail("Unexpected exception: " + e); + } + } + + /** + * + */ + public void test_traceMethodCalls() { + /**/System.out.println("test_traceMethodCalls"); + java.util.Random r = new java.util.Random(); + try { + for (int ind2 = 0; ind2 < 1000; ind2++) { + Runtime.getRuntime().traceMethodCalls((r.nextInt(10) % 2) == 0); + Math.pow((long) ind2, (long) ind2); + Math.IEEEremainder((double) ind2, (double) ind2); + } + } catch (Throwable e) { + fail("Unexpected exception: " + e); + } + } + + /** + * + */ + public void test_halt() { + //System.out.println("test_halt"); + //Runtime.getRuntime().halt(777); + //fail("what's wrong ;) ?"); + } + + /** + * + */ + public void test_exit() { + //System.out.println("test_exit"); + //Runtime.getRuntime().exit(777); + //fail("what's wrong ;) ?"); + } +} diff --git vm/tests/kernel/java/lang/RuntimeTest2.java vm/tests/kernel/java/lang/RuntimeTest2.java new file mode 100644 index 0000000..3a91a5f --- /dev/null +++ vm/tests/kernel/java/lang/RuntimeTest2.java @@ -0,0 +1,910 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import junit.framework.TestCase; + +/* + * Created on January 5, 2005 + * + * This RuntimeTest class is used to test the Core API Runtime class + * + */ + + +/** + * ############################################################################### + * ############################################################################### + * REMINDER("XXX") LIST: + * 1. [Jun 11, 2005] test_availableProcessors, test_freeMemory, test_gc, test_runFinalization, + * test_runFinalizersOnExit fail on "ORP+our Runtime+CLASSPATH API" platform + * because the availableProcessors, freeMemory, runFinalization (runFinalizersOnExit?) + * methods aren't correctly supported yet in orp/drl_natives/src + * 2. [Jun 11, 2005] test_maxMemory, test_totalMemory fail on "ORP+CLASSPATH API" platform + * because the maxMemory + * method isn't correctly supported yet in orp/drl_natives/src: + * (Exception: java.lang.UnsatisfiedLinkError: Error compiling method java/lang/Runtime.maxMemory()J) + * 3. [Jun 11, 2005] test_availableProcessors fails on "ORP+CLASSPATH API" platform + * because the availableProcessors + * method isn't correctly supported yet in orp/drl_natives/src: + * (Exception: java.lang.UnsatisfiedLinkError: Error compiling method java/lang/Runtime.availableProcessors()I) + * ############################################################################### + * ############################################################################### + **/ + +public class RuntimeTest2 extends TestCase { + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + } + + + /** + * + */ + static class forInternalUseOnly { + String stmp; + + forInternalUseOnly () { + this.stmp = ""; + for (int ind2 = 0; ind2 < 100; ind2++) { + this.stmp += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; + } + } + protected void finalize() throws Throwable { + runFinalizationFlag = true; + super.finalize(); + } + } + + static boolean runFinalizationFlag = false; + public void test_runFinalization() { + //System.out.println("test_runFinalization"); + runFinalizationFlag = false; + for (int ind2 = 0; ind2 < 10; ind2++) { + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + // Runtime.getRuntime().runFinalization(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check001: Unexpected exception: " + e); + } + Runtime.getRuntime().gc(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check002: Unexpected exception: " + e); + } + Runtime.getRuntime().runFinalization(); + } + assertTrue("finalization has not been run", runFinalizationFlag); + } + + /** + * + */ + public void test_runFinalizersOnExit() { + /**/System.out.println("test_runFinalizersOnExit"); + runFinalizationFlag = false; + for (int ind2 = 0; ind2 < 5; ind2++) { + Runtime.runFinalizersOnExit(false); + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + // / Runtime.getRuntime().runFinalization(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check001: Unexpected exception: " + e); + } + Runtime.getRuntime().gc(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check002: Unexpected exception: " + e); + } + // / Runtime.getRuntime().runFinalization(); + } + assertTrue("check003: finalizers were not run", runFinalizationFlag); + + runFinalizationFlag = false; + for (int ind2 = 0; ind2 < 5; ind2++) { + Runtime.runFinalizersOnExit(true); + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + // / Runtime.getRuntime().runFinalization(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check004: Unexpected exception: " + e); + } + Runtime.getRuntime().gc(); + try { + Thread.sleep(10); + } catch (Exception e) { + fail("check005: Unexpected exception: " + e); + } + // / Runtime.getRuntime().runFinalization(); + } + assertTrue("check006: finalizers were not run", runFinalizationFlag); + } + + /** + * + */ + class threadForInternalUseOnly1 extends Thread { + public void run() { + // System.out.println("START threadForInternalUseOnly1"); + int I = threadForInternalUseOnly2.getI(); + int counter = 0; + while ((I < 50 || number < I) && counter < 24000) { + try { + Thread.sleep(50); + } catch (Exception e) { + } + I = threadForInternalUseOnly2.getI(); + counter += 1; + } + // System.out.println("FINISH threadForInternalUseOnly1"); + } + + protected void finalize() throws Throwable { + // System.out.println(">>>>>>>>>>>>>>START + // threadForInternalUseOnly1.finalize"); + if (runFinalizationFlag2 == 1 || runFinalizationFlag2 == 11 + || runFinalizationFlag2 == 21) { + // :) // assertTrue( "FAILED: addShutdownHook.check001", false); + } + super.finalize(); + //System.out.println(">>>>>>>>>>>>>>FINISH threadForInternalUseOnly1.finalize"); + } + } + + static class threadForInternalUseOnly2 extends Thread { + static int I = 0; + long NM; + int ORD; + + synchronized static void incrI() { + I++; + }; + + synchronized static int getI() { + return I; + }; + + threadForInternalUseOnly2(int ind) { + super(); + NM = System.currentTimeMillis(); + ORD = ind; + } + + public void run() { + // System.out.println("START threadForInternalUseOnly2: "+ORD); + if (ORD == 1 || ORD == 11 || ORD == 21) { + synchronized (threadForInternalUseOnly2.class) { + runFinalizationFlag2 = ORD; + } + } + incrI(); + for (int j = 0; j < 30/* 100 */; j++) { + try { + Thread.sleep(10); + } catch (Exception e) { + } + } + // System.out.println("FINISH threadForInternalUseOnly2: "+ORD); + } + + protected void finalize() throws Throwable { + // System.out.println("<<<<<<<<<<<<<<<<<START + // threadForInternalUseOnly2.finalize"); + if (runFinalizationFlag2 == 1 || runFinalizationFlag2 == 11 + || runFinalizationFlag2 == 21) { + // :) // assertTrue( "FAILED: addShutdownHook.check002", false); + } + super.finalize(); + // System.out.println("<<<<<<<<<<<<<<<<<FINISH + // threadForInternalUseOnly2.finalize"); + } + } + + static class threadForInternalUseOnly3 extends Thread { + static int I = 0; + + synchronized static void incrI() { + I++; + }; + + synchronized static int getI() { + return I; + }; + + public void run() { + // System.out.println("Run threadForInternalUseOnly3: "+getI()); + incrI(); + } + } + + static int runFinalizationFlag2 = -1; + static int number = 4; //100; + static int nthr = 2; //21; + + public void test_addShutdownHook() { + /**/System.out.println("test_addShutdownHook"); + Thread[] thr = new Thread[number]; + for (int i = 0; i < number / 2; i++) { + Runtime + .getRuntime() + .addShutdownHook( + thr[2 * i + 0] = new threadForInternalUseOnly3());// null);// + try { + Thread.sleep(5); + } catch (Exception e) { + } + Runtime.getRuntime().addShutdownHook( + thr[2 * i + 1] = new threadForInternalUseOnly2(2 * i + 1)); + try { + Thread.sleep(5); + } catch (Exception e) { + } + } + // System.out.println("2test_addShutdownHook"); + Runtime.runFinalizersOnExit(true); + new threadForInternalUseOnly1().start(); + try { + Runtime.getRuntime().addShutdownHook(thr[nthr]); + fail("IllegalArgumentException has not been thrown"); + } catch (IllegalArgumentException e) { + } + //System.out.println("3test_addShutdownHook"); + } + + /** + * + */ + public void test_removeShutdownHook() { + /**/System.out.println("test_removeShutdownHook"); + Thread[] thr = new Thread[number]; + for (int i = 0; i < number / 2; i++) { + Runtime.getRuntime().addShutdownHook( + thr[2 * i + 0] = new threadForInternalUseOnly3()); + try { + Thread.sleep(5); + } catch (Exception e) { + } + Runtime.getRuntime().addShutdownHook( + thr[2 * i + 1] = new threadForInternalUseOnly2(2 * i + 1)); + try { + Thread.sleep(5); + } catch (Exception e) { + } + } + // Runtime.getRuntime().removeShutdownHook(thr[1]); + // Runtime.getRuntime().removeShutdownHook(thr[11]); + Runtime.getRuntime().removeShutdownHook(thr[nthr]); + new threadForInternalUseOnly1().start(); + try { + // Runtime.getRuntime().addShutdownHook(thr[1]); + // Runtime.getRuntime().addShutdownHook(thr[11]); + Runtime.getRuntime().addShutdownHook(thr[nthr]); + // Runtime.getRuntime().removeShutdownHook(thr[1]); + // Runtime.getRuntime().removeShutdownHook(thr[11]); + Runtime.getRuntime().removeShutdownHook(thr[nthr]); + // Runtime.getRuntime().removeShutdownHook(thr[1]); + // Runtime.getRuntime().removeShutdownHook(thr[11]); + Runtime.getRuntime().removeShutdownHook(thr[nthr]); + } catch (Exception e) { + fail("Unexpected Exception: " + e); + } + } + + /** + * + */ + public void test_exec_Str() { + /**/System.out.println("test_exec_Str"); + if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) { + try { + String pathList = System.getProperty("java.library.path"); + String[] paths = pathList.split(File.pathSeparator); + String cmnd = null; + int ind1; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + File asf = new java.io.File(paths[ind1] + File.separator + + "cmd.exe"); + if (asf.exists()) { + cmnd = paths[ind1] + File.separator + "cmd.exe"; + break; + } + } + if (cmnd == null) { + if (new java.io.File( + // XXX:IA64? + (cmnd = "C:\\WINNT\\system32\\cmd.exe")).exists()) { + } else if (new java.io.File( + // XXX:IA64? + (cmnd = "C:\\WINDOWS\\system32\\cmd.exe")).exists()) { + } else { + fail("cmd.exe hasn't been found! Please, set the path" + + " to cmd.exe via java.library.path property."); + } + } + cmnd = cmnd + " /C date"; + Process pi3 = Runtime.getRuntime().exec(cmnd); + // System.out.println("1test_exec_Str"); + try { + Thread.sleep(2000); + } catch (Exception e) { + } + java.io.OutputStream os = pi3.getOutputStream(); + pi3.getErrorStream(); + java.io.InputStream is = pi3.getInputStream(); + if (is.available() < 1) { + fail("exec(String[], String[], File).check001: where is " + + "the date's answer/request?"); + } + // System.out.println("2test_exec_Str"); + // System.out.println("is.available()"+is.available()); + int ia = is.available(); + byte[] bb = new byte[ia]; + is.read(bb); + // System.out.println("3test_exec_Str"); + String r1 = new String(bb); + if (r1.indexOf("The current date is") == -1 + || r1.indexOf("Enter the new date") == -1) { + fail("exec(String[], String[], File).check002: where is " + + "the date's answer/request?"); + } + // System.out.println("4test_exec_Str"); + for (int ii = 0; ii < ia; ii++) { + bb[ii] = (byte) 0; + } + + // byte[] ans = {'1','1','-','1','3','-','0','4','\n'}; + // os.write(ans); + // os.write('1'); + // os.write('3'); + // os.write('-'); + // os.write('1'); + // os.write('3'); + // os.write('-'); + // os.write('1'); + // os.write('3'); + // os.write('\n'); + os.write('x'); + os.write('x'); + os.write('-'); + os.write('x'); + os.write('x'); + os.write('-'); + os.write('x'); + os.write('x'); + os.write('\n'); + os.flush(); + + try { + Thread.sleep(2000); + } catch (Exception e) { + } + if (is.available() < 1) { + fail("exec(String[], String[], File).check003: where is " + + "the date's reaction on the incorrect entering?"); + } + ia = is.available(); + byte[] bbb = new byte[ia]; + is.read(bbb); + r1 = new String(bbb); + if (r1.indexOf("The system cannot accept the date entered") == -1 + && r1.indexOf("Enter the new date") == -1) { + fail("exec(String[], String[], File).check004: where is " + + "the date's reaction on the incorrect enterring?"); + } + os.write('\n'); + try { + pi3.exitValue(); + } catch (IllegalThreadStateException e) { + os.flush(); + try { + pi3.waitFor(); + } catch (InterruptedException ee) { + } + } + // System.out.println("5test_exec_Str"); + // os.write('\n'); + // os.write('\n'); + // os.flush(); + pi3.destroy(); + // pi3.waitFor(); + } catch (java.io.IOException eeee) { + eeee.printStackTrace(); + System.out.println("test_exec_Str test hasn't finished correctly because of the competent IOException."); + return; + } catch (Exception eeee) { + eeee.printStackTrace(); + fail("check005: UnexpectedException on " + + "exec(String[], String[], File)"); + } + } else if (System.getProperty("os.name").toLowerCase() + .indexOf("linux") != -1) { + // TODO + } else { + //UNKNOWN + } + } + + /** + * + */ + public void test_exec_StrArr() { + /**/System.out.println("test_exec_StrArr"); + String[] command = null; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + command = new String[]{"cmd", "/C", "echo S_O_M_E_T_H_I_N_G"}; + } else { + command = new String[]{"/bin/sh", "-c", "echo S_O_M_E_T_H_I_N_G"}; + } + String procValue = null; + try { + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + procValue = br.readLine(); + } catch (IOException e) { + fail("Unexpected IOException"); + } + assertTrue("echo command has not been run", + procValue.indexOf("S_O_M_E_T_H_I_N_G") != -1); + } + + /** + * + */ + public void test_exec_StrArr_StrArr() { + /**/System.out.println("test_exec_StrArr"); + String[] command = null; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + command = new String[] {"cmd", "/C", "echo %Z_S_S%"}; + } else { + command = new String[] {"/bin/sh", "-c", "echo $Z_S_S"}; + } + String procValue = null; + try { + Process proc = Runtime.getRuntime().exec(command, + new String[] {"Z_S_S=S_O_M_E_T_H_I_N_G"}); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + procValue = br.readLine(); + } catch (IOException e) { + fail("Unexpected IOException"); + } + assertTrue("echo command has not been run", + procValue.indexOf("S_O_M_E_T_H_I_N_G") != -1); + } + + /** + * + */ + public void test_exec_StrArr_StrArr_Fil() { + /**/System.out.println("test_exec_StrArr"); + String[] command = null; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + command = new String[] {"cmd", "/C", "env"}; + } else { + command = new String[] {"/bin/sh", "-c", "env"}; + } + String as[]; + int len = 0; + try { + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + while (br.readLine() != null) { + len++; + } + + } catch (IOException e) { + fail("check001: Unexpected IOException"); + } + as = new String[len]; + try { + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + for (int i = 0; i < len; i++) { + as[i] = br.readLine(); + } + + } catch (IOException e) { + fail("check002: Unexpected IOException"); + } +/**/ + if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) { + as = new String[]{"to_avoid=#s1s2f1t1"}; // <<<<<<<<<<< !!! to remember + command = new String[]{"cmd", "/C", "dir"}; + } else { + command = new String[]{"sh", "-c", "pwd"}; + } + try { + Process proc = Runtime.getRuntime().exec(command, as, new File(System.getProperty("java.io.tmpdir"))); + BufferedReader br = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + //for (int i = 0; i < len; i++) { + String ln; + while ( (ln = br.readLine()) != null) { + if(ln.indexOf(System.getProperty("java.io.tmpdir").substring(0,System.getProperty("java.io.tmpdir").length() -1 ))!=-1) { + return; + } + } + fail("Error3"); + } catch (IOException e) { + e.printStackTrace(); + fail("Error4"); + } + fail("Error5"); +/**/ + } + + /** + * + */ + public void test_exec_Str_StrArr() { + /**/System.out.println("test_exec_StrArr"); + String command = null; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + command = "cmd /C \"echo %Z_S_S_2%\""; + } else { + //command = "/bin/sh -c \"echo $Z_S_S_2\""; + //command = "/bin/echo $Z_S_S_2"; + command = "/usr/bin/env"; + } + String procValue = null; + try { + Process proc = Runtime.getRuntime().exec(command, + new String[] {"Z_S_S_2=S_O_M_E_T_H_I_N_G"}); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + while ((procValue = br.readLine()) != null) { + if (procValue.indexOf("S_O_M_E_T_H_I_N_G") != -1) { + return; + } + fail("It should be the only singl environment variable here (" + procValue + ")"); + } + fail("Z_S_S_2 var should be present and assingned correctly."); + } catch (IOException e) { + fail("Unexpected IOException"); + } + /**/ + // Commented because the drlvm issue + try { + Process proc = Runtime.getRuntime().exec(command, new String[] { + "Z_S_S_2=S_O_M_E_T_H_I_N_G_s1s2f1t1", //<<<<<<<<<<< !!! to remember + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "Z_S_S_3=S_O_M_E_T_H_I_N_G L_O_N_GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + }); + BufferedReader br = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + procValue = br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + fail("Error3"); + } + assertTrue("Error4",procValue.indexOf("S_O_M_E_T_H_I_N_G")!=-1); + /**/ + } + + /** + * + */ + public void test_exec_Str_StrArr_Fil() { + /**/System.out.println("test_exec_Str_StrArr_Fil"); + String[] command = null; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + command = new String[] {"cmd", "/C", "env"}; + } else { + command = new String[] {"/bin/sh", "-c", "env"}; + } + String as[]; + int len = 0; + try { + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + while (br.readLine() != null) { + len++; + } + } catch (IOException e) { + fail("check001: Unexpected IOException"); + } + as = new String[len]; + try { + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader(proc + .getInputStream())); + for (int i = 0; i < len; i++) { + as[i] = br.readLine(); + } + + } catch (IOException e) { + fail("check002: Unexpected IOException"); + } +/**/ + String command2; + if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) { + as = new String[]{"to_avoid=#s1s2f1t1"};//<<<<<<<<<<< !!! to remember + command2 = "cmd /C dir"; + } else { + command2 = "sh -c pwd"; + } + try { + Process proc = Runtime.getRuntime().exec(command2, as, new File(System.getProperty("java.io.tmpdir"))); + BufferedReader br = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + String ln; + while ( (ln = br.readLine()) != null) { + if(ln.indexOf(System.getProperty("java.io.tmpdir").substring(0,System.getProperty("java.io.tmpdir").length() -1 ))!=-1) { + return; + } + } + fail("Error3"); + } catch (IOException e) { + e.printStackTrace(); + fail("Error4"); + } + fail("Error5"); +/**/ + } + + /** + * + */ + public void test_exec_Str_F2T1S2Z() { + /**/System.out.println("test_exec_Str_F2T1S2Z"); + String line; + if (System.getProperty("os.name").toLowerCase() + .indexOf("windows") != -1) { + String strarr[] = {"7", "Hello", "HELL", "Hello", "world", + "World hello", "vasa", "d:?*/\\ World", "hello"}; + try { + String pathList = System.getProperty("java.library.path"); + String[] paths = pathList.split(File.pathSeparator); + String cmnd = null; + int ind1; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + File asf = new java.io.File(paths[ind1] + File.separator + + "cmd.exe"); + if (asf.exists()) { + cmnd = paths[ind1] + File.separator + "cmd.exe"; + break; + } + } + if (cmnd == null) { + if (new java.io.File( + (cmnd = "C:\\WINNT\\system32\\cmd.exe")).exists()) { // XXX:IA64? + } else if (new java.io.File( + (cmnd = "C:\\WINDOWS\\system32\\cmd.exe")).exists()) { // XXX:IA64? + } else { + fail("check001: cmd.exe hasn't been found! " + + "Please, set the path to cmd.exe via " + + "java.library.path property."); + } + } + File f = new java.io.File("C:\\CygWin\\bin"); + Process p; + if (f.exists()) { + p = Runtime.getRuntime().exec(new String[] { + cmnd, "/C", "sh", "-c", + "echo $#; echo $0; echo $1; echo $2; echo $3; " + + "echo $4; echo $5; echo $6; echo $7", + "Hello", "HELL", "\"Hello\" \"world\"", + "World hello", "vas\"a d:?*/\\", "\"World hello\""}, + new String[] {}, f); + p.waitFor(); + } else { + p = Runtime.getRuntime().exec(new String[] { + cmnd, "/C", "sh", "-c", + "echo $#; echo $0; echo $1; echo $2; echo $3; " + + "echo $4; echo $5; echo $6; echo $7", + "Hello", "HELL", "\"Hello\" \"world\"", + "World hello", "vas\"a d:?*/\\", "\"World hello\""}); + if (p.waitFor() != 0) { + fail("check002: sh.exe seems to have not been found " + + "by default! Please, set the path to sh.exe" + + " via java.library.path property."); + } + } + BufferedReader input = new BufferedReader( + new InputStreamReader(p.getErrorStream())); + boolean flg = false; + while ((line = input.readLine()) != null) { + flg = true; + System.err.println("ErrorStream: " + line); + } + input.close(); + if (flg) { + fail("check003: ErrorStream should be empty!"); + } + input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + int i = 0; + while ((line = input.readLine()) != null) { + if (!line.equals(strarr[i])) { + flg = true; + System.out.println(line + " != " + strarr[i]); + } + i++; + } + input.close(); + if (flg) { + fail("An uncoincidence was found (see above)!"); + } + } catch (Exception eeee) { + fail("check004: Unexpected exception on " + + "exec(String[], String[], File)"); + } + } else if (System.getProperty("os.name").toLowerCase() + .indexOf("linux") != -1) { + String strarr[] = {"6",System.getProperty("java.io.tmpdir") + + File.separator + + "vasja", "Hello", "HELL", "\"Hello\" \"world\"", + "World hello", "vas\"a d:?*/\\" }; + java.io.File fff = null; + java.io.PrintStream ps = null; + try { + fff = new java.io.File(System.getProperty("java.io.tmpdir") + + File.separator + "vasja"); + fff.createNewFile(); + ps = new java.io.PrintStream(new java.io.FileOutputStream(fff)); + ps.println("{ echo $#; echo $0; echo $1; " + + "echo $2; echo $3; echo $4; echo $5; }"); + } catch (Throwable e) { + System.err.println(e); + System.err.println(System.getProperty("user.home") + + File.separator + "vasja"); + new Throwable().printStackTrace(); + fail("Preparing fails!"); + } + try { + String pathList = System.getProperty("java.library.path"); + String[] paths = pathList.split(File.pathSeparator); + String cmnd = null; + int ind1; + for (ind1 = 0; ind1 < paths.length; ind1++) { + if (paths[ind1] == null) { + continue; + } + File asf = new java.io.File(paths[ind1] + File.separator + + "sh"); + if (asf.exists()) { + cmnd = paths[ind1] + File.separator + "sh"; + break; + } + } + if (cmnd == null) { + cmnd = "/bin/sh"; + } + File f = new java.io.File("/bin"); + Process p; + if (f.exists()) { + p = Runtime.getRuntime().exec(new String[] { + cmnd, System.getProperty("java.io.tmpdir") + + File.separator + "vasja", "Hello", "HELL", + "\"Hello\" \"world\"", "World hello", + "vas\"a d:?*/\\", "\"World hello\"" }, + new String[] {}, f); + p.waitFor(); + } else { + p = Runtime.getRuntime().exec(new String[] { + cmnd, System.getProperty("java.io.tmpdir") + + File.separator + "vasja", "Hello", "HELL", + "\"Hello\" \"world\"", "World hello", + "vas\"a d:?*/\\", "\"World hello\"" }); + if (p.waitFor() != 0) { + fail("check005: sh.exe seems to have not been found" + + " by default! Please, set the path to sh.exe" + + " via java.library.path property."); + } + } + BufferedReader input = new BufferedReader( + new InputStreamReader(p.getErrorStream())); + boolean flg = false; + while ((line = input.readLine()) != null) { + flg = true; + System.err.println("ErrorStream: " + line); + } + input.close(); + if (flg) { + fail("check006: ErrorStream should be empty!"); + } + + input = new BufferedReader(new InputStreamReader(p + .getInputStream())); + int i = 0; + while ((line = input.readLine()) != null) { + if (!line.equals(strarr[i])) { + flg = true; + System.out.println(line + " != " + strarr[i]); + } + i++; + } + input.close(); + if (flg) { + fail("check007: An uncoincidence was found (see above)!"); + } + } catch (Exception eeee) { + fail("check008: Unexpected exception on " + + "exec(String[], String[], File)"); + } + try { + fff.delete(); + } catch (Throwable _) { + } + } else { + //UNKNOWN + } + } +} diff --git vm/tests/kernel/java/lang/SecurityManagerRTest.java vm/tests/kernel/java/lang/SecurityManagerRTest.java new file mode 100644 index 0000000..7aece55 --- /dev/null +++ vm/tests/kernel/java/lang/SecurityManagerRTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Vladimir Ivanov + * @version $Revision$ + */ + +package java.lang; + +import org.apache.harmony.test.ReversibleSecurityManager; + +import junit.framework.TestCase; + +public class SecurityManagerRTest extends TestCase { + + public void testSetSM() { + SecurityManager sm = System.getSecurityManager(); + try { + System.setSecurityManager(new ReversibleSecurityManager()); + new Test().m(); + } finally { + System.setSecurityManager(sm); + } + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(SecurityManagerRTest.class); + } + +} + +class Test { + void m() { + new test1(); + } + + class test1 { + } +} diff --git vm/tests/kernel/java/lang/StackTraceElementTest.java vm/tests/kernel/java/lang/StackTraceElementTest.java new file mode 100644 index 0000000..a736bb9 --- /dev/null +++ vm/tests/kernel/java/lang/StackTraceElementTest.java @@ -0,0 +1,151 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Dmitry B. Yershov + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +public class StackTraceElementTest extends TestCase { + + /** + * Constructor under test StackTraceElement(String, int, String, + * String, boolean) + */ + public void testStackTraceElement() { + String[] fileName = new String[] {null, "", "file"}; + int[] lineNumber = new int[] {-10, 0, 10}; + String declaringClass = "class"; + String methodName = "method"; + try { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + new StackTraceElement(declaringClass, methodName, fileName[i], + lineNumber[j]); + } catch (Throwable th) { + fail("Constructor should work with all types of data"); + } + } + + /** + * Method under test boolean Equals(Object) + */ + public void testEquals() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 2); + StackTraceElement ste1 = new StackTraceElement("class", "method", "file", -2); + StackTraceElement ste2 = new StackTraceElement("class1", "method", "file", 2); + StackTraceElement ste3 = new StackTraceElement("class", "method1", "file", 2); + StackTraceElement ste4 = new StackTraceElement("class", "method", "file1", 2); + StackTraceElement ste5 = new StackTraceElement("class", "method", "file", 2); + assertFalse("Assert 0: objects should differ", ste.equals(new Object())); + assertFalse("Assert 1: objects should differ", ste.equals(ste1)); + assertFalse("Assert 2: objects should differ", ste.equals(ste2)); + assertFalse("Assert 3: objects should differ", ste.equals(ste3)); + assertFalse("Assert 4: objects should differ", ste.equals(ste4)); + assertTrue("Assert 5: objects should equal", ste.equals(ste5)); + } + + /** + * Method under test String getClassName() + */ + public void testGetClassName() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + assertEquals("incorrect class name", "class", ste.getClassName()); + } + + /** + * Method under test String getFileName() + */ + public void testGetFileName() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + assertEquals("incorrect file name", "file", ste.getFileName()); + } + + /** + * Method under test int getLineNumber() + */ + public void testGetLineNumber() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + assertEquals("incorrect line number", 1, ste.getLineNumber()); + } + + /** + * Method under test String getMethodName() + */ + public void testGetMethodName() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + assertEquals("incorrect file name", "method", ste.getMethodName()); + } + + /** + * Method under test int hashCode() + */ + public void testHashCode() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + StackTraceElement ste1 = new StackTraceElement("class", "method", "file", 1); + assertEquals("hash codes should equal", ste.hashCode(), ste1.hashCode()); + } + + /** + * Method under test boolean isNativeMethod() + * when file name is null + */ + public void testIsNativeMethod() { + StackTraceElement ste = new StackTraceElement("class", "method", null, -2); + assertTrue("method should be native", ste.isNativeMethod()); + ste = new StackTraceElement("class", "method", "file", 1); + assertFalse("method should not be native", ste.isNativeMethod()); + } + + /** + * Method under test boolean isNativeMethod() + * when file name is not null + */ + public void testIsNativeMethod_FileNotNull() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", -2); + assertTrue("method should be native", ste.isNativeMethod()); + ste = new StackTraceElement("class", "method", "file", 1); + assertFalse("method should not be native", ste.isNativeMethod()); + } + + /** + * Method under test String toString() + */ + public void testToString() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", 1); + assertEquals("Assert 0: incorrect output", "class.method(file:1)", ste.toString()); + ste = new StackTraceElement("class", "method", "file", -1); + assertEquals("Assert 0: incorrect output", "class.method(file)", ste.toString()); + ste = new StackTraceElement("class", "method", null, 1); + assertEquals("Assert 0: incorrect output", "class.method(Unknown Source)", ste.toString()); + ste = new StackTraceElement("class", "method", null, -1); + assertEquals("Assert 0: incorrect output", "class.method(Unknown Source)", ste.toString()); + ste = new StackTraceElement("class", "method", null, -2); + assertEquals("Assert 0: incorrect output", "class.method(Native Method)", ste.toString()); + } + + /** + * Method under test String toString() + * when file name is null and line number is -2 + */ + public void testToString_FileNotNullLineMinus2() { + StackTraceElement ste = new StackTraceElement("class", "method", "file", -2); + assertEquals("incorrect output", "class.method(file)", ste.toString()); + } +} diff --git vm/tests/kernel/java/lang/SystemExtensionTest.java vm/tests/kernel/java/lang/SystemExtensionTest.java new file mode 100644 index 0000000..02bf83c --- /dev/null +++ vm/tests/kernel/java/lang/SystemExtensionTest.java @@ -0,0 +1,595 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang; + +import java.io.File; + +import junit.framework.TestCase; + +/* + * Created on 01.31.2006 + * + * This SystemExtensionTest class is used to test the Core API + * java.lang.System class + * + */ + +public class SystemExtensionTest extends TestCase { + + /** + * + */ + public void test_arraycopy_Obj_I_Obj_I_I() { + class X { + public int fld; + public X(int i) { fld = i; } + } + X ax1[] = new X[]{new X(0), new X(1), new X(2), new X(3), new X(4), new X(5), new X(6), new X(7), new X(8), new X(9)}; + X ax2[] = new X[20]; + try { + System.arraycopy((Object)ax1, 5, (Object)ax2, 12, 3); + assertTrue("Error1", ax2[12].fld == 5 && ax2[13].fld == 6 && ax2[14].fld == 7 ); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + System.out.println("test_arraycopy_Obj_I_Obj_I_I"); + } + + /** + * + */ + public void test_currentTimeMillis_V() { + assertTrue("Error1", (System.currentTimeMillis() - System.currentTimeMillis()) <= 0); + System.out.println("test_currentTimeMillis_V"); + } + + /** + * + */ + public void test_exit_I() { + //exit(777); + System.out.println("test_exit_I"); + } + + + /** + * + */ + public void test_gc() { + long r1=Runtime.getRuntime().freeMemory(); + long r2, r4; + String[] sa = new String[(int)r1/50000]; + int ind1=0; + try { + String stmp = ""; + for(int ind2=0; ind2<50/*1000*/; ind2++){ + stmp += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; + } + for(ind1=0; ind1 <(int)r1/50000; ind1++){ + sa[ind1]=""+stmp; + } + + r2=Runtime.getRuntime().freeMemory(); + for(ind1=0; ind1 <(int)r1/50000; /*ind1++*/ind1+=100){ + sa[ind1]=null; + System.gc(); + try{Thread.sleep(10);}catch(Exception e){} + } + sa=null; + try{Thread.sleep(500);}catch(Exception e){} + System.gc(); + try{Thread.sleep(500);}catch(Exception e){} + r4=Runtime.getRuntime().freeMemory(); + + if( !(r4>r2) ){ + System.out.println( "WARNNING: It would be better if System.gc method could initiate garbage collecting! (Here we have "+r4+" !> "+r2+" .)"); + } + } catch (OutOfMemoryError e) { + System.out.println( "WARNNING: test did not check System.gc method due to the technical reason !"); + } catch (Exception e) { + fail("Error1: " + e.toString()); + } + System.out.println("test_gc"); + } + + /** + * See SystemTest.testGetenvString() + */ + //public void test_getenv_Str() { + //} + + /** + * + */ + public void test_getProperties_V() { + try { + java.util.Properties pl = System.getProperties(); + for (java.util.Enumeration e = pl.propertyNames() ; e.hasMoreElements() ;) { + if (((String)e.nextElement()).equals("os.name")) { + System.out.println("test_getProperties_V"); + return; + } + } + fail("Error1"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getProperty_Str() { + try { + if (System.getProperty("java.version")!=null || System.getProperty("java.vendor")!=null || System.getProperty("java.vendor.url")!=null || System.getProperty("java.home")!=null || System.getProperty("java.vm.specification.version")!=null || System.getProperty("java.vm.specification.vendor")!=null || System.getProperty("java.vm.specification.name")!=null || System.getProperty("java.vm.version")!=null || System.getProperty("java.vm.vendor")!=null || System.getProperty("java.vm.name")!=null || System.getProperty("java.specification.version")!=null || System.getProperty("java.specification.vendor")!=null || System.getProperty("java.specification.name")!=null || System.getProperty("java.class.version")!=null || System.getProperty("java.class.path")!=null || System.getProperty("java.library.path")!=null || System.getProperty("java.io.tmpdir")!=null || System.getProperty("java.compiler")!=null || System.getProperty("java.ext.dirs")!=null || System.getProperty("os.name")!=null || System.getProperty("os.arch")!=null || System.getProperty("os.version")!=null || System.getProperty("file.separator")!=null || System.getProperty("path.separator")!=null || System.getProperty("line.separator")!=null || System.getProperty("user.name")!=null || System.getProperty("user.home")!=null || System.getProperty("user.dir")!=null || System.getProperty("os.name")!=null) { + System.out.println("test_getProperty_Str"); + return; + } + fail("Error1"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getProperty_Str_Str() { + try { + if (System.getProperty(System.getProperty("os.name")+"_UND_"+System.getProperty("user.name"), "ZSS").equals("ZSS")) { + System.out.println("test_getProperty_Str_Str"); + return; + } + fail("Error1"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getSecurityManager_V() { + assertTrue("Error1", System.getSecurityManager() == null); + System.out.println("test_getSecurityManager_V"); + } + + /** + * + */ + public void test_identityHashCode_Obj() { + assertTrue("Error1", System.identityHashCode(null) == 0); + Boolean o1 = new Boolean(true); + assertTrue("Error2", System.identityHashCode(o1) != o1.hashCode()); + Byte o2 = new Byte(Byte.MAX_VALUE); + assertTrue("Error3", System.identityHashCode(o2) != o2.hashCode()); + Character o3 = new Character(Character.MAX_VALUE); + assertTrue("Error4", System.identityHashCode(o3) != o3.hashCode()); + Double o4 = new Double(Double.MAX_VALUE); + assertTrue("Error5", System.identityHashCode(o4) != o4.hashCode()); + Float o5 = new Float(Float.MAX_VALUE); + assertTrue("Error6", System.identityHashCode(o5) != o5.hashCode()); + Integer o6 = new Integer(Integer.MAX_VALUE); + assertTrue("Error7", System.identityHashCode(o6) != o6.hashCode()); + Long o7 = new Long(Long.MAX_VALUE); + assertTrue("Error8", System.identityHashCode(o7) != o7.hashCode()); + Short o8 = new Short(Short.MAX_VALUE); + assertTrue("Error9", System.identityHashCode(o8) != o8.hashCode()); + System.out.println("test_identityHashCode_Obj"); + } + + /** + * + */ + public void test_load_Str() { + String jLP = null; + + String jlp = System.getProperty("java.library.path"); + String vblp = System.getProperty("vm.boot.library.path"); + jLP = ( jlp!=null && jlp.length()!=0 ?jlp:"")+( vblp!=null && vblp.length()!=0 ?File.pathSeparator+vblp:""); + + if (jLP.length()==0) { + System.out.println( "WARNNING: test didn't check the loading process."); + return; + } + String[] paths = jLP.split(File.pathSeparator); + String ext = (System.getProperty("os.name").indexOf("indows")!=-1 ? ".dll":".so"); + int ind1; + int ind2; + File[] asf = null; + for (ind1 = 0; ind1< paths.length; ind1++){ + asf = new java.io.File(paths[ind1]).listFiles(); + if (asf!=null) { + for (ind2 = 0; ind2< asf.length; ind2++){ + if (asf[ind2].getName().indexOf(ext)!=-1){ + try{ + System.load(asf[ind2].getCanonicalPath()); + System.out.println("test_load_Str"); + return; + } catch (UnsatisfiedLinkError e) { + continue; + } catch (Throwable e) { + continue; + } + } + } + } + } + fail("System.load method should provide loading a dynamic library!"); + } + + /** + * + */ + public void test_loadLibrary_Str() { + String jLP = null; + + String jlp = System.getProperty("java.library.path"); + String vblp = System.getProperty("vm.boot.library.path"); + jLP = ( jlp!=null && jlp.length()!=0 ?jlp:"")+( vblp!=null && vblp.length()!=0 ?File.pathSeparator+vblp:""); + if (jLP.length()==0) { + System.out.println( "WARNNING: test didn't check the loading process."); + return; + } + String[] paths = jLP.split(File.pathSeparator); + String ext = (System.getProperty("os.name").indexOf("indows")!=-1 ? ".dll":".so"); + int ind1; + int ind2; + File[] asf = null; + for (ind1 = 0; ind1< paths.length; ind1++){ + if (paths[ind1]==null) { + continue; + } + asf = new java.io.File(paths[ind1]).listFiles(); + if (asf!=null) { + for (ind2 = 0; ind2< asf.length; ind2++){ + if (asf[ind2].getName().indexOf(ext)!=-1){ + String libName = asf[ind2].getName(); + if(ext.equals(".dll")){ + libName = libName.substring(0,libName.length()-4); + } else { + libName = libName.substring(3,libName.length()-3); + } + try{ + System.loadLibrary(libName); + System.out.println("test_loadLibrary_Str"); + return; + } catch (UnsatisfiedLinkError e) { + continue; + } catch (Throwable e) { + continue; + } + + } + } + } + } + fail("System.loadLibrary method should provide loading a dynamic library!"); + } + + /** + * + */ + public void test_mapLibraryName_Str() { + assertTrue("Error1", System.mapLibraryName("lib").indexOf((System.getProperty("os.name").toLowerCase().indexOf("windows")!=-1 ? ".dll":".so")) != -1); + System.out.println("test_mapLibraryName_Str"); + } + + /** + * + */ + static class forInternalUseOnly { + String stmp; + + forInternalUseOnly () { + this.stmp = ""; + for(int ind2=0; ind2<100; ind2++){ + this.stmp += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"+ + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; + } + } + protected void finalize() throws Throwable { + runFinalizationFlag = true; + super.finalize(); + } + } + + static boolean runFinalizationFlag = false; + public void test_runFinalization_V() { + runFinalizationFlag = false; + for(int ind2=0; ind2<10; ind2++){ + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + try{Thread.sleep(10);}catch(Exception e){} + System.gc(); + try{Thread.sleep(10);}catch(Exception e){} + System.runFinalization(); + } + assertTrue( "ERROR1: someting's wrong", runFinalizationFlag); + System.out.println("test_runFinalization_V"); + } + + /** + * + */ + public void test_runFinalizersOnExit_Z() { + runFinalizationFlag = false; + for(int ind2=0; ind2<5; ind2++){ + System.runFinalizersOnExit(false); + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + try{Thread.sleep(10);}catch(Exception e){} + System.gc(); + try{Thread.sleep(10);}catch(Exception e){} + } + assertTrue( "ERROR1: someting's wrong", runFinalizationFlag); + + runFinalizationFlag = false; + for(int ind2=0; ind2<5; ind2++){ + System.runFinalizersOnExit(true); + forInternalUseOnly ins = new forInternalUseOnly(); + ins.stmp += ""; + ins = null; + try{Thread.sleep(10);}catch(Exception e){} + System.gc(); + try{Thread.sleep(10);}catch(Exception e){} + } + assertTrue( "ERROR2: someting's wrong", runFinalizationFlag); + System.out.println("test_runFinalizersOnExit_Z"); + } + + /** + * + */ + public void test_setErr_Pri() { + java.io.PrintStream cp = System.err; + java.io.ByteArrayOutputStream es = new java.io.ByteArrayOutputStream(1000); + System.setErr(new java.io.PrintStream(es)); + System.err.print("Serguei S.Zapreyev"); + System.err.flush(); + System.setErr(cp); + assertTrue("Error1", es.toString().indexOf("Serguei S.Zapreyev") != -1); + System.out.println("test_setErr_Pri"); + } + + /** + * + */ + public void test_setIn_Inp() { + java.io.InputStream cp = System.in; + byte ab[] = new byte[300]; + System.setIn(new java.io.StringBufferInputStream("Serguei S.Zapreyev")); + try { + System.in.read(ab, 0, 18); + } catch (java.io.IOException _) { + System.setIn(cp); + fail("Error1"); + } + System.setIn(cp); + assertTrue("Error2", new String(ab).toString().indexOf("Serguei S.Zapreyev") != -1); + System.out.println("test_setIn_Inp"); + } + + /** + * + */ + public void test_setOut_Pri() { + java.io.PrintStream cp = System.out; + java.io.ByteArrayOutputStream os = new java.io.ByteArrayOutputStream(1000); + System.setOut(new java.io.PrintStream(os)); + System.out.print("Serguei S.Zapreyev"); + System.out.flush(); + System.setOut(cp); + assertTrue("Error1", os.toString().indexOf("Serguei S.Zapreyev") != -1); + System.out.println("test_setOut_Pri"); + } + + /** + * + */ + public void test_setProperties_Pro() { + try { + java.util.Properties pl = System.getProperties(); + pl.setProperty("SeStZa", "ZAPREYEV SERGUEI"); + System.setProperties(pl); + if (System.getProperty("SeStZa").equals("ZAPREYEV SERGUEI")) { + System.out.println("test_setProperties_Pro"); + return; + } + fail("Error1"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setProperty_Str_Str() { + try { + System.setProperty("ZSS", "Serguei S.Zapreyev"); + if (System.getProperty("ZSS").equals("Serguei S.Zapreyev")) { + System.out.println("test_setProperty_Str_Str"); + return; + } + fail("Error1"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + static String policyFile; + static { + if (System.getProperty("java.vm.vendor").equals("Intel DRL")) { + //policyFile = "drl.policy"; + policyFile = "java.policy"; + } else { + policyFile = "java.policy"; + } + } +// Commented because of the drlvm issue (env.SYSTEMDRIVE) + public void te_st_setSecurityManager_Sec() { + setAllPermissions(); + assertTrue("Error1", System.getSecurityManager() != null); + setNoPermissions(); + try { + new SystemExtensionTest().test_load_Str(); + fail("Error2"); + } catch (SecurityException e) { + // correct behaviour + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + System.setSecurityManager(null); + assertTrue("Error4", System.getSecurityManager() == null); + + File fff = null; + try { + fff = new File(System.getProperty("user.home") + java.io.File.separator + "."+policyFile+".copiedBySMT"); + if (fff.exists()) { + File fff3 = new File(System.getProperty("user.home") + java.io.File.separator + "."+policyFile+""); + if (fff3.exists()) { + fff3.delete(); + } + fff.renameTo(fff3); + } + } catch (Throwable e) { + e.printStackTrace(); + } + System.out.println("test_setSecurityManager_Sec"); + } + + /** + * + */ + private void setTestPermission0(String perm, String arg1, String arg2, boolean changeSM) { + SecurityManager sm = System.getSecurityManager(); + try { + File fff2 = null; + java.io.DataOutputStream dos2 = null; + try { + fff2 = new File(System.getProperty("user.home") + java.io.File.separator + "."+policyFile+""); + if (fff2.exists()) { + File fff3 = new File(System.getProperty("user.home") + java.io.File.separator + "."+policyFile+".copiedBySMT"); + if (fff3.exists()) { + fff2.delete(); + fff2 = new File(System.getProperty("user.home") + java.io.File.separator + "."+policyFile+""); + } else { + fff2.renameTo(fff3); + } + } + ; + fff2.createNewFile(); + dos2 = new java.io.DataOutputStream(new java.io.FileOutputStream(fff2)); + } catch (Throwable e) { + e.printStackTrace(); + } + + try { + dos2.writeBytes("grant {\n"); + String tmpstr = ""; + if (arg1.length() != 0 || arg2.length() != 0) { + if (arg1.length() != 0 && arg2.length() != 0) { + tmpstr = " \"" + arg1 + "\", \"" + arg2 + "\""; + } else { + tmpstr = " \"" + arg1 + arg2 + "\""; + } + } + if (perm != null && perm.length() != 0){ + dos2.writeBytes("permission " + perm + tmpstr + ";\n"); + } + if (changeSM) { + dos2.writeBytes("permission " + "java.lang.RuntimePermission \"createSecurityManager\";\n"); + dos2.writeBytes("permission " + "java.lang.RuntimePermission \"setSecurityManager\";\n"); + dos2.writeBytes("permission " + "java.util.PropertyPermission \"user.home\", \"read\";\n"); + String tmp = System.getProperty("user.home") + java.io.File.separator + "."+policyFile+""; + tmp = tmp.replace(java.io.File.separatorChar,'='); + tmp = tmp.replaceAll("=", "=="); + tmp = tmp.replace('=',java.io.File.separatorChar); + dos2.writeBytes("permission " + "java.io.FilePermission \""+tmp+"\", \"read,delete,write\";\n"); + tmp = System.getProperty("user.home") + java.io.File.separator + "."+policyFile+".copiedBySMT"; + tmp = tmp.replace(java.io.File.separatorChar,'='); + tmp = tmp.replaceAll("=", "=="); + tmp = tmp.replace('=',java.io.File.separatorChar); + dos2.writeBytes("permission " + "java.io.FilePermission \""+tmp+"\", \"read,delete\";\n"); + dos2.writeBytes("permission " + "java.util.PropertyPermission \"java.security.policy\", \"write\";\n"); + dos2.writeBytes("permission " + "java.security.SecurityPermission \"getPolicy\";\n"); + dos2.writeBytes("permission " + "java.security.SecurityPermission \"setProperty.policy.url.1\";\n"); + } + dos2.writeBytes("};\n"); + dos2.flush(); + dos2.close(); + } catch (Throwable e) { + e.printStackTrace(); + } + //System.setProperty("java.security.policy", "=" + System.getProperty("user.home") + java.io.File.separator + "."+policyFile+""); + java.security.Policy.getPolicy().refresh(); + //java.security.Security.setProperty("policy.url.1", "file:${java.home}/lib/security/"+policyFile+""); + java.security.Security.setProperty("policy.url.1", "file:${user.home}/."+policyFile+""); + + sm = new SecurityManager(); + System.setSecurityManager(sm); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + /** + * + */ + private void setAllPermissions() { + setTestPermission0("java.security.AllPermission", "", "", false); + } + + /** + * + */ + private void setNoPermissions() { + //setTestPermission0("NothingPermissions", "", "", false); + setTestPermission0("", "", "", true); + } + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/SystemTest.java vm/tests/kernel/java/lang/SystemTest.java new file mode 100644 index 0000000..9c83855 --- /dev/null +++ vm/tests/kernel/java/lang/SystemTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Roman S. Bushmanov + * @version $Revision$ + */ +package java.lang; + +import java.util.Map; + +import junit.framework.TestCase; + +public class SystemTest extends TestCase { + + /** + * Test for String getenv(String) + */ + public void testGetenvString() { + assertNull("_NONEXISTENT_ENVIRONMENT_VARIABLE_", + System.getenv("_NONEXISTENT_ENVIRONMENT_VARIABLE_")); + try { + System.getenv(null); + fail("NPE is expected"); + } catch (NullPointerException ok) {} + } + + /** + * test for Map getenv() + */ + public void testGetenv() { + Map<String, String> env = System.getenv(); + for (String key : env.keySet()) { + assertEquals("Value of " + key, env.get(key), System.getenv(key)); + } + } + + public void testNanoTime() { + long start = System.nanoTime(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + fail("Was interruptred"); + } + long duration = System.nanoTime() - start; + assertTrue("Elapsed time should be >0", duration > 0); + } + + public void testNanoTime1() { + long startNano = System.nanoTime(); + long startMilli = System.currentTimeMillis(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + fail("Was interruptred"); + } + long durationNano = System.nanoTime() - startNano; + long durationMillis = System.currentTimeMillis() - startMilli; + assertTrue("Bad accuracy!", Math.abs(durationNano / 1000000 - durationMillis) < 50); + } + + public void testClearProperty(){ + String name = "user.name"; + String initialValue = System.getProperty(name); + String newValue = "Baba Yaga"; + System.setProperty(name, newValue); + assertEquals("incorrect value", newValue, System.getProperty(name)); + System.clearProperty(name); + assertNull("user.name should not be null", System.getProperty(name)); + System.setProperties(null); + assertEquals("user.name has not been restored", initialValue, System.getProperty(name)); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ThreadGroupTest.java vm/tests/kernel/java/lang/ThreadGroupTest.java new file mode 100644 index 0000000..33ae40c --- /dev/null +++ vm/tests/kernel/java/lang/ThreadGroupTest.java @@ -0,0 +1,1216 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Roman S. Bushmanov + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; +import java.io.*; + +import org.apache.harmony.test.ReversibleSecurityManager; + +public class ThreadGroupTest extends TestCase { + + private static final String INTERRUPTED_MESSAGE = + "thread has been unexpectedly interrupted"; + + // max time interval to wait for some events in ms + private static final long waitDuration = 3000; + + // waiting time for some event + private static long waitTime = 0; + private boolean expired; + private static PrintStream systemOut = System.out; + private static PrintStream systemErr = System.err; + + class ExceptionHandler implements Thread.UncaughtExceptionHandler { + + public boolean wasCalled = false; + + public void uncaughtException(Thread t, Throwable e) { + wasCalled = true; + } + } + + class ThreadGroupHandler extends ThreadGroup { + boolean handlerWasCalled = false; + + public ThreadGroupHandler(String name) { + super(name); + } + + public ThreadGroupHandler(ThreadGroup g, String name) { + super(g, name); + } + + public void uncaughtException(Thread t, Throwable e) { + handlerWasCalled = true; + } + } + + class TestThread extends Thread { + + volatile boolean enough = false; + + boolean finished = false; + + TestThread(ThreadGroup group, String name) { + super(group, name); + } + + public void run() { + while (!enough) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + finished = true; + } + } + + /** + * Sleep for "interval" ms + * @return true if waitTime is up + */ + private static boolean doSleep(int interval) { + try { + Thread.sleep(interval); + } catch (InterruptedException e) { + fail("unexpected InterruptedException while sleeping"); + } + waitTime -= interval; + return waitTime <= 0; + } + + /** + * ThreadGroup(String) + */ + public void testThreadGroupThreadGroupString() { + ThreadGroup group = new ThreadGroup("group"); + assertSame("wrong parrent", + Thread.currentThread().getThreadGroup(), group.getParent()); + } + + /** + * Create a ThreadGroup in a destroyed ThreadGroup + */ + public void testThreadGroupThreadGroupString_InDestroyedGroup() { + try { + ThreadGroup group = new ThreadGroup("group"); + group.destroy(); + new ThreadGroup(group, "group1"); + fail("Constructor should throw IllegalThreadStateException!"); + } catch (IllegalThreadStateException e) { + return; + } + } + + /** + * test ThreadGroup(null) + */ + public void testThreadGroupString_Null() { + ThreadGroup group = null; + try { + group = new ThreadGroup(null); + } catch (NullPointerException e) { + fail("Constructor should accept null names!"); + } + assertNull(group.getName()); + } + + /** + * activeCount() in a new ThreadGroup + */ + public void testActiveCount_NoThreads() { + ThreadGroup group = new ThreadGroup("new"); + assertEquals(0, group.activeCount()); + } + + /** + * activeCount() in a ThreadGroup with an empty subgroup + */ + public void testActiveCount_CreateDestroySubgroup() { + ThreadGroup group = new ThreadGroup("group"); + ThreadGroup group1 = new ThreadGroup(group, "group1"); + assertEquals(1, group.activeGroupCount()); + group1.destroy(); + assertEquals(0, group.activeGroupCount()); + } + + /** + * activeCount() in a ThreadGroup with a few new threads + */ + public void testActiveCount_NewThreads() { + ThreadGroup group = new ThreadGroup("new"); + new Thread(group, "t1"); + new Thread(group, "t2"); + new Thread(group, "t3"); + assertEquals(0, group.activeCount()); + } + + /** + * activeCount() in a ThreadGroup with a few started and + * terminated threads + */ + public void testActiveCount_StartedTerminatedThreads() { + ThreadGroup group = new ThreadGroup("new"); + ThreadTest.ThreadRunning t1 = new ThreadTest.ThreadRunning(group, "t1"); + ThreadTest.ThreadRunning t2 = new ThreadTest.ThreadRunning(group, "t2"); + ThreadTest.ThreadRunning t3 = new ThreadTest.ThreadRunning(group, "t3"); + t1.start(); + t2.start(); + t3.start(); + doSleep(100); + assertEquals("incorrect number of started threads", + 3, group.activeCount()); + t1.stopWork = true; + t2.stopWork = true; + t3.stopWork = true; + try { + t1.join(); + t2.join(); + t3.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertEquals("there should be no live threads", 0, group.activeCount()); + } + + /** + * activeCount() in a ThreadGroup with a few threads running in a subgroups + */ + public void testActiveCount_Subgroup() { + ThreadGroup parent = new ThreadGroup("parent"); + ThreadGroup child1 = new ThreadGroup(parent, "child1"); + ThreadTest.ThreadRunning t11 = new ThreadTest.ThreadRunning(parent, + "t11"); + ThreadTest.ThreadRunning tc11 = new ThreadTest.ThreadRunning(child1, + "tc11"); + ThreadTest.ThreadRunning tc12 = new ThreadTest.ThreadRunning(child1, + "tc12"); + ThreadGroup gChild1 = new ThreadGroup(child1, "gChild1"); + ThreadTest.ThreadRunning tgc11 = new ThreadTest.ThreadRunning(gChild1, + "tgc11"); + ThreadTest.ThreadRunning tgc12 = new ThreadTest.ThreadRunning(gChild1, + "tgc12"); + ThreadGroup child2 = new ThreadGroup(parent, "child2"); + ThreadTest.ThreadRunning tc21 = new ThreadTest.ThreadRunning(child2, + "tc21"); + ThreadTest.ThreadRunning tc22 = new ThreadTest.ThreadRunning(child2, + "tc22"); + assertEquals("new threads should not be counted", + 0, parent.activeCount()); + t11.start(); + tc11.start(); + tc12.start(); + tgc11.start(); + tgc12.start(); + tc21.start(); + tc22.start(); + doSleep(100); + assertEquals("incorrect number of active threads", + 7, parent.activeCount()); + t11.stopWork = true; + tc11.stopWork = true; + tc12.stopWork = true; + tgc11.stopWork = true; + tgc12.stopWork = true; + tc21.stopWork = true; + tc22.stopWork = true; + try { + t11.join(); + tc11.join(); + tc12.join(); + tgc11.join(); + tgc12.join(); + tc21.join(); + tc22.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertEquals("there should be no live threads", 0, parent.activeCount()); + } + + /** + * Verify activeGroupCount() for a group containing + * a few subgroups + */ + public void testActiveGroupCount_Subgroups() { + ThreadGroup tg1 = new ThreadGroup("group 1"); + new ThreadGroup(tg1, "group 11"); + ThreadGroup tg12 = new ThreadGroup(tg1, "group 12"); + new ThreadGroup(tg1, "group 13"); + new ThreadGroup(tg12, "group 121"); + new ThreadGroup(tg12, "group 122"); + ThreadGroup tg123 = new ThreadGroup(tg12, "group 123"); + new Thread(tg123, "thread 1231"); + new Thread(tg123, "thread 1232"); + assertEquals(6, tg1.activeGroupCount()); + } + + /** + * Verify activeGroupCount() after destroying a group + * where one of subgroups is not empty + */ + public void testActiveGroupCount_DestroyNonEmptySubgroup() { + ThreadGroup tg1 = new ThreadGroup("group 1"); + new ThreadGroup(tg1, "group 11"); + ThreadGroup tg12 = new ThreadGroup(tg1, "group 12"); + new ThreadGroup(tg1, "group 13"); + new ThreadGroup(tg12, "group 121"); + new ThreadGroup(tg12, "group 122"); + ThreadGroup tg123 = new ThreadGroup(tg12, "group 123"); + new ThreadTest.ThreadRunning(tg123, "thread 1231").start(); + new ThreadTest.ThreadRunning(tg123, "thread 1232").start(); + // tg1 and its non-empty subgroups tg123 and tg12 + // should not be destroyed. + // All empty subgroups shoud be destroyed. + // IllegalThreadStateException should be thrown. + try { + tg1.destroy(); + fail("IllegalThreadStateException has not been thrown when " + + "destroying non-empty subgroup"); + } catch (IllegalThreadStateException e) { + } + assertEquals("wrong group count in tg1", 2, tg1.activeGroupCount()); + assertEquals("wrong group count in tg12", 1, tg12.activeGroupCount()); + } + + /** + * Verify the checkAccess() method + */ + public void testCheckAccess() { + SecurityManager sm = System.getSecurityManager(); + System.setSecurityManager(new ReversibleSecurityManager()); + ThreadGroup tg1 = new ThreadGroup("tg1"); + try { + tg1.checkAccess(); + } finally { + System.setSecurityManager(sm); + } + } + + /** + * Checks the destroy() method for a destroyed thread group. + * IllegalThreadStateException should be thrown. + */ + public void testDestroy_Destroyed() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + tg2.setDaemon(true); + TestThread t2 = new TestThread(tg2, "t2"); + t2.start(); + t2.enough = true; + try { + t2.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + // tg2 is daemon and should be already destroyed + try { + tg2.destroy(); + fail("IllegalThreadStateException should be thrown " + + "when destroying a destroyed thread group"); + } catch (IllegalThreadStateException e) { + } + } + + /** + * Checks the destroy() method for a group containing a destroyed subgroup. + * IllegalThreadStateException should not be thrown. + */ + public void testDestroy_DestroyedSubgroup() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + tg2.setDaemon(true); + TestThread t2 = new TestThread(tg2, "t2"); + t2.start(); + t2.enough = true; + try { + t2.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + + // tg1 should be destroyed because its subgroup tg2 has been destroyed + // silently as a daemon ThreadGroup with no live threads + try { + tg1.destroy(); + } catch (IllegalThreadStateException e) { + fail("IllegalThreadStateException has been thrown when destroying" + + " a thread group containing a destroyed subgroup"); + } + } + + /** + * Verify destroying a group where one of subgroups is not empty + * but all threads in it have finished. + */ + public void testDestroy_FinishedThreads() { + ThreadGroup tg1 = new ThreadGroup("group 1"); + ThreadGroup tg11 = new ThreadGroup(tg1, "group 11"); + ThreadGroup tg12 = new ThreadGroup(tg1, "group 12"); + ThreadGroup tg13 = new ThreadGroup(tg1, "group 13"); + ThreadGroup tg121 = new ThreadGroup(tg12, "group 121"); + ThreadGroup tg122 = new ThreadGroup(tg12, "group 122"); + ThreadGroup tg123 = new ThreadGroup(tg12, "group 123"); + ThreadTest.ThreadRunning t1 = new ThreadTest.ThreadRunning(tg123, + "thread 1231"); + t1.start(); + ThreadTest.ThreadRunning t2 = new ThreadTest.ThreadRunning(tg123, + "thread 1232"); + t2.start(); + t1.stopWork = true; + t2.stopWork = true; + try { + t1.join(); + t2.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + for (waitTime = waitDuration; t1.isAlive() && t2.isAlive() && !(expired = doSleep(10));) { + } + if (expired) { + fail("thread have not finished for " + waitDuration + " ms"); + } + try { + tg1.destroy(); + } catch (IllegalThreadStateException e) { + fail("IllegalThreadStateException should not been thrown " + + "because threads have fnished"); + } + assertTrue(tg1.getName() + " has not been destroyed", tg1.isDestroyed()); + assertTrue(tg11.getName() + " has not been destroyed", tg11.isDestroyed()); + assertTrue(tg12.getName() + " has not been destroyed", tg12.isDestroyed()); + assertTrue(tg13.getName() + " has not been destroyed", tg13.isDestroyed()); + assertTrue(tg121.getName() + " has not been destroyed", tg121.isDestroyed()); + assertTrue(tg122.getName() + " has not been destroyed", tg122.isDestroyed()); + assertTrue(tg123.getName() + " has not been destroyed", tg123.isDestroyed()); + assertEquals("tg1 should be empty", 0, tg1.activeGroupCount()); + assertEquals("tg12 should be empty", 0, tg12.activeGroupCount()); + } + + /** + * Checks the destroy() method for a group with 3 subgroups. + * Verifies the <code>destroyed</code> flag. + */ + public void testDestroy_ThreeChildren() { + ThreadGroup groups[] = {new ThreadGroup("tg0"), null, null, null}; + groups[1] = new ThreadGroup(groups[0], "tg1"); + groups[2] = new ThreadGroup(groups[0], "tg2"); + groups[3] = new ThreadGroup(groups[0], "tg3"); + groups[0].destroy(); + assertTrue("group[0] has not been destroyed", groups[0].isDestroyed()); + assertTrue("group[1] has not been destroyed", groups[1].isDestroyed()); + assertTrue("group[2] has not been destroyed", groups[2].isDestroyed()); + assertTrue("group[3] has not been destroyed", groups[3].isDestroyed()); + } + + /** + * Checks the destroy() method for a group with 2 subgroups. + * Verifies the activeGroupCount() value. + */ + public void testDestroy_TwoChildren() { + ThreadGroup group = new ThreadGroup("group"); + new ThreadGroup(group, "group1"); + new ThreadGroup(group, "group2"); + assertEquals(2, group.activeGroupCount()); + group.destroy(); + assertEquals(0, group.activeGroupCount()); + } + + /** + * Verify getMaxPriority() + */ + public void testGetMaxPriority() { + ThreadGroup tg = new ThreadGroup("tg"); + int groupMaxPriority = tg.getMaxPriority(); + assertEquals("incorrect priority", + Thread.currentThread().getThreadGroup().getMaxPriority(), + groupMaxPriority); + Thread t = new Thread(tg, "t"); + assertTrue("incorect thread's priority", + t.getPriority() <= groupMaxPriority); + } + + /** + * Verify enumerate(Thread[]) + */ + public void testEnumerateThread() { + ThreadGroup tg = new ThreadGroup("tg"); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + ThreadTest.ThreadRunning tArray[] = new ThreadTest.ThreadRunning[9]; + for (int i = 0; i < 3; i++) { + tArray[i] = new ThreadTest.ThreadRunning(tg, "ttt"); + tArray[i].start(); + tArray[i + 3] = new ThreadTest.ThreadRunning(tg1, "ttt"); + tArray[i + 3].start(); + tArray[i + 6] = new ThreadTest.ThreadRunning(tg2, "ttt"); + tArray[i + 6].start(); + } + doSleep(50); + // estimate dimension as 9 threads + 1 + int estimateLength = 10; + Thread list[]; + int count; + while (true) { + list = new Thread[estimateLength]; + count = tg.enumerate(list); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("ttt") > 0) { + enumerateCount++; + } + } + for (int i = 0; i < 9; i++) { + tArray[i].stopWork = true; + } + assertEquals("incorrect number of threads in tg", 9, enumerateCount); + } + + /** + * Verify enumerate(Thread[], false) + */ + public void testEnumerateThreadBoolean_False() { + ThreadGroup tg = new ThreadGroup("tg"); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + ThreadTest.ThreadRunning tArray[] = new ThreadTest.ThreadRunning[9]; + for (int i = 0; i < 3; i++) { + tArray[i] = new ThreadTest.ThreadRunning(tg, "ttt"); + tArray[i].start(); + tArray[i + 3] = new ThreadTest.ThreadRunning(tg1, "ttt"); + tArray[i + 3].start(); + tArray[i + 6] = new ThreadTest.ThreadRunning(tg2, "ttt"); + tArray[i + 6].start(); + } + doSleep(50); + // estimate dimension as 3 threads + 1 + int estimateLength = 4; + Thread list[]; + int count; + while (true) { + list = new Thread[estimateLength]; + count = tg.enumerate(list, false); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("ttt") > 0) { + enumerateCount++; + } + } + for (int i = 0; i < 9; i++) { + tArray[i].stopWork = true; + } + assertEquals("incorrect number of threads in tg", 3, enumerateCount); + } + + /** + * Verify enumerate(Thread[], true) + */ + public void testEnumerateThread_True() { + ThreadGroup tg = new ThreadGroup("tg"); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + ThreadTest.ThreadRunning tArray[] = new ThreadTest.ThreadRunning[9]; + for (int i = 0; i < 3; i++) { + tArray[i] = new ThreadTest.ThreadRunning(tg, "ttt"); + tArray[i].start(); + tArray[i + 3] = new ThreadTest.ThreadRunning(tg1, "ttt"); + tArray[i + 3].start(); + tArray[i + 6] = new ThreadTest.ThreadRunning(tg2, "ttt"); + tArray[i + 6].start(); + } + doSleep(50); + // estimate dimension as 9 threads + 1 + int estimateLength = 10; + Thread list[]; + int count; + while (true) { + list = new Thread[estimateLength]; + count = tg.enumerate(list, true); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("ttt") > 0) { + enumerateCount++; + } + } + for (int i = 0; i < 9; i++) { + tArray[i].stopWork = true; + } + assertEquals("incorrect number of threads in tg", 9, enumerateCount); + } + + /** + * Verify enumerate(ThreadGroup[]) + */ + public void testEnumerateThreadGroup() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg11 = new ThreadGroup(tg1, "tg11"); + new ThreadGroup(tg1, "tg12"); + new ThreadGroup(tg11, "tg111"); + new ThreadGroup(tg11, "tg112"); + // estimate dimension as 4 threads + 1 + int estimateLength = 5; + ThreadGroup list[]; + int count; + while (true) { + list = new ThreadGroup[estimateLength]; + count = tg1.enumerate(list); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("tg1") > 0) { + enumerateCount++; + } + } + assertEquals("incorrect number of thread groups in tg", + 4, enumerateCount); + } + + /** + * Verify enumerate(ThreadGroup[]) when there is a destroyed subgroup + */ + public void testEnumerateThreadGroup_Destroyed() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg11 = new ThreadGroup(tg1, "tg11"); + new ThreadGroup(tg1, "tg12"); + ThreadGroup tg111 = new ThreadGroup(tg11, "tg111"); + new ThreadGroup(tg11, "tg112"); + tg111.destroy(); + // estimate dimension as 4 threads + 1 + int estimateLength = 5; + ThreadGroup list[]; + int count; + while (true) { + list = new ThreadGroup[estimateLength]; + count = tg1.enumerate(list); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("tg1") > 0) { + enumerateCount++; + } + } + assertEquals("incorrect number of thread groups in tg", + 3, enumerateCount); + } + + /** + * Verify enumerate(ThreadGroup[], false) + */ + public void testEnumerateThreadGroup_False() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg11 = new ThreadGroup(tg1, "tg11"); + new ThreadGroup(tg1, "tg12"); + new ThreadGroup(tg11, "tg111"); + new ThreadGroup(tg11, "tg112"); + // estimate dimension as 4 threads + 1 + int estimateLength = 5; + ThreadGroup list[]; + int count; + while (true) { + list = new ThreadGroup[estimateLength]; + count = tg1.enumerate(list, false); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("tg1") > 0) { + enumerateCount++; + } + } + assertEquals("incorrect number of thread groups in tg", + 2, enumerateCount); + } + + /** + * Verify enumerate(ThreadGroup[], true) + */ + public void testEnumerateThreadGroup_True() { + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadGroup tg11 = new ThreadGroup(tg1, "tg11"); + new ThreadGroup(tg1, "tg12"); + new ThreadGroup(tg11, "tg111"); + new ThreadGroup(tg11, "tg112"); + // estimate dimension as 4 threads + 1 + int estimateLength = 5; + ThreadGroup list[]; + int count; + while (true) { + list = new ThreadGroup[estimateLength]; + count = tg1.enumerate(list, true); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("tg1") > 0) { + enumerateCount++; + } + } + assertEquals("incorrect number of thread groups in tg", + 4, enumerateCount); + } + + /** + * Verify getName() + */ + public void testGetName() { + String name = "newGroup"; + String childName = "newChildGroup"; + ThreadGroup tg = new ThreadGroup(name); + assertEquals("wrong name", name, tg.getName()); + ThreadGroup tgChild = new ThreadGroup(tg, childName); + assertEquals("wrong child name", childName, tgChild.getName()); + } + + /** + * Verify getParent() + */ + public void testGetParent() { + ThreadGroup parent = new ThreadGroup("parent"); + ThreadGroup child = new ThreadGroup(parent, "child"); + ThreadGroup grandChild = new ThreadGroup(child, "grandChild"); + assertSame("improper parent of child", parent, child.getParent()); + assertSame("improper parent of grandchild", + child, grandChild.getParent()); + } + + /** + * Verify getParent() of a destroyed group + */ + public void testGetParent_DestroyedGroup() { + ThreadGroup parent = new ThreadGroup("parent"); + ThreadGroup child = new ThreadGroup(parent, "child"); + ThreadGroup grandchild = new ThreadGroup(child, "grandchild"); + child.destroy(); + assertTrue("child has not been destroyed", child.isDestroyed()); + assertTrue("grandchild has not been destroyed", + grandchild.isDestroyed()); + assertSame("improper parent of a destroyed group", + parent, child.getParent()); + assertSame("a destroyed group should stay parent", + child, grandchild.getParent()); + } + + /** + * Verify getParent() of a top-level group + */ + public void testGetParent_TopLevelGroup() { + ThreadGroup parent = Thread.currentThread().getThreadGroup().getParent(); + int groupCount = 1000; + while ((parent != null) && (--groupCount >= 0)) { + parent = parent.getParent(); + } + assertNull("top-level group's parent is not null", parent); + } + + /** + * Interrupt a running thread + */ + public void testInterrupt() { + ThreadGroup tg = new ThreadGroup("tg"); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + ThreadTest.ThreadRunning tArray[] = new ThreadTest.ThreadRunning[6]; + for (int i = 0; i < 3; i++) { + tArray[i] = new ThreadTest.ThreadRunning(tg, "ttt"); + tArray[i].start(); + tArray[i + 3] = new ThreadTest.ThreadRunning(tg1, "ttt"); + tArray[i + 3].start(); + } + doSleep(50); + tg.interrupt(); + waitTime = waitDuration; + for (int i = 0; i < 6; i++) { + while (!tArray[i].isInterrupted() && !(expired = doSleep(10))) { + } + if (expired) { + break; + } + } + for (int i = 0; i < 6; i++) { + tArray[i].stopWork = true; + } + if (expired) { + fail("threads have not been interrupted"); + } + } + + /** + * Verify list() + */ + public void testList() { + File file = null; + PrintStream newOut = null; + try { + file = File.createTempFile("JUnit_ThreadGroupListTest", ".tmp"); + newOut = new PrintStream(new FileOutputStream(file)); + } catch (java.io.IOException e) { + fail("unexpected IOException 1: " + e); + } + try { + System.setOut(newOut); + } catch (SecurityException e) { + return; + } + ThreadGroup tg = new ThreadGroup("tg"); + tg.list(); + newOut.close(); + System.setOut(systemOut); + byte buf[] = new byte[100]; + try { + FileInputStream inp = new FileInputStream(file); + inp.read(buf); + inp.close(); + } catch (java.io.IOException e) { + fail("unexpected IOException 2: " + e); + } + file.delete(); + String toString = "java.lang.ThreadGroup[name=tg,maxpri="; + assertEquals("thread group info has not been printed", + 0, new String(buf).indexOf(toString)); + } + + /** + * Verify parentOf() + */ + public void testParentOf() { + ThreadGroup tg = new ThreadGroup("tg"); + assertTrue("should be true for the argument", tg.parentOf(tg)); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + assertTrue("tg should be parent of tg1", tg.parentOf(tg1)); + ThreadGroup tg2 = new ThreadGroup(tg1, "tg2"); + assertTrue("tg1 should be parent of tg2", tg1.parentOf(tg2)); + assertTrue("tg should be parent of tg2", tg.parentOf(tg2)); + } + + /** + * Verify that maxPriority is inherited by a created subgroup + */ + public void testSetMaxPriority_CreateSubgroup() { + ThreadGroup tg = new ThreadGroup("tg"); + int pri = Thread.MAX_PRIORITY - 1; + tg.setMaxPriority(pri); + ThreadGroup tg1 = new ThreadGroup(tg, "tg1"); + assertEquals("incorrect priority for the created subgroup", + pri, tg1.getMaxPriority()); + } + + /** + * Decrease group's maxPriority. + * Verify that threads in the thread group that already have a higher + * priority are not affected. + */ + public void testSetMaxPriority_Decrease() { + ThreadGroup group = new ThreadGroup("new"); + Thread t1 = new Thread(); + int threadPri = t1.getPriority(); + int newGroupMaxPri = threadPri - 1; + group.setMaxPriority(newGroupMaxPri); + assertEquals("incorrect group's priority", + newGroupMaxPri, group.getMaxPriority()); + assertEquals("thread's priority should not be affected", + threadPri, t1.getPriority()); + } + + /** + * Verify that lower maxPriority is set recursively to all subgroups + */ + public void testSetMaxPriority_DecreaseRecursively() { + String gName = "tg"; + int i; + ThreadGroup tg = new ThreadGroup(gName); + int pri = Thread.MAX_PRIORITY - 1; + tg.setMaxPriority(pri); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg, gName + i); + } + ThreadGroup tg11 = new ThreadGroup(tg, gName + "11"); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg11, gName + i); + } + ThreadGroup tg22 = new ThreadGroup(tg11, gName + "22"); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg22, gName + i); + } + pri--; + tg.setMaxPriority(pri); + ThreadGroup list[] = new ThreadGroup[11]; + tg.enumerate(list); + for (i = 0; i < 11; i++) { + assertEquals("incorrect new priority for the group " + list[i], + pri, list[i].getMaxPriority()); + } + } + + /** + * Increase group's maxPriority. + */ + public void testSetMaxPriority_Increase() { + ThreadGroup group = new ThreadGroup("new"); + group.setMaxPriority(Thread.NORM_PRIORITY); + int newGroupMaxPri = Thread.NORM_PRIORITY + 1; + group.setMaxPriority(newGroupMaxPri); + assertEquals("incorrect group's priority", + newGroupMaxPri, group.getMaxPriority()); + } + + /** + * Verify that higher maxPriority is set recursively to all subgroups + */ + public void testSetMaxPriority_IncreaseRecursively() { + String gName = "tg"; + int i; + ThreadGroup tg = new ThreadGroup(gName); + int pri = Thread.NORM_PRIORITY; + tg.setMaxPriority(pri); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg, gName + i); + } + ThreadGroup tg11 = new ThreadGroup(tg, gName + "11"); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg11, gName + i); + } + ThreadGroup tg22 = new ThreadGroup(tg11, gName + "22"); + for (i = 0; i < 3; i++) { + new ThreadGroup(tg22, gName + i); + } + pri++; + tg.setMaxPriority(pri); + ThreadGroup list[] = new ThreadGroup[11]; + tg.enumerate(list); + for (i = 0; i < 11; i++) { + assertEquals("incorrect new priority for the group " + list[i], + pri, list[i].getMaxPriority()); + } + } + + /** + * Try to set maxPriority which is higher than the parent's one + */ + public void testSetMaxPriority_HigherParent() { + ThreadGroup parent = new ThreadGroup("par"); + int parPriority = Thread.MAX_PRIORITY - 1; + parent.setMaxPriority(parPriority); + assertEquals("incorrect priority received", + parPriority, parent.getMaxPriority()); + ThreadGroup child = new ThreadGroup(parent, "ch"); + child.setMaxPriority(parPriority - 1); + int newChildPriority = parPriority + 1; + child.setMaxPriority(newChildPriority); + // according to spec the smaller of newChildPriority and parPriority + // should be set + assertEquals("child priority should equal to parent's one", + parPriority, child.getMaxPriority()); + } + + /** + * Try to set maxPriority which is out of range + */ + public void testSetMaxPriority_OutOfRange() { + ThreadGroup tg = new ThreadGroup("tg"); + int curPriority = tg.getMaxPriority(); + int newPriority = Thread.MAX_PRIORITY + 1; + tg.setMaxPriority(newPriority); + assertEquals("Assert1: group priority should not change", + curPriority, tg.getMaxPriority()); + newPriority = Thread.MIN_PRIORITY - 1; + tg.setMaxPriority(newPriority); + assertEquals("Assert2: group priority should not change", + curPriority, tg.getMaxPriority()); + } + + /** + * Verify setMaxPriority() of a system group + */ + public void testSetMaxPriority_TopLevelGroup() { + ThreadGroup system = Thread.currentThread().getThreadGroup(); + ThreadGroup parent = system.getParent(); + int groupCount = 1000; + while (parent != null && --groupCount >= 0) { + system = parent; + parent = system.getParent(); + } + int newSystemPriority = system.getMaxPriority() - 1; + try { + system.setMaxPriority(newSystemPriority); + assertEquals("priority has not changed", + newSystemPriority, system.getMaxPriority()); + } catch (SecurityException e) { + } + } + + /** + * Verify set/isDaemon() + */ + public void testSetDaemon() { + ThreadGroup tg = new ThreadGroup("tg"); + assertFalse("a new group should not be daemon", tg.isDaemon()); + tg.setDaemon(true); + assertTrue("daemon status has not been set", tg.isDaemon()); + ThreadGroup child = new ThreadGroup(tg, "child"); + assertTrue("a child of a daemon group should be daemon", + child.isDaemon()); + tg.setDaemon(false); + assertFalse("daemon status has not been removed", tg.isDaemon()); + } + + /** + * Verifies the suspend/resume() method + */ + public void testSuspend() { + ThreadGroup group = new ThreadGroup("Custom group"); + TestThread thread = new TestThread(group, "Custom thread"); + thread.start(); + group.suspend(); + assertFalse("the suspended thread should not finish", thread.finished); + thread.enough = true; + group.resume(); + try { + thread.join(1000); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertTrue("thread has not finished", thread.finished); + } + + /** + * Verify toString() output + */ + public void testToString() { + ThreadGroup tg = new ThreadGroup("tg"); + String toString = "java.lang.ThreadGroup[name=tg,maxpri="; + assertEquals("incorrect representation", + 0, tg.toString().indexOf(toString)); + } + + public void testUncaughtExceptionHandlers() { + ExceptionHandler defaultHandler = new ExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(defaultHandler); + Thread t = new Thread("test thread"); + Thread.UncaughtExceptionHandler handler = t.getUncaughtExceptionHandler(); + assertNotNull("handler should not be null", handler); + assertSame("thread's thread group expected to be a handler", + t.getThreadGroup(), handler); + handler.uncaughtException(t, new RuntimeException()); + assertTrue("Default exception handler was not called", + defaultHandler.wasCalled); + } + + /** + * Verify that thread's explicit exception handler is used + */ + public void testUncaughtExceptionHandler_Explicit(){ + ExceptionHandler handler = new ExceptionHandler(); + Thread testThread = new Thread("test thread") { + public void run() { + throw new RuntimeException(); + } + }; + testThread.setUncaughtExceptionHandler(handler); + testThread.start(); + for(int i=0; i<10 && testThread.isAlive(); i++){ + try{ + Thread.sleep(50); + }catch(InterruptedException e){} + } + assertTrue("Thread's uncaught exception handler wasn't called", + handler.wasCalled); + } + + /** + * Verify that thread's explicit exception handler is used first + * even if a default UncaughtExceptionHandler is set + */ + public void testUncaughtException_ExplicitDefault() { + ExceptionHandler deh = new ExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(deh); + Thread t = new Thread("test thread") { + public void run() { + throw new RuntimeException(); + } + }; + ExceptionHandler eh = new ExceptionHandler(); + t.setUncaughtExceptionHandler(eh); + t.start(); + waitTime = waitDuration; + while (!eh.wasCalled && !(expired = doSleep(10))) { + } + assertFalse("thread's default exception handler should not been called", + deh.wasCalled); + if (expired) { + fail("thread's exception handler has not been called"); + } + } + + /** + * Verify that uncaughtException() method of thread's parent ThreadGroup + * is called even if a default UncaughtExceptionHandler is set + */ + public void testUncaughtException_ThreadGroupDefault() { + ExceptionHandler deh = new ExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(deh); + ThreadGroup grandPa = new ThreadGroup("grandPa"); + ThreadGroupHandler parent = new ThreadGroupHandler(grandPa, "parent"); + ThreadGroup child = new ThreadGroup(parent, "tg"); + String tName = "testHandler"; + Thread t = new Thread(child, tName) { + public void run() { + throw new RuntimeException(); + } + }; + t.start(); + waitTime = waitDuration; + while (!parent.handlerWasCalled && !(expired = doSleep(10))) { + } + assertFalse("thread's default exception handler should not been called", + deh.wasCalled); + if (expired) { + fail("threadGroup's uncaughtException() has not been called"); + } + } + + /** + * Verify that uncaughtException(Thread, Throwable) method + * where Throwable is ThreadDeath does nothing + */ + public void testUncaughtException_ThreadDeath() { + Thread.setDefaultUncaughtExceptionHandler(null); + File file = null; + PrintStream newErr = null; + try { + file = File.createTempFile("JUnit_ThreadUETest1", ".tmp"); + newErr = new PrintStream(new FileOutputStream(file)); + } catch (java.io.IOException e) { + fail("unexpected IOException 1: " + e); + } + try { + System.setErr(newErr); + } catch (SecurityException e) { + return; + } + Thread t = new Thread("testThreadDeath") { + public void run() { + throw new ThreadDeath(); + } + }; + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + newErr.close(); + System.setErr(systemErr); + byte buf[] = new byte[2]; + try { + FileInputStream inp = new FileInputStream(file); + inp.read(buf); + inp.close(); + } catch (java.io.IOException e) { + fail("unexpected IOException 2: " + e); + } + file.delete(); + assertTrue("Uncaught Exception message has not been printed", + buf[0] == 0); + } + + /** + * Verify that uncaughtException(Thread, Throwable) method + * prints a proper message + */ + public void testUncaughtException_NullPointerException() { + Thread.setDefaultUncaughtExceptionHandler(null); + File file = null; + PrintStream newErr = null; + try { + file = File.createTempFile("JUnit_ThreadUETest2", ".tmp"); + newErr = new PrintStream(new FileOutputStream(file)); + } catch (java.io.IOException e) { + fail("unexpected IOException 1: " + e); + } + try { + System.setErr(newErr); + } catch (SecurityException e) { + return; + } + Thread t = new Thread("testNullPointerException") { + public void run() { + throw new NullPointerException(); + } + }; + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + newErr.close(); + System.setErr(systemErr); + byte buf[] = new byte[100]; + try { + FileInputStream inp = new FileInputStream(file); + inp.read(buf); + inp.close(); + } catch (java.io.IOException e) { + fail("unexpected IOException 2: " + e); + } + file.delete(); + assertTrue("Uncaught Exception message has not been printed", + new String(buf).indexOf("NullPointerException") > 0); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ThreadRTest.java vm/tests/kernel/java/lang/ThreadRTest.java new file mode 100644 index 0000000..6d78428 --- /dev/null +++ vm/tests/kernel/java/lang/ThreadRTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Elena Semukhina + * @version $Revision$ + */ +package java.lang; + +import junit.framework.TestCase; + +public class ThreadRTest extends TestCase { + + private class ThreadRunning extends Thread { + volatile boolean stopWork = false; + int i = 0; + + ThreadRunning() { + super(); + } + + ThreadRunning(ThreadGroup g, String name) { + super(g, name); + } + public void run () { + while (!stopWork) { + i++; + } + } + } + + public void testGetThreadGroupDeadThread() { + ThreadRunning t = new ThreadRunning(); + t.start(); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + t.getThreadGroup(); + t.getThreadGroup(); + } catch (NullPointerException e) { + fail("NullPointerException has been thrown"); + } + } +} diff --git vm/tests/kernel/java/lang/ThreadTest.java vm/tests/kernel/java/lang/ThreadTest.java new file mode 100644 index 0000000..244a418 --- /dev/null +++ vm/tests/kernel/java/lang/ThreadTest.java @@ -0,0 +1,1812 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Roman S. Bushmanov + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +import java.util.Map; +import java.util.Set; +import org.apache.harmony.test.ReversibleSecurityManager; + +/** + * This class provides an implementation of J2SE v. 1.5 API Specification of + * unit.java.lang.ThreadTest class. + */ +public class ThreadTest extends TestCase { + + private static final String INTERRUPTED_MESSAGE = + "thread has been unexpectedly interrupted"; + + // max time interval to wait for some events in ms + private static final long waitDuration = 3000; + + // waiting time for some event + private long waitTime = 0; + + private boolean expired; + private SecurityManager sm = null; + + private enum Action {WAIT, SLEEP, JOIN} + + private class RunProject extends Thread { + private Team team; + RunProject(Team t) { + this.team = t; + } + + public void run () { + team.work(); + } + } + + private class Team { + private int i = 0; + volatile boolean stopProject = false; + + public synchronized void work() { + while (!stopProject) { + i++; + } + } + public void stopWork() { + stopProject = true; + } + } + + private class TestThread extends Thread { + + public InterruptedException e = null; + + public void run() { + try { + synchronized (this) { + this.notify(); + this.wait(); + } + } catch(InterruptedException e) { + this.e = e; + } + } + } + + static class ThreadRunning extends Thread { + volatile boolean stopWork = false; + long startTime; + int i = 0; + + ThreadRunning() { + super(); + } + + ThreadRunning(String name) { + super(name); + } + + ThreadRunning(Runnable target, String name) { + super(target, name); + } + + ThreadRunning(ThreadGroup g, String name) { + super(g, name); + } + + ThreadRunning(ThreadGroup g, Runnable target) { + super(g, target); + } + + ThreadRunning(ThreadGroup g, Runnable target, String name) { + super(g, target, name); + } + + public void run () { + startTime = System.currentTimeMillis(); + while (!stopWork) { + i++; + } + } + + public long getStartTime() { + return startTime; + } + } + + private class ThreadWaiting extends Thread { + private long millis; + private int nanos; + private Action action; + private boolean exceptionReceived = false; + private long startTime; + + ThreadWaiting(Action action, long millis, int nanos) { + this.millis = millis; + this.nanos = nanos; + this.action = action; + this.startTime = System.currentTimeMillis(); + } + + public void run () { + switch (action) { + case WAIT: + try { + synchronized (this) { + this.wait(millis, nanos); + } + } catch (InterruptedException e) { + exceptionReceived = true; + } + case SLEEP: + try { + Thread.sleep(millis, nanos); + } catch (InterruptedException e) { + exceptionReceived = true; + } + case JOIN: + try { + this.join(millis, nanos); + } catch (InterruptedException e) { + exceptionReceived = true; + } + } + } + + public long getStartTime() { + return startTime; + } + } + + private class ThreadRunningAnotherThread extends Thread { + int field = 0; + volatile boolean stop = false; + boolean childIsDaemon = false; + Thread curThread = null; + + public ThreadRunningAnotherThread() { + super(); + } + + public ThreadRunningAnotherThread(String name) { + super(name); + } + + public void run () { + Thread child = new Thread(); + curThread = Thread.currentThread(); + childIsDaemon = child.isDaemon(); + while (!stop) { + field++; + } + } + } + + private static class ThreadYielding extends Thread { + private int item; + public static final int dim = 200; + public static int list[] = new int[dim]; + private static int index = 0; + + public ThreadYielding(int item) { + this.item = item; + } + + private static synchronized int getNextIndex() { + return index++; + } + + public synchronized void setItem() { + list[getNextIndex()] = this.item; + } + + public void run () { + for (int i = 0; i < dim / 2; i++) { + setItem(); + Thread.yield(); + } + } + } + + class Square implements Runnable { + volatile boolean stop = false; + boolean once; + int number; + int squaredNumber; + + Square(int number) { + this(number, false); + } + + Square(int number, boolean once) { + this.number = number; + this.once = once; + } + + public void run() { + while (!stop) { + squaredNumber = number * number; + if (once) { + break; + } + } + } + } + + /** + * Sleep for "interval" ms + * @return true if waitTime is up + */ + private boolean doSleep(int interval) { + try { + Thread.sleep(interval); + } catch (InterruptedException e) { + fail("unexpected InterruptedException while sleeping"); + } + waitTime -= interval; + return waitTime <= 0; + } + + /** + * Verify that the toString() method displays the thread's name, + * priority and thread group. + */ + public void testToString() { + Thread t = new Thread(); + String info = t.toString(); + String name = t.getName(); + assertTrue("thread's name is not displayed", info.indexOf(name) >= 0); + String stringPriority = new Integer(t.getPriority()).toString(); + assertTrue("thread's priority is not displayed", + info.indexOf("," + stringPriority + ",") > 0); + String groupName = t.getThreadGroup().getName(); + assertTrue("thread's group is not displayed", info.indexOf(groupName) > 0); + } + + /** + * Thread() + */ + public void testThread() { + Thread t = new Thread(); + assertTrue("incorrect thread name", + t.toString().indexOf("Thread-") >= 0); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + } + + /** + * Verify that a thread created by a daemon thread is daemon + */ + public void testThread_Daemon() { + ThreadRunningAnotherThread t = new ThreadRunningAnotherThread(); + t.setDaemon(true); + t.start(); + t.stop = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertTrue("the child thread of a daemon thread is non-daemon", + t.childIsDaemon); + } + + /** + * Verify that a thread created by a non-daemon thread is not daemon + */ + public void testThread_NotDaemon() { + ThreadRunningAnotherThread t = new ThreadRunningAnotherThread(); + t.setDaemon(false); + t.start(); + t.stop = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertFalse("the child thread of a non-daemon thread is daemon", + t.childIsDaemon); + } + + /** + * Thread(Runnable) + */ + public void testThreadRunnable() { + Square s = new Square(25); + Thread t = new Thread(s); + t.start(); + waitTime = waitDuration; + while (s.squaredNumber == 0 && !(expired = doSleep(10))) { + } + assertEquals("incorrect thread name", 0, t.getName().indexOf("Thread-")); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + s.stop = true; + assertEquals("thread has not run", 625, s.squaredNumber); + } + + /** + * Thread(Runnable, String) + */ + public void testThreadRunnableString() { + Square s = new Square(25); + String name = "squaring"; + Thread t = new Thread(s, name); + t.start(); + waitTime = waitDuration; + while (s.squaredNumber == 0 && !(expired = doSleep(10))) { + } + assertEquals("incorrect thread name", name, t.getName()); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + s.stop = true; + assertEquals("thread has not run", 625, s.squaredNumber); + } + + /** + * Thread(Runnable, String) + */ + public void testThreadRunnableString_NullNotNull() { + String name = "newThread"; + ThreadRunning t = new ThreadRunning((Runnable) null, name); + assertEquals("incorrect thread name", name, t.getName()); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + t.start(); + // thread's run() method should be called if Runnable==null + waitTime = waitDuration; + while (t.i == 0 && !(expired = doSleep(10))) { + } + t.stopWork = true; + assertTrue("thread's run() method has not started", t.i != 0); + } + + /** + * Thread(String) + */ + public void testThreadString() { + String name = "threadString"; + Thread t = new Thread(name); + assertTrue("incorrect thread name", + t.toString().indexOf(name) >= 0); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + } + + /** + * Verify creating a thread with the null name. + * NullPointerException should be thrown. + */ + public void testThreadStringNull() { + String threadName = null; + try { + new Thread(threadName); + fail ("NullPointerException should be thrown when creating " + + "a thread with null name"); + } catch (NullPointerException e) { + return; + } + } + + /** + * Thread(ThreadGroup, Runnable) + */ + public void testThreadThreadGroupRunnable() { + Square s = new Square(25); + ThreadGroup tg = new ThreadGroup("newGroup"); + Thread t = new Thread(tg, s); + t.start(); + waitTime = waitDuration; + while (s.squaredNumber == 0 && !(expired = doSleep(10))) { + } + assertEquals("incorrect thread name", 0, t.getName().indexOf("Thread-")); + assertSame("incorrect thread group", tg, t.getThreadGroup()); + s.stop = true; + assertEquals("thread has not run", 625, s.squaredNumber); + } + + /** + * Thread(ThreadGroup, Runnable) where both arguments are null + */ + public void testThreadThreadGroupRunnable_NullNull() { + ThreadRunning t = new ThreadRunning((ThreadGroup) null, (Runnable) null); + assertEquals("incorrect thread name", 0, t.getName().indexOf("Thread-")); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + t.start(); + // thread's run() method should be called if Runnable==null + waitTime = waitDuration; + while (t.i == 0 && !(expired = doSleep(10))) { + } + t.stopWork = true; + assertTrue("thread's run() method has not started", t.i != 0); + } + + /** + * Thread(ThreadGroup, Runnable, String) + */ + public void testThreadThreadGroupRunnableString() { + ThreadGroup tg = new ThreadGroup("newGroup"); + String name = "t1"; + Square s = new Square(25); + Thread t = new Thread(tg, s, name); + t.start(); + waitTime = waitDuration; + while (s.squaredNumber == 0 && !(expired = doSleep(10))) { + } + assertEquals("incorrect thread name", 0, t.getName().indexOf(name)); + assertSame("incorrect thread group", tg, t.getThreadGroup()); + s.stop = true; + assertEquals("thread has not run", 625, s.squaredNumber); + } + + /** + * Thread(ThreadGroup, Runnable, String) where all arguments are null + */ + public void testThreadThreadGroupRunnableString_NullNullNull() { + try { + new Thread(null, null, null); + fail("NullPointerException has not been thrown"); + } catch (NullPointerException e) { + return; + } + } + + /** + * Thread(ThreadGroup, Runnable, String) where both + * ThreadGroup and Runnable are null + */ + public void testThreadThreadGroupRunnableString_NullNullNotNull() { + String name = "t1"; + ThreadRunning t1 = new ThreadRunning(null, null, name); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t1.getThreadGroup()); + t1.start(); + // thread's run() method should be called if Runnable==null + waitTime = waitDuration; + while (t1.i == 0 && !(expired = doSleep(10))) { + } + t1.stopWork = true; + assertTrue("thread's run() method has not started", t1.i != 0); + } + + /** + * Thread(ThreadGroup, Runnable, String) where ThreadGroup is null + */ + public void testThreadThreadGroupRunnableString_NullNotNullNotNull() { + String name = "t1"; + Square s = new Square(25); + Thread t = new Thread(null, s, name); + t.start(); + waitTime = waitDuration; + while (s.squaredNumber == 0 && !(expired = doSleep(10))) { + } + assertEquals("incorrect thread name", 0, t.getName().indexOf(name)); + assertSame("incorrect thread group", + Thread.currentThread().getThreadGroup(), t.getThreadGroup()); + s.stop = true; + assertEquals("thread has not run", 625, s.squaredNumber); + } + + /** + * Thread(ThreadGroup, Runnable, String, long) + */ + public void testThreadThreadGroupRunnableStringlong() { + ThreadGroup tg = new ThreadGroup("newGroup"); + String name = "t1"; + Square s = new Square(25); + Thread t = new Thread(tg, s, name, 1); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("unexpected: thread has not started"); + } + StackTraceElement ste[] = t.getStackTrace(); + assertTrue("stack dump of thread t1 is empty", ste.length > 0); + s.stop = true; + } + + /** + * Thread(ThreadGroup, Runnable, String, long) + */ +/* + // fails on some platforms due to the known issue: + // OutOfMemoryError when running a thread created with too high stack size + public void testThreadThreadGroupRunnableStringlong_Long_MAX_VALUE() { + ThreadGroup tg = new ThreadGroup("newGroup"); + String name = "t1"; + Square s = new Square(25); + StackTraceElement ste[] = null; + try { + Thread t = new Thread(tg, s, name, Long.MAX_VALUE); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("unexpected: thread has not started"); + } + ste = t.getStackTrace(); + } catch (OutOfMemoryError er) { + fail("OutOfMemoryError when stack size is Long.MAX_VALUE"); + } + assertTrue("stack dump of thread t1 is empty", ste.length > 0); + s.stop = true; + } +*/ + /** + * Thread(ThreadGroup, String) + */ + public void testThreadThreadGroupString() { + String name = "newThread"; + ThreadGroup tg = new ThreadGroup("newGroup"); + Thread t = new Thread(tg, name); + assertEquals("incorrect thread name", name, t.getName()); + assertSame("incorrect thread group", tg, t.getThreadGroup()); + } + + /** + * Get active threads count; should be > 0 + */ + public void testActiveCount() { + int activeCount = Thread.activeCount(); + assertTrue("The active threads count must be >0.", activeCount > 0); + } + + /** + * Verify currentThread() + */ + public void testCurrentThread() { + String name = "runThread"; + ThreadRunningAnotherThread t = new ThreadRunningAnotherThread(name); + t.start(); + waitTime = waitDuration; + while (t.curThread == null && !(expired = doSleep(10))) { + } + assertEquals("incorect current thread name", name, t.curThread.getName()); + t.stop = true; + } + + /** + * Verify currentThread() + */ + public void testCurrentThread_Main() { + String name = "ain"; + Thread t = Thread.currentThread(); + assertTrue("incorect current thread name", t.getName().indexOf(name) > 0); + } + + public void testEnumerate() { + ThreadRunning t1 = new ThreadRunning("ttt1"); + t1.start(); + ThreadRunning t2 = new ThreadRunning("ttt2"); + t2.start(); + ThreadGroup tg1 = new ThreadGroup("tg1"); + ThreadRunning t11 = new ThreadRunning(tg1, "ttt11"); + t11.start(); + ThreadRunning t12 = new ThreadRunning(tg1, "ttt12"); + t12.start(); + ThreadGroup tg12 = new ThreadGroup(tg1, "tg12"); + ThreadRunning t121 = new ThreadRunning(tg12, "ttt121"); + t121.start(); + ThreadRunning t122 = new ThreadRunning(tg12, "ttt122"); + t122.start(); + // estimate dimension as 6 created threads + // plus 10 for some other threads + int estimateLength = 16; + Thread list[]; + int count; + while (true) { + list = new Thread[estimateLength]; + count = Thread.enumerate(list); + if (count == estimateLength) { + estimateLength *= 2; + } else { + break; + } + } + int enumerateCount = 0; + for (int i = 0; i < count; i++) { + if (list[i].toString().indexOf("ttt") > 0) { + enumerateCount++; + } + } + t1.stopWork = true; + t2.stopWork = true; + t11.stopWork = true; + t12.stopWork = true; + t121.stopWork = true; + t122.stopWork = true; + assertEquals("some threads are missed", 6, enumerateCount); + } + + /** + * Test for holdsLock(Object obj) + */ + public void testHoldsLock_False() { + Object lock = new Object(); + assertFalse("lock should not be held", Thread.holdsLock(lock)); + } + + /** + * Test for holdsLock(Object obj) + */ + public void testHoldsLock_True() { + Object lock = new Object(); + synchronized (lock) { + assertTrue("lock should be held", Thread.holdsLock(lock)); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertTrue("lock should be held after sleeping", + Thread.holdsLock(lock)); + try { + lock.wait(100); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertTrue("lock should be obtained after waiting", + Thread.holdsLock(lock)); + } + assertFalse("lock should not be held", Thread.holdsLock(lock)); + } + + /** + * Test for holdsLock(null) + */ + public void testHoldsLock_Null() { + try { + Thread.holdsLock(null); + fail("NullPointerException has not been thrown"); + } catch (NullPointerException e) { + return; + } + } + + /** + * Verify that interrupt status is cleared by the interrupted() + */ + public void testInterrupted() { + class ThreadInterrupt extends Thread { + private boolean interrupted1 = false; + private boolean interrupted2; + + public void run() { + interrupt(); + interrupted1 = Thread.interrupted(); + interrupted2 = Thread.interrupted(); + } + }; + ThreadInterrupt t = new ThreadInterrupt(); + t.start(); + for (waitTime = waitDuration; !t.interrupted1 && !(expired = doSleep(10));) { + } + assertTrue("interrupt status has not changed to true", t.interrupted1); + assertFalse("interrupt status has not changed to false", t.interrupted2); + } + + /** + * Test for void sleep(long) + */ + public void testSleeplong() { + long millis = 2000; + ThreadWaiting tW = new ThreadWaiting(Action.SLEEP, millis, 0); + tW.start(); + try { + tW.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + long duration = System.currentTimeMillis() - tW.getStartTime(); + assertTrue("thread has not slept enough", + duration >= millis); + } + + /** + * Test for void sleep(long, int) + */ + public void testSleeplongint() { + long millis = 2000; + int nanos = 123456; + ThreadWaiting tW = new ThreadWaiting(Action.SLEEP, millis, nanos); + tW.start(); + try { + tW.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + long duration = System.currentTimeMillis() - tW.getStartTime(); + duration *= 1000000; + long sleepTime = millis * 1000000 + nanos; + assertTrue("thread has not slept enough", + duration >= sleepTime); + } + + public void testYield() { + ThreadYielding t1 = new ThreadYielding(1); + ThreadYielding t2 = new ThreadYielding(2); + t1.start(); + t2.start(); + try { + t1.join(); + t2.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + int oneCount = 0; + int threadNum = ThreadYielding.dim / 2; + for (int i = 0; i < threadNum; i++) { + if (ThreadYielding.list[i] == 1) { + oneCount++; + } + } + // We suppose that threads t1 and t2 alternate with each other. + // The might be a case when some another thread (not t2) runs + // while t1 is yelding. In this case the 'list' might start with 1s + // and end with 2s and look like threads does not alternate. + // We cannot treat this as failure nevertheless. + assertTrue("threads have not yielded", oneCount < threadNum); + } + + /** + * Test for checkAccess when there is a SecurityManager + */ + public void testCheckAccess() { + SecurityManager sm = System.getSecurityManager(); + System.setSecurityManager(new ReversibleSecurityManager()); + Thread t = new Thread(); + try { + t.checkAccess(); + } finally { + System.setSecurityManager(sm); + } + } + + public void testDestroy() { + Thread t = new Thread(); + try { + t.destroy(); + fail("the destroy method should not be implemented"); + } catch (NoSuchMethodError er) { + return; + } + } + + /** + * Get context ClassLoader of a newly created thread + */ + public void testGetContextClassLoader() { + Thread t = new Thread(); + assertSame("improper ClassLoader", + Thread.currentThread().getContextClassLoader(), + t.getContextClassLoader()); + } + + /** + * Get context ClassLoader of main thread + */ + public void testGetContextClassLoader_Main() { + ClassLoader cl = null; + + // find the root ThreadGroup + ThreadGroup parent = new ThreadGroup(Thread.currentThread().getThreadGroup(), + "Temporary"); + ThreadGroup newParent = parent.getParent(); + while (newParent != null) { + parent = newParent; + newParent = parent.getParent(); + } + + // enumerate threads and select "main" thread + int threadsCount = parent.activeCount() + 1; + int count; + Thread[] liveThreads; + while (true) { + liveThreads = new Thread[threadsCount]; + count = parent.enumerate(liveThreads); + if (count == threadsCount) { + threadsCount *= 2; + } else { + break; + } + } + for (int i = 0; i < count; i++) { + if (liveThreads[i].toString().indexOf("ain]") > 0) { + cl = liveThreads[i].getContextClassLoader(); + break; + } + } + assertSame("improper ClassLoader", cl, ClassLoader.getSystemClassLoader()); + } + + /** + * Check that IDs of different threads differ + */ + public void testGetIdUnique() { + Thread t1 = new Thread("thread1"); + Thread t2 = new Thread("thread2"); + assertTrue("Thread id must be unique", t1.getId() != t2.getId()); + } + + /** + * Check that ID of a thread does not change + */ + public void testGetIdUnchanged() { + ThreadRunning t1 = new ThreadRunning(); + long tIdNew = t1.getId(); + t1.start(); + waitTime = waitDuration; + while (t1.i == 0 && !(expired = doSleep(10))) { + } + if (expired) { + fail("thread has not started"); + } + long tIdRun = t1.getId(); + assertEquals("Thread ID after start should not change", tIdNew, tIdRun); + t1.stopWork = true; + try { + t1.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + long tIdTerm = t1.getId(); + assertEquals("Thread ID after termination should not change", tIdRun, tIdTerm); + } + + /** + * Verify the getName() method for a thread created with the default name. + * It should start with "Thread-". + */ + public void testGetNameDefault() { + Thread t = new Thread(); + String name = t.getName(); + assertEquals("Thread name must start with 'Thread-'", 0, name.indexOf("Thread-")); + } + + /** + * Verify the getName() method for a thread created with the given name. + */ + public void testGetName() { + Thread t = new Thread("newThread"); + String name = t.getName(); + assertEquals("newThread", name); + } + + /** + * Verify the getPriority() method for a newly created thread. + */ + public void testGetPriority() { + Thread t = new Thread(); + int p = t.getPriority(); + assertTrue("The thread's priority is out of range", + Thread.MIN_PRIORITY <= p && p <= Thread.MAX_PRIORITY); + } + + /** + * Get the stack trace of a thread. + * Should be empty for new and terminated threads. + * Should not be empty for running threads. + */ + public void testGetStackTrace() { + ThreadRunning tR = new ThreadRunning(); + + // get stack trace of a new thread + StackTraceElement ste[] = tR.getStackTrace(); + assertEquals("stack dump of a new thread is not empty", ste.length, 0); + tR.start(); + + // get stack trace of a running thread + waitTime = waitDuration; + do { + ste = tR.getStackTrace(); + } while (ste.length == 0 && !(expired = doSleep(10))); + if (expired) { + fail("stack dump of a running thread is empty"); + } else { + assertTrue("incorrect length", ste.length >= 1); + assertEquals("incorrect class name", + "java.lang.ThreadTest$ThreadRunning", + ste[0].getClassName()); + assertEquals("incorrect method name", + "run", ste[0].getMethodName()); + } + + // get stack trace of a terminated thread + tR.stopWork = true; + try { + tR.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + waitTime = waitDuration; + do { + ste = tR.getStackTrace(); + } while (ste.length != 0 && !(expired = doSleep(10))); + if (expired) { + fail("stack dump of a terminated thread is not empty"); + } + } + + /** + * Verify getAllStackTraces() + */ + public void testGetAllStackTraces() { + StackTraceElement ste[] = null; + ThreadRunning tR = new ThreadRunning("MyThread"); + tR.start(); + + Map<Thread, StackTraceElement[]> m = Thread.getAllStackTraces(); + tR.stopWork = true; + assertTrue("getAllStackTraces() returned an empty Map", m.size() > 0); + + // verify stack traces of all threads + Set<Thread> threadSet = m.keySet(); + for (Thread t : threadSet) { + ste = m.get(t); + assertNotNull("improper stack trace for thread " + t, ste); + } + } + + /** + * Get the thread group of a thread created in the current thread's + * thread group. + */ + public void testGetThreadGroup() { + Thread t = new Thread(); + ThreadGroup threadGroup = t.getThreadGroup(); + ThreadGroup curThreadGroup = Thread.currentThread().getThreadGroup(); + assertEquals("incorrect value returned by getThreadGroup()", + curThreadGroup, threadGroup); + } + + /** + * Get the thread group of a thread created in the specified thread group. + */ + public void testGetThreadGroup1() { + ThreadGroup tg = new ThreadGroup("group1"); + Thread t = new Thread(tg, "t1"); + ThreadGroup threadGroup = t.getThreadGroup(); + assertEquals("incorrect value returned by getThreadGroup()", + tg, threadGroup); + } + + /** + * Get the thread group of a dead thread. + */ + public void testGetThreadGroup_DeadThread() { + ThreadRunning t = new ThreadRunning(); + t.start(); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + assertNull("Thread group of a dead thread must be null", + t.getThreadGroup()); + } + + /** + * Get the state of a blocked thread. + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetStateBlocked() { + Team team = new Team(); + RunProject pr1 = new RunProject(team); + pr1.start(); + RunProject pr2 = new RunProject(team); + pr2.start(); + Thread.State state; + waitTime = waitDuration; + do { + state = pr2.getState(); + } while (!state.equals(Thread.State.BLOCKED) && !(expired = doSleep(10))); + team.stopWork(); + if (expired) { + fail("BLOCKED state has not been set"); + } + } +*/ + /** + * Get the state of a new thread. + */ + public void testGetStateNew() { + ThreadRunning tR = new ThreadRunning(); + Thread.State state = tR.getState(); + assertEquals(Thread.State.NEW, state); + } + + /** + * Get the state of a new thread. + */ + public void testGetStateNew1() { + Square s = new Square(15); + Thread t = new Thread(s); + assertEquals(Thread.State.NEW, t.getState()); + } + + /** + * Get the state of a runnable thread. + */ + public void testGetStateRunnable() { + ThreadRunning tR = new ThreadRunning(); + tR.start(); + Thread.State state; + waitTime = waitDuration; + do { + state = tR.getState(); + } while (!state.equals(Thread.State.RUNNABLE) && !(expired = doSleep(10))); + tR.stopWork = true; + if (expired) { + fail("RUNNABLE state has not been set"); + } + } + + /** + * Get the state of a runnable thread. + */ + public void testGetStateRunnable1() { + Square s = new Square(15); + Thread t = new Thread(s); + t.start(); + Thread.State state; + waitTime = waitDuration; + do { + state = t.getState(); + } while (!state.equals(Thread.State.RUNNABLE) && !(expired = doSleep(10))); + s.stop = true; + if (expired) { + fail("RUNNABLE state has not been set"); + } + } + + /** + * Get the state of a terminated thread. + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetStateTerminated() { + ThreadRunning tR = new ThreadRunning(); + tR.start(); + tR.stopWork = true; + try { + tR.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + Thread.State state; + waitTime = waitDuration; + do { + state = tR.getState(); + } while (!state.equals(Thread.State.TERMINATED) && !(expired = doSleep(10))); + if (expired) { + fail("TERMINATED state has not been set"); + } + } +*/ + /** + * Get the state of a terminated thread. + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetStateTerminated1() { + Square s = new Square(15); + Thread tR = new Thread(s); + tR.start(); + s.stop = true; + try { + tR.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + Thread.State state = tR.getState(); + waitTime = waitDuration; + while (!state.equals(Thread.State.TERMINATED) && !(expired = doSleep(10))) { + state = tR.getState(); + } + if (expired) { + fail("TERMINATED state has not been set"); + } + } +*/ + /** + * Get the state of a timed waiting thread. + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetStateTimedWaiting() { + ThreadWaiting tW = new ThreadWaiting(Action.WAIT, 6000, 0); + tW.start(); + Thread.State state; + waitTime = waitDuration; + do { + state = tW.getState(); + } while (!state.equals(Thread.State.TIMED_WAITING) && !(expired = doSleep(10))); + synchronized (tW) { + tW.notify(); + } + if (expired) { + fail("TIMED_WAITING state has not been set"); + } + } +*/ + /** + * Get the state of a waiting thread. + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetStateWaiting() { + ThreadWaiting tW = new ThreadWaiting(Action.WAIT, 0, 0); + tW.start(); + Thread.State state; + waitTime = waitDuration; + do { + state = tW.getState(); + } while (!state.equals(Thread.State.WAITING) && !(expired = doSleep(10))); + synchronized (tW) { + tW.notify(); + } + if (expired) { + fail("WAITING state has not been set"); + } + } +*/ + class ExceptionHandler implements Thread.UncaughtExceptionHandler { + + public boolean wasCalled = false; + + public void uncaughtException(Thread t, Throwable e) { + wasCalled = true; + } + } + + /** + * Test for getUncaughtExceptionHandler() + */ + public void testGetUncaughtExceptionHandler() { + ThreadGroup tg = new ThreadGroup("test thread group"); + Thread t = new Thread(tg, "test thread"); + Thread.UncaughtExceptionHandler hndlr = t.getUncaughtExceptionHandler(); + assertSame("Thread's thread group is expected to be a handler", + tg, hndlr); + } + + /** + * Test getUncaughtExceptionHandler() for a terminated thread + */ +/* + // fails due to the known issue: getState() does not return correct values + public void testGetUncaughtExceptionHandler_Null() { + ThreadGroup tg = new ThreadGroup("test thread group"); + Thread t = new Thread(tg, "test thread"); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + Thread.State state; + waitTime = waitDuration; + do { + state = t.getState(); + } while (!state.equals(Thread.State.TERMINATED) && !(expired = doSleep(10))); + if (expired) { + fail("TERMINATED state has not been set"); + } + assertNull("handler should be null for a terminated thread", + t.getUncaughtExceptionHandler()); + } +*/ + /** + * Test for setUncaughtExceptionHandler() + */ + public void testSetUncaughtExceptionHandler() { + ThreadGroup tg = new ThreadGroup("test thread group"); + Thread t = new Thread(tg, "test thread"); + ExceptionHandler eh = new ExceptionHandler(); + t.setUncaughtExceptionHandler(eh); + assertSame("the handler has not been set", + eh, t.getUncaughtExceptionHandler()); + } + + /** + * Test for setUncaughtExceptionHandler(null) + */ + public void testSetUncaughtExceptionHandler_Null() { + ThreadGroup tg = new ThreadGroup("test thread group"); + Thread t = new Thread(tg, "test thread"); + t.setUncaughtExceptionHandler(null); + assertSame("Thread's thread group is expected to be a handler", + tg, t.getUncaughtExceptionHandler()); + } + + /** + * Test set/get DefaultUncaughtExceptionHandler() + */ + public void testSetDefaultUncaughtExceptionHandler() { + ExceptionHandler eh = new ExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(eh); + assertSame("the default handler has not been set", + eh, Thread.getDefaultUncaughtExceptionHandler()); + } + + /** + * Test set/get DefaultUncaughtExceptionHandler(null) + */ + public void testSetDefaultUncaughtExceptionHandler_Null() { + Thread.setDefaultUncaughtExceptionHandler(null); + assertNull("default handler should be null", + Thread.getDefaultUncaughtExceptionHandler()); + } + + /** + * Interrupt a newly created thread + */ + public void testInterrupt_New() { + Thread t = new Thread(); + t.interrupt(); + waitTime = waitDuration; + while (!t.isInterrupted() && !(expired = doSleep(10))) { + } + if (expired) { + fail("interrupt status has not changed to true"); + } + } + + /** + * Interrupt a running thread + */ + public void testInterrupt_RunningThread() { + ThreadRunning t = new ThreadRunning(); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("unexpected: thread has not started"); + } + t.interrupt(); + waitTime = waitDuration; + while (!t.isInterrupted() && !(expired = doSleep(10))) { + } + t.stopWork = true; + if (expired) { + fail("interrupt status has not changed to true"); + } + } + + /** + * Interrupt the current thread + */ +/* + // fails due to the known issue: interrupt() does not set + // the current thread's interrupted status + public void testInterrupt_CurrentThread() { + Thread t = new Thread() { + public void run() { + interrupt(); + } + }; + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("unexpected: thread has not started"); + } + waitTime = waitDuration; + while (!t.isInterrupted() && !(expired = doSleep(10))) { + } + if (expired) { + fail("interrupt status has not changed to true"); + } + } +*/ + /** + * Interrupt a terminated thread + */ + public void testInterrupt_Terminated() { + ThreadRunning t = new ThreadRunning(); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("thread has not started"); + } + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + t.interrupt(); + assertTrue("interrupt status has not changed to true", + t.isInterrupted()); + } + + /** + * Interrupt a joining thread + */ + + public void testInterrupt_Joining() { + ThreadWaiting t = new ThreadWaiting(Action.JOIN, 10000, 0); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("thread has not started for " + waitDuration + "ms"); + } + t.interrupt(); + waitTime = waitDuration; + while (!t.exceptionReceived && !(expired = doSleep(10))) { + } + if (expired) { + fail("joining thread has not received the InterruptedException"); + } + assertFalse("interrupt status has not been cleared", + t.isInterrupted()); + } + + /** + * Interrupt a sleeping thread + */ + public void testInterrupt_Sleeping() { + ThreadWaiting t = new ThreadWaiting(Action.SLEEP, 10000, 0); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("thread has not started for " + waitDuration + "ms"); + } + t.interrupt(); + waitTime = waitDuration; + while (!t.exceptionReceived && !(expired = doSleep(10))) { + } + if (expired) { + fail("sleeping thread has not received the InterruptedException"); + } + assertFalse("interrupt status has not been cleared", + t.isInterrupted()); + } + + /** + * Interrupt a waiting thread + */ + public void testInterrupt_Waiting() { + ThreadWaiting t = new ThreadWaiting(Action.WAIT, 10000, 0); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("thread has not started for " + waitDuration + "ms"); + } + t.interrupt(); + waitTime = waitDuration; + while (!t.exceptionReceived && !(expired = doSleep(10))) { + } + if (expired) { + fail("waiting thread has not received the InterruptedException"); + } + assertFalse("interrupt status has not been cleared", + t.isInterrupted()); + + } + + /** + * Verify that the current thread is alive + */ + public void testIsAliveCurrent() { + assertTrue("The current thread must be alive!", Thread.currentThread().isAlive()); + } + + /** + * Verify the isAlive() method for a newly created, running + * and finished thread + */ + public void testIsAlive1() { + TestThread t = new TestThread(); + assertFalse("Newly created and not started thread must not be alive!", + t.isAlive()); + try { + synchronized (t) { + t.start(); + t.wait(); + } + if (!t.isAlive()) { + if (t.e != null) { + fail("The thread was interrupted"); + } + fail("The thread must be alive"); + } + synchronized (t) { + t.notify(); + } + waitTime = waitDuration; + while (t.isAlive() && !(expired = doSleep(10))) { + t.join(); + } + if (expired) { + fail("thread has not finished for " + waitDuration + "ms"); + } + } catch (InterruptedException e) { + fail("Current thread was interrupted"); + } + } + + /** + * Verify the isAlive() method for a few threads + */ + public void testIsAlive2() { + ThreadRunning t1 = new ThreadRunning(); + ThreadRunning t2 = new ThreadRunning(); + ThreadRunning t3 = new ThreadRunning(); + assertFalse("t1 has not started and must not be alive", t1.isAlive()); + assertFalse("t2 has not started and must not be alive", t2.isAlive()); + assertFalse("t3 has not started and must not be alive", t3.isAlive()); + t1.start(); + t2.start(); + t3.start(); + assertTrue("t1 must be alive", t1.isAlive()); + assertTrue("t2 must be alive", t2.isAlive()); + assertTrue("t3 must be alive", t3.isAlive()); + t1.stopWork = true; + t2.stopWork = true; + t3.stopWork = true; + try { + t1.join(); + t2.join(); + t3.join(); + } catch (InterruptedException e) { + fail("threads have been interrupted"); + } + assertFalse("t1 has finished and must not be alive", t1.isAlive()); + assertFalse("t2 has finished and must not be alive", t2.isAlive()); + assertFalse("t3 has finished and must not be alive", t3.isAlive()); + } + + public void testIsDaemonFalse() { + Thread t = new Thread(); + assertFalse("thread should not be daemon", t.isDaemon()); + } + + public void testIsDaemonTrue() { + Thread t = new Thread(); + t.setDaemon(true); + assertTrue("thread should be daemon", t.isDaemon()); + } + + /** + * Check that interrupt status is not affected by isInterrupted() + */ + public void testIsInterrupted() { + ThreadRunning t = new ThreadRunning(); + t.start(); + waitTime = waitDuration; + while (!t.isAlive() && !(expired = doSleep(10))) { + } + if (expired) { + fail("unexpected: thread has not started"); + } + t.interrupt(); + waitTime = waitDuration; + while (!t.isInterrupted() && !(expired = doSleep(10))) { + } + t.stopWork = true; + if (expired) { + fail("interrupt status has not changed to true"); + } + assertTrue("interrupt status has been cleared by the previous call", + t.isInterrupted()); + } + + /** + * Test for void join(long) + */ + public void testJoinlong() { + long millis = 2000; + ThreadRunning t = new ThreadRunning(); + t.start(); + try { + t.join(millis); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + long curTime = System.currentTimeMillis(); + long duration = curTime - t.getStartTime(); + t.stopWork = true; + assertTrue("join(" + millis + ") has waited for " + duration, + duration >= millis); + } + + /** + * Test for void join(long, int) + */ + public void testJoinlongint() { + long millis = 2000; + int nanos = 999999; + ThreadRunning t = new ThreadRunning(); + t.start(); + try { + t.join(millis, nanos); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + long curTime = System.currentTimeMillis(); + long duration = 1000000 * (curTime - t.getStartTime()); + long joinTime = 1000000 * millis + nanos; + t.stopWork = true; + assertTrue("join should wait for at least " + joinTime + + " but waited for " + duration, + duration >= joinTime); + } + + /** + * Test for run(). Should do nothing. + */ + public void testRun() { + Thread t = new Thread(); + Thread.State tsBefore = t.getState(); + t.run(); + Thread.State tsAfter = t.getState(); + assertEquals("run() should do nothing", tsBefore, tsAfter); + } + + /** + * Test for run(). Should call run() of a Runnable object. + */ + public void testRun_Runnable() { + Square s = new Square(25, true); + Thread t = new Thread(s); + t.run(); + assertEquals("thread has not run", 625, s.squaredNumber); + } + + public void testSetContextClassLoader() { + Class c = null; + try { + c = Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + fail("ClassNotFoundException for java.lang.String"); + } + ClassLoader cl = c.getClassLoader(); + ThreadRunningAnotherThread t = new ThreadRunningAnotherThread(); + ClassLoader clt = t.getContextClassLoader(); + t.setContextClassLoader(cl); + ClassLoader clNew = t.getContextClassLoader(); + assertSame("incorrect ClassLoader has been set", + cl, clNew); + assertNotSame("ClassLoader has not changed", clt, clNew); + } + + /** + * Make a thread daemon + */ + public void testSetDaemon() { + Thread t = new Thread(); + assertFalse("Assert 0: the newly created thread must not be daemon", + t.isDaemon()); + t.setDaemon(true); + assertTrue("Assert 1: the thread must be daemon", t.isDaemon()); + } + + /** + * Try to make a running thread daemon + */ + public void testSetDaemonLiveThread() { + ThreadRunning t = new ThreadRunning(); + t.start(); + try { + t.setDaemon(true); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + fail("IllegalThreadStateException has not been thrown"); + } catch (IllegalThreadStateException e) { + return; + } + } + + /** + * Make a dead thread daemon + */ + public void testSetDaemonDeadThread() { + ThreadRunning t = new ThreadRunning(); + t.start(); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + boolean threadDaemonStatus = t.isDaemon(); + try { + t.setDaemon(!threadDaemonStatus); + } catch (IllegalThreadStateException e) { + fail("IllegalThreadStateException should not be thrown" + + " for a dead thread"); + } + } + + /** + * Verify the setName() method + */ + public void testSetName() { + Thread thread = new Thread(); + String newName = "qwerty"; + thread.setName(newName); + assertEquals("setName() has not set the new name", + newName, thread.getName()); + } + + /** + * Verify the setName(null) method + */ + public void testSetNameNull() { + Thread thread = new Thread(); + try { + thread.setName(null); + } catch (NullPointerException e) { + return; + } + fail("setName() should not accept null names"); + } + + /** + * Verify the setName() method when a SecurityManager is set. + */ + public void testSetName_CheckAccess() { + sm = System.getSecurityManager(); + System.setSecurityManager(new ReversibleSecurityManager()); + Thread thread = new Thread(); + String newName = "qwerty"; + thread.setName(newName); + String gotName = thread.getName(); + System.setSecurityManager(sm); + assertEquals("setName() has not set the new name", + newName, gotName); + } + + /** + * Verify the setPriority() method to a dead thread. + * NullPointerException is expected + */ + public void testSetPriorityDeadThread() { + ThreadGroup tg = new ThreadGroup("group1"); + int maxTGPriority = Thread.MAX_PRIORITY - 1; + tg.setMaxPriority(maxTGPriority); + ThreadRunning t = new ThreadRunning(tg, "running"); + t.start(); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + int newPriority = Thread.MAX_PRIORITY; + try { + t.setPriority(newPriority); + fail("NullPointerException has not been thrown"); + } catch (NullPointerException e) { + return; + } + } + + /** + * Verify the setPriority() method with new priority higher + * than the maximum permitted priority for the thread's group. + */ + public void testSetPriorityGreaterMax() { + ThreadGroup tg = new ThreadGroup("group1"); + int maxTGPriority = Thread.MAX_PRIORITY - 1; + tg.setMaxPriority(maxTGPriority); + Thread t = new Thread(tg, "t"); + t.setPriority(Thread.MAX_PRIORITY); + assertEquals(maxTGPriority, t.getPriority()); + } + + /** + * Verify the setPriority() method with new priority lower + * than the current one. + */ + public void testSetPriorityLower() { + Thread t = new Thread(); + int p = t.getPriority(); + int newPriority = p - 1; + if (newPriority >= Thread.MIN_PRIORITY) { + t.setPriority(newPriority); + assertEquals(newPriority, t.getPriority()); + } + } + + /** + * Verify the setPriority() method with new priority out of the legal range. + */ + public void testSetPriorityOutOfRange() { + Thread t = new Thread(); + try { + t.setPriority(Thread.MAX_PRIORITY + 2); + fail("IllegalArgumentException should be thrown when setting " + + "illegal priority"); + } catch (IllegalArgumentException e) { + return; + } + } + + /** + * Verify the setPriority() method when a SecurityManager is set. + */ + public void testSetPriority_CheckAccess() { + sm = System.getSecurityManager(); + System.setSecurityManager(new ReversibleSecurityManager()); + Thread t = new Thread(); + int p = t.getPriority(); + t.setPriority(p); + int newP = t.getPriority(); + System.setSecurityManager(sm); + assertEquals(p, newP); + } + + /** + * Start the already started thread + */ + public void testStart_Started() { + ThreadRunning t = new ThreadRunning(); + t.start(); + try { + t.start(); + t.stopWork = true; + fail("IllegalThreadStateException is expected when starting " + + "a started thread"); + } catch (IllegalThreadStateException e) { + t.stopWork = true; + } + } + + /** + * Start the already finished thread + */ + public void testStart_Finished() { + ThreadRunning t = new ThreadRunning(); + t.start(); + t.stopWork = true; + try { + t.join(); + } catch (InterruptedException e) { + fail(INTERRUPTED_MESSAGE); + } + try { + t.start(); + fail("IllegalThreadStateException is expected when starting " + + "a finished thread"); + } catch (IllegalThreadStateException e) { + return; + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ThrowableRTest.java vm/tests/kernel/java/lang/ThrowableRTest.java new file mode 100644 index 0000000..a984475 --- /dev/null +++ vm/tests/kernel/java/lang/ThrowableRTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Elena Semukhina + * @version $Revision$ + */ + +package java.lang; + +import junit.framework.TestCase; + +public class ThrowableRTest extends TestCase { + + private class initCauseExc extends RuntimeException { + + private static final long serialVersionUID = 0L; + + initCauseExc(Throwable cause){ + super(cause); + } + + public Throwable initCause(Throwable cause) { + return cause; + } + } + + /* + * Test the Throwable(Throwable) constructor when the initCause() method + * is overloaded + */ + public void testThrowableThrowableInitCause() { + NullPointerException nPE = new NullPointerException(); + initCauseExc iC = new initCauseExc(nPE); + assertTrue("Assert 0: The cause has not been set", + iC.getCause() != null); + assertTrue("Assert 1: The invalid cause has been set", + iC.getCause() == nPE); + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/ThrowableTest.java vm/tests/kernel/java/lang/ThrowableTest.java new file mode 100644 index 0000000..a0b4d3b --- /dev/null +++ vm/tests/kernel/java/lang/ThrowableTest.java @@ -0,0 +1,325 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Dmitry B. Yershov + * @version $Revision$ + */ +package java.lang; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import junit.framework.TestCase; + +public class ThrowableTest extends TestCase { + + private static final boolean isLinux = System.getProperty("os.name") + .toLowerCase().indexOf("linux") != -1; + + private static final String printOutput = + "java.lang.Throwable: Throwable 0\n" + + "\tat d.d(d:1)\n\tat c.c(c:1)\n\tat b.b(Native Method)\n\tat a.a(a:1)\n" + + "Caused by: java.lang.Throwable: Throwable 1\n" + + "\tat f.f(f:1)\n\tat e.e(Native Method)\n\tat d.d(d:1)\n\t... 3 more\n" + + "Caused by: java.lang.Throwable: Throwable 2\n" + + "\tat d.d(d:1)\n\t... 3 more" + (isLinux ? "\n" : "\r\n"); + + /** + * Constructor under test Throwable(String) + */ + public void testThrowableString() { + Throwable th = new Throwable("aaa"); + assertEquals("incorrect message", "aaa", th.getMessage()); + assertNull("cause should be null", th.getCause()); + assertTrue("empty stack trace", th.getStackTrace().length > 0); + } + + /** + * Constructor under test Throwable(String, Throwable) + */ + public void testThrowableStringThrowable() { + Throwable th1 = new Throwable(); + Throwable th = new Throwable("aaa", th1); + assertEquals("incorrect message", "aaa", th.getMessage()); + assertSame("incorrect cause", th1, th.getCause()); + assertTrue("empty stack trace", th.getStackTrace().length > 0); + } + + /** + * Constructor under test Throwable(Throwable) + */ + public void testThrowableThrowable() { + Throwable th1 = new Throwable("aaa"); + Throwable th = new Throwable(th1); + assertEquals("incorrect message", + "java.lang.Throwable: aaa", th.getMessage()); + assertSame("incorrect cause", th1, th.getCause()); + assertTrue("empty stack trace", th.getStackTrace().length > 0); + } + + /** + * fillInStackTrace() should return reference to <code>this</code> + * of the target Throwable. + */ + public void testFillInStackTrace_return() { + + Throwable th = new Throwable(); + assertSame(th, th.fillInStackTrace()); + } + + private Throwable makeThrowable() { + return new Throwable(); + } + + private void updateThrowable(Throwable t, int depth) { + if (depth-- > 0) { + updateThrowable(t, depth); + } else { + t.fillInStackTrace(); + } + } + + /** + * fillInStackTrace() should not change recorded stack info + * on subsequent invocations. + */ + public void testFillInStackTrace_manytimes() { + Throwable th = makeThrowable(); + int len1 = th.getStackTrace().length; + th.fillInStackTrace(); + assertEquals("case 1", len1, th.getStackTrace().length); + updateThrowable(th, 10); + assertEquals("case 2", len1, th.getStackTrace().length); + } + + /** + * Method under test Throwable getCause() + */ + public void testGetCause() { + Throwable th = new Throwable(); + Throwable th1 = new Throwable(); + assertNull("cause should be null", th.getCause()); + th = new Throwable(th1); + assertSame("incorrect cause", th1, th.getCause()); + } + + /** + * Method under test String getLocalizedMessage() + */ + public void testGetLocalizedMessage() { + Throwable th = new Throwable("aaa"); + assertEquals("incorrect localized message", + "aaa", th.getLocalizedMessage()); + } + + /** + * Method under test String getMessage() + */ + public void testGetMessage() { + Throwable th = new Throwable("aaa"); + assertEquals("incorrect message", "aaa", th.getMessage()); + } + + /** + * Method under test StackTraceElement[] getStackTrace() + */ + public void testGetStackTrace() { + StackTraceElement[] ste = new StackTraceElement[1]; + ste[0] = new StackTraceElement("class", "method", "file", -2); + Throwable th = new Throwable("message"); + th.setStackTrace(ste); + ste = th.getStackTrace(); + assertEquals("incorrect length", 1, ste.length); + assertEquals("incorrect file name", "file", ste[0].getFileName()); + assertEquals("incorrect line number", -2, ste[0].getLineNumber()); + assertEquals("incorrect class name", "class", ste[0].getClassName()); + assertEquals("incorrect method name", "method", ste[0].getMethodName()); + assertTrue("native method should be reported", ste[0].isNativeMethod()); + } + + /** + * Method under test Throwable initCause(Throwable) + */ + public void testInitCause() { + Throwable th = new Throwable(); + Throwable th1 = new Throwable(); + th.initCause(th1); + assertSame("incorrect cause", th1, th.getCause()); + th = new Throwable(); + th.initCause(null); + assertNull("cause should be null", th.getCause()); + th = new Throwable(); + try { + th.initCause(th); + fail("Throwable initialized by itself"); + } catch (IllegalArgumentException ex) { + } + th = new Throwable((Throwable)null); + try { + th.initCause(th1); + fail("Second initialization"); + } catch (IllegalStateException ex) { + } + th = new Throwable(th1); + try { + th.initCause(th1); + fail("Second initialization"); + } catch (IllegalStateException ex) { + } + th = new Throwable(); + th1 = th.initCause(th1); + assertSame("incorrect value returned from initCause", th, th1); + } + + /** + * Method under test void setStackTrace(StackTraceElement[]) + */ + public void testSetStackTrace() { + StackTraceElement[] ste = new StackTraceElement[2]; + ste[0] = new StackTraceElement("class", "method", "file", -2); + ste[1] = new StackTraceElement("class", "method", "file", 1); + Throwable th = new Throwable(); + th.setStackTrace(ste); + ste = th.getStackTrace(); + assertEquals("incorrect length", 2, ste.length); + assertEquals("incorrect file name", "file", ste[0].getFileName()); + assertEquals("incorrect line number", -2, ste[0].getLineNumber()); + assertEquals("incorrect class name", "class", ste[0].getClassName()); + assertEquals("incorrect method name", "method", ste[0].getMethodName()); + assertTrue("native method should be reported", ste[0].isNativeMethod()); + assertEquals("incorrect file name", "file", ste[1].getFileName()); + assertEquals("incorrect line number", 1, ste[1].getLineNumber()); + assertEquals("incorrect class name", "class", ste[1].getClassName()); + assertEquals("incorrect method name", "method", ste[1].getMethodName()); + assertFalse("native method should NOT be reported", ste[1].isNativeMethod()); + ste[1] = null; + try { + th.setStackTrace(ste); + } catch (NullPointerException ex) { + } + ste = null; + try { + th.setStackTrace(ste); + } catch (NullPointerException ex) { + } + } + + /** + * Method under test void setStackTrace(StackTraceElement[]). + * Null arguments are verified + */ + public void testSetStackTrace_Null() { + Throwable th = new Throwable(); + StackTraceElement[] ste = null; + try { + th.setStackTrace(ste); + fail("Assert 1: NullPointerException should be thrown"); + } catch (NullPointerException ex) { + } + ste = new StackTraceElement[2]; + ste[0] = new StackTraceElement("class", "method", "file", -2); + ste[1] = null; + try { + th.setStackTrace(ste); + fail("Assert 2: NullPointerException should be thrown"); + } catch (NullPointerException ex) { + } + } + + + /** + * Method under test String toString() + */ + public void testToString() { + Throwable th = new Throwable("aaa"); + assertEquals("incorrect String representation", + "java.lang.Throwable: aaa", th.toString()); + } + + /** + * Method under test: + * - void printStackTrace(PrintStream) + */ + public void testPrintStackTracePrintStream() { + Throwable th; + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(ba); + th = prepareThrowables(); + th.printStackTrace(ps); + assertEquals("incorrect info printed in stack trace", + printOutput, ba.toString()); + } + + /** + * Methods under test: + * - void printStackTrace(PrintWriter), + * where PrintWriter does not flush automatically. + */ + public void testPrintStackTracePrintWriter_False() { + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + PrintWriter ps = new PrintWriter(ba, false); + try { + throw new Exception("level1", new Exception("level2", new Exception("level3", new NullPointerException()))); + } catch (Exception e) { + e.printStackTrace(ps); + } + assertEquals("the output should be empty until flush", + "", ba.toString()); + } + + /** + * Methods under test: + * - void printStackTrace(PrintWriter), + * where PrintWriter flushes automatically + */ + public void testPrintStackTracePrintWriter_True() { + Throwable th; + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + PrintWriter ps = new PrintWriter(ba, true); + th = prepareThrowables(); + th.printStackTrace(ps); + assertEquals("incorrect info in printed stack trace", + printOutput, ba.toString()); + } + + private Throwable prepareThrowables() { + Throwable th, th1, th2; + StackTraceElement[] ste = new StackTraceElement[4]; + StackTraceElement[] ste1 = new StackTraceElement[6]; + + ste[0] = new StackTraceElement("d", "d", "d", 1); + ste[1] = new StackTraceElement("c", "c", "c", 1); + ste[2] = new StackTraceElement("b", "b", null, -2); + ste[3] = new StackTraceElement("a", "a", "a", 1); + + ste1[0] = new StackTraceElement("f", "f", "f", 1); + ste1[1] = new StackTraceElement("e", "e", null, -2); + ste1[2] = new StackTraceElement("d", "d", "d", 1); + ste1[3] = new StackTraceElement("c", "c", "c", 1); + ste1[4] = new StackTraceElement("b", "b", null, -2); + ste1[5] = new StackTraceElement("a", "a", "a", 1); + + th2 = new Throwable("Throwable 2"); + th2.setStackTrace(ste); + th1 = new Throwable("Throwable 1"); + th1.initCause(th2); + th1.setStackTrace(ste1); + th = new Throwable("Throwable 0", th1); + th.setStackTrace(ste); + return th; + } +} diff --git vm/tests/kernel/java/lang/pkg1/Bogus.java vm/tests/kernel/java/lang/pkg1/Bogus.java new file mode 100644 index 0000000..2a2bab9 --- /dev/null +++ vm/tests/kernel/java/lang/pkg1/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg1; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg1/package-info.java vm/tests/kernel/java/lang/pkg1/package-info.java new file mode 100644 index 0000000..4216d41 --- /dev/null +++ vm/tests/kernel/java/lang/pkg1/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@TagAntn +package java.lang.pkg1; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; diff --git vm/tests/kernel/java/lang/pkg2/Bogus.java vm/tests/kernel/java/lang/pkg2/Bogus.java new file mode 100644 index 0000000..0b17b94 --- /dev/null +++ vm/tests/kernel/java/lang/pkg2/Bogus.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +package java.lang.pkg2; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg2/package-info.java vm/tests/kernel/java/lang/pkg2/package-info.java new file mode 100644 index 0000000..825f3e1 --- /dev/null +++ vm/tests/kernel/java/lang/pkg2/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@TagAntn +@ValAntn +package java.lang.pkg2; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn; diff --git vm/tests/kernel/java/lang/pkg3/Bogus.java vm/tests/kernel/java/lang/pkg3/Bogus.java new file mode 100644 index 0000000..55b4189 --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg3; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg3/Pkg3Antn.java vm/tests/kernel/java/lang/pkg3/Pkg3Antn.java new file mode 100644 index 0000000..4a844ad --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/Pkg3Antn.java @@ -0,0 +1,29 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg3; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +public @interface Pkg3Antn {} diff --git vm/tests/kernel/java/lang/pkg3/package-info.java vm/tests/kernel/java/lang/pkg3/package-info.java new file mode 100644 index 0000000..e65d87a --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@Pkg3Antn +package java.lang.pkg3; diff --git vm/tests/kernel/java/lang/pkg3/pkg31/Bogus.java vm/tests/kernel/java/lang/pkg3/pkg31/Bogus.java new file mode 100644 index 0000000..2b8d55f --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/pkg31/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg3.pkg31; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg3/pkg31/Pkg31Antn.java vm/tests/kernel/java/lang/pkg3/pkg31/Pkg31Antn.java new file mode 100644 index 0000000..cfb060f --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/pkg31/Pkg31Antn.java @@ -0,0 +1,29 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg3.pkg31; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +public @interface Pkg31Antn {} diff --git vm/tests/kernel/java/lang/pkg3/pkg31/package-info.java vm/tests/kernel/java/lang/pkg3/pkg31/package-info.java new file mode 100644 index 0000000..03839e0 --- /dev/null +++ vm/tests/kernel/java/lang/pkg3/pkg31/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@Pkg31Antn +package java.lang.pkg3.pkg31; diff --git vm/tests/kernel/java/lang/pkg4/Bogus.java vm/tests/kernel/java/lang/pkg4/Bogus.java new file mode 100644 index 0000000..98ffd8d --- /dev/null +++ vm/tests/kernel/java/lang/pkg4/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg4; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg4/package-info.java vm/tests/kernel/java/lang/pkg4/package-info.java new file mode 100644 index 0000000..826173d --- /dev/null +++ vm/tests/kernel/java/lang/pkg4/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@notfound.MissingAntn +package java.lang.pkg4; diff --git vm/tests/kernel/java/lang/pkg5/Bogus.java vm/tests/kernel/java/lang/pkg5/Bogus.java new file mode 100644 index 0000000..1498153 --- /dev/null +++ vm/tests/kernel/java/lang/pkg5/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg5; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg5/package-info.java vm/tests/kernel/java/lang/pkg5/package-info.java new file mode 100644 index 0000000..9a701d6 --- /dev/null +++ vm/tests/kernel/java/lang/pkg5/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn +package java.lang.pkg5; diff --git vm/tests/kernel/java/lang/pkg6/Bogus.java vm/tests/kernel/java/lang/pkg6/Bogus.java new file mode 100644 index 0000000..9ba5a2a --- /dev/null +++ vm/tests/kernel/java/lang/pkg6/Bogus.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.pkg6; + +public class Bogus {} diff --git vm/tests/kernel/java/lang/pkg6/package-info.java vm/tests/kernel/java/lang/pkg6/package-info.java new file mode 100644 index 0000000..dbf5881 --- /dev/null +++ vm/tests/kernel/java/lang/pkg6/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +@org.apache.harmony.lang.AnnotatedElementTestFrame.MissingTypeAntn +package java.lang.pkg6; diff --git vm/tests/kernel/java/lang/reflect/AccessibleObjectTest.java vm/tests/kernel/java/lang/reflect/AccessibleObjectTest.java new file mode 100644 index 0000000..d7dd30b --- /dev/null +++ vm/tests/kernel/java/lang/reflect/AccessibleObjectTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang.reflect; + +import junit.framework.TestCase; + +/* + * Created on 01.28.2006 + */ + +@SuppressWarnings(value={"all"}) public class AccessibleObjectTest extends TestCase { + + /** + * + */ + public void test_isAccessible_V() { + class X { + private int fld; + + private X() { + return; + } + } + try { + Field f1 = X.class.getDeclaredField("fld"); + Constructor m1 = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.AccessibleObjectTest.class }); + assertTrue("Error1", !f1.isAccessible()); + assertTrue("Error2", !m1.isAccessible()); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_setAccessible_Acc_B() { + class X { + private int fld; + + private X() { + return; + } + } + try { + Field f1 = X.class.getDeclaredField("fld"); + Constructor m1 = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.AccessibleObjectTest.class }); + assertTrue("Error1", !f1.isAccessible() && !m1.isAccessible()); + AccessibleObject[] aa = new AccessibleObject[] { f1, m1 }; + AccessibleObject.setAccessible(aa, true); + assertTrue("Error2", f1.isAccessible() && m1.isAccessible()); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_setAccessible_B() { + class X { + private int fld; + + private X() { + return; + } + } + try { + Field f1 = X.class.getDeclaredField("fld"); + f1.setAccessible(true); + Constructor m1 = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.AccessibleObjectTest.class }); + m1.setAccessible(true); + assertTrue("Error1", f1.isAccessible()); + assertTrue("Error2", m1.isAccessible()); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/ArrayTest.java vm/tests/kernel/java/lang/reflect/ArrayTest.java new file mode 100644 index 0000000..0988d31 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ArrayTest.java @@ -0,0 +1,382 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + * This ArrayTest class ("Software") is furnished under license and may only be + * used or copied in accordance with the terms of that license. + * + */ + +package java.lang.reflect; + +import junit.framework.TestCase; + +/* + * Created on 01.28.2006 + */ + +@SuppressWarnings(value={"all"}) public class ArrayTest extends TestCase { + + /** + * + */ + public void test_get_Obj_I() { + class X { + public int fld; + + public X() { + return; + } + + public X(X a9) { + return; + } + } + try { + Object o = Array.newInstance(X.class, 777); + X inst[] = (X[]) o; + inst[776] = new X(); + inst[776].fld = 777; + assertTrue("Error1", ((X) Array.get(o, 776)).fld == 777); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getBoolean_I() { + try { + Object o = Array.newInstance(boolean.class, 777); + boolean inst[] = (boolean[]) o; + inst[776] = false; + assertTrue("Error1", + (((Boolean) Array.get(o, 776)).booleanValue()) == false); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getByte_I() { + try { + Object o = Array.newInstance(byte.class, 777); + byte inst[] = (byte[]) o; + inst[776] = (byte) 7; + assertTrue("Error1", + (((Byte) Array.get(o, 776)).byteValue()) == (byte) 7); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getChar_I() { + try { + Object o = Array.newInstance(char.class, 777); + char inst[] = (char[]) o; + inst[776] = 'Z'; + assertTrue("Error1", + (((Character) Array.get(o, 776)).charValue()) == 'Z'); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getDouble_I() { + try { + Object o = Array.newInstance(double.class, 777); + double inst[] = (double[]) o; + inst[776] = 345.543d; + assertTrue("Error1", + (((Double) Array.get(o, 776)).doubleValue()) == 345.543d); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getFloat_I() { + try { + Object o = Array.newInstance(float.class, 777); + float inst[] = (float[]) o; + inst[776] = 543.345f; + assertTrue("Error1", + (((Float) Array.get(o, 776)).floatValue()) == 543.345f); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getInt_I() { + try { + Object o = Array.newInstance(int.class, 777); + int inst[] = (int[]) o; + inst[776] = Integer.MAX_VALUE; + assertTrue( + "Error1", + (((Integer) Array.get(o, 776)).intValue()) == Integer.MAX_VALUE); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getLength_Obj() { + try { + Object o = Array.newInstance(ArrayTest.class, 777); + assertTrue("Error1", Array.getLength(o) == 777); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getLong_I() { + try { + Object o = Array.newInstance(long.class, 777); + long inst[] = (long[]) o; + inst[776] = 999999999999l; + assertTrue("Error1", + (((Long) Array.get(o, 776)).longValue()) == 999999999999l); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getShort_I() { + try { + Object o = Array.newInstance(short.class, 777); + short inst[] = (short[]) o; + inst[776] = Short.MAX_VALUE; + assertTrue( + "Error1", + (((Short) Array.get(o, 776)).shortValue()) == Short.MAX_VALUE); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_newInstance_Obj() { + class X { + public X() { + return; + } + + public X(X a9) { + return; + } + } + new X(new X()); + try { + Object o = Array.newInstance(X.class, 777); + assertTrue("Error1", o.getClass().getName().equals( + "[Ljava.lang.reflect.ArrayTest$2X;")); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_newInstance_Obj_IArr() { + class X { + public X() { + return; + } + + public X(X a9) { + return; + } + } + new X(new X()); + try { + Object o = Array.newInstance(X.class, 777); + Object o2 = Array.newInstance(o.getClass(), 255); + assertTrue("Error1" + o2.getClass().getName(), o2.getClass() + .getName().equals("[[Ljava.lang.reflect.ArrayTest$3X;")); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_set_Obj_I() { + class X { + public int fld; + + public X() { + return; + } + + public X(X a9) { + return; + } + } + try { + Object o = Array.newInstance(X.class, 777); + X x = new X(); + x.fld = 777; + Array.set(o, 776, (Object) x); + assertTrue("Error1", ((X) Array.get(o, 776)).fld == 777); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setBoolean_I() { + try { + Object o = Array.newInstance(boolean.class, 777); + Array.set(o, 776, (Object) new Boolean(false)); + assertTrue("Error1", + (((Boolean) Array.get(o, 776)).booleanValue()) == false); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setByte_I() { + try { + Object o = Array.newInstance(byte.class, 777); + Array.set(o, 776, (Object) new Byte((byte) 7)); + assertTrue("Error1", + (((Byte) Array.get(o, 776)).byteValue()) == (byte) 7); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setChar_I() { + try { + Object o = Array.newInstance(char.class, 777); + Array.set(o, 776, (Object) new Character('Z')); + assertTrue("Error1", + (((Character) Array.get(o, 776)).charValue()) == 'Z'); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setDouble_I() { + try { + Object o = Array.newInstance(double.class, 777); + Array.set(o, 776, (Object) new Double(345.543d)); + assertTrue("Error1", + (((Double) Array.get(o, 776)).doubleValue()) == 345.543d); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setFloat_I() { + try { + Object o = Array.newInstance(float.class, 777); + Array.set(o, 776, (Object) new Float(543.345f)); + assertTrue("Error1", + (((Float) Array.get(o, 776)).floatValue()) == 543.345f); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setInt_I() { + try { + Object o = Array.newInstance(int.class, 777); + Array.set(o, 776, (Object) new Integer(Integer.MAX_VALUE)); + assertTrue( + "Error1", + (((Integer) Array.get(o, 776)).intValue()) == Integer.MAX_VALUE); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setLong_I() { + try { + Object o = Array.newInstance(long.class, 777); + Array.set(o, 776, (Object) new Long(999999999999l)); + assertTrue("Error1", + (((Long) Array.get(o, 776)).longValue()) == 999999999999l); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setShort_I() { + try { + Object o = Array.newInstance(short.class, 777); + Array.set(o, 776, (Object) new Short(Short.MAX_VALUE)); + assertTrue( + "Error1", + (((Short) Array.get(o, 776)).shortValue()) == Short.MAX_VALUE); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/ConstructorTest.java vm/tests/kernel/java/lang/reflect/ConstructorTest.java new file mode 100644 index 0000000..41dcbe6 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ConstructorTest.java @@ -0,0 +1,286 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + * This MethodTest class ("Software") is furnished under license and may only be + * used or copied in accordance with the terms of that license. + * + */ + +package java.lang.reflect; + +import junit.framework.TestCase; + +/* + * Created on 01.28.2006 + */ + +@SuppressWarnings(value={"all"}) public class ConstructorTest extends TestCase { + + /** + * + */ + public void test_equals_Obj() { + class X { + public X() { + return; + } + } + class Y { + public Y() { + return; + } + } + try { + Constructor m1 = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.ConstructorTest.class }); + Constructor m2 = Y.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.ConstructorTest.class }); + assertTrue( + "Error1: lack of coincidence of the equal constructors is detected", + m1.equals(m1)); + assertTrue( + "Error2: coincidence of the unequal constructors is detected", + !m1.equals(m2)); + } catch (NoSuchMethodException e) { + fail("Error3: unfound constructor" + e.toString()); + } + } + + /** + * + */ + public void test_getDeclaringClass_V() { + class X { + public X() { + return; + } + } + new X(); + try { + Constructor m = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.ConstructorTest.class }); + assertTrue("Error1", m.getDeclaringClass().getName().equals( + "java.lang.reflect.ConstructorTest$2X")); + } catch (NoSuchMethodException _) { + fail("Error2"); + } + } + + /** + * + */ + public void test_getExceptionTypes_V() { + class X { + class Y extends Throwable { + private static final long serialVersionUID = 0L; + }; + + public X() throws Throwable, Y { + return; + } + + public X(Y a1) { + return; + } + } + try { + Constructor m = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.ConstructorTest.class }); + assertTrue("Error1", (m.getExceptionTypes()[0].getName().equals( + "java.lang.reflect.ConstructorTest$3X$Y") || m + .getExceptionTypes()[0].getName().equals( + "java.lang.Throwable")) + && (m.getExceptionTypes()[1].getName().equals( + "java.lang.reflect.ConstructorTest$3X$Y") || m + .getExceptionTypes()[1].getName().equals( + "java.lang.Throwable"))); + } catch (Exception e) { + fail("Error2" + e.toString()); + } + try { + Constructor m = X.class.getDeclaredConstructor(new Class[] { + java.lang.reflect.ConstructorTest.class, X.Y.class }); + assertTrue("Error3", m.getExceptionTypes().length == 0); + } catch (Exception e) { + fail("Error4" + e.toString()); + } + } + + /** + * + */ + public void test_getModifiers_V() { + class X { + public X() { + return; + } + } + new X(); + try { + Constructor m = X.class + .getDeclaredConstructor(new Class[] { java.lang.reflect.ConstructorTest.class }); + assertTrue("Error1", java.lang.reflect.Modifier.isPublic(m + .getModifiers())); + } catch (Exception e) { + fail("Error2" + e.toString()); + } + } + + /** + * + */ + public void test_getName_V() { + class X { + public X() { + return; + } + + public X(X a1) { + return; + } + } + new X(); + Constructor af[] = X.class.getDeclaredConstructors(); + assertEquals("num of ctors", 2, af.length); + for (int i = 0; i < af.length; i++) { + assertEquals("name", "java.lang.reflect.ConstructorTest$5X", af[i].getName()); + } + } + + /** + * + */ + public void test_getParameterTypes_V() { + class X { + public X(boolean a1, byte a2, char a3, double a4, float a5, int a6, + long a7, short a8, X a9, ConstructorTest a10) { + return; + } + } + try { + Class ac[] = X.class.getDeclaredConstructor( + new Class[] { java.lang.reflect.ConstructorTest.class, + boolean.class, byte.class, char.class, + double.class, float.class, int.class, long.class, + short.class, X.class, ConstructorTest.class }) + .getParameterTypes(); + int res = 0; + for (int i = 0; i < ac.length; i++) { + if (ac[i].getName().equals("boolean")) + res += 1; + if (ac[i].getName().equals("byte")) + res += 10; + if (ac[i].getName().equals("char")) + res += 100; + if (ac[i].getName().equals("double")) + res += 1000; + if (ac[i].getName().equals("float")) + res += 10000; + if (ac[i].getName().equals("int")) + res += 100000; + if (ac[i].getName().equals("long")) + res += 1000000; + if (ac[i].getName().equals("short")) + res += 10000000; + if (ac[i].getName().equals( + "java.lang.reflect.ConstructorTest$6X")) + res += 100000000; + if (ac[i].getName().equals("java.lang.reflect.ConstructorTest")) + res += 1000000000; + } + assertTrue("Error1", res == 2111111111); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_hashCode_V() { + class X { + public X(X a9) { + return; + } + } + try { + Constructor m = X.class.getDeclaredConstructor(new Class[] { + java.lang.reflect.ConstructorTest.class, X.class }); + assertTrue("Error1", m.hashCode() == m.getDeclaringClass() + .getName().hashCode()); + } catch (NoSuchMethodException _) { + fail("Error2"); + } + } + + /** + * + */ +//Commented because of the drlvm issue +/* + public void test_newInstance_Obj() { + class X { + public X() { + return; + } + + public X(X a9) { + return; + } + } + X x = new X(new X()); + try { + Constructor m = X.class.getDeclaredConstructor(new Class[] { + java.lang.reflect.ConstructorTest.class, X.class }); + Object o = m.newInstance(new Object[] { + new java.lang.reflect.ConstructorTest(), new X() }); + assertTrue("Error1", o instanceof X); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } +*/ + /** + * + */ + public void test_toString_Obj() { + class X { + public X() { + return; + } + + public X(X a9) { + return; + } + } + try { + Constructor m = X.class.getDeclaredConstructor(new Class[] { + java.lang.reflect.ConstructorTest.class, X.class }); + assertTrue( + "Error1 " + m.toString(), + m + .toString() + .equals( + "public java.lang.reflect.ConstructorTest$8X(java.lang.reflect.ConstructorTest,java.lang.reflect.ConstructorTest$8X)")); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/ConstructorTestNewInstace.java vm/tests/kernel/java/lang/reflect/ConstructorTestNewInstace.java new file mode 100644 index 0000000..e72aea1 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ConstructorTestNewInstace.java @@ -0,0 +1,130 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import junit.framework.TestCase; + +/** + * tested class: java.lang.Constructor + * tested method: newInstance + * + */ +public class ConstructorTestNewInstace extends TestCase { + + /** + * Attempt to create a class with a protected constructor + * from another package. + * This situation must produce IllegalAccessException. + */ + public void test1() { + try { + Constructor c = java.lang.ProtectedConstructor.class + .getDeclaredConstructor((Class[]) null); + c.newInstance((Object[]) null); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage(), e instanceof IllegalAccessException); + } + } + + /** + * Attempt to create a class with a protected constructor + * from another package. + * Now we've changed the constructor accessiblity before creating. + * This situation must not produce any exception. + */ + public void test2() { + try { + Constructor c = java.lang.ProtectedConstructor.class + .getDeclaredConstructor((Class[]) null); + c.setAccessible(true); + c.newInstance((Object[]) null); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + /** + * Attempt to create a class with a protected constructor + * in the same package. + * This situation must not produce any exception. + */ + public void test3() { + try { + Constructor c = java.lang.reflect.ProtectedConstructor.class + .getDeclaredConstructor((Class[]) null); + c.newInstance((Object[]) null); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + /** + * Attempt to create an inner class which is package accessible. + * This situation must produce IllegalAccessException. + */ + public void test4() { + try { + Object o = java.lang.PackageAccessible + .getProtectedClassInstance(); + Constructor c = o.getClass().getDeclaredConstructor((Class[]) null); + c.newInstance((Object[]) null); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage(), e instanceof IllegalAccessException); + } + } + + /** + * Attempt to create an inner class which is package accessible. + * Now we've changed the class accessiblity. + * This situation must not produce any exception. + */ + public void test5() { + try { + Object o = java.lang.PackageAccessible + .getProtectedClassInstance(); + Constructor c = o.getClass().getDeclaredConstructor((Class[]) null); + c.setAccessible(true); + c.newInstance((Object[]) null); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + public void test6() { + try { + A.class.getDeclaredConstructor((Class[]) null).newInstance( + (Object[]) null); + } catch (InvocationTargetException e) { + return; + } catch (Exception e) { + } + fail("The InvocationTargetException exception expected"); + } + + static class A { + + public A() { + throw new NullPointerException(); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/Ctor5Test.java vm/tests/kernel/java/lang/reflect/Ctor5Test.java new file mode 100644 index 0000000..29c4ee3 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/Ctor5Test.java @@ -0,0 +1,187 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang.reflect; + + +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingTypeAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class Ctor5Test extends Method5Test { + + public static void main(String[] args) { + junit.textui.TestRunner.run(Ctor5Test.class); + } + + protected @Override AnnotatedElement getElement1() throws Throwable { + return AnnotatedCtor.class.getConstructor(); + } + + protected @Override AnnotatedElement getElement2() throws Throwable { + return AnnotatedCtor.class.getConstructor(Object.class); + } + + protected @Override AnnotatedElement getElement3() throws Throwable { + return AnnotatedCtor.class.getConstructor(String.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the notfound.MissingAntn. + */ + protected @Override AnnotatedElement getElement4() throws Throwable { + return AnnotatedCtor.class.getConstructor(int.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingClassValAntn. + */ + protected @Override AnnotatedElement getElement5() throws Throwable { + return AnnotatedCtor.class.getConstructor(long.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingTypeAntn. + */ + protected @Override AnnotatedElement getElement6() throws Throwable { + return AnnotatedCtor.class.getConstructor(char.class); + } + + + @Override + protected Member getParamElement1() throws Throwable { + return AnnotatedParamCtor.class.getConstructor(); + } + + @Override + protected Member getParamElement2() throws Throwable { + return AnnotatedParamCtor.class.getConstructor( + Object.class, Class.class, boolean.class); + } + + @Override + protected Member getParamElement3() throws Throwable { + return AnnotatedParamCtor.class.getConstructor( + String.class, int.class); + } + + static class A { + private Object obj; + class InA { + Object o = obj; + } + } + + enum E { E1, E2, E3} + + static class B { + public B() {} + public B(Object o) {} + public B(Object o1, int... i) {} + public B(Object[] o) {} + } + + /** + * isSynthetic() should return true if and only if + * the target c-tor does not appear in the source code. + */ + public void testIsSynthetic() throws Exception { + assertFalse("case1.1: ordinary ctor", + AnnotatedCtor.class.getConstructor().isSynthetic()); + assertFalse("case1.2: implicit default c-tor", + A.class.getDeclaredConstructor().isSynthetic()); + + Constructor[] cs = B.class.getConstructors(); + for (Constructor<?> c : cs){ + assertFalse("case2: " + c, c.isSynthetic()); + } + // XXX how to force synthetic c-tor ? + } + + /** + * isVarArgs() should return true if and only if + * the target method is declared with varargs. + */ + public void testIsVarargs() throws Exception { + assertFalse("case1: ordinary c-tor", + AnnotatedCtor.class.getConstructor().isVarArgs()); + + assertTrue("case2: varargs c-tor", + B.class.getConstructor(Object.class, int[].class).isVarArgs()); + + assertFalse("case3: ordinary c-tor", + B.class.getConstructor(Object[].class).isVarArgs()); + } + + static abstract strictfp class C { + protected <T extends Throwable & Comparable<Throwable>> C(T num, OneParamType<? super T> l) throws T, Error {} + } + + /** + * toGenericString() should return a string exactly matching + * the API specification. + */ + public void testToGenericString() throws Exception { + String s = C.class.getDeclaredConstructor(Throwable.class, + OneParamType.class).toGenericString(); + System.out.println(s); + assertEquals( + // Should constructor type parameter be followed by a type bound? It is unspecified. + // The known reference implementation doesn't do it as well: + //"protected <T extends java.lang.Throwable & " + //+ "java.lang.Comparable<java.lang.Throwable>>" + "protected strictfp <T>" + + " java.lang.reflect.Ctor5Test$C(T,java.lang.reflect.OneParamType<? super T>)" + + " throws T,java.lang.Error", + s); + } + + /** + * toGenericString() should return a string exactly matching + * the API specification. + */ + public void testToGenericString2() throws Exception { + String s = B.class.getConstructor(Object.class, int[].class).toGenericString(); + System.out.println(s); + assertEquals("public java.lang.reflect.Ctor5Test$B(" + + "java.lang.Object,int[])", s); + } + +} + +class AnnotatedCtor { + @TagAntn public AnnotatedCtor(){} + @TagAntn @ValAntn public AnnotatedCtor(Object param){} + public AnnotatedCtor(@P1Antn String s){} + @notfound.MissingAntn public AnnotatedCtor(int i) {} + @MissingClassValAntn public AnnotatedCtor(long l){} + @MissingTypeAntn public AnnotatedCtor(char ch){} +} + +class AnnotatedParamCtor { + @TagAntn public AnnotatedParamCtor(){} + @ValAntn("abc") public AnnotatedParamCtor(@P1Antn Object p1, + @P2Antn(123) Class p2, @P3Antn @ValAntn("xyz") boolean p3){} + public AnnotatedParamCtor(String s, @TagAntn int i){} +} diff --git vm/tests/kernel/java/lang/reflect/Field5Test.java vm/tests/kernel/java/lang/reflect/Field5Test.java new file mode 100644 index 0000000..e5e2ad7 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/Field5Test.java @@ -0,0 +1,160 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.reflect; + +import org.apache.harmony.lang.AnnotatedElementTestFrame; +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingTypeAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn; + +class AnnotatedField { + @TagAntn public Object foo; + @TagAntn @ValAntn public Object[] bar; + public static transient volatile TwoParamType<String, ?> buz; + @notfound.MissingAntn public int i; + @MissingClassValAntn public long l; + @MissingTypeAntn public char ch; +} + +class TwoParamType<K, V> {} +class OneParamType<U> {} + +public class Field5Test extends AnnotatedElementTestFrame { + + protected @Override AnnotatedElement getElement1() throws Throwable { + return AnnotatedField.class.getField("foo"); + } + + protected @Override AnnotatedElement getElement2() throws Throwable { + return AnnotatedField.class.getField("bar"); + } + + protected @Override AnnotatedElement getElement3() throws Throwable { + return AnnotatedField.class.getField("buz"); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the notfound.MissingAntn. + */ + protected @Override AnnotatedElement getElement4() throws Throwable { + return AnnotatedField.class.getField("i"); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingClassValAntn. + */ + protected @Override AnnotatedElement getElement5() throws Throwable { + return AnnotatedField.class.getField("l"); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingTypeAntn. + */ + protected @Override AnnotatedElement getElement6() throws Throwable { + return AnnotatedField.class.getField("ch"); + } + + + public static void main(String[] args) { + junit.textui.TestRunner.run(Field5Test.class); + } + + class A { + { + assert true; + } + } + enum E { E1, E2, E3} + static class B { + public E foo; + } + + /** + * isSynthetic() should return true if and only if + * the target field does not appear in the source code. + */ + public void testIsSynthetic() throws Exception { + assertFalse("case1.1: ordinary field", + AnnotatedField.class.getField("foo").isSynthetic()); + assertFalse("case1.2: ordinary field", + B.class.getField("foo").isSynthetic()); + + Field[] fs = A.class.getDeclaredFields(); + assertTrue(fs != null && fs.length > 0); + for (Field f : fs){ + assertTrue("case2: " + f.getName(), f.isSynthetic()); + } + + fs = E.class.getFields(); + assertTrue(fs != null && fs.length > 0); + for (Field f : fs){ + assertFalse("case3: " + f.getName(), f.isSynthetic()); + } + } + + /** + * isEnumConstant() should return true if and only if + * the target field is an element of an enumeration. + */ + public void testIsEnumConstant() throws Exception { + assertFalse("case1: ordinary field", + AnnotatedField.class.getField("foo").isEnumConstant()); + + Field[] fs = E.class.getFields(); + assertTrue(fs != null && fs.length > 0); + for (Field f : fs){ + assertTrue("case2: " + f.getName(), f.isEnumConstant()); + } + + assertFalse("case3: enum-typed member field", + B.class.getField("foo").isEnumConstant()); + } + + enum E2 { + E1; + public int i; + } + /** + * isEnumConstant() should not return true + * for ordinary members (not elements) of an enumeration. + */ + public void testIsEnumConstant2() throws Exception { + assertFalse(E2.class.getField("i").isEnumConstant()); + } + + /** + * toGenericString() should return a string exactly matching + * the API specification. + */ + public void testToGenericString() throws Exception { + String s = AnnotatedField.class.getField("buz").toGenericString(); + System.out.println(s); + assertEquals( + "public static transient volatile" + + " java.lang.reflect.TwoParamType<java.lang.String, ?>" + + " java.lang.reflect.AnnotatedField.buz", + s); + } +} diff --git vm/tests/kernel/java/lang/reflect/FieldTest.java vm/tests/kernel/java/lang/reflect/FieldTest.java new file mode 100644 index 0000000..7c76b0a --- /dev/null +++ vm/tests/kernel/java/lang/reflect/FieldTest.java @@ -0,0 +1,624 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + */ + +package java.lang.reflect; + +import junit.framework.TestCase; + +/* + * Created on 01.28.2006 + */ + +@SuppressWarnings(value={"all"}) public class FieldTest extends TestCase { + static public boolean sfld1 = true; + + public boolean ifld1 = false; + + static public byte sfld2 = (byte) 7; + + public byte ifld2 = (byte) 5; + + static public char sfld3 = 'G'; + + public char ifld3 = 'l'; + + static public double sfld4 = 777.d; + + public double ifld4 = 55.5d; + + static public float sfld5 = 7.77f; + + public float ifld5 = .555f; + + static public int sfld6 = 777; + + public int ifld6 = 555; + + static public long sfld7 = 777l; + + public long ifld7 = 555l; + + static public short sfld8 = Short.MAX_VALUE; + + public short ifld8 = Short.MIN_VALUE; + + /** + * + */ + public void test_equals_Obj() { + class X { + public int Xfld = 777; + } + class Y { + public int Xfld = 777; + } + try { + Field f1 = X.class.getField("Xfld"); + Field f2 = Y.class.getField("Xfld"); + assertEquals("Error: equal fields should coincide", f1, f1); + assertTrue("Error: coincidence of the unequal fields is detected", + !f1.equals(f2)); + } catch (NoSuchFieldException _) { + fail("Error: unfound field"); + } + } + + /** + * + */ +//Commented because of the drlvm issue +/* + public void test_get_Obj() { + class X { + public int Xfld = 777; + } + X x = new X(); + x.Xfld = 333; + try { + Field f1 = X.class.getField("Xfld"); + assertTrue("Error1: x.Xfld should be equal 333", ((Integer) (f1 + .get(x))).intValue() == 333); + } catch (Exception e) { + //e.printStackTrace(); + fail("Error2: " + e.toString()); + } + try { + Field f1 = X.class.getField("Xfld"); + f1.get(null); + fail("Error3: NullPointerException should be risen just above"); + } catch (NullPointerException _) { + // The specified object is null and the field is an instance field + } catch (Exception e) { + fail("Error4: " + e.toString()); + } + } +*/ + /** + * + */ + public void test_getBoolean_Obj() { + try { + sfld1 = true; + Field f1 = FieldTest.class.getField("sfld1"); + assertTrue("Error1", + ((Boolean) (f1.get(null))).booleanValue() == true); + Field f2 = FieldTest.class.getField("ifld1"); + FieldTest ft = new FieldTest(); + ft.ifld1 = true; + assertTrue("Error2", ((Boolean) (f2.get(ft))).booleanValue()); + assertTrue("Error3", f2.getBoolean(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getByte_Obj() { + try { + sfld2 = (byte) 7; + Field f1 = FieldTest.class.getField("sfld2"); + assertEquals("Error1", 7, ((Byte) (f1.get(null))).byteValue()); + Field f2 = FieldTest.class.getField("ifld2"); + FieldTest ft = new FieldTest(); + ft.ifld2 = 6; + assertEquals("Error2", 6, ((Byte) (f2.get(ft))).byteValue()); + assertEquals("Error2", 6, f2.getByte(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getChar_Obj() { + try { + sfld3 = 'G'; + Field f1 = FieldTest.class.getField("sfld3"); + assertEquals("Error1", + 'G', ((Character) (f1.get(null))).charValue()); + Field f2 = FieldTest.class.getField("ifld3"); + FieldTest ft = new FieldTest(); + ft.ifld3 = 'm'; + assertEquals("Error2", 'm', ((Character) (f2.get(ft))).charValue()); + assertEquals("Error2", 'm', f2.getChar(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getDeclaringClass_V() { + class X { + public int Xfld = 777; + } + X x = new X(); + x.Xfld = 333; + try { + Field f1 = X.class.getField("Xfld"); + assertEquals("Error1", "java.lang.reflect.FieldTest$2X", + f1.getDeclaringClass().getName()); + } catch (NoSuchFieldException _) { + fail("Error2"); + } + } + + /** + * + */ + public void test_getDouble_Obj() { + try { + sfld4 = 777.d; + Field f1 = FieldTest.class.getField("sfld4"); + assertEquals("Error1", 777.d, + ((Double) (f1.get(null))).doubleValue()); + Field f2 = FieldTest.class.getField("ifld4"); + FieldTest ft = new FieldTest(); + ft.ifld4 = 11.1d; + assertEquals("Error2", + 11.1d, ((Double) (f2.get(ft))).doubleValue()); + assertEquals("Error2", + 11.1d, f2.getDouble(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getFloat_Obj() { + try { + sfld5 = 7.77f; + Field f1 = FieldTest.class.getField("sfld5"); + assertEquals("Error1", + 7.77f, ((Float) (f1.get(null))).floatValue()); + Field f2 = FieldTest.class.getField("ifld5"); + FieldTest ft = new FieldTest(); + ft.ifld5 = .9999f; + assertEquals("Error2", .9999f, ((Float) (f2.get(ft))).floatValue()); + assertEquals("Error2", .9999f, f2.getFloat(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getInt_Obj() { + try { + sfld6 = 777; + Field f1 = FieldTest.class.getField("sfld6"); + assertEquals("Error1", 777, ((Integer) (f1.get(null))).intValue()); + Field f2 = FieldTest.class.getField("ifld6"); + FieldTest ft = new FieldTest(); + ft.ifld6 = 222; + assertEquals("Error2", 222, ((Integer) (f2.get(ft))).intValue()); + assertEquals("Error2", 222, f2.getInt(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getLong_Obj() { + try { + sfld7 = 777l; + Field f1 = FieldTest.class.getField("sfld7"); + assertEquals("Error1", 777l, ((Long) (f1.get(null))).longValue()); + Field f2 = FieldTest.class.getField("ifld7"); + FieldTest ft = new FieldTest(); + ft.ifld7 = 4444l; + assertEquals("Error2", 4444l, ((Long) (f2.get(ft))).longValue()); + assertEquals("Error2", 4444l, f2.getLong(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getModifiers_V() { + class X { + public int Xfld; + + final int Yfld = 777; + } + new X(); + try { + Field f1 = X.class.getField("Xfld"); + assertTrue("Error1", java.lang.reflect.Modifier.isPublic(f1 + .getModifiers())); + Field af[] = X.class.getDeclaredFields(); + for (int i = 0; i < af.length; i++) { + if (af[i].getName().equals("Yfld")) + assertTrue("Error2", java.lang.reflect.Modifier + .isFinal(af[i].getModifiers())); + } + } catch (NoSuchFieldException _) { + fail("Error3"); + } + } + + /** + * + */ + public void test_getName_V() { + class X { + public int Xfld; + + final int Yfld = 777; + } + new X(); + try { + Field f1 = X.class.getField("Xfld"); + assertEquals("Error1", "Xfld", f1.getName()); + Field af[] = X.class.getDeclaredFields(); + int res = 0; + for (int i = 0; i < af.length; i++) { + if (af[i].getName().equals("Yfld") + || af[i].getName().equals("Xfld")) + res++; + } + assertEquals("Error2", 2, res); + } catch (NoSuchFieldException _) { + fail("Error3"); + } + } + + /** + * + */ + public void test_getShort_Obj() { + try { + sfld8 = Short.MAX_VALUE; + Field f1 = FieldTest.class.getField("sfld8"); + assertEquals("Error1", + Short.MAX_VALUE, ((Short) (f1.get(null))).shortValue()); + Field f2 = FieldTest.class.getField("ifld8"); + FieldTest ft = new FieldTest(); + ft.ifld8 = Short.MIN_VALUE; + assertEquals("Error2", + Short.MIN_VALUE, ((Short) (f2.get(ft))).shortValue()); + assertEquals("Error2", + Short.MIN_VALUE, f2.getShort(ft)); + } catch (Exception e) { + fail("Error3: " + e.toString()); + } + } + + /** + * + */ + public void test_getType_V() { + Field af[] = FieldTest.class.getDeclaredFields(); + int res = 0; + for (int i = 0; i < af.length; i++) { + if (af[i].getType().getName().equals("boolean")) + res += 1; + if (af[i].getType().getName().equals("byte")) + res += 10; + if (af[i].getType().getName().equals("char")) + res += 100; + if (af[i].getType().getName().equals("double")) + res += 1000; + if (af[i].getType().getName().equals("float")) + res += 10000; + if (af[i].getType().getName().equals("int")) + res += 100000; + if (af[i].getType().getName().equals("long")) + res += 1000000; + if (af[i].getType().getName().equals("short")) + res += 10000000; + } + assertEquals("Error1", 22222222, res); + } + + /** + * + */ + public void test_hashCode_V() { + try { + Field f1 = FieldTest.class.getField("sfld8"); + assertEquals("Error1", + f1.getDeclaringClass().getName().hashCode() ^ + f1.getName().hashCode(), + f1.hashCode()); + } catch (NoSuchFieldException _) { + fail("Error2"); + } + } + + /** + * + */ +//Commented because of the drlvm issue +/* + public void test_set_Obj_Obj() { + class X { + X xx; + + int Yfld = 777; + + public int m() { + return Yfld; + }; + } + X x = new X(); + try { + Field f1 = X.class.getDeclaredField("Yfld"); + f1.set(x, new Integer(345)); + assertTrue("Error1", x.m() == 345); + + f1 = X.class.getDeclaredField("xx"); + f1.set(x, x); + assertTrue("Error2", x.xx.Yfld == 345); + assertTrue("Error3", x.xx.m() == 345); + assertTrue("Error4", x.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.equals(x)); + Field f2 = x.xx.xx.xx.xx.xx.xx.xx.xx.getClass().getDeclaredField( + "Yfld"); + assertTrue("Error5", x.Yfld == ((Integer) f2 + .get(x.xx.xx.xx.xx.xx.xx.xx.xx.xx)).intValue()); + } catch (Exception e) { + //e.printStackTrace(); + fail("Error6: " + e.toString()); + } + } +*/ + /** + * + */ + static class XX { + static int Yfld = 777; + } + public void test_set_Obj_Obj_2() { + XX x = new XX(); + try { + Field f1 = XX.class.getDeclaredField("Yfld"); + f1.set(x, new Integer(345)); + assertTrue("Error1", x.Yfld == 345); + } catch (Exception e) { + e.printStackTrace(); + fail("Error2: " + e.toString()); + } + } + public void test_set_Null_Negative() throws Throwable { + try { + Field f1 = XX.class.getDeclaredField("Yfld"); + f1.set(null, null); + fail("null value should not be unboxed to primitive"); + } catch (IllegalArgumentException ok) {} + } + + /** + * + */ + public void test_setBoolean_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld1"); + f1.setBoolean((Object) null, false); + assertFalse("Error1", ((Boolean) (f1.get(null))).booleanValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setByte_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld2"); + f1.setByte((Object) null, (byte) 8); + assertEquals("Error1", + (byte) 8, ((Byte) (f1.get(null))).byteValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setChar_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld3"); + f1.setChar((Object) null, 'Z'); + assertEquals("Error1", + 'Z', ((Character) (f1.get(null))).charValue()); + FieldTest.class.getField("ifld3"); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setDouble_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld4"); + f1.setDouble((Object) null, 12.3d); + assertEquals("Error1", + 12.3d, ((Double) (f1.get(null))).doubleValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setFloat_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld5"); + f1.setFloat((Object) null, 0.0057f); + assertEquals("Error1", + 0.0057f, ((Float) (f1.get(null))).floatValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setInt_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld6"); + f1.setInt((Object) null, 222333444); + assertEquals("Error1", + 222333444, ((Integer) (f1.get(null))).intValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setLong_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld7"); + f1.setLong((Object) null, 99999999999l); + assertEquals("Error1", + 99999999999l, ((Long) (f1.get(null))).longValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_setShort_Obj() { + try { + Field f1 = FieldTest.class.getField("sfld8"); + f1.setShort((Object) null, + (short) (Short.MAX_VALUE + Short.MIN_VALUE)); + assertEquals("Error1", + (short) (Short.MAX_VALUE + Short.MIN_VALUE), + ((Short) (f1.get(null))).shortValue()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_toString_Obj() { + class X { + int Yfld = 777; + } + new X(); + try { + Field f1 = X.class.getDeclaredField("Yfld"); + assertEquals("Error1 ", + "int java.lang.reflect.FieldTest$5X.Yfld", f1.toString()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + static class RefFld { + public Object o; + public static Object so; + public Integer i; + public static Integer si; + } + + public void testSet_Obj() throws Throwable { + Field f = RefFld.class.getField("o"); + RefFld obj = new RefFld(); + Object val = "dmjb"; + f.set(obj, val); + assertSame(val, f.get(obj)); + f.set(obj, null); + assertNull(f.get(obj)); + } + + public void testSet_Obj_Static() throws Throwable { + Field f = RefFld.class.getField("so"); + RefFld obj = new RefFld(); + Object val = "dmjb"; + f.set(obj, val); + assertSame(val, f.get(null)); + f.set(null, null); + assertNull(f.get(obj)); + } + + public void testSet_BoxObj() throws Throwable { + Field f = RefFld.class.getField("i"); + RefFld obj = new RefFld(); + Object val = new Integer(35434); + f.set(obj, val); + assertSame(val, f.get(obj)); + f.set(obj, null); + assertNull(f.get(obj)); + } + + public void testSet_BoxObj_Static() throws Throwable { + Field f = RefFld.class.getField("si"); + RefFld obj = new RefFld(); + Object val = new Integer(589878); + f.set(obj, val); + assertSame(val, f.get(null)); + f.set(null, null); + assertNull(f.get(obj)); + } + + public void testSet_Obj_Invalid() throws Throwable { + try { + Field f = RefFld.class.getField("si"); + f.set(null, "345"); + fail("IllegalArgumentException was not thrown on incompartible value"); + } catch (IllegalArgumentException ok) {} + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/FieldTestSet.java vm/tests/kernel/java/lang/reflect/FieldTestSet.java new file mode 100644 index 0000000..ec29594 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/FieldTestSet.java @@ -0,0 +1,56 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +public class FieldTestSet extends TestCase { + + private boolean bool = false; + + private Integer integer = null; + + public void test1() { + try { + final boolean value = true; + Field field = getClass().getDeclaredField("bool"); + field.set(this, new Boolean(value)); + assertEquals(value, bool); + } catch (Exception e) { + fail(e.toString()); + } + } + + public void testBug533() { + try { + final int value = 2005; + Field field = getClass().getDeclaredField("integer"); + field.setAccessible(true); + Integer integerObject = new Integer(value); + field.set(this, integerObject); + assertEquals(value, integer.intValue()); + } catch (Exception e) { + fail(e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/FieldTestSetInt.java vm/tests/kernel/java/lang/reflect/FieldTestSetInt.java new file mode 100644 index 0000000..8ffe40c --- /dev/null +++ vm/tests/kernel/java/lang/reflect/FieldTestSetInt.java @@ -0,0 +1,43 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +public class FieldTestSetInt extends TestCase { + + private Integer integer = null; + + public void test1() { + try { + final int value = 2005; + Field field = getClass().getDeclaredField("integer"); + field.setInt(this, value); + assertEquals(value, integer.intValue()); + } catch (IllegalArgumentException e) { + return; + } catch (Exception e) { + } + fail("The IllegalArgumentException exception expected"); + } +} diff --git vm/tests/kernel/java/lang/reflect/Method5Test.java vm/tests/kernel/java/lang/reflect/Method5Test.java new file mode 100644 index 0000000..e0d8381 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/Method5Test.java @@ -0,0 +1,341 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package java.lang.reflect; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.apache.harmony.lang.AnnotatedElementTestFrame; +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingTypeAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn; +import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class Method5Test extends AnnotatedElementTestFrame { + + protected @Override AnnotatedElement getElement1() throws Throwable { + return AnnotatedMethod.class.getMethod("foo"); + } + + protected @Override AnnotatedElement getElement2() throws Throwable { + return AnnotatedMethod.class.getMethod("bar"); + } + + protected @Override AnnotatedElement getElement3() throws Throwable { + return AnnotatedMethod.class.getMethod("buz", String.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the notfound.MissingAntn. + */ + protected @Override AnnotatedElement getElement4() throws Throwable { + return AnnotatedMethod.class.getMethod("i", int.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingClassValAntn. + */ + protected @Override AnnotatedElement getElement5() throws Throwable { + return AnnotatedMethod.class.getMethod("l", long.class); + } + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingTypeAntn. + */ + protected @Override AnnotatedElement getElement6() throws Throwable { + return AnnotatedMethod.class.getMethod("ch", char.class); + } + + + public static void main(String[] args) { + junit.textui.TestRunner.run(Method5Test.class); + } + + protected final Annotation[][] getParamAnnotations(Member obj) throws Throwable { + assertTrue("illegal argument: " + obj, + (obj instanceof Method) || (obj instanceof Constructor)); + Method m = obj.getClass().getMethod("getParameterAnnotations"); + return (Annotation[][])m.invoke(obj); + } + + protected Member getParamElement1() throws Throwable { + return AnnotatedParamMethod.class.getMethod("foo"); + } + + protected Member getParamElement2() throws Throwable { + return AnnotatedParamMethod.class.getMethod("bar", + Object.class, Class.class, boolean.class); + } + + protected Member getParamElement3() throws Throwable { + return AnnotatedParamMethod.class.getMethod("buz", + String.class, int.class); + } + + /** + * getParameterAnnotations() should return empty array + * if member has no parameters. + */ + public void testGetParameterAnnotations1() throws Throwable { + Annotation[][] an = getParamAnnotations(getParamElement1()); + assertNotNull(an); + assertEquals(0, an.length); + } + + /** + * getParameterAnnotations() should return array of annotation + * arrays for member parameters, in declaration order. + */ + public void testGetParameterAnnotations2() throws Throwable { + Annotation[][] an = getParamAnnotations(getParamElement2()); + assertNotNull(an); + assertEquals("param num", 3, an.length); + + assertEquals("1st param annotation num", 1, an[0].length); + assertSame("1st param annotation type", P1Antn.class, + an[0][0].annotationType()); + + assertEquals("2nd param annotation num", 1, an[1].length); + assertSame("2nd param annotation type", P2Antn.class, + an[1][0].annotationType()); + assertEquals("2nd param annotation value", 123, ((P2Antn)an[1][0]).value()); + + assertEquals("3rd param annotation num", 2, an[2].length); + assertSame("3rd param annotation 1 type", P3Antn.class, + an[2][0].annotationType()); + assertSame("3rd param annotation 2 type", ValAntn.class, + an[2][1].annotationType()); + assertEquals("3rd param annotation 2 value", "xyz", ((ValAntn)an[2][1]).value()); + } + + /** + * For each parameter having no annotations, + * getParameterAnnotations() should return corresponding + * nested arrays with zero size. + */ + public void testGetParameterAnnotations3() throws Throwable { + Annotation[][] an = getParamAnnotations(getParamElement3()); + assertNotNull(an); + assertEquals("param num", 2, an.length); + + assertEquals("1st param annotation num", 0, an[0].length); + + assertEquals("2nd param annotation num", 1, an[1].length); + assertSame("2nd param annotation type", TagAntn.class, + an[1][0].annotationType()); + } + + /** + * getParameterAnnotations() should return cloned arrays + * which can be safely modified by a caller. + */ + public void testGetParameterAnnotationsImmutable() throws Throwable { + Member m = getParamElement2(); + Annotation[][] an0 = getParamAnnotations(m); + assertNotNull(an0); + assertEquals("param num", 3, an0.length); + an0[1] = an0[2]; + an0[1][1] = null; + an0[2] = new Annotation[0]; + + Annotation[][] an = getParamAnnotations(m); + + assertEquals("1st param annotation num", 1, an[0].length); + assertSame("1st param annotation type", P1Antn.class, + an[0][0].annotationType()); + + assertEquals("2nd param annotation num", 1, an[1].length); + assertSame("2nd param annotation type", P2Antn.class, + an[1][0].annotationType()); + assertEquals("2nd param annotation value", 123, ((P2Antn)an[1][0]).value()); + + assertEquals("3rd param annotation num", 2, an[2].length); + assertSame("3rd param annotation 1 type", P3Antn.class, + an[2][0].annotationType()); + assertSame("3rd param annotation 2 type", ValAntn.class, + an[2][1].annotationType()); + assertEquals("3rd param annotation 2 value", "xyz", ((ValAntn)an[2][1]).value()); + } + + static class A { + private Object obj; + class InA { + Object o = obj; + } + } + + enum E { E1, E2, E3} + + static class B1 { + public Object foo() { return null;} + public Object bar(int i, Object... o) { return null;} + public static void main1(String... s){} + public static void main2(String[] s){} + } + + static class B2 extends B1 { + public String foo() { return "";} + public String bar(int i, Object... o) { return "";} + } + + /** + * isSynthetic() should return true if and only if + * the target method does not appear in the source code. + */ + public void testIsSynthetic() throws Exception { + assertFalse("case1.1: ordinary method", + AnnotatedMethod.class.getMethod("foo").isSynthetic()); + assertFalse("case1.2: ordinary vararg method", + B1.class.getMethod("main1", String[].class).isSynthetic()); + + Method[] ms = A.class.getDeclaredMethods(); + assertTrue(ms != null && ms.length > 0); + for (Method m : ms){ + assertTrue("case2: " + m, m.isSynthetic()); + } + + // XXX bug in compiler? + //assertTrue("case3: EnumType.values()", + // E.class.getMethod("values").isSynthetic()); + } + + /** + * isBridge() should return true if and only if + * the target method does not appear in the source code + * and overrides covariant return type method. + */ + public void testIsBridge() throws Exception { + assertFalse("case1.1: ordinary method", + AnnotatedMethod.class.getMethod("foo").isBridge()); + assertFalse("case1.2: ordinary vararg method", + B1.class.getMethod("main1", String[].class).isBridge()); + + Method[] ms = B1.class.getMethods(); + assertTrue(ms != null && ms.length > 0); + for (Method m : ms){ + assertFalse("case2.1: " + m, m.isBridge()); + } + + ms = B2.class.getDeclaredMethods(); + assertTrue(ms != null && ms.length > 0); + for (Method m : ms){ + //System.out.println("case2.2 " + m); + assertTrue("case2.2: " + m, + m.getReturnType() != Object.class ^ m.isBridge()); + } + + assertFalse("case3: EnumType.values()", + E.class.getMethod("values").isBridge()); + } + + /** + * isVarArgs() should return true if and only if + * the target method is declared with varargs. + */ + public void testIsVarargs() throws Exception { + assertFalse("case1: ordinary method", + AnnotatedMethod.class.getMethod("foo").isVarArgs()); + + assertTrue("case2: varargs method", + B1.class.getMethod("main1", String[].class).isVarArgs()); + + assertFalse("case3: ordinary method", + B1.class.getMethod("main2", String[].class).isVarArgs()); + } + + static abstract class C { + protected abstract <T extends Throwable> + OneParamType<? extends T> go(T t) throws T, Error; + } + + /** + * toGenericString() should return a string exactly matching + * the API specification. + */ + public void testToGenericString() throws Exception { + String s = C.class.getDeclaredMethod("go", + Throwable.class).toGenericString(); + System.out.println(s); + assertEquals( + // Should method type parameter be followed by a type bound? It is unspecified. + // The known reference implementation doesn't do it as well: + //"protected abstract <T extends java.lang.Throwable>" + "protected abstract <T>" + + " java.lang.reflect.OneParamType<? extends T>" + + " java.lang.reflect.Method5Test$C.go(T)" + + " throws T,java.lang.Error", + s); + } + + /** + * toGenericString() should return a string exactly matching + * the API specification. + */ + public void testToGenericString2() throws Exception { + String s = B2.class.getDeclaredMethod("bar", + int.class, Object[].class).toGenericString(); + // it is unspecified which method should be returned: + // original (overriden with covariant return) or + // compiler-generated bridge. + // different implementations behave differently, + // so relaxed this check to allow both variants. + assertTrue("start: " + s, s.startsWith("public java.lang.")); // String or Object + assertTrue("end: " + s, + s.endsWith(" java.lang.reflect.Method5Test$B2." + + "bar(int,java.lang.Object[])")); + } +} + +abstract class AnnotatedMethod { + @TagAntn public abstract void foo(); + @TagAntn @ValAntn public Object[] bar() {return null;} + public String buz(String s){return s;} + @notfound.MissingAntn public void i(int i) {} + @MissingClassValAntn public void l(long l){} + @MissingTypeAntn public void ch(char ch){} +} + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@interface P1Antn {} + +@Retention(RetentionPolicy.RUNTIME) +@interface P2Antn { + int value(); +} + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@interface P3Antn { + String[] meta1() default {}; + P1Antn meta2() default @P1Antn; +} + +class AnnotatedParamMethod { + @TagAntn public void foo(){} + @ValAntn("abc") public void bar(@P1Antn Object p1, + @P2Antn(123) Class p2, @P3Antn @ValAntn("xyz") boolean p3){} + public void buz(String s, @TagAntn int i){} +} diff --git vm/tests/kernel/java/lang/reflect/MethodTest.java vm/tests/kernel/java/lang/reflect/MethodTest.java new file mode 100644 index 0000000..ca59327 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/MethodTest.java @@ -0,0 +1,304 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + * + * This MethodTest class ("Software") is furnished under license and may only be + * used or copied in accordance with the terms of that license. + * + */ + +package java.lang.reflect; + +import junit.framework.TestCase; + +/* + * Created on 01.28.2006 + */ + +@SuppressWarnings(value={"all"}) public class MethodTest extends TestCase { + + /** + * + */ + public void test_equals_Obj() { + class X { + public int m() { + return 777; + } + } + class Y { + public int m() { + return 777; + } + } + try { + Method m1 = X.class.getDeclaredMethod("m", (Class[]) null); + Method m2 = Y.class.getDeclaredMethod("m", (Class[]) null); + assertEquals("Error1: equal methods should coincide", m1, m1); + assertTrue("Error2: coincidence of the unequal methods is detected", + !m1.equals(m2)); + } catch (NoSuchMethodException _) { + fail("Error3: unfound method"); + } + } + + /** + * + */ + public void test_getDeclaringClass_V() { + class X { + public int m() { + return 777; + } + } + new X(); + try { + Method m = X.class.getDeclaredMethod("m", (Class[]) null); + assertEquals("Error1", "java.lang.reflect.MethodTest$2X", + m.getDeclaringClass().getName()); + } catch (NoSuchMethodException _) { + fail("Error2"); + } + } + + /** + * + */ + public void test_getExceptionTypes_V() { + class X { + class Y extends Throwable { + private static final long serialVersionUID = 0L; + }; + + public int m() throws Throwable, Y { + return 777; + } + + public int m2() { + return 777; + } + } + new X(); + try { + Method m = X.class.getDeclaredMethod("m", (Class[]) null); + assertTrue("Error1", (m.getExceptionTypes()[0].getName().equals( + "java.lang.reflect.MethodTest$3X$Y") || m + .getExceptionTypes()[0].getName().equals( + "java.lang.Throwable")) + && (m.getExceptionTypes()[1].getName().equals( + "java.lang.reflect.MethodTest$3X$Y") || m + .getExceptionTypes()[1].getName().equals( + "java.lang.Throwable"))); + } catch (Exception e) { + fail("Error2" + e.toString()); + } + try { + Method m = X.class.getDeclaredMethod("m2", (Class[]) null); + assertEquals("Error3", 0, m.getExceptionTypes().length); + } catch (Exception e) { + fail("Error4" + e.toString()); + } + } + + /** + * + */ + public void test_getModifiers_V() { + class X { + public int m() { + return 777; + } + + final int m2() { + return 777; + } + } + new X(); + try { + Method m = X.class.getDeclaredMethod("m", (Class[]) null); + assertTrue("Error1", java.lang.reflect.Modifier.isPublic(m + .getModifiers())); + m = X.class.getDeclaredMethod("m2", (Class[]) null); + assertTrue("Error2", java.lang.reflect.Modifier.isFinal(m + .getModifiers())); + } catch (Exception e) { + fail("Error3" + e.toString()); + } + } + + /** + * + */ + public void test_getName_V() { + class X { + public int first() { + return 777; + } + + final int second() { + return 777; + } + } + new X(); + try { + Method af[] = X.class.getDeclaredMethods(); + int res = 0; + for (int i = 0; i < af.length; i++) { + if (af[i].getName().equals("first") + || af[i].getName().equals("second")) + res++; + } + assertTrue("Error1", res == 2); + } catch (Exception e) { + fail("Error2" + e.toString()); + } + } + + /** + * + */ + public void test_getParameterTypes_V() { + class X { + public int m(boolean a1, byte a2, char a3, double a4, float a5, + int a6, long a7, short a8, X a9, MethodTest a10) { + return 777; + } + } + new X(); + try { + Class ac[] = X.class.getDeclaredMethod( + "m", + new Class[] { boolean.class, byte.class, char.class, + double.class, float.class, int.class, long.class, + short.class, X.class, MethodTest.class }) + .getParameterTypes(); + int res = 0; + for (int i = 0; i < ac.length; i++) { + if (ac[i].getName().equals("boolean")) + res += 1; + if (ac[i].getName().equals("byte")) + res += 10; + if (ac[i].getName().equals("char")) + res += 100; + if (ac[i].getName().equals("double")) + res += 1000; + if (ac[i].getName().equals("float")) + res += 10000; + if (ac[i].getName().equals("int")) + res += 100000; + if (ac[i].getName().equals("long")) + res += 1000000; + if (ac[i].getName().equals("short")) + res += 10000000; + if (ac[i].getName().equals("java.lang.reflect.MethodTest$6X")) + res += 100000000; + if (ac[i].getName().equals("java.lang.reflect.MethodTest")) + res += 1000000000; + } + assertEquals("Error1", 1111111111, res); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_getReturnType_V() { + class X { + public X m(X a9) { + return a9; + } + } + new X(); + try { + assertEquals("Error1", + "java.lang.reflect.MethodTest$7X", + X.class.getDeclaredMethod("m", new Class[] { X.class }) + .getReturnType().getName()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } + + /** + * + */ + public void test_hashCode_V() { + class X { + public X first(X a9) { + return a9; + } + } + try { + Method m = X.class.getDeclaredMethod("first", + new Class[] { X.class }); + assertEquals("Error1", m.getDeclaringClass().getName().hashCode() + ^ m.getName().hashCode(), m.hashCode()); + } catch (NoSuchMethodException _) { + fail("Error2"); + } + } + + /** + * + */ +//Commented because of the drlvm issue +/* + public void test_invoke_Obj_Obj() { + + class X { + public X first(X a9) { + return a9; + } + } + X x = new X(); + try { + Method m = X.class.getDeclaredMethod("first", + new Class[] { X.class }); + Object o = m.invoke(x, new Object[] { new X() }); + assertTrue("Error1", o instanceof X); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } +*/ + /** + * + */ + public void test_toString_Obj() { + class X { + public X first(X a9) { + return a9; + } + } + new X(); + try { + Method m = X.class.getDeclaredMethod("first", + new Class[] { X.class }); + assertEquals("Error1 ", + "public java.lang.reflect.MethodTest$9X " + + "java.lang.reflect.MethodTest$9X.first(" + + "java.lang.reflect.MethodTest$9X)", + m.toString()); + } catch (Exception e) { + fail("Error2: " + e.toString()); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/MethodTestInvoke.java vm/tests/kernel/java/lang/reflect/MethodTestInvoke.java new file mode 100644 index 0000000..4521936 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/MethodTestInvoke.java @@ -0,0 +1,178 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import java.lang.reflect.Method; + +import org.apache.harmony.lang.C2; +import org.apache.harmony.lang.ProtectedMethod; +import org.apache.harmony.lang.ProtectedSuccessor; + +import junit.framework.TestCase; + +@SuppressWarnings(value={"all"}) public class MethodTestInvoke extends TestCase { + + int state = 0; + + public void test1() { + new Inner1().test1(); + } + + public void test2() { + new Inner2().test2(); + } + + public void test3() { + int status = 0; + try { + Method meth = C2.class.getMethod("publicMethod", (Class[])null); + Field statField = C2.class.getField("stat"); + C2 clazz = new C2(); + assertEquals(0, clazz.stat); + clazz.publicMethod(); + assertEquals(10, clazz.stat); + meth.invoke(clazz, (Object[])null); + status = ((Integer) statField.get(clazz)).intValue(); + } catch (Exception e) { + fail(e.toString()); + } + assertEquals(20, status); + } + + public void test4() { + new Inner3().test4(); + } + + public void test5() { + new Inner4().test5(); + } + + /* PRIVATE SECTION */ + + private void privateMethod() { + state += 10; + } + + // helper class for test1 + class Inner1 extends Object { + + void test1() { + try { + assertEquals(0, state); + privateMethod(); + assertEquals(10, state); + Method method = MethodTestInvoke.class + .getDeclaredMethod("privateMethod", (Class[])null); + method.invoke(MethodTestInvoke.this, (Object[])null); + assertEquals(20, state); + } catch (Exception e) { + fail(e.toString()); + } + } + } + + // helper class for test 2 + class Inner2 extends ProtectedMethod { + + public void test2() { + Inner2 thisInstance = new Inner2(); + ProtectedMethod superInstance = new ProtectedMethod(); + Method m = null; + try { + assertEquals(0, status); + assertEquals(0, thisInstance.status); + assertEquals(0, superInstance.status); + m = ProtectedMethod.class.getDeclaredMethod("protectedMethod", new Class[] {}); + m.invoke(thisInstance, (Object[])null); + } catch (Exception e) { + fail(e.toString()); + } + try { + assertEquals(0, status); + assertEquals(10, thisInstance.status); + assertEquals(0, superInstance.status); + m.invoke(superInstance, (Object[])null); + } catch (IllegalAccessException e) { + assertEquals(0, status); + assertEquals(10, thisInstance.status); + assertEquals(0, superInstance.status); + return; + } catch (Exception e) { + } + fail("IllegalAccessException expected"); + } + } + + // helper class for test4 + class Inner3 { + + public void test4() { + try { + Method m = ProtectedMethod.class + .getDeclaredMethod("protectedMethod", new Class[] {}); + m.invoke(this, (Object[])null); + } catch (IllegalArgumentException e) { + return; + } catch (Exception e) { + fail(e.toString()); + } + fail("IllegalArgumentException expected"); + } + } + + // helper class for test 5 + class Inner4 extends ProtectedSuccessor { + + public void test5() { + Method m = null; + try { + assertEquals(0, status); + this.protectedMethod(); + assertEquals(10, status); + m = ProtectedMethod.class + .getDeclaredMethod("protectedMethod", new Class[] {}); + m.invoke(this, (Object[])null); + } catch (Exception e) { + fail(e.toString()); + } + try { + assertEquals(20, status); + ProtectedSuccessor successor = new ProtectedSuccessor(); + m = ProtectedSuccessor.class + .getDeclaredMethod("privateMethod", new Class[] {}); + m.invoke(successor, (Object[])null); + } catch (IllegalAccessException e) { + } catch (Exception e) { + fail(e.toString()); + } + try { + assertEquals(20, status); + m = ProtectedSuccessor.class + .getDeclaredMethod("privateMethod", new Class[] {}); + m.invoke(this, (Object[])null); + } catch (IllegalAccessException e) { + } catch (Exception e) { + fail(e.toString()); + } + assertEquals(20, status); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck.java vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck.java new file mode 100644 index 0000000..e1fd261 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck.java @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ + +package java.lang.reflect; + +import junit.framework.TestCase; +import org.apache.harmony.lang.ProtectedMethod; +import org.apache.harmony.lang.ProtectedSuccessor; + +public class ProtectedAccessCheck extends TestCase { + + public void test1() { + B b = new B(); + new A().new Inner1().invoke(b); + } +} + +class A extends ProtectedSuccessor { + + class Inner1 { + public void invoke(Object o) { + assertEquals(0, status); + ((B)o).protectedMethod(); + assertEquals(0, status); + try { + Method m = ProtectedMethod.class.getDeclaredMethod( + "protectedMethod", new Class[] {}); + m.invoke(o, (Object[]) null); + assertEquals(0, status); + assertEquals(20, ((B)o).status); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private void assertEquals(int i1, int i2) { + if (i1 != i2) throw new RuntimeException("Assertion failed: " + i1 + + " is not equal to " + i2); + } +} + +class B extends A { + +} \ No newline at end of file diff --git vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck1.java vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck1.java new file mode 100644 index 0000000..f4b8daa --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck1.java @@ -0,0 +1,62 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import junit.framework.TestCase; +import org.apache.harmony.lang.ProtectedMethod; +import org.apache.harmony.lang.ProtectedSuccessor; + +public class ProtectedAccessCheck1 extends TestCase { + + public void test1() { + B1 b = new B1(); + new A1().new Inner1().invoke(b); + } +} + +class A1 extends ProtectedSuccessor { + + class Inner1 extends ProtectedSuccessor { + public void invoke(Object o) { + assertEquals(0, status); + ((B1)o).protectedMethod(); + assertEquals(0, status); + try { + Method m = ProtectedMethod.class.getDeclaredMethod( + "protectedMethod", new Class[] {}); + m.invoke(o, (Object[]) null); + assertEquals(0, status); + assertEquals(20, ((B1) o).status); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private void assertEquals(int i1, int i2) { + if (i1 != i2) throw new RuntimeException("Assertion failed: " + i1 + + " is not equal to " + i2); + } +} + +class B1 extends A1 { + +} diff --git vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck2.java vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck2.java new file mode 100644 index 0000000..db73c17 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ProtectedAccessCheck2.java @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +import junit.framework.TestCase; +import org.apache.harmony.lang.ProtectedMethod; +import org.apache.harmony.lang.ProtectedSuccessor; + +public class ProtectedAccessCheck2 extends TestCase { + + public void test1() { + B2.Inner2 inn2 = new B2.Inner2(); + new A2().new Inner1().invoke(inn2); + } +} + +class A2 extends ProtectedSuccessor { + + class Inner1 extends ProtectedSuccessor { + public void invoke(Object o) { + try { + assertEquals(0, status); + Method m = ProtectedMethod.class.getDeclaredMethod( + "protectedMethod", new Class[] {}); + m.invoke(o, (Object[]) null); + } catch (Exception e) { + return; + } + throw new RuntimeException("IllegalAccessException expected"); + } + } + + private void assertEquals(int i1, int i2) { + if (i1 != i2) throw new RuntimeException("Assertion failed: " + i1 + + " is not equal to " + i2); + } +} + +class B2 extends A2 { + static class Inner2 { + } +} diff --git vm/tests/kernel/java/lang/reflect/ProtectedConstructor.java vm/tests/kernel/java/lang/reflect/ProtectedConstructor.java new file mode 100644 index 0000000..380b236 --- /dev/null +++ vm/tests/kernel/java/lang/reflect/ProtectedConstructor.java @@ -0,0 +1,33 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package java.lang.reflect; + +public class ProtectedConstructor { + + protected ProtectedConstructor() { + } + + public class A { + + public A() { + } + } +} diff --git vm/tests/kernel/notfound/MissingAntn.java vm/tests/kernel/notfound/MissingAntn.java new file mode 100644 index 0000000..6e797c8 --- /dev/null +++ vm/tests/kernel/notfound/MissingAntn.java @@ -0,0 +1,28 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package notfound; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface MissingAntn { + +} diff --git vm/tests/kernel/notfound/MissingClass.java vm/tests/kernel/notfound/MissingClass.java new file mode 100644 index 0000000..6850954 --- /dev/null +++ vm/tests/kernel/notfound/MissingClass.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package notfound; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class MissingClass { + +} diff --git vm/tests/kernel/notfound/MissingEnum.java vm/tests/kernel/notfound/MissingEnum.java new file mode 100644 index 0000000..624655f --- /dev/null +++ vm/tests/kernel/notfound/MissingEnum.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package notfound; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public enum MissingEnum { + A, B, C +} diff --git vm/tests/kernel/org/apache/harmony/lang/AnnotatedElementTestFrame.java vm/tests/kernel/org/apache/harmony/lang/AnnotatedElementTestFrame.java new file mode 100644 index 0000000..c2f8639 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/AnnotatedElementTestFrame.java @@ -0,0 +1,334 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.List; + +import notfound.MissingAntn; +import notfound.MissingClass; +import notfound.MissingEnum; + +import junit.framework.TestCase; + +/** + * Basic framework for testing implementations of the + * {@link java.lang.reflect.AnnotatedElement AnnotatedElement} interface. + * Expected usage: concrete test extending this class should only provide + * objects to be tested, via realization of several abstract methods. + * @see #getElement1() + * @see #getElement2() + * @see #getElement3() + * @see #getElement4() + * @see #getElement5() + * @see #getElement6() + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public abstract class AnnotatedElementTestFrame extends TestCase { + + @Retention(RetentionPolicy.RUNTIME) + public @interface TagAntn {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface ValAntn { + String value() default "<unspecified>"; + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface None{} + + @Retention(RetentionPolicy.RUNTIME) + public @interface MissingClassValAntn { + Class clss() default MissingClass.class; + Class[] clssArray() default MissingClass.class; + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface MissingTypeAntn { + MissingAntn antn() default @MissingAntn; + MissingEnum enm() default MissingEnum.A; + MissingAntn[] antnArray() default @MissingAntn; + MissingEnum[] enmArray() default MissingEnum.A; + } + + /** + * Provides an instance to be tested. The instance must be annotated + * exactly by the single type {@link TagAntn TagAntn}. + */ + protected abstract AnnotatedElement getElement1() throws Throwable; + + /** + * Provides an instance to be tested. The instance must be annotated + * exactly by the two types {@link TagAntn TagAntn} and {@link ValAntn ValAntn}. + */ + protected abstract AnnotatedElement getElement2() throws Throwable; + + /** + * Provides an instance to be tested. The instance must not be annotated. + */ + protected abstract AnnotatedElement getElement3() throws Throwable; + + /** + * Provides an instance to be tested. The instance must be annotated + * by the notfound.MissingAntn. + */ + protected abstract AnnotatedElement getElement4() throws Throwable; + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingClassValAntn. + */ + protected abstract AnnotatedElement getElement5() throws Throwable; + + /** + * Provides an instance to be tested. The instance must be annotated + * by the MissingTypeAntn. + */ + protected abstract AnnotatedElement getElement6() throws Throwable; + + /** + * getAnnotation(Class) should return + * an annotation presented on the element1. + */ + public void testGetAnnotation() throws Throwable { + Annotation an = getElement1().getAnnotation(TagAntn.class); + assertNotNull(an); + assertSame(TagAntn.class, an.annotationType()); + } + + /** + * getAnnotation(Class) should return + * an annotation presented on the element2. + */ + public void testGetAnnotation2() throws Throwable { + Annotation an = getElement2().getAnnotation(ValAntn.class); + assertNotNull(an); + assertSame(ValAntn.class, an.annotationType()); + } + + /** + * getAnnotation(Class) should return + * null for unexpected annotation type. + */ + public void testGetAnnotation_Negative() throws Throwable { + assertNull("case 1", getElement2().getAnnotation(None.class)); + assertNull("case 2", getElement2().getAnnotation(None.class)); + } + + /** + * getAnnotation(Class) should return + * null for non-annotated instance. + */ + public void testGetAnnotation_Negative2() throws Throwable { + assertNull("case 1", getElement3().getAnnotation(TagAntn.class)); + assertNull("case 2", getElement3().getAnnotation(None.class)); + } + + /** + * getAnnotation(Class) should throw NPE on null argument. + */ + public void testGetAnnotation_Null() throws Throwable { + try { + getElement1().getAnnotation(null); + fail("failed to throw NPE"); + } catch (NullPointerException ok) {} + } + + /** + * getDeclaredAnnotations() should return + * all annotations presented on the element1. + */ + public void testGetDeclaredAnnotations() throws Throwable { + Annotation[] an = getElement1().getDeclaredAnnotations(); + assertNotNull(an); + assertEquals("number of Declared Annotations", 1, an.length); + assertSame(TagAntn.class, an[0].annotationType()); + } + + /** + * getDeclaredAnnotations() should return + * all annotations presented on the element2. + */ + public void testGetDeclaredAnnotations2() throws Throwable { + Annotation[] an = getElement2().getDeclaredAnnotations(); + assertNotNull(an); + assertEquals("number of Declared Annotations", 2, an.length); + List<Class> la = Arrays.asList(new Class[] { + an[0].annotationType(), an[1].annotationType()}); + assertTrue("1st annotation", la.contains(TagAntn.class)); + assertTrue("2nd annotation", la.contains(ValAntn.class)); + } + + /** + * getDeclaredAnnotations() should return + * empty array for the element3. + */ + public void testGetDeclaredAnnotations3() throws Throwable { + Annotation[] an = getElement3().getDeclaredAnnotations(); + assertNotNull(an); + assertEquals(0, an.length); + } + + /** + * getDeclaredAnnotations() should return cloned array + * which can be safely modified by a caller. + */ + public void testGetDeclaredAnnotationsImmutable() throws Throwable { + AnnotatedElement el = getElement1(); + Annotation[] an = el.getDeclaredAnnotations(); + assertNotNull(an); + assertEquals("number of Declared Annotations", 1, an.length); + assertSame(TagAntn.class, an[0].annotationType()); + an[0] = null; + Annotation[] an2 = el.getDeclaredAnnotations(); + assertNotNull(an2); + assertEquals("number of second Declared Annotations", 1, an2.length); + assertNotNull("array is not immutable", an2[0]); + assertSame(TagAntn.class, an2[0].annotationType()); + } + + /** + * getAnnotations() should return + * all annotations presented on the element1. + */ + public void testGetAnnotations() throws Throwable { + Annotation[] an = getElement1().getAnnotations(); + assertNotNull(an); + assertEquals("number of Annotations", 1, an.length); + assertSame(TagAntn.class, an[0].annotationType()); + } + + /** + * getAnnotations() should return + * all annotations presented on the element2. + */ + public void testGetAnnotations2() throws Throwable { + Annotation[] an = getElement2().getAnnotations(); + assertNotNull(an); + assertEquals("number of Annotations", 2, an.length); + List<Class> la = Arrays.asList(new Class[] { + an[0].annotationType(), an[1].annotationType()}); + assertTrue("1st annotation", la.contains(TagAntn.class)); + assertTrue("2nd annotation", la.contains(ValAntn.class)); + } + + /** + * getAnnotations() should return + * empty array for the element3. + */ + public void testGetAnnotations3() throws Throwable { + Annotation[] an = getElement3().getAnnotations(); + assertNotNull(an); + assertEquals(0, an.length); + } + + /** + * getAnnotations() should throw TypeNotPresentException + * for the element4. + */ + public void testGetAnnotations4() throws Throwable { + try { + getElement4().getAnnotations(); + fail("Misconfigured test"); + } catch (TypeNotPresentException tnpe) { + assertTrue("reported type name: " + tnpe.typeName(), + tnpe.typeName().matches("notfound.MissingAntn")); + } + } + + /** + * getAnnotations() should return + * all annotations presented on the element5. + */ + public void testGetAnnotations5() throws Throwable { + Annotation[] an = getElement5().getAnnotations(); + assertNotNull(an); + assertEquals("number of Annotations", 1, an.length); + assertSame(MissingClassValAntn.class, an[0].annotationType()); + } + + /** + * getAnnotations() should throw NoClassDefFoundError + * for the element6. + */ + public void testGetAnnotations6() throws Throwable { + try { + getElement6().getAnnotations(); + fail("Misconfigured test"); + } catch (TypeNotPresentException tnpe) { + assertTrue("reported type name: " + tnpe.typeName(), + tnpe.typeName().matches("notfound.Missing(.)+")); + } catch (NoClassDefFoundError e) { + assertTrue("reported type name: " + e.getMessage(), + e.getMessage().matches("notfound.Missing(.)+")); + } + } + + /** + * getAnnotations() should return cloned array + * which can be safely modified by a caller. + */ + public void testGetAnnotationsImmutable() throws Throwable { + AnnotatedElement el = getElement1(); + Annotation[] an = el.getAnnotations(); + assertNotNull(an); + assertEquals("number of Annotations", 1, an.length); + assertSame(TagAntn.class, an[0].annotationType()); + an[0] = null; + Annotation[] an2 = el.getAnnotations(); + assertNotNull(an2); + assertEquals("number of second Annotations", 1, an2.length); + assertNotNull("array is not immutable", an2[0]); + assertSame(TagAntn.class, an2[0].annotationType()); + } + + /** + * isAnnotationPresent(Class) should return true + * for the annotation(s) presented. + */ + public void testIsAnnotationPresent() throws Throwable { + assertTrue("case 1", getElement1().isAnnotationPresent(TagAntn.class)); + assertTrue("case 2", getElement2().isAnnotationPresent(TagAntn.class)); + assertTrue("case 3", getElement2().isAnnotationPresent(ValAntn.class)); + } + + /** + * isAnnotationPresent(Class) should return false + * for the annotation(s) not presented. + */ + public void testIsAnnotationPresent_Negative() throws Throwable { + assertFalse("case 1", getElement1().isAnnotationPresent(ValAntn.class)); + assertFalse("case 2", getElement1().isAnnotationPresent(None.class)); + assertFalse("case 3", getElement2().isAnnotationPresent(None.class)); + assertFalse("case 4", getElement3().isAnnotationPresent(TagAntn.class)); + } + + /** + * isAnnotationPresent(Class) should throw NPE on null argument + */ + public void testIsAnnotationPresent_Null() throws Throwable { + try { + getElement1().isAnnotationPresent(null); + fail("failed to throw NPE"); + } catch (NullPointerException ok) {} + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/C2.java vm/tests/kernel/org/apache/harmony/lang/C2.java new file mode 100644 index 0000000..4095005 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/C2.java @@ -0,0 +1,33 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package org.apache.harmony.lang; + +public class C2 extends C1 { +} + +class C1 { + + public int stat = 0; + + public void publicMethod() { + stat += 10; + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/ProtectedMethod.java vm/tests/kernel/org/apache/harmony/lang/ProtectedMethod.java new file mode 100644 index 0000000..a449ccc --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/ProtectedMethod.java @@ -0,0 +1,30 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ +package org.apache.harmony.lang; + +public class ProtectedMethod { + + public int status = 0; + + protected void protectedMethod() { + status += 10; + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/ProtectedSuccessor.java vm/tests/kernel/org/apache/harmony/lang/ProtectedSuccessor.java new file mode 100644 index 0000000..d49698a --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/ProtectedSuccessor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Evgueni V. Brevnov + * @version $Revision$ + */ + +package org.apache.harmony.lang; + +@SuppressWarnings(value={"all"}) public class ProtectedSuccessor extends ProtectedMethod { + + private void privateMethod() { + status +=5; + } + +} diff --git vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn.java vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn.java new file mode 100644 index 0000000..e64a758 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn.java @@ -0,0 +1,92 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.annotation; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The annotation containing all possible types of elements with default values. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@Retention(RetentionPolicy.RUNTIME) +@AllTypesAntn +@SuppressWarnings(value={"all"}) public @interface AllTypesAntn { + public enum TheEnum {A, B, C, } + public @interface TheAntn {} + + int intValue() default 345; + byte byteValue() default (byte)28; + short shortValue() default (short)3247; + long longValue() default 234956955L; + char charValue() default 'q'; + float floatValue() default 213235.34546546f; + double doubleValue() default 7E-34; + boolean booleanValue() default true; + Class classValue() default AllTypesAntn.class; + //TheEnum enumValue() default TheEnum.A; //FIXME enum de/serialization fails + TheAntn antnValue() default @TheAntn; + + int[] intArrayValue() default 345; + byte[] byteArrayValue() default (byte)28; + short[] shortArrayValue() default (short)3247; + long[] longArrayValue() default 234956955L; + char[] charArrayValue() default 'q'; + float[] floatArrayValue() default 213235.34546546f; + double[] doubleArrayValue() default 7E-34; + boolean[] booleanArrayValue() default true; + Class[] classArrayValue() default AllTypesAntn.class; + //TheEnum[] enumArrayValue() default TheEnum.A; //FIXME enum de/serialization fails + TheAntn[] antnArrayValue() default @TheAntn; + + /** + * Elementary implementation of the enclosing interface. + */ + public static class MockedImpl implements AllTypesAntn { + public static class TheAntnImpl implements TheAntn { + public Class<? extends Annotation> annotationType() {return TheAntn.class;} + } + + public Class<? extends Annotation> annotationType() {return AllTypesAntn.class;} + + public int intValue() {return 345;} + public byte byteValue() {return (byte)28;} + public short shortValue() {return (short)3247;} + public long longValue() {return 234956955L;} + public char charValue() {return 'q';} + public float floatValue() {return 213235.34546546f;} + public double doubleValue() {return 7E-34;} + public boolean booleanValue() {return true;} + public Class classValue() {return AllTypesAntn.class;} + //public TheEnum enumValue() {return TheEnum.A; } //FIXME enum de/serialization fails + public TheAntn antnValue() {return new TheAntnImpl();} + + public int[] intArrayValue() {return new int[]{345};} + public byte[] byteArrayValue() {return new byte[] {(byte)28};} + public short[] shortArrayValue() {return new short[] {(short)3247};} + public long[] longArrayValue() {return new long[] {234956955L};} + public char[] charArrayValue() {return new char[] {'q'};} + public float[] floatArrayValue() {return new float[] {213235.34546546f};} + public double[] doubleArrayValue() {return new double[] {7E-34};} + public boolean[] booleanArrayValue() {return new boolean[]{true};} + public Class[] classArrayValue() {return new Class[] {AllTypesAntn.class};} + //public TheEnum[] enumArrayValue() {return new TheEnum[] {TheEnum.A}; } //FIXME enum de/serialization fails + public TheAntn[] antnArrayValue() {return new TheAntn[] {new TheAntnImpl()};} + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn2.java vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn2.java new file mode 100644 index 0000000..826cc85 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesAntn2.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The annotation containing all possible types of elements. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@Retention(RetentionPolicy.RUNTIME) +@AllTypesAntn2(intValue=1,intArrayValue=2, + byteValue=3, byteArrayValue=4, + shortValue=5, shortArrayValue=6, + longValue=7, longArrayValue=8, + charArrayValue='s', charValue='e', + floatArrayValue=234, floatValue=456.456745f, + doubleArrayValue=34, doubleValue=345, + booleanArrayValue=true, booleanValue=false, + classArrayValue=AllTypesAntn2.class, classValue=AllTypesAntn2.class, + //enumArrayValue=AllTypesAntn2.TheEnum.B, enumValue=AllTypesAntn2.TheEnum.C, //FIXME enum de/serialization fails + antnArrayValue=@AllTypesAntn2.TheAntn, antnValue=@AllTypesAntn2.TheAntn) +public @interface AllTypesAntn2 { + public enum TheEnum {A, B, C, } + public @interface TheAntn {} + + int intValue(); + byte byteValue(); + short shortValue(); + long longValue() ; + char charValue() ; + float floatValue(); + double doubleValue() ; + boolean booleanValue(); + Class classValue() ; + //TheEnum enumValue(); //FIXME enum de/serialization fails + TheAntn antnValue(); + + int[] intArrayValue() ; + byte[] byteArrayValue(); + short[] shortArrayValue() ; + long[] longArrayValue() ; + char[] charArrayValue() ; + float[] floatArrayValue() ; + double[] doubleArrayValue(); + boolean[] booleanArrayValue() ; + Class[] classArrayValue() ; + // TheEnum[] enumArrayValue(); //FIXME enum de/serialization fails + TheAntn[] antnArrayValue(); +} diff --git vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesTest.java vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesTest.java new file mode 100644 index 0000000..74e7a8a --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/annotation/AllTypesTest.java @@ -0,0 +1,221 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.annotation; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Method; + +import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn; + +import junit.framework.TestCase; + +/** + * The test of annotation implementation, covering all possible types of elements. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@AllTypesAntn +public class AllTypesTest extends TestCase { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTypesTest.class); + } + + /** + * The annotation instance should return correct default values + * of elements if no actual values were specified. + */ + public void testGetAnnotation_ByDefault() throws Throwable { + AllTypesAntn antn = AllTypesAntn.class.getAnnotation(AllTypesAntn.class); + assertNotNull("the annotation", antn); + Method[] ms = AllTypesAntn.class.getDeclaredMethods(); + for (Method m : ms) { + Object defaultValue = m.getDefaultValue(); + String name = m.getName(); + assertNotNull("null defaultValue of " + name, defaultValue); + Object value = m.invoke(antn); + assertNotNull("null value of " + name, value); + Class<?> def = m.getReturnType(); + Class<?> real = value.getClass(); + if (def.isAnnotation()) { + assertTrue("nested antn value type : def=" + def + "; real=" + real, def.isInstance(value)); + } else if (def.isPrimitive()) { + assertSame("unboxed value type", def, real.getField("TYPE").get(null)); + } else { + assertSame("value type", def, real); + } + + if (m.getReturnType().isArray()) { + int len = Array.getLength(defaultValue); + assertEquals("array length of " + m.getName(), len, Array.getLength(value)); + for (int i = 0; i < len; i++) { + assertEquals(m.getName() + "["+i+"]", Array.get(defaultValue, i), Array.get(value, i)); + } + } else { + assertEquals(m.getName(), defaultValue, value); + } + } + } + + /** + * The annotation instance should return correct actual values + * of elements overriding their defaults. + */ + public void testGetAnnotation_NoDefault() throws Throwable { + AllTypesAntn2 antn = AllTypesAntn2.class.getAnnotation(AllTypesAntn2.class); + assertNotNull("the annotation", antn); + Method[] ms = AllTypesAntn2.class.getDeclaredMethods(); + for (Method m : ms) { + Object defaultValue = m.getDefaultValue(); + String name = m.getName(); + assertNull("defaultValue of " + name, defaultValue); + Object value = m.invoke(antn); + assertNotNull("null value of " + name, value); + Class<?> def = m.getReturnType(); + Class<?> real = value.getClass(); + if (def.isAnnotation()) { + assertTrue("nested antn value type : def=" + def + "; real=" + real, def.isInstance(value)); + } else if (def.isPrimitive()) { + assertSame("unboxed value type", def, real.getField("TYPE").get(null)); + } else { + assertSame("value type", def, real); + } + } + } + + /** + * The equals() method of annotation instance + * must true if equivalent annotation instance is passed, false otherwise. + */ + @AllTypesAntn(intArrayValue=346546) + public void testEquals() throws Throwable { + AllTypesAntn antn = AllTypesAntn.class.getAnnotation(AllTypesAntn.class); + assertTrue("case1", antn.equals(antn)); + Object obj = this.getClass().getAnnotation(AllTypesAntn.class); + assertEquals("case2", obj, antn); + assertEquals("case2_1", obj.hashCode(), antn.hashCode()); + AllTypesAntn2 antn2 = AllTypesAntn2.class.getAnnotation(AllTypesAntn2.class); + assertEquals("case3", antn2, AllTypesAntn2.class.getAnnotation(AllTypesAntn2.class)); + assertFalse("case4", antn.equals(antn2)); + assertFalse("case5", antn.equals( + this.getClass().getMethod("testEquals").getAnnotation(AllTypesAntn.class))); + } + + /** + * The equals() method of annotation instance + * must correctly work with alternative implementations. + */ + public void testEquals_ForeignImpl() throws Throwable { + AllTypesAntn antn = AllTypesAntn.class.getAnnotation(AllTypesAntn.class); + assertTrue(antn.equals(new AllTypesAntn.MockedImpl())); + } + + /** + * The toString() method of annotation instance + * must return meaningful description. + */ + public void testToString() throws Throwable { + String s = AllTypesAntn.class.getAnnotation(AllTypesAntn.class).toString(); + assertNotNull(s); + assertTrue(s.length() != 0); + assertTrue(s.startsWith("@org.apache.harmony.lang.annotation.AllTypesAntn")); + } + + /** + * The annotationType() method of annotation instance + * must return correct Class. + */ + public void testAnnotationType() throws Throwable { + assertSame(AllTypesAntn.class, + AllTypesAntn.class.getAnnotation(AllTypesAntn.class).annotationType()); + } + + /** + * An annotation should defer throwing TypeNotPresentException + * for a Class-valued member until the member accessed. + */ + @MissingClassValAntn + public void testAnnotation_ElementError() throws Throwable { + MissingClassValAntn antn = this.getClass().getMethod( + "testAnnotation_ElementError").getAnnotation(MissingClassValAntn.class); + try { + antn.clss(); + fail("Misconfigured test: " + + "notfound.MissingClass should not be in classpath"); + } catch (TypeNotPresentException tnpe) { + assertTrue("reported type name: " + tnpe.typeName(), + tnpe.typeName().matches("notfound.MissingClass")); + } + + try { + antn.clssArray(); + fail("Misconfigured test: " + + "notfound.MissingClass should not be in classpath"); + } catch (TypeNotPresentException tnpe) { + assertTrue("reported type name: " + tnpe.typeName(), + tnpe.typeName().matches("notfound.MissingClass")); + } + } + + /** + * Tests that annotation can be serialized and deserialized without + * exceptions, and that deserialization really produces deeply cloned + * objects. + */ + public void testSerialization() throws Throwable { + Object[] arr = new Object[] { + AllTypesAntn.class.getAnnotation(AllTypesAntn.class), + AllTypesAntn2.class.getAnnotation(AllTypesAntn2.class) + }; + for (Object data : arr) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + putObjectToStream(data, bos); + ByteArrayInputStream bis = new ByteArrayInputStream(bos + .toByteArray()); + assertEquals(data, getObjectFromStream(bis)); + } + } + + /** + * Serializes specified object to an output stream. + */ + static void putObjectToStream(Object obj, OutputStream os) + throws IOException { + ObjectOutputStream oos = new ObjectOutputStream(os); + oos.writeObject(obj); + oos.flush(); + oos.close(); + } + + /** + * Deserializes single object from an input stream. + */ + static Object getObjectFromStream(InputStream is) throws IOException, + ClassNotFoundException { + ObjectInputStream ois = new ObjectInputStream(is); + Object result = ois.readObject(); + ois.close(); + return result; + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/annotation/AnnotationLoaderTest.java vm/tests/kernel/org/apache/harmony/lang/annotation/AnnotationLoaderTest.java new file mode 100644 index 0000000..40a0c4f --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/annotation/AnnotationLoaderTest.java @@ -0,0 +1,123 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.harmony.test.TestResources; + +import junit.framework.TestCase; + +/** + * Test verifies that correct classloader is used to reflect + * annotations. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class AnnotationLoaderTest extends TestCase { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AnnotationLoaderTest.class); + } + + protected ClassLoader ld; + protected Class<?> test; + + @Override + protected void setUp() throws Exception { + ld = TestResources.getLoader(); + test = ld.loadClass("org.apache.harmony.lang.test.resource.AnnotatedMembers"); + } + + /** + * Tests that the defining classloader is used to lookup class annotations. + */ + public void testClass() throws Throwable { + Annotation[] an = test.getAnnotations(); + assertNotNull(an); + assertEquals("annotations num", 1, an.length); + assertEquals("the class annotation", "AnotherAntn", an[0].annotationType().getSimpleName()); + } + + /** + * Tests that the defining classloader is used to lookup package annotations. + */ + public void testPackage() throws Throwable { + Package p = test.getPackage(); + assertNotNull("package", p); + Annotation[] an = p.getAnnotations(); + assertNotNull(an); + assertEquals("annotations num", 1, an.length); + assertEquals("the package annotation", "AnotherAntn", an[0].annotationType().getSimpleName()); + } + + /** + * Tests that the defining classloader is used to lookup annotations + * of fields of a class. + */ + public void testField() throws Throwable { + Field f = test.getField("foo"); + assertNotNull("field", f); + Annotation[] an = f.getAnnotations(); + assertNotNull("annotations", an); + assertEquals("annotations num", 1, an.length); + assertEquals("the class annotation", "AnotherAntn", an[0].annotationType().getSimpleName()); + } + + /** + * Tests that the defining classloader is used to lookup annotations + * of methods of a class. + */ + public void testMethod() throws Throwable { + Method m = test.getMethod("bar"); + assertNotNull("method", m); + Annotation[] an = m.getAnnotations(); + assertNotNull("annotations", an); + assertEquals("annotations num", 1, an.length); + assertEquals("the class annotation", "AnotherAntn", an[0].annotationType().getSimpleName()); + } + + /** + * Tests that the defining classloader is used to lookup annotations + * of constructors of a class. + */ + public void testCtor() throws Throwable { + Constructor ctor = test.getConstructor(); + assertNotNull("ctor", ctor); + Annotation[] an = ctor.getAnnotations(); + assertNotNull("annotations", an); + assertEquals("annotations num", 1, an.length); + assertEquals("the class annotation", "AnotherAntn", an[0].annotationType().getSimpleName()); + } + + /** + * Tests that the defining classloader is used to lookup parameter annotations + * of class's methods. + */ + public void testParam() throws Throwable { + Method m = test.getMethod("buz", String.class); + assertNotNull("method", m); + Annotation[][] an = m.getParameterAnnotations(); + assertNotNull("annotations", an); + assertEquals("param num", 1, an.length); + assertEquals("annotations num", 1, an[0].length); + assertEquals("the class annotation", "AnotherAntn", an[0][0].annotationType().getSimpleName()); + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/generics/ClassLoaderTest.java vm/tests/kernel/org/apache/harmony/lang/generics/ClassLoaderTest.java new file mode 100644 index 0000000..40c630e --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/generics/ClassLoaderTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + **/ + +package org.apache.harmony.lang.generics; + +@SuppressWarnings(value={"all"}) public class ClassLoaderTest extends junit.framework.TestCase { + public static int flag = 0; + public void test() { + try { + SpecialClassLoader mcl = new SpecialClassLoader(); + Class cls = mcl.loadClass(""); + Object obj = cls.newInstance(); + cls.getDeclaredMethod("test", (Class[])null).invoke(obj, (Object[])null); + } catch (Exception e) { + e.printStackTrace(); + } + } + public void main(String[] args) { + (new ClassLoaderTest()).test(); + } + +} diff --git vm/tests/kernel/org/apache/harmony/lang/generics/SpecialC.java vm/tests/kernel/org/apache/harmony/lang/generics/SpecialC.java new file mode 100644 index 0000000..a84a7aa --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/generics/SpecialC.java @@ -0,0 +1,25 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + **/ + +package org.apache.harmony.lang.generics; + +public class SpecialC { +} diff --git vm/tests/kernel/org/apache/harmony/lang/generics/SpecialClassLoader.java vm/tests/kernel/org/apache/harmony/lang/generics/SpecialClassLoader.java new file mode 100644 index 0000000..3d32da2 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/generics/SpecialClassLoader.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + **/ + +package org.apache.harmony.lang.generics; +import java.io.File; +import java.io.FileInputStream; + +@SuppressWarnings(value={"all"}) public class SpecialClassLoader extends ClassLoader { + public Class findClass(String name) { + try { + String s=""; + String s2=""; + if (ClassLoaderTest.flag == 0) { + s="org"+File.separator+"apache"+File.separator+"harmony"+File.separator+"lang"+File.separator+"generics"+File.separator+"SpecialD"; + s2="org.apache.harmony.lang.generics.SpecialD"; + } else { + s="org"+File.separator+"apache"+File.separator+"harmony"+File.separator+"lang"+File.separator+"generics"+File.separator+"SpecialC"; + s2="org.apache.harmony.lang.generics.SpecialC"; + } + FileInputStream fis; + fis = new FileInputStream(System.getProperty("java.ext.dirs")+File.separator+"classes"+File.separator+s+".class"); + byte[] classToBytes = new byte[fis.available()]; + fis.read(classToBytes); + return defineClass(s2, classToBytes, 0, classToBytes.length); + } catch (Exception e) { + System.err.println("Unexpected exception during classloading: "); + e.printStackTrace(); + return null; + } + } + + public Class checkFind(String name) { + return findLoadedClass(name); + } +} diff --git vm/tests/kernel/org/apache/harmony/lang/generics/SpecialD.java vm/tests/kernel/org/apache/harmony/lang/generics/SpecialD.java new file mode 100644 index 0000000..d282c6a --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/generics/SpecialD.java @@ -0,0 +1,47 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + **/ + +package org.apache.harmony.lang.generics; + +import junit.framework.TestCase; + +public class SpecialD extends TestCase { + public void test() { + try { + new SpecialC(); + if(((SpecialClassLoader)this.getClass().getClassLoader()).checkFind("org.apache.harmony.lang.generics.SpecialC")==null) { + fail("FAILED: " + this.getClass().getClassLoader().getClass() + " wasn't marked as initiating classloader for SpecialC"); + } else { + //System.out.println("PASSED: " + this.getClass().getClassLoader().getClass() + " was marked as initiating classloader for SpecialC"); + } + //System.out.println("Trying to define SpecialC for the second time..."); + ClassLoaderTest.flag++; + try { + ((SpecialClassLoader)this.getClass().getClassLoader()).loadClass(""); + fail("FAILED: LinkageError wasn't thrown"); + } catch (LinkageError err) { + } + } catch (Throwable t) { + fail("FAILED: Unexpected error thrown:"); + t.printStackTrace(); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/org/apache/harmony/lang/generics/TemplateSet.java vm/tests/kernel/org/apache/harmony/lang/generics/TemplateSet.java new file mode 100644 index 0000000..13915ab --- /dev/null +++ vm/tests/kernel/org/apache/harmony/lang/generics/TemplateSet.java @@ -0,0 +1,82 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Serguei S.Zapreyev + * @version $Revision$ + **/ + +package org.apache.harmony.lang.generics; + +import java.lang.reflect.*; + +//import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/* + * Created on May 05, 2006 + * + * This TemplateSet class keeps the template set for the java.lang.ClassGenericsTest4 unit test + * + */ + +public class TemplateSet<X> { + + @Retention(value=RetentionPolicy.RUNTIME) + @interface igt{ + abstract String author() default "Zapreyev"; + }; + @igt class Mc001 {}; + + + @igt interface MI001<T0 extends java.io.Serializable> {}; + @igt interface MI002<T1 extends MI001> {}; + @igt interface MI003<T2> extends MI001 {}; + @igt interface MI004<T2> { + @igt interface MI005<T21, T22> { + }; + }; + @igt(author="Serguei Stepanovich Zapreyev") public class Mc002<T3 extends TemplateSet/*Class*/> { + @igt public class Mc004<T5 extends TemplateSet/*Integer*/> { + }; + }; + @igt class Mc003<T4 extends Thread &java.io.Serializable &Cloneable> extends TemplateSet<? super Class>.Mc002<TemplateSet> implements MI002<MI003<java.io.Serializable>>, MI003<MI003<Cloneable>>, MI004/*<Cloneable>*/.MI005<Type, Type> {}; + @igt class Mc007\u0391<T7 extends Thread &java.io.Serializable &Cloneable> {}; + @igt class Mc008\u0576\u06C0\u06F10<T8 extends Mc007\u0391 &java.io.Serializable &Cloneable> extends TemplateSet<? super Mc007\u0391>.Mc002<TemplateSet> implements MI002<MI003<java.io.Serializable>>, MI003<MI003<Cloneable>>, MI004.MI005<Mc007\u0391, Type> {}; + @igt class Mc010\u0576\u06C0\u06F10 {}; + @igt interface MI010\u0576\u06C0\u06F10 {}; + @igt class MC011\u0576\u06C0\u06F10 extends Mc010\u0576\u06C0\u06F10 implements MI010\u0576\u06C0\u06F10 {}; + + class Mc005 extends Thread implements java.io.Serializable, Cloneable {private static final long serialVersionUID = 0L;}; + public Mc003<Mc005> fld0; + public TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> f0; + public X f111; + public TemplateSet f112; + class Mc009\u0576\u06C0\u06F1 extends Throwable implements java.io.Serializable, Cloneable {private static final long serialVersionUID = 0L;}; + @igt(author="*****") public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> void foo1For_5(UuUuU a1) throws UuUuU, java.io.IOException {} + public <\u0391 extends Throwable, TM1, TM2, TM3, TM4, TM5, TM6, TM7> X foo2For_5() throws \u0391, java.io.IOException {X f = null; return f;} + public <\u0576\u06C0\u06F1 extends Throwable, \u0576\u06C0\u06F11 extends Throwable, \u0576\u06C0\u06F12 extends Throwable, \u0576\u06C0\u06F13 extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> TM2 foo3For_5(\u0576\u06C0\u06F1[] BAAB, TM1 a1, TM2 a2, TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> a3) throws \u0576\u06C0\u06F1, Throwable, \u0576\u06C0\u06F13, \u0576\u06C0\u06F12, \u0576\u06C0\u06F11, TemplateSet.Mc009\u0576\u06C0\u06F1 {TM2 f = null; return f;} + public Mc003<Mc005> foo4For_5(TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<?> a1, @igt(author="Czar") Mc003<Mc005> a2, @igt(author="President") Mc003<Mc005> ... a3) {return a2;} + public TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> foo5For_5(X a1, Class<Type> a2, TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> a3) {return a3;} + class MC006{ + @igt(author="*****") public <UuUuU extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> MC006(UuUuU a1) throws UuUuU, java.io.IOException {} + public <\u0391 extends Throwable, TM1, TM2, TM3, TM4, TM5, TM6, TM7> MC006() throws \u0391, java.io.IOException {} + public <\u0576\u06C0\u06F1 extends Throwable, \u0576\u06C0\u06F11 extends Throwable, \u0576\u06C0\u06F12 extends Throwable, \u0576\u06C0\u06F13 extends Throwable, TM1, TM2 extends Thread &java.io.Serializable &Cloneable> MC006(\u0576\u06C0\u06F1[] BAAB, TM1 a1, TM2 a2, TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> a3) throws \u0576\u06C0\u06F1, Throwable, \u0576\u06C0\u06F13, \u0576\u06C0\u06F12, \u0576\u06C0\u06F11 {} + public MC006(TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<?> a1, @igt(author="Czar") Mc003<Mc005> a2, @igt(author="President") Mc003<Mc005> ... a3) {} + public MC006(X a1, Class<Type> a2, TemplateSet<? super Class>.Mc002<TemplateSet>.Mc004<TemplateSet> a3) {} + } +} \ No newline at end of file diff --git vm/tests/kernel/org/apache/harmony/test/ReversibleSecurityManager.java vm/tests/kernel/org/apache/harmony/test/ReversibleSecurityManager.java new file mode 100644 index 0000000..530d43d --- /dev/null +++ vm/tests/kernel/org/apache/harmony/test/ReversibleSecurityManager.java @@ -0,0 +1,36 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.test; + +import java.security.Permission; + +/** + * Security Manager implementation which does not prevent + * re-setting of the system security manager. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class ReversibleSecurityManager extends SecurityManager { + public static final RuntimePermission RESET_PERMISSION = + new RuntimePermission("setSecurityManager"); + + public void checkPermission(Permission perm) { + if (!RESET_PERMISSION.equals(perm)) { + super.checkPermission(perm); + } + } +} \ No newline at end of file diff --git vm/tests/kernel/org/apache/harmony/test/TestResources.java vm/tests/kernel/org/apache/harmony/test/TestResources.java new file mode 100644 index 0000000..e134480 --- /dev/null +++ vm/tests/kernel/org/apache/harmony/test/TestResources.java @@ -0,0 +1,69 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.test; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Various test utilities are provided as static methods of this class. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class TestResources { + + /** + * Name of system property specifying URL or filepath of + * isolated bundle with test resources. + * + * @see #getLoader() + */ + public static final String RESOURCE_PATH = "test.resource.path"; + + private static ClassLoader loader; + + /** + * Certain tests may require existence of isolated test resources - + * i.e. some resources not available via system (caller's) loader. + * This method is intended to support such resources. + * @see #RESOURCE_PATH + * @return a classloader which is aware of location of isolated resources + */ + public static ClassLoader getLoader() { + if (loader == null) { + URL url = null; + try { + String path = System.getProperty(RESOURCE_PATH, "."); + File f = new File(path); + if (f.exists()) { + url = f.toURI().toURL(); + } else { + url = new URL(path); + } + } catch (MalformedURLException e) { + throw new RuntimeException( + "Misconfigured path to test resources. " + + "Please set correct value of system property: " + + RESOURCE_PATH, e); + } + loader = URLClassLoader.newInstance(new URL[] { url }); + } + return loader; + } +} diff --git vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnnotatedMembers.java vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnnotatedMembers.java new file mode 100644 index 0000000..0c3db9c --- /dev/null +++ vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnnotatedMembers.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.test.resource; + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@AnotherAntn +public abstract class AnnotatedMembers { + @AnotherAntn + public Object foo; + + @AnotherAntn + public abstract void bar(); + + public abstract void buz(@AnotherAntn String param); + + @AnotherAntn + public AnnotatedMembers() {} +} diff --git vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnotherAntn.java vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnotherAntn.java new file mode 100644 index 0000000..bb0bdb6 --- /dev/null +++ vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/AnotherAntn.java @@ -0,0 +1,56 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.test.resource; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The annotation containing all possible types of elements with default values. + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@Retention(RetentionPolicy.RUNTIME) +@AnotherAntn +public @interface AnotherAntn { + public enum TheEnum {A, B, C, } + public @interface TheAntn {} + + int intValue() default 345; + byte byteValue() default (byte)28; + short shortValue() default (short)3247; + long longValue() default 234956955L; + char charValue() default 'q'; + float floatValue() default 213235.34546546f; + double doubleValue() default 7E-34; + boolean booleanValue() default true; + Class classValue() default AnotherAntn.class; + TheEnum enumValue() default TheEnum.A; + TheAntn antnValue() default @TheAntn; + + int[] intArrayValue() default 345; + byte[] byteArrayValue() default (byte)28; + short[] shortArrayValue() default (short)3247; + long[] longArrayValue() default 234956955L; + char[] charArrayValue() default 'q'; + float[] floatArrayValue() default 213235.34546546f; + double[] doubleArrayValue() default 7E-34; + boolean[] booleanArrayValue() default true; + Class[] classArrayValue() default AnotherAntn.class; + TheEnum[] enumArrayValue() default TheEnum.A; + TheAntn[] antnArrayValue() default @TheAntn; +} diff --git vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/package-info.java vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/package-info.java new file mode 100644 index 0000000..fbd515a --- /dev/null +++ vm/tests/kernel_resources/org/apache/harmony/lang/test/resource/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +@AnotherAntn +package org.apache.harmony.lang.test.resource; diff --git vm/tests/smoke/StackTest.java vm/tests/smoke/StackTest.java old mode 100644 new mode 100755 index 3cd2307..b121ffd --- vm/tests/smoke/StackTest.java +++ vm/tests/smoke/StackTest.java @@ -14,9 +14,6 @@ * limitations under the License. */ -/** - * @keyword XXX_fails - */ public class StackTest { static int depth = 0; diff --git vm/tests/smoke/classloader/SysRes.java vm/tests/smoke/classloader/SysRes.java deleted file mode 100644 index cf8d05b..0000000 --- vm/tests/smoke/classloader/SysRes.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Pavel Pervov - * @version $Revision: 1.7.28.4 $ - */ -package classloader; -import java.io.InputStream; - -/** - * Test resource reading. - * @keyword golden - */ -public class SysRes { - public static void main(String[] s) { - InputStream is = ClassLoader.getSystemResourceAsStream( - "classloader/SysRes.class"); - int c; - try { - while ((c = is.read()) != -1) { - System.out.println(c); - } - } catch (java.io.IOException ioe) { - System.out.println("IOE = " + ioe); - } - } -} diff --git vm/tests/smoke/gc/LOS.java vm/tests/smoke/gc/LOS.java index 4af3da9..dffa2a2 100644 --- vm/tests/smoke/gc/LOS.java +++ vm/tests/smoke/gc/LOS.java @@ -24,7 +24,6 @@ import java.util.ArrayList; /** * Try large object allocation after filling the heap with small objects. * - * @keyword gc X_ipf_bug_5195 */ public class LOS extends Thread { diff --git vm/tests/smoke/stress/Exceptions.java vm/tests/smoke/stress/Exceptions.java deleted file mode 100644 index 59b6bf0..0000000 --- vm/tests/smoke/stress/Exceptions.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Pavel Afremov - * @version $Revision: 1.6.20.4 $ - */ -package stress; -import java.util.Vector; - -/** - * @keyword golden slow - */ -public class Exceptions { - - Exception e[] = { - new RuntimeException("RuntimeException"), - new NullPointerException("NullPointerException"), - new ClassNotFoundException("ClassNotFoundException"), - new NoSuchFieldException("NoSuchFieldException"), - new NoSuchMethodException("NoSuchMethodException"), - new InterruptedException("NoSuchMethodException"), - }; - - synchronized boolean test(int ignore) { - - for (int i = e.length - 1; i >= 0; i--) { - try { - - System.out.println("Throw exception: " + e[i].toString()); - - throw e[i]; - - } catch (Throwable t) { - System.out.println(" Got exception: " + t.toString()); - } - } - - final int size = 1000; - Vector v = new Vector(); - - String s[] = new String[size]; - - for (int i = 0; i < 1000000; i++) { - try { - String tmp = new String("iteration " + i); - s[i % (size + 1)] = tmp; - v.add(tmp); - } catch (ArrayIndexOutOfBoundsException foo) { - System.out.println("Got ArrayIndexOutOfBoundsException"); - } - - if ((i % 10000) == 0) { - System.out.println("Git GC on " + i + " iteration"); - v.removeAllElements(); - System.gc(); - } - } - return true; - } - - public static void main(String[] args) { - boolean pass = false; - - try { - Exceptions test = new Exceptions(); - pass = test.test(0); - } catch (Throwable e) { - System.out.println("Got exception: " + e.toString()); - } - System.out.println("Exceptions test " + (pass ? "passed" : "failed")); - } -} diff --git vm/tests/smoke/util/Logger.java vm/tests/smoke/util/Logger.java deleted file mode 100644 index cd509dc..0000000 --- vm/tests/smoke/util/Logger.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Alexei Fedotov - * @version $Revision: 1.10.20.4 $ - */ -package util; -import java.util.logging.Level; - -/** - * Test a logger. - * @keyword golden X_Linux_bug_5898 - */ -public class Logger { - private final static java.util.logging.Logger LOG = - java.util.logging.Logger.getAnonymousLogger(); - private final static String MESSAGE = "logging message"; - - public static void main(String[] args) { - LOG.setLevel(Level.ALL); - LOG.info(MESSAGE); - System.out.println("passed"); - } -} diff --git vm/tests/smoke/util/UriGetFile.java vm/tests/smoke/util/UriGetFile.java deleted file mode 100644 index ef036ba..0000000 --- vm/tests/smoke/util/UriGetFile.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Alexei Fedotov - * @version $Revision: 1.7.24.4 $ - */ -package util; - -import java.net.MalformedURLException; -import java.net.URL; - -/** - * @keyword golden - */ -public class UriGetFile { - - public static boolean test() - { - URL url = null; - try { - url = new URL("file://"); - } catch (MalformedURLException mue) { - } - System.out.println(url.getFile()); - - return true; - } - - public static void main(String[] args) { - boolean pass = false; - try { - pass = UriGetFile.test(); - } catch (Throwable e) { - System.out.println("Got exception: " + e.toString()); - } - System.out.println("UriGetFile " + (pass ? "passed" : "failed")); - } -} diff --git vm/tests/smoke/util/Zip.java vm/tests/smoke/util/Zip.java deleted file mode 100644 index a237fdb..0000000 --- vm/tests/smoke/util/Zip.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Alexei Fedotov - * @version $Revision: 1.2.40.3 $ - */ -package util; -import java.util.zip.ZipFile; - -/** - * Test a static initializer - * - * @keyword golden - */ -public class Zip { - public static void main(String[] s) { - System.out.println("LOCTIM = " + ZipFile.LOCTIM); - } -} diff --git vm/thread/src/hythr.def vm/thread/src/hythr.def index e4783a5..63ba100 100644 --- vm/thread/src/hythr.def +++ vm/thread/src/hythr.def @@ -111,6 +111,7 @@ hymutex_destroy hythread_wait_for_all_nondaemon_threads hythread_is_alive +hythread_is_terminated hythread_init countdown_nondaemon_threads increase_nondaemon_threads_count diff --git vm/thread/src/hythr.exp vm/thread/src/hythr.exp index 2b8781d..6702512 100644 --- vm/thread/src/hythr.exp +++ vm/thread/src/hythr.exp @@ -145,6 +145,7 @@ hythread_is_sleeping; hythread_is_waiting_with_timeout; hythread_is_waiting_indefinitely; hythread_is_runnable; +hythread_is_terminated; hythread_thin_monitor_get_recursion; array_add; array_create; diff --git vm/thread/src/thread_init.c vm/thread/src/thread_init.c index 227e118..9a5ff8e 100644 --- vm/thread/src/thread_init.c +++ vm/thread/src/thread_init.c @@ -54,6 +54,9 @@ hythread_monitor_t p_global_monitor; hythread_group_t TM_DEFAULT_GROUP; hythread_group_t group_list; +hythread_monitor_t *lock_table = NULL; +int table_size = 8024; + IDATA groups_count; IDATA nondaemon_thread_count; @@ -99,21 +102,24 @@ void VMCALL hythread_init(hythread_libra if(TM_LOCK) { return; } - - apr_status = apr_initialize(); - assert(apr_status == APR_SUCCESS); - apr_status = apr_pool_create(&TM_POOL, NULL); - assert(apr_status == APR_SUCCESS); - status = hymutex_create(&TM_LOCK, TM_MUTEX_NESTED); - assert (status == TM_ERROR_NONE); - status = hymutex_create(&TM_START_LOCK, TM_MUTEX_NESTED); - assert (status == TM_ERROR_NONE); - status = hymutex_create(&FAT_MONITOR_TABLE_LOCK, TM_MUTEX_NESTED); - assert (status == TM_ERROR_NONE); - apr_status = apr_threadkey_private_create(&TM_THREAD_KEY, NULL, TM_POOL); - assert(apr_status == APR_SUCCESS); - status = init_group_list(); - assert (status == TM_ERROR_NONE); + + apr_status = apr_initialize(); + assert(apr_status == APR_SUCCESS); + apr_status = apr_pool_create(&TM_POOL, NULL); + assert(apr_status == APR_SUCCESS); + + apr_status = apr_threadkey_private_create(&TM_THREAD_KEY, NULL, TM_POOL); + assert(apr_status == APR_SUCCESS); + + status = hymutex_create(&TM_LOCK, TM_MUTEX_NESTED); + assert (status == TM_ERROR_NONE); + status = hymutex_create(&TM_START_LOCK, TM_MUTEX_NESTED); + assert (status == TM_ERROR_NONE); + status = hymutex_create(&FAT_MONITOR_TABLE_LOCK, TM_MUTEX_NESTED); + assert (status == TM_ERROR_NONE); + + status = init_group_list(); + assert (status == TM_ERROR_NONE); // Create default group - hosts any thread crated with NULL group status = hythread_group_create(&TM_DEFAULT_GROUP); @@ -125,6 +131,9 @@ void VMCALL hythread_init(hythread_libra status = hycond_create(&nondaemon_thread_cond); assert (status == TM_ERROR_NONE); + lock_table = (hythread_monitor_t *)malloc(sizeof(hythread_monitor_t)*table_size); + assert(lock_table); + // init global monitor status=hythread_monitor_init_with_name(&p_global_monitor, 0, "Thread Global Monitor"); assert (status == TM_ERROR_NONE); @@ -174,8 +183,7 @@ IDATA VMCALL hythread_global_unlock() { return hymutex_unlock(TM_LOCK); } -/* - */ + IDATA increase_nondaemon_threads_count() { IDATA status; @@ -186,8 +194,7 @@ IDATA increase_nondaemon_threads_count() status = hymutex_unlock(TM_LOCK); return status; } -/* - */ + IDATA countdown_nondaemon_threads() { IDATA status; @@ -236,14 +243,10 @@ IDATA VMCALL hythread_wait_for_all_nonda return status; } -/* - */ hythread_group_t get_java_thread_group(void){ return TM_DEFAULT_GROUP; } -/* - */ static IDATA init_group_list() { // Initial group, does not contain any actual group, but serves //as a head and a tail of this list; @@ -261,8 +264,6 @@ static IDATA init_group_list() { return TM_ERROR_NONE; } -/* - */ static IDATA destroy_group_list() { hythread_group_t cur; IDATA status,status2; @@ -287,14 +288,10 @@ static IDATA destroy_group_list() { return status; } -/* - */ IDATA acquire_start_lock() { return hymutex_lock(TM_START_LOCK); } -/* - */ IDATA release_start_lock() { return hymutex_unlock(TM_START_LOCK); } @@ -307,7 +304,7 @@ IDATA release_start_lock() { */ #define TABLE_SIZE 256 char *names [TABLE_SIZE]; -unsigned data [TABLE_SIZE]; +UDATA data [TABLE_SIZE]; int size = 0; /* diff --git vm/thread/src/thread_java_basic.c vm/thread/src/thread_java_basic.c index 07ecac1..10c9f81 100644 --- vm/thread/src/thread_java_basic.c +++ vm/thread/src/thread_java_basic.c @@ -469,10 +469,9 @@ IDATA jthread_exception_stop(jthread jav IDATA status; JNIEnv* env; - tm_native_thread = jthread_get_native_thread(java_thread); - - hythread_suspend_other(tm_native_thread); - + tm_native_thread = jthread_get_native_thread(java_thread); + status=hythread_suspend_other(tm_native_thread); + if (status != TM_ERROR_NONE) return status; tm_java_thread = hythread_get_private_data(tm_native_thread); // Install safepoint callback that would throw exception diff --git vm/thread/src/thread_java_iterator.c vm/thread/src/thread_java_iterator.c index ed4d0b1..dacb9b9 100644 --- vm/thread/src/thread_java_iterator.c +++ vm/thread/src/thread_java_iterator.c @@ -81,7 +81,7 @@ jthread VMCALL jthread_iterator_next(jth * * @param[in] iterator */ -int32 VMCALL jthread_iterator_size(jthread_iterator_t iterator) { +IDATA VMCALL jthread_iterator_size(jthread_iterator_t iterator) { jthread res; IDATA status; int count=0; diff --git vm/thread/src/thread_java_suspend.c vm/thread/src/thread_java_suspend.c index 2e44a62..cabadab 100644 --- vm/thread/src/thread_java_suspend.c +++ vm/thread/src/thread_java_suspend.c @@ -82,8 +82,8 @@ IDATA VMCALL jthread_resume_all(jvmtiErr */ IDATA VMCALL jthread_suspend(jthread java_thread) { hythread_t tm_native_thread = vm_jthread_get_tm_data(java_thread); - hythread_suspend_other(tm_native_thread); - return TM_ERROR_NONE; + return hythread_suspend_other(tm_native_thread); + } /** diff --git vm/thread/src/thread_native_basic.c vm/thread/src/thread_native_basic.c index 8a6efb7..e5cfad2 100644 --- vm/thread/src/thread_native_basic.c +++ vm/thread/src/thread_native_basic.c @@ -316,17 +316,20 @@ #ifdef APR_TLS_USE * @see hythread_attach * */ -extern "C" hythread_t hythread_self() { hythread_t thread; apr_status_t UNUSED apr_status; // Extract hythread_t from TLS - apr_status = apr_threadkey_private_get((void **)(&thread), TM_THREAD_KEY); + apr_status = apr_threadkey_private_get((void **)(&thread), TM_THREAD_KEY); assert(apr_status == APR_SUCCESS); return thread; } + +static void thread_set_self(hythread_t thread) { + apr_threadkey_private_set(thread, TM_THREAD_KEY); +} #else #ifdef FS14_TLS_USE /** @@ -374,13 +377,15 @@ static void thread_set_self(hythread_t #endif #endif -/* - */ IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable) { IDATA status; hythread_t thread = tm_self_tls; + if(nanos == 0 && millis == 0) { + hythread_yield(); + return TM_ERROR_NONE; + } // Report error in case current thread is not attached if (!thread) return TM_ERROR_UNATTACHED_THREAD; @@ -413,7 +418,7 @@ IDATA VMCALL hythread_sleep_interruptabl * * @see hythread_sleep_interruptable */ -IDATA VMCALL hythread_sleep(int64 millis) { +IDATA VMCALL hythread_sleep(I_64 millis) { return thread_sleep_impl(millis, 0, WAIT_NONINTERRUPTABLE); } @@ -489,7 +494,7 @@ IDATA thread_destroy(hythread_t thread) thread->next->prev = thread->prev; thread->group->threads_count--; - fast_thread_array[thread->thread_id] = NULL; + //fast_thread_array[thread->thread_id] = NULL; status =hythread_global_unlock(NULL); if (status != TM_ERROR_NONE) return status; @@ -706,7 +711,7 @@ static void* APR_THREAD_FUNC thread_star // Cleanup TLS after thread completes thread_set_self(NULL); - return (void *)apr_thread_exit(thd, APR_SUCCESS); + return (void *)(IDATA)apr_thread_exit(thd, APR_SUCCESS); } apr_pool_t* get_local_pool() { diff --git vm/thread/src/thread_native_condvar.c vm/thread/src/thread_native_condvar.c index 62ac394..aceb866 100644 --- vm/thread/src/thread_native_condvar.c +++ vm/thread/src/thread_native_condvar.c @@ -46,8 +46,6 @@ IDATA VMCALL hycond_create (hycond_t *co return TM_ERROR_NONE; } -/* - */ IDATA condvar_wait_impl(hycond_t cond, hymutex_t mutex, I_64 ms, IDATA nano, IDATA interruptable) { apr_status_t apr_status; int disable_count; diff --git vm/thread/src/thread_native_groups.c vm/thread/src/thread_native_groups.c old mode 100644 new mode 100755 index 8574de4..0c5ebb4 --- vm/thread/src/thread_native_groups.c +++ vm/thread/src/thread_native_groups.c @@ -28,7 +28,7 @@ #include <open/hythread_ext.h> #include "thread_private.h" extern hythread_group_t group_list; // list of thread groups -extern int groups_count; // number of thread groups +extern IDATA groups_count; // number of thread groups /** @name Thread groups support @@ -80,6 +80,7 @@ IDATA VMCALL hythread_group_create(hythr (*group)->threads_count = 0; groups_count++; + status=hythread_global_unlock(); return status; @@ -113,28 +114,28 @@ IDATA VMCALL hythread_group_release(hyth * @param[out] list thread group array * @param[out] size array size */ -IDATA VMCALL hythread_group_get_list(hythread_group_t **list, int* size) { - hythread_group_t cur; - int i=0; - hythread_group_t *array_for_list; - IDATA status; - status=hythread_global_lock(); - if (status != TM_ERROR_NONE) - return status; - (*size) = groups_count; - array_for_list=(hythread_group_t*)malloc(sizeof(hythread_group_t)*groups_count); - if(array_for_list==NULL) - { - status=hythread_global_unlock(); - return TM_ERROR_OUT_OF_MEMORY; - } - for (cur = group_list->next; cur != group_list; cur = cur->next) - { - array_for_list[i++]=cur; - } - (*list)=array_for_list; - status=hythread_global_unlock(); - return status; + IDATA VMCALL hythread_group_get_list(hythread_group_t **list, int* size) { + hythread_group_t cur; + int i=0; + hythread_group_t *array_for_list; + IDATA status; + status=hythread_global_lock(); + if (status != TM_ERROR_NONE) + return status; + (*size) = groups_count; + array_for_list=(hythread_group_t*)malloc(sizeof(hythread_group_t)*groups_count); + if(array_for_list==NULL) + { + status=hythread_global_unlock(); + return TM_ERROR_OUT_OF_MEMORY; + } + for (cur = group_list->next; cur != group_list; cur = cur->next) + { + array_for_list[i++]=cur; + } + (*list)=array_for_list; + status=hythread_global_unlock(); + return status; } //@} diff --git vm/thread/src/thread_native_semaphore.c vm/thread/src/thread_native_semaphore.c index fc341de..e5cf15e 100644 --- vm/thread/src/thread_native_semaphore.c +++ vm/thread/src/thread_native_semaphore.c @@ -34,7 +34,7 @@ #include "thread_private.h" * @param[in] initial_count initial semaphore count * @param[in] max_count maximum semaphore count */ -IDATA VMCALL hysem_create(hysem_t *sem, unsigned initial_count, unsigned max_count) { +IDATA VMCALL hysem_create(hysem_t *sem, UDATA initial_count, UDATA max_count) { hysem_t l; apr_pool_t *pool = get_local_pool(); apr_status_t apr_status; @@ -203,7 +203,7 @@ IDATA VMCALL hysem_set(hysem_t sem, IDAT * @param[out] count semaphore count * @param[in] sem semaphore */ -IDATA VMCALL hysem_getvalue(int *count, hysem_t sem) { +IDATA VMCALL hysem_getvalue(IDATA *count, hysem_t sem) { IDATA status; status = hymutex_lock(sem->mutex); diff --git vm/thread/src/thread_native_suspend.c vm/thread/src/thread_native_suspend.c index f9226d0..1768e27 100644 --- vm/thread/src/thread_native_suspend.c +++ vm/thread/src/thread_native_suspend.c @@ -28,12 +28,15 @@ #undef LOG_DOMAIN #define LOG_DOMAIN "tm.suspend" #include <open/hythread_ext.h> +#include <open/thread_externals.h> #include "thread_private.h" -#include "apr_thread_ext.h" - - +#include <apr_atomic.h> +#include <port_atomic.h> static void thread_safe_point_impl(hythread_t thread); +int16 atomic16_inc(int16 *value); +int16 atomic16_dec(int16 *value); + /** @name Safe suspension support */ //@{ @@ -78,12 +81,13 @@ suspended: #else thread=tm_self_tls; thread->suspend_disable_count--; + #endif - if(!thread->suspend_request || thread->suspend_disable_count!=0) { - return; - } + // if(!thread->suspend_request || thread->suspend_disable_count!=0) { + // return; + // } - hylatch_count_down(thread->safe_region_event); + // hylatch_count_down(thread->safe_region_event); } /** @@ -159,7 +163,7 @@ static void thread_safe_point_impl(hythr apr_memory_rw_barrier(); // code for Ipf that support StackIterator and immmediate suspend // notify suspender - hylatch_count_down(thread->safe_region_event); + // hylatch_count_down(thread->safe_region_event); // wait for resume event hysem_wait(thread->resume_event); @@ -177,41 +181,45 @@ static void thread_safe_point_impl(hythr // the function do not suspend self. static void send_suspend_request(hythread_t thread) { - assert(thread->suspend_request >=0); - // already suspended? - if(thread->suspend_request > 0) { - thread->suspend_request++; - return; - } + assert(thread->suspend_request >=0); + // already suspended? + if(thread->suspend_request > 0) { + atomic16_inc((int16 *)&(thread->suspend_request)); + return; + } - //we realy need to suspend thread. + //we realy need to suspend thread. - hysem_set(thread->resume_event, 0); + hysem_set(thread->resume_event, 0); - thread->suspend_request++; - apr_memory_rw_barrier(); - apr_thread_yield_other(thread->os_handle); + atomic16_inc((int16 *)&(thread->suspend_request)); + + apr_thread_yield_other(thread->os_handle); - TRACE(("TM: suspend requiest sent: %p request count: %d",thread , thread->suspend_request)); + TRACE(("TM: suspend requiest sent: %p request count: %d",thread , thread->suspend_request)); } // the second part of suspention // blocked in case was selfsuspended. -static void wait_safe_region_event(hythread_t thread) { - assert(thread->suspend_request >= 1); - if(thread->suspend_request > 1 || thread == tm_self_tls) { - TRACE(("TM: suspend wait self exit thread: %p request count: %d",thread , thread->suspend_request)); - return; - } - +static IDATA wait_safe_region_event(hythread_t thread) { + assert(thread->suspend_request >= 1); + if(thread->suspend_request > 1 || thread == tm_self_tls) { + TRACE(("TM: suspend wait self exit thread: %p request count: %d",thread , thread->suspend_request)); + return TM_ERROR_NONE; + } // we need to wait for notification only in case the thread is in the unsafe/disable region - while (thread->suspend_disable_count) { - // wait for the notification - hylatch_wait_timed(thread->safe_region_event, 50, 0); - } - TRACE(("TM: suspend wait exit safe region thread: %p request count: %d",thread , thread->suspend_request)); - thread->state |= TM_THREAD_STATE_SUSPENDED; + while (thread->suspend_disable_count) { + // HIT cyclic suspend + /*if(tm_self_tls->suspend_request > 1) { + return TM_ERROR_EBUSY; + }*/ + // wait for the notification + return TM_ERROR_EBUSY;//hythread_yield(); + } + TRACE(("TM: suspend wait exit safe region thread: %p request count: %d",thread , thread->suspend_request)); + thread->state |= TM_THREAD_STATE_SUSPENDED; + return TM_ERROR_NONE; } /** @@ -224,11 +232,11 @@ static void wait_safe_region_event(hythr * @see hythread_resume */ void VMCALL hythread_suspend() { - hythread_t self = tm_self_tls; - hythread_global_lock(); - self->suspend_request++; - hythread_global_unlock(); - hythread_safe_point(); + hythread_t thread = tm_self_tls; + + atomic16_inc((int16 *)&(thread->suspend_request)); + + hythread_safe_point(); } @@ -256,31 +264,27 @@ void VMCALL hythread_suspend() { * point where safe suspension is possible. * * @param[in] thread thread to be suspended + * @return TM_ERROR_EBUSY if deadlock, TM_ERROR_NONE if OK */ -void VMCALL hythread_suspend_other(hythread_t thread) { +IDATA VMCALL hythread_suspend_other(hythread_t thread) { hythread_t self; - hythread_global_lock(); self = tm_self_tls; - TRACE(("TM: suspend one enter thread: %p request count: %d",thread , thread->suspend_request)); if(self == thread) { - hythread_global_unlock(); hythread_suspend(); - return; + return TM_ERROR_NONE; } - // try to prevent cyclic suspend dead-lock - //while(self->suspend_request > 0) { - // hythread_global_unlock(); - // thread_safe_point_impl(self); - // hythread_global_lock(); - //} - send_suspend_request(thread); - wait_safe_region_event(thread); - hythread_global_unlock(); + while(wait_safe_region_event(thread)!=TM_ERROR_NONE) { + if(self->suspend_request>0) + { + hythread_resume(thread); + return TM_ERROR_EBUSY; + } + } TRACE(("TM: suspend one exit thread: %p request count: %d",thread , thread->suspend_request)); - return; + return TM_ERROR_NONE; } /** @@ -296,12 +300,12 @@ void VMCALL hythread_suspend_other(hythr * @see hythread_create, hythread_suspend */ void VMCALL hythread_resume(hythread_t thread) { - hythread_global_lock(); TRACE(("TM: start resuming: %p request count: %d",thread , thread->suspend_request)); // If there was request for suspension, decrease the request counter + // printf("resume other now lock %d %d %d %d\n",tm_self_tls->thread_id,tm_self_tls->suspend_disable_count,thread->thread_id,thread->suspend_disable_count); if(thread->suspend_request > 0) { - thread->suspend_request--; - // If no more requests left, thread needs to be resumed + + atomic16_dec((int16 *)&(thread->suspend_request)); if(thread->suspend_request == 0) { // Notify the thread that it may wake up now hysem_post(thread->resume_event); @@ -309,7 +313,7 @@ void VMCALL hythread_resume(hythread_t t thread->state &= ~TM_THREAD_STATE_SUSPENDED; } } - hythread_global_unlock(); + // printf("resume other now lock-compl %d %d %d %d\n",tm_self_tls->thread_id,tm_self_tls->suspend_disable_count,thread->thread_id,thread->suspend_disable_count); } /** @@ -351,15 +355,15 @@ IDATA VMCALL hythread_suspend_all(hythre hythread_t self = tm_self_tls; hythread_t next; hythread_iterator_t iter; - TRACE(("TM: suspend all")); + self = tm_self_tls; // try to prevent cyclic suspend dead-lock while(self->suspend_request > 0) { thread_safe_point_impl(self); } - - iter = hythread_iterator_create(group); + + iter = hythread_iterator_create(group); // send suspend requests to all threads TRACE(("TM: send suspend requests")); while((next = hythread_iterator_next(&iter)) != NULL) { @@ -367,21 +371,26 @@ IDATA VMCALL hythread_suspend_all(hythre send_suspend_request(next); } } - hythread_iterator_reset(&iter); // all threads should be stoped in safepoints or be in safe region. - TRACE(("TM: wait suspend responses")); + TRACE(("TM: wait suspend responses")); while((next = hythread_iterator_next(&iter)) != NULL) { if(next != self) { - wait_safe_region_event(next); + while (wait_safe_region_event(next)!=TM_ERROR_NONE) + { + thread_safe_point_impl(tm_self_tls); + hythread_yield(); + } } } hythread_iterator_reset(&iter); hythread_iterator_release(&iter); - if(t) { + if(t) + { *t=iter; } + return TM_ERROR_NONE; } @@ -395,16 +404,17 @@ IDATA VMCALL hythread_suspend_all(hythre IDATA VMCALL hythread_resume_all(hythread_group_t group) { hythread_t self = tm_self_tls; hythread_t next; - hythread_iterator_t iter = hythread_iterator_create(group); + hythread_iterator_t iter; + iter = hythread_iterator_create(group); TRACE(("TM: resume all")); // send suspend requests to all threads - while((next = hythread_iterator_next(&iter)) != NULL) { - if(next != self) { - hythread_resume(next); - } - } + while((next = hythread_iterator_next(&iter)) != NULL) { + if(next != self) { + hythread_resume(next); + } + } - hythread_iterator_release(&iter); + hythread_iterator_release(&iter); return TM_ERROR_NONE; } @@ -416,19 +426,38 @@ int reset_suspend_disable() { int dis = self->suspend_disable_count; self->suspend_disable_count = 0; if(self->suspend_request >0) { - // notify suspender - hylatch_count_down(self->safe_region_event); - } + // notify suspender + hylatch_count_down(self->safe_region_event); + } return dis; } void set_suspend_disable(int count) { - hythread_t self = tm_self_tls; - assert(count>=0); + hythread_t self = tm_self_tls; + assert(count>=0); self->suspend_disable_count = count; - if(count) { - thread_safe_point_impl(self); - } + if(count) { + thread_safe_point_impl(self); + } +} +int16 atomic16_inc(int16 *value) +{ + int16 old_value=*value; + while(port_atomic_cas16((volatile apr_uint16_t*)value,(apr_uint16_t)(old_value+1),(apr_uint16_t)old_value)!=old_value) + { + old_value=*value; + } + + return old_value+1; +} +int16 atomic16_dec(int16 *value) +{ + int16 old_value=*value; + while(port_atomic_cas16((volatile apr_uint16_t*)value,(apr_uint16_t)(old_value-1),(apr_uint16_t)old_value)!=old_value) + { + old_value=*value; + } + return old_value-1; } diff --git vm/thread/src/thread_native_thin_monitor.c vm/thread/src/thread_native_thin_monitor.c index 63850a7..efa5721 100644 --- vm/thread/src/thread_native_thin_monitor.c +++ vm/thread/src/thread_native_thin_monitor.c @@ -61,14 +61,19 @@ #define RECURSION_INC(lockword_ptr, lock #define RECURSION_DEC(lockword_ptr, lockword) (*lockword_ptr=lockword - (1<<11)) #define MAX_RECURSION 31 -IDATA owns_thin_lock(hythread_t thread, IDATA lockword) { +IDATA owns_thin_lock(hythread_t thread, I_32 lockword) { IDATA this_id = thread->thread_id; assert(!IS_FAT_LOCK(lockword)); - return THREAD_ID(lockword) == this_id; +#ifdef LOCK_RESERVATION + return THREAD_ID(lockword) == this_id + && (!IS_RESERVED(lockword) || RECURSION(lockword) !=0); +#else + return THREAD_ID(lockword) == this_id; +#endif } void set_fat_lock_id(hythread_thin_monitor_t *lockword_ptr, IDATA monitor_id) { - IDATA lockword = *lockword_ptr; + I_32 lockword = *lockword_ptr; #ifdef LOCK_RESERVATION assert(!IS_RESERVED(lockword)); #endif @@ -107,9 +112,9 @@ extern hymutex_t TM_LOCK; /* * Unreserves the lock already owned by this thread */ -void unreserve_self_lock(IDATA* lockword_ptr) { - IDATA lockword = *lockword_ptr; - IDATA lockword_new; +void unreserve_self_lock(hythread_thin_monitor_t *lockword_ptr) { + I_32 lockword = *lockword_ptr; + I_32 lockword_new; TRACE(("unreserve self_id %d lock owner %d", hythread_get_id(hythread_self()), THREAD_ID(lockword))); assert(hythread_get_id(hythread_self()) == THREAD_ID(lockword)); assert (!IS_FAT_LOCK(*lockword_ptr)); @@ -121,8 +126,8 @@ void unreserve_self_lock(IDATA* lockword if (RECURSION(lockword_new) != 0) { RECURSION_DEC(lockword_ptr, lockword_new); } else { - lockword_new = lockword_new & 0x0000ffff; - *lockword_ptr =lockword_new; + lockword_new = lockword_new & 0x0000ffff; + *lockword_ptr = lockword_new; } assert(!IS_RESERVED(*lockword_ptr)); TRACE(("unreserved self")); @@ -131,23 +136,28 @@ void unreserve_self_lock(IDATA* lockword /* * Used lockword */ -IDATA unreserve_lock(IDATA* lockword_ptr) { - IDATA lockword = *lockword_ptr; - IDATA lockword_new; - IDATA lock_id = THREAD_ID(lockword); +IDATA unreserve_lock(hythread_thin_monitor_t *lockword_ptr) { + I_32 lockword = *lockword_ptr; + I_32 lockword_new; + uint16 lock_id; hythread_t owner; IDATA status; // trylock used to prevent cyclic suspend deadlock // the java_monitor_enter calls safe_point between attempts. - status = hymutex_trylock(TM_LOCK); + /* status = hymutex_trylock(TM_LOCK); if(status !=TM_ERROR_NONE) { return status; + }*/ + + if(IS_FAT_LOCK(lockword)) + { + return TM_ERROR_NONE; } + lock_id = THREAD_ID(lockword); owner = hythread_get_thread(lock_id); TRACE(("Unreaserve other %d \n", ++unreserve_count/*, vm_get_object_class_name(lockword_ptr-1)*/)); - lockword = * lockword_ptr; - if(!IS_RESERVED(lockword)) { - hymutex_unlock(TM_LOCK); + if(!IS_RESERVED(lockword) || IS_FAT_LOCK(lockword)) { + // hymutex_unlock(TM_LOCK); return TM_ERROR_NONE; } // suspend owner @@ -155,8 +165,11 @@ IDATA unreserve_lock(IDATA* lockword_ptr assert(owner); assert(hythread_get_id(owner) == lock_id); assert(owner != hythread_self()); - hythread_suspend_other(owner); - } + status=hythread_suspend_other(owner); + if(status !=TM_ERROR_NONE) { + return status; + } + } // prepare new unreserved lockword and try to CAS it with old one. while (IS_RESERVED(lockword)) { assert (!IS_FAT_LOCK(lockword)); @@ -183,12 +196,12 @@ IDATA unreserve_lock(IDATA* lockword_ptr hythread_resume(owner); } - status = hymutex_unlock(TM_LOCK); + /* status = hymutex_unlock(TM_LOCK);*/ assert(!IS_RESERVED(*lockword_ptr)); - return status; + return TM_ERROR_NONE; } #else -IDATA unreserve_lock(IDATA* lockword_ptr) { +IDATA unreserve_lock(I_32* lockword_ptr) { return TM_ERROR_NONE; } #endif @@ -214,7 +227,7 @@ IDATA hythread_thin_monitor_create(hythr * @param[in] lockword_ptr monitor addr */ IDATA hythread_thin_monitor_try_enter(hythread_thin_monitor_t *lockword_ptr) { - IDATA lockword; + I_32 lockword; // warkaround strange intel compiler bug #if defined (__INTEL_COMPILER) && defined (LINUX) volatile @@ -227,7 +240,6 @@ IDATA hythread_thin_monitor_try_enter(hy assert (!hythread_is_suspend_enabled()); assert((UDATA)lockword_ptr > 4); assert(tm_self_tls); - lockword = *lockword_ptr; lock_id = THREAD_ID(lockword); //TRACE(("try lock %x %d", this_id, RECURSION(lockword))); @@ -262,6 +274,7 @@ #endif // Acquire monitor if (0 != port_atomic_cas16 (((volatile apr_uint16_t*) lockword_ptr)+1, (apr_uint16_t) this_id, 0)) { + #ifdef SPIN_COUNT continue; #else @@ -361,7 +374,7 @@ IDATA hythread_thin_monitor_enter(hythre * @param[in] lockword_ptr monitor addr */ IDATA VMCALL hythread_thin_monitor_exit(hythread_thin_monitor_t *lockword_ptr) { - IDATA lockword = *lockword_ptr; + I_32 lockword = *lockword_ptr; hythread_monitor_t fat_monitor; IDATA this_id = tm_self_tls->thread_id; // obtain current thread id assert(this_id > 0 && this_id < 0xffff); @@ -396,7 +409,7 @@ #endif IDATA thin_monitor_wait_impl(hythread_thin_monitor_t *lockword_ptr, I_64 ms, IDATA nano, IDATA interruptable) { // get this thread hythread_t this_thread = tm_self_tls; - IDATA lockword = *lockword_ptr; + I_32 lockword = *lockword_ptr; hythread_monitor_t fat_monitor; if (!IS_FAT_LOCK(lockword)) { @@ -536,7 +549,7 @@ hythread_monitor_t VMCALL inflate_lock(h hythread_monitor_t fat_monitor; IDATA status; IDATA fat_monitor_id; - IDATA lockword; + I_32 lockword; int i; status=hymutex_lock(FAT_MONITOR_TABLE_LOCK); assert (status == TM_ERROR_NONE); @@ -616,8 +629,8 @@ void deflate_lock(hythread_monitor_t fat //FIXME: make table resizable, implement delete -int table_size=8024; -static hythread_monitor_t lock_table[8024]; +extern int table_size; +extern hythread_monitor_t *lock_table; int fat_monitor_count = 1; // Lock table implementation @@ -643,7 +656,15 @@ IDATA locktable_put_fat_monitor(hythread int id; //hythread_global_lock(); id = fat_monitor_count++; - assert(id >=0 && id < table_size); + if (id >= table_size) { + hythread_suspend_all(NULL, NULL); + table_size = table_size*2; + lock_table = (hythread_monitor_t *)realloc(lock_table, sizeof(hythread_monitor_t)*table_size); + assert(lock_table); + apr_memory_rw_barrier(); + hythread_resume_all(NULL); + } + lock_table[id] = fat_monitor; //hythread_global_unlock(); return id; @@ -667,7 +688,7 @@ hythread_monitor_t locktable_delete_ent * @param[in] lockword_ptr monitor addr */ hythread_t VMCALL hythread_thin_monitor_get_owner(hythread_thin_monitor_t *lockword_ptr) { - IDATA lockword; + I_32 lockword; hythread_monitor_t fat_monitor; assert(lockword_ptr); @@ -685,7 +706,7 @@ hythread_t VMCALL hythread_thin_monitor_ * @param[in] lockword_ptr monitor addr */ IDATA VMCALL hythread_thin_monitor_get_recursion(hythread_thin_monitor_t *lockword_ptr) { - IDATA lockword; + I_32 lockword; hythread_monitor_t fat_monitor; assert(lockword_ptr); diff --git vm/thread/src/thread_private.h vm/thread/src/thread_private.h index def38e5..513dbf5 100644 --- vm/thread/src/thread_private.h +++ vm/thread/src/thread_private.h @@ -49,20 +49,26 @@ #define CONVERT_ERROR(stat) (stat) #define MAX_OWNED_MONITOR_NUMBER 200 //FIXME: switch to dynamic resize #define FAST_LOCAL_STORAGE_SIZE 10 +#if !defined (_EM64T_) && !defined (_IPF_) //use lock reservation #define LOCK_RESERVATION // spin with try_lock SPIN_COUNT times #define SPIN_COUNT 5 -//use optimized asm monitor enter and exit -#define ASM_MONITOR_HELPER +#endif //!defined (_EM64T_) && !defined (_IPF_) -// TLS access options #ifdef WIN32 +//use optimized asm monitor enter and exit helpers +#define ASM_MONITOR_HELPER +// FS14_TLS_USE define turns on windows specific TLS access optimization +// We use free TIB slot with 14 offset, see following article for details +// http://www.microsoft.com/msj/archive/S2CE.aspx #define FS14_TLS_USE #endif -//#define APR_TLS_USE +#ifdef _EM64T_ +#define APR_TLS_USE +#endif #ifdef __cplusplus @@ -70,12 +76,15 @@ extern "C" { #endif /* __cplusplus */ // optimization code #if !defined (APR_TLS_USE ) && !defined (FS14_TLS_USE) + #ifdef PLATFORM_POSIX extern __thread hythread_t tm_self_tls; #else extern __declspec(thread) hythread_t tm_self_tls; -#endif +#endif //PLATFORM_POSIX + #else +#if defined (WIN32) && defined (FS14_TLS_USE) __forceinline hythread_t tmn_self_macro() { register hythread_t t; @@ -88,8 +97,13 @@ __forceinline hythread_t tmn_self_macro( #define store_tm_self(self) (__asm(mov self, fs:[0x14])) #define tm_self_tls (tmn_self_macro()) +#endif + #endif +#ifdef APR_TLS_USE +#define tm_self_tls (hythread_self()) +#endif /** * get_local_pool() function return apr pool asociated with the current thread. @@ -151,7 +165,11 @@ typedef struct HyThread { /** * Number of suspend requests made for this thread. */ - IDATA suspend_request; + int32 suspend_request; + /** + * Field reserved for JIT proprietary needs. + */ + int32 jit_private_data; /** * Flag indicating that thread can safely be suspended. @@ -536,7 +554,7 @@ typedef struct HySemaphore { // Global variables extern hythread_group_t group_list; // list of thread groups -extern int groups_count; // number of thread groups +extern IDATA groups_count; // number of thread groups extern apr_pool_t *TM_POOL; //global APR pool for thread manager @@ -565,11 +583,11 @@ void set_suspend_disable(int count); /* thin monitor functions used java monitor */ IDATA is_fat_lock(hythread_thin_monitor_t lockword); -IDATA owns_thin_lock(hythread_t thread, IDATA lockword); +IDATA owns_thin_lock(hythread_t thread, I_32 lockword); hythread_monitor_t inflate_lock(hythread_thin_monitor_t *lockword_ptr); -IDATA unreserve_lock(IDATA *lockword_ptr); - +IDATA unreserve_lock(hythread_thin_monitor_t *lockword_ptr); +IDATA VMCALL hythread_get_group(hythread_group_t *group, hythread_t thread); /** * Auxiliary function to throw java.lang.InterruptedException */ @@ -596,7 +614,7 @@ IDATA acquire_start_lock(void); IDATA release_start_lock(void); IDATA thread_destroy(hythread_t thread); -IDATA VMCALL hythread_get_group(hythread_group_t *group, hythread_t thread); + IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable); IDATA condvar_wait_impl(hycond_t cond, hymutex_t mutex, I_64 ms, IDATA nano, IDATA interruptable); IDATA monitor_wait_impl(hythread_monitor_t mon_ptr, I_64 ms, IDATA nano, IDATA interruptable); diff --git vm/thread/src/thread_ti_instr.c vm/thread/src/thread_ti_instr.c index 73d5373..ac6185b 100644 --- vm/thread/src/thread_ti_instr.c +++ vm/thread/src/thread_ti_instr.c @@ -303,7 +303,6 @@ IDATA VMCALL jthread_get_state(jthread j tm_native_thread = vm_jthread_get_tm_data(java_thread); *state = 0; - if (! tm_native_thread) return TM_ERROR_NONE; // Not started yet if (hythread_is_alive(tm_native_thread)) {*state |= JVMTI_THREAD_STATE_ALIVE;} @@ -318,6 +317,7 @@ IDATA VMCALL jthread_get_state(jthread j if (hythread_is_suspended(tm_native_thread)) {*state |= JVMTI_THREAD_STATE_SUSPENDED;} if (hythread_interrupted(tm_native_thread)) {*state |= JVMTI_THREAD_STATE_INTERRUPTED;} if (hythread_is_in_native(tm_native_thread)) {*state |= JVMTI_THREAD_STATE_IN_NATIVE;} + if (hythread_is_terminated(tm_native_thread)) {*state |= JVMTI_THREAD_STATE_TERMINATED;} return TM_ERROR_NONE; } @@ -466,8 +466,8 @@ IDATA VMCALL jthread_get_lock_recursion( IDATA recursion = 0; assert(monitor); - hythread_suspend_disable(); given_thread = owner?vm_jthread_get_tm_data(owner):NULL; + hythread_suspend_disable(); lockword = vm_object_get_lockword_addr(monitor); lock_owner = hythread_thin_monitor_get_owner(lockword); diff --git vm/thread/src/thread_ti_monitors.c vm/thread/src/thread_ti_monitors.c index a21907f..ac3452f 100644 --- vm/thread/src/thread_ti_monitors.c +++ vm/thread/src/thread_ti_monitors.c @@ -169,7 +169,7 @@ IDATA VMCALL jthread_raw_monitor_exit(jr * TM_ERROR_INTERRUPT wait was interrupted * TM_ERROR_INVALID_MONITOR current thread isn't the owner */ -IDATA VMCALL jthread_raw_monitor_wait(jrawMonitorID mon_ptr, int64 millis) { +IDATA VMCALL jthread_raw_monitor_wait(jrawMonitorID mon_ptr, I_64 millis) { hythread_monitor_t monitor; if (!(monitor = (hythread_monitor_t)array_get(jvmti_monitor_table, (UDATA)mon_ptr))) { return TM_ERROR_INVALID_MONITOR; diff --git vm/thread/src/thread_ti_timing.c vm/thread/src/thread_ti_timing.c index 2063f43..0171fdf 100644 --- vm/thread/src/thread_ti_timing.c +++ vm/thread/src/thread_ti_timing.c @@ -59,16 +59,10 @@ IDATA VMCALL jthread_get_thread_blocked_ IDATA VMCALL jthread_get_thread_cpu_time(jthread java_thread, jlong *nanos_ptr) { hythread_t tm_native_thread; - apr_time_t kernel_time; - apr_time_t user_time; - - assert(java_thread); - assert(nanos_ptr); - tm_native_thread = vm_jthread_get_tm_data(java_thread); - apr_thread_times(tm_native_thread->os_handle, &user_time, &kernel_time); - *nanos_ptr = kernel_time + user_time; - - return TM_ERROR_NONE; + assert(java_thread); + assert(nanos_ptr); + tm_native_thread = vm_jthread_get_tm_data(java_thread); + return CONVERT_ERROR(apr_get_thread_time(tm_native_thread->os_handle,nanos_ptr)); } /** diff --git vm/vmcore/include/Class.h vm/vmcore/include/Class.h index 4c452bd..7dd4df6 100644 --- vm/vmcore/include/Class.h +++ vm/vmcore/include/Class.h @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Pavel Pervov * @version $Revision: 1.1.2.7.2.1.2.5 $ - */ + */ #ifndef _CLASS_H_ #define _CLASS_H_ /** @@ -70,7 +70,7 @@ union Const_Java_Value { double d; String *string; void *object; - Const_Java_Value() {l.lo_bytes=l.hi_bytes=0;} + //Const_Java_Value() {l.lo_bytes=l.hi_bytes=0;} }; @@ -120,6 +120,49 @@ #define STORE_GLOBAL_REFERENCE(SLOT_ADDR /////////////////////////////////////////////////////////////////////////////// +// class file attributes +/////////////////////////////////////////////////////////////////////////////// +enum Attributes { + ATTR_SourceFile, // Class (no more than 1 in each class file) + ATTR_InnerClasses, // Class + ATTR_ConstantValue, // Field (no more than 1 for each field) + ATTR_Code, // Method + ATTR_Exceptions, // Method + ATTR_LineNumberTable, // Code + ATTR_LocalVariableTable, // Code + ATTR_Synthetic, // Class/Field/Method + ATTR_Deprecated, // Class/Field/Method + ATTR_SourceDebugExtension, // Class (no more than 1 in each class file) + ATTR_Signature, // Class/Field/Method (spec does not limit number???) + ATTR_EnclosingMethod, // Class (1 at most) + ATTR_LocalVariableTypeTable, // Code + ATTR_RuntimeVisibleAnnotations, // Class/Field/Method (at most 1 per entity) + ATTR_RuntimeInvisibleAnnotations, // Class/Field/Method + ATTR_RuntimeVisibleParameterAnnotations, // Method + ATTR_RuntimeInvisibleParameterAnnotations, // Method + ATTR_AnnotationDefault, // Method (spec does not limit number???) + N_ATTR, + ATTR_UNDEF, + ATTR_ERROR +}; + +#define N_COMMON_ATTR 5 +#define N_FIELD_ATTR 1 +#define N_METHOD_ATTR 5 +#define N_CODE_ATTR 3 +#define N_CLASS_ATTR 4 + +// +// magic number, and major/minor version numbers of class file +// +#define CLASSFILE_MAGIC 0xCAFEBABE +#define CLASSFILE_MAJOR 45 +// Supported class files up to this version +#define CLASSFILE_MAJOR_MAX 49 +#define CLASSFILE_MINOR 3 + + +/////////////////////////////////////////////////////////////////////////////// // Constant pool entries. /////////////////////////////////////////////////////////////////////////////// @@ -160,7 +203,7 @@ union Const_Pool { uint32 int_value; // CONSTANT_Integer float float_value; // CONSTANT_Float struct { - uint32 low_bytes; // each Const_Pool element is 64bit in this case + uint32 low_bytes; // each Const_Pool element is 64bit in this case uint32 high_bytes; // we pack all 8 bytes of long/double in one // Const_Pool element (and leave the second // Const_Pool element of the long/double unused) @@ -177,7 +220,82 @@ union Const_Pool { } CONSTANT_Utf8; }; +enum AnnotationValueType { + // 'B', 'C', 'D', 'F', 'I', 'J', 'S', and 'Z' 's' 'e' 'c' '@' '[' + AVT_BYTE = 'B', + AVT_CHAR = 'C', + AVT_DOUBLE = 'D', + AVT_FLOAT = 'F', + AVT_INT = 'I', + AVT_LONG = 'J', + AVT_SHORT = 'S', + AVT_BOOLEAN = 'Z', + AVT_STRING = 's', + AVT_ENUM = 'e', + AVT_CLASS = 'c', + AVT_ANNOTN = '@', + AVT_ARRAY = '[' +}; +struct Annotation; // forward declaration + +// element-value pair of an annotation +struct AnnotationValue { + union { + Const_Java_Value const_value; + String* class_name; + Annotation * nested; + struct { + String* type; + String* name; + } enum_const; + struct { + AnnotationValue* items; + uint16 length; + } array; + }; + AnnotationValueType tag; +}; + +struct AnnotationElement { + String* name; + AnnotationValue value; +}; + +struct Annotation { + String* type; + AnnotationElement* elements; + uint16 num_elements; +}; + +struct AnnotationTable { + uint16 length; + Annotation * table[1]; +}; + +struct Line_Number_Entry { + uint16 start_pc; + uint16 line_number; +}; + +struct Line_Number_Table { + uint16 length; + Line_Number_Entry table[1]; +}; + +struct Local_Var_Entry { + uint16 start_pc; + uint16 length; + uint16 index; + String* name; + String* type; + String* generic_type; +}; + +struct Local_Var_Table { + uint16 length; + Local_Var_Entry table[1]; +}; /////////////////////////////////////////////////////////////////////////////// @@ -266,7 +384,7 @@ #endif // POINTER64 #define GC_BYTES_IN_VTABLE (sizeof(void *)) typedef struct VTable { - + Byte _gc_private_information[GC_BYTES_IN_VTABLE]; Class *clss; // the class - see above before change @@ -346,7 +464,8 @@ typedef struct Class { }; const String * name; // class name in internal (VM, class-file) format - String * java_name; // class canonical (Java) name + //String * java_name; // class canonical (Java) name + String * Signature; // generic type information (since 1.5) // // See the masks in vm_for_gc.h. @@ -361,7 +480,7 @@ typedef struct Class { unsigned int allocated_size; unsigned int array_element_size; - + ///////////////////////////////////////////////////////////////////// //////// Fields above this point can not be moved without redefining @@ -426,13 +545,13 @@ typedef struct Class { // // number of dimensions in array; current VM limitation is 255 // - // Note, that you can derive the base component type of the array + // Note, that you can derive the base component type of the array // by looking at name->bytes[n_dimensions]. // unsigned char n_dimensions; // - // for non-primitive arrays only, array_base_class is the base class + // for non-primitive arrays only, array_base_class is the base class // of an array // Class *array_base_class; @@ -448,11 +567,17 @@ typedef struct Class { uint16 n_static_fields; uint16 n_methods; - // for inner class support + // for inner class support uint16 declaringclass_index; + uint16 enclosing_class_index; + uint16 enclosing_method_index; uint16 n_innerclasses; uint16 *innerclass_indexes; + // simple name of the class as given in the source code + // empty string if anonymous + String * simple_name; + Const_Pool *const_pool; // constant pool array; size is cp_size Field *fields; // array of fields; size is n_fields Method *methods; // array of methods; size is n_methods @@ -464,14 +589,15 @@ typedef struct Class { // Class_Superinterface *superinterfaces; - const String *class_file_name; // string name of file from which + const String *class_file_name; // string name of file from which // this class has been loaded - const String *src_file_name; // string name of file from which + const String *src_file_name; // string name of file from which // this class has been compiled Class_State state; // state of this class Package *package; // package to which this class belongs + bool deprecated; // // the following sizes are all in bytes // @@ -496,15 +622,15 @@ typedef struct Class { unsigned char **static_method_block; // array of pointers to code of // static methods - // This is the size of an instance without any alignment padding. + // This is the size of an instance without any alignment padding. // It can be used while calculating the field offsets of subclasses. // It does not include the OBJECT_HEADER_SIZE but does include the // OBJECT_VTABLE_POINTER_SIZE. // The allocated_size field will be this field properly aligned. unsigned unpadded_instance_data_size; - // Size of java/lang/Class instances in bytes. This variable is used during bootstrapping to allocate - // the three classes (i.e. Class instances) loaded before java.lang.Class: java.lang.Object, + // Size of java/lang/Class instances in bytes. This variable is used during bootstrapping to allocate + // the three classes (i.e. Class instances) loaded before java.lang.Class: java.lang.Object, // java.io.Serializable and java.lang.Class. //static unsigned sizeof_class_class; @@ -513,11 +639,11 @@ typedef struct Class { // // The next to high bit is set if allocation needs to consider class_properties. // (mumble->instance_data_size & NEXT_TO_HIGH_BIT_CLEAR_MASK) will always return the - // actual size of and instance of class mumble. + // actual size of and instance of class mumble. // Use get_instance_data_size() to get the actual size of an instance. // Use set_instance_data_size_constraint_bit() to set this bit. - unsigned instance_data_size; // For most classes the size of a class instance's + unsigned instance_data_size; // For most classes the size of a class instance's // data block. This is what is passed to the GC. // See above for details. // ppervov: FIXME: the next two should be joined into a union @@ -562,7 +688,7 @@ #ifdef VM_STATS uint64 num_bytes_allocated; #endif - // Number of "padding" bytes curently added per class instance to its fields to + // Number of "padding" bytes curently added per class instance to its fields to // make each field at least 32 bits. uint32 num_field_padding_bytes; @@ -571,12 +697,12 @@ #endif // and the num_field_padding_bytes field will reflect those alignment padding bytes. static bool compact_fields; - // If set true by the "-sort_fields" command line option, the VM will sort fields by size before + // If set true by the "-sort_fields" command line option, the VM will sort fields by size before // assigning their offset during class preparation. static bool sort_fields; // Notify JITs whenever this class is extended by calling their JIT_extended_class_callback callback function, - Class_Extended_Notification_Record *notify_extended_records; + Class_Extended_Notification_Record *notify_extended_records; int depth; // The field is_suitable_for_fast_instanceof should be 0 if depth==0 or depth>=vm_max_fast_instanceof_depth() @@ -596,7 +722,7 @@ #endif static Byte *managed_null; //#ifdef VM_STATS - // 20020923 Total number of allocations and total number of bytes for class-related data structures. + // 20020923 Total number of allocations and total number of bytes for class-related data structures. // This includes any rounding added to make each item aligned (current alignment is to the next 16 byte boundary). // Might need to make these uint64 for some data structures. static unsigned num_statics_allocations; @@ -621,7 +747,7 @@ #endif // class operations lock Lock_Manager* m_lock; - + // List of constant pool entries, which resolution had failed // Required for fast enumeration of error objects Const_Pool* m_failedResolution; @@ -631,6 +757,8 @@ #endif // verify data void *verify_data; + + AnnotationTable * annotations; } Class; // typedef struct Class @@ -653,6 +781,7 @@ void class_set_error_cause(Class *c, jth jthrowable class_get_error_cause(Class *c); String* class_get_java_name(Class* clss, Global_Env* env); +String* class_get_simple_name(Class* clss, Global_Env* env); // // access modifiers // @@ -661,6 +790,7 @@ #define class_is_final(clss) ((cl #define class_is_super(clss) ((clss)->access_flags & ACC_SUPER) #define class_is_interface(clss) ((clss)->access_flags & ACC_INTERFACE) #define class_is_abstract(clss) ((clss)->access_flags & ACC_ABSTRACT) +#define class_is_annotation(clss) ((clss)->access_flags & ACC_ANNOTATION) // // Look up of methods and fields in class. @@ -761,13 +891,13 @@ public: // // access modifiers // - bool is_public() {return (_access_flags&ACC_PUBLIC)?true:false;} - bool is_private() {return (_access_flags&ACC_PRIVATE)?true:false;} - bool is_protected() {return (_access_flags&ACC_PROTECTED)?true:false;} - bool is_static() {return (_access_flags&ACC_STATIC)?true:false;} - bool is_final() {return (_access_flags&ACC_FINAL)?true:false;} + bool is_public() {return (_access_flags&ACC_PUBLIC)?true:false;} + bool is_private() {return (_access_flags&ACC_PRIVATE)?true:false;} + bool is_protected() {return (_access_flags&ACC_PROTECTED)?true:false;} + bool is_static() {return (_access_flags&ACC_STATIC)?true:false;} + bool is_final() {return (_access_flags&ACC_FINAL)?true:false;} bool is_strict() {return (_access_flags&ACC_STRICT)?true:false;} - bool is_synthetic() {return _synthetic;} + bool is_synthetic() {return (_access_flags&ACC_SYNTHETIC)?true:_synthetic;} bool is_deprecated() {return _deprecated;} unsigned get_access_flags() {return _access_flags;} @@ -780,6 +910,9 @@ public: // Get the type descriptor (Sec. 4.3.2) String *get_descriptor() const {return _descriptor;} + String *get_signature() const {return _signature;} + + AnnotationTable* get_declared_annotations() const {return _annotations;} friend void assign_instance_field_offset(Class *clss, Field *field, bool do_field_compaction); friend void assign_offsets_to_static_fields(Class *clss, Field **field_ptrs, bool do_field_compaction); @@ -794,7 +927,7 @@ public: void* Alloc(size_t size); protected: - Class_Member() + Class_Member() { _access_flags = 0; _class = NULL; @@ -804,9 +937,10 @@ #ifdef VM_STATS num_slow_accesses = 0; #endif _synthetic = _deprecated = false; + _annotations = NULL; + _signature = NULL; } - // offset of class member; // for virtual methods, the method's offset within the vtable // for static methods, the method's offset within the class' static method table @@ -814,20 +948,30 @@ #endif // for static data, offset within the class' static data block unsigned _offset; + bool _synthetic; + bool _deprecated; + AnnotationTable * _annotations; uint16 _access_flags; - String *_name; - String *_descriptor; // descriptor - Class *_class; + String * _name; + String * _descriptor; + String * _signature; + Class * _class; + bool parse(Class* clss, Const_Pool* cp, unsigned cp_size, ByteReader& cfs); + /* + * returns ATTR_ERROR if attribute was recognized but parsing failed; + * returns ATTR_UNDEF if attribute was not recognized + * otherwise returns passed attr value + */ + Attributes process_common_attribute(Attributes attr, uint32 attr_len, ByteReader& cfs); + public: #ifdef VM_STATS uint64 num_accesses; uint64 num_slow_accesses; #endif - bool _synthetic; - bool _deprecated; }; // Class_Member @@ -848,7 +992,7 @@ public: // Return the type of this field. Java_Type get_java_type() { - return (Java_Type)(get_descriptor()->bytes[0]); + return (Java_Type)(get_descriptor()->bytes[0]); }; Const_Java_Value get_const_value() { return const_value; }; @@ -861,6 +1005,8 @@ public: _field_type_desc = 0; _offset_computed = 0; _is_injected = 0; + track_access = 0; + track_modification = 0; } void Reset() { } @@ -877,13 +1023,18 @@ public: _descriptor = fd._descriptor; _deprecated = fd._deprecated; _synthetic = fd._synthetic; - + _annotations = fd._annotations; + _signature = fd._signature; + // copy Field fields _const_value_index = fd._const_value_index; _field_type_desc = fd._field_type_desc; _is_injected = fd._is_injected; _offset_computed = fd._offset_computed; const_value = fd.const_value; + track_access = fd.track_access; + track_modification = fd.track_modification; + return *this; } // @@ -891,7 +1042,8 @@ public: // unsigned is_volatile() {return (_access_flags&ACC_VOLATILE);} unsigned is_transient() {return (_access_flags&ACC_TRANSIENT);} - + bool is_enum() {return (_access_flags&ACC_ENUM)?true:false;} + bool parse(Class* clss, Const_Pool* cp, unsigned cp_size, ByteReader& cfs); unsigned calculate_size() { @@ -906,10 +1058,28 @@ public: Boolean is_injected() {return _is_injected;} void set_injected() { _is_injected = 1; } + void set_track_access(bool value) { + track_access = value ? 1 : 0 ; + } + + void set_track_modification(bool value) { + track_modification = value ? 1 : 0 ; + } + + void get_track_access_flag(char** address, char* mask) { + *address = &track_access; + *mask = TRACK_ACCESS_MASK; + } + + void get_track_modification_flag(char** address, char* mask) { + *address = &track_modification; + *mask = TRACK_MODIFICATION_MASK; + } + private: // - // The initial values of static fields. This is defined by the - // ConstantValue attribute in the class file. + // The initial values of static fields. This is defined by the + // ConstantValue attribute in the class file. // // If there was not ConstantValue attribute for that field then _const_value_index==0 // @@ -918,6 +1088,28 @@ private: TypeDesc* _field_type_desc; unsigned _is_injected : 1; unsigned _offset_computed : 1; + + /** Turns on sending FieldAccess events on access to this field */ + char track_access; + const static char TRACK_ACCESS_MASK = 1; + + /** Turns on sending FieldModification events on modification of this field */ + char track_modification; + const static char TRACK_MODIFICATION_MASK = 1; + + //union { + // char bit_flags; + // struct { + + // /** Turns on sending FieldAccess events on access to this field */ + // char track_access : 1; + // const static char TRACK_ACCESS_MASK = 4; + + // /** Turns on sending FieldModification events on modification of this field */ + // char track_modification : 1; + // const static char TRACK_MODIFICATION_MASK = 8; + // }; + //}; }; // Field @@ -1063,11 +1255,11 @@ public: // The section id of the main code chunk for a method. Using an enum avoids a VC++ bug on Windows. enum {main_code_chunk_id = 0}; - // A predicate that returns true iff this is the main code chunk for a method: i.e, it 1) contains the method's entry point, + // A predicate that returns true iff this is the main code chunk for a method: i.e, it 1) contains the method's entry point, // and 2) contains the various flavors of JIT data for that method. static bool is_main_code_chunk(CodeChunkInfo *chunk) { assert(chunk); return (chunk->get_id() == main_code_chunk_id); } - // A predicate that returns true iff "id" is the section id of the main code chunk for a method. + // A predicate that returns true iff "id" is the section id of the main code chunk for a method. static bool is_main_code_chunk_id(int id) { return (id == main_code_chunk_id); } private: @@ -1083,7 +1275,7 @@ private: bool _has_been_loaded_for_vtune; - // 20040224 This records information about the methods (actually, CodeChunkInfo's) called by this CodeChunkInfo. + // 20040224 This records information about the methods (actually, CodeChunkInfo's) called by this CodeChunkInfo. // 20040405 This now records for each callee, the number of times it was called by each call IP in the caller. // That is, this is a list of Callee_Info structures, each giving a call IP Callee_Info *_callee_info; // points to an array of max_callees Callee_Info entries for this code chunk @@ -1116,7 +1308,7 @@ #endif -// Used to notify interested JITs whenever a method is changed: overwritten, recompiled, +// Used to notify interested JITs whenever a method is changed: overwritten, recompiled, // or initially compiled. struct Method_Change_Notification_Record { Method *method_of_interest; @@ -1221,7 +1413,7 @@ public: // bytecodes are not available (presumably they have been garbage collected by VM). const Byte *get_byte_code_addr() {return _byte_codes;} size_t get_byte_code_size() {return _byte_code_length;} - + // From the class file (Sec. 4.7.4) unsigned get_max_stack() { return _max_stack; } unsigned get_max_locals() { return _max_locals; } @@ -1317,7 +1509,7 @@ public: private: State _state; void *_code; - VTable_Patches *_vtable_patch; + VTable_Patches *_vtable_patch; NativeCodePtr _counting_stub; @@ -1330,7 +1522,7 @@ public: Method(); // destructor should be instead of this function, but it's not allowed to use it because copy for Method class is // done with memcpy, and old value is destroyed with delete operator. - void MethodClearInternals(); + void MethodClearInternals(); // // access modifiers @@ -1338,6 +1530,8 @@ public: bool is_synchronized() {return (_access_flags&ACC_SYNCHRONIZED)?true:false;} bool is_native() {return (_access_flags&ACC_NATIVE)?true:false;} bool is_abstract() {return (_access_flags&ACC_ABSTRACT)?true:false;} + bool is_varargs() {return (_access_flags&ACC_VARARGS)?true:false;} + bool is_bridge() {return (_access_flags&ACC_BRIDGE)?true:false;} // method flags bool is_init() {return _flags.is_init?true:false;} @@ -1351,7 +1545,7 @@ public: unsigned get_index() {return _index;} - // Fake methods are interface methods inherited by an abstract class that are not (directly or indirectly) + // Fake methods are interface methods inherited by an abstract class that are not (directly or indirectly) // implemented by that class. They are added to the class to ensure they have thecorrect vtable offset. // These fake methods point to the "real" interface method for which they are surrogates; this information // is used by reflection methods. @@ -1377,7 +1571,17 @@ public: friend void add_new_fake_method(Class* clss, Class* example, unsigned* next); friend void add_any_fake_methods(Class* clss); + unsigned get_num_param_annotations() {return _num_param_annotations;} + AnnotationTable * get_param_annotations(unsigned index) { + return index < _num_param_annotations ? _param_annotations[index] : NULL; + } + AnnotationValue * get_default_value() {return _default_value; } + private: + uint8 _num_param_annotations; + AnnotationTable ** _param_annotations; + AnnotationValue * _default_value; + unsigned _index; // index in method table uint16 _max_stack; uint16 _max_locals; @@ -1404,7 +1608,7 @@ private: bool _parse_line_numbers(unsigned attr_len, ByteReader &cfs); - bool _parse_local_vars(Const_Pool *cp, unsigned cp_size, + bool _parse_local_vars(Const_Pool *cp, unsigned cp_size, unsigned attr_len, ByteReader &cfs); bool _parse_exceptions(Const_Pool *cp, unsigned cp_size, unsigned attr_len, @@ -1415,46 +1619,41 @@ private: // // debugging info // - struct Line_Number_Entry { - uint16 start_pc; - uint16 line_number; - }; - - struct Line_Number_Table { - uint16 length; - Line_Number_Entry table[1]; - }; - - struct Local_Var_Entry { - uint16 start_pc; - uint16 length; - uint16 index; - String* name; - String* type; - }; - - struct Local_Var_Table { - uint16 length; - Local_Var_Entry table[1]; - }; - Line_Number_Table *_line_number_table; Local_Var_Table *_local_vars_table; + + Local_Var_Table * _parse_local_vars(Const_Pool *cp, unsigned cp_size, + unsigned attr_len, ByteReader &cfs, const char* attr_name); + + // This is the number of breakpoints which should be set in the + // method when it is compiled. This number does not reflect + // multiple breakpoints that are set in the same location by + // different environments, it counts only unique locations + uint32 pending_breakpoints; public: unsigned get_line_number_table_size() { return (_line_number_table) ? _line_number_table->length : 0; } + bool get_line_number_entry(unsigned index, jlong* pc, jint* line); + unsigned get_local_var_table_size() { return (_local_vars_table) ? _local_vars_table->length : 0; } + bool get_local_var_entry(unsigned index, jlong* pc, - jint* length, jint* slot, String** name, String** type); + jint* length, jint* slot, String** name, String** type, + String** generic_type); + + // XXX + //bool get_local_var_entry(unsigned index, jlong* pc, + // jint* length, jint* slot, String** name, String** type); + // Returns number of line in the source file, to which the given bytecode offset // corresponds, or -1 if it is unknown. - int get_line_number(uint16 bc_offset); + int get_line_number(uint16 bc_offset); Inline_Record *inline_records; void set_inline_assumption(JIT *jit, Method *caller); @@ -1467,42 +1666,22 @@ public: void lock(); void unlock(); -}; // Method + uint32 get_pending_breakpoints() + { + return pending_breakpoints; + } + void insert_pending_breakpoint() + { + pending_breakpoints++; + } -/////////////////////////////////////////////////////////////////////////////// -// class file attributes -/////////////////////////////////////////////////////////////////////////////// -enum Attributes { - ATTR_SourceFile, // Class (no more than 1 in each class file) - ATTR_InnerClasses, // inner class - ATTR_ConstantValue, // Field (no more than 1 for each field) - ATTR_Code, // Method - ATTR_Exceptions, // Method - ATTR_LineNumberTable, // Code - ATTR_LocalVariableTable, // Code - ATTR_Synthetic, // Field/Method - ATTR_Deprecated, // Field/Method - ATTR_SourceDebugExtension, // Class (no more than 1 in each class file) - N_ATTR, - ATTR_UNDEF, - ATTR_ERROR -}; - -#define N_FIELD_ATTR 3 -#define N_METHOD_ATTR 4 -#define N_CODE_ATTR 2 -#define N_CLASS_ATTR 3 - -// -// magic number, and major/minor version numbers of class file -// -#define CLASSFILE_MAGIC 0xCAFEBABE -#define CLASSFILE_MAJOR 45 -// Supported class files up to this version -#define CLASSFILE_MAJOR_MAX 49 -#define CLASSFILE_MINOR 3 + void remove_pending_breakpoint() + { + pending_breakpoints--; + } +}; // Method VMEXPORT Class* load_class(Global_Env *env, const String *classname); @@ -1510,7 +1689,7 @@ Class* find_loaded_class(Global_Env *env #define BITS_PER_BYTE 8 // We want to use signed arithmetic when we do allocation pointer/limit compares. -// In order to do this all sizes must be positive so when we want to overflow instead of +// In order to do this all sizes must be positive so when we want to overflow instead of // setting the high bit we set the next to high bit. If we set the high bit and the allocation buffer // is at the top of memory we might not detect an overflow the unsigned overflow would produce // a small positive number that is smaller then the limit. @@ -1518,7 +1697,7 @@ #define BITS_PER_BYTE 8 #define NEXT_TO_HIGH_BIT_SET_MASK (1<<((sizeof(unsigned) * BITS_PER_BYTE)-2)) #define NEXT_TO_HIGH_BIT_CLEAR_MASK ~NEXT_TO_HIGH_BIT_SET_MASK -inline unsigned int get_instance_data_size (Class *c) +inline unsigned int get_instance_data_size (Class *c) { return (c->instance_data_size & NEXT_TO_HIGH_BIT_CLEAR_MASK); } diff --git vm/vmcore/include/String_Pool.h vm/vmcore/include/String_Pool.h index e27d48e..02c2072 100644 --- vm/vmcore/include/String_Pool.h +++ vm/vmcore/include/String_Pool.h @@ -22,42 +22,46 @@ #ifndef _STRING_POOL_H_ #define _STRING_POOL_H_ #include <string.h> +#include <apr_hash.h> + #include "tl/memory_pool.h" #include "object_layout.h" +#define STRING_PADDING 4 + extern "C" { typedef struct String { #ifdef _DEBUG - unsigned id; // id for debugging + unsigned id; // id for debugging #endif - // 20030507 Ref to the interned string used by java.lang.String.intern(). It is compressed when compressing refs. - union { - ManagedObject* raw_ref; // raw reference to interned string if not compressing references - uint32 compressed_ref; // equivalent compressed reference. + // 20030507 Ref to the interned string used by java.lang.String.intern(). + // It is compressed when compressing refs. + union { + // raw reference to interned string if not compressing references + ManagedObject * raw_ref; + // equivalent compressed reference. + uint32 compressed_ref; } intern; unsigned len; - char bytes[4]; + char bytes[STRING_PADDING]; } String; } - - class String_Pool { public: String_Pool(); - // // lookup string in string table & insert if not found - // - VMEXPORT String *lookup(const char *str); - String *lookup(const char *str, unsigned len); + VMEXPORT String * lookup(const char *str); + String * lookup(const char *str, unsigned len); // Iterators for GC - String *get_first_string(); - String *get_first_string_intern(unsigned *); + String * get_first_string_intern(); - String *get_next_string(String *); - String *get_next_string_intern(String *, unsigned *); + String * get_next_string_intern(); + + // intern the string + ManagedObject * intern(String *); // The GC enumeration code needs to lock and unlock the // pool in order to enumerate it in a thread safe manner. @@ -65,40 +69,70 @@ public: void unlock_pool(); private: - bool valid_string_pool(); + enum { STRING_TABLE_SIZE = 44449, INTERNED_STRING_ARRAY_SIZE = STRING_TABLE_SIZE / 10 }; - // - // Entry in string table - // - class _Entry { + class Entry { public: - _Entry *const next; - String str; - _Entry(const char *s, unsigned len, _Entry *n); + Entry * next; + String str; + Entry(const char *s, unsigned len, Entry *n); /** * Memory is already allocated for this object. */ - void *operator new(size_t UNREF sz, void * mem) { return mem; } - void operator delete(void * UNREF mem, void * UNREF mem1) { - // define empty operator delete just to get rid of warning - } + void *operator new(size_t UNREF sz, void * mem) { return mem; } + void operator delete(void * UNREF mem, void * UNREF mem1) {} }; - // - // string table size - // -#define STRING_TABLE_SIZE 44449 - // - // table of string entries - // - _Entry *_table[STRING_TABLE_SIZE]; - // + struct Interned_Strings { + Interned_Strings * next; + // this field is used for synchronization purposes + volatile unsigned free_slot; + String * elem[INTERNED_STRING_ARRAY_SIZE]; + }; + + struct Interned_Strings_Index { + Interned_Strings * current; + unsigned index; + }; + + // bit mask to test for end of line character + static const POINTER_SIZE_INT BIT_MASK = +#ifdef POINTER64 + 0x7efefefefefefeffL; +#else + 0x7efefeffL; +#endif + + bool has_line_end(POINTER_SIZE_INT val); + void hash_it(const char * str, unsigned * len, POINTER_SIZE_INT * hash); + POINTER_SIZE_INT hash_it(const char * str, unsigned len); + String * lookup(const char *str, unsigned len, POINTER_SIZE_INT hash); + void register_interned_string(String * str); + // memory pool - // - tl::MemoryPool memory_pool; + tl::MemoryPool memory_pool; + // table of string entries + Entry ** table; + // linked list of arrays of interned strings + Interned_Strings * head_interned; + // current list element + volatile Interned_Strings * current_interned; + // iterator to go through interned strings + // NOTE: only one thread can iterate through at once + // Moreover the iteration should be done in stop_the_world phase since no + // synchronization between String_Pool::intern() & String_Pool::get_next_string_intern() + Interned_Strings_Index * index_interned; + + // In order to make this code thread safe a light weight lock is used. + // The protocol is simple and the lock is local to this string pool. + volatile POINTER_SIZE_INT string_pool_lock; // 1 is locked, 0 is unlocked - // sufficient to compile empty class and its prerequisites - //#define INITIAL_STRING_ARENA_SIZE 94000 +#ifdef VM_STATS + friend class VM_Statistics; +public: + apr_hash_t * string_stat; + unsigned num_ambiguity; +#endif }; #endif // _STRING_POOL_H_ diff --git vm/vmcore/include/annotations.h vm/vmcore/include/annotations.h new file mode 100644 index 0000000..3bd7776 --- /dev/null +++ vm/vmcore/include/annotations.h @@ -0,0 +1,51 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +#ifndef _ANNOTATIONS_H_ +#define _ANNOTATIONS_H_ + +#include "jni_types.h" +#include "vm_core_types.h" + +struct AnnotationTable; +struct Annotation; +struct AnnotationValue; + +// Returns array of declared annotations. +// Returns zero-sized array if there are no annotations. +// May raise an exception, in this case returns null. +jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss); + +// Returns resolved annotation or null if resolution failed. +// If the cause parameter is not null, resolution error is assigned to it for upstream processing; +// otherwise the error is raised. +// In case of errors other than resolving failure, the error is raised, +// null is returned and cause is unchanged +jobject resolve_annotation(JNIEnv* jenv, Annotation* antn, Class* clss, jthrowable* cause = NULL); + +// Returns resolved annotation value or null if resolution failed. +// In case of a resolution failure, the error is assigned to the "cause" parameter +// for upstream processing. +// In case of errors other than resolving failure, the error is raised, +// null is returned and cause is unchanged +jobject resolve_annotation_value(JNIEnv* jenv, AnnotationValue& antn, Class* antn_clss, + String* name, jthrowable* cause); + +#endif // !_ANNOTATIONS_H_ diff --git vm/vmcore/include/assertion_registry.h vm/vmcore/include/assertion_registry.h new file mode 100644 index 0000000..3cf2aae --- /dev/null +++ vm/vmcore/include/assertion_registry.h @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +#ifndef _ASSERTIONS_H_ +#define _ASSERTIONS_H_ + +#include "environment.h" + +struct Assertion_Record { + Assertion_Record *next; + bool status; + unsigned len; + char name[1]; +}; + +enum Assertion_Status {ASRT_DISABLED = -1, ASRT_UNSPECIFIED = 0, ASRT_ENABLED = 1}; + +struct Assertion_Registry { + bool enable_system; + Assertion_Status enable_all; + Assertion_Record* classes; + Assertion_Record* packages; + +public: + Assertion_Registry() { + enable_system = false; + enable_all = ASRT_UNSPECIFIED; + classes = NULL; + packages = NULL; + } + + void add_class(const Global_Env* genv, const char* name, unsigned len, bool value); + void add_package(const Global_Env* genv, const char* name, unsigned len, bool value); + Assertion_Status get_class_status(const char* name) const; + Assertion_Status get_package_status(const char* name) const; + + //assertions status for all but system classes + Assertion_Status is_enabled(bool system) const { + return system ? (enable_system ? ASRT_ENABLED : ASRT_DISABLED) : enable_all; + } +}; + +#endif // !_ASSERTIONS_H_ diff --git vm/vmcore/include/class_interface.h vm/vmcore/include/class_interface.h index a5b2de4..0ff0301 100644 --- vm/vmcore/include/class_interface.h +++ vm/vmcore/include/class_interface.h @@ -460,6 +460,30 @@ method_get_exc_handler_info( method_hand unsigned short *handler_pc, unsigned short *catch_type ); /** + * Gets number of exceptions a method can throw. + * Parameter <i>hmethod</i> must not equal to <code>NULL</code>. + * + * @param hmethod method handle + * + * @return number of exceptions + */ +unsigned short +method_get_number_exc_method_can_throw( method_handler hmethod ); + +/** + * Gets name of exception a method can throw. + * Parameter <i>hmethod</i> must not equal to <code>NULL</code>. + * If parameter <i>index</i> is out of range, returns <code>NULL</code>. + * + * @param hmethod method handle + * @param index index of exception + * + * @return name of exception + */ +const char * +method_get_exc_method_can_throw( method_handler hmethod, unsigned short index ); + +/** * Class loader interface */ diff --git vm/vmcore/include/compile.h vm/vmcore/include/compile.h index 1076c8c..983cce1 100644 --- vm/vmcore/include/compile.h +++ vm/vmcore/include/compile.h @@ -56,26 +56,7 @@ NativeCodePtr compile_gen_compile_me(Met void patch_code_with_threads_suspended(Byte *code_block, Byte *new_code, size_t size); - -// On IPF this type is actually a Merced_Code_Emitter*, while on IA32 it is a char* pointer to a code block for the stub. -typedef void *Emitter_Handle; - -// The following function is IA32 only. -// If reference on the stack is null, throw a null pointer exception. -Emitter_Handle gen_throw_if_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset); -// The following two null reference conversion procedures are IA32 only. -// Convert a reference on the stack, if null, from a managed (heap_base) to an unmanaged null (NULL/0). -Emitter_Handle gen_convert_managed_to_unmanaged_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset); -// Convert a reference on the stack, if null, from an unmanaged (NULL/0) to an managed null (heap_base). -Emitter_Handle gen_convert_unmanaged_to_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset); - -// The following two null reference conversion procedures are IPF only. -// Convert a reference in register "reg", if null, from a managed null (heap_base) to an unmanaged one (NULL/0). Uses SCRATCH_GENERAL_REG. -void gen_convert_managed_to_unmanaged_null_ipf(Emitter_Handle emitter, unsigned reg); -// Convert a reference in a register, if null, from an unmanaged null (NULL/0) to an managed one (heap_base). -void gen_convert_unmanaged_to_managed_null_ipf(Emitter_Handle emitter, unsigned reg); - - +typedef char * Emitter_Handle; struct Compilation_Handle { Global_Env* env; @@ -94,31 +75,6 @@ NativeCodePtr interpreter_compile_create // Create a LIL stub for PINVOKE interfacing NativeCodePtr compile_create_lil_pinvoke_stub(Method_Handle method, void* func, NativeStubOverride nso); - -// The final action taken by a create_call_native_proc_stub() stub after calling "proc_addr". For example, methods are JITed -// by having the stub jump to the new method's code (CNP_JmpToRetAddrFinalAction) after jit_a_method finishes compiling it. -enum CNP_FinalAction { - CNP_ReturnFinalAction, // return after calling the native procedure (e.g. delegate Invoke) - CNP_JmpToRetAddrFinalAction // branch to the procedure whose address is returned by "proc_addr" (e.g. JIT compile method) -}; - - -// If CNP_Final_Action is CNP_ReturnFinalAction, the type returned by the called "proc_addr". -// NB: "proc_addr" MUST return any result in eax/edx as a long (int64) value; The CNP_ReturnType determines -// what registers to set.from this value. -enum CNP_ReturnType { - CNP_VoidReturnType, - CNP_IntReturnType, // leave the int32/int64 result in eax/edx - CNP_FloatReturnType, // move the float32 value in eax to ST(0), the top of the FP stack - CNP_DoubleReturnType, // move the float64 value in eax/edx to ST(0), the top of the FP stack - CNP_NumberOfReturnTypes // must be last -}; - - -// create_call_native_proc_stub() creates a semi-customized stub that can be used to call a native procedure from managed code. -void *create_call_native_proc_stub(char *proc_addr, char *stub_name, CNP_FinalAction final_action, CNP_ReturnType return_type); - - // // Support for stub override code sequences // @@ -156,4 +112,19 @@ NativeCodePtr compile_do_instrumentation // A MethodInstrumentationProc that records the number of calls from the caller code chunk to the callee. void count_method_calls(CodeChunkInfo *callee); +struct DynamicCode +{ + const char *name; + const void *address; + jint length; + DynamicCode *next; +}; + +// Adding dynamic generated code info to global list +// Is used in JVMTI and native frames interface +DynamicCode* compile_get_dynamic_code_list(void); +// Adding dynamic generated code info to global list +void compile_add_dynamic_generated_code_chunk(const char* name, const void* address, jint length); +void compile_clear_dynamic_code_list(DynamicCode* list); + #endif diff --git vm/vmcore/include/dll_jit_intf.h vm/vmcore/include/dll_jit_intf.h index 3c61e3c..3d0c686 100644 --- vm/vmcore/include/dll_jit_intf.h +++ vm/vmcore/include/dll_jit_intf.h @@ -26,7 +26,6 @@ #include <string.h> #include "jit_intf_cpp.h" #include "jit_export_jpda.h" #include <apr_dso.h> -#include <apr_dso.h> bool vm_is_a_jit_dll(const char *dll_filename); diff --git vm/vmcore/include/dump.h vm/vmcore/include/dump.h index 304a794..3e515bb 100644 --- vm/vmcore/include/dump.h +++ vm/vmcore/include/dump.h @@ -21,6 +21,16 @@ #ifndef _DUMP_H_ #define _DUMP_H_ +#ifndef NDEBUG + extern bool dump_stubs; + + #define DUMP_STUB(addr, name, len) \ + if (dump_stubs) \ + dump(((char *)addr), (name), (len)); +#else + #define DUMP_STUB(addr, name, len) +#endif + int dump(const char * code, const char * name, unsigned int length); #endif // _DUMP_H_ diff --git vm/vmcore/include/environment.h vm/vmcore/include/environment.h index a3f076d..ffa91af 100644 --- vm/vmcore/include/environment.h +++ vm/vmcore/include/environment.h @@ -30,6 +30,8 @@ #include "open/compmgr.h" #include "open/em_vm.h" typedef struct NSOTableItem NSOTableItem; +typedef struct DynamicCode DynamicCode; +typedef struct Assertion_Registry Assertion_Registry; struct Global_Env { public: @@ -42,7 +44,8 @@ struct Global_Env { DebugUtilsTI* TI; NSOTableItem* nsoTable; void* portLib; // Classlib's port library - + DynamicCode* dcList; + Assertion_Registry* assert_reg; // // globals // @@ -64,15 +67,10 @@ struct Global_Env { String* Init_String; String* Clinit_String; String* FinalizeName_String; + String* EnqueueName_String; String* VoidVoidDescriptor_String; - String* ByteDescriptor_String; - String* CharDescriptor_String; - String* DoubleDescriptor_String; - String* FloatDescriptor_String; - String* IntDescriptor_String; - String* LongDescriptor_String; - String* ShortDescriptor_String; - String* BooleanDescriptor_String; + String* VoidIntegerDescriptor_String; + String* VoidBooleanDescriptor_String; String* Clonable_String; String* Serializable_String; @@ -85,7 +83,9 @@ struct Global_Env { String* JavaNioByteBuffer_String; String* JavaLangArrayIndexOutOfBoundsException_String; String* JavaLangThrowable_String; + String* JavaLangNoClassDefFoundError_String; String* JavaLangString_String; + String* JavaLangStringBuffer_String; String* Length_String; String* LoadClass_String; @@ -198,6 +198,7 @@ struct Global_Env { //load a class via bootstrap classloader Class* LoadCoreClass(const String* name); + Class* LoadCoreClass(const char* name); /** * Set "Ready For Exceptions" state. diff --git vm/vmcore/include/exception.h vm/vmcore/include/exception.h deleted file mode 100644 index b3204a6..0000000 --- vm/vmcore/include/exception.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Pavel Afremov - * @version $Revision: 1.1.2.1.4.4 $ - */ - -// This describes the core VM interface to exception manipulation, throwing, and catching - -#ifndef _INTERFACE_EXCEPTION_H_ -#define _INTERFACE_EXCEPTION_H_ - -#include "jni.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct StackTraceFrame { - Method_Handle method; - NativeCodePtr ip; - void *outdated_this; -}; - -#ifdef __cplusplus -} -#endif -#endif // !_INTERFACE_EXCEPTION_H_ diff --git vm/vmcore/include/exceptions.h vm/vmcore/include/exceptions.h index 67928b2..716cd00 100644 --- vm/vmcore/include/exceptions.h +++ vm/vmcore/include/exceptions.h @@ -21,6 +21,7 @@ #ifndef _EXCEPTIONS_H_ #define _EXCEPTIONS_H_ +#include "exceptions_type.h" #include "jni.h" #include "open/types.h" @@ -44,36 +45,15 @@ The functions to work with exceptions ar */ /** - * Throws an exception, and chooses the appropriate method - * (destructive/non-destructive) automatically. - * May not return in case of destructive exception propagation. - * - * @note The other methods which throws exception is removed - * from first version of exception interface. It's necessary - * crfeate additional component "conveniences" - */ -VMEXPORT void exn_throw(jthrowable exception); - -/** - * Throws an exception, and check that frame type is throwble. - */ -void exn_throw_only(jthrowable exception); - -/** - * Rise an exception, and check that frame type is unthrowble. - */ -void exn_raise_only(jthrowable exception); - -/** * Returns the thread-local exception object * or NULL if no exception occured. - * - * @note rename of get_current_thread_exception(). It may be eliminated if - * all other componets can use combination of exn_try() and exn_catch() - * instead it. */ VMEXPORT jthrowable exn_get(); +VMEXPORT Class* exn_get_class(); +VMEXPORT const char* exn_get_name(); + + /** * Returns true if the thread-local exception object is set. */ @@ -90,10 +70,34 @@ VMEXPORT void exn_clear(); /** * Creates exception object. */ -jthrowable exn_create(const char* exception_class); -jthrowable exn_create(const char* exception_class, jthrowable cause); -jthrowable exn_create(const char* exception_class, const char* message); -jthrowable exn_create(const char* exception_class, const char* message, jthrowable cause); +//FIXME LAZY EXCEPTION (2006.05.06) +// Maybe change to exn_object_create (whole 7) +jthrowable exn_create(Exception* exception); + +jthrowable exn_create(Class* exc_class); +jthrowable exn_create(Class* exc_class, jthrowable cause); +jthrowable exn_create(Class* exc_class, const char* message); +jthrowable exn_create(Class* exc_class, const char* message, jthrowable cause); + +/** + * Creates exception object. + */ +VMEXPORT jthrowable exn_create(const char* exc_name); + +/** + * Creates exception object. + */ +VMEXPORT jthrowable exn_create(const char* exc_name, jthrowable cause); + +/** + * Creates exception object. + */ +VMEXPORT jthrowable exn_create(const char* exc_name, const char* message); + +/** + * Creates exception object. + */ +VMEXPORT jthrowable exn_create(const char* exc_name, const char* message, jthrowable cause); /** * Returns true if frame is unwindable and false if isn't. @@ -101,49 +105,102 @@ jthrowable exn_create(const char* except VMEXPORT bool is_unwindable(); /** - * Creates and throws an exception. - * Uses exn_throw_only() internally. - * May not return in case of destructive exception propagation. + * Sets unwindable property of frame. If frame is unwindable property + * should be true and should be false if frame isn't unwindable. + * Returns previous value of unwindable property. + */ +bool set_unwindable(bool unwindable); + +/** + * Throws an exception object * * @note internal convenience function, may not be exposed to VMI interface. */ -void exn_throw_by_name(const char* exception_name); +void exn_throw_object(jthrowable exc_object); /** - * Creates and throws an exception. - * Uses exn_throw_only() internally. - * May not return in case of destructive exception propagation. + * Throws an exceptionas lazy. + * Does not return in case of destructive exception propagation. * * @note internal convenience function, may not be exposed to VMI interface. */ -void exn_throw_by_name(const char* exception_name, const char* message); +void exn_throw_by_class(Class* exc_class); +void exn_throw_by_class(Class* exc_class, jthrowable exc_cause); +void exn_throw_by_class(Class* exc_class, const char* exc_message); +void exn_throw_by_class(Class* exc_class, const char* exc_message, + jthrowable exc_cause); /** - * Creates and throws an exception. - * Uses exn_throw_only() internally. - * May not return in case of destructive exception propagation. + * Throws an exceptionas lazy. + * Does not return in case of destructive exception propagation. + */ +VMEXPORT void exn_throw_by_name(const char* exception_name); + +/** + * Throws an exceptionas lazy. + * Does not return in case of destructive exception propagation. + */ +VMEXPORT void exn_throw_by_name(const char* exception_name, jthrowable cause); + +/** + * Throws an exceptionas lazy. + * Does not return in case of destructive exception propagation. + */ +VMEXPORT void exn_throw_by_name(const char* exception_name, const char* message); + +/** + * Throws an exceptionas lazy. + * Does not return in case of destructive exception propagation. + */ +VMEXPORT void exn_throw_by_name(const char* exception_name, const char* message, jthrowable cause); + +/** + * Sets exceptions as a thread local exception. * - * @note internal convenience function, may not be exposed to VMI interface. + * @note explicit non-destructive semantics should be deduced from context. */ -VMEXPORT void exn_throw_by_name(const char* exception_name, jthrowable cause, const char* message); +VMEXPORT void exn_raise_object(jthrowable exc_object); /** - * Creates exceptions and sets it - * as a thread local exception object. + * Sets exception lazy as a thread local exception. * * @note internal convenience function, may not be exposed to VMI interface. * @note explicit non-destructive semantics should be deduced from context. */ -void exn_raise_by_name(const char* exception_name); +void exn_raise_by_class(Class* exc_class); +void exn_raise_by_class(Class* exc_class, jthrowable exc_cause); +void exn_raise_by_class(Class* exc_class, const char* exc_message); +void exn_raise_by_class(Class* exc_class, const char* exc_message, + jthrowable exc_cause); /** - * Creates exceptions and sets it - * as a thread local exception object. + * Sets exception lazy as a thread local exception. + * + * @note explicit non-destructive semantics should be deduced from context. + */ +VMEXPORT void exn_raise_by_name(const char* exception_name); + +/** + * Sets exception lazy as a thread local exception. + * + * @note explicit non-destructive semantics should be deduced from context. + */ +VMEXPORT void exn_raise_by_name(const char* exception_name, jthrowable exc_cause); + +/** + * Sets exception lazy as a thread local exception. * - * @note internal convenience function, may not be exposed to VMI interface. * @note explicit non-destructive semantics should be deduced from context. */ -void exn_raise_by_name(const char* exception_name, const char* message); +VMEXPORT void exn_raise_by_name(const char* exception_name, const char* message); + +/** + * Sets exception lazy as a thread local exception. + * + * @note explicit non-destructive semantics should be deduced from context. + */ +VMEXPORT void exn_raise_by_name(const char* exception_name, const char* message, + jthrowable exc_cause); /** * Pushes dummy non-unwindable stack frame in order to prevent stack unwinding. @@ -174,6 +231,21 @@ #define exn_try (if (exn_function_try()) */ #define exn_catch (th) (if ( th = exn_function_catch())) +#define ASSERT_THROW_AREA \ +assert(is_unwindable()); + +#define ASSERT_RAISE_AREA \ +assert(!is_unwindable()); + +#define BEGIN_RAISE_AREA \ +{ \ +bool unwindable = set_unwindable(false); + +#define END_RAISE_AREA \ +set_unwindable(unwindable);\ +if (unwindable) exn_rethrow_if_pending();\ +} + //////////////////////////////////////////////////////////////////////// // FUNCTIONS below are from old VM implementation ////////////////////// @@ -186,92 +258,24 @@ struct ManagedObject; //**** Stack Trace support // Print the stack trace stored in the exception object to the given file. -void exn_print_stack_trace(FILE* f, ManagedObject* exn); - -void print_uncaught_exception_message(FILE *f, char* context_message, Java_java_lang_Throwable *exc); - -//**** Main exception propogation entry points - -// Throw an exception in the current thread. -// Must be called with an M2nFrame on the top of the stack, and throws to the previous managed -// frames or the previous M2nFrame. -// If exn_obj is nonnull then it is the exception, otherwise the exception is an instance of -// exn_class created using the given constructor and arguments (a null exn_constr indicates the default constructor). -// Does not return. -void exn_athrow(ManagedObject* exn_obj, Class_Handle exn_class, Method_Handle exn_constr=NULL, uint8* exn_constr_args=NULL); - -// Throw an exception in the current thread. -// Must be called with the current thread "suspended" in managed code and regs holds the suspended values. -// Exception defined as in previous two functions. -// Mutates the regs value, which should be used to "resume" the managed code. -void exn_athrow_regs(Registers* regs, Class_Handle exn_class); - -// exception catch callback to restore stack after Stack Overflow Error -void exception_catch_callback(); - -//**** Runtime exception support - -// rth_throw takes an exception and throws it -NativeCodePtr exn_get_rth_throw(); - -// rth_throw_lazy takes a constructor, the class for that constructor, and arguments for that constructor. -// it throws a (lazily created) instance of that class using that constructor and arguments. -NativeCodePtr exn_get_rth_throw_lazy(); - -// rth_throw_lazy_trampoline takes an exception class in the first standard place -// and throws a (lazily created) instance of that class using the default constructor -NativeCodePtr exn_get_rth_throw_lazy_trampoline(); - -// rth_throw_null_pointer throws a null pointer exception (lazily) -NativeCodePtr exn_get_rth_throw_null_pointer(); +void exn_print_stack_trace(FILE* f, jthrowable exc); -// rth_throw_array_index_out_of_bounds throws an array index out of bounds exception (lazily) -NativeCodePtr exn_get_rth_throw_array_index_out_of_bounds(); +void print_uncaught_exception_message(FILE *f, char* context_message, jthrowable exc); -// rth_throw_negative_array_size throws a negative array size exception (lazily) -NativeCodePtr exn_get_rth_throw_negative_array_size(); - -// rth_throw_array_store throws an array store exception (lazily) -NativeCodePtr exn_get_rth_throw_array_store(); - -// rth_throw_arithmetic throws an arithmetic exception (lazily) -NativeCodePtr exn_get_rth_throw_arithmetic(); - -// rth_throw_class_cast_exception throws a class cast exception (lazily) -NativeCodePtr exn_get_rth_throw_class_cast_exception(); - -// rth_throw_incompatible_class_change_exception throws an incompatible class change exception (lazily) -NativeCodePtr exn_get_rth_throw_incompatible_class_change_exception(); - -NativeCodePtr exn_get_rth_throw_illegal_state_exception(); - -//**** Various standard exception types - -Class_Handle exn_get_class_cast_exception_type(); //**** Native code exception support -VMEXPORT // temporary solution for interpreter unplug -void clear_current_thread_exception(); -void rethrow_current_thread_exception(); -void rethrow_current_thread_exception_if_pending(); - -// These functions are depreciated and should not be called under any circumstance -VMEXPORT void throw_java_exception(const char *exception_name); -VMEXPORT void throw_java_exception(const char *exception_name, const char *message); - -VMEXPORT jthrowable create_chained_exception(const char *exception_name, jthrowable); - -// Per-thread exception object -VMEXPORT // temporary solution for interpreter unplug -ManagedObject* get_current_thread_exception(); -VMEXPORT // temporary solution for interpreter unplug -void __stdcall set_current_thread_exception(ManagedObject* obj); +void exn_rethrow(); +void exn_rethrow_if_pending(); +#ifndef _EM64T_ void set_guard_stack(); +#endif void init_stack_info(); VMEXPORT size_t get_available_stack_size(); +#ifndef _EM64T_ VMEXPORT bool check_available_stack_size(size_t required_size); +#endif VMEXPORT size_t get_default_stack_size(); #endif // _EXCEPTIONS_H_ diff --git vm/vmcore/include/exceptions_impl.h vm/vmcore/include/exceptions_impl.h new file mode 100644 index 0000000..1d6d0c7 --- /dev/null +++ vm/vmcore/include/exceptions_impl.h @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ +#ifndef _EXCEPTIONS_IMPL_H_ +#define _EXCEPTIONS_IMPL_H_ + +#include "exceptions_type.h" +#include "jni.h" +#include "open/types.h" + +#define VM_LAZY_EXCEPTION + +Class *get_exc_class(const char *exception_name); +Method* lookup_exc_constructor(Class * exc_class, const char *signature); +void init_cause(jthrowable exc_object, jthrowable exc_cause); + +jthrowable create_exception(Class* exc_class, Method* exc_init, jvalue* args); +jthrowable create_exception(Class* exc_class, + const char* exc_message, jthrowable exc_cause); +jthrowable create_exception(Exception* exception); + +void exn_throw_object_internal(jthrowable exc_object); +void exn_throw_by_class_internal(Class* exc_class, const char* exc_message, + jthrowable exc_cause); +void exn_throw_by_name_internal(const char* exc_name, const char* exc_message, + jthrowable exc_cause); + +void exn_raise_object_internal(jthrowable exc_object); +void exn_raise_by_class_internal(Class* exc_class, const char* exc_message, + jthrowable exc_cause); +void exn_raise_by_name_internal(const char* exc_name, const char* exc_message, + jthrowable exc_cause); + +ManagedObject* __stdcall get_exception_object_internal(); +void __stdcall set_exception_object_internal(ManagedObject * exn); +void __stdcall clear_exception_internal(); + +#endif // _EXCEPTIONS_IMPL_H_ diff --git vm/vmcore/include/exceptions_int.h vm/vmcore/include/exceptions_int.h new file mode 100644 index 0000000..31c4e6b --- /dev/null +++ vm/vmcore/include/exceptions_int.h @@ -0,0 +1,30 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ +#ifndef _EXCEPTIONS_INT_H_ +#define _EXCEPTIONS_INT_H_ + +#include "open/types.h" + +VMEXPORT void clear_current_thread_exception(); +VMEXPORT bool check_current_thread_exception(); +VMEXPORT ManagedObject* get_current_thread_exception(); +VMEXPORT void set_current_thread_exception(ManagedObject* obj); + +#endif // _EXCEPTIONS_INT_H_ diff --git vm/vmcore/include/exceptions_jit.h vm/vmcore/include/exceptions_jit.h new file mode 100644 index 0000000..67d39ed --- /dev/null +++ vm/vmcore/include/exceptions_jit.h @@ -0,0 +1,95 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ +#ifndef _EXCEPTIONS_JIT_H_ +#define _EXCEPTIONS_JIT_H_ + +#include "exceptions_type.h" +#include "jni.h" +#include "open/types.h" + + +//**** Main exception propogation entry points +void exn_throw_for_JIT(ManagedObject* exn_obj, Class_Handle exn_class, + Method_Handle exn_constr, uint8* jit_exn_constr_args, jvalue* vm_exn_constr_args); + +// Throw an exception in the current thread. +// Must be called with an M2nFrame on the top of the stack, and throws to the previous managed +// frames or the previous M2nFrame. +// If exn_obj is nonnull then it is the exception, otherwise the exception is an instance of +// exn_class created using the given constructor and arguments (a null exn_constr indicates the default constructor). +// Does not return. +void exn_athrow(ManagedObject* exn_obj, Class_Handle exn_class, Method_Handle exn_constr=NULL, uint8* exn_constr_args=NULL); + +// Throw an exception in the current thread. +// Must be called with the current thread "suspended" in managed code and regs holds the suspended values. +// Exception defined as in previous two functions. +// Mutates the regs value, which should be used to "resume" the managed code. +void exn_athrow_regs(Registers* regs, Class_Handle exn_class); + +// exception catch callback to restore stack after Stack Overflow Error +void exception_catch_callback(); + +// exception catch support for JVMTI +void jvmti_exception_catch_callback(Registers* regs); + +//**** Runtime exception support + +// rth_throw_illegal_monitor_state throws an java.lang.IllegalMonitorStateException (lazily) +NativeCodePtr exn_get_rth_throw_illegal_monitor_state(); + +// rth_throw takes an exception and throws it +NativeCodePtr exn_get_rth_throw(); + +// rth_throw_lazy takes a constructor, the class for that constructor, and arguments for that constructor. +// it throws a (lazily created) instance of that class using that constructor and arguments. +NativeCodePtr exn_get_rth_throw_lazy(); + +// rth_throw_lazy_trampoline takes an exception class in the first standard place +// and throws a (lazily created) instance of that class using the default constructor +NativeCodePtr exn_get_rth_throw_lazy_trampoline(); + +// rth_throw_null_pointer throws a null pointer exception (lazily) +NativeCodePtr exn_get_rth_throw_null_pointer(); + +// rth_throw_array_index_out_of_bounds throws an array index out of bounds exception (lazily) +NativeCodePtr exn_get_rth_throw_array_index_out_of_bounds(); + +// rth_throw_negative_array_size throws a negative array size exception (lazily) +NativeCodePtr exn_get_rth_throw_negative_array_size(); + +// rth_throw_array_store throws an array store exception (lazily) +NativeCodePtr exn_get_rth_throw_array_store(); + +// rth_throw_arithmetic throws an arithmetic exception (lazily) +NativeCodePtr exn_get_rth_throw_arithmetic(); + +// rth_throw_class_cast_exception throws a class cast exception (lazily) +NativeCodePtr exn_get_rth_throw_class_cast_exception(); + +// rth_throw_incompatible_class_change_exception throws an incompatible class change exception (lazily) +NativeCodePtr exn_get_rth_throw_incompatible_class_change_exception(); + +NativeCodePtr exn_get_rth_throw_illegal_state_exception(); + +//**** Various standard exception types + +Class_Handle exn_get_class_cast_exception_type(); + +#endif // _EXCEPTIONS_JIT_H_ diff --git vm/vmcore/include/exceptions_type.h vm/vmcore/include/exceptions_type.h new file mode 100644 index 0000000..0a3f4a2 --- /dev/null +++ vm/vmcore/include/exceptions_type.h @@ -0,0 +1,42 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Afremov + * @version $Revision: 1.1.2.1.2.2 $ + */ + +// This describes the core VM interface to exception manipulation, throwing, and catching + +#ifndef _INTERFACE_EXCEPTIONS_TYPE_H_ +#define _INTERFACE_EXCEPTIONS_TYPE_H_ + +//#include "jni.h" +#include "open/types.h" + +#ifdef __cplusplus +extern "C" { +#endif +struct Exception { + ManagedObject* exc_object; + Class* exc_class; + const char* exc_message; + ManagedObject* exc_cause; +}; + +#ifdef __cplusplus +} +#endif +#endif // !_INTERFACE_EXCEPTIONS_TYPE_H_ diff --git vm/vmcore/include/heap.h vm/vmcore/include/heap.h index 049345a..d3f94ee 100644 --- vm/vmcore/include/heap.h +++ vm/vmcore/include/heap.h @@ -107,7 +107,7 @@ Vector_Handle vm_new_vector_or_null(Clas * and control is returned. */ Vector_Handle vm_new_vector_using_vtable_and_thread_pointer( - Allocation_Handle vector_handle, int length, void *tp); + int length, Allocation_Handle vector_handle, void *tp); /** * allocates new vector. @@ -118,7 +118,7 @@ Vector_Handle vm_new_vector_using_vtable * @note XXX The purpose of this function is not clear. -salikh */ Vector_Handle vm_new_vector_or_null_using_vtable_and_thread_pointer( - Allocation_Handle vector_handle, int length, void *tp); + int length, Allocation_Handle vector_handle, void *tp); /** * alocates new multidimensional array recursively. @@ -150,7 +150,7 @@ Vector_Handle vm_multianewarray_resolved * @note XXX is it used in debug version only? -salikh */ void vm_new_vector_update_stats( - Allocation_Handle vector_handle, POINTER_SIZE_INT length, void *tp); + int length, Allocation_Handle vector_handle, void *tp); /** * allocate new object using its Class structure. @@ -189,13 +189,4 @@ ManagedObject *class_alloc_new_object_an ManagedObject *class_alloc_new_object_and_run_constructor( Class * clss, Method * constructor, uint8 * constructor_args); -/** - * allocates new object. - * - * @copydoc class_alloc_new_object() - * @note XXX exception and out of memory semantics are not specified -salikh - * @note XXX does it use non-unwinding sematics? - */ -ManagedObject *class_alloc_new_object_or_null(Class *clss); - #endif /* #ifndef _HEAP_H */ diff --git vm/vmcore/include/jit_export.h vm/vmcore/include/jit_export.h index d8160f1..7e1db2b 100644 --- vm/vmcore/include/jit_export.h +++ vm/vmcore/include/jit_export.h @@ -91,17 +91,11 @@ typedef struct OpenMethodExecutionParams /** call corresponding VM helper upon exit from the managed method */ Boolean exe_notify_method_exit : 1; - /** call corresponding VM helper upon reading a value of any instance field */ - Boolean exe_notify_instance_field_read : 1; + /** call corresponding VM helper upon reading a value of a field which has <field access mask> set */ + Boolean exe_notify_field_access : 1; - /** call corresponding VM helper upon setting a value of any instance field */ - Boolean exe_notify_instance_field_write : 1; - - /** call corresponding VM helper upon reading a value of any static field */ - Boolean exe_notify_static_field_read : 1; - - /** call corresponding VM helper upon setting a value of any static field */ - Boolean exe_notify_static_field_write : 1; + /** call corresponding VM helper upon setting a value of a field which has <field modification mask> set */ + Boolean exe_notify_field_modification : 1; /** * call corresponding VM helper upon exception throw, diff --git vm/vmcore/include/jit_runtime_support_common.h vm/vmcore/include/jit_runtime_support_common.h index 52e9667..55d2dbe 100644 --- vm/vmcore/include/jit_runtime_support_common.h +++ vm/vmcore/include/jit_runtime_support_common.h @@ -47,6 +47,13 @@ void vm_instanceof_update_stats(ManagedO void vm_checkcast_update_stats(ManagedObject *obj, Class *super); void vm_aastore_test_update_stats(ManagedObject *elem, Vector_Handle array); +void vm_rt_class_initialize(Class *clss); +void vm_rt_class_throw_linking_error(Class_Handle ch, unsigned index, unsigned opcode); + +ManagedObject* vm_rt_class_alloc_new_object(Class *c); +Vector_Handle vm_rt_new_vector(Class *vector_class, int length); +Vector_Handle vm_rt_new_vector_using_vtable_and_thread_pointer( + int length, Allocation_Handle vector_handle, void *tp); // creates a LIL code stub for checkcast or instanceof // can be used by both IA32 and IPF code diff --git vm/vmcore/include/jni_utils.h vm/vmcore/include/jni_utils.h index db89933..494cbb2 100644 --- vm/vmcore/include/jni_utils.h +++ vm/vmcore/include/jni_utils.h @@ -58,6 +58,8 @@ #ifdef __cplusplus } #endif +bool ensure_initialised(JNIEnv* jenv, Class* clss); + jobject create_default_instance(Class* clss); jobject CreateNewThrowable(JNIEnv* jenv, Class* clazz, const char * message, jthrowable cause); diff --git vm/vmcore/include/jvmti_dasm.h vm/vmcore/include/jvmti_dasm.h new file mode 100644 index 0000000..15a4aac --- /dev/null +++ vm/vmcore/include/jvmti_dasm.h @@ -0,0 +1,158 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander V. Astapchuk + * @version $Revision: $ + */ +/** + * @file + * @brief Disassembler for JVMTI interface declaration. + */ +#if !defined(__JVMTI_DASM_H_INCLUDED__) +#define __JVMTI_DASM_H_INCLUDED__ + +#include "open/types.h" +#include "jni_types.h" +#include <assert.h> + +class InstructionDisassembler { +public: + + enum Type { + OPCODEERROR, + UNKNOWN, + OTHER=UNKNOWN, + RELATIVE_JUMP, + RELATIVE_COND_JUMP, + ABSOLUTE_CALL, + RELATIVE_CALL + }; + /** + * @brief Enum of possible condtions for conditional jump-s. + * + * @note To simplify decoding, the current order of the enum constants + * exactly matches the order of ConditionalMnemonic constants + * in #EncoderBase. Reordering of this constants requires some + * changes in InstructionDisassembler::disasm. + */ + enum CondJumpType + { + JUMP_OVERFLOW=0, + JUMP_NOT_OVERFLOW=1, + JUMP_BELOW=2, JUMP_NOT_ABOVE_OR_EQUAL=JUMP_BELOW, JUMP_CARRY=JUMP_BELOW, + JUMP_NOT_BELOW=3, JUMP_ABOVE_OR_EQUAL=JUMP_NOT_BELOW, JUMP_NOT_CARRY=JUMP_NOT_BELOW, + JUMP_ZERO=4, JUMP_EQUAL=JUMP_ZERO, + JUMP_NOT_ZERO=5, JUMP_NOT_EQUAL=JUMP_NOT_ZERO, + JUMP_BELOW_OR_EQUAL=6, JUMP_NOT_ABOVE=JUMP_BELOW_OR_EQUAL, + JUMP_NOT_BELOW_OR_EQUAL=7, JUMP_ABOVE=JUMP_NOT_BELOW_OR_EQUAL, + + JUMP_SIGN=8, + JUMP_NOT_SIGN=9, + JUMP_PARITY=10, JUMP_PARITY_EVEN=JUMP_PARITY, + JUMP_NOT_PARITY=11, JUMP_PARITY_ODD=JUMP_NOT_PARITY, + JUMP_LESS=12, JUMP_NOT_GREATER_OR_EQUAL=JUMP_LESS, + JUMP_NOT_LESS=13, JUMP_GREATER_OR_EQUAL=JUMP_NOT_LESS, + JUMP_LESS_OR_EQUAL=14, JUMP_NOT_GREATER=JUMP_LESS_OR_EQUAL, + JUMP_NOT_LESS_OR_EQUAL=15, JUMP_GREATER=JUMP_NOT_LESS_OR_EQUAL, + + CondJumpType_Count = 16 + }; + + + InstructionDisassembler(NativeCodePtr address) + { + disasm(address, this); + } + + InstructionDisassembler(InstructionDisassembler &d) + { + type = d.type; + target = d.target; + len = d.len; + cond_jump_type = d.cond_jump_type; + } + + /** + * @brief Returns type of underlying instruction. + */ + Type get_type(void) const + { + return type; + } + /** + * @brief Returns length (in bytes) of underlying instruction. + * + * The size includes instruction's prefixes, if any. + */ + jint get_length_with_prefix(void) const + { + assert(type != OPCODEERROR); + return len; + } + /** + * @brief Returns absolute address of target, if applicable. + * + * For instructions other than relative JMP, CALL and conditional jumps, + * the value is undefined. + */ + NativeCodePtr get_jump_target_address(void) const + { + assert(type == RELATIVE_JUMP || type == RELATIVE_COND_JUMP || + type == ABSOLUTE_CALL || type == RELATIVE_CALL); + return target; + } + /** + * @brief Returns type of conditional jump. + * + * @note For instructions other than conditional jump, the value is + * undefined. + */ + CondJumpType get_cond_jump_type(void) const + { + assert(type == RELATIVE_COND_JUMP); + return cond_jump_type; + } + +private: + /** + * @brief Performs disassembling, fills out InstructionDisassembler's + * fields. + * + * If it's impossible (for any reason) to decode an instruction, then + * type is set to OPCODEERROR and other fields' values are undefined. + */ + static void disasm(const NativeCodePtr addr, + InstructionDisassembler * pidi); + /** + * @brief Type of instruction. + */ + Type type; + /** + * @brief Absolute address of target, if applicable. + */ + NativeCodePtr target; + /** + * @brief Length of the instruction, in bytes. + */ + unsigned len; + /** + * @brief Type of conditional jump. + */ + CondJumpType cond_jump_type; +}; + + +#endif // __JVMTI_DASM_H_INCLUDED__ diff --git vm/vmcore/include/jvmti_direct.h vm/vmcore/include/jvmti_direct.h index 6099dcf..0312b15 100644 --- vm/vmcore/include/jvmti_direct.h +++ vm/vmcore/include/jvmti_direct.h @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Gregory Shimansky * @version $Revision: 1.1.2.2.4.4 $ - */ + */ #ifndef _JVMTI_DIRECT_H_ #define _JVMTI_DIRECT_H_ @@ -74,8 +74,9 @@ struct TIEnv }; jint JNICALL create_jvmti_environment(JavaVM *vm, void **env, jint version); -void jvmti_add_dynamic_generated_code_chunk(const char *name, const void *address, jint length); jint get_thread_stack_depth(VM_thread *thread, jint* pskip = NULL); +void jvmti_set_pending_breakpoints(Method *method); +void jvmti_get_compilation_flags(OpenMethodExecutionParams *flags); /* Events functions */ @@ -102,18 +103,30 @@ void jvmti_send_class_file_load_hook_eve void jvmti_send_class_prepare_event(Class* clss); VMEXPORT void jvmti_send_thread_start_end_event(int is_start); void jvmti_send_vm_death_event(); +bool jvmti_send_jit_breakpoint_event(Registers *regs); #ifdef __cplusplus } #endif /* External events functions */ -VMEXPORT void jvmti_interpreter_exception_event_callback_call(void); -ManagedObject *jvmti_jit_exception_event_callback_call(ManagedObject *exn_object, +VMEXPORT void jvmti_interpreter_exception_event_callback_call( + ManagedObject *exc, Method *method, jlocation location, + Method *catch_method, jlocation catch_location); +ManagedObject *jvmti_jit_exception_event_callback_call(ManagedObject *exn, JIT *jit, Method *method, NativeCodePtr native_location, JIT *catch_jit, Method *catch_method, NativeCodePtr native_catch_location); +VMEXPORT void jvmti_interpreter_exception_catch_event_callback_call( + ManagedObject *exc, Method *catch_method, jlocation catch_location); +ManagedObject *jvmti_jit_exception_catch_event_callback_call(ManagedObject + *exn_object, JIT *catch_jit, Method *catch_method, + NativeCodePtr native_catch_location); VMEXPORT void jvmti_process_method_entry_event(jmethodID method); VMEXPORT void jvmti_process_method_exit_event(jmethodID method, jboolean exn_flag, jvalue ret_val); +VMEXPORT void jvmti_process_field_access_event(Field_Handle field, + jmethodID method, jlocation location, jobject* object); +VMEXPORT void jvmti_process_field_modification_event(Field_Handle field, + jmethodID method, jlocation location, jobject* object, jvalue new_value); #ifdef __cplusplus extern "C" { @@ -122,639 +135,639 @@ #endif extern struct JNINativeInterface_ jni_vtable; /* 2 : Set Event Notification Mode */ - VMEXPORT jvmtiError JNICALL jvmtiSetEventNotificationMode (jvmtiEnv* env, - jvmtiEventMode mode, - jvmtiEvent event_type, - jthread event_thread, + VMEXPORT jvmtiError JNICALL jvmtiSetEventNotificationMode (jvmtiEnv* env, + jvmtiEventMode mode, + jvmtiEvent event_type, + jthread event_thread, ...); /* 4 : Get All Threads */ - VMEXPORT jvmtiError JNICALL jvmtiGetAllThreads (jvmtiEnv* env, - jint* threads_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetAllThreads (jvmtiEnv* env, + jint* threads_count_ptr, jthread** threads_ptr); /* 5 : Suspend Thread */ - VMEXPORT jvmtiError JNICALL jvmtiSuspendThread (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiSuspendThread (jvmtiEnv* env, jthread thread); /* 6 : Resume Thread */ - VMEXPORT jvmtiError JNICALL jvmtiResumeThread (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiResumeThread (jvmtiEnv* env, jthread thread); /* 7 : Stop Thread */ - VMEXPORT jvmtiError JNICALL jvmtiStopThread (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiStopThread (jvmtiEnv* env, + jthread thread, jobject exception); /* 8 : Interrupt Thread */ - VMEXPORT jvmtiError JNICALL jvmtiInterruptThread (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiInterruptThread (jvmtiEnv* env, jthread thread); /* 9 : Get Thread Info */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadInfo (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadInfo (jvmtiEnv* env, + jthread thread, jvmtiThreadInfo* info_ptr); /* 10 : Get Owned Monitor Info */ - VMEXPORT jvmtiError JNICALL jvmtiGetOwnedMonitorInfo (jvmtiEnv* env, - jthread thread, - jint* owned_monitor_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetOwnedMonitorInfo (jvmtiEnv* env, + jthread thread, + jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr); /* 11 : Get Current Contended Monitor */ - VMEXPORT jvmtiError JNICALL jvmtiGetCurrentContendedMonitor (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetCurrentContendedMonitor (jvmtiEnv* env, + jthread thread, jobject* monitor_ptr); /* 12 : Run Agent Thread */ - VMEXPORT jvmtiError JNICALL jvmtiRunAgentThread (jvmtiEnv* env, - jthread thread, - jvmtiStartFunction proc, - const void* arg, + VMEXPORT jvmtiError JNICALL jvmtiRunAgentThread (jvmtiEnv* env, + jthread thread, + jvmtiStartFunction proc, + const void* arg, jint priority); /* 13 : Get Top Thread Groups */ - VMEXPORT jvmtiError JNICALL jvmtiGetTopThreadGroups (jvmtiEnv* env, - jint* group_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetTopThreadGroups (jvmtiEnv* env, + jint* group_count_ptr, jthreadGroup** groups_ptr); /* 14 : Get Thread Group Info */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadGroupInfo (jvmtiEnv* env, - jthreadGroup group, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadGroupInfo (jvmtiEnv* env, + jthreadGroup group, jvmtiThreadGroupInfo* info_ptr); /* 15 : Get Thread Group Children */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadGroupChildren (jvmtiEnv* env, - jthreadGroup group, - jint* thread_count_ptr, - jthread** threads_ptr, - jint* group_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadGroupChildren (jvmtiEnv* env, + jthreadGroup group, + jint* thread_count_ptr, + jthread** threads_ptr, + jint* group_count_ptr, jthreadGroup** groups_ptr); /* 16 : Get Frame Count */ - VMEXPORT jvmtiError JNICALL jvmtiGetFrameCount (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetFrameCount (jvmtiEnv* env, + jthread thread, jint* count_ptr); /* 17 : Get Thread State */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadState (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadState (jvmtiEnv* env, + jthread thread, jint* thread_state_ptr); /* 19 : Get Frame Location */ - VMEXPORT jvmtiError JNICALL jvmtiGetFrameLocation (jvmtiEnv* env, - jthread thread, - jint depth, - jmethodID* method_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetFrameLocation (jvmtiEnv* env, + jthread thread, + jint depth, + jmethodID* method_ptr, jlocation* location_ptr); /* 20 : Notify Frame Pop */ - VMEXPORT jvmtiError JNICALL jvmtiNotifyFramePop (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiNotifyFramePop (jvmtiEnv* env, + jthread thread, jint depth); /* 21 : Get Local Variable - Object */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalObject (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalObject (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jobject* value_ptr); /* 22 : Get Local Variable - Int */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalInt (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalInt (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jint* value_ptr); /* 23 : Get Local Variable - Long */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalLong (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalLong (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jlong* value_ptr); /* 24 : Get Local Variable - Float */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalFloat (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalFloat (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jfloat* value_ptr); /* 25 : Get Local Variable - Double */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalDouble (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalDouble (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jdouble* value_ptr); /* 26 : Set Local Variable - Object */ - VMEXPORT jvmtiError JNICALL jvmtiSetLocalObject (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiSetLocalObject (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jobject value); /* 27 : Set Local Variable - Int */ - VMEXPORT jvmtiError JNICALL jvmtiSetLocalInt (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiSetLocalInt (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jint value); /* 28 : Set Local Variable - Long */ - VMEXPORT jvmtiError JNICALL jvmtiSetLocalLong (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiSetLocalLong (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jlong value); /* 29 : Set Local Variable - Float */ - VMEXPORT jvmtiError JNICALL jvmtiSetLocalFloat (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiSetLocalFloat (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jfloat value); /* 30 : Set Local Variable - Double */ - VMEXPORT jvmtiError JNICALL jvmtiSetLocalDouble (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, + VMEXPORT jvmtiError JNICALL jvmtiSetLocalDouble (jvmtiEnv* env, + jthread thread, + jint depth, + jint slot, jdouble value); /* 31 : Create Raw Monitor */ - VMEXPORT jvmtiError JNICALL jvmtiCreateRawMonitor (jvmtiEnv* env, - const char* name, + VMEXPORT jvmtiError JNICALL jvmtiCreateRawMonitor (jvmtiEnv* env, + const char* name, jrawMonitorID* monitor_ptr); /* 32 : Destroy Raw Monitor */ - VMEXPORT jvmtiError JNICALL jvmtiDestroyRawMonitor (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiDestroyRawMonitor (jvmtiEnv* env, jrawMonitorID monitor); /* 33 : Raw Monitor Enter */ - VMEXPORT jvmtiError JNICALL jvmtiRawMonitorEnter (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiRawMonitorEnter (jvmtiEnv* env, jrawMonitorID monitor); /* 34 : Raw Monitor Exit */ - VMEXPORT jvmtiError JNICALL jvmtiRawMonitorExit (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiRawMonitorExit (jvmtiEnv* env, jrawMonitorID monitor); /* 35 : Raw Monitor Wait */ - VMEXPORT jvmtiError JNICALL jvmtiRawMonitorWait (jvmtiEnv* env, - jrawMonitorID monitor, + VMEXPORT jvmtiError JNICALL jvmtiRawMonitorWait (jvmtiEnv* env, + jrawMonitorID monitor, jlong millis); /* 36 : Raw Monitor Notify */ - VMEXPORT jvmtiError JNICALL jvmtiRawMonitorNotify (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiRawMonitorNotify (jvmtiEnv* env, jrawMonitorID monitor); /* 37 : Raw Monitor Notify All */ - VMEXPORT jvmtiError JNICALL jvmtiRawMonitorNotifyAll (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiRawMonitorNotifyAll (jvmtiEnv* env, jrawMonitorID monitor); /* 38 : Set Breakpoint */ - VMEXPORT jvmtiError JNICALL jvmtiSetBreakpoint (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiSetBreakpoint (jvmtiEnv* env, + jmethodID method, jlocation location); /* 39 : Clear Breakpoint */ - VMEXPORT jvmtiError JNICALL jvmtiClearBreakpoint (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiClearBreakpoint (jvmtiEnv* env, + jmethodID method, jlocation location); /* 41 : Set Field Access Watch */ - VMEXPORT jvmtiError JNICALL jvmtiSetFieldAccessWatch (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiSetFieldAccessWatch (jvmtiEnv* env, + jclass klass, jfieldID field); /* 42 : Clear Field Access Watch */ - VMEXPORT jvmtiError JNICALL jvmtiClearFieldAccessWatch (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiClearFieldAccessWatch (jvmtiEnv* env, + jclass klass, jfieldID field); /* 43 : Set Field Modification Watch */ - VMEXPORT jvmtiError JNICALL jvmtiSetFieldModificationWatch (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiSetFieldModificationWatch (jvmtiEnv* env, + jclass klass, jfieldID field); /* 44 : Clear Field Modification Watch */ - VMEXPORT jvmtiError JNICALL jvmtiClearFieldModificationWatch (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiClearFieldModificationWatch (jvmtiEnv* env, + jclass klass, jfieldID field); /* 46 : Allocate */ - VMEXPORT jvmtiError JNICALL jvmtiAllocate (jvmtiEnv* env, - jlong size, + VMEXPORT jvmtiError JNICALL jvmtiAllocate (jvmtiEnv* env, + jlong size, unsigned char** mem_ptr); /* 47 : Deallocate */ - VMEXPORT jvmtiError JNICALL jvmtiDeallocate (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiDeallocate (jvmtiEnv* env, unsigned char* mem); /* 48 : Get Class Signature */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassSignature (jvmtiEnv* env, - jclass klass, - char** signature_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetClassSignature (jvmtiEnv* env, + jclass klass, + char** signature_ptr, char** generic_ptr); /* 49 : Get Class Status */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassStatus (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiGetClassStatus (jvmtiEnv* env, + jclass klass, jint* status_ptr); /* 50 : Get Source File Name */ - VMEXPORT jvmtiError JNICALL jvmtiGetSourceFileName (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiGetSourceFileName (jvmtiEnv* env, + jclass klass, char** source_name_ptr); /* 51 : Get Class Modifiers */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassModifiers (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiGetClassModifiers (jvmtiEnv* env, + jclass klass, jint* modifiers_ptr); /* 52 : Get Class Methods */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassMethods (jvmtiEnv* env, - jclass klass, - jint* method_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetClassMethods (jvmtiEnv* env, + jclass klass, + jint* method_count_ptr, jmethodID** methods_ptr); /* 53 : Get Class Fields */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassFields (jvmtiEnv* env, - jclass klass, - jint* field_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetClassFields (jvmtiEnv* env, + jclass klass, + jint* field_count_ptr, jfieldID** fields_ptr); /* 54 : Get Implemented Interfaces */ - VMEXPORT jvmtiError JNICALL jvmtiGetImplementedInterfaces (jvmtiEnv* env, - jclass klass, - jint* interface_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetImplementedInterfaces (jvmtiEnv* env, + jclass klass, + jint* interface_count_ptr, jclass** interfaces_ptr); /* 55 : Is Interface */ - VMEXPORT jvmtiError JNICALL jvmtiIsInterface (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiIsInterface (jvmtiEnv* env, + jclass klass, jboolean* is_interface_ptr); /* 56 : Is Array Class */ - VMEXPORT jvmtiError JNICALL jvmtiIsArrayClass (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiIsArrayClass (jvmtiEnv* env, + jclass klass, jboolean* is_array_class_ptr); /* 57 : Get Class Loader */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassLoader (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiGetClassLoader (jvmtiEnv* env, + jclass klass, jobject* classloader_ptr); /* 58 : Get Object Hash Code */ - VMEXPORT jvmtiError JNICALL jvmtiGetObjectHashCode (jvmtiEnv* env, - jobject object, + VMEXPORT jvmtiError JNICALL jvmtiGetObjectHashCode (jvmtiEnv* env, + jobject object, jint* hash_code_ptr); /* 59 : Get Object Monitor Usage */ - VMEXPORT jvmtiError JNICALL jvmtiGetObjectMonitorUsage (jvmtiEnv* env, - jobject object, + VMEXPORT jvmtiError JNICALL jvmtiGetObjectMonitorUsage (jvmtiEnv* env, + jobject object, jvmtiMonitorUsage* info_ptr); /* 60 : Get Field Name (and Signature) */ - VMEXPORT jvmtiError JNICALL jvmtiGetFieldName (jvmtiEnv* env, - jclass klass, - jfieldID field, - char** name_ptr, - char** signature_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetFieldName (jvmtiEnv* env, + jclass klass, + jfieldID field, + char** name_ptr, + char** signature_ptr, char** generic_ptr); /* 61 : Get Field Declaring Class */ - VMEXPORT jvmtiError JNICALL jvmtiGetFieldDeclaringClass (jvmtiEnv* env, - jclass klass, - jfieldID field, + VMEXPORT jvmtiError JNICALL jvmtiGetFieldDeclaringClass (jvmtiEnv* env, + jclass klass, + jfieldID field, jclass* declaring_class_ptr); /* 62 : Get Field Modifiers */ - VMEXPORT jvmtiError JNICALL jvmtiGetFieldModifiers (jvmtiEnv* env, - jclass klass, - jfieldID field, + VMEXPORT jvmtiError JNICALL jvmtiGetFieldModifiers (jvmtiEnv* env, + jclass klass, + jfieldID field, jint* modifiers_ptr); /* 63 : Is Field Synthetic */ - VMEXPORT jvmtiError JNICALL jvmtiIsFieldSynthetic (jvmtiEnv* env, - jclass klass, - jfieldID field, + VMEXPORT jvmtiError JNICALL jvmtiIsFieldSynthetic (jvmtiEnv* env, + jclass klass, + jfieldID field, jboolean* is_synthetic_ptr); /* 64 : Get Method Name (and Signature) */ - VMEXPORT jvmtiError JNICALL jvmtiGetMethodName (jvmtiEnv* env, - jmethodID method, - char** name_ptr, - char** signature_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetMethodName (jvmtiEnv* env, + jmethodID method, + char** name_ptr, + char** signature_ptr, char** generic_ptr); /* 65 : Get Method Declaring Class */ - VMEXPORT jvmtiError JNICALL jvmtiGetMethodDeclaringClass (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiGetMethodDeclaringClass (jvmtiEnv* env, + jmethodID method, jclass* declaring_class_ptr); /* 66 : Get Method Modifiers */ - VMEXPORT jvmtiError JNICALL jvmtiGetMethodModifiers (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiGetMethodModifiers (jvmtiEnv* env, + jmethodID method, jint* modifiers_ptr); /* 68 : Get Max Locals */ - VMEXPORT jvmtiError JNICALL jvmtiGetMaxLocals (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiGetMaxLocals (jvmtiEnv* env, + jmethodID method, jint* max_ptr); /* 69 : Get Arguments Size */ - VMEXPORT jvmtiError JNICALL jvmtiGetArgumentsSize (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiGetArgumentsSize (jvmtiEnv* env, + jmethodID method, jint* size_ptr); /* 70 : Get Line Number Table */ - VMEXPORT jvmtiError JNICALL jvmtiGetLineNumberTable (jvmtiEnv* env, - jmethodID method, - jint* entry_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetLineNumberTable (jvmtiEnv* env, + jmethodID method, + jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr); /* 71 : Get Method Location */ - VMEXPORT jvmtiError JNICALL jvmtiGetMethodLocation (jvmtiEnv* env, - jmethodID method, - jlocation* start_location_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetMethodLocation (jvmtiEnv* env, + jmethodID method, + jlocation* start_location_ptr, jlocation* end_location_ptr); /* 72 : Get Local Variable Table */ - VMEXPORT jvmtiError JNICALL jvmtiGetLocalVariableTable (jvmtiEnv* env, - jmethodID method, - jint* entry_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetLocalVariableTable (jvmtiEnv* env, + jmethodID method, + jint* entry_count_ptr, jvmtiLocalVariableEntry** table_ptr); /* 75 : Get Bytecodes */ - VMEXPORT jvmtiError JNICALL jvmtiGetBytecodes (jvmtiEnv* env, - jmethodID method, - jint* bytecode_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetBytecodes (jvmtiEnv* env, + jmethodID method, + jint* bytecode_count_ptr, unsigned char** bytecodes_ptr); /* 76 : Is Method Native */ - VMEXPORT jvmtiError JNICALL jvmtiIsMethodNative (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiIsMethodNative (jvmtiEnv* env, + jmethodID method, jboolean* is_native_ptr); /* 77 : Is Method Synthetic */ - VMEXPORT jvmtiError JNICALL jvmtiIsMethodSynthetic (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiIsMethodSynthetic (jvmtiEnv* env, + jmethodID method, jboolean* is_synthetic_ptr); /* 78 : Get Loaded Classes */ - VMEXPORT jvmtiError JNICALL jvmtiGetLoadedClasses (jvmtiEnv* env, - jint* class_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetLoadedClasses (jvmtiEnv* env, + jint* class_count_ptr, jclass** classes_ptr); /* 79 : Get Classloader Classes */ - VMEXPORT jvmtiError JNICALL jvmtiGetClassLoaderClasses (jvmtiEnv* env, - jobject initiating_loader, - jint* class_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetClassLoaderClasses (jvmtiEnv* env, + jobject initiating_loader, + jint* class_count_ptr, jclass** classes_ptr); /* 80 : Pop Frame */ - VMEXPORT jvmtiError JNICALL jvmtiPopFrame (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiPopFrame (jvmtiEnv* env, jthread thread); /* 87 : Redefine Classes */ - VMEXPORT jvmtiError JNICALL jvmtiRedefineClasses (jvmtiEnv* env, - jint class_count, + VMEXPORT jvmtiError JNICALL jvmtiRedefineClasses (jvmtiEnv* env, + jint class_count, const jvmtiClassDefinition* class_definitions); /* 88 : Get Version Number */ - VMEXPORT jvmtiError JNICALL jvmtiGetVersionNumber (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetVersionNumber (jvmtiEnv* env, jint* version_ptr); /* 89 : Get Capabilities */ - VMEXPORT jvmtiError JNICALL jvmtiGetCapabilities (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetCapabilities (jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr); /* 90 : Get Source Debug Extension */ - VMEXPORT jvmtiError JNICALL jvmtiGetSourceDebugExtension (jvmtiEnv* env, - jclass klass, + VMEXPORT jvmtiError JNICALL jvmtiGetSourceDebugExtension (jvmtiEnv* env, + jclass klass, char** source_debug_extension_ptr); /* 91 : Is Method Obsolete */ - VMEXPORT jvmtiError JNICALL jvmtiIsMethodObsolete (jvmtiEnv* env, - jmethodID method, + VMEXPORT jvmtiError JNICALL jvmtiIsMethodObsolete (jvmtiEnv* env, + jmethodID method, jboolean* is_obsolete_ptr); /* 92 : Suspend Thread List */ - VMEXPORT jvmtiError JNICALL jvmtiSuspendThreadList (jvmtiEnv* env, - jint request_count, - const jthread* request_list, + VMEXPORT jvmtiError JNICALL jvmtiSuspendThreadList (jvmtiEnv* env, + jint request_count, + const jthread* request_list, jvmtiError* results); /* 93 : Resume Thread List */ - VMEXPORT jvmtiError JNICALL jvmtiResumeThreadList (jvmtiEnv* env, - jint request_count, - const jthread* request_list, + VMEXPORT jvmtiError JNICALL jvmtiResumeThreadList (jvmtiEnv* env, + jint request_count, + const jthread* request_list, jvmtiError* results); /* 100 : Get All Stack Traces */ - VMEXPORT jvmtiError JNICALL jvmtiGetAllStackTraces (jvmtiEnv* env, - jint max_frame_count, - jvmtiStackInfo** stack_info_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetAllStackTraces (jvmtiEnv* env, + jint max_frame_count, + jvmtiStackInfo** stack_info_ptr, jint* thread_count_ptr); /* 101 : Get Thread List Stack Traces */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadListStackTraces (jvmtiEnv* env, - jint thread_count, - const jthread* thread_list, - jint max_frame_count, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadListStackTraces (jvmtiEnv* env, + jint thread_count, + const jthread* thread_list, + jint max_frame_count, jvmtiStackInfo** stack_info_ptr); /* 102 : Get Thread Local Storage */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadLocalStorage (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadLocalStorage (jvmtiEnv* env, + jthread thread, void** data_ptr); /* 103 : Set Thread Local Storage */ - VMEXPORT jvmtiError JNICALL jvmtiSetThreadLocalStorage (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiSetThreadLocalStorage (jvmtiEnv* env, + jthread thread, const void* data); /* 104 : Get Stack Trace */ - VMEXPORT jvmtiError JNICALL jvmtiGetStackTrace (jvmtiEnv* env, - jthread thread, - jint start_depth, - jint max_frame_count, - jvmtiFrameInfo* frame_buffer, + VMEXPORT jvmtiError JNICALL jvmtiGetStackTrace (jvmtiEnv* env, + jthread thread, + jint start_depth, + jint max_frame_count, + jvmtiFrameInfo* frame_buffer, jint* count_ptr); /* 106 : Get Tag */ - VMEXPORT jvmtiError JNICALL jvmtiGetTag (jvmtiEnv* env, - jobject object, + VMEXPORT jvmtiError JNICALL jvmtiGetTag (jvmtiEnv* env, + jobject object, jlong* tag_ptr); /* 107 : Set Tag */ - VMEXPORT jvmtiError JNICALL jvmtiSetTag (jvmtiEnv* env, - jobject object, + VMEXPORT jvmtiError JNICALL jvmtiSetTag (jvmtiEnv* env, + jobject object, jlong tag); /* 108 : Force Garbage Collection */ VMEXPORT jvmtiError JNICALL jvmtiForceGarbageCollection (jvmtiEnv* env); /* 109 : Iterate Over Objects Reachable From Object */ - VMEXPORT jvmtiError JNICALL jvmtiIterateOverObjectsReachableFromObject (jvmtiEnv* env, - jobject object, - jvmtiObjectReferenceCallback object_reference_callback, + VMEXPORT jvmtiError JNICALL jvmtiIterateOverObjectsReachableFromObject (jvmtiEnv* env, + jobject object, + jvmtiObjectReferenceCallback object_reference_callback, void* user_data); /* 110 : Iterate Over Reachable Objects */ - VMEXPORT jvmtiError JNICALL jvmtiIterateOverReachableObjects (jvmtiEnv* env, - jvmtiHeapRootCallback heap_root_callback, - jvmtiStackReferenceCallback stack_ref_callback, - jvmtiObjectReferenceCallback object_ref_callback, + VMEXPORT jvmtiError JNICALL jvmtiIterateOverReachableObjects (jvmtiEnv* env, + jvmtiHeapRootCallback heap_root_callback, + jvmtiStackReferenceCallback stack_ref_callback, + jvmtiObjectReferenceCallback object_ref_callback, void* user_data); /* 111 : Iterate Over Heap */ - VMEXPORT jvmtiError JNICALL jvmtiIterateOverHeap (jvmtiEnv* env, - jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, + VMEXPORT jvmtiError JNICALL jvmtiIterateOverHeap (jvmtiEnv* env, + jvmtiHeapObjectFilter object_filter, + jvmtiHeapObjectCallback heap_object_callback, void* user_data); /* 112 : Iterate Over Instances Of Class */ - VMEXPORT jvmtiError JNICALL jvmtiIterateOverInstancesOfClass (jvmtiEnv* env, - jclass klass, - jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, + VMEXPORT jvmtiError JNICALL jvmtiIterateOverInstancesOfClass (jvmtiEnv* env, + jclass klass, + jvmtiHeapObjectFilter object_filter, + jvmtiHeapObjectCallback heap_object_callback, void* user_data); /* 114 : Get Objects With Tags */ - VMEXPORT jvmtiError JNICALL jvmtiGetObjectsWithTags (jvmtiEnv* env, - jint tag_count, - const jlong* tags, - jint* count_ptr, - jobject** object_result_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetObjectsWithTags (jvmtiEnv* env, + jint tag_count, + const jlong* tags, + jint* count_ptr, + jobject** object_result_ptr, jlong** tag_result_ptr); /* 120 : Set JNI Function Table */ - VMEXPORT jvmtiError JNICALL jvmtiSetJNIFunctionTable (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiSetJNIFunctionTable (jvmtiEnv* env, const jniNativeInterface* function_table); /* 121 : Get JNI Function Table */ - VMEXPORT jvmtiError JNICALL jvmtiGetJNIFunctionTable (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetJNIFunctionTable (jvmtiEnv* env, jniNativeInterface** function_table); /* 122 : Set Event Callbacks */ - VMEXPORT jvmtiError JNICALL jvmtiSetEventCallbacks (jvmtiEnv* env, - const jvmtiEventCallbacks* callbacks, + VMEXPORT jvmtiError JNICALL jvmtiSetEventCallbacks (jvmtiEnv* env, + const jvmtiEventCallbacks* callbacks, jint size_of_callbacks); /* 123 : Generate Events */ - VMEXPORT jvmtiError JNICALL jvmtiGenerateEvents (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGenerateEvents (jvmtiEnv* env, jvmtiEvent event_type); /* 124 : Get Extension Functions */ - VMEXPORT jvmtiError JNICALL jvmtiGetExtensionFunctions (jvmtiEnv* env, - jint* extension_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetExtensionFunctions (jvmtiEnv* env, + jint* extension_count_ptr, jvmtiExtensionFunctionInfo** extensions); /* 125 : Get Extension Events */ - VMEXPORT jvmtiError JNICALL jvmtiGetExtensionEvents (jvmtiEnv* env, - jint* extension_count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetExtensionEvents (jvmtiEnv* env, + jint* extension_count_ptr, jvmtiExtensionEventInfo** extensions); /* 126 : Set Extension Event Callback */ - VMEXPORT jvmtiError JNICALL jvmtiSetExtensionEventCallback (jvmtiEnv* env, - jint extension_event_index, + VMEXPORT jvmtiError JNICALL jvmtiSetExtensionEventCallback (jvmtiEnv* env, + jint extension_event_index, jvmtiExtensionEvent callback); /* 127 : Dispose Environment */ VMEXPORT jvmtiError JNICALL jvmtiDisposeEnvironment (jvmtiEnv* env); /* 128 : Get Error Name */ - VMEXPORT jvmtiError JNICALL jvmtiGetErrorName (jvmtiEnv* env, - jvmtiError error, + VMEXPORT jvmtiError JNICALL jvmtiGetErrorName (jvmtiEnv* env, + jvmtiError error, char** name_ptr); /* 129 : Get JLocation Format */ - VMEXPORT jvmtiError JNICALL jvmtiGetJLocationFormat (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetJLocationFormat (jvmtiEnv* env, jvmtiJlocationFormat* format_ptr); /* 130 : Get System Properties */ - VMEXPORT jvmtiError JNICALL jvmtiGetSystemProperties (jvmtiEnv* env, - jint* count_ptr, + VMEXPORT jvmtiError JNICALL jvmtiGetSystemProperties (jvmtiEnv* env, + jint* count_ptr, char*** property_ptr); /* 131 : Get System Property */ - VMEXPORT jvmtiError JNICALL jvmtiGetSystemProperty (jvmtiEnv* env, - const char* property, + VMEXPORT jvmtiError JNICALL jvmtiGetSystemProperty (jvmtiEnv* env, + const char* property, char** value_ptr); /* 132 : Set System Property */ - VMEXPORT jvmtiError JNICALL jvmtiSetSystemProperty (jvmtiEnv* env, - const char* property, + VMEXPORT jvmtiError JNICALL jvmtiSetSystemProperty (jvmtiEnv* env, + const char* property, const char* value); /* 133 : Get Phase */ - VMEXPORT jvmtiError JNICALL jvmtiGetPhase (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetPhase (jvmtiEnv* env, jvmtiPhase* phase_ptr); /* 134 : Get Current Thread CPU Timer Information */ - VMEXPORT jvmtiError JNICALL jvmtiGetCurrentThreadCpuTimerInfo (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetCurrentThreadCpuTimerInfo (jvmtiEnv* env, jvmtiTimerInfo* info_ptr); /* 135 : Get Current Thread CPU Time */ - VMEXPORT jvmtiError JNICALL jvmtiGetCurrentThreadCpuTime (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetCurrentThreadCpuTime (jvmtiEnv* env, jlong* nanos_ptr); /* 136 : Get Thread CPU Timer Information */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadCpuTimerInfo (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadCpuTimerInfo (jvmtiEnv* env, jvmtiTimerInfo* info_ptr); /* 137 : Get Thread CPU Time */ - VMEXPORT jvmtiError JNICALL jvmtiGetThreadCpuTime (jvmtiEnv* env, - jthread thread, + VMEXPORT jvmtiError JNICALL jvmtiGetThreadCpuTime (jvmtiEnv* env, + jthread thread, jlong* nanos_ptr); /* 138 : Get Timer Information */ - VMEXPORT jvmtiError JNICALL jvmtiGetTimerInfo (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetTimerInfo (jvmtiEnv* env, jvmtiTimerInfo* info_ptr); /* 139 : Get Time */ - VMEXPORT jvmtiError JNICALL jvmtiGetTime (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetTime (jvmtiEnv* env, jlong* nanos_ptr); /* 140 : Get Potential Capabilities */ - VMEXPORT jvmtiError JNICALL jvmtiGetPotentialCapabilities (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetPotentialCapabilities (jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr); /* 142 : Add Capabilities */ - VMEXPORT jvmtiError JNICALL jvmtiAddCapabilities (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiAddCapabilities (jvmtiEnv* env, const jvmtiCapabilities* capabilities_ptr); /* 143 : Relinquish Capabilities */ - VMEXPORT jvmtiError JNICALL jvmtiRelinquishCapabilities (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiRelinquishCapabilities (jvmtiEnv* env, const jvmtiCapabilities* capabilities_ptr); /* 144 : Get Available Processors */ - VMEXPORT jvmtiError JNICALL jvmtiGetAvailableProcessors (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetAvailableProcessors (jvmtiEnv* env, jint* processor_count_ptr); /* 147 : Get Environment Local Storage */ - VMEXPORT jvmtiError JNICALL jvmtiGetEnvironmentLocalStorage (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiGetEnvironmentLocalStorage (jvmtiEnv* env, void** data_ptr); /* 148 : Set Environment Local Storage */ - VMEXPORT jvmtiError JNICALL jvmtiSetEnvironmentLocalStorage (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiSetEnvironmentLocalStorage (jvmtiEnv* env, const void* data); /* 149 : Add To Bootstrap Class Loader Search */ - VMEXPORT jvmtiError JNICALL jvmtiAddToBootstrapClassLoaderSearch (jvmtiEnv* env, + VMEXPORT jvmtiError JNICALL jvmtiAddToBootstrapClassLoaderSearch (jvmtiEnv* env, const char* segment); /* 150 : Set Verbose Flag */ - VMEXPORT jvmtiError JNICALL jvmtiSetVerboseFlag (jvmtiEnv* env, - jvmtiVerboseFlag flag, + VMEXPORT jvmtiError JNICALL jvmtiSetVerboseFlag (jvmtiEnv* env, + jvmtiVerboseFlag flag, jboolean value); /* 154 : Get Object Size */ - VMEXPORT jvmtiError JNICALL jvmtiGetObjectSize (jvmtiEnv* env, - jobject object, + VMEXPORT jvmtiError JNICALL jvmtiGetObjectSize (jvmtiEnv* env, + jobject object, jlong* size_ptr); #ifdef __cplusplus diff --git vm/vmcore/include/jvmti_interface.h vm/vmcore/include/jvmti_interface.h index 8e99638..af35e1a 100644 --- vm/vmcore/include/jvmti_interface.h +++ vm/vmcore/include/jvmti_interface.h @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Gregory Shimansky * @version $Revision: 1.1.2.1.4.4 $ - */ + */ #ifndef _JVMTI_INTF_H #define _JVMTI_INTF_H @@ -42,6 +42,39 @@ void jvmti_method_enter_callback(Method_ */ void jvmti_method_exit_callback(Method_Handle method, jvalue* return_value); +/** + * Field access callback which is called from JITted code compiled with <field access> flag whenever + * access of field which has <field access mask> set occures. + * Garbage collector must be enabled. + * @param field - handle of the field under access + * @param method - handle of the method, which accesses field + * @param location - location of code which accesses field + * @param object - pointer to the reference of the object, which field is beeng + * accessed or NULL for static field + */ +void jvmti_field_access_callback(Field_Handle field, + Method_Handle method, + jlocation location, + jobject* object); + +/** + * Field modification callback which is called from JITted code compiled with <field modification> flag whenever + * modification of field which has <field modification mask> set occures. + * Garbage collector must be enabled. + * @param field - handle of the field under modification + * @param method - handle of the method, which modifies field + * @param location - location of code which modifies field + * @param object - pointer to the reference of the object, which field is beeng + * modified or NULL for static field + * @param new_value - pointer to the new value for the field + */ +void jvmti_field_modification_callback(Field_Handle field, + Method_Handle method, + jlocation location, + jobject* object, + jvalue* new_value); + + #ifdef __cplusplus } #endif diff --git vm/vmcore/include/jvmti_internal.h vm/vmcore/include/jvmti_internal.h index db5951f..f24f757 100644 --- vm/vmcore/include/jvmti_internal.h +++ vm/vmcore/include/jvmti_internal.h @@ -26,6 +26,8 @@ #include "jit_export_jpda.h" #include <apr_dso.h> #include <apr_strings.h> #include "log_macro.h" +#include "lock_manager.h" +#include "jvmti_dasm.h" //using namespace du_ti; @@ -78,17 +80,25 @@ struct jvmti_frame_pop_listener struct BreakPoint { jmethodID method; jlocation location; + NativeCodePtr native_location; + InstructionDisassembler *disasm; void *id; BreakPoint *next; + TIEnv *env; + + BreakPoint(TIEnv *_env) : method(NULL), location(0), next(NULL), env(_env) {} +}; + +/* + * Type which will describe one watched field + */ +class Watch { +public: TIEnvList *envs; + jfieldID field; + Watch *next; - TIEnvList *find_env(TIEnv *env) - { - for(TIEnvList *el = envs; NULL != el; el = el->next) - if (el->env == env) - return el; - return NULL; - } + Watch() : envs(NULL), field(0), next(NULL) {} void add_env(TIEnvList *el) { @@ -97,6 +107,14 @@ struct BreakPoint { envs = el; } + TIEnvList *find_env(TIEnv *env) + { + for(TIEnvList *el = envs; NULL != el; el = el->next) + if (el->env == env) + return el; + return NULL; + } + void remove_env(TIEnvList *el) { assert(envs); @@ -119,30 +137,26 @@ struct BreakPoint { ABORT("Can't find the element"); } - - BreakPoint() : method(NULL), location(0), next(NULL), envs(NULL) {} -}; - -struct DynamicCode -{ - const char *name; - const void *address; - jint length; - DynamicCode *next; }; typedef struct Class Class; +/* + * JVMTI state of the VM + */ class DebugUtilsTI { public: jint agent_counter; + Lock_Manager brkpntlst_lock; + Lock_Manager TIenvs_lock; + Lock_Manager dcList_lock; DebugUtilsTI(); ~DebugUtilsTI(); jint Init(); void Shutdown(); - void setInterpreterState(Global_Env *p_env); + void setExecutionMode(Global_Env *p_env); int getVersion(char* version); void addAgent(const char*); // add agent name (string) Agent *getAgents(); @@ -163,7 +177,8 @@ class DebugUtilsTI { void addEnvironment(TIEnv *env) { - // FIXME: thread unsafe modification + // assert(TIenvs_lock._lock_or_null()); + env->next = p_TIenvs; p_TIenvs = env; } @@ -175,7 +190,8 @@ class DebugUtilsTI { if (NULL == e) return; - // FIXME: thread unsafe modification of the list + // assert(TIenvs_lock._lock_or_null()); + if (e == env) { p_TIenvs = env->next; @@ -195,18 +211,17 @@ class DebugUtilsTI { TIEnv *getEnvironments(void) { + // assert(TIenvs_lock._lock_or_null()); + return p_TIenvs; } - DynamicCode *getDynamicCodeList(void) + BreakPoint *find_breakpoint(jmethodID m, jlocation l, TIEnv *env) { - return dcList; - } + // assert(brkpntlst_lock._lock_or_null()); - BreakPoint *find_breakpoint(jmethodID m, jlocation l) - { for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) - if (bp->method == m && bp->location == l) + if (bp->method == m && bp->location == l && bp->env == env) return bp; return NULL; @@ -214,6 +229,8 @@ class DebugUtilsTI { bool have_breakpoint(jmethodID m) { + // assert(brkpntlst_lock._lock_or_null()); + for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) if (bp->method == m) return true; @@ -223,6 +240,8 @@ class DebugUtilsTI { BreakPoint* find_first_bpt(jmethodID m) { + // assert(brkpntlst_lock._lock_or_null()); + for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) if (bp->method == m) return bp; @@ -232,6 +251,8 @@ class DebugUtilsTI { BreakPoint* find_next_bpt(BreakPoint* bpt, jmethodID m) { + // assert(brkpntlst_lock._lock_or_null()); + for (BreakPoint *bp = bpt->next; NULL != bp; bp = bp->next) if (bp->method == m) return bp; @@ -239,25 +260,83 @@ class DebugUtilsTI { return NULL; } + BreakPoint* find_first_bpt(jmethodID m, jlocation l) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) + if (bp->method == m && bp->location == l) + return bp; + + return NULL; + } + + BreakPoint* find_next_bpt(BreakPoint* bpt, jmethodID m, jlocation l) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint *bp = bpt->next; NULL != bp; bp = bp->next) + if (bp->method == m && bp->location == l) + return bp; + + return NULL; + } + + BreakPoint* find_first_bpt(NativeCodePtr np) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) + if (bp->native_location == np) + return bp; + + return NULL; + } + + BreakPoint* find_next_bpt(BreakPoint* bpt, NativeCodePtr np) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint *bp = bpt->next; NULL != bp; bp = bp->next) + if (bp->native_location == np) + return bp; + + return NULL; + } + + BreakPoint *get_other_breakpoint_same_location(jmethodID m, jlocation l, TIEnv *env) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint *bp = brkpntlst; NULL != bp; bp = bp->next) + if (bp->method == m && bp->location == l && bp->env != env) + return bp; + + return NULL; + } + void add_breakpoint(BreakPoint *bp) { - // FIXME: linked list modification without synchronization + // assert(brkpntlst_lock._lock_or_null()); + bp->next = brkpntlst; brkpntlst = bp; } void remove_breakpoint(BreakPoint *bp) { + // assert(brkpntlst_lock._lock_or_null()); assert(brkpntlst); if (bp == brkpntlst) { brkpntlst = bp->next; + if (NULL != bp->disasm) + delete bp->disasm; _deallocate((unsigned char *)bp); return; } - // FIXME: linked list modification without synchronization for (BreakPoint *p_bp = brkpntlst; NULL != p_bp->next; p_bp = p_bp->next) if (p_bp->next == bp) { @@ -269,6 +348,77 @@ class DebugUtilsTI { ABORT("Can't find the breakpoint"); } + void remove_all_breakpoints_env(TIEnv *env) + { + // assert(brkpntlst_lock._lock_or_null()); + + for (BreakPoint **pp_bp = &brkpntlst; NULL != *pp_bp; ) + { + BreakPoint *p_bp = *pp_bp; + + if (p_bp->env == env) + { + *pp_bp = p_bp->next; + _deallocate((unsigned char *)p_bp); + } + else + { + pp_bp = &(p_bp->next); + } + } + } + + // Watched fields' support + + Watch** get_access_watch_list() + { + return &access_watch_list; + } + + Watch** get_modification_watch_list() + { + return &modification_watch_list; + } + + Watch *find_watch(Watch** p_watch_list, jfieldID f) + { + for (Watch *w = *p_watch_list; NULL != w; w = w->next) + if (w->field == f) + return w; + + return NULL; + } + + void add_watch(Watch** p_watch_list, Watch *w) + { + // FIXME: linked list modification without synchronization + w->next = *p_watch_list; + *p_watch_list = w; + } + + void remove_watch(Watch** p_watch_list, Watch *w) + { + assert(*p_watch_list); + + if (w == *p_watch_list) + { + *p_watch_list = w->next; + _deallocate((unsigned char *)w); + return; + } + + // FIXME: linked list modification without synchronization + for (Watch *p_w = *p_watch_list; NULL != p_w->next; p_w = p_w->next) + if (p_w->next == w) + { + p_w->next = w->next; + _deallocate((unsigned char *)w); + return; + } + + ABORT("Can't find the watch"); + } + void SetPendingNotifyLoadClass( Class *klass ); void SetPendingNotifyPrepareClass( Class *klass ); unsigned GetNumberPendingNotifyLoadClass(); @@ -282,7 +432,9 @@ class DebugUtilsTI { TI_GC_ENABLE_METHOD_EXIT = 0x02, TI_GC_ENABLE_FRAME_POP_NOTIFICATION = 0x04, TI_GC_ENABLE_SINGLE_STEP = 0x08, - TI_GC_ENABLE_EXCEPTION_EVENT = 0x10 + TI_GC_ENABLE_EXCEPTION_EVENT = 0x10, + TI_GC_ENABLE_FIELD_ACCESS_EVENT = 0x20, + TI_GC_ENABLE_FIELD_MODIFICATION_EVENT = 0x40 }; void set_global_capability(GlobalCapabilities ti_gc) @@ -292,7 +444,7 @@ class DebugUtilsTI { void reset_global_capability(GlobalCapabilities ti_gc) { - global_capabilities &= ti_gc; + global_capabilities &= ~ti_gc; } unsigned get_global_capability(GlobalCapabilities ti_gc) @@ -305,11 +457,12 @@ class DebugUtilsTI { protected: friend jint JNICALL create_jvmti_environment(JavaVM *vm, void **env, jint version); BreakPoint *brkpntlst; + Watch *access_watch_list; + Watch *modification_watch_list; bool status; Agent* agents; TIEnv* p_TIenvs; jvmtiPhase phase; - DynamicCode *dcList; const unsigned MAX_NOTIFY_LIST; Class **notifyLoadList; unsigned loadListNumber; @@ -329,6 +482,8 @@ jint load_agentpath(Agent *agent, const // Object check functions Boolean is_valid_thread_object(jthread thread); +Boolean is_valid_thread_group_object(jthreadGroup group); +Boolean is_valid_class_object(jclass klass); // JIT support jvmtiError jvmti_translate_jit_error(OpenExeJpdaError error); diff --git vm/vmcore/include/mon_enter_exit.h vm/vmcore/include/mon_enter_exit.h index f185ec6..c36a3b8 100644 --- vm/vmcore/include/mon_enter_exit.h +++ vm/vmcore/include/mon_enter_exit.h @@ -41,6 +41,9 @@ void vm_monitor_init(); // Does a monitorexit operation. extern void (*vm_monitor_exit)(ManagedObject *p_obj); extern void (*vm_monitor_enter)(ManagedObject *p_obj); +extern uint32 (*vm_monitor_try_enter)(ManagedObject *p_obj); +extern uint32 (*vm_monitor_try_exit)(ManagedObject *p_obj); + #define HASH_MASK 0x7e #ifdef __cplusplus diff --git vm/vmcore/include/native_modules.h vm/vmcore/include/native_modules.h new file mode 100755 index 0000000..7660c5f --- /dev/null +++ vm/vmcore/include/native_modules.h @@ -0,0 +1,77 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#ifndef _NATIVE_MODULES_H_ +#define _NATIVE_MODULES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SEGMENT_TYPE_UNKNOWN, + SEGMENT_TYPE_CODE, + SEGMENT_TYPE_DATA +} native_seg_type_t; + +typedef struct { + native_seg_type_t type; + void* base; + size_t size; +} native_segment_t; + +typedef struct native_module_t native_module_t; + +struct native_module_t { + char* filename; + size_t seg_count; + native_module_t* next; + native_segment_t segments[1]; +}; + + +bool get_all_native_modules(native_module_t**, int*); +void clear_native_modules(native_module_t**); + +#ifdef PLATFORM_POSIX +typedef struct _raw_module raw_module; + +// Structure to accumulate several segments for the same module +struct _raw_module +{ + void* start; + void* end; + bool acc_r; + bool acc_x; + char* name; + raw_module* next; +}; + +void native_clear_raw_list(raw_module*); +raw_module* native_add_raw_segment(raw_module*, void*, void*, char, char); +native_module_t* native_fill_module(raw_module*, size_t); +#endif // PLATFORM_POSIX + + +#ifdef __cplusplus +} +#endif + +#endif // _NATIVE_MODULES_H_ diff --git vm/vmcore/include/native_stack.h vm/vmcore/include/native_stack.h new file mode 100755 index 0000000..30b9b8f --- /dev/null +++ vm/vmcore/include/native_stack.h @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#ifndef _NATIVE_STACK_H_ +#define _NATIVE_STACK_H_ + +#include "jni.h" +#include "stack_iterator.h" +#include "native_modules.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + jint java_depth; + void* ip; + void* frame; + void* stack; +} native_frame_t; + + +// If frame_array is NULL, only returns real frame count +int walk_native_stack_registers(Registers* pregs, + VM_thread* pthread, int max_depth, native_frame_t* frame_array); + +////////////////////////////////////////////////////////////////////////////// +// Interchange between platform-dependent and general functions +void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp); +bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp); +void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp); +void native_get_sp_from_si_jit_context(StackIterator* si, void** sp); +bool native_is_out_of_stack(void* value); +bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp); +int native_test_unwind_special(native_module_t* modules, void* sp); +bool native_unwind_special(native_module_t* modules, + void* stack, void** ip, void** sp, void** bp, bool is_last); +bool native_is_ip_in_modules(native_module_t* modules, void* ip); +bool native_is_ip_stub(void* ip); + + +#ifdef __cplusplus +} +#endif + +#endif // _NATIVE_STACK_H_ diff --git vm/vmcore/include/natives_support.h vm/vmcore/include/natives_support.h index 24b0ca9..c72323e 100644 --- vm/vmcore/include/natives_support.h +++ vm/vmcore/include/natives_support.h @@ -28,6 +28,7 @@ #define _NATIVES_SUPPORT_LIB_H_ #include <apr_dso.h> #include "vm_core_types.h" +#include "String_Pool.h" #include "jni_types.h" /** diff --git vm/vmcore/include/object.h vm/vmcore/include/object.h index 70eadd0..aa99fba 100644 --- vm/vmcore/include/object.h +++ vm/vmcore/include/object.h @@ -31,6 +31,7 @@ #endif // Return the generic hashcode for an object jint object_get_generic_hashcode(JNIEnv*, jobject); +jint default_hashcode(Managed_Object_Handle obj); jobject object_clone(JNIEnv*, jobject); diff --git vm/vmcore/include/properties.h vm/vmcore/include/properties.h index 363ac21..d1be251 100644 --- vm/vmcore/include/properties.h +++ vm/vmcore/include/properties.h @@ -198,6 +198,7 @@ public: prop = prop_; } public: + Prop_entry *currentEntry() const {return current;} void reset() { current = NULL; @@ -211,9 +212,11 @@ public: for(; i < prop->BUCKET_SIZE; i++) if(prop->bucket[i]) break; - if(i == prop->BUCKET_SIZE) - return NULL; - current = prop->bucket[i]; + if(i == prop->BUCKET_SIZE) { + current = NULL; + } else { + current = prop->bucket[i]; + } idx = i; return current; } @@ -247,7 +250,12 @@ public: iter->reset(); return iter; } - + void destroyIterator(Iterator* it) + { + assert(it!=iterator); + assert(it->prop == this); + delete it; + } void add(const char* k, Prop_Value* v); /*Caller delete k and v*/ #ifdef USE_MEM_MANAGER_FOR_ALLOCATION void add(const char* k, Prop_Value* v, tl::MemoryPool& m); @@ -290,6 +298,12 @@ #endif typedef struct _properties* PropertiesHandle; VMEXPORT const char* properties_get_string_property(PropertiesHandle prop, const char* key); +VMEXPORT void properties_set_string_property(PropertiesHandle ph, const char* key, const char* value); +VMEXPORT PropertiesIteratorHandle properties_iterator_create(PropertiesHandle ph); +VMEXPORT void properties_iterator_destroy(PropertiesHandle ph, PropertiesIteratorHandle pih); +VMEXPORT Boolean properties_iterator_advance(PropertiesIteratorHandle pih); +VMEXPORT const char* properties_get_name(PropertiesIteratorHandle pih); +VMEXPORT const char* properties_get_string_value(PropertiesIteratorHandle pih); inline int Properties::index_of(const char *key) { diff --git vm/vmcore/include/reflection.h vm/vmcore/include/reflection.h index 1f4c9f0..3cc3b54 100644 --- vm/vmcore/include/reflection.h +++ vm/vmcore/include/reflection.h @@ -30,22 +30,9 @@ jobjectArray reflection_get_class_interf jobjectArray reflection_get_class_fields(JNIEnv*, jclass); jobjectArray reflection_get_class_constructors(JNIEnv*, jclass); jobjectArray reflection_get_class_methods(JNIEnv* jenv, jclass clazz); -jobjectArray reflection_get_parameter_types(JNIEnv *jenv, Class* type, jobject jmethod, Method* method = 0); - -enum reflection_fields{ - PARAMETERS, - EXCEPTIONS, - DECLARING_CLASS, - NAME, - TYPE, - VM_MEMBER, - FIELDS_NUMBER -}; - -Field* get_reflection_field(Class* clss, reflection_fields descriptor); - -Class_Member* reflection_jobject_to_Class_Member(jobject jmember, Class* type); - +jobjectArray reflection_get_parameter_types(JNIEnv *jenv, Method* method); +jobject reflection_get_enum_value(JNIEnv *jenv, Class* enum_type, String* name); bool jobjectarray_to_jvaluearray(JNIEnv* jenv, jvalue** output, Method* method, jobjectArray input); +jclass descriptor_to_jclass(Type_Info_Handle desc); #endif // !_REFLECTION_H_ diff --git vm/vmcore/include/stack_dump.h vm/vmcore/include/stack_dump.h new file mode 100755 index 0000000..3a1cded --- /dev/null +++ vm/vmcore/include/stack_dump.h @@ -0,0 +1,33 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Vladimir Nenashev + * @version $Revision$ + */ + + +#ifndef __STACK_DUMP_H_ +#define __STACK_DUMP_H_ + +#include "vm_core_types.h" +#include "jni.h" + +/** + * Prints a stack trace using given register context for current thread + */ +void st_print_stack(Registers* regs); + +#endif //!__STACK_DUMP_H_ diff --git vm/vmcore/include/stack_trace.h vm/vmcore/include/stack_trace.h old mode 100644 new mode 100755 index a7f13ea..cc984f9 --- vm/vmcore/include/stack_trace.h +++ vm/vmcore/include/stack_trace.h @@ -22,58 +22,153 @@ #ifndef _STACK_TRACE_H_ #define _STACK_TRACE_H_ -// This module provides stack traces. -// A stack trace is a sequence of frames starting from the topmost on the stack down to the bottom most. -// It inlcudes one frame for each managed stack frame, and one frame for each M2nFrame that has an associated method. -// For each frame, the method and ip is provided, and optionally the file and line number. + +/** + *@file + * Mechanism for tracing the stack of Java and native code. + * + * This module provides stack traces. A <b>stack trace</b> is a sequence + * of frames counting from the top to the bottom of the stack. + * + * The stack trace inlcudes one frame for each managed + * stack frame and one frame for each M2N frame that has an associated + * method. For each frame, the method and the IP are provided and, optionally, + * the file and line number. + * + * The current implementation supports the following types of frames: + * + * <ul> + * <li>Managed code frames corresponding to Java code + * <li>Managed-to-native frames (M2N) for transferring + * data and control between managed and native frames + * + * Native frames iteration is not currently supported. To iterate over + * native frames, use OS-provided tools. + * </ul> + */ #include <stdio.h> #include "open/vm_util.h" // Defines the StackTraceFrame structure -#include "exception.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct StackTraceFrame { + Method_Handle method; + NativeCodePtr ip; + void *outdated_this; +}; + +#ifdef __cplusplus +} +#endif #ifdef __cplusplus extern "C" { #endif -// Return the length of the stack trace for the current thread. -VMEXPORT unsigned st_get_depth(); +/** + * Gets the depth of the stack trace for the specified thread. + * + * The <b>depth</b> is the number of supported stack frames in the current + * thread stack, from most recently pushed to the first pushed. The depth + * also includes the number of inlined methods. + * + * @param[in] p_vmthread - pointer to the thread + * + * @return The number of frames above the current one including the current frame and + * inlined methods. + */ +VMEXPORT unsigned st_get_depth(VM_thread *p_vmthread); -// Return the stack frame frame at the given depth (zero based) for the current thread. -// Returns true on success, false if depth is greater than or equal to the current thread's stack trace length. -VMEXPORT bool st_get_frame(unsigned depth, StackTraceFrame*); +/** + * Fills the stack trace frame at the given depth for the current thread. + * + * @param[in] depth - the zero-based depth of the frame or inlined method, + * information about which will be stored at the given stack trace + * frame, <i>stf</i> + * @param[out] stf - the pointer to the <code>StackTraceFrame</code> structure that needs + * to be filled with the data on the frame or inlined method + * corresponding to the given depth + * + * @return <code>TRUE</code> on success, <code>FALSE</code> if the depth is greater than + * or equal to thecurrent thread's stack trace length. + */ +VMEXPORT bool st_get_frame(unsigned depth, StackTraceFrame* stf); -// Allocate required num of frames. Used internaly by interpreter to avoid -// memory allocation / deallocation conflicts in VM and DLLS in Win32 +/** + * Allocates memory required for the given number of stack trace frames. + * + * Used internaly by the interpreter to avoid memory allocation/de-allocation conflicts + * in the VM and DLLs on Windows / IA-32 systems. + * + * @param[in] num - required number of stack trace frames + * + * @return The pointer to the allocated array of stack trace frames. + * + * @note The caller is responsible for freeing the memory. + */ VMEXPORT StackTraceFrame* st_alloc_frames(int num); -// Return the stack trace for the current thread. -// The caller is responsible for freeing the memory. -VMEXPORT void st_get_trace(unsigned* depth, StackTraceFrame**); +/** + * Fills the stack trace frames for the specified number of frames of the specified thread. + * + * @param[in] p_vmthread - pointer to the thread + * @param[in] depth - the number of frames including inlined methods, + * information about which should be stored + * @param[out] stfs - the pointer to the array of stack trace frames + * created by this function and returned via this + * pointer. + * + * @note The caller is responsible for freeing the memory. + */ +VMEXPORT void st_get_trace(VM_thread *p_vmthread, unsigned* depth, + StackTraceFrame** stfs); -// Function takes method and ip and fills in source file and line number +/** + * Fills the given pointer to a source file and line number by using the given method and IP. + * + * @param[in] method - the handle of the method information to identify the source file + * @param[in] ip - the instruction pointer to identify the JIT and using the JIT line number + * @param[out] file - the pointer to the file reference to be filled by this function + * @param[out] line - the pointer to the line number to be filled by this function + */ VMEXPORT void get_file_and_line(Method_Handle method, void *ip, const char **file, int *line); #ifdef __cplusplus } #endif -// Append to buf a suitable human readable version of the frame. -void st_print_frame(ExpandableMemBlock* buf, StackTraceFrame*); +/** + * Appends data about the given frame to the expandable buffer in a human-readable form. + * + * @param[in] buf - the pointer to <code>ExpandableMemBlock</code>, where data will be added + * @param[in] stf - the pointer to the stack trace frame, data from which will be + * printed into buffer + */ +void st_print_frame(ExpandableMemBlock* buf, StackTraceFrame* stf); -// Print the current thread's trace. -// This function includes all M2nFrames. -// It is intended for debugging purposes. -void st_print(FILE*); +/** + * Prints the current thread's trace. + * + * This function supports and prints all Java and M2N frames. + * + * @param[in] f - the pointer to the file, where the stack trace will be printed + * + * @note Intended for debugging purposes. + */ +void st_print(FILE* f); +/** + * Prints the current thread's trace into the <code>stderr</code> stream. + * + * This function supports and prints all Java and M2N frames. + * + * @note Intended for debugging purposes. + */ void st_print(); -Method_Handle get_method(StackIterator* si); - - -uint32 si_get_inline_depth(StackIterator* si); - - #endif //!_STACK_TRACE_H_ diff --git vm/vmcore/include/vm_core_types.h vm/vmcore/include/vm_core_types.h index 452ae20..533d002 100644 --- vm/vmcore/include/vm_core_types.h +++ vm/vmcore/include/vm_core_types.h @@ -27,6 +27,7 @@ #include "open/types.h" // This file names all types commonly used in the VM. // It defines those types that have no other logical place, other types are defined in header files appropriate to them. +struct String; struct Class; class Class_Member; struct Field; diff --git vm/vmcore/include/vm_log.h vm/vmcore/include/vm_log.h index 3904c84..b0b80e6 100644 --- vm/vmcore/include/vm_log.h +++ vm/vmcore/include/vm_log.h @@ -56,13 +56,13 @@ inline LoggerString& operator<<(LoggerSt /** * The convenience method for logging Method instances. */ -inline LoggerString& operator<<(LoggerString& log, const Method* method) { - if (method) { - log << method->get_class() << "." - << method->get_name() - << method->get_descriptor(); +inline LoggerString& operator<<(LoggerString& log, const Class_Member* m) { + if (m) { + log << m->get_class() << "." + << m->get_name() + << m->get_descriptor(); } else { - log << "<null method>"; + log << "<null member>"; } return log; diff --git vm/vmcore/include/vm_stats.h vm/vmcore/include/vm_stats.h index 293bbf1..ab179a5 100644 --- vm/vmcore/include/vm_stats.h +++ vm/vmcore/include/vm_stats.h @@ -18,19 +18,26 @@ * @version $Revision: 1.1.2.1.4.3 $ */ - - - - #ifndef _VM_STATS_H_ #define _VM_STATS_H_ -#include "simplehashtable.h" - #ifdef VM_STATS +#include <apr_hash.h> +#include <apr_pools.h> +#include <apr_time.h> + #include "open/types.h" +#include "simplehashtable.h" +#include "lock_manager.h" +typedef struct String_Stat { + static unsigned int num_embiguity; + unsigned int num_lookup; + unsigned int num_lookup_collision; + POINTER_SIZE_INT raw_hash; + bool is_interned; +} String_Stat; class VM_Statistics { @@ -223,12 +230,23 @@ public: SimpleHashtable rt_function_requests; SimpleHashtable rt_function_calls; - VM_Statistics(); + Lock_Manager vm_stats_lock; + apr_pool_t * vm_stats_pool; + + ~VM_Statistics(); + + static VM_Statistics & get_vm_stats(); void print(); -}; //VM_Statistics -VMEXPORT extern VM_Statistics vm_stats_total; +private: + // get_vm_stats should be used to get instance + VM_Statistics(); + + void print_rt_function_stats(); + void print_string_pool_stats(); + +}; //VM_Statistics extern bool vm_print_total_stats; extern int vm_print_total_stats_level; diff --git vm/vmcore/include/vm_threads.h vm/vmcore/include/vm_threads.h index bbf6f9b..bad3999 100644 --- vm/vmcore/include/vm_threads.h +++ vm/vmcore/include/vm_threads.h @@ -36,6 +36,7 @@ #include "open/ti_thread.h" #include "vm_core_types.h" #include "object_layout.h" #include "open/vm_gc.h" +#include "exceptions_type.h" #include "jvmti.h" @@ -69,7 +70,15 @@ public: // In case exception is thrown, Exception object is put here // TODO: Needs to be replaced with jobject! - volatile ManagedObject* p_exception_object; + //volatile ManagedObject* p_exception_object; + volatile Exception thread_exception; + + // For support of JVMTI events: EXCEPTION, EXCEPTION_CATCH + // If p_exception_object is set and p_exception_object_ti is not + // - EXCEPTION event should be generated + // If p_exception_object_ti is set and p_exception_object is not + // - EXCEPTION_CATCH even should be generated + volatile ManagedObject* p_exception_object_ti; // flag which indicate that guard page on the stak should be restored bool restore_guard_page; @@ -87,6 +96,10 @@ public: bool is_stoped; JVMTILocalStorage jvmti_local_storage; + // Buffer used to create instructions instead of original instruction + // to transfer execution control back to the code after breakpoint + // has been processed + jbyte jvmti_jit_breakpoints_handling_buffer[50]; jvmti_frame_pop_listener *frame_pop_listener; // CPU registers. diff --git vm/vmcore/src/class_support/Assertion_Registry.cpp vm/vmcore/src/class_support/Assertion_Registry.cpp new file mode 100644 index 0000000..86cc722 --- /dev/null +++ vm/vmcore/src/class_support/Assertion_Registry.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision$ +*/ + +#define LOG_DOMAIN "vm.core" +#include "cxxlog.h" + +#include "assertion_registry.h" + +void Assertion_Registry::add_class(const Global_Env* genv, const char* name, unsigned len, bool value) { + Assertion_Record* rec = (Assertion_Record*)genv->mem_pool.alloc( + sizeof(Assertion_Record) + len * sizeof(char)); + rec->status = value; + rec->len = len; + strncpy(rec->name, name, len); + rec->name[len] = '\0'; + rec->next = classes; + classes = rec; +} + +void Assertion_Registry::add_package(const Global_Env* genv, const char* name, unsigned len, bool value) { + Assertion_Record* rec = (Assertion_Record*)genv->mem_pool.alloc( + sizeof(Assertion_Record) + len * sizeof(char)); + rec->status = value; + rec->len = len; + strncpy(rec->name, name, len); + rec->name[len] = '\0'; + rec->next = packages; + packages = rec; +} + +Assertion_Status Assertion_Registry::get_class_status(const char* name) const { + for (Assertion_Record* it = classes; it != NULL; it = it->next) { + if (strcmp(name, it->name) == 0) { + return it->status ? ASRT_ENABLED : ASRT_DISABLED; + } + } + return ASRT_UNSPECIFIED; +} + +Assertion_Status Assertion_Registry::get_package_status(const char* name) const { + unsigned best_len = 0; + Assertion_Status status = ASRT_UNSPECIFIED; + for (Assertion_Record* it = packages; it != NULL; it = it->next) { + unsigned len = it->len; + if (len == 0 && !strchr(name, '.')) { + //have a match for default package + return it->status ? ASRT_ENABLED : ASRT_DISABLED; + } + if ((strncmp(name, it->name, len) == 0) && ('.' == name[len])) { + if (len > best_len) { + best_len = len; + status = it->status ? ASRT_ENABLED : ASRT_DISABLED; + } + } + } + return status; +} diff --git vm/vmcore/src/class_support/C_Interface.cpp vm/vmcore/src/class_support/C_Interface.cpp index fed3e1c..6f95054 100644 --- vm/vmcore/src/class_support/C_Interface.cpp +++ vm/vmcore/src/class_support/C_Interface.cpp @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Intel, Alexei Fedotov * @version $Revision: 1.1.2.6.2.1.2.4 $ - */ + */ #define LOG_DOMAIN "vm.core" #include "cxxlog.h" @@ -171,7 +171,17 @@ Class_Handle field_get_class(Field_Handl return ((Field *)f)->get_class(); } //field_get_class +void field_get_track_access_flag(Field_Handle f, char** address, + char* mask) +{ + return ((Field *)f)->get_track_access_flag(address, mask); +} +void field_get_track_modification_flag(Field_Handle f, char** address, + char* mask) +{ + return ((Field *)f)->get_track_modification_flag(address, mask); +} Boolean method_is_static(Method_Handle m) { @@ -290,7 +300,7 @@ method_allocate_code_block(Method_Handle JIT *jit = (JIT *)j; assert(jit); - + Byte *code_block = NULL; // the following method is safe to call from multiple threads code_block = (Byte *) method->allocate_code_block_mt(size, alignment, jit, heat, id, action); @@ -516,7 +526,6 @@ char* class_get_java_name(Class_Handle c assert(ch); return class_get_java_name((Class *)ch, VM_Global_State::loader_env)->bytes; } - unsigned class_get_flags(Class_Handle cl) { assert(cl); @@ -544,7 +553,7 @@ int class_get_depth(Class_Handle cl) } //class_get_depth //#endif -VMEXPORT +VMEXPORT Class_Handle vtable_get_class(VTable_Handle vh) { return vh->clss; } @@ -579,6 +588,7 @@ Boolean class_has_non_default_finalizer( Class_Handle class_get_super_class(Class_Handle cl) { assert(cl); +//sundr printf("class %p %p\n", cl, cl->super_class); return (Class_Handle)((Class *)cl)->super_class; } //class_get_super_class @@ -650,6 +660,7 @@ Boolean class_hint_is_exceptiontype(Clas if(ch == exc_base_clss) { return TRUE; } + //sundr printf("class name before super: %s %p\n", ch->name->bytes, ch); ch = class_get_super_class(ch); } return FALSE; @@ -707,7 +718,7 @@ Class_Handle class_get_class_of_primitiv clss = NULL; // ts07.09.02 - to allow star jit initialization break; default: - ABORT("Unknown vm data type"); // We need a better way to indicate an internal error + ABORT("Unknown vm data type"); // We need a better way to indicate an internal error } return clss; } //class_get_class_of_primitive_type @@ -722,7 +733,7 @@ VTable_Handle class_get_vtable(Class_Han const char *class_get_source_file_name(Class_Handle cl) { if (cl == 0) return 0; - if ( ((Class *)cl)->src_file_name == 0 ) + if ( ((Class *)cl)->src_file_name == 0 ) return 0; return ((Class *)cl)->src_file_name->bytes; } //class_get_source_file_name @@ -755,7 +766,7 @@ const char *class_get_const_string(Class // Returns the address where the interned version of the string is stored: this will be the address -// of a slot containing a Java_java_lang_String* or a uint32 compressed reference. Also interns the +// of a slot containing a Java_java_lang_String* or a uint32 compressed reference. Also interns the // string so that the JIT can load a reference to the interned string without checking if it is null. void *class_get_const_string_intern_addr(Class_Handle cl, unsigned index) { @@ -775,9 +786,11 @@ void *class_get_const_string_intern_addr // vm_instantiate_cp_string_resolved assumes that GC is disabled tmn_suspend_disable(); // Discard the result. We are only interested in the side-effect of setting str->intern. + BEGIN_RAISE_AREA; vm_instantiate_cp_string_resolved(str); + END_RAISE_AREA; tmn_suspend_enable(); - + } if (env->compress_references) { @@ -808,7 +821,7 @@ VM_Data_Type class_get_cp_field_type(Cla // TODO: check that cp_index is valid for src_class; assert for now assert(cp_index < ((Class*)src_class)->cp_size); assert(cp_is_fieldref(((Class*)src_class)->const_pool, cp_index)); - + char class_id = (class_get_cp_entry_signature(src_class, cp_index))[0]; switch(class_id) { @@ -865,7 +878,7 @@ Arg_List_Iterator method_get_argument_li -Class_Handle +Class_Handle vm_resolve_class(Compile_Handle h, Class_Handle c, unsigned index) @@ -876,7 +889,7 @@ vm_resolve_class(Compile_Handle h, -Class_Handle +Class_Handle vm_resolve_class_new(Compile_Handle h, Class_Handle c, unsigned index) @@ -942,11 +955,7 @@ class_load_class_by_descriptor(const cha case 'L': { int len = (int) strlen(descr); - //char *name = new char[len]; - //memcpy(name, descr + 1, len - 2); - //name[len - 2] = 0; n = env->string_pool.lookup(descr + 1, len - 2); - //delete []name; } break; case 'B': @@ -996,11 +1005,12 @@ Class_Handle class_find_loaded(ClassLoad Class_Handle class_find_class_from_loader(ClassLoaderHandle loader, const char* n, Boolean init) { + ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // -salikh char *new_name = strdup(n); char *p = new_name; while (*p) { - if (*p == '.') *p = '/'; + if (*p == '.') *p = '/'; p++; } String* name = VM_Global_State::loader_env->string_pool.lookup(new_name); @@ -1016,9 +1026,15 @@ Class_Handle class_find_class_from_loade if (!ch) return NULL; // All initialization from jni should not propagate exceptions and // should return to calling native method. - if(init) class_initialize_from_jni(ch); + if(init) { + class_initialize_from_jni(ch); - if(exn_get()) { + if (exn_raised()) { + return NULL; + } + } + + if(exn_raised()) { return 0; } @@ -1191,7 +1207,7 @@ Class_Handle method_get_throws(Method_Ha Class *c = class_loader->LoadVerifyAndPrepareClass(VM_Global_State::loader_env, exn_name); if (!c && !exn_raised()) { - exn_raise_only(class_loader->GetClassError(exn_name->bytes)); + exn_raise_object(class_loader->GetClassError(exn_name->bytes)); } return (Class_Handle)c; } @@ -1333,6 +1349,14 @@ Class_Handle get_system_object_class() +Class_Handle get_system_class_class() +{ + Global_Env *env = VM_Global_State::loader_env; + return env->JavaLangClass_Class; +} //get_system_class_class + + + Class_Handle get_system_string_class() { Global_Env *env = VM_Global_State::loader_env; @@ -1441,12 +1465,10 @@ Boolean class_is_compact_field() } #endif -// 20020220 TO DO: -// 1. Add the is_enum field to the Java build of VM? Boolean class_is_enum(Class_Handle ch) { assert(ch); - return FALSE; + return ((ch->access_flags & ACC_ENUM) == 0) ? FALSE : TRUE; } //class_is_enum @@ -1488,7 +1510,7 @@ static Class *class_get_array_of_primiti case VM_DATA_TYPE_INTPTR: case VM_DATA_TYPE_UINTPTR: default: - ABORT("Unexpected vm data type"); // We need a better way to indicate an internal error + ABORT("Unexpected vm data type"); // We need a better way to indicate an internal error break; } return clss; @@ -1503,7 +1525,7 @@ Class_Handle class_get_array_of_unboxed( VM_Data_Type typ = class_get_primitive_type_of_class(ch); return class_get_array_of_primitive_type(typ); } else { - // 20020319 This should never happen for Java. + // 20020319 This should never happen for Java. ABORT("The given class handle does not represent a primitive type"); return 0; } @@ -1761,7 +1783,7 @@ Class_Handle field_get_class_of_field_va { assert(hythread_is_suspend_enabled()); assert(fh); - Class_Handle ch = class_load_class_by_descriptor(field_get_descriptor(fh), + Class_Handle ch = class_load_class_by_descriptor(field_get_descriptor(fh), field_get_class(fh)); if(!class_verify(VM_Global_State::loader_env, ch)) return NULL; @@ -1959,7 +1981,7 @@ Boolean type_info_is_unmanaged_pointer(T Boolean type_info_is_void(Type_Info_Handle tih) { - TypeDesc* td = (TypeDesc*)tih; + TypeDesc* td = (TypeDesc*)tih; assert(td); return td->get_kind()==K_Void; } //type_info_is_void @@ -2014,6 +2036,10 @@ Class_Handle type_info_get_class(Type_In Managed_Object_Handle* type_info_get_loading_error(Type_Info_Handle tih) { TypeDesc* td = (TypeDesc*) tih; + if (td->is_vector()) { + Managed_Object_Handle* err = type_info_get_loading_error((Type_Info_Handle)td->get_element_type()); + if (err) return err; + } const String* name = td->get_type_name(); ClassLoader* cl = td->get_classloader(); jthrowable ex = class_get_error(cl, name->bytes); @@ -2135,7 +2161,7 @@ WeakReferenceType class_is_reference(Cla int class_get_referent_offset(Class_Handle ch) { - Field_Handle referent = + Field_Handle referent = class_lookup_field_recursive(ch, "referent", "Ljava/lang/Object;"); if (!referent) { DIE("Class " << class_get_name(ch) << " have no 'Object referent' field"); @@ -2163,7 +2189,7 @@ unsigned class_get_alignment_unboxed(Cla // // Returns the size of an element in the array class. -// +// unsigned class_element_size(Class_Handle ch) { assert(ch); @@ -2220,7 +2246,7 @@ Boolean method_is_require_security_objec #define QUAL_NAME_BUFF_SIZE 128 -// Class ch is a subclass of method_get_class(mh). The function returns a method handle +// Class ch is a subclass of method_get_class(mh). The function returns a method handle // for an accessible method overriding mh in ch or in its closest superclass that overrides mh. // Class ch must be a class not an interface. Method_Handle method_find_overridden_method(Class_Handle ch, Method_Handle mh) @@ -2428,14 +2454,14 @@ int vm_max_fast_instanceof_depth() //////////////////////////////////////////////////////////////////////////////////// -// Direct call-related functions that allow a JIT to be notified whenever a VM data +// Direct call-related functions that allow a JIT to be notified whenever a VM data // structure changes that would require code patching or recompilation. //////////////////////////////////////////////////////////////////////////////////// -// Called by a JIT in order to be notified whenever the given class (or any of its subclasses?) -// is extended. The callback_data pointer will be passed back to the JIT during the callback. +// Called by a JIT in order to be notified whenever the given class (or any of its subclasses?) +// is extended. The callback_data pointer will be passed back to the JIT during the callback. // The callback function is JIT_extended_class_callback. -void vm_register_jit_extended_class_callback(JIT_Handle jit, Class_Handle clss, +void vm_register_jit_extended_class_callback(JIT_Handle jit, Class_Handle clss, void *callback_data) { assert(clss); @@ -2445,10 +2471,10 @@ void vm_register_jit_extended_class_call } //vm_register_jit_extended_class_callback -// Called by a JIT in order to be notified whenever the given method is overridden by a newly -// loaded class. The callback_data pointer will be passed back to the JIT during the callback. +// Called by a JIT in order to be notified whenever the given method is overridden by a newly +// loaded class. The callback_data pointer will be passed back to the JIT during the callback. // The callback function is JIT_overridden_method_callback. -void vm_register_jit_overridden_method_callback(JIT_Handle jit, Method_Handle method, +void vm_register_jit_overridden_method_callback(JIT_Handle jit, Method_Handle method, void *callback_data) { assert(method); @@ -2458,7 +2484,7 @@ void vm_register_jit_overridden_method_c } //vm_register_jit_overridden_method_callback -// Called by a JIT in order to be notified whenever the given method is recompiled or +// Called by a JIT in order to be notified whenever the given method is recompiled or // initially compiled. The callback_data pointer will be passed back to the JIT during the callback. // The callback method is JIT_recompiled_method_callback. void vm_register_jit_recompiled_method_callback(JIT_Handle jit, Method_Handle method, @@ -2478,8 +2504,8 @@ void vm_patch_code_block(Byte *code_bloc // 20030203 We ensure that no thread is executing code that is simultaneously being patched. // We do this in part by stopping the other threads. This ensures that no thread will try to - // execute code while it is being patched. Also, we take advantage of restrictions on the - // patches done by JIT on IPF: it replaces the branch offset in a single bundle containing + // execute code while it is being patched. Also, we take advantage of restrictions on the + // patches done by JIT on IPF: it replaces the branch offset in a single bundle containing // a branch long. Note that this function does not synchronize the I- or D-caches. // Run through list of active threads and suspend the other ones. @@ -2491,10 +2517,10 @@ void vm_patch_code_block(Byte *code_bloc } //vm_patch_code_block -// Called by a JIT to have the VM recompile a method using the specified JIT. After -// recompilation, the corresponding vtable entries will be updated, and the necessary -// callbacks to JIT_recompiled_method_callback will be made. It is a requirement that -// the method has not already been compiled by the given JIT; this means that multiple +// Called by a JIT to have the VM recompile a method using the specified JIT. After +// recompilation, the corresponding vtable entries will be updated, and the necessary +// callbacks to JIT_recompiled_method_callback will be made. It is a requirement that +// the method has not already been compiled by the given JIT; this means that multiple // instances of a JIT may need to be active at the same time. (See vm_clone_jit.) void vm_recompile_method(JIT_Handle jit, Method_Handle method) { @@ -2606,7 +2632,7 @@ void method_iterator_advance(ChaMethodIt return; // Move the class iterator forward until a class is found that - // implements the method, such that the method handle's class + // implements the method, such that the method handle's class // is equal to the current class of the iterator. Method *m = (Method *) chaClassIterator->_method; const String *name = m->get_name(); @@ -2640,3 +2666,48 @@ unsigned thread_get_suspend_request_offs //return APR_OFFSETOF(VM_thread, suspend_request); return 0; } + + + //temporary: for EscapeAnalysis prototype +unsigned thread_get_thread_state_flag_offset() { + return 0;//APR_OFFSETOF(hythread_t, state); +} + + + +void vm_properties_set_value(const char* name, const char* value) +{ + PropertiesHandle ph = (PropertiesHandle)&VM_Global_State::loader_env->properties; + properties_set_string_property(ph, name, value); +} + +// Create iterator for system properties. +// All iterators created with this method call +// must be destroyed with vm_properties_iterator_destroy +PropertiesIteratorHandle vm_properties_iterator_create() { + PropertiesHandle ph = (PropertiesHandle)&VM_Global_State::loader_env->properties; + return properties_iterator_create(ph); +} + +// Destroy iterator created by vm_properties_iterator_create +void vm_properties_iterator_destroy(PropertiesIteratorHandle props_iter) { + PropertiesHandle ph = (PropertiesHandle)&VM_Global_State::loader_env->properties; + properties_iterator_destroy(ph, props_iter); +} + +// Advance iterator to a next property. +// Return false if no more properties left to iterate +Boolean vm_properties_iterator_advance(PropertiesIteratorHandle props_iter) { + return properties_iterator_advance(props_iter); +} + +// Return a name of the current property +const char* vm_properties_get_name(PropertiesIteratorHandle props_iter) { + return properties_get_name(props_iter); + +} + +// Return a value of the current property +const char* vm_properties_get_string_value(PropertiesIteratorHandle props_iter) { + return properties_get_string_value(props_iter); +} diff --git vm/vmcore/src/class_support/Class.cpp vm/vmcore/src/class_support/Class.cpp index 5c36609..9a63b8e 100644 --- vm/vmcore/src/class_support/Class.cpp +++ vm/vmcore/src/class_support/Class.cpp @@ -21,6 +21,8 @@ #define LOG_DOMAIN "class" #include "cxxlog.h" +#include <cctype> + #include "Class.h" #include "environment.h" #include "lock_manager.h" @@ -221,6 +223,11 @@ Method::Method() _line_number_table = NULL; _local_vars_table = NULL; + _num_param_annotations = 0; + _param_annotations = NULL; + _default_value = NULL; + + pending_breakpoints = 0; } //Method::Method void Method::MethodClearInternals() @@ -249,11 +256,11 @@ void Method::MethodClearInternals() _byte_codes = NULL; } - if (_local_vars_table != NULL) + /*if (_local_vars_table != NULL) { STD_FREE(_local_vars_table); _local_vars_table = NULL; - } + }*/ if (_handlers != NULL) { @@ -316,6 +323,7 @@ void Method::unlock() // ManagedObject *struct_Class_to_java_lang_Class(Class *clss) { +//sundr printf("struct to class %s, %p, %p\n", clss->name->bytes, clss, clss->super_class); assert(!hythread_is_suspend_enabled()); assert(clss); ManagedObject** hjlc = clss->class_handle; @@ -344,7 +352,7 @@ jobject struct_Class_to_java_lang_Class_ assert(*(clss->class_handle)); ManagedObject* UNUSED jlc = *(clss->class_handle); assert(jlc->vt()); - assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class); + //assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class); #ifndef NDEBUG // gc disabling was needed only to protect assertions tmn_suspend_enable_recursive(); @@ -403,7 +411,7 @@ Class *java_lang_Class_to_struct_Class(M assert(!hythread_is_suspend_enabled()); assert(jlc != NULL); assert(jlc->vt()); - assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class); + //assert(jlc->vt()->clss == VM_Global_State::loader_env->JavaLangClass_Class); assert(VM_Global_State::loader_env->vm_class_offset != 0); Class **vm_class_ptr = (Class **)(((Byte *)jlc) + VM_Global_State::loader_env->vm_class_offset); @@ -463,17 +471,58 @@ jthrowable class_get_linking_error(Class String* class_get_java_name(Class* clss, Global_Env* env) { - if (!clss->java_name) { - unsigned len = clss->name->len + 1; - char* name = (char*) STD_ALLOCA(len); - memcpy(name, clss->name->bytes, len); - for(char *p = name; *p; ++p) { - if (*p=='/') *p='.'; + unsigned len = clss->name->len + 1; + char * name = (char*) STD_ALLOCA(len); + char * tmp_name = name; + memcpy(name, clss->name->bytes, len); + while (tmp_name = strchr(tmp_name, '/')) { + *tmp_name = '.'; + ++tmp_name; + } + return VM_Global_State::loader_env->string_pool.lookup(name); +} + +String* class_get_simple_name(Class* clss, Global_Env* env) +{ + if (!clss->simple_name) + { + if (clss->is_array) + { + String* simple_base_name = class_get_simple_name(clss->array_base_class, env); + unsigned len = simple_base_name->len; + unsigned dims = clss->n_dimensions; + char * buf = (char*)STD_ALLOCA(dims * 2 + len); + strcpy(buf, simple_base_name->bytes); + while (dims-- > 0) { + buf[len++] = '['; + buf[len++] = ']'; + } + clss->simple_name = env->string_pool.lookup(buf, len); + } + else + { + const char* fn = clss->name->bytes; + const char* start; + if (clss->enclosing_class_index) + { + const char* enclosing_name = const_pool_get_class_name(clss, + clss->enclosing_class_index); + start = fn + strlen(enclosing_name); + while (*start == '$' || isdigit(*start)) start++; + } + else + { + start = strrchr(fn, '/'); + } + + if (start) { + clss->simple_name = env->string_pool.lookup(start + 1); + } else { + clss->simple_name = const_cast<String*> (clss->name); + } } - String* str = env->string_pool.lookup(name); - clss->java_name = str; } - return clss->java_name; + return clss->simple_name; } void vm_notify_live_object_class(Class_Handle clss) @@ -659,7 +708,8 @@ class_register_methods(Class_Handle klas << klass->name->bytes << "." << name->bytes << desc->bytes); // raise an exception - exn_raise_by_name( "java/lang/NoSuchMethodError", error ); + jthrowable exc_object = exn_create("java/lang/NoSuchMethodError", error); + exn_raise_object(exc_object); return true; } } diff --git vm/vmcore/src/class_support/Class_File_Loader.cpp vm/vmcore/src/class_support/Class_File_Loader.cpp index 31278af..936f38e 100644 --- vm/vmcore/src/class_support/Class_File_Loader.cpp +++ vm/vmcore/src/class_support/Class_File_Loader.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ /** - * @author Pavel Pervov + * @author Pavel Pervov, Alexey V. Varlamov * @version $Revision: 1.1.2.6.4.6 $ */ @@ -57,6 +57,16 @@ #endif //_IPF_ // (7) interfaces cannot have super classes (assumed in preparation) // +#define REPORT_FAILED_CLASS_FORMAT(klass, msg) \ + { \ + std::stringstream ss; \ + ss << klass->name->bytes << " : " << msg; \ + klass->class_loader->ReportFailedClass(klass, "java/lang/ClassFormatError", ss); \ + } + +#define valid_cpi(clss, idx, type) \ + (idx < clss->cp_size && cp_tag(clss->const_pool, idx) == type) + String *cp_check_utf8(Const_Pool *cp, @@ -85,6 +95,8 @@ #endif } //cp_check_class +static String *common_attr_strings[N_COMMON_ATTR+1]; +static Attributes common_attrs[N_COMMON_ATTR]; static String *field_attr_strings[N_FIELD_ATTR+1]; static Attributes field_attrs[N_FIELD_ATTR]; @@ -98,38 +110,52 @@ static Attributes class_attrs[N_CLASS_AT static String *code_attr_strings[N_CODE_ATTR+1]; static Attributes code_attrs[N_CODE_ATTR]; -static String *must_recognize_attr_strings[4]; -static Attributes must_recognize_attrs[3]; +static String *must_recognize_attr_strings[5]; +static Attributes must_recognize_attrs[4]; // // initialize string pool by preloading it with commonly used strings // static bool preload_attrs(String_Pool& string_pool) { + common_attr_strings[0] = string_pool.lookup("Synthetic"); + common_attrs[0] = ATTR_Synthetic; + + common_attr_strings[1] = string_pool.lookup("Deprecated"); + common_attrs[1] = ATTR_Deprecated; + + common_attr_strings[2] = string_pool.lookup("Signature"); + common_attrs[2] = ATTR_Signature; + + common_attr_strings[3] = string_pool.lookup("RuntimeVisibleAnnotations"); + common_attrs[3] = ATTR_RuntimeVisibleAnnotations; + + common_attr_strings[4] = string_pool.lookup("RuntimeInvisibleAnnotations"); + common_attrs[4] = ATTR_RuntimeInvisibleAnnotations; + + common_attr_strings[5] = NULL; + method_attr_strings[0] = string_pool.lookup("Code"); method_attrs[0] = ATTR_Code; method_attr_strings[1] = string_pool.lookup("Exceptions"); method_attrs[1] = ATTR_Exceptions; - method_attr_strings[2] = string_pool.lookup("Synthetic"); - method_attrs[2] = ATTR_Synthetic; + method_attr_strings[2] = string_pool.lookup("RuntimeVisibleParameterAnnotations"); + method_attrs[2] = ATTR_RuntimeVisibleParameterAnnotations; - method_attr_strings[3] = string_pool.lookup("Deprecated"); - method_attrs[3] = ATTR_Deprecated; + method_attr_strings[3] = string_pool.lookup("RuntimeInvisibleParameterAnnotations"); + method_attrs[3] = ATTR_RuntimeInvisibleParameterAnnotations; - method_attr_strings[4] = NULL; + method_attr_strings[4] = string_pool.lookup("AnnotationDefault"); + method_attrs[4] = ATTR_AnnotationDefault; + + method_attr_strings[5] = NULL; field_attr_strings[0] = string_pool.lookup("ConstantValue"); field_attrs[0] = ATTR_ConstantValue; - field_attr_strings[1] = string_pool.lookup("Synthetic"); - field_attrs[1] = ATTR_Synthetic; - - field_attr_strings[2] = string_pool.lookup("Deprecated"); - field_attrs[2] = ATTR_Deprecated; - - field_attr_strings[3] = NULL; + field_attr_strings[1] = NULL; class_attr_strings[0] = string_pool.lookup("SourceFile"); class_attrs[0] = ATTR_SourceFile; @@ -140,7 +166,10 @@ static bool preload_attrs(String_Pool& s class_attr_strings[2] = string_pool.lookup("SourceDebugExtension"); class_attrs[2] = ATTR_SourceDebugExtension; - class_attr_strings[3] = NULL; + class_attr_strings[3] = string_pool.lookup("EnclosingMethod"); + class_attrs[3] = ATTR_EnclosingMethod; + + class_attr_strings[4] = NULL; code_attr_strings[0] = string_pool.lookup("LineNumberTable"); code_attrs[0] = ATTR_LineNumberTable; @@ -148,7 +177,10 @@ static bool preload_attrs(String_Pool& s code_attr_strings[1] = string_pool.lookup("LocalVariableTable"); code_attrs[1] = ATTR_LocalVariableTable; - code_attr_strings[2] = NULL; + code_attr_strings[2] = string_pool.lookup("LocalVariableTypeTable"); + code_attrs[2] = ATTR_LocalVariableTypeTable; + + code_attr_strings[3] = NULL; must_recognize_attr_strings[0] = string_pool.lookup("Code"); must_recognize_attrs[0] = ATTR_Code; @@ -159,19 +191,45 @@ static bool preload_attrs(String_Pool& s must_recognize_attr_strings[2] = string_pool.lookup("Exceptions"); must_recognize_attrs[2] = ATTR_Exceptions; - must_recognize_attr_strings[3] = NULL; + must_recognize_attr_strings[3] = string_pool.lookup("Signature"); + must_recognize_attrs[3] = ATTR_Signature; + + must_recognize_attr_strings[4] = NULL; return true; } //init_loader +String* parse_signature_attr(ByteReader &cfs, + uint32 attr_len, + Class* clss) +{ + if (attr_len != 2) { + REPORT_FAILED_CLASS_FORMAT(clss, + "unexpected length of Signature attribute : " << attr_len); + return NULL; + } + uint16 idx; + if (!cfs.parse_u2_be(&idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse Signature index"); + return NULL; + } + String* sig = cp_check_utf8(clss->const_pool, clss->cp_size, idx); + if(!sig) { + REPORT_FAILED_CLASS_FORMAT(clss, "invalid Signature index : " << idx); + } + return sig; +} + Attributes parse_attribute(ByteReader &cfs, Const_Pool *cp, unsigned cp_size, String *attr_strings[], Attributes attrs[], - uint32 *attr_len) + uint32 *attr_len, + bool use_common = true) { static bool UNUSED init = preload_attrs(VM_Global_State::loader_env->string_pool); @@ -192,6 +250,12 @@ #endif return ATTR_ERROR; } unsigned i; + if (use_common) { + for (i=0; common_attr_strings[i] != NULL; i++) { + if (common_attr_strings[i] == attr_name) + return common_attrs[i]; + } + } for (i=0; attr_strings[i] != NULL; i++) { if (attr_strings[i] == attr_name) return attrs[i]; @@ -217,6 +281,327 @@ #endif return ATTR_UNDEF; } //parse_attribute +// forward declaration +uint32 parse_annotation_value(AnnotationValue& value, ByteReader& cfs, Class* clss); + +// returns number of read bytes, 0 if error occurred +uint32 parse_annotation(Annotation** value, ByteReader& cfs, Class* clss) +{ + uint16 type_idx; + if (!cfs.parse_u2_be(&type_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse type index of annotation"); + return 0; + } + String* type = cp_check_utf8(clss->const_pool, clss->cp_size, type_idx); + if (type == NULL) { + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid type index of annotation : " << type_idx); + return 0; + } + + uint16 num_elements; + if (!cfs.parse_u2_be(&num_elements)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse number of annotation elements"); + return 0; + } + + Annotation* antn = (Annotation*) clss->class_loader->Alloc( + sizeof(Annotation) + num_elements * sizeof(AnnotationElement)); + antn->type = type; + antn->num_elements = num_elements; + antn->elements = (AnnotationElement*)((POINTER_SIZE_INT)antn + sizeof(Annotation)); + *value = antn; + + uint32 read_len = 4; + + for (unsigned j = 0; j < num_elements; j++) + { + uint16 name_idx; + if (!cfs.parse_u2_be(&name_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse element_name_index of annotation element"); + return 0; + } + antn->elements[j].name = cp_check_utf8(clss->const_pool, clss->cp_size, name_idx); + if (antn->elements[j].name == NULL) { + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid element_name_index of annotation : " << name_idx); + return 0; + } + + uint16 size = parse_annotation_value(antn->elements[j].value, cfs, clss); + if (size == 0) { + return 0; + } + read_len += size + 2; + } + + return read_len; +} + +// returns number of read bytes, 0 if error occurred +uint32 parse_annotation_value(AnnotationValue& value, ByteReader& cfs, Class* clss) +{ + uint8 tag; + if (!cfs.parse_u1(&tag)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse annotation value tag"); + return 0; + } + value.tag = (AnnotationValueType)tag; + uint32 read_len = 1; + + Const_Pool *cp = clss->const_pool; + unsigned cp_size = clss->cp_size; + + char ctag = (char)tag; + switch(ctag) { + case AVT_BOOLEAN: + case AVT_BYTE: + case AVT_SHORT: + case AVT_CHAR: + case AVT_INT: + case AVT_LONG: + case AVT_FLOAT: + case AVT_DOUBLE: + case AVT_STRING: + { + uint16 const_idx; + if (!cfs.parse_u2_be(&const_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse const index of annotation value"); + return 0; + } + switch (ctag) { + case AVT_BOOLEAN: + case AVT_BYTE: + case AVT_SHORT: + case AVT_CHAR: + case AVT_INT: + if (valid_cpi(clss, const_idx, CONSTANT_Integer)) { + value.const_value.i = cp[const_idx].int_value; + break; + } + case AVT_FLOAT: + if (valid_cpi(clss, const_idx, CONSTANT_Float)) { + value.const_value.f = cp[const_idx].float_value; + break; + } + case AVT_LONG: + if (valid_cpi(clss, const_idx, CONSTANT_Long)) { + value.const_value.l.lo_bytes = cp[const_idx].CONSTANT_8byte.low_bytes; + value.const_value.l.hi_bytes = cp[const_idx].CONSTANT_8byte.high_bytes; + break; + } + case AVT_DOUBLE: + if (valid_cpi(clss, const_idx, CONSTANT_Double)) { + value.const_value.l.lo_bytes = cp[const_idx].CONSTANT_8byte.low_bytes; + value.const_value.l.hi_bytes = cp[const_idx].CONSTANT_8byte.high_bytes; + break; + } + case AVT_STRING: + if (valid_cpi(clss, const_idx, CONSTANT_Utf8)) { + value.const_value.string = cp[const_idx].CONSTANT_Utf8.string; + break; + } + default: + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid const index " << const_idx + << " of annotation value of type " <<ctag); + return 0; + } + read_len += 2; + } + break; + + case AVT_CLASS: + { + uint16 class_idx; + if (!cfs.parse_u2_be(&class_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse class_info_index of annotation value"); + return 0; + } + value.class_name = cp_check_utf8(cp, cp_size, class_idx); + if (value.class_name == NULL) { + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid class_info_index of annotation value: " << class_idx); + return 0; + } + read_len += 2; + } + break; + + case AVT_ENUM: + { + uint16 type_idx; + if (!cfs.parse_u2_be(&type_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse type_name_index of annotation enum value"); + return 0; + } + value.enum_const.type = cp_check_utf8(cp, cp_size, type_idx); + if (value.enum_const.type == NULL) { + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid type_name_index of annotation enum value: " << type_idx); + return 0; + } + uint16 name_idx; + if (!cfs.parse_u2_be(&name_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse const_name_index of annotation enum value"); + return 0; + } + value.enum_const.name = cp_check_utf8(cp, cp_size, name_idx); + if (value.enum_const.name == NULL) { + REPORT_FAILED_CLASS_FORMAT(clss, + "invalid const_name_index of annotation enum value: " << name_idx); + return 0; + } + read_len += 4; + } + break; + + case AVT_ANNOTN: + { + uint32 size = parse_annotation(&value.nested, cfs, clss); + if (size == 0) { + return 0; + } + read_len += size; + } + break; + + case AVT_ARRAY: + { + uint16 num; + if (!cfs.parse_u2_be(&num)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse num_values of annotation array value"); + return 0; + } + read_len += 2; + value.array.length = num; + if (num) { + value.array.items = (AnnotationValue*) clss->class_loader->Alloc( + num * sizeof(AnnotationValue)); + for (int i = 0; i < num; i++) { + uint32 size = parse_annotation_value(value.array.items[i], cfs, clss); + if (size == 0) { + return 0; + } + read_len += size; + } + } + } + break; + + default: + REPORT_FAILED_CLASS_FORMAT(clss, + "unrecognized annotation value tag : " << ctag); + return 0; + } + + return read_len; +} + +// returns number of read bytes, 0 if error occurred +uint32 parse_annotation_table(AnnotationTable ** table, ByteReader& cfs, Class* clss) +{ + uint16 num_annotations; + if (!cfs.parse_u2_be(&num_annotations)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse number of Annotations"); + return 0; + } + uint32 read_len = 2; + + if (num_annotations) { + *table = (AnnotationTable*) clss->class_loader->Alloc( + sizeof (AnnotationTable) + (num_annotations - 1)*sizeof(Annotation*)); + (*table)->length = num_annotations; + + for (unsigned i = 0; i < num_annotations; i++) + { + uint16 size = parse_annotation((*table)->table + i, cfs, clss); + if (size == 0) { + return 0; + } + read_len += size; + } + } else { + *table = NULL; + } + + return read_len; +} + + +Attributes Class_Member::process_common_attribute(Attributes attr, uint32 attr_len, ByteReader& cfs) +{ + switch(attr) { + case ATTR_Synthetic: + if(attr_len != 0) { + REPORT_FAILED_CLASS_FORMAT(_class, + "non-zero length of Synthetic attribute for class member " + << _name->bytes << " " <<_descriptor->bytes ); + return ATTR_ERROR; + } + _synthetic = true; + _access_flags |= ACC_SYNTHETIC; + break; + + case ATTR_Deprecated: + if(attr_len != 0) { + REPORT_FAILED_CLASS_FORMAT(_class, + "non-zero length of Deprecated attribute for class member " + << _name->bytes << " " <<_descriptor->bytes ); + return ATTR_ERROR; + } + _deprecated = true; + break; + + case ATTR_Signature: + { + if (!(_signature = parse_signature_attr(cfs, attr_len, _class))) { + return ATTR_ERROR; + } + } + break; + + case ATTR_RuntimeVisibleAnnotations: + { + uint32 read_len = parse_annotation_table(&_annotations, cfs, _class); + if (read_len == 0) { + return ATTR_ERROR; + } else if (attr_len != read_len) { + REPORT_FAILED_CLASS_FORMAT(_class, + "error parsing Annotations attribute for class member " + << _name->bytes << " " <<_descriptor->bytes + << "; declared length " << attr_len + << " does not match actual " << read_len); + return ATTR_ERROR; + } + } + break; + + case ATTR_RuntimeInvisibleAnnotations: + { + if(!cfs.skip(attr_len)) { + REPORT_FAILED_CLASS_FORMAT(_class, + "failed to skip RuntimeInvisibleAnnotations attribute"); + return ATTR_ERROR; + } + } + break; + + default: + return ATTR_UNDEF; + } + return attr; +} void* Class_Member::Alloc(size_t size) { ClassLoader* cl = get_class()->class_loader; @@ -228,23 +613,20 @@ void* Class_Member::Alloc(size_t size) { bool Class_Member::parse(Class *clss, Const_Pool *cp, unsigned cp_size, ByteReader &cfs) { if (!cfs.parse_u2_be(&_access_flags)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": error parsing field/method access flags"); + REPORT_FAILED_CLASS_FORMAT(clss, "cannot parse member access flags"); return false; } _class = clss; uint16 name_index; if (!cfs.parse_u2_be(&name_index)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": error parsing field/method name"); + REPORT_FAILED_CLASS_FORMAT(clss, "cannot parse member name index"); return false; } uint16 descriptor_index; if (!cfs.parse_u2_be(&descriptor_index)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": error parsing field/method descriptor"); + REPORT_FAILED_CLASS_FORMAT(clss, "cannot parse member descriptor index"); return false; } @@ -255,9 +637,9 @@ bool Class_Member::parse(Class *clss, Co String *name = cp_check_utf8(cp,cp_size,name_index); String *descriptor = cp_check_utf8(cp,cp_size,descriptor_index); if (name == NULL || descriptor == NULL) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": error parsing field/method: constant pool index " << name_index << " or " << descriptor_index - << " is not CONSTANT_Utf8 entry"); + REPORT_FAILED_CLASS_FORMAT(clss, + "some of member name or descriptor indexes is not CONSTANT_Utf8 entry : " + << name_index << " or " << descriptor_index); return false; } _name = name; @@ -265,6 +647,44 @@ bool Class_Member::parse(Class *clss, Co return true; } //Class_Member::parse +// JVM spec: +// Unqualified names must not contain the characters ’.’, ’;’, ’[’ or ’/’. Method names are +// further constrained so that, with the exception of the special method names (§3.9) +// <init> and <clinit>, they must not contain the characters ’<’ or ’>’. +static inline bool +check_field_name(const String *name) +{ + for (const char* ch = name->bytes; ch[0] != '\0'; ++ch) { + switch(ch[0]){ + case '.': + case ';': + case '[': + case '/': + return false; + } + } + return true; +} + +static inline bool +check_method_name(const String *name, const Global_Env& env) +{ + if (name == env.Init_String || name == env.Clinit_String) + return true; + + for (const char* ch = name->bytes; ch[0] != '\0'; ++ch) { + switch(ch[0]){ + case '.': + case ';': + case '[': + case '/': + case '<': + case '>': + return false; + } + } + return true; +} static inline bool check_field_descriptor( const char *descriptor, @@ -303,11 +723,12 @@ check_field_descriptor( const char *desc *next = iterator + 1; return true; } - // break; // exclude remark #111: statement is unreachable case '[': { - // descriptor is checked in recursion - if(!check_field_descriptor(descriptor + 1, next, is_void_legal )) + unsigned dim = 1; + while(*(++descriptor) == '[') dim++; + if (dim > 255) return false; + if(!check_field_descriptor(descriptor, next, is_void_legal )) return false; return true; } @@ -323,32 +744,36 @@ bool Field::parse(Class *clss, Const_Poo if(!Class_Member::parse(clss, cp, cp_size, cfs)) return false; - // check field descriptor - const char *next; - if(!check_field_descriptor(get_descriptor()->bytes, &next, false) || *next != '\0') { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": bad field descriptor"); + if(!check_field_name(_name)) { + REPORT_FAILED_CLASS_FORMAT(clss, "illegal field name : " << _name->bytes); return false; } - if((is_public() && is_protected() || is_protected() && is_private() || is_public() && is_private()) - || (is_final() && is_volatile())) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": field " << get_name()->bytes << " has invalid combination of access flags"); + // check field descriptor + const char *next; + if(!check_field_descriptor(_descriptor->bytes, &next, false) || *next != '\0') { + REPORT_FAILED_CLASS_FORMAT(clss, "illegal field descriptor : " << _descriptor->bytes); return false; } // check interface fields access flags if( class_is_interface(clss) ) { - if(!(is_public() && is_static() && is_final()) || - is_private() || is_protected() || is_volatile() || is_transient()) - { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": interface field " - << get_descriptor()->bytes << " " - << clss->name->bytes << "." << get_name()->bytes + if(!(is_public() && is_static() && is_final())){ + REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes << " does not have one of ACC_PUBLIC, ACC_STATIC, or ACC_FINAL access flags set"); return false; } + if(_access_flags & ~(ACC_FINAL | ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC)){ + REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes + << " has illegal access flags set : " << _access_flags); //FIXME to hex format + return false; + } + } else if((is_public() && is_protected() + || is_protected() && is_private() + || is_public() && is_private()) + || (is_final() && is_volatile())) { + REPORT_FAILED_CLASS_FORMAT(clss, " field " << get_name()->bytes + << " has invalid combination of access flags : " << _access_flags); //FIXME to hex format + return false; } uint16 attr_count; @@ -364,8 +789,10 @@ bool Field::parse(Class *clss, Const_Poo uint32 attr_len = 0; - for (unsigned j=0; j<attr_count; j++) { - switch (parse_attribute(cfs, cp, cp_size, field_attr_strings, field_attrs, &attr_len)){ + for (unsigned j=0; j<attr_count; j++) + { + Attributes cur_attr = parse_attribute(cfs, cp, cp_size, field_attr_strings, field_attrs, &attr_len); + switch (cur_attr) { case ATTR_ConstantValue: { // constant value attribute // JVM spec (4.7.2) says that we should silently ignore the @@ -478,36 +905,24 @@ bool Field::parse(Class *clss, Const_Poo } break; } - case ATTR_Synthetic: - if(attr_len != 0) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes - << ": invalid Synthetic attribute length for field " - << get_name()); - return false; - } - _synthetic = true; - break; - case ATTR_Deprecated: - if(attr_len != 0) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes - << ": invalid Deprecated attribute length for field " - << get_name()); - return false; - } - _deprecated = true; - break; + case ATTR_UNDEF: // unrecognized attribute; skipped break; default: - // error occured - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/InternalError", - clss->name->bytes - << ": error parsing attributes for field " - << get_name()); - return false; + switch(process_common_attribute(cur_attr, attr_len, cfs)) { + case ATTR_ERROR: + // tried and failed + return false; + case ATTR_UNDEF: + // unprocessed + REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/InternalError", + clss->name->bytes + << ": error parsing attributes for field " + << get_name() + << "; unprocessed attribute " << cur_attr); + return false; + } // switch } // switch } // for @@ -517,7 +932,7 @@ bool Field::parse(Class *clss, Const_Poo //std::stringstream ss; //ss << clss->name->bytes << ": could not create type descriptor for field " << get_name(); //jthrowable exn = exn_create("java/lang/OutOfMemoryError", ss.str().c_str()); - exn_raise_only(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return false; } set_field_type_desc(td); @@ -600,7 +1015,8 @@ bool Method::get_line_number_entry(unsig } bool Method::get_local_var_entry(unsigned index, jlong* pc, - jint* length, jint* slot, String** name, String** type) { + jint* length, jint* slot, String** name, + String** type, String** generic_type) { if (_line_number_table && index < _local_vars_table->length) { *pc = _local_vars_table->table[index].start_pc; @@ -608,6 +1024,7 @@ bool Method::get_local_var_entry(unsigne *slot = _local_vars_table->table[index].index; *name = _local_vars_table->table[index].name; *type = _local_vars_table->table[index].type; + *generic_type = _local_vars_table->table[index].generic_type; return true; } else { return false; @@ -709,101 +1126,104 @@ bool Method::_parse_line_numbers(unsigne return true; } //Method::_parse_line_numbers -bool Method::_parse_local_vars(Const_Pool *cp, unsigned cp_size, - unsigned attr_len, ByteReader &cfs) { +Local_Var_Table * Method::_parse_local_vars(Const_Pool *cp, unsigned cp_size, + unsigned attr_len, ByteReader &cfs, const char* attr_name) { uint16 n_local_vars; if(!cfs.parse_u2_be(&n_local_vars)) { REPORT_FAILED_METHOD("could not parse local variables number " - "while parsing LocalVariableTable attribute"); - return false; + "of " << attr_name << " attribute"); + return NULL; } unsigned real_lnt_attr_len = 2 + n_local_vars * 10; if(real_lnt_attr_len != attr_len) { - REPORT_FAILED_METHOD("real LocalVariableTable length differ " - "from attribute_length (" + REPORT_FAILED_METHOD("real " << attr_name << " length differ " + "from declared length (" << attr_len << " vs. " << real_lnt_attr_len << ")" ); - return false; + return NULL; + } + if (!n_local_vars) { + return NULL; } - _local_vars_table = - (Local_Var_Table *)STD_MALLOC(sizeof(Local_Var_Table) + + Local_Var_Table * table = (Local_Var_Table *)_class->class_loader->Alloc( + sizeof(Local_Var_Table) + sizeof(Local_Var_Entry) * (n_local_vars - 1)); // ppervov: FIXME: should throw OOME - _local_vars_table->length = n_local_vars; + table->length = n_local_vars; for (unsigned j = 0; j < n_local_vars; j++) { uint16 start_pc; if(!cfs.parse_u2_be(&start_pc)) { - REPORT_FAILED_METHOD("could not parse start pc " - "while parsing LocalVariableTable attribute"); - return false; + REPORT_FAILED_METHOD("could not parse start_pc " + "in " << attr_name << " attribute"); + return NULL; } uint16 length; if(!cfs.parse_u2_be(&length)) { - REPORT_FAILED_METHOD("could not parse length " - << _name->bytes << _descriptor->bytes); - return false; + REPORT_FAILED_METHOD("could not parse length entry " + "in " << attr_name << " attribute"); + return NULL; } if( (start_pc >= _byte_code_length) || (start_pc + (unsigned)length) > _byte_code_length ) { - REPORT_FAILED_METHOD("local var code range " - "[start_pc, start_pc + length] points outside bytecode " - "while parsing LocalVariableTable attribute"); - return false; + REPORT_FAILED_METHOD(attr_name << " entry " + "[start_pc, start_pc + length) points outside bytecode range"); + return NULL; } uint16 name_index; if(!cfs.parse_u2_be(&name_index)) { REPORT_FAILED_METHOD("could not parse name index " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } uint16 descriptor_index; if(!cfs.parse_u2_be(&descriptor_index)) { REPORT_FAILED_METHOD("could not parse descriptor index " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } String* name = cp_check_utf8(cp,cp_size,name_index); if(name == NULL) { REPORT_FAILED_METHOD("name index is not valid CONSTANT_Utf8 entry " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } String* descriptor = cp_check_utf8(cp,cp_size,descriptor_index); if(descriptor == NULL) { REPORT_FAILED_METHOD("descriptor index is not valid CONSTANT_Utf8 entry " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } uint16 index; if(!cfs.parse_u2_be(&index)) { REPORT_FAILED_METHOD("could not parse index " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } // FIXME Don't work with long and double if (index >= _max_locals) { REPORT_FAILED_METHOD("invalid local index " - "while parsing LocalVariableTable attribute"); - return false; + "in " << attr_name << " attribute"); + return NULL; } - _local_vars_table->table[j].start_pc = start_pc; - _local_vars_table->table[j].length = length; - _local_vars_table->table[j].index = index; - _local_vars_table->table[j].name = name; - _local_vars_table->table[j].type = descriptor; + table->table[j].start_pc = start_pc; + table->table[j].length = length; + table->table[j].index = index; + table->table[j].name = name; + table->table[j].type = descriptor; + table->table[j].generic_type = NULL; } - return true; + return table; } //Method::_parse_local_vars bool Method::_parse_code( Const_Pool *cp, unsigned cp_size, unsigned code_attr_len, ByteReader &cfs) @@ -906,9 +1326,13 @@ bool Method::_parse_code( Const_Pool *cp } real_code_attr_len += 2; + static bool TI_enabled = VM_Global_State::loader_env->TI->isEnabled(); + Local_Var_Table * generic_vars = NULL; + uint32 attr_len = 0; for (i=0; i<n_attrs; i++) { - switch (parse_attribute(cfs, cp, cp_size, code_attr_strings, code_attrs, &attr_len)){ + Attributes cur_attr = parse_attribute(cfs, cp, cp_size, code_attr_strings, code_attrs, &attr_len, false); + switch(cur_attr) { case ATTR_LineNumberTable: { if (!_parse_line_numbers(attr_len, cfs)) { @@ -918,10 +1342,10 @@ bool Method::_parse_code( Const_Pool *cp } case ATTR_LocalVariableTable: { - static bool TI_enabled = VM_Global_State::loader_env->TI->isEnabled(); if (TI_enabled) { - if (!_parse_local_vars(cp, cp_size, attr_len, cfs)) + if (!(_local_vars_table = + _parse_local_vars(cp, cp_size, attr_len, cfs, "LocalVariableTable"))) { return false; } @@ -932,6 +1356,23 @@ bool Method::_parse_code( Const_Pool *cp } break; } + case ATTR_LocalVariableTypeTable: + { + if (TI_enabled) + { + if (!(generic_vars = + _parse_local_vars(cp, cp_size, attr_len, cfs, "LocalVariableTypeTable"))) + { + return false; + } + } + else if (!cfs.skip(attr_len)) + { + REPORT_FAILED_METHOD("error skipping LocalVariableTypeTable"); + } + } + break; + case ATTR_UNDEF: // unrecognized attribute; skipped break; @@ -940,7 +1381,8 @@ bool Method::_parse_code( Const_Pool *cp REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/InternalError", _class->name->bytes << ": unknown error occured " "while parsing attributes for code of method " - << _name->bytes << _descriptor->bytes); + << _name->bytes << _descriptor->bytes + << "; unprocessed attribute " << cur_attr); return false; } // switch real_code_attr_len += 6 + attr_len; // u2 - attribute_name_index, u4 - attribute_length @@ -955,6 +1397,19 @@ bool Method::_parse_code( Const_Pool *cp return false; } + // JVM spec hints that LocalVariableTypeTable is meant to be a supplement to LocalVariableTable + // so we have no reason to cross-check these tables + if (generic_vars && _local_vars_table) { + unsigned j; + for (i = 0; i < generic_vars->length; ++i) { + for (j = 0; j < _local_vars_table->length; ++j) { + if (generic_vars->table[i].name == _local_vars_table->table[j].name) { + _local_vars_table->table[j].generic_type = generic_vars->table[i].type; + } + } + } + } + return true; } //Method::_parse_code @@ -988,6 +1443,11 @@ bool Method::parse(Global_Env& env, Clas if (!Class_Member::parse(clss, cp, cp_size, cfs)) return false; + if(!check_method_name(_name, env)) { + REPORT_FAILED_CLASS_FORMAT(clss, "illegal method name : " << _name->bytes); + return false; + } + // check method descriptor if(!check_method_descriptor(_descriptor->bytes)) { REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/ClassFormatError", @@ -1075,7 +1535,7 @@ bool Method::parse(Global_Env& env, Clas return false; } } - if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract())) { + if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract() || is_bridge())) { REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/ClassFormatError", _class->name->bytes << "." << _name->bytes << _descriptor->bytes << ": constructor cannot have access flags other then " @@ -1104,45 +1564,105 @@ bool Method::parse(Global_Env& env, Clas // // only code and exception attributes are defined for Method // - switch (parse_attribute(cfs, cp, cp_size, method_attr_strings, method_attrs, &attr_len)){ + Attributes cur_attr = parse_attribute(cfs, cp, cp_size, method_attr_strings, method_attrs, &attr_len); + switch(cur_attr) { case ATTR_Code: n_code_attr++; if(!_parse_code(cp, cp_size, attr_len, cfs)) return false; break; + case ATTR_Exceptions: n_exceptions_attr++; if(!_parse_exceptions(cp, cp_size, attr_len, cfs)) return false; break; - case ATTR_Synthetic: - if(attr_len != 0) { - REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/ClassFormatError", - _class->name->bytes << ": attribute Synthetic has non-zero length for method " - << _name->bytes << _descriptor->bytes); + + case ATTR_RuntimeInvisibleParameterAnnotations: + if (!cfs.skip(attr_len)) + { + REPORT_FAILED_METHOD("error skipping RuntimeInvisibleParameterAnnotations"); return false; } - _synthetic = true; break; - case ATTR_Deprecated: - if(attr_len != 0) { - REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/ClassFormatError", - _class->name->bytes << ": attribute Deprecated has non-zero length for method " - << _name->bytes << _descriptor->bytes); - return false; + + case ATTR_RuntimeVisibleParameterAnnotations: + { + if (_param_annotations) { + REPORT_FAILED_METHOD( + "more than one RuntimeVisibleParameterAnnotations attribute"); + return false; + } + + if (!cfs.parse_u1(&_num_param_annotations)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse number of ParameterAnnotations"); + return false; + } + uint32 read_len = 1; + if (_num_param_annotations) { + _param_annotations = (AnnotationTable**)_class->class_loader->Alloc( + _num_param_annotations * sizeof (AnnotationTable*)); + + for (unsigned i = 0; i < _num_param_annotations; i++) + { + uint32 next_len = parse_annotation_table(_param_annotations + i, cfs, _class); + if (next_len == 0) { + return false; + } + read_len += next_len; + } + } + if (attr_len != read_len) { + REPORT_FAILED_METHOD( + "error parsing ParameterAnnotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } } - _deprecated = true; break; + + case ATTR_AnnotationDefault: + { + if (_default_value) { + REPORT_FAILED_METHOD("more than one AnnotationDefault attribute"); + return false; + } + _default_value = (AnnotationValue *)_class->class_loader->Alloc( + sizeof(AnnotationValue)); + + uint16 read_len = parse_annotation_value(*_default_value, cfs, clss); + if (read_len == 0) { + return false; + } else if (read_len != attr_len) { + REPORT_FAILED_METHOD( + "declared length " << attr_len + << " of AnnotationDefault attribute " + << " does not match actual " << read_len); + return false; + } + } + break; + case ATTR_UNDEF: // unrecognized attribute; skipped break; + default: - // error occured - REPORT_FAILED_CLASS_CLASS(_class->class_loader, _class, "java/lang/InternalError", - _class->name->bytes << ": unknown error occured " - "while parsing attributes for method " - << _name->bytes << _descriptor->bytes); - return false; + switch(process_common_attribute(cur_attr, attr_len, cfs)) { + case ATTR_ERROR: + // tried and failed + return false; + case ATTR_UNDEF: + // unprocessed + REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/InternalError", + clss->name->bytes + << " : error parsing attributes for method " + << _name->bytes << _descriptor->bytes + << "; unprocessed attribute " << cur_attr); + return false; + } // switch } // switch } // for @@ -1207,25 +1727,6 @@ static bool class_parse_fields(Global_En { env->string_pool.lookup("java/lang/Class"), env->string_pool.lookup("vm_class"), env->string_pool.lookup("J"), ACC_PRIVATE}, - - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Constructor, Method, Field - env->string_pool.lookup("vm_member"), - env->string_pool.lookup("J"), ACC_PRIVATE}, - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Constructor, Method - env->string_pool.lookup("parameterTypes"), - env->string_pool.lookup("[Ljava/lang/Class;"), ACC_PRIVATE}, - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Constructor, Method - env->string_pool.lookup("exceptionTypes"), - env->string_pool.lookup("[Ljava/lang/Class;"), ACC_PRIVATE}, - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Constructor, Method, Field - env->string_pool.lookup("declaringClass"), - env->string_pool.lookup("Ljava/lang/Class;"), ACC_PRIVATE}, - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Method, Field - env->string_pool.lookup("name"), - env->string_pool.lookup("Ljava/lang/String;"), ACC_PRIVATE}, - { env->string_pool.lookup("java/lang/reflect/AccessibleObject"), // Method, Field - env->string_pool.lookup("type"), - env->string_pool.lookup("Ljava/lang/Class;"), ACC_PRIVATE} }; if(!cfs.parse_u2_be(&clss->n_fields)) { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", @@ -1329,6 +1830,8 @@ static String* const_pool_parse_utf8data // get utf8 bytes and move buffer pointer const char* utf8data = (const char*)cfs.get_and_skip(len); + + // FIXME: decode 6-byte Java 1.5 encoding // check utf8 correctness if(memchr(utf8data, 0, len) != NULL) @@ -1741,7 +2244,8 @@ bool class_parse(Global_Env* env, * so we should add a check here */ if (clss->name && name != clss->name) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/NoClassDefFoundError", + REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, clss->name->bytes << ": class name in class data does not match class name passed"); return false; } @@ -1819,10 +2323,12 @@ bool class_parse(Global_Env* env, unsigned n_source_file_attr = 0; unsigned numSourceDebugExtensions = 0; + unsigned numEnclosingMethods = 0; uint32 attr_len = 0; for (unsigned i=0; i<n_attrs; i++) { - switch(parse_attribute(cfs, clss->const_pool, clss->cp_size, class_attr_strings, class_attrs, &attr_len)){ + Attributes cur_attr = parse_attribute(cfs, clss->const_pool, clss->cp_size, class_attr_strings, class_attrs, &attr_len); + switch(cur_attr){ case ATTR_SourceFile: { // a class file can have at most one source file attribute @@ -1861,6 +2367,9 @@ bool class_parse(Global_Env* env, case ATTR_InnerClasses: { + if (clss->declaringclass_index || clss->innerclass_indexes) { + REPORT_FAILED_CLASS_FORMAT(clss, "more than one InnerClasses attribute"); + } bool isinner = false; // found_myself == 2: myself is not inner class or has passed myself when iterating inner class attribute arrays // found_myself == 1: myself is inner class, current index of inner class attribute arrays is just myself @@ -1879,8 +2388,6 @@ bool class_parse(Global_Env* env, return false; } - clss->declaringclass_index = 0; // would it be a valid index - clss->innerclass_indexes = NULL; if(isinner) clss->n_innerclasses = (uint16)(num_of_classes - 1); //exclude itself else @@ -1942,14 +2449,21 @@ bool class_parse(Global_Env* env, << " while parsing InnerClasses attribute"); return false; } - if(inner_name_idx - && cp_tag(clss->const_pool,inner_name_idx) != CONSTANT_Utf8) + if(inner_name_idx && !valid_cpi(clss, inner_name_idx, CONSTANT_Utf8)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": inner name index points to incorrect constant pool entry" - << " while parsing InnerClasses attribute"); + REPORT_FAILED_CLASS_FORMAT(clss, + "inner name index points to incorrect constant pool entry"); return false; } + if(found_myself == 1 /*&& outer_clss_info_idx*/){ + if (inner_name_idx) { + clss->simple_name = clss->const_pool[inner_name_idx].CONSTANT_Utf8.string; + } else { + //anonymous class + clss->simple_name = env->string_pool.lookup(""); + } + } + uint16 inner_clss_access_flag; if(!cfs.parse_u2_be(&inner_clss_access_flag)) { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", @@ -1979,6 +2493,109 @@ bool class_parse(Global_Env* env, // The debug_extension array holds a string, which must be in UTF-8 format. // There is no terminating zero byte. clss->sourceDebugExtension = const_pool_parse_utf8data(env->string_pool, cfs, attr_len); + if (!clss->sourceDebugExtension) { + REPORT_FAILED_CLASS_FORMAT(clss, "invalid SourceDebugExtension attribute"); + return false; + } + } + break; + + case ATTR_EnclosingMethod: + { + if ( ++numEnclosingMethods > 1 ) { + REPORT_FAILED_CLASS_FORMAT(clss,"more than one EnclosingMethod attribute"); + return false; + } + if (attr_len != 4) { + REPORT_FAILED_CLASS_FORMAT(clss, + "unexpected length of EnclosingMethod attribute: " << attr_len); + return false; + } + uint16 class_idx; + if(!cfs.parse_u2_be(&class_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "could not parse class index of EnclosingMethod attribute"); + return false; + } + if(!valid_cpi(clss, class_idx, CONSTANT_Class)) + { + REPORT_FAILED_CLASS_FORMAT(clss, + "incorrect class index of EnclosingMethod attribute"); + return false; + } + clss->enclosing_class_index = class_idx; + + uint16 method_idx; + if(!cfs.parse_u2_be(&method_idx)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "could not parse method index of EnclosingMethod attribute"); + return false; + } + if(method_idx && !valid_cpi(clss, method_idx, CONSTANT_NameAndType)) + { + REPORT_FAILED_CLASS_FORMAT(clss, + "incorrect method index of EnclosingMethod attribute"); + return false; + } + clss->enclosing_method_index = method_idx; + } + break; + + case ATTR_Synthetic: + { + if(attr_len != 0) { + REPORT_FAILED_CLASS_FORMAT(clss, + "attribute Synthetic has non-zero length"); + return false; + } + clss->access_flags |= ACC_SYNTHETIC; + } + break; + + case ATTR_Deprecated: + { + if(attr_len != 0) { + REPORT_FAILED_CLASS_FORMAT(clss, + "attribute Deprecated has non-zero length"); + return false; + } + clss->deprecated = true; + } + break; + + case ATTR_Signature: + { + if(clss->Signature) { + REPORT_FAILED_CLASS_FORMAT(clss, + "more than one Signature attribute for the class"); + return false; + } + if (!(clss->Signature = parse_signature_attr(cfs, attr_len, clss))) { + return false; + } + } + break; + + case ATTR_RuntimeVisibleAnnotations: + { + uint32 read_len = parse_annotation_table(&(clss->annotations), cfs, clss); + if (attr_len != read_len) { + REPORT_FAILED_CLASS_FORMAT(clss, + "error parsing Annotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } + } + break; + + case ATTR_RuntimeInvisibleAnnotations: + { + if(!cfs.skip(attr_len)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "failed to skip RuntimeInvisibleAnnotations attribute"); + return false; + } } break; @@ -1989,24 +2606,47 @@ bool class_parse(Global_Env* env, // error occured REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/InternalError", clss->name->bytes << ": unknown error occured" - " while parsing attributes for class"); + " while parsing attributes for class" + << "; unprocessed attribute " << cur_attr); return false; } // switch } // for + if (cfs.have(1)) { + REPORT_FAILED_CLASS_FORMAT(clss, "Extra bytes at the end of class file"); + return false; + } + + if (clss->enclosing_class_index && !clss->simple_name) { + WARN("Attention: EnclosingMethod attribute does not imply " + "InnerClasses presence for class " << clss->name->bytes); + } + + /* * can't be both final and interface, or both final and abstract */ if (class_is_final(clss) && class_is_interface(clss)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": interface cannot have ACC_FINAL flag set"); + REPORT_FAILED_CLASS_FORMAT(clss, "interface cannot be final"); return false; } if (class_is_final(clss) && class_is_abstract(clss)) { - REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/ClassFormatError", - clss->name->bytes << ": class cannot have both ACC_FINAL and ACC_ABSTRACT flags set"); + REPORT_FAILED_CLASS_FORMAT(clss, "abstract class cannot be final"); + return false; + } + + // This requirement seems to be ignored by some compilers + // if(class_is_interface(clss) && !class_is_abstract(clss)) + //{ + // REPORT_FAILED_CLASS_FORMAT(clss, "interface must have ACC_ABSTRACT flag set"); + // return false; + //} + + if(class_is_annotation(clss) && !class_is_interface(clss)) + { + REPORT_FAILED_CLASS_FORMAT(clss, "annotation type must be interface"); return false; } diff --git vm/vmcore/src/class_support/Environment.cpp vm/vmcore/src/class_support/Environment.cpp index 24290f7..f3b8d93 100644 --- vm/vmcore/src/class_support/Environment.cpp +++ vm/vmcore/src/class_support/Environment.cpp @@ -30,6 +30,7 @@ #include "GlobalClassLoaderIterator.h" #include "verifier.h" #include "native_overrides.h" +#include "compile.h" Global_Env::Global_Env(tl::MemoryPool & mp, Properties & prop): mem_pool(mp), @@ -39,7 +40,16 @@ properties(prop), bootstrapping(false), ready_for_exceptions(false) { + JavaLangString_String = string_pool.lookup("java/lang/String"); + JavaLangStringBuffer_String = string_pool.lookup("java/lang/StringBuffer"); + JavaLangObject_String = string_pool.lookup("java/lang/Object"); + JavaLangClass_String = string_pool.lookup("java/lang/Class"); + VoidVoidDescriptor_String = string_pool.lookup("()V"); + VoidBooleanDescriptor_String = string_pool.lookup("()Z"); + VoidIntegerDescriptor_String = string_pool.lookup("()I"); JavaLangThrowable_String = string_pool.lookup("java/lang/Throwable"); + JavaLangNoClassDefFoundError_String = string_pool.lookup("java/lang/NoClassDefFoundError"); + JavaLangArrayIndexOutOfBoundsException_String = string_pool.lookup("java/lang/ArrayIndexOutOfBoundsException"); JavaNioByteBuffer_String = string_pool.lookup("java/nio/ByteBuffer"); JavaLangIllegalArgumentException_String = string_pool.lookup("java/lang/IllegalArgumentException"); @@ -48,21 +58,12 @@ ready_for_exceptions(false) JavaLangReflectMethod_String = string_pool.lookup("java/lang/reflect/Method"); JavaLangUnsatisfiedLinkError_String = string_pool.lookup("java/lang/UnsatisfiedLinkError"); JavaLangNullPointerException_String = string_pool.lookup("java/lang/NullPointerException"); - JavaLangString_String = string_pool.lookup("java/lang/String"); - JavaLangObject_String = string_pool.lookup("java/lang/Object"); - JavaLangClass_String = string_pool.lookup("java/lang/Class"); + + Init_String = string_pool.lookup("<init>"); Clinit_String = string_pool.lookup("<clinit>"); FinalizeName_String = string_pool.lookup("finalize"); - VoidVoidDescriptor_String = string_pool.lookup("()V"); - ByteDescriptor_String = string_pool.lookup("B"); - CharDescriptor_String = string_pool.lookup("C"); - DoubleDescriptor_String = string_pool.lookup("D"); - FloatDescriptor_String = string_pool.lookup("F"); - IntDescriptor_String = string_pool.lookup("I"); - LongDescriptor_String = string_pool.lookup("J"); - ShortDescriptor_String = string_pool.lookup("S"); - BooleanDescriptor_String = string_pool.lookup("Z"); + EnqueueName_String = string_pool.lookup("enqueue"); Clonable_String = string_pool.lookup("java/lang/Cloneable"); Serializable_String = string_pool.lookup("java/io/Serializable"); @@ -144,6 +145,8 @@ #endif // !_IPF_ nsoTable = nso_init_lookup_table(&this->string_pool); + + dcList = NULL; } //Global_Env::Global_Env void Global_Env::EnvClearInternals() @@ -166,6 +169,9 @@ void Global_Env::EnvClearInternals() nso_clear_lookup_table(nsoTable); nsoTable = NULL; + + compile_clear_dynamic_code_list(dcList); + dcList = NULL; } Class* Global_Env::LoadCoreClass(const String* s) @@ -179,3 +185,8 @@ Class* Global_Env::LoadCoreClass(const S } return clss; } + +Class* Global_Env::LoadCoreClass(const char* s) +{ + return LoadCoreClass(this->string_pool.lookup(s)); +} diff --git vm/vmcore/src/class_support/Initialize.cpp vm/vmcore/src/class_support/Initialize.cpp index 8fd0637..d56477b 100644 --- vm/vmcore/src/class_support/Initialize.cpp +++ vm/vmcore/src/class_support/Initialize.cpp @@ -35,6 +35,7 @@ #include "vm_threads.h" static void class_initialize1(Class *clss) { + ASSERT_RAISE_AREA; assert(!exn_raised()); assert(!hythread_is_suspend_enabled()); @@ -57,9 +58,8 @@ static void class_initialize1(Class *cls (clss->state == ST_Initializing) ) { // thread_object_wait had been expecting the only unsafe reference // to be its parameter, so enable_gc() should be safe here -salikh - jthread_monitor_wait(jlc); - jthrowable exc = exn_get(); - if (exc) { + jthread_monitor_wait(jlc); + if (exn_raised()) { jthread_monitor_exit(jlc); return; } @@ -84,11 +84,8 @@ static void class_initialize1(Class *cls if (clss->state == ST_Error) { jthread_monitor_exit(jlc); tmn_suspend_enable(); - jthrowable exn = exn_create("java/lang/NoClassDefFoundError", - clss->name->bytes); + exn_raise_by_name("java/lang/NoClassDefFoundError", clss->name->bytes); tmn_suspend_disable(); - exn_raise_only(exn); - return; } @@ -202,8 +199,8 @@ static void class_initialize1(Class *cls // --- step 10 ---------------------------------------------------------- if(p_error_object) { - assert(!hythread_is_suspend_enabled()); - clear_current_thread_exception(); + assert(!hythread_is_suspend_enabled()); + exn_clear(); Class *p_error_class = p_error_object->object->vt()->clss; Class *jle = VM_Global_State::loader_env->java_lang_Error_Class; while(p_error_class && p_error_class != jle) { @@ -234,7 +231,7 @@ #endif assert(!hythread_is_suspend_enabled()); jthread_monitor_notify_all(jlc); jthread_monitor_exit(jlc); - exn_raise_only(p_error_object); + exn_raise_object(p_error_object); } // end of 11 step class initialization program } //class_initialize1 @@ -247,13 +244,14 @@ extern "C" { #endif void class_initialize_from_jni(Class *clss) { + ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); // check verifier constraints if(!class_verify_constraints(VM_Global_State::loader_env, clss)) { if (!exn_raised()) { tmn_suspend_disable(); - exn_throw(class_get_error(clss->class_loader, clss->name->bytes)); + exn_raise_object(class_get_error(clss->class_loader, clss->name->bytes)); tmn_suspend_enable(); } return; @@ -272,13 +270,13 @@ #endif // VMEXPORT void class_initialize(Class *clss) { + ASSERT_RAISE_AREA; class_initialize_ex(clss); } - - void class_initialize_ex(Class *clss) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); // check verifier constraints @@ -286,7 +284,7 @@ void class_initialize_ex(Class *clss) if(!class_verify_constraints(VM_Global_State::loader_env, clss)) { if (!exn_raised()) { tmn_suspend_disable(); - exn_throw(class_get_error(clss->class_loader, clss->name->bytes)); + exn_raise_object(class_get_error(clss->class_loader, clss->name->bytes)); } return; } diff --git vm/vmcore/src/class_support/Prepare.cpp vm/vmcore/src/class_support/Prepare.cpp index e0f321f..4d04006 100644 --- vm/vmcore/src/class_support/Prepare.cpp +++ vm/vmcore/src/class_support/Prepare.cpp @@ -44,6 +44,8 @@ #include "jni.h" #include "jvmti_direct.h" #endif +#include "dump.h" + static void class_initialize_if_no_side_effects(Class *clss); @@ -432,6 +434,7 @@ #endif // DEBUG_FIELD_SORTING // Required for reflection. See class_prepare STEP20 for further explanation. bool assign_values_to_class_static_final_fields(Class *clss) { + ASSERT_RAISE_AREA; bool do_field_compaction = Class::compact_fields; for (int i=0; i<clss->n_fields; i++) { @@ -463,6 +466,7 @@ bool assign_values_to_class_static_final tmn_suspend_disable(); // ------------------------------------------------------------vv Java_java_lang_String *str = vm_instantiate_cp_string_resolved(cvalue.string); + if (!str) { assert(exn_raised()); tmn_suspend_enable(); @@ -914,6 +918,7 @@ #endif bool initialize_static_fields_for_interface(Class *clss) { + ASSERT_RAISE_AREA; tmn_suspend_disable(); // Initialize static fields clss->state = ST_Prepared; @@ -951,7 +956,9 @@ bool initialize_static_fields_for_interf // compress static reference fields. // It must be a String assert(strcmp(field.get_descriptor()->bytes, "Ljava/lang/String;") == 0); - Java_java_lang_String *str = vm_instantiate_cp_string_resolved(field_const_value.string); + Java_java_lang_String *str + = vm_instantiate_cp_string_resolved(field_const_value.string); + if (!str) { assert(exn_raised()); tmn_suspend_enable(); @@ -1066,6 +1073,7 @@ void point_class_vtable_entries_to_stubs extern bool dump_stubs; +// It's a rutime helper. So should be named as rth_prepare_throw_abstract_method_error void prepare_throw_abstract_method_error(Class_Handle clss, Method_Handle method) { char* buf = (char*)STD_ALLOCA(clss->name->len + method->get_name()->len @@ -1073,6 +1081,8 @@ void prepare_throw_abstract_method_error sprintf(buf, "%s.%s%s", clss->name->bytes, method->get_name()->bytes, method->get_descriptor()->bytes); tmn_suspend_enable(); + + // throw exception here because it's a helper exn_throw_by_name("java/lang/AbstractMethodError", buf); tmn_suspend_disable(); } @@ -1091,12 +1101,16 @@ NativeCodePtr prepare_gen_throw_abstract "call.noret %2i;", clss, method, p_throw_ame); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "prepare_throw_abstract_method_error", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "prepare_throw_abstract_method_error", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } +// It's a rutime helper. So should be named as rth_prepare_throw_illegal_access_error void prepare_throw_illegal_access_error(Class_Handle to, Method_Handle from) { char* buf = (char*)STD_ALLOCA(from->get_class()->name->len @@ -1106,6 +1120,8 @@ void prepare_throw_illegal_access_error( to->name->bytes, from->get_name()->bytes, from->get_descriptor()->bytes); tmn_suspend_enable(); + + // throw exception here because it's a helper exn_throw_by_name("java/lang/IllegalAccessError", buf); tmn_suspend_disable(); } @@ -1124,7 +1140,10 @@ NativeCodePtr prepare_gen_throw_illegal_ "call.noret %2i;", to, from, p_throw_iae); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_throw_linking_exception", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_linking_exception", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; @@ -1242,6 +1261,7 @@ static void initialize_regular_class_dat bool class_prepare(Global_Env* env, Class *clss) { + ASSERT_RAISE_AREA; // fast path switch(clss->state) { @@ -1291,7 +1311,7 @@ bool class_prepare(Global_Env* env, Clas } if(!class_prepare(env, clss->superinterfaces[i].clss)) { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, - "java/lang/NoClassDefFoundError", + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, clss->name->bytes << ": error preparing superinterface " << clss->superinterfaces[i].clss->name->bytes); return false; @@ -1309,7 +1329,7 @@ bool class_prepare(Global_Env* env, Clas // Regular class with super-class. if(!class_prepare(env, clss->super_class)) { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, - "java/lang/NoClassDefFoundError", + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, clss->name->bytes << ": error preparing superclass " << clss->super_class->name->bytes); return false; @@ -1624,7 +1644,7 @@ #endif // before java.lang.Class: java.lang.Object and java.io.Serializable. if(clss->name == env->JavaLangClass_String) { String *name = env->string_pool.lookup("vm_class"); - String* desc = env->LongDescriptor_String; + String* desc = env->string_pool.lookup("J"); Field *vm_class_field = class_lookup_field(clss, name, desc); assert(vm_class_field != NULL); env->vm_class_offset = vm_class_field->get_offset(); diff --git vm/vmcore/src/class_support/Resolve.cpp vm/vmcore/src/class_support/Resolve.cpp index 2ee0dbc..77d5b6e 100644 --- vm/vmcore/src/class_support/Resolve.cpp +++ vm/vmcore/src/class_support/Resolve.cpp @@ -203,11 +203,10 @@ static Class* _resolve_class(Global_Env static bool class_can_instantiate(Class* clss, bool _throw) { + ASSERT_RAISE_AREA; bool fail = class_is_abstract(clss); if(fail && _throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/InstantiationError", clss->name->bytes); - tmn_suspend_disable(); + exn_raise_by_name("java/lang/InstantiationError", clss->name->bytes); } return !fail; } @@ -216,8 +215,13 @@ static bool class_can_instantiate(Class* Class* _resolve_class_new(Global_Env *env, Class *clss, unsigned cp_index) { + ASSERT_RAISE_AREA; + Class *new_clss = _resolve_class(env,clss,cp_index); - if (new_clss && !class_can_instantiate(new_clss, false)) { + if (!new_clss) return NULL; + bool can_instantiate = class_can_instantiate(new_clss, false); + + if (new_clss && !can_instantiate) { return NULL; } return new_clss; @@ -464,12 +468,11 @@ static Field* _resolve_field(Global_Env bool field_can_link(Class* clss, Field* field, bool _static, bool putfield, bool _throw) { + ASSERT_RAISE_AREA; if(_static?(!field->is_static()):(field->is_static())) { if(_throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/IncompatibleClassChangeError", + exn_raise_by_name("java/lang/IncompatibleClassChangeError", field->get_class()->name->bytes); - tmn_suspend_disable(); } return false; } @@ -480,13 +483,12 @@ bool field_can_link(Class* clss, Field* } } if(_throw) { - tmn_suspend_enable(); unsigned buf_size = clss->name->len + field->get_class()->name->len + field->get_name()->len + 15; char* buf = (char*)STD_ALLOCA(buf_size); memset(buf, 0, buf_size); sprintf(buf, " from %s to %s.%s", clss->name->bytes, field->get_class()->name->bytes, field->get_name()->bytes); - exn_throw_by_name("java/lang/IllegalAccessError", buf); - tmn_suspend_disable(); + jthrowable exc_object = exn_create("java/lang/IllegalAccessError", buf); + exn_raise_object(exc_object); } return false; } @@ -505,6 +507,8 @@ static Field* _resolve_static_field(Glob unsigned cp_index, bool putfield) { + ASSERT_RAISE_AREA; + Field *field = _resolve_field(env,clss,cp_index); if(field && !field_can_link(clss, field, CAN_LINK_FROM_STATIC, putfield, LINK_NO_THROW)) { return NULL; @@ -519,6 +523,8 @@ static Field* _resolve_nonstatic_field(G unsigned cp_index, unsigned putfield) { + ASSERT_RAISE_AREA; + Field *field = _resolve_field(env, clss, cp_index); if(field && !field_can_link(clss, field, CAN_LINK_FROM_FIELD, putfield, LINK_NO_THROW)) { return NULL; @@ -629,12 +635,12 @@ static Method* _resolve_method(Global_En static bool method_can_link_static(Class* clss, unsigned index, Method* method, bool _throw) { + ASSERT_RAISE_AREA; + if (!method->is_static()) { if(_throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/IncompatibleClassChangeError", + exn_raise_by_name("java/lang/IncompatibleClassChangeError", method->get_class()->name->bytes); - tmn_suspend_disable(); } return false; } @@ -645,6 +651,8 @@ static Method* _resolve_static_method(Gl Class *clss, unsigned cp_index) { + ASSERT_RAISE_AREA; + Method* method = _resolve_method(env, clss, cp_index); if(method && !method_can_link_static(clss, cp_index, method, LINK_NO_THROW)) return NULL; @@ -654,24 +662,23 @@ static Method* _resolve_static_method(Gl static bool method_can_link_virtual(Class* clss, unsigned cp_index, Method* method, bool _throw) { + ASSERT_RAISE_AREA; + if(method->is_static()) { if(_throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/IncompatibleClassChangeError", + exn_raise_by_name("java/lang/IncompatibleClassChangeError", method->get_class()->name->bytes); - tmn_suspend_disable(); } return false; } if(class_is_interface(method->get_class())) { if(_throw) { - tmn_suspend_enable(); char* buf = (char*)STD_ALLOCA(clss->name->len + method->get_name()->len + method->get_descriptor()->len + 2); sprintf(buf, "%s.%s%s", clss->name->bytes, method->get_name()->bytes, method->get_descriptor()->bytes); - exn_throw_by_name("java/lang/AbstractMethodError", buf); - tmn_suspend_disable(); + jthrowable exc_object = exn_create("java/lang/AbstractMethodError", buf); + exn_raise_object(exc_object); } return false; } @@ -761,6 +768,8 @@ Method_Handle resolve_virtual_method(Com static bool method_can_link_special(Class* clss, unsigned index, Method* method, bool _throw) { + ASSERT_RAISE_AREA; + unsigned class_idx = clss->const_pool[index].CONSTANT_ref.class_index; unsigned class_name_idx = clss->const_pool[class_idx].CONSTANT_Class.name_index; String* ref_class_name = clss->const_pool[class_name_idx].CONSTANT_String.string; @@ -769,20 +778,16 @@ static bool method_can_link_special(Clas && method->get_class()->name != ref_class_name) { if(_throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/NoSuchMethodError", + exn_raise_by_name("java/lang/NoSuchMethodError", method->get_name()->bytes); - tmn_suspend_disable(); } return false; } if(method->is_static()) { if(_throw) { - tmn_suspend_enable(); - exn_throw_by_name("java/lang/IncompatibleClassChangeError", + exn_raise_by_name("java/lang/IncompatibleClassChangeError", method->get_class()->name->bytes); - tmn_suspend_disable(); } return false; } @@ -794,7 +799,8 @@ static bool method_can_link_special(Clas char* buf = (char*)STD_ALLOCA(buf_size); memset(buf, 0, buf_size); sprintf(buf, "%s.%s%s", clss->name->bytes, method->get_name()->bytes, method->get_descriptor()->bytes); - exn_throw_by_name("java/lang/AbstractMethodError", buf); + jthrowable exc_object = exn_create("java/lang/AbstractMethodError", buf); + exn_raise_object(exc_object); tmn_suspend_disable(); } return false; @@ -810,6 +816,8 @@ Method_Handle resolve_special_method_env Class_Handle curr_clss, unsigned index) { + ASSERT_RAISE_AREA; + Method* method = _resolve_method(env, curr_clss, index); if(!method) { return NULL; @@ -907,9 +915,11 @@ Class_Handle resolve_class(Compile_Handl void class_throw_linking_error(Class_Handle ch, unsigned index, unsigned opcode) { + ASSERT_RAISE_AREA; + Const_Pool* cp = ch->const_pool; if(cp_in_error(cp, index)) { - exn_throw((jthrowable)(&(cp[index].error.cause))); + exn_raise_object((jthrowable)(&(cp[index].error.cause))); return; // will return in interpreter mode } @@ -953,7 +963,7 @@ void class_throw_linking_error(Class_Han // FIXME Potentially this can be any RuntimeException or Error // The most probable case is OutOfMemoryError. WARN("**Java exception occured during resolution under compilation"); - exn_throw(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); //ASSERT(0, "Unexpected opcode: " << opcode); break; } diff --git vm/vmcore/src/class_support/String_Pool.cpp vm/vmcore/src/class_support/String_Pool.cpp index aebdff9..e023905 100644 --- vm/vmcore/src/class_support/String_Pool.cpp +++ vm/vmcore/src/class_support/String_Pool.cpp @@ -18,10 +18,6 @@ * @version $Revision: 1.1.2.1.4.4 $ */ - -#define LOG_DOMAIN util::CLASS_LOGGER -#include "cxxlog.h" - #include "platform_lowlevel.h" //MVM @@ -30,19 +26,23 @@ using namespace std; #include <assert.h> #include <apr_atomic.h> +#include <apr_pools.h> +#include <apr_hash.h> +#include <apr_time.h> #include "String_Pool.h" #include "environment.h" +#include "open/hythread.h" #include "open/vm_util.h" #include "atomics.h" +#include "vm_strings.h" +#include "vm_stats.h" -// In order to make this code thread safe a light weight lock is used. -// The protocol is simple and the lock is local to this string pool. -volatile POINTER_SIZE_INT string_pool_lock; // 1 is locked, 0 is unlocked +#define LOG_DOMIAN "vm.strings" +#include "cxxlog.h" // apr_atomic_casptr should result in an .acq on IPF. -void String_Pool::lock_pool () -{ +void String_Pool::lock_pool () { // Spin until lock is m_free. while (apr_atomic_casptr( (volatile void **)&string_pool_lock, (void *)1, (void *)0) != 0) { @@ -51,341 +51,276 @@ void String_Pool::lock_pool () } // Release lock. string_pool_lock is volatile which results in a st.rel on IPF -void String_Pool::unlock_pool () -{ +void String_Pool::unlock_pool () { assert (string_pool_lock != 0); string_pool_lock = 0; } //String_Pool::unlock_pool - -String_Pool::_Entry::_Entry(const char *s, unsigned len, _Entry *n) : next(n) -{ - str.len = len; - strncpy(str.bytes, s, len); - str.bytes[len] = '\0'; - // This constructor can be run very early on during VM execution--even before main is entered. - // This is before we have had a chance to process any command line arguments. So, initialize the - // interned Java_lang_String reference to NULL in a way that will work whether references are compressed or not. - str.intern.raw_ref = NULL; +String_Pool::Entry::Entry(const char * s, unsigned len, Entry *n) : next(n) { +// This constructor can be run very early on during VM execution--even before main is entered. +// This is before we have had a chance to process any command line arguments. So, initialize the +// interned Java_lang_String reference to NULL in a way that will work whether references are compressed or not. str.intern.raw_ref = NULL; -} //String_Pool::_Entry::_Entry + str.len = (len); + assert(strlen(s) >= (len)); + memcpy(str.bytes, s, len); + str.bytes[len] = '\0'; +} //String_Pool::Entry::Entry -String_Pool::String_Pool() -{ - // lock_pool(); - IvanV: no need, who will use string pool before - // constructor? - // - // allocate the string table and zero it out - // - unsigned table_size = sizeof(_Entry*) * STRING_TABLE_SIZE; - memset(_table,0,table_size); - // unlock_pool(); - IvanV: no need, who will use string pool before - // constructor? -} //String_Pool::String_Pool +String_Pool::String_Pool() { + unsigned size = sizeof(Entry*) * STRING_TABLE_SIZE; + table = (Entry **)memory_pool.alloc(size); + memset(table, 0, size); + + head_interned = (Interned_Strings *)memory_pool.alloc(sizeof(Interned_Strings)); + memset(head_interned, 0, sizeof(Interned_Strings)); + current_interned = head_interned; + index_interned = (Interned_Strings_Index *)memory_pool.alloc(sizeof(Interned_Strings_Index)); +#ifdef VM_STATS + string_stat = apr_hash_make(VM_Statistics::get_vm_stats().vm_stats_pool); + num_ambiguity = 0; +#endif +} //String_Pool::String_Pool -#ifdef _DEBUG_STRING_POOL +inline bool String_Pool::has_line_end(POINTER_SIZE_INT val) { + return (val ^ ~(val + BIT_MASK)) & ~BIT_MASK; +} -// Should be wrapped in assert. -static int valid_count = 0; +void String_Pool::hash_it(const char * s, unsigned * len, POINTER_SIZE_INT * hash) { + POINTER_SIZE_INT h1 = 0; + POINTER_SIZE_INT h2 = 0; + const char * p_val = s; + + // to avoid access violation exception in a while(true) cycle below we need + // to be sure that the input string is aligned on the pointer size boundary + if (((POINTER_SIZE_INT)s & (sizeof(POINTER_SIZE_INT) - 1)) != 0) { + *len = strlen(s); + *hash = hash_it(s, *len); + return; + } -bool String_Pool::valid_string_pool() -{ - _Entry *e; - Java_java_lang_String *jstr; - unsigned short hash; - for (hash = 0; hash < STRING_TABLE_SIZE; hash++) { - for (e = _table[hash]; e != NULL; e = e->next) { - if (VM_Global_State::loader_env->compress_references) { - jstr = (Java_java_lang_String *)uncompress_compressed_reference(e->intern.compressed_ref); - } else { - jstr = e->intern.raw_ref; - } - if (jstr != NULL) { - assert(jstr->vt); // Make sure it is a valid vtable. + while(true) { + POINTER_SIZE_INT val = *(POINTER_SIZE_INT *)p_val; + if (has_line_end(val)) { + for (unsigned i = 0; i < sizeof(POINTER_SIZE_INT); i++) { + if (p_val[i] != '\0') { + h2 += p_val[i]; + } else { + // line end found + *len = p_val - s + i; + goto done; + } } + // false signal !!! + h2 = 0; } + h1 += val; + p_val += sizeof(POINTER_SIZE_INT); } - valid_count++; - return true; -} //String_Pool::valid_string_pool - -#else // !_DEBUG_STRING_POOL - -inline bool String_Pool::valid_string_pool() -{ - return true; -} //String_Pool::valid_string_pool - -#endif // !_DEBUG_STRING_POOL +done: + // check that length was computed correctly + assert(strlen(s) == *len); + *hash = h1 - h2; +} +POINTER_SIZE_INT String_Pool::hash_it(const char * s, unsigned len) { + POINTER_SIZE_INT h1 = 0, h2 = 0; + const unsigned parts = len / sizeof(POINTER_SIZE_INT); + + for (unsigned i = 0; i < parts; i++) { + h1 += *((POINTER_SIZE_INT *)s + i); + } -String *String_Pool::lookup(const char *s) -{ + for (unsigned j = parts * sizeof(POINTER_SIZE_INT); j < len; j++) { + h2 += s[j]; + } + + return h1 - h2; +} - // - // compute hash - // - int hash = 0; - unsigned len = 0; - const char *t = s; - int c; - int h1 = 0, h2 = 0; - while ((c = *t++) != '\0') { - h1 = h1 + c; - if((c = *t++) == 0) { - break; - } - h2 = h2 + c; +String * String_Pool::lookup(const char *s, unsigned len, POINTER_SIZE_INT raw_hash) { +#ifdef VM_STATS + // we need a lock here since apr_palloc & apr_hash_set is single threaded + LMAutoUnlock auto_lock(&VM_Statistics::get_vm_stats().vm_stats_lock); + String_Stat * key_stats = + (String_Stat *)apr_hash_get(string_stat, s, len); + if (key_stats == NULL) { + key_stats = (String_Stat *) + apr_palloc(VM_Statistics::get_vm_stats().vm_stats_pool, sizeof(String_Stat)); + memset(key_stats, 0, sizeof(String_Stat)); + char * str = (char *)apr_palloc(VM_Statistics::get_vm_stats().vm_stats_pool, len + 1); + memcpy(str, s, len); + str[len] = '\0'; + apr_hash_set(string_stat, str, len, key_stats); + key_stats->raw_hash = raw_hash; } - hash = (h1 + (h2 << 8)) & 0x7fffffff; - len = (unsigned) ((t - s) - 1); - hash = hash % STRING_TABLE_SIZE; + assert(key_stats->raw_hash == raw_hash); + ++key_stats->num_lookup; +#endif - assert (valid_string_pool()); + int hash = raw_hash % STRING_TABLE_SIZE; - // // search bucket for string, no lock - // - _Entry *e; - for (e = _table[hash]; e != NULL; e = e->next) { + for (Entry *e = table[hash]; e != NULL; e = e->next) { if (e->str.len == len && memcmp(s, e->str.bytes, len) == 0) { - // // found string in table - // return &e->str; } +#ifdef VM_STATS + ++key_stats->num_lookup_collision; +#endif } lock_pool(); - // // search bucket for string, strict variant with locking to avoid // duplication - // - for (e = _table[hash]; e != NULL; e = e->next) { - if (e->str.len == len && memcmp(s, e->str.bytes, len) == 0) { - // + Entry **last_entry = &table[hash]; + Entry * cur_entry = *last_entry; + while (cur_entry) { + if (cur_entry->str.len == len && memcmp(s, cur_entry->str.bytes, len) == 0) { // found string in table - // unlock_pool(); - return &e->str; + return &cur_entry->str; } + last_entry = &(cur_entry->next); + cur_entry = cur_entry->next; } - // + +#ifdef VM_STATS + if (table[hash]) { + // there is already an element with the same hash + num_ambiguity++; + } +#endif + // string not in table; insert a new string entry into string pool // - // compute size of _Entry record + // compute size of Entry record // add one to str_len for '\0' - // subtract 2 for bytes[2] already in _Entry - // - unsigned entry_size = sizeof(_Entry) + len + 1 - 2; - + // subtract STRING_PADDING already in Entry + unsigned entry_size = sizeof(Entry) + len + 1 - STRING_PADDING; + /* Synchronized via String_Pool lock */ void * mem = memory_pool.alloc(entry_size); - + // We need ordering of writes here as we use the collection without lock. // Entry's next pointer should be updated before we update head reference. - e = new(mem) _Entry(s,len,_table[hash]); + cur_entry = new(mem) Entry(s, len, 0); MemoryWriteBarrier(); - _table[hash] = e; - - assert (valid_string_pool()); + *last_entry = cur_entry; unlock_pool(); - return &e->str; -} //String_Pool::lookup - - -String *String_Pool::lookup(const char *s, unsigned len) -{ - // - // compute hash - // - int hash = 0; - const char *t = s; - const char *eos = s + len; - int c; - int h1 = 0, h2 = 0; - while (t != eos) { - c = *t++; - h1 = h1 + c; - if(t == eos) { - break; - } - c = *t++; - h2 = h2 + c; - } - hash = (h1 + (h2 << 8)) & 0x7fffffff; - hash = hash % STRING_TABLE_SIZE; - - lock_pool(); - - assert (valid_string_pool()); - - // - // search bucket for string - // - _Entry *e; - for (e = _table[hash]; e != NULL; e = e->next) { - if (e->str.len == len && strncmp(s, e->str.bytes, len) == 0) { - // - // found string in table - // - unlock_pool(); - return &e->str; - } - } - // - // string not in table; insert a new string entry into string pool - // - // compute size of _Entry record - // add one to str_len for '\0' - // subtract 2 for bytes[2] already in _Entry - // - unsigned entry_size = sizeof(_Entry) + len + 1 - 2; - // - // round up to word aligned size - // - entry_size = (entry_size + 3) & 0xFFFFFFFC; + return &cur_entry->str; +} - /* Synchronized via String_Pool lock */ - void * mem = memory_pool.alloc(entry_size); +String * String_Pool::lookup(const char *s) { + POINTER_SIZE_INT hash; + unsigned len; + + hash_it(s, &len, &hash); + return lookup(s, len, hash); +} //String_Pool::lookup - _table[hash] = e = new(mem) _Entry(s,len,_table[hash]); - assert (valid_string_pool()); - unlock_pool(); - return &e->str; +String * String_Pool::lookup(const char *s, unsigned len) { + return lookup(s, len, hash_it(s, len)); } //String_Pool::lookup +String * String_Pool::get_first_string_intern() { + index_interned->current = head_interned; + index_interned->index = 0; + return get_next_string_intern(); +} -// A simple iterator. -// It is used for GC at the moment, but it should be replaced with -// something that would allow GC of classes. -String *String_Pool::get_first_string() -{ - for(unsigned i = 0; i < STRING_TABLE_SIZE; i++) { - if(_table[i] != NULL) - return &(_table[i]->str); +String * String_Pool::get_next_string_intern() { + unsigned index = index_interned->index; + if (index < index_interned->current->free_slot) { + index_interned->index++; + return index_interned->current->elem[index]; } - return NULL; -} //String_Pool::get_first_string - - - -String *String_Pool::get_next_string(String *prev) -{ - assert(prev); - // hash on string name address - int hash = 0; - const char *s = prev->bytes; - const char *t = s; - int c; - int h1 = 0, h2 = 0; - while ((c = *t++) != '\0') { - h1 = h1 + c; - if((c = *t++) == 0) { - break; - } - h2 = h2 + c; - } - hash = (h1 + (h2 << 8)) & 0x7fffffff; - hash = hash % STRING_TABLE_SIZE; - - for(_Entry *e = _table[hash]; e != NULL; e = e->next) { - if((&(e->str)) == prev) { - if(e->next) { - return &(e->next->str); - } else { - for(unsigned i = hash + 1; i < STRING_TABLE_SIZE; i++) { - if(_table[i] != NULL) - return &(_table[i]->str); - } - return NULL; - } - } + index_interned->current = index_interned->current->next; + if (index_interned->current) { + index_interned->index = 0; + return get_next_string_intern(); } - ABORT("Can't find the string given in the table"); return NULL; -} //String_Pool::get_next_string - +} -String *String_Pool::get_first_string_intern(unsigned *cookie) -{ - if (VM_Global_State::loader_env->compress_references) { - // Examine the "compressed_ref" instead of the "raw_ref" field. - for (unsigned i = 0; i < STRING_TABLE_SIZE; i++) { - for (_Entry *e = _table[i]; e != NULL; e = e->next) { - if (e->str.intern.compressed_ref != 0) { - *cookie = i; - return &(e->str); - } - } - } +void String_Pool::register_interned_string(String * str) { + void * result; + while ((result = apr_atomic_casptr( + (volatile void **)(current_interned->elem + current_interned->free_slot), + (void *)str, + (void *)NULL)) != NULL) { + hythread_yield(); + } + assert(current_interned->free_slot < INTERNED_STRING_ARRAY_SIZE); + if (current_interned->free_slot == INTERNED_STRING_ARRAY_SIZE - 1) { + // this piece of code should be executed in one thread until current_interned is updated + volatile Interned_Strings * local_current_interned = current_interned; + Interned_Strings * new_elem = (Interned_Strings *)memory_pool.alloc(sizeof(Interned_Strings)); + memset(new_elem, 0, sizeof(Interned_Strings)); + current_interned->next = new_elem; + MemoryWriteBarrier(); + current_interned = new_elem; + MemoryWriteBarrier(); + local_current_interned->free_slot++; } else { - for (unsigned i = 0; i < STRING_TABLE_SIZE; i++) { - for (_Entry *e = _table[i]; e != NULL; e = e->next) { - if (e->str.intern.raw_ref != NULL) { - *cookie = i; - return &(e->str); - } - } - } + current_interned->free_slot++; } - *cookie = 0; - return NULL; -} //String_Pool::get_first_string_intern +} +// NOTE: it is safe to call this function in multiple threads BUT +// don't iterate through interned strings while other threads do interning +ManagedObject * String_Pool::intern(String * str) { + ManagedObject* lang_string = string_create_from_utf8(str->bytes, str->len); + + if (!lang_string) { // if OutOfMemory + return NULL; + } + assert(!hythread_is_suspend_enabled()); -String *String_Pool::get_next_string_intern(String *prev, unsigned *cookie) -{ - assert(prev); - unsigned short hash = (short)*cookie; + // Atomically update the string structure since some other thread might be trying to make the same update. + // The GC won't be able to enumerate here since GC is disabled, so there are no race conditions with GC. if (VM_Global_State::loader_env->compress_references) { - // Examine the "compressed_ref" instead of the "raw_ref" field. - for (_Entry *e = _table[hash]; e != NULL; e = e->next) { - if ((&(e->str)) == prev) { - for (e = e->next; e != NULL; e = e->next) { - if (e->str.intern.compressed_ref) { - // same cookie - return &(e->str); - } - } - break; - } - } - for (unsigned i = hash +1; i < STRING_TABLE_SIZE; i++ ) { - for (_Entry *e = _table[i]; e!= NULL; e= e->next) { - if (e->str.intern.compressed_ref) { - *cookie = i; - return &(e->str); - } - } + COMPRESSED_REFERENCE compressed_lang_string = (COMPRESSED_REFERENCE)((POINTER_SIZE_INT)lang_string - (POINTER_SIZE_INT)Class::heap_base); + assert(is_compressed_reference(compressed_lang_string)); + assert(sizeof(LONG) == sizeof(uint32)); + uint32 result = apr_atomic_cas32( + /*destination*/ (volatile uint32 *)&str->intern.compressed_ref, + /*exchange*/ compressed_lang_string, + /*comparand*/ 0); + if (result == 0) { + // Note the successful write of the object. + gc_heap_write_global_slot_compressed( + (COMPRESSED_REFERENCE *)&str->intern.compressed_ref, + (Managed_Object_Handle)lang_string); + // add this string to interned strings + register_interned_string(str); } + // Some other thread may have beaten us to the slot. + lang_string = (ManagedObject *)uncompress_compressed_reference(str->intern.compressed_ref); } else { - for (_Entry *e = _table[hash]; e != NULL; e = e->next) { - if ((&(e->str)) == prev) { - for (e = e->next; e != NULL; e = e->next) { - if (e->str.intern.raw_ref) { - // same cookie - return &(e->str); - } - } - break; - } - } - for (unsigned i = hash +1; i < STRING_TABLE_SIZE; i++ ) { - for (_Entry *e = _table[i]; e!= NULL; e= e->next) { - if (e->str.intern.raw_ref) { - *cookie = i; - return &(e->str); - } - } + void *result = + (void *)apr_atomic_casptr( + /*destination*/ (volatile void **)&str->intern.raw_ref, + /*exchange*/ (void *)lang_string, + /*comparand*/ (void *)NULL); + if (result == NULL) { + // Note the successful write of the object. + gc_heap_write_global_slot( + (Managed_Object_Handle *)&str->intern.raw_ref, + (Managed_Object_Handle)lang_string); + // add this string to interned strings + register_interned_string(str); } + // Some other thread may have beaten us to the slot. + lang_string = str->intern.raw_ref; } - return NULL; -} //String_Pool::get_next_string_intern + return lang_string; +} diff --git vm/vmcore/src/class_support/Verifier_stub.cpp vm/vmcore/src/class_support/Verifier_stub.cpp index 890e65c..7e3d9a5 100644 --- vm/vmcore/src/class_support/Verifier_stub.cpp +++ vm/vmcore/src/class_support/Verifier_stub.cpp @@ -113,7 +113,8 @@ class_verify_constraints(const Global_En clss->m_lock->_unlock(); if( result == VER_ErrorLoadClass ) { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, - "java/lang/NoClassDefFoundError", error); + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + error); } else { REPORT_FAILED_CLASS_CLASS(clss->class_loader, clss, "java/lang/VerifyError", error); diff --git vm/vmcore/src/class_support/class_impl.cpp vm/vmcore/src/class_support/class_impl.cpp index 160b80d..57e66c5 100644 --- vm/vmcore/src/class_support/class_impl.cpp +++ vm/vmcore/src/class_support/class_impl.cpp @@ -497,6 +497,29 @@ method_get_exc_handler_info( method_hand } // method_get_exc_handler_info /** + * Gets number of exceptions a method can throw. + */ +unsigned short +method_get_number_exc_method_can_throw( method_handler hmethod ) +{ + assert( hmethod ); + Method *method = (Method*)hmethod; + return method->num_exceptions_method_can_throw(); +} // method_get_number_exc_method_can_throw + +/** + * Gets name of exception a method can throw. + */ +const char * +method_get_exc_method_can_throw( method_handler hmethod, + unsigned short index) +{ + assert( hmethod ); + Method *method = (Method*)hmethod; + return method->get_exception_name( index )->bytes; +} // method_get_exc_method_can_throw + +/** * Function sets verify data in class loader. */ void diff --git vm/vmcore/src/class_support/classloader.cpp vm/vmcore/src/class_support/classloader.cpp index cf8bec2..a5a6caa 100644 --- vm/vmcore/src/class_support/classloader.cpp +++ vm/vmcore/src/class_support/classloader.cpp @@ -70,7 +70,7 @@ void mark_classloader(ClassLoader* cl) { if(cl->GetLoader() && cl->NotMarked()) { TRACE2("classloader.unloading.markloader", " Marking loader " - << cl << " (" << cl->GetLoader() << " : " + << cl << " (" << (void*)cl->GetLoader() << " : " << ((VTable*)(*(unsigned**)(cl->GetLoader())))->clss->name->bytes << ")"); cl->Mark(); } @@ -220,7 +220,7 @@ void ClassLoader::LoadingClass::RemoveWa Class* ClassLoader::NewClass(const Global_Env* env, const String* name) { Class *clss = NULL; - TRACE2("classloader.newclass", "allocating Class for \"" << name->bytes << "\"\n" ); + TRACE2("classloader.newclass", "allocating Class for \"" << name->bytes << "\"" ); if(env->InBootstrap() && name == env->JavaLangClass_String) { assert(env->JavaLangClass_Class == NULL); @@ -246,16 +246,14 @@ Class* ClassLoader::DefineClass(Global_E { const String *className; - TRACE2("classloader.defineclass", "Defining class " << class_name << " with loader " << this); + LOG2("classloader.defineclass", "Defining class " << class_name << " with loader " << this); if(class_name) { className = env->string_pool.lookup(class_name); } else { className = class_extract_name(env, bytecode, offset, length); if(className == NULL) { - jthrowable exn = exn_create("java/lang/LinkageError", - "DefineClass was called without class name and " - "class name could not be extracted from provided class data"); - exn_raise_only(exn); + exn_raise_by_name("java/lang/ClassFormatError", + "class name could not be extracted from provided class data", NULL); return NULL; } } @@ -751,6 +749,7 @@ void ClassLoader::ReallocateTable( unsig Class* ClassLoader::StartLoadingClass(Global_Env* UNREF env, const String* className) { + TRACE2("classloader.loading", "StartLoading class " << className << " with loader " << this); Class** pklass = NULL; Class* klass = NULL; @@ -822,10 +821,11 @@ #endif void ClassLoader::FailedLoadingClass(const String* className) { + LOG2("classloader", "Failed loading class " << className << " with loader " << this); LMAutoUnlock aulock( &m_lock ); LoadingClass* lc = m_loadingClasses->Lookup(className); - if(lc) { + if (lc) { lc->SignalLoading(); RemoveLoadingClass(className, lc); } @@ -910,7 +910,7 @@ Class* ClassLoader::WaitDefinition(Globa std::stringstream ss; ss << "class " << clss->name->bytes << " is defined second time"; jthrowable exn = exn_create("java/lang/LinkageError", ss.str().c_str()); - exn_raise_only(exn); + exn_raise_object(exn); return NULL; } @@ -973,7 +973,9 @@ Class* ClassLoader::SetupAsArray(Global_ baseType[nameLen] != 0; nameLen++); if(!baseType[nameLen]) { FailedLoadingClass(classNameString); - REPORT_FAILED_CLASS_NAME(this, className, "java/lang/NoClassDefFoundError", className); + REPORT_FAILED_CLASS_NAME(this, className, + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + className); return NULL; } baseClass = LoadVerifyAndPrepareClass(env, env->string_pool.lookup(baseType, nameLen)); @@ -988,7 +990,8 @@ Class* ClassLoader::SetupAsArray(Global_ default: FailedLoadingClass(classNameString); REPORT_FAILED_CLASS_NAME(this, className, - "java/lang/NoClassDefFoundError", className); + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + className); return NULL; } ClassLoader* baseLoader = baseClass->class_loader; @@ -1050,9 +1053,11 @@ Class* ClassLoader::SetupAsArray(Global_ // insert Java field, required by spec - 'length' klass->n_fields = 1; klass->fields = new Field[1]; - klass->fields[0].set(klass, env->Length_String, env->IntDescriptor_String, ACC_PUBLIC|ACC_FINAL); + klass->fields[0].set(klass, env->Length_String, + env->string_pool.lookup("I"), ACC_PUBLIC|ACC_FINAL); klass->fields[0].set_field_type_desc( type_desc_create_from_java_descriptor("I", NULL)); + klass->fields[0].set_injected(); klass->super_name = env->JavaLangObject_String; @@ -1093,17 +1098,6 @@ Class* ClassLoader::AllocateAndReportIns assert(name); if (env->InBootstrap()) { - - /* - * AnnotatedElement, GenericDeclaration, Type are there becuase in - * Java 5, Class implements them in addition to Serializable - */ - assert((clss->name == env->JavaLangObject_String) - || (strcmp(clss->name->bytes, "java/io/Serializable") == 0) - || (clss->name == env->JavaLangClass_String) - || (strcmp(clss->name->bytes, "java/lang/reflect/AnnotatedElement") == 0) - || (strcmp(clss->name->bytes, "java/lang/reflect/GenericDeclaration") == 0) - || (strcmp(clss->name->bytes, "java/lang/reflect/Type") == 0)); clss->class_handle = NULL; } else { Class* root_class = env->JavaLangClass_Class; @@ -1118,7 +1112,7 @@ Class* ClassLoader::AllocateAndReportIns tmn_suspend_enable(); // couldn't allocate java.lang.Class instance for this class // ppervov: TODO: throw OutOfMemoryError - exn_raise_only( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); return NULL; } @@ -1213,9 +1207,19 @@ void ClassLoader::FieldClearInternals(Cl void ClassLoader::LoadNativeLibrary( const char *name ) { + // Translate library path to full canonical path to ensure that + // natives_support:search_library_list() will recognize all loaded libraries + apr_pool_t* tmp_pool; + apr_status_t stat = apr_pool_create(&tmp_pool, this->pool); + // FIXME: process failure properly + const char* canoname = port_filepath_canonical(name, tmp_pool); + // get library name from string pool Global_Env *env = VM_Global_State::loader_env; - const String *lib_name = env->string_pool.lookup( name ); + const String *lib_name = env->string_pool.lookup( canoname ); + + // free temporary pool + apr_pool_destroy(tmp_pool); // lock class loader LMAutoUnlock cl_lock( &m_lock ); @@ -1236,7 +1240,7 @@ void ClassLoader::LoadNativeLibrary( con // load native library bool just_loaded; NativeLoadStatus status; - NativeLibraryHandle handle = natives_load_library(name, &just_loaded, &status); + NativeLibraryHandle handle = natives_load_library(lib_name->bytes, &just_loaded, &status); if( !handle || !just_loaded ) { // create error message char apr_error_message[1024]; @@ -1244,7 +1248,7 @@ void ClassLoader::LoadNativeLibrary( con sizeof(apr_error_message)); std::stringstream message_stream; - message_stream << "Failed loading library \"" << name << "\": " + message_stream << "Failed loading library \"" << lib_name->bytes << "\": " << apr_error_message; // trace @@ -1261,7 +1265,7 @@ void ClassLoader::LoadNativeLibrary( con // trace TRACE2("classloader.native", "Loader (" << this - << ") loaded native library: " << name); + << ") loaded native library: " << lib_name->bytes); // allocate memory info = (NativeLibInfo*)Alloc(sizeof(NativeLibInfo)); @@ -1317,7 +1321,8 @@ GenericFunctionPointer ClassLoader::Look << method_name->bytes << method_desc->bytes); // raise exception - exn_raise_by_name( "java/lang/UnsatisfiedLinkError", error ); + jthrowable exc_object = exn_create( "java/lang/UnsatisfiedLinkError", error); + exn_raise_object(exc_object); return NULL; } @@ -1599,6 +1604,7 @@ Class* BootstrapClassLoader::LoadClass(G Class* UserDefinedClassLoader::LoadClass(Global_Env* env, const String* className) { + ASSERT_RAISE_AREA; assert(m_loader != NULL); Class* klass = StartLoadingClass(env, className); @@ -1620,19 +1626,16 @@ Class* UserDefinedClassLoader::LoadClass } // Replace '/' with '.' - unsigned class_name_len = className->len + 1; - char* class_name_buf = new char[class_name_len]; // !!! replace with MM allocation - for(unsigned i = 0; i < class_name_len; i++) { - char c = className->bytes[i]; - if(c == '/') { - class_name_buf[i] = '.'; - } else { - class_name_buf[i] = c; - } + unsigned len = className->len + 1; + char* name = (char*) STD_ALLOCA(len); + char* tmp_name = name; + memcpy(name, className->bytes, len); + while (tmp_name = strchr(tmp_name, '/')) { + *tmp_name = '.'; + ++tmp_name; } - assert(env); - String* class_name_with_dots = env->string_pool.lookup( class_name_buf ); - delete[] class_name_buf; + String* class_name_with_dots = + VM_Global_State::loader_env->string_pool.lookup(name); // call the version that takes the resolve flag // some subclasses of ClassLoader do NOT overload the (Ljava/lang/String;) version of the method @@ -1729,7 +1732,9 @@ Class* UserDefinedClassLoader::LoadClass // class was not loaded but exception was not thrown tmn_suspend_enable(); FailedLoadingClass(className); - REPORT_FAILED_CLASS_NAME(this, className->bytes, "java/lang/NoClassDefFoundError", className->bytes); + REPORT_FAILED_CLASS_NAME(this, className->bytes, + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + className->bytes); return NULL; } ObjectHandle oh = (ObjectHandle) res.l; @@ -1813,8 +1818,9 @@ Class* BootstrapClassLoader::LoadFromFil } assert(clss == NULL); } - REPORT_FAILED_CLASS_NAME(this, class_name->bytes, - "java/lang/NoClassDefFoundError", class_name->bytes); + REPORT_FAILED_CLASS_NAME(this, class_name->bytes, + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + class_name->bytes); FailedLoadingClass(class_name); return NULL; } // BootstrapClassLoader::LoadFromFile @@ -1921,7 +1927,8 @@ classloader_find_native(const Method_Han void ClassLoader::ReportException(const char* exn_name, std::stringstream& message_stream) { // raise exception - exn_raise_by_name(exn_name, message_stream.str().c_str()); + jthrowable exn = exn_create(exn_name, message_stream.str().c_str()); + exn_raise_object(exn); } void BootstrapClassLoader::ReportException(const char* exn_name, std::stringstream& message_stream) diff --git vm/vmcore/src/class_support/java_type.cpp vm/vmcore/src/class_support/java_type.cpp index 8a68249..18cf7c9 100644 --- vm/vmcore/src/class_support/java_type.cpp +++ vm/vmcore/src/class_support/java_type.cpp @@ -53,12 +53,8 @@ TypeDesc* type_desc_create_from_java_des en++; } unsigned len = (unsigned)(en-sn); - char* name = (char*)STD_MALLOC(len+1); - memcpy( name, sn, len ); - name[len] = '\0'; - - String* str = env->string_pool.lookup(name); - STD_FREE(name); + String* str = env->string_pool.lookup(sn, len); + assert(loader); loader->LockTypesCache(); TypeDesc** tdres = loader->GetJavaTypes()->Lookup(str); diff --git vm/vmcore/src/class_support/method_lookup.cpp vm/vmcore/src/class_support/method_lookup.cpp index 9718831..80eb205 100644 --- vm/vmcore/src/class_support/method_lookup.cpp +++ vm/vmcore/src/class_support/method_lookup.cpp @@ -176,14 +176,14 @@ #ifdef USE_METHOD_LOOKUP_CACHE void *guess_end = ((char *)guess->get_code_block_addr()) + guess->get_code_block_size(); if ((addr >= guess_start) && (addr < guess_end)) { #ifdef VM_STATS - vm_stats_total.num_method_lookup_cache_hit++; + VM_Statistics::get_vm_stats().num_method_lookup_cache_hit++; #endif //VM_STATS return guess; } } #endif //USE_METHOD_LOOKUP_CACHE #ifdef VM_STATS - vm_stats_total.num_method_lookup_cache_miss++; + VM_Statistics::get_vm_stats().num_method_lookup_cache_miss++; #endif //VM_STATS p_meth_addr_table_lock->_lock(); diff --git vm/vmcore/src/exception/exceptions.cpp vm/vmcore/src/exception/exceptions.cpp old mode 100644 new mode 100755 index c2d2faa..9c9fdb1 --- vm/vmcore/src/exception/exceptions.cpp +++ vm/vmcore/src/exception/exceptions.cpp @@ -24,530 +24,340 @@ #include "clog.h" #include "heap.h" #include "classloader.h" #include "exceptions.h" +#include "exceptions_impl.h" +#include "exceptions_jit.h" #include "ini.h" #include "interpreter.h" +#include "jni_utils.h" #include "m2n.h" #include "object_handles.h" +#include "vm_arrays.h" #include "vm_strings.h" -// internal declaration of functions -void __stdcall set_current_thread_exception_internal(ManagedObject * exn); - -void exn_throw(jthrowable exc) +bool exn_raised() { - if (interpreter_enabled() - || (m2n_get_frame_type(m2n_get_last_frame()) & FRAME_NON_UNWINDABLE)) { - exn_raise_only(exc); - return; - } - else { - exn_throw_only(exc); - } -} // exn_throw + // no need to disable gc for simple null equality check + return ((NULL != p_TLS_vmthread->thread_exception.exc_object) + || (NULL != p_TLS_vmthread->thread_exception.exc_class)); +} -void exn_throw_only(jthrowable exc) + +//FIXME LAZY EXCEPTION (2006.05.06) +//Find all usage and change to lazy use +jthrowable exn_get() { - assert(!hythread_is_suspend_enabled()); - // Temporary fix of incorrect using of throw_by name in the interpreter - if (interpreter_enabled()) { - exn_raise_only(exc); - return; + // we can check heap references for equality to NULL + // without disabling gc, because GC wouldn't change + // null to non-null and vice versa. + if ((NULL == p_TLS_vmthread->thread_exception.exc_object) + && (NULL == p_TLS_vmthread->thread_exception.exc_class)) { + return NULL; } - assert(is_unwindable()); - - TRACE2("exn", ("%s", "exn_throw_only(), delegating to exn_athrow()")); - // XXX salikh: change to unconditional thread_disable_suspend() - // we use conditional until all of the VM - // is refactored to be definitely gc-safe. - exn_athrow(exc->object, NULL, NULL, NULL); -} + // returned value which will contains jthrowable value of + // curent thread exception + jobject exc; -void exn_raise_only(jthrowable exc) -{ - assert(!is_unwindable()); - assert(exc); + if (NULL != p_TLS_vmthread->thread_exception.exc_object) { + tmn_suspend_disable_recursive(); + exc = oh_allocate_local_handle(); + exc->object = (ManagedObject *) p_TLS_vmthread->thread_exception.exc_object; + tmn_suspend_enable_recursive(); + } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { + exc = exn_create((Exception*)&(p_TLS_vmthread->thread_exception)); + } else { + DIE(("It's impossible internal error in exception handling.")); + } + return exc; +} // exn_get - TRACE2("exn", ("%s", "exn_raise_only(), propagating non-destructively")); +Class* exn_get_class() { + // we can check heap references for equality to NULL + // without disabling gc, because GC wouldn't change + // null to non-null and vice versa. + if ((NULL == p_TLS_vmthread->thread_exception.exc_object) + && (NULL == p_TLS_vmthread->thread_exception.exc_class)) { + return NULL; + } - tmn_suspend_disable_recursive(); - set_current_thread_exception_internal(exc->object); - tmn_suspend_enable_recursive(); -} + Class* result; -bool exn_raised() -{ - // no need to disable gc for simple null equality check - return (NULL != p_TLS_vmthread->p_exception_object); + if (NULL != p_TLS_vmthread->thread_exception.exc_object) { + tmn_suspend_disable_recursive(); + ManagedObject* exn = p_TLS_vmthread->thread_exception.exc_object; + result = exn->vt()->clss; + tmn_suspend_enable_recursive(); + } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { + result = p_TLS_vmthread->thread_exception.exc_class; + } else { + DIE(("It's impossible internal error in exception handling.")); + } + return result; } -jthrowable exn_get() -{ +const char* exn_get_name() { + Class* exc_class = exn_get_class(); - // we can check heap references for equality to NULL - // without disabling gc, because GC wouldn't change - // null to non-null and vice versa. - if (NULL == p_TLS_vmthread->p_exception_object) { + if (NULL == exc_class) { return NULL; } - tmn_suspend_disable_recursive(); - jobject exc = oh_allocate_local_handle(); - exc->object = (ManagedObject *) p_TLS_vmthread->p_exception_object; - tmn_suspend_enable_recursive(); - return exc; -} // exn_get + return class_get_name(exc_class); +} void exn_clear() { tmn_suspend_disable_recursive(); - clear_current_thread_exception(); + clear_exception_internal(); tmn_suspend_enable_recursive(); } bool is_unwindable() { - return !(interpreter_enabled() - || (m2n_get_frame_type(m2n_get_last_frame()) & FRAME_NON_UNWINDABLE)); + M2nFrame* lastFrame = m2n_get_last_frame(); + return !(interpreter_enabled() || (!lastFrame) + || (m2n_get_frame_type(lastFrame) & FRAME_NON_UNWINDABLE)); } -static Class *get_class(const char *exception_name) +bool set_unwindable(bool unwindable) { - Global_Env *env = VM_Global_State::loader_env; - String *exc_str = env->string_pool.lookup(exception_name); - Class *exc_clss = - env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - if (exc_clss == NULL) return NULL; - tmn_suspend_disable(); - class_initialize(exc_clss); - tmn_suspend_enable(); - assert(!exn_raised()); - return exc_clss; -} + M2nFrame* lastFrame = m2n_get_last_frame(); -static Method *lookup_constructor(Class * exc_clss, const char *signature) -{ - Global_Env *env = VM_Global_State::loader_env; - // Get the method for the constructor - String *init_name = env->Init_String; - String *init_descr = env->string_pool.lookup(signature); - Method *exc_init = class_lookup_method(exc_clss, init_name, init_descr); - assert(exc_init); - return exc_init; -} - -static jthrowable create_exception(const char *exception_name) -{ - - assert(hythread_is_suspend_enabled()); - Class *exc_clss = get_class(exception_name); - if (exc_clss == NULL) { - assert(exn_raised()); - return exn_get(); + if (interpreter_enabled() || (!lastFrame)) { + assert(!unwindable); + return false; } - tmn_suspend_disable(); - ManagedObject *e = - class_alloc_new_object_and_run_default_constructor(exc_clss); + int lastFrameType = m2n_get_frame_type(lastFrame); + bool previousValue = !(lastFrameType & FRAME_NON_UNWINDABLE); - if (!e) { - tmn_suspend_enable(); - return VM_Global_State::loader_env->java_lang_OutOfMemoryError; + if (unwindable) { + lastFrameType &= ~FRAME_NON_UNWINDABLE; + } else { + lastFrameType |= FRAME_NON_UNWINDABLE; } + m2n_set_frame_type( lastFrame, (frame_type) lastFrameType); + return previousValue; +} - jobject exc = oh_allocate_local_handle(); - exc->object = e; - tmn_suspend_enable(); - return (jthrowable) exc; +jthrowable exn_create(Exception* exception) { + return create_exception(exception); } -static jthrowable create_exception(const char *exception_name, - jthrowable cause) +jthrowable exn_create(Class* exc_class) { - assert(hythread_is_suspend_enabled()); - Class *exc_clss = get_class(exception_name); - if (exc_clss == NULL) { - assert(exn_raised()); - return exn_get(); - } - Method *exc_init = - lookup_constructor(exc_clss, "(Ljava/lang/Throwable;)V"); - // XXX salikh: change to unconditional thread_disable_suspend() - //bool gc_has_been_disabled = tmn_suspend_disable_and_return_old_value(); - tmn_suspend_disable(); - ManagedObject *e = class_alloc_new_object(exc_clss); - - if (!e) { - tmn_suspend_enable(); - return VM_Global_State::loader_env->java_lang_OutOfMemoryError; - } - - jthrowable exc = oh_allocate_local_handle(); - exc->object = e; - - jvalue args[2]; - args[0].l = exc; - args[1].l = cause; - vm_execute_java_method_array((jmethodID) exc_init, 0, args); - tmn_suspend_enable(); - if (exn_raised()) { - DIE(("Exception constructor has thrown an exception")); - } - //if (!gc_has_been_disabled) tmn_suspend_disable(); - return exc; -} // create_exception(const char* exception_name, jthrowable cause) + return exn_create(exc_class, NULL , NULL); +} -static jthrowable create_exception(const char *exception_name, - jthrowable cause, const char *message) +jthrowable exn_create(Class* exc_class, jthrowable exc_cause) { - // XXX salikh: change to unconditional thread_disable_suspend() - assert(hythread_is_suspend_enabled()); - - Class *exc_clss = get_class(exception_name); - if (exc_clss == NULL) { - assert(exn_raised()); - return exn_get(); - } - Method *exc_init = lookup_constructor(exc_clss, "(Ljava/lang/String;)V"); - tmn_suspend_disable(); // ---------------------vvvvvvvvvvvvvvvvvvvvv - - ManagedObject *exc_obj = class_alloc_new_object(exc_clss); - - if (!exc_obj) { - tmn_suspend_enable(); - return VM_Global_State::loader_env->java_lang_OutOfMemoryError; - } - - jthrowable exc = oh_allocate_local_handle(); - exc->object = exc_obj; - - jobject arg = NULL; - - if (message != NULL) { - ManagedObject *arg_obj = - string_create_from_utf8(message, (unsigned) strlen(message)); - - if (!arg_obj) { - tmn_suspend_enable(); - return VM_Global_State::loader_env->java_lang_OutOfMemoryError; - } + return exn_create(exc_class, NULL, exc_cause); +} - arg = oh_allocate_local_handle(); - arg->object = arg_obj; - } +jthrowable exn_create(Class* exc_class, const char* exc_message) +{ + return exn_create(exc_class, exc_message , NULL); +} - jvalue args[2]; - args[0].l = exc; - args[1].l = arg; +jthrowable exn_create(Class* exc_class, const char* exc_message, jthrowable exc_cause) +{ + ASSERT_RAISE_AREA; + jthrowable exc_object = create_exception(exc_class, exc_message, exc_cause); - vm_execute_java_method_array((jmethodID) exc_init, 0, args); - tmn_suspend_enable(); // ---------------------^^^^^^^^^^^^^^^^^^^^^^^^ - if (exn_raised()) { - DIE(("Exception constructor has thrown an exception")); - } + if (exc_object == NULL) { + exc_object = create_exception(exc_class, exc_message , NULL); - if (cause != 0) { - Method *exc_init_cause = class_lookup_method_recursive(exc_clss, - "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); - assert(exc_init_cause); - jvalue args[2]; - args[0].l = exc; - args[1].l = cause; - jvalue ret_val; - tmn_suspend_disable(); // ---------------------vvvvvvvvvvvvvvvvvvvvv - vm_execute_java_method_array((jmethodID) exc_init_cause, &ret_val, - args); - tmn_suspend_enable(); // ---------------------^^^^^^^^^^^^^^^^^^^^^^^ - - if (exn_raised()) { - DIE(("Exception constructor has thrown an exception")); + if (exc_object == NULL) { + return NULL; } + init_cause(exc_object, exc_cause); } - return exc; -} // create_exception - -jthrowable exn_create(const char* exception_class) -{ - return create_exception(exception_class); + return exc_object; } - -jthrowable exn_create(const char* exception_class, jthrowable cause) +jthrowable exn_create(const char* exc_name) { - return create_exception(exception_class, cause); + return exn_create(exc_name, NULL, NULL); } - -jthrowable exn_create(const char* exception_class, const char* message) +jthrowable exn_create(const char* exc_name, jthrowable exc_cause) { - return create_exception(exception_class, NULL, message); -} - + return exn_create(exc_name, NULL, exc_cause); +} // exn_create(const char* exc_name, jthrowable cause) -jthrowable exn_create(const char* exception_class, const char* message, jthrowable cause) +jthrowable exn_create(const char* exc_name,const char *exc_message) { - return create_exception(exception_class, cause, message); -} + return exn_create(exc_name, exc_message, NULL); +} // exn_create(const char *exception_name, const char *exc_message) - -void exn_throw_by_name(const char *exception_name) +jthrowable exn_create(const char *exc_name, const char *exc_message, jthrowable cause) { - assert(hythread_is_suspend_enabled()); - jthrowable exc = create_exception(exception_name); - tmn_suspend_disable(); - exn_throw_only(exc); - tmn_suspend_enable(); + ASSERT_RAISE_AREA; + Class *exc_class = get_exc_class(exc_name); -} // exn_throw_by_name(const char* exception_name) + if (exc_class == NULL) { + assert(exn_raised()); + return NULL; + } + return exn_create(exc_class, exc_message, cause); +} // exn_create -void exn_throw_by_name(const char *exception_name, const char *message) -{ - assert(hythread_is_suspend_enabled()); - jthrowable exc = create_exception(exception_name, NULL, message); - tmn_suspend_disable(); - exn_throw_only(exc); - tmn_suspend_enable(); +void exn_throw_object(jthrowable exc_object) { + assert(!hythread_is_suspend_enabled()); + assert(is_unwindable()); + // XXX salikh: change to unconditional thread_disable_suspend() + // we use conditional until all of the VM + // is refactored to be definitely gc-safe. -} // exn_throw_by_name(const char* exception_name, const char* message) + exn_throw_object_internal(exc_object); +} -void exn_throw_by_name(const char *exception_name, jthrowable cause, - const char *message) +void exn_throw_by_class(Class* exc_class) { - jthrowable exc = create_exception(exception_name, cause, message); - tmn_suspend_disable(); - exn_throw_only(exc); - tmn_suspend_enable(); -} // exn_throw_by_name(const char* exception_name, jthrowable cause, const char* message) + exn_throw_by_class(exc_class, NULL, NULL); +} -void exn_raise_by_name(const char *exception_name) +void exn_throw_by_class(Class* exc_class, jthrowable exc_cause) { - jthrowable exc = create_exception(exception_name); - exn_raise_only(exc); -} // exn_raise_by_name(const char* exception_name) + exn_throw_by_class(exc_class, NULL, exc_cause); +} -void exn_raise_by_name(const char *exception_name, const char *message) +void exn_throw_by_class(Class* exc_class, const char* exc_message) { - jthrowable exc = create_exception(exception_name, NULL, message); - exn_raise_only(exc); -} // exn_raise_by_name(const char* exception_name, const char* message) + exn_throw_by_class(exc_class, exc_message, NULL); +} -// XXX salikh: remove throw_java_exception -void throw_java_exception(const char *exception_name) +void exn_throw_by_class(Class* exc_class, const char* exc_message, + jthrowable exc_cause) { - exn_throw_by_name(exception_name); -} //throw_java_exception + assert(!hythread_is_suspend_enabled()); + assert(is_unwindable()); -// XXX salikh: remove throw_java_exception -void throw_java_exception(const char *exception_name, const char *message) -{ - exn_throw_by_name(exception_name, message); -} //throw_java_exception + exn_throw_by_class_internal(exc_class, exc_message, exc_cause); +} -// XXX salikh: remove create_chained_exception -jthrowable create_chained_exception(const char *exception_name, - jthrowable cause) +void exn_throw_by_name(const char* exc_name) { - return create_exception(exception_name, cause); + exn_throw_by_name(exc_name, NULL, NULL); } - -//////////////////////////////////////////////////////////////////////// -/// SOURCES BELOW HAVE NOT BEEN REFACTORED NOR CLEANED UP //-salikh///// -//////////////////////////////////////////////////////////////////////// - - -#include <assert.h> -#include <float.h> -#include <stdlib.h> -#include <stdio.h> - -#include "platform.h" - -#include "Class.h" -#include "classloader.h" -#include "environment.h" -#include "exception.h" -#include "exceptions.h" -#include "jit_intf.h" -#include "jit_intf_cpp.h" -#include "jni_direct.h" -#include "jni_utils.h" -#include "lil.h" -#include "lil_code_generator.h" -#include "mon_enter_exit.h" -#include "object_handles.h" -#include "vm_arrays.h" -#include "vm_stats.h" -#include "vm_strings.h" -#include "open/types.h" - -#include "open/vm_util.h" - -#include "stack_iterator.h" -#include "stack_trace.h" -#include "interpreter.h" - -#ifdef _IPF_ -#elif defined _EM64T_ -#include "../m2n_em64t_internal.h" -#else -#include "../m2n_ia32_internal.h" -#endif - - -extern bool dump_stubs; - -//////////////////////////////////////////////////////////////////////////// -// Target_Exception_Handler - -Target_Exception_Handler::Target_Exception_Handler(NativeCodePtr start_ip, - NativeCodePtr end_ip, - NativeCodePtr handler_ip, Class_Handle exn_class, bool exn_is_dead) +void exn_throw_by_name(const char* exc_name, jthrowable exc_cause) { - _start_ip = start_ip; - _end_ip = end_ip; - _handler_ip = handler_ip; - _exc = exn_class; - _exc_obj_is_dead = exn_is_dead; + exn_throw_by_name(exc_name, NULL, exc_cause); } -NativeCodePtr Target_Exception_Handler::get_start_ip() +void exn_throw_by_name(const char* exc_name, const char* exc_message) { - return _start_ip; + exn_throw_by_name(exc_name, exc_message, NULL); } -NativeCodePtr Target_Exception_Handler::get_end_ip() +void exn_throw_by_name(const char* exc_name, const char* exc_message, + jthrowable exc_cause) { - return _end_ip; + assert(!hythread_is_suspend_enabled()); + assert(is_unwindable()); + + exn_throw_by_name_internal(exc_name, exc_message, exc_cause); } -NativeCodePtr Target_Exception_Handler::get_handler_ip() +void exn_raise_object(jthrowable exc_object) { - return _handler_ip; + assert(!is_unwindable()); + assert(exc_object); + exn_raise_object_internal(exc_object); } -Class_Handle Target_Exception_Handler::get_exc() +void exn_raise_by_class(Class* exc_class) { - return _exc; + exn_raise_by_class(exc_class, NULL, NULL); } -bool Target_Exception_Handler::is_exc_obj_dead() +void exn_raise_by_class(Class* exc_class, jthrowable exc_cause) { - return _exc_obj_is_dead; + exn_raise_by_class(exc_class, NULL, exc_cause); } -#ifdef POINTER64 -typedef uint64 NumericNativeCodePtr; -#else -typedef uint32 NumericNativeCodePtr; -#endif - -bool Target_Exception_Handler::is_in_range(NativeCodePtr ip, bool is_ip_past) +void exn_raise_by_class(Class* exc_class, const char* exc_message) { - NumericNativeCodePtr nip = (NumericNativeCodePtr) ip; - NumericNativeCodePtr sip = (NumericNativeCodePtr) _start_ip; - NumericNativeCodePtr eip = (NumericNativeCodePtr) _end_ip; - - return (is_ip_past ? sip < nip && nip <= eip : sip <= nip && nip < eip); -} //Target_Exception_Handler::is_in_range + exn_raise_by_class(exc_class, exc_message, NULL); +} -bool Target_Exception_Handler::is_assignable(Class_Handle exn_class) -{ - if (!_exc) - return true; - Class_Handle e = exn_class; - while (e) - if (e == _exc) - return true; - else - e = class_get_super_class(e); - return false; -} //Target_Exception_Handler::is_assignable - -void Target_Exception_Handler::update_catch_range(NativeCodePtr new_start_ip, - NativeCodePtr new_end_ip) +void exn_raise_by_class(Class* exc_class, const char* exc_message, + jthrowable exc_cause) { - _start_ip = new_start_ip; - _end_ip = new_end_ip; -} //Target_Exception_Handler::update_catch_range + assert(!is_unwindable()); + assert(exc_class); + exn_raise_by_class_internal(exc_class, exc_message, exc_cause); +} -void Target_Exception_Handler:: -update_handler_address(NativeCodePtr new_handler_ip) +void exn_raise_by_name(const char* exc_name) { - _handler_ip = new_handler_ip; -} //Target_Exception_Handler::update_handler_address - - -////////////////////////////////////////////////////////////////////////// -// Current thread exception + exn_raise_by_name(exc_name, NULL, NULL); +} -void __stdcall set_current_thread_exception_internal(ManagedObject * exn) +void exn_raise_by_name(const char* exc_name, jthrowable exc_cause) { - assert(!hythread_is_suspend_enabled()); - p_TLS_vmthread->p_exception_object = (volatile ManagedObject *) exn; - p_TLS_vmthread->ti_exception_callback_pending = true; + exn_raise_by_name(exc_name, NULL, exc_cause); } -VMEXPORT // temporary solution for interpreter unplug - ManagedObject * get_current_thread_exception() +void exn_raise_by_name(const char* exc_name, const char* exc_message) { - return (ManagedObject *) p_TLS_vmthread->p_exception_object; -} //get_current_thread_exception + exn_raise_by_name(exc_name, exc_message, NULL); +} -VMEXPORT // temporary solution for interpreter unplug -void __stdcall set_current_thread_exception(ManagedObject * exn) +void exn_raise_by_name(const char* exc_name, const char* exc_message, + jthrowable exc_cause) { assert(!is_unwindable()); - set_current_thread_exception_internal(exn); -} //set_current_thread_exception - -VMEXPORT // temporary solution for interpreter unplug -void clear_current_thread_exception() -{ - // function should be only called from suspend disabled mode - // it changes enumeratable reference to zero which is not - // gc safe operation. - assert(!hythread_is_suspend_enabled()); - p_TLS_vmthread->p_exception_object = NULL; + assert(exc_name); + exn_raise_by_name_internal(exc_name, exc_message, exc_cause); +} - if (p_TLS_vmthread->restore_guard_page) { - set_guard_stack(); - } -} //clear_current_thread_exception -void rethrow_current_thread_exception() +void exn_rethrow() { - ManagedObject *exn = get_current_thread_exception(); +#ifndef VM_LAZY_EXCEPTION + ManagedObject *exn = get_exception_object_internal(); assert(exn); - clear_current_thread_exception(); - exn_athrow(exn, NULL); -} //rethrow_current_thread_exception + clear_exception_internal(); + exn_throw_for_JIT(exn, NULL, NULL, NULL, NULL); +#else + if (NULL != p_TLS_vmthread->thread_exception.exc_object) { + ManagedObject* exn_mng_object = p_TLS_vmthread->thread_exception.exc_object; + clear_exception_internal(); + exn_throw_for_JIT(exn_mng_object, NULL, NULL, NULL, NULL); + } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { + Class * exc_class = p_TLS_vmthread->thread_exception.exc_class; + const char* exc_message = p_TLS_vmthread->thread_exception.exc_message; + jthrowable exc_cause = oh_allocate_local_handle(); + exc_cause->object = p_TLS_vmthread->thread_exception.exc_cause; + clear_exception_internal(); + exn_throw_by_class_internal(exc_class, exc_message, exc_cause); + } else { + DIE(("There is no exception.")); + } +#endif + DIE(("It's Unreachable place.")); +} //exn_rethrow -void rethrow_current_thread_exception_if_pending() +void exn_rethrow_if_pending() { - ManagedObject *exn = get_current_thread_exception(); - if (exn) { - clear_current_thread_exception(); - exn_athrow(exn, NULL); + if (exn_raised()) { + exn_rethrow(); } -} //rethrow_current_thread_exception_if_pending - +} //exn_rethrow_if_pending ////////////////////////////////////////////////////////////////////////// // Java Stack Trace Utilities #define STF_AS_JLONG 5 // prints stackTrace via java -inline void exn_java_print_stack_trace(FILE * UNREF f, ManagedObject * exn) +inline void exn_java_print_stack_trace(FILE * UNREF f, jthrowable exc) { // finds java environment JNIEnv_Internal *jenv = jni_native_intf; - // creates exception object - jthrowable exc = (jthrowable) oh_allocate_local_handle(); - ((ObjectHandle) exc)->object = exn; - // finds class of Throwable jclass throwableClazz = FindClass(jenv, VM_Global_State::loader_env->JavaLangThrowable_String); @@ -555,9 +365,6 @@ inline void exn_java_print_stack_trace(F jmethodID printStackTraceID = GetMethodID(jenv, throwableClazz, "printStackTrace", "()V"); CallVoidMethod(jenv, exc, printStackTraceID); - - // free exception object - oh_discard_local_handle((ObjectHandle) exc); } // prints stackTrace via jni @@ -573,12 +380,14 @@ inline void exn_jni_print_stack_trace(FI // print exception message if (ExceptionCheck(jenv)) return; - //if(get_current_thread_exception()) return; + jmethodID getMessageId = GetMethodID(jenv, throwableClazz, "getMessage", "()Ljava/lang/String;"); jstring message = CallObjectMethod(jenv, exc, getMessageId); + if (ExceptionCheck(jenv)) return; + tmn_suspend_disable(); const char *exceptionNameChars = exc->object->vt()->clss->name->bytes; tmn_suspend_enable(); @@ -590,6 +399,7 @@ inline void exn_jni_print_stack_trace(FI GetMethodID(jenv, throwableClazz, "getStackTrace", "()[Ljava/lang/StackTraceElement;"); jobjectArray stackTrace = CallObjectMethod(jenv, exc, getStackTraceID); + if (ExceptionCheck(jenv) || !stackTrace) return; int stackTraceLenth = GetArrayLength(jenv, stackTrace); @@ -624,10 +434,12 @@ inline void exn_jni_print_stack_trace(FI // gets and prints information about class and method jstring className = CallObjectMethod(jenv, stackTraceElement, getClassNameId); + if (ExceptionCheck(jenv)) return; jstring methodName = CallObjectMethod(jenv, stackTraceElement, getMethodNameId); + if (ExceptionCheck(jenv)) return; const char *classNameChars = @@ -640,6 +452,7 @@ inline void exn_jni_print_stack_trace(FI // gets information about java file name jstring fileName = CallObjectMethod(jenv, stackTraceElement, getFileNameId); + if (ExceptionCheck(jenv)) return; @@ -736,704 +549,67 @@ #endif } // prints stack trace using 3 ways: via java, via jni, and native -void exn_print_stack_trace(FILE * f, ManagedObject * exn) +void exn_print_stack_trace(FILE * f, jthrowable exc) { - assert(!hythread_is_suspend_enabled()); + assert(hythread_is_suspend_enabled()); // saves curent thread exception and clear to allow java to work - Java_java_lang_Throwable *cte = get_current_thread_exception(); - jthrowable j = oh_allocate_local_handle(); - j->object = cte; + jthrowable cte = exn_get(); /* - Afremov Pavel 20050120 - FIXME:Don't wor under JIT, Fix requred - // 1 way -> tries to print stacktrace via java - exn_java_print_stack_trace(f, exn); - - // if everything ok ... - if (!get_current_thread_exception()) - { - // restores curent thread exception and returns - set_current_thread_exception_internal(j->object); - return; - } - */ - // clears exception to allow java to work - clear_current_thread_exception(); + Afremov Pavel 20050120 + FIXME:Don't work under JIT, Fix requred + // 1 way -> tries to print stacktrace via java + exn_java_print_stack_trace(f, exn); + // if everything ok ... + if (!exn_raised()) { - NativeObjectHandles lhs; - jobject exc = oh_allocate_local_handle(); - exc->object = exn; - - // 2 way -> tries to print using jni access to class method - tmn_suspend_enable(); - exn_jni_print_stack_trace(f, exc); - tmn_suspend_disable(); - exn = exc->object; + // restores curent thread exception and returns + exn_raise_object(cte); + return; } + */ + // clears exception to allow java to work + exn_clear(); + + // 2 way -> tries to print using jni access to class method + exn_jni_print_stack_trace(f, exc); -/* -Afremov Pavel 20050120 -FIXME:Don't wor under ClassPath, Fix requred // if everything OK ... - if (!get_current_thread_exception()) + if (!exn_raised()) { // restores curent thread exception and returns - set_current_thread_exception_internal(j->object); + exn_raise_object(cte); return; } -*/ - // restore curent thread exception - set_current_thread_exception_internal(j->object); + // 3 way -> last + tmn_suspend_disable(); + ManagedObject *exn = exc->object; exn_native_print_stack_trace(f, exn); - fflush(f); -} - - -////////////////////////////////////////////////////////////////////////// -// Uncaught Exceptions - -void print_uncaught_exception_message(FILE * f, char *context_message, - ManagedObject * exn) -{ - assert(!hythread_is_suspend_enabled()); - fprintf(f, "** During %s uncaught exception: %s\n", context_message, - exn->vt()->clss->name->bytes); - exn_print_stack_trace(f, exn); -} - - -////////////////////////////////////////////////////////////////////////// -// Lazy Exception Utilities - -static ManagedObject *create_lazy_exception(StackIterator * UNREF throw_si, - Class_Handle exn_class, Method_Handle exn_constr, uint8 * exn_constr_args) -{ - assert(!hythread_is_suspend_enabled()); - volatile ManagedObject *exn_obj = 0; - assert(!hythread_is_suspend_enabled()); - exn_obj = - class_alloc_new_object_and_run_constructor((Class *) exn_class, - (Method *) exn_constr, exn_constr_args); - return (ManagedObject *) exn_obj; -} //create_object_lazily - -////////////////////////////////////////////////////////////////////////// -// Main Exception Propogation Function - -// This function propagates an exception to its handler. -// It can only be called for the current thread. -// The input stack iterator provides the starting point for propogation. If the top frame is an M2nFrame, it is ignored. -// Let A be the current frame, let B be the most recent M2nFrame prior to A. -// The exception is propagated to the first managed frame between A and B that has a handler for the exception, -// or to the native code that managed frame immediately after B if no such managed frame exists. -// If exn_obj is nonnull then it is the exception, otherwise the exception is an instance of -// exn_class created using the given constructor and arguments (a null exn_constr indicates the default constructor). -// The stack iterator is mutated to represent the context that should be resumed. -// The client should either use si_transfer_control to resume it, or use an OS context mechanism -// copied from the final stack iterator. - -static void exn_propagate_exception(StackIterator * si, - ManagedObject ** exn_obj, Class_Handle exn_class, - Method_Handle exn_constr, uint8 * exn_constr_args) -{ - assert(!hythread_is_suspend_enabled()); - ASSERT_NO_INTERPRETER assert(*exn_obj || exn_class); - // Save the throw context - StackIterator *throw_si = si_dup(si); - - // Determine the type of the exception for the type tests below. - if (*exn_obj) - exn_class = (*exn_obj)->vt()->clss; - -#ifdef VM_STATS - ((Class *) exn_class)->num_throws++; - vm_stats_total.num_exceptions++; -#endif // VM_STATS - - // Skip first frame if it is an M2nFrame (which is always a transition from managed to the throw code). - // The M2nFrame will be removed from the thread's M2nFrame list but transfer control or copy to registers. - if (si_is_native(si)) { - si_goto_previous(si); - } - - Method *interrupted_method = NULL; - NativeCodePtr interrupted_method_location = NULL; - JIT *interrupted_method_jit = NULL; - - if (!si_is_native(si)) - { - CodeChunkInfo *interrupted_cci = si_get_code_chunk_info(si); - assert(interrupted_cci); - interrupted_method = interrupted_cci->get_method(); - interrupted_method_location = si_get_ip(si); - interrupted_method_jit = interrupted_cci->get_jit(); - } - - bool same_frame = true; - while (!si_is_past_end(si) && !si_is_native(si)) { - CodeChunkInfo *cci = si_get_code_chunk_info(si); - assert(cci); - Method *method = cci->get_method(); - JIT *jit = cci->get_jit(); - assert(method && jit); - NativeCodePtr ip = si_get_ip(si); - bool is_ip_past = !!si_get_jit_context(si)->is_ip_past; - -#ifdef VM_STATS - cci->num_throws++; -#endif // VM_STATS - - // Examine this frame's exception handlers looking for a match - unsigned num_handlers = cci->get_num_target_exception_handlers(); - for (unsigned i = 0; i < num_handlers; i++) { - Target_Exception_Handler_Ptr handler = - cci->get_target_exception_handler_info(i); - if (!handler) - continue; - if (handler->is_in_range(ip, is_ip_past) - && handler->is_assignable(exn_class)) { - // Found a handler that catches the exception. -#ifdef VM_STATS - cci->num_catches++; - if (same_frame) - vm_stats_total.num_exceptions_caught_same_frame++; - if (handler->is_exc_obj_dead()) - vm_stats_total.num_exceptions_dead_object++; -#endif // VM_STATS - // Setup handler context - jit->fix_handler_context(method, si_get_jit_context(si)); - si_set_ip(si, handler->get_handler_ip(), false); - - // Create exception if necessary - if (!*exn_obj) { - if (handler->is_exc_obj_dead()) { -#ifdef VM_STATS - vm_stats_total.num_exceptions_object_not_created++; -#endif // VM_STATS - } - else { - *exn_obj = - create_lazy_exception(throw_si, exn_class, - exn_constr, exn_constr_args); - } - } - - // Reload exception object pointer because it could have - // moved while calling JVMTI callback - *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, - interrupted_method_jit, interrupted_method, - interrupted_method_location, - jit, method, handler->get_handler_ip()); - - TRACE2("exn", ("setting return pointer to %d", exn_obj)); - - si_set_return_pointer(si, (void **) exn_obj); - si_free(throw_si); - return; - } - } - - // No appropriate handler found, undo synchronization - if (method->is_synchronized()) { - if (method->is_static()) { - assert(!hythread_is_suspend_enabled()); - TRACE2("tm.locks", ("unlock staic sync methods... %x", exn_obj)); - vm_monitor_exit(struct_Class_to_java_lang_Class(method-> - get_class())); - } - else { - void **p_this = - (void **) jit->get_address_of_this(method, - si_get_jit_context(si)); - TRACE2("tm.locks", ("unlock sync methods...%x" , *p_this)); - vm_monitor_exit((ManagedObject *) * p_this); - } - } - - jvalue ret_val = {(jlong)0}; - jvmti_process_method_exit_event(reinterpret_cast<jmethodID>(method), - JNI_TRUE, ret_val); - - // Goto previous frame - si_goto_previous(si); - same_frame = false; - } + tmn_suspend_enable(); - // Exception propagates to the native code + fflush(f); - // The current thread exception is set to the exception and we return 0/NULL to the native code - if (*exn_obj == NULL) { - *exn_obj = - create_lazy_exception(throw_si, exn_class, exn_constr, - exn_constr_args); - } - assert(!hythread_is_suspend_enabled()); + // restore curent thread exception + exn_raise_object(cte); - CodeChunkInfo *catch_cci = si_get_code_chunk_info(si); - Method *catch_method = NULL; - if (catch_cci) - catch_method = catch_cci->get_method(); - - // Reload exception object pointer because it could have - // moved while calling JVMTI callback - *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, - interrupted_method_jit, interrupted_method, interrupted_method_location, - NULL, NULL, NULL); - - set_current_thread_exception_internal(*exn_obj); - - *exn_obj = NULL; - si_set_return_pointer(si, (void **) exn_obj); - si_free(throw_si); -} //exn_propagate_exception - -#ifndef _IPF_ -// Alexei -// Check if we could proceed with destructive stack unwinding, -// i. e. the last GC frame is created before the last m2n frame. -// We use here a knowledge that the newer stack objects -// have smaller addresses for ia32 and em64t architectures. -static bool UNUSED is_gc_frame_before_m2n_frame() -{ - if (p_TLS_vmthread->gc_frames) { - POINTER_SIZE_INT m2n_address = - (POINTER_SIZE_INT) m2n_get_last_frame(); - POINTER_SIZE_INT gc_frame_address = - (POINTER_SIZE_INT) p_TLS_vmthread->gc_frames; - // gc frame is created before the last m2n frame - return m2n_address < gc_frame_address; - } - else { - return true; // no gc frames - nothing to be broken - } } -#endif // _IPF_ -// Throw an exception in the current thread. -// Must be called with an M2nFrame on the top of the stack, and throws to the previous managed -// frames or the previous M2nFrame. -// Exception defined as in previous function. -// Does not return. - -void exn_athrow(ManagedObject * exn_obj, Class_Handle exn_class, - Method_Handle exn_constr, uint8 * exn_constr_args) -{ -/* - * !!!! NO LOGGER IS ALLOWED IN THIS FUNCTION !!! - * !!!! RELEASE BUILD WILL BE BROKEN !!! - * !!!! NO TRACE2, INFO, WARN, ECHO, ASSERT, ... - */ - assert(!hythread_is_suspend_enabled()); - //TRACE2("exn","exn_athrow"); - ASSERT_NO_INTERPRETER if ((exn_obj == NULL) && (exn_class == NULL)) { - Global_Env *env = VM_Global_State::loader_env; - exn_class = env->java_lang_NullPointerException_Class; - } - ManagedObject *local_exn_obj = exn_obj; - StackIterator *si = si_create_from_native(); - -#ifndef _IPF_ - assert(is_gc_frame_before_m2n_frame()); - /*ASSERT(is_gc_frame_before_m2n_frame(), \ - "Last GC frame (" \ - << (POINTER_SIZE_INT) p_TLS_vmthread->gc_frames \ - << ") is below M2N frame (" \ - << (POINTER_SIZE_INT) m2n_get_last_frame() \ - << ") and would be broken during " \ - "destructive stack unwinding"); */ -#endif // _IPF_ - - - //TRACE2("exn", "unwinding stack"); - if (si_is_past_end(si)) { - set_current_thread_exception_internal(local_exn_obj); - return; - } - - // - //TRACE2("exn", "transferring registers"); - si_transfer_all_preserved_registers(si); - //TRACE2("exn", "propagating exception"); - exn_propagate_exception(si, &local_exn_obj, exn_class, exn_constr, - exn_constr_args); - // - //TRACE2("exn", "transferring control"); - si_transfer_control(si); -} //exn_athrow - - -// Throw an exception in the current thread. -// Must be called with the current thread "suspended" in managed code and regs holds the suspended values. -// Exception defined as in previous two functions. -// Mutates the regs value, which should be used to "resume" the managed code. - -void exn_athrow_regs(Registers * regs, Class_Handle exn_class) -{ - assert(exn_class); -#ifndef _IPF_ - M2nFrame *m2nf = m2n_push_suspended_frame(regs); - StackIterator *si = si_create_from_native(); - ManagedObject *local_exn_obj = NULL; - exn_propagate_exception(si, &local_exn_obj, exn_class, NULL, NULL); - si_copy_to_registers(si, regs); - si_free(si); - STD_FREE(m2nf); -#endif -} //exn_athrow_regs ////////////////////////////////////////////////////////////////////////// -// Exception Catch support - -// exception catch callback to restore stack after Stack Overflow Error -void exception_catch_callback() { - if (p_TLS_vmthread->restore_guard_page) { - set_guard_stack(); - } -} - -////////////////////////////////////////////////////////////////////////// -// Runtime Exception Support - -// rt_throw takes an exception and throws it -NativeCodePtr exn_get_rth_throw() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed:ref:void;" - "push_m2n 0, 0;" - "m2n_save_all;" "out platform:ref,pint,pint,pint:void;"); - assert(cs); - - if (VM_Global_State::loader_env->compress_references) - cs = lil_parse_onto_end(cs, - "jc i0=%0i:ref,%n;" - "o0=i0;" "j %o;" ":%g;" "o0=0:ref;" ":%g;", Class::heap_base); - else - cs = lil_parse_onto_end(cs, "o0=i0;"); - assert(cs); - - lil_parse_onto_end(cs, - "o1=0;" "o2=0;" "o3=0;" "call.noret %0i;", exn_athrow); - assert(cs); - - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, "rth_throw", - dump_stubs); - lil_free_code_stub(cs); - return addr; -} //exn_get_rth_throw - - -static void rth_throw_lazy(Method * exn_constr) -{ -#if defined(_IPF_) || defined(_EM64T_) - ABORT("Not supported on this platform"); -#else - uint8 *args = (uint8 *) (m2n_get_args(m2n_get_last_frame()) + 1); // +1 to skip constructor - args += exn_constr->get_num_arg_bytes() - 4; - exn_athrow(NULL, *(Class_Handle *) args, exn_constr, args); -#endif -} //rth_throw_lazy - - -// rt_throw_lazy takes a constructor, the class for that constructor, and arguments for that constructor. -// it throws a (lazily created) instance of that class using that constructor and arguments. -NativeCodePtr exn_get_rth_throw_lazy() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed:pint:void;" - "push_m2n 0, 0;" - "m2n_save_all;" "in2out platform:void;" "call.noret %0i;", - rth_throw_lazy); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, "rth_throw_lazy", - dump_stubs); - lil_free_code_stub(cs); - return addr; -} //exn_get_rth_throw_lazy - - -// rt_throw_lazy_trampoline takes an exception class as first standard place -// and throws a (lazily created) instance of that class using the default constructor -NativeCodePtr exn_get_rth_throw_lazy_trampoline() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 1:managed::void;" - "push_m2n 0, 0;" - "m2n_save_all;" - "out platform:ref,pint,pint,pint:void;" - "o0=0:ref;" "o1=sp0;" "o2=0;" "o3=0;" "call.noret %0i;", - exn_athrow); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_lazy_trampoline", dump_stubs); - lil_free_code_stub(cs); - return addr; -} //exn_get_rth_throw_lazy_trampoline - - -// rth_throw_null_pointer throws a null pointer exception (lazily) -NativeCodePtr exn_get_rth_throw_null_pointer() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - Class *exn_clss = - VM_Global_State::loader_env->java_lang_NullPointerException_Class; - LilCodeStub *cs = - lil_parse_code_stub("entry 0:managed::void;" "std_places 1;" - "sp0=%0i;" "tailcall %1i;", - exn_clss, - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_null_pointer", dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_null_pointer - - -// rth_throw_array_index_out_of_bounds throws an array index out of bounds exception (lazily) -NativeCodePtr exn_get_rth_throw_array_index_out_of_bounds() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - Global_Env *env = VM_Global_State::loader_env; - Class *exn_clss = env->java_lang_ArrayIndexOutOfBoundsException_Class; - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - exn_clss, - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_array_index_out_of_bounds", dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_array_index_out_of_bounds - - -// Return the type of negative array size exception -Class_Handle exn_get_negative_array_size_exception_type() -{ - assert(hythread_is_suspend_enabled()); - Class *exn_clss; - - - Global_Env *env = VM_Global_State::loader_env; - String *exc_str = - env->string_pool.lookup("java/lang/NegativeArraySizeException"); - exn_clss = - env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - assert(exn_clss); - - - return exn_clss; -} - -// rth_throw_negative_array_size throws a negative array size exception (lazily) -NativeCodePtr exn_get_rth_throw_negative_array_size() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - exn_get_negative_array_size_exception_type(), - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_negative_array_size", dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_negative_array_size - - -// Return the type of illegal state exception -Class_Handle exn_get_illegal_state_exception_type() -{ - assert(hythread_is_suspend_enabled()); - Class *exn_clss; - - - Global_Env *env = VM_Global_State::loader_env; - String *exc_str = - env->string_pool.lookup("java/lang/IllegalMonitorStateException"); - exn_clss = - env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - assert(exn_clss); - - return exn_clss; -} - -// rth_throw_negative_array_size throws a negative array size exception (lazily) -NativeCodePtr exn_get_rth_throw_illegal_state_exception() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - exn_get_illegal_state_exception_type(), - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_illegal_state_exception", dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_illegal_state_exception - - -// rth_throw_array_store throws an array store exception (lazily) -NativeCodePtr exn_get_rth_throw_array_store() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - Global_Env *env = VM_Global_State::loader_env; - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - env->java_lang_ArrayStoreException_Class, - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, "rth_throw_array_store", - dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_array_store - - -// rth_throw_arithmetic throws an arithmetic exception (lazily) -NativeCodePtr exn_get_rth_throw_arithmetic() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - Global_Env *env = VM_Global_State::loader_env; - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - env->java_lang_ArithmeticException_Class, - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, "rth_throw_arithmetic", - dump_stubs); - lil_free_code_stub(cs); - - return addr; -} //exn_get_rth_throw_arithmetic - - -// Return the type of class cast exception -Class_Handle exn_get_class_cast_exception_type() -{ - assert(hythread_is_suspend_enabled()); - Class *exn_clss; - - Global_Env *env = VM_Global_State::loader_env; - String *exc_str = env->string_pool.lookup("java/lang/ClassCastException"); - exn_clss = - env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - assert(exn_clss); - - return exn_clss; -} - -// rth_throw_class_cast_exception throws a class cast exception (lazily) -NativeCodePtr exn_get_rth_throw_class_cast_exception() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } +// Uncaught Exceptions - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - exn_get_class_cast_exception_type(), - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(cs && lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_class_cast_exception", dump_stubs); - lil_free_code_stub(cs); - return addr; -} //exn_get_rth_throw_class_cast_exception - - -// Return the type of incompatible class change exception -Class_Handle exn_get_incompatible_class_change_exception_type() +void print_uncaught_exception_message(FILE * f, char *context_message, + jthrowable exc) { assert(hythread_is_suspend_enabled()); - Class *exn_clss; - - Global_Env *env = VM_Global_State::loader_env; - String *exc_str = - env->string_pool.lookup("java/lang/IncompatibleClassChangeError"); - exn_clss = - env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - assert(exn_clss); + tmn_suspend_disable(); + fprintf(f, "** During %s uncaught exception: %s\n", context_message, + exc->object->vt()->clss->name->bytes); + tmn_suspend_enable(); - return exn_clss; + exn_print_stack_trace(f, exc); } - -// rth_throw_incompatible_class_change_exception throws an incompatible class change exception (lazily) -NativeCodePtr exn_get_rth_throw_incompatible_class_change_exception() -{ - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } - - LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" - "std_places 1;" "sp0=%0i;" "tailcall %1i;", - exn_get_incompatible_class_change_exception_type(), - lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); - assert(cs && lil_is_valid(cs)); - addr = - LilCodeGenerator::get_platform()->compile(cs, - "rth_throw_incompatible_class_change_exception", dump_stubs); - lil_free_code_stub(cs); - return addr; -} //exn_get_rth_throw_incompatible_class_change_exception - diff --git vm/vmcore/src/exception/exceptions_impl.cpp vm/vmcore/src/exception/exceptions_impl.cpp new file mode 100644 index 0000000..d1035e6 --- /dev/null +++ vm/vmcore/src/exception/exceptions_impl.cpp @@ -0,0 +1,419 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ + + +#define LOG_DOMAIN "exn" +#include "clog.h" + +#include "Class.h" +#include "classloader.h" +#include "exceptions.h" +#include "exceptions_jit.h" +#include "exceptions_type.h" +#include "environment.h" +#include "heap.h" +#include "ini.h" +#include "vm_strings.h" + +Class *get_exc_class(const char *exception_name) +{ + ASSERT_RAISE_AREA; + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = env->string_pool.lookup(exception_name); + Class *exc_class = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + if (exc_class == NULL) return NULL; + tmn_suspend_disable(); + class_initialize(exc_class); + tmn_suspend_enable(); + assert(!exn_raised()); + return exc_class; +} + +Method* lookup_exc_constructor(Class * exc_class, const char *signature) +{ + ASSERT_RAISE_AREA; + Global_Env *env = VM_Global_State::loader_env; + // Get the method for the constructor + String *init_name = env->Init_String; + String *init_descr = env->string_pool.lookup(signature); + Method *exc_init = class_lookup_method(exc_class, init_name, init_descr); + return exc_init; +} + +//FIXME LAZY EXCEPTION (2006.05.13) +// internal declaration of functions should be moved to exception_impl.h +static Method* prepare_exc_creating(Class* exc_class, jvalue* args, + const char* exc_message); +static Method* prepare_exc_creating(Class* exc_class, jvalue* args, + const char* exc_message, jthrowable exc_cause); + +//FIXME LAZY EXCEPTION (2006.05.13) +// cause can be null +static Method* prepare_exc_creating(Class* exc_class, jvalue* args) { + ASSERT_RAISE_AREA; + + // Finds corresponding constructor + Method* exc_init = lookup_exc_constructor(exc_class, "()V"); + + // Check that constructor is found + if (NULL == exc_init) { + return prepare_exc_creating(exc_class, args, ""); + } + + // Returns found constructor + return exc_init; +} + +static Method* prepare_exc_creating(Class* exc_class, jvalue* args, + jthrowable exc_cause) { + ASSERT_RAISE_AREA; + + // Checks that it's corresponding method + if (NULL == exc_cause) { + return prepare_exc_creating(exc_class, args); + } + + // Finds corresponding constructor + Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/Throwable;)V"); + + // Check that constructor is found + if (exc_init == NULL){ + return prepare_exc_creating(exc_class, args, "", exc_cause); + } + + // Fills arguments for constructor + args[1].l = exc_cause; + + // Returns found constructor + return exc_init; +} + +static Method* prepare_exc_creating(Class* exc_class, jvalue* args, + const char* exc_message) { + ASSERT_RAISE_AREA; + + // Checks that it's corresponding method + if (NULL == exc_message) { + return prepare_exc_creating(exc_class, args); + } + + // Finds corresponding constructor + Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/String;)V"); + + // Check that constructor is found + if (NULL == exc_init){ + return NULL; + } + + // Creates string object + tmn_suspend_disable_recursive(); + + ManagedObject *arg_obj = + string_create_from_utf8(exc_message, (unsigned) strlen(exc_message)); + + if (!arg_obj) { + exn_throw_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + return NULL; + } + jobject arg = oh_allocate_local_handle(); + arg->object = arg_obj; + + tmn_suspend_enable_recursive(); + + // Fills arguments for constructor + args[1].l = arg; + + // Returns found constructor + return exc_init; +} + +static Method* prepare_exc_creating(Class* exc_class, jvalue* args, + const char* exc_message, jthrowable exc_cause) { + ASSERT_RAISE_AREA; + + // Checks that it's corresponding method + if (NULL == exc_message) { + return prepare_exc_creating(exc_class, args, exc_cause); + } + + // Checks that it's corresponding method + if (NULL == exc_cause) { + return prepare_exc_creating(exc_class, args, exc_message); + } + + // Finds corresponding constructor + Method* exc_init = lookup_exc_constructor(exc_class, "(Ljava/lang/String;Ljava/lang/Throwable;)V"); + + // Check that constructor is found + if (NULL == exc_init){ + return NULL; + } + + // Creates string object + tmn_suspend_disable_recursive(); + + ManagedObject *arg_obj = + string_create_from_utf8(exc_message, (unsigned) strlen(exc_message)); + + if (!arg_obj) { + exn_throw_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + return NULL; + } + jobject arg = oh_allocate_local_handle(); + arg->object = arg_obj; + + tmn_suspend_enable_recursive(); + + // Fills arguments for constructor + args[1].l = arg; + args[2].l = exc_cause; + + // Returns found constructor + return exc_init; +} + +void init_cause(jthrowable exc_object, jthrowable exc_cause) { + ASSERT_RAISE_AREA; + assert(exc_cause); + + bool suspended_enabled = hythread_is_suspend_enabled(); + + if (suspended_enabled) { + tmn_suspend_disable(); + } + + Class* exc_class = exc_object->object->vt()->clss; + Method *init_cause_method = class_lookup_method_recursive(exc_class, + "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); + assert(init_cause_method); + jvalue args[2]; + args[0].l = exc_object; + args[1].l = exc_cause; + jvalue ret_val; + vm_execute_java_method_array((jmethodID) init_cause_method, &ret_val, + args); + + if (suspended_enabled) { + tmn_suspend_enable(); + } + + if (exn_raised()) { + DIE(("Exception constructor has thrown an exception")); + } +} + +jthrowable create_exception(Class* exc_class, Method* exc_init, jvalue* args) { + ASSERT_RAISE_AREA; + + bool suspended_enabled = hythread_is_suspend_enabled(); + + if (suspended_enabled) { + tmn_suspend_disable(); + } + + ManagedObject *man_obj = class_alloc_new_object(exc_class); + + if (!man_obj) { + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + return NULL; + } + + jthrowable exc_object = oh_allocate_local_handle(); + exc_object->object = man_obj; + args[0].l = exc_object; + + vm_execute_java_method_array((jmethodID) exc_init, 0, args); + + if (suspended_enabled) { + tmn_suspend_enable(); + } + + return exc_object; +} + +jthrowable create_exception(Class* exc_class, + const char* exc_message, jthrowable exc_cause) +{ + jvalue args[3]; + Method *exc_init = + prepare_exc_creating(exc_class, args, exc_message, exc_cause); + + if (exc_init == NULL){ + return NULL; + } + + jthrowable exc_object = create_exception(exc_class, exc_init, args); + + if (exn_raised()) { + DIE(("Exception constructor has thrown an exception")); + } + return exc_object; +} // create_exception(Class *exc_class, const char *exc_message, jthrowable exc_cause) + +jthrowable create_exception(Exception* exception) +{ + ASSERT_RAISE_AREA; + if ( NULL != exception->exc_class) { + jthrowable exc_cause = NULL; + Class* exc_class = exception->exc_class; + const char* exc_message = exception->exc_message; + + if (NULL != exception->exc_cause) { + tmn_suspend_disable_recursive(); + jthrowable exc_cause = oh_allocate_local_handle(); + exc_cause->object = exception->exc_cause; + tmn_suspend_enable_recursive(); + } + exn_clear(); + return exn_create(exc_class, exc_message, exc_cause); + } else { + return NULL; + } +} + +void exn_throw_object_internal(jthrowable exc_object) +{ + TRACE2("exn", ("%s", "exn_throw_object(), delegating to exn_throw_for_JIT()")); + exn_throw_for_JIT(exc_object->object, NULL, NULL, NULL, NULL); +} + +void exn_throw_by_class_internal(Class* exc_class, const char* exc_message, + jthrowable exc_cause) +{ + assert(is_unwindable()); +#ifdef VM_LAZY_EXCEPTION + set_unwindable(false); + + jvalue args[3]; + Method* exc_init = prepare_exc_creating( + exc_class, args, exc_message, exc_cause); + + if (NULL == exc_init) { + TRACE2("exn", ("%s", + "exn_throw_by_class(),create exception and delegating to exn_throw_for_JIT()")); + jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); + exn_rethrow_if_pending(); + set_unwindable(true); + exn_throw_object_internal(exc_object); + } else { + TRACE2("exn", ("%s", "exn_throw_by_class(), lazy delegating to exn_throw_for_JIT()")); + set_unwindable(true); + exn_throw_for_JIT(NULL, exc_class, exc_init, NULL, args); + } +#else + set_unwindable(false); + jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); + set_unwindable(true); + exn_rethrow_if_pending(); + exn_throw_object_internal(exc_object); +#endif +} +void exn_throw_by_name_internal(const char* exc_name, const char* exc_message, + jthrowable exc_cause) +{ + assert(hythread_is_suspend_enabled()); + set_unwindable(false); + Class *exc_class = get_exc_class(exc_name); + set_unwindable(true); + + if (exc_class == NULL) { + assert(exn_raised()); + exn_rethrow(); + return; // unreachable code + } + exn_throw_by_class_internal(exc_class, exc_message, exc_cause); +} + +void exn_raise_object_internal(jthrowable exc_object) +{ + TRACE2("exn", ("%s", "exn_raise_object(), propagating non-destructively")); + + tmn_suspend_disable_recursive(); + p_TLS_vmthread->thread_exception.exc_object = exc_object->object; + tmn_suspend_enable_recursive(); +} + +void exn_raise_by_class_internal(Class* exc_class, const char* exc_message, + jthrowable exc_cause) +{ +#ifdef VM_LAZY_EXCEPTION + TRACE2("exn", ("%s", "exn_raise_object(), propagating lazy & non-destructively")); + + tmn_suspend_disable_recursive(); + p_TLS_vmthread->thread_exception.exc_class = exc_class; + p_TLS_vmthread->thread_exception.exc_message = exc_message; + + if (exc_cause != NULL) { + p_TLS_vmthread->thread_exception.exc_cause = exc_cause->object; + } else { + p_TLS_vmthread->thread_exception.exc_cause = NULL; + } + tmn_suspend_enable_recursive(); +#else + jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); + + if (exn_raised()){ + return; + } + exn_raise_object_internal(exc_object); +#endif +} + +void exn_raise_by_name_internal(const char* exc_name, const char* exc_message, + jthrowable exc_cause) +{ + assert(hythread_is_suspend_enabled()); + Class *exc_class = get_exc_class(exc_name); + + if (exc_class == NULL) { + assert(exn_raised()); + return; + } + exn_raise_by_class_internal(exc_class, exc_message, exc_cause); +} + +void __stdcall clear_exception_internal() +{ + p_TLS_vmthread->thread_exception.exc_object = NULL; + p_TLS_vmthread->thread_exception.exc_class = NULL; + p_TLS_vmthread->thread_exception.exc_cause = NULL; + p_TLS_vmthread->thread_exception.exc_message = NULL; +} + +void __stdcall set_exception_object_internal(ManagedObject * exc) +{ + assert(!hythread_is_suspend_enabled()); + p_TLS_vmthread->thread_exception.exc_object = exc; +} // set_exc_object_internal + +ManagedObject* __stdcall get_exception_object_internal() +{ + if (NULL != p_TLS_vmthread->thread_exception.exc_object) { + return p_TLS_vmthread->thread_exception.exc_object; + } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { + Exception* exception = (Exception*)&(p_TLS_vmthread->thread_exception); + jthrowable exc_object = create_exception(exception); + return exc_object->object; + } else { + return NULL; + } +} // get_exc_object_internal + diff --git vm/vmcore/src/exception/exceptions_int.cpp vm/vmcore/src/exception/exceptions_int.cpp new file mode 100644 index 0000000..79f7dec --- /dev/null +++ vm/vmcore/src/exception/exceptions_int.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ + +#define LOG_DOMAIN "exn" +#include "clog.h" + +#include "exceptions.h" +#include "exceptions_impl.h" + +////////////////////////////////////////////////////////////////////////// +// Interpreter support +ManagedObject * get_exception_for_interpreter() +{ + return get_exception_object_internal(); +}//get_exception_for_interpreter + +void set_exception_for_interpreter(ManagedObject * exn) +{ + assert(!is_unwindable()); + set_exception_object_internal(exn); +} //set_exception_for_interpreter + +void clear_exception_for_interpreter() +{ + // function should be only called from suspend disabled mode + // it changes enumeratable reference to zero which is not + // gc safe operation. + assert(!hythread_is_suspend_enabled()); + clear_exception_internal(); +} //clear_current_thread_exception + + + + +VMEXPORT +ManagedObject* get_current_thread_exception() { + return get_exception_for_interpreter(); +} + +VMEXPORT +void set_current_thread_exception(ManagedObject* obj) { + set_exception_for_interpreter(obj); +} + +VMEXPORT +void clear_current_thread_exception(){ + clear_exception_for_interpreter(); +} + +VMEXPORT +bool check_current_thread_exception(){ + return exn_raised(); +} + diff --git vm/vmcore/src/exception/exceptions_jit.cpp vm/vmcore/src/exception/exceptions_jit.cpp new file mode 100755 index 0000000..88ab87d --- /dev/null +++ vm/vmcore/src/exception/exceptions_jit.cpp @@ -0,0 +1,872 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Pavel Afremov + * @version $Revision: 1.1 $ + */ + + +#define LOG_DOMAIN "exn" +#include "clog.h" + +#include "Class.h" +#include "open/types.h" + +#include "classloader.h" +#include "exceptions.h" +#include "exceptions_impl.h" +#include "environment.h" +#include "dump.h" +#include "heap.h" +#include "interpreter.h" +#include "jit_intf_cpp.h" +#include "lil.h" +#include "lil_code_generator.h" +#include "m2n.h" +#include "mon_enter_exit.h" +#include "stack_iterator.h" +#include "vm_stats.h" + +#ifdef _IPF_ +#elif defined _EM64T_ +#include "../m2n_em64t_internal.h" +#else +#include "../m2n_ia32_internal.h" +#endif + + +//////////////////////////////////////////////////////////////////////////// +// Target_Exception_Handler + +Target_Exception_Handler::Target_Exception_Handler(NativeCodePtr start_ip, + NativeCodePtr end_ip, + NativeCodePtr handler_ip, Class_Handle exn_class, bool exn_is_dead) +{ + _start_ip = start_ip; + _end_ip = end_ip; + _handler_ip = handler_ip; + _exc = exn_class; + _exc_obj_is_dead = exn_is_dead; +} + +NativeCodePtr Target_Exception_Handler::get_start_ip() +{ + return _start_ip; +} + +NativeCodePtr Target_Exception_Handler::get_end_ip() +{ + return _end_ip; +} + +NativeCodePtr Target_Exception_Handler::get_handler_ip() +{ + return _handler_ip; +} + +Class_Handle Target_Exception_Handler::get_exc() +{ + return _exc; +} + +bool Target_Exception_Handler::is_exc_obj_dead() +{ + return _exc_obj_is_dead; +} + +#ifdef POINTER64 +typedef uint64 NumericNativeCodePtr; +#else +typedef uint32 NumericNativeCodePtr; +#endif + +bool Target_Exception_Handler::is_in_range(NativeCodePtr ip, bool is_ip_past) +{ + NumericNativeCodePtr nip = (NumericNativeCodePtr) ip; + NumericNativeCodePtr sip = (NumericNativeCodePtr) _start_ip; + NumericNativeCodePtr eip = (NumericNativeCodePtr) _end_ip; + + return (is_ip_past ? sip < nip && nip <= eip : sip <= nip && nip < eip); +} //Target_Exception_Handler::is_in_range + +bool Target_Exception_Handler::is_assignable(Class_Handle exn_class) +{ + if (!_exc) + return true; + Class_Handle e = exn_class; + while (e) + if (e == _exc) + return true; + else + e = class_get_super_class(e); + return false; +} //Target_Exception_Handler::is_assignable + +void Target_Exception_Handler::update_catch_range(NativeCodePtr new_start_ip, + NativeCodePtr new_end_ip) +{ + _start_ip = new_start_ip; + _end_ip = new_end_ip; +} //Target_Exception_Handler::update_catch_range + +void Target_Exception_Handler:: +update_handler_address(NativeCodePtr new_handler_ip) +{ + _handler_ip = new_handler_ip; +} //Target_Exception_Handler::update_handler_address + +////////////////////////////////////////////////////////////////////////// +// Lazy Exception Utilities + +// Note: Function runs from unwindable area +static ManagedObject *create_lazy_exception( + Class_Handle exn_class, + Method_Handle exn_constr, + uint8 * exn_constr_args, + jvalue* vm_exn_constr_args) +{ + assert(!hythread_is_suspend_enabled()); + + bool unwindable = set_unwindable(false); + ManagedObject* result; + if (NULL == vm_exn_constr_args) { + result = class_alloc_new_object_and_run_constructor( + (Class*) exn_class, (Method*) exn_constr, exn_constr_args); + } else { + jthrowable exc_object = create_exception( + (Class*) exn_class, (Method*) exn_constr, vm_exn_constr_args); + result = exc_object->object; + } + set_unwindable(unwindable); + exn_rethrow_if_pending(); + return result; +} //create_object_lazily + +////////////////////////////////////////////////////////////////////////// +// Main Exception Propogation Function + +// This function propagates an exception to its handler. +// It can only be called for the current thread. +// The input stack iterator provides the starting point for propogation. If the top frame is an M2nFrame, it is ignored. +// Let A be the current frame, let B be the most recent M2nFrame prior to A. +// The exception is propagated to the first managed frame between A and B that has a handler for the exception, +// or to the native code that managed frame immediately after B if no such managed frame exists. +// If exn_obj is nonnull then it is the exception, otherwise the exception is an instance of +// exn_class created using the given constructor and arguments (a null exn_constr indicates the default constructor). +// The stack iterator is mutated to represent the context that should be resumed. +// The client should either use si_transfer_control to resume it, or use an OS context mechanism +// copied from the final stack iterator. + +static void exn_propagate_exception( + StackIterator * si, + ManagedObject ** exn_obj, + Class_Handle exn_class, + Method_Handle exn_constr, + uint8 * jit_exn_constr_args, + jvalue* vm_exn_constr_args) +{ + assert(!hythread_is_suspend_enabled()); + ASSERT_NO_INTERPRETER; + assert(*exn_obj || exn_class); + + // Save the throw context + StackIterator *throw_si = si_dup(si); + + // Determine the type of the exception for the type tests below. + if (*exn_obj) + exn_class = (*exn_obj)->vt()->clss; + +#ifdef VM_STATS + ((Class *) exn_class)->num_throws++; + VM_Statistics::get_vm_stats().num_exceptions++; +#endif // VM_STATS + + // Skip first frame if it is an M2nFrame (which is always a transition from managed to the throw code). + // The M2nFrame will be removed from the thread's M2nFrame list but transfer control or copy to registers. + if (si_is_native(si)) { + si_goto_previous(si); + } + + Method *interrupted_method = NULL; + NativeCodePtr interrupted_method_location = NULL; + JIT *interrupted_method_jit = NULL; + + if (!si_is_native(si)) + { + CodeChunkInfo *interrupted_cci = si_get_code_chunk_info(si); + assert(interrupted_cci); + interrupted_method = interrupted_cci->get_method(); + interrupted_method_location = si_get_ip(si); + interrupted_method_jit = interrupted_cci->get_jit(); + } + + bool same_frame = true; + while (!si_is_past_end(si) && !si_is_native(si)) { + CodeChunkInfo *cci = si_get_code_chunk_info(si); + assert(cci); + Method *method = cci->get_method(); + JIT *jit = cci->get_jit(); + assert(method && jit); + NativeCodePtr ip = si_get_ip(si); + bool is_ip_past = !!si_get_jit_context(si)->is_ip_past; + +#ifdef VM_STATS + cci->num_throws++; +#endif // VM_STATS + + // Examine this frame's exception handlers looking for a match + unsigned num_handlers = cci->get_num_target_exception_handlers(); + for (unsigned i = 0; i < num_handlers; i++) { + Target_Exception_Handler_Ptr handler = + cci->get_target_exception_handler_info(i); + if (!handler) + continue; + if (handler->is_in_range(ip, is_ip_past) + && handler->is_assignable(exn_class)) { + // Found a handler that catches the exception. +#ifdef VM_STATS + cci->num_catches++; + if (same_frame) + VM_Statistics::get_vm_stats().num_exceptions_caught_same_frame++; + if (handler->is_exc_obj_dead()) + VM_Statistics::get_vm_stats().num_exceptions_dead_object++; +#endif // VM_STATS + // Setup handler context + jit->fix_handler_context(method, si_get_jit_context(si)); + si_set_ip(si, handler->get_handler_ip(), false); + + // Create exception if necessary + if (!*exn_obj) { + if (handler->is_exc_obj_dead()) { +#ifdef VM_STATS + VM_Statistics::get_vm_stats().num_exceptions_object_not_created++; +#endif // VM_STATS + } + else { + *exn_obj = + create_lazy_exception(exn_class, exn_constr, + jit_exn_constr_args, vm_exn_constr_args); + } + } + + // Reload exception object pointer because it could have + // moved while calling JVMTI callback + *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, + interrupted_method_jit, interrupted_method, + interrupted_method_location, + jit, method, handler->get_handler_ip()); + + TRACE2("exn", ("setting return pointer to %d", exn_obj)); + + si_set_return_pointer(si, (void **) exn_obj); + si_free(throw_si); + return; + } + } + + // No appropriate handler found, undo synchronization + if (method->is_synchronized()) { + bool unwindable = set_unwindable(false); + if (method->is_static()) { + assert(!hythread_is_suspend_enabled()); + TRACE2("tm.locks", ("unlock staic sync methods... %x", exn_obj)); + vm_monitor_exit(struct_Class_to_java_lang_Class(method-> + get_class())); + } + else { + void **p_this = + (void **) jit->get_address_of_this(method, + si_get_jit_context(si)); + TRACE2("tm.locks", ("unlock sync methods...%x" , *p_this)); + vm_monitor_exit((ManagedObject *) * p_this); + } + exn_clear(); + set_unwindable(unwindable); + } + + jvalue ret_val = {(jlong)0}; + jvmti_process_method_exit_event(reinterpret_cast<jmethodID>(method), + JNI_TRUE, ret_val); + + // Goto previous frame + si_goto_previous(si); + same_frame = false; + } + + // Exception propagates to the native code + + // The current thread exception is set to the exception and we return 0/NULL to the native code + if (*exn_obj == NULL) { + *exn_obj = + create_lazy_exception(exn_class, exn_constr, + jit_exn_constr_args, vm_exn_constr_args); + } + assert(!hythread_is_suspend_enabled()); + + CodeChunkInfo *catch_cci = si_get_code_chunk_info(si); + Method *catch_method = NULL; + if (catch_cci) + catch_method = catch_cci->get_method(); + + // Reload exception object pointer because it could have + // moved while calling JVMTI callback + *exn_obj = jvmti_jit_exception_event_callback_call(*exn_obj, + interrupted_method_jit, interrupted_method, interrupted_method_location, + NULL, NULL, NULL); + + set_exception_object_internal(*exn_obj); + + *exn_obj = NULL; + si_set_return_pointer(si, (void **) exn_obj); + si_free(throw_si); +} //exn_propagate_exception + +#ifndef _IPF_ +// Alexei +// Check if we could proceed with destructive stack unwinding, +// i. e. the last GC frame is created before the last m2n frame. +// We use here a knowledge that the newer stack objects +// have smaller addresses for ia32 and em64t architectures. +static bool UNUSED is_gc_frame_before_m2n_frame() +{ + if (p_TLS_vmthread->gc_frames) { + POINTER_SIZE_INT m2n_address = + (POINTER_SIZE_INT) m2n_get_last_frame(); + POINTER_SIZE_INT gc_frame_address = + (POINTER_SIZE_INT) p_TLS_vmthread->gc_frames; + // gc frame is created before the last m2n frame + return m2n_address < gc_frame_address; + } + else { + return true; // no gc frames - nothing to be broken + } +} +#endif // _IPF_ + +void exn_throw_for_JIT(ManagedObject* exn_obj, Class_Handle exn_class, + Method_Handle exn_constr, uint8* jit_exn_constr_args, jvalue* vm_exn_constr_args) +{ +/* + * !!!! NO LOGGER IS ALLOWED IN THIS FUNCTION !!! + * !!!! RELEASE BUILD WILL BE BROKEN !!! + * !!!! NO TRACE2, INFO, WARN, ECHO, ASSERT, ... + */ + assert(!hythread_is_suspend_enabled()); + ASSERT_NO_INTERPRETER + + if ((exn_obj == NULL) && (exn_class == NULL)) { + exn_class = VM_Global_State::loader_env->java_lang_NullPointerException_Class; + } + ManagedObject* local_exn_obj = exn_obj; + StackIterator* si = si_create_from_native(); + +#ifndef _IPF_ + assert(is_gc_frame_before_m2n_frame()); +#endif // _IPF_ + + if (si_is_past_end(si)) { + //FIXME LAZY EXCEPTION (2006.05.12) + // should be replaced by lazy version + set_exception_object_internal(local_exn_obj); + return; + } + + si_transfer_all_preserved_registers(si); + exn_propagate_exception(si, &local_exn_obj, exn_class, exn_constr, + jit_exn_constr_args, vm_exn_constr_args); + si_transfer_control(si); +} //exn_throw_for_JIT + +// Throw an exception in the current thread. +// Must be called with an M2nFrame on the top of the stack, and throws to the previous managed +// frames or the previous M2nFrame. +// Exception defined as in previous function. +// Does not return. + +void exn_athrow(ManagedObject* exn_obj, Class_Handle exn_class, + Method_Handle exn_constr, uint8* exn_constr_args) +{ + exn_throw_for_JIT(exn_obj, exn_class, exn_constr, exn_constr_args, NULL); +} + + +// Throw an exception in the current thread. +// Must be called with the current thread "suspended" in managed code and regs holds the suspended values. +// Exception defined as in previous two functions. +// Mutates the regs value, which should be used to "resume" the managed code. + +void exn_athrow_regs(Registers * regs, Class_Handle exn_class) +{ + assert(exn_class); +#ifndef _IPF_ + M2nFrame *m2nf = m2n_push_suspended_frame(regs); + StackIterator *si = si_create_from_native(); + ManagedObject *local_exn_obj = NULL; + exn_propagate_exception(si, &local_exn_obj, exn_class, NULL, NULL, NULL); + si_copy_to_registers(si, regs); + si_free(si); + STD_FREE(m2nf); +#endif +} //exn_athrow_regs + +////////////////////////////////////////////////////////////////////////// +// Exception Catch support + +// exception catch callback to restore stack after Stack Overflow Error +void exception_catch_callback() { + if (p_TLS_vmthread->restore_guard_page) { +#ifndef _EM64T_ + set_guard_stack(); +#endif + } +} + +// exception catch support for JVMTI, also restore stack after Stack Overflow Error +void jvmti_exception_catch_callback(Registers* regs) { + if (p_TLS_vmthread->restore_guard_page) { +#ifndef _EM64T_ + set_guard_stack(); +#endif + } + + M2nFrame *m2nf = m2n_push_suspended_frame(regs); + + printf("jvmti_exception_catch_callback\n"); + st_print(); + + StackIterator *si = si_create_from_native(); + + if (si_is_native(si)) { + si_goto_previous(si); + } + + if (!si_is_native(si)) + { + CodeChunkInfo* catch_cci = si_get_code_chunk_info(si); + assert(catch_cci); + Method* catch_method = catch_cci->get_method(); + NativeCodePtr catch_method_location = si_get_ip(si); + JIT* catch_method_jit = catch_cci->get_jit(); +#ifndef _EM64T_ + // + // FIXME: implement si_get_return_pointer() for EM64T + // + ManagedObject** exn_obj = (ManagedObject**) si_get_return_pointer(si); + *exn_obj = jvmti_jit_exception_catch_event_callback_call( *exn_obj, + catch_method_jit, catch_method, catch_method_location); +#else + assert(0); +#endif + } + + m2n_set_last_frame(m2n_get_previous_frame(m2nf)); + STD_FREE(m2nf); +} + +////////////////////////////////////////////////////////////////////////// +// Runtime Exception Support + +// rt_throw takes an exception and throws it +NativeCodePtr exn_get_rth_throw() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed:ref:void;" + "push_m2n 0, 0;" + "m2n_save_all;" "out platform:ref,pint,pint,pint:void;"); + assert(cs); + + if (VM_Global_State::loader_env->compress_references) + cs = lil_parse_onto_end(cs, + "jc i0=%0i:ref,%n;" + "o0=i0;" "j %o;" ":%g;" "o0=0:ref;" ":%g;", Class::heap_base); + else + cs = lil_parse_onto_end(cs, "o0=i0;"); + assert(cs); + + lil_parse_onto_end(cs, + "o1=0;" "o2=0;" "o3=0;" "call.noret %0i;", exn_athrow); + assert(cs); + + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw + + +static void rth_throw_lazy(Method * exn_constr) +{ +#if defined(_IPF_) || defined(_EM64T_) + ABORT("Lazy exceptions are not supported on this platform"); +#else + uint8 *args = (uint8 *) (m2n_get_args(m2n_get_last_frame()) + 1); // +1 to skip constructor + args += exn_constr->get_num_arg_bytes() - 4; + exn_athrow(NULL, *(Class_Handle *) args, exn_constr, args); +#endif +} //rth_throw_lazy + + +// rt_throw_lazy takes a constructor, the class for that constructor, and arguments for that constructor. +// it throws a (lazily created) instance of that class using that constructor and arguments. +NativeCodePtr exn_get_rth_throw_lazy() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed:pint:void;" + "push_m2n 0, 0;" + "m2n_save_all;" "in2out platform:void;" "call.noret %0i;", + rth_throw_lazy); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_lazy", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw_lazy + + +// rt_throw_lazy_trampoline takes an exception class as first standard place +// and throws a (lazily created) instance of that class using the default constructor +NativeCodePtr exn_get_rth_throw_lazy_trampoline() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 1:managed::void;" + "push_m2n 0, 0;" + "m2n_save_all;" + "out platform:ref,pint,pint,pint:void;" + "o0=0:ref;" "o1=sp0;" "o2=0;" "o3=0;" "call.noret %0i;", + exn_athrow); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_lazy_trampoline", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw_lazy_trampoline + + +// rth_throw_null_pointer throws a null pointer exception (lazily) +NativeCodePtr exn_get_rth_throw_null_pointer() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + Class *exn_clss = + VM_Global_State::loader_env->java_lang_NullPointerException_Class; + LilCodeStub *cs = + lil_parse_code_stub("entry 0:managed::void;" "std_places 1;" + "sp0=%0i;" "tailcall %1i;", + exn_clss, + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_null_pointer", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_null_pointer + +// Return the type of illegal monitor state exception +Class_Handle exn_get_illegal_monitor_state_exception_type() +{ + static Class *exn_clss = NULL; + + if (exn_clss != NULL) { + return exn_clss; + } + + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = + env->string_pool.lookup("java/lang/IllegalMonitorStateException"); + exn_clss = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + assert(exn_clss); + + return exn_clss; +} + +// rth_throw_illegal_monitor_state throws an java.lang.IllegalMonitorStateException (lazily) +NativeCodePtr exn_get_rth_throw_illegal_monitor_state() { + static NativeCodePtr addr = NULL; + + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_get_illegal_monitor_state_exception_type(), + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline()) + ); + assert(lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_illegal_monitor_state", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_null_pointer + + +// rth_throw_array_index_out_of_bounds throws an array index out of bounds exception (lazily) +NativeCodePtr exn_get_rth_throw_array_index_out_of_bounds() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + Global_Env *env = VM_Global_State::loader_env; + Class *exn_clss = env->java_lang_ArrayIndexOutOfBoundsException_Class; + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_clss, + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_array_index_out_of_bounds", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw_array_index_out_of_bounds + + +// Return the type of negative array size exception +Class_Handle exn_get_negative_array_size_exception_type() +{ + assert(hythread_is_suspend_enabled()); + Class *exn_clss; + + + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = + env->string_pool.lookup("java/lang/NegativeArraySizeException"); + exn_clss = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + assert(exn_clss); + + + return exn_clss; +} + +// rth_throw_negative_array_size throws a negative array size exception (lazily) +NativeCodePtr exn_get_rth_throw_negative_array_size() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_get_negative_array_size_exception_type(), + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_negative_array_size", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_negative_array_size + + +// Return the type of illegal state exception +Class_Handle exn_get_illegal_state_exception_type() +{ + assert(hythread_is_suspend_enabled()); + Class *exn_clss; + + + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = + env->string_pool.lookup("java/lang/IllegalMonitorStateException"); + exn_clss = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + assert(exn_clss); + + return exn_clss; +} + +// rth_throw_negative_array_size throws a negative array size exception (lazily) +NativeCodePtr exn_get_rth_throw_illegal_state_exception() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_get_illegal_state_exception_type(), + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_illegal_state_exception", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_illegal_state_exception + + +// rth_throw_array_store throws an array store exception (lazily) +NativeCodePtr exn_get_rth_throw_array_store() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + Global_Env *env = VM_Global_State::loader_env; + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + env->java_lang_ArrayStoreException_Class, + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_array_store", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_array_store + + +// rth_throw_arithmetic throws an arithmetic exception (lazily) +NativeCodePtr exn_get_rth_throw_arithmetic() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + Global_Env *env = VM_Global_State::loader_env; + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + env->java_lang_ArithmeticException_Class, + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_arithmetic", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + + return addr; +} //exn_get_rth_throw_arithmetic + + +// Return the type of class cast exception +Class_Handle exn_get_class_cast_exception_type() +{ + assert(hythread_is_suspend_enabled()); + Class *exn_clss; + + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = env->string_pool.lookup("java/lang/ClassCastException"); + exn_clss = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + assert(exn_clss); + + return exn_clss; +} + +// rth_throw_class_cast_exception throws a class cast exception (lazily) +NativeCodePtr exn_get_rth_throw_class_cast_exception() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_get_class_cast_exception_type(), + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(cs && lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_class_cast_exception", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw_class_cast_exception + + +// Return the type of incompatible class change exception +Class_Handle exn_get_incompatible_class_change_exception_type() +{ + assert(hythread_is_suspend_enabled()); + Class *exn_clss; + + Global_Env *env = VM_Global_State::loader_env; + String *exc_str = + env->string_pool.lookup("java/lang/IncompatibleClassChangeError"); + exn_clss = + env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); + assert(exn_clss); + + + return exn_clss; +} + +// rth_throw_incompatible_class_change_exception throws an incompatible class change exception (lazily) +NativeCodePtr exn_get_rth_throw_incompatible_class_change_exception() +{ + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + LilCodeStub *cs = lil_parse_code_stub("entry 0:managed::void;" + "std_places 1;" "sp0=%0i;" "tailcall %1i;", + exn_get_incompatible_class_change_exception_type(), + lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); + assert(cs && lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_incompatible_class_change_exception", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} //exn_get_rth_throw_incompatible_class_change_exception + diff --git vm/vmcore/src/gc/dll_gc.cpp vm/vmcore/src/gc/dll_gc.cpp index 735333b..1ff52d4 100644 --- vm/vmcore/src/gc/dll_gc.cpp +++ vm/vmcore/src/gc/dll_gc.cpp @@ -32,6 +32,7 @@ #include "open/gc.h" #include "open/vm_util.h" #include "environment.h" #include "properties.h" +#include "object.h" static void default_gc_write_barrier(Managed_Object_Handle); static void default_gc_pin_object(Managed_Object_Handle*); @@ -59,6 +60,7 @@ static void default_gc_add_root_set_entr static void *default_gc_heap_base_address(); static void *default_gc_heap_ceiling_address(); static void default_gc_test_safepoint(); +static int32 default_gc_get_hashcode(Managed_Object_Handle); static Boolean default_gc_supports_frontier_allocation(unsigned *offset_of_current, unsigned *offset_of_limit); @@ -115,6 +117,7 @@ Boolean (*gc_supports_frontier_allocatio void (*gc_pin_object)(Managed_Object_Handle* p_object) = 0; void (*gc_unpin_object)(Managed_Object_Handle* p_object) = 0; Managed_Object_Handle (*gc_get_next_live_object)(void *iterator) = 0; +int32 (*gc_get_hashcode0) (Managed_Object_Handle p_object) = 0; void (*gc_finalize_on_exit)() = 0; @@ -240,6 +243,8 @@ void vm_add_gc(const char *dllName) gc_finalize_on_exit = (void (*)()) getFunctionOptional(handle, "gc_finalize_on_exit", dllName, (apr_dso_handle_sym_t)default_gc_finalize_on_exit); + gc_get_hashcode0 = (int32 (*)(Managed_Object_Handle)) + getFunctionOptional(handle, "gc_get_hashcode", dllName, (apr_dso_handle_sym_t) default_gc_get_hashcode); gc_vm_initialized = (void (*)()) getFunction(handle, "gc_vm_initialized", dllName); gc_requires_barriers = (Boolean (*)()) @@ -410,6 +415,9 @@ static Boolean default_gc_supports_front return FALSE; } +static int32 default_gc_get_hashcode(Managed_Object_Handle obj) { + return default_hashcode(obj); +} static void *default_gc_heap_ceiling_address() { diff --git vm/vmcore/src/gc/root_set_enum_common.cpp vm/vmcore/src/gc/root_set_enum_common.cpp index 64238c7..d224e09 100644 --- vm/vmcore/src/gc/root_set_enum_common.cpp +++ vm/vmcore/src/gc/root_set_enum_common.cpp @@ -34,32 +34,29 @@ static void vm_enumerate_interned_strings() { TRACE2("enumeration", "vm_enumerate_interned_strings()"); - unsigned cookie = 0; - VM_Global_State::loader_env->string_pool.lock_pool(); - String *ps = VM_Global_State::loader_env->string_pool.get_first_string_intern(&cookie); + // string enumeration should be done in stop_the_world phase. + // see String_Pool for more information + String *ps = VM_Global_State::loader_env->string_pool.get_first_string_intern(); // 20030405 Don't enumerate references that are *unmanaged null* (i.e. zero/NULL) // since vm_enumerate_root_reference() expects to be called with slots containing managed refs. if (VM_Global_State::loader_env->compress_references) { while (ps != NULL) { COMPRESSED_REFERENCE compressed_ref = ps->intern.compressed_ref; assert(is_compressed_reference(compressed_ref)); - if (compressed_ref != 0) { - vm_enumerate_compressed_root_reference((COMPRESSED_REFERENCE *)&ps->intern.compressed_ref, - VM_Global_State::loader_env->pin_interned_strings); - } - ps = VM_Global_State::loader_env->string_pool.get_next_string_intern(ps, &cookie); + assert(compressed_ref != 0); + vm_enumerate_compressed_root_reference((COMPRESSED_REFERENCE *)&ps->intern.compressed_ref, + VM_Global_State::loader_env->pin_interned_strings); + ps = VM_Global_State::loader_env->string_pool.get_next_string_intern(); } } else { while (ps != NULL) { ManagedObject* s = ps->intern.raw_ref; - if (s != NULL) { - vm_enumerate_root_reference((void **)&(ps->intern.raw_ref), - VM_Global_State::loader_env->pin_interned_strings); - } - ps = VM_Global_State::loader_env->string_pool.get_next_string_intern(ps, &cookie); + assert(s != NULL); + vm_enumerate_root_reference((void **)&(ps->intern.raw_ref), + VM_Global_State::loader_env->pin_interned_strings); + ps = VM_Global_State::loader_env->string_pool.get_next_string_intern(); } } - VM_Global_State::loader_env->string_pool.unlock_pool(); } //vm_enumerate_interned_strings @@ -227,8 +224,14 @@ VMEXPORT // temporary solution for inter void vm_enumerate_root_set_single_thread_not_on_stack(VM_thread *thread) { assert(thread); - if (thread->p_exception_object != NULL) { - vm_enumerate_root_reference((void **)&(thread->p_exception_object), FALSE); + if (thread->thread_exception.exc_object != NULL) { + vm_enumerate_root_reference((void **)&(thread->thread_exception.exc_object), FALSE); + } + if (thread->thread_exception.exc_cause != NULL) { + vm_enumerate_root_reference((void **)&(thread->thread_exception.exc_cause), FALSE); + } + if (thread->p_exception_object_ti != NULL) { + vm_enumerate_root_reference((void **)&(thread->p_exception_object_ti), FALSE); } if (thread->native_handles) @@ -249,7 +252,7 @@ void vm_enumerate_root_set_single_thread CodeChunkInfo* cci = si_get_code_chunk_info(si); if (cci) { #ifdef VM_STATS - vm_stats_inc(vm_stats_total.num_unwind_java_frames_gc); + vm_stats_inc(VM_Statistics::get_vm_stats().num_unwind_java_frames_gc); vm_stats_inc(cci->num_unwind_java_frames_gc); #endif TRACE2("enumeration", "enumerating eip=" << (void *) si_get_ip(si) @@ -265,7 +268,7 @@ #endif << method_get_descriptor(cci->get_method())); } else { #ifdef VM_STATS - vm_stats_inc(vm_stats_total.num_unwind_native_frames_gc); + vm_stats_inc(VM_Statistics::get_vm_stats().num_unwind_native_frames_gc); #endif TRACE2("enumeration", "enumeration local handles " << (m2n_get_method(si_get_m2n(si)) ? method_get_name(m2n_get_method(si_get_m2n(si))) : "") diff --git vm/vmcore/src/init/bootclasspath.properties vm/vmcore/src/init/bootclasspath.properties index 1d4f0fd..f1958c7 100644 --- vm/vmcore/src/init/bootclasspath.properties +++ vm/vmcore/src/init/bootclasspath.properties @@ -105,3 +105,5 @@ bootclasspath.32=xercesImpl.jar bootclasspath.33=xml-apis.jar bootclasspath.34=x-net.jar + +bootclasspath.35=antlr-2.7.5.jar diff --git vm/vmcore/src/init/finalize.cpp vm/vmcore/src/init/finalize.cpp index e518b72..01af4db 100644 --- vm/vmcore/src/init/finalize.cpp +++ vm/vmcore/src/init/finalize.cpp @@ -334,13 +334,9 @@ void Objects_To_Finalize::run_finalizers tmn_suspend_enable(); if (exn_raised()) { - jobject exc = exn_get(); - tmn_suspend_disable(); - assert(exc->object->vt()->clss); INFO2("finalize", "Uncaught exception " - << class_get_name(exc->object->vt()->clss) + << exn_get_name() << " while running a wakeFinalization in FinalizerThread"); - tmn_suspend_enable(); exn_clear(); } p_TLS_vmthread->finalize_thread_flags &= ~FINALIZER_STARTER; @@ -389,19 +385,20 @@ int Objects_To_Finalize::do_finalization continue; } - Method *finalize = class_lookup_method_recursive(clss, "finalize", "()V"); + Method *finalize = class_lookup_method_recursive(clss, + VM_Global_State::loader_env->FinalizeName_String, + VM_Global_State::loader_env->VoidVoidDescriptor_String); + assert(finalize); TRACE2("finalize", "finalize object " << class_get_name(handle->object->vt()->clss)); vm_execute_java_method_array( (jmethodID) finalize, 0, args); tmn_suspend_enable(); if (exn_raised()) { - jobject exc = exn_get(); tmn_suspend_disable(); - assert(exc->object->vt()->clss); assert(handle->object->vt()->clss); INFO2("finalize", "Uncaught exception " - << class_get_name(exc->object->vt()->clss) + << exn_get_name() << " while running a finalize of the object" << class_get_name(object->vt()->clss) << "."); tmn_suspend_enable(); @@ -436,18 +433,18 @@ void References_To_Enqueue::enqueue_refe assert(handle->object->vt()->clss); Class *clss = handle->object->vt()->clss; TRACE2("ref","Enqueueing reference " << (handle->object)); - Method *enqueue = class_lookup_method_recursive(clss, "enqueue", "()Z"); + Method *enqueue = class_lookup_method_recursive(clss, + VM_Global_State::loader_env->EnqueueName_String, + VM_Global_State::loader_env->VoidBooleanDescriptor_String); assert(enqueue); vm_execute_java_method_array( (jmethodID) enqueue, &r, args); tmn_suspend_enable(); if (exn_raised()) { - jobject exc = exn_get(); tmn_suspend_disable(); - assert(exc->object->vt()->clss); assert(object->vt()->clss); INFO2("ref", "Uncaught exception " - << class_get_name(exc->object->vt()->clss) + << exn_get_name() << " while running a enqueue method of the object" << class_get_name(object->vt()->clss) << "."); tmn_suspend_enable(); diff --git vm/vmcore/src/init/parse_arguments.cpp vm/vmcore/src/init/parse_arguments.cpp index 9ce0f5d..033900c 100644 --- vm/vmcore/src/init/parse_arguments.cpp +++ vm/vmcore/src/init/parse_arguments.cpp @@ -34,6 +34,7 @@ #include <ctype.h> #include "Class.h" #include "properties.h" #include "environment.h" +#include "assertion_registry.h" #include "open/gc.h" @@ -110,15 +111,47 @@ void print_generic_help() " load JVMTI agent library, library name is platform dependent\n" " -verify\n" " do full bytecode verification\n" - " -enableassertions[:<package>|:<class>]\n" - " -ea[:<package>|:<class>]\n" - " enable assertions - NOT SUPPORTED\n" + " -enableassertions[:<package>...|:<class>]\n" + " -ea[:<package>...|:<class>]\n" + " enable assertions\n" + " -disableassertions[:<package>...|:<class>]\n" + " -da[:<package>...|:<class>]\n" + " disable assertions\n" + " -esa | -enablesystemassertions\n" + " enable system assertions\n" + " -dsa | -disablesystemassertions\n" + " disable system assertions\n" " -? -help print this help message\n" " -help properties\n" " help on system properties\n" " -X print help on non-standard options"); } +static inline Assertion_Registry* get_assert_reg(Global_Env *p_env) { + if (!p_env->assert_reg) { + void * mem = p_env->mem_pool.alloc(sizeof(Assertion_Registry)); + p_env->assert_reg = new (mem) Assertion_Registry(); + } + return p_env->assert_reg; +} + +static void add_assert_rec(Global_Env *p_env, const char* option, const char* cmdname, bool value) { + const char* arg = option + strlen(cmdname); + if ('\0' == arg[0]) { + get_assert_reg(p_env)->enable_all = value ? ASRT_ENABLED : ASRT_DISABLED; + } else if (':' != arg[0]) { + ECHO("Unknown option " << option << USE_JAVA_HELP); + LOGGER_EXIT(1); + } else { + unsigned len = strlen(++arg); + if (len >= 3 && strncmp("...", arg + len - 3, 3) == 0) { + get_assert_reg(p_env)->add_package(p_env, arg, len - 3, value); + } else { + get_assert_reg(p_env)->add_class(p_env, arg, len, value); + } + } +} + void parse_vm_arguments(Global_Env *p_env) { #ifdef _DEBUG @@ -281,6 +314,29 @@ #endif //_DEBUG // Store a pointer to the portlib p_env->portLib = p_env->vm_arguments.options[i].extraInfo; } + else if (begins_with(option, "-enableassertions")) { + add_assert_rec(p_env, option, "-enableassertions", true); + } + else if (begins_with(option, "-ea")) { + add_assert_rec(p_env, option, "-ea", true); + } + else if (begins_with(option, "-disableassertions")) { + add_assert_rec(p_env, option, "-disableassertions", false); + } + else if (begins_with(option, "-da")) { + add_assert_rec(p_env, option, "-da", false); + } + else if (strcmp(option, "-esa") == 0 + || strcmp(option, "-enablesystemassertions") == 0) { + get_assert_reg(p_env)->enable_system = true; + } + else if (strcmp(option, "-dsa") == 0 + || strcmp(option, "-disablesystemassertions") == 0) { + if (p_env->assert_reg) { + p_env->assert_reg->enable_system = false; + } + } + else { ECHO("Unknown option " << option << USE_JAVA_HELP); LOGGER_EXIT(1); @@ -451,6 +507,12 @@ #endif {false, "-fullversion", strlen("-fullversion"), 0}, {true, "-ea", strlen("-ea"), 0}, {true, "-enableassertions", strlen("-enableassertions"), 0}, + {true, "-da", strlen("-da"), 0}, + {true, "-disableassertions", strlen("-disableassertions"), 0}, + {false, "-dsa", strlen("-esa"), 0}, + {false, "-esa", strlen("-dsa"), 0}, + {false, "-enablesystemassertions", strlen("-enablesystemassertions"), 0}, + {false, "-disablesystemassertions", strlen("-disablesystemassertions"), 0}, {false, "-Xgc", strlen("-Xgc"), 1}, {true, "-Xem", strlen("-Xem"), 1}, {true, "-Xms", strlen("-Xms"), 0}, @@ -471,17 +533,17 @@ #endif {true, "-Xcategory", strlen("-Xcategory"), 0}, {true, "-Xtimestamp", strlen("-Xtimestamp"), 0}, {true, "-Xwarn", strlen("-Xwarn"), 0}, - {true, "-Xfunction", strlen("-Xfunction"), 0}, + {true, "-Xfunction", strlen("-Xfunction"), 0}, #ifdef _DEBUG {true, "-Xtrace", strlen("-Xtrace"), 0}, {true, "-Xlog", strlen("-Xlog"), 0}, #endif //_DEBUG {true, "-D", strlen("-D"), 0}, {false, "-Xdumpstubs", strlen("-Xdumpstubs"), 0}, - {false, "-Xparallel_jit", strlen("-Xparallel_jit"), 0}, + {false, "-Xparallel_jit", strlen("-Xparallel_jit"), 0}, {false, "-Xno_parallel_jit", strlen("-Xno_parallel_jit"), 0}, {false, "-Xdumpfile", strlen("-Xdumpfile"), 1}, - {false, "-XcleanupOnExit", strlen("-XcleanupOnExit"), 0}, + {false, "-XcleanupOnExit", strlen("-XcleanupOnExit"), 0}, {false, "-jar", strlen("-jar"), 0} }; //supported_parameters @@ -712,14 +774,6 @@ static int parse_vm_option(JavaVMInitArg strcat(option, ":"); strcat(option, argv[i + 1]); } - else if (strncmp(argv[i], "-enableassertions", - strlen("-enableassertions")) == 0 || - strncmp(argv[i], "-ea", strlen("-ea")) == 0) - { - ECHO("Error: Assertions are not supported.\n" - << " please invoke VM without -ea and -enableassertions options..."); - LOGGER_EXIT(1); - } else { option = argv[i]; diff --git vm/vmcore/src/init/properties.cpp vm/vmcore/src/init/properties.cpp index e85e6f0..5a43b56 100644 --- vm/vmcore/src/init/properties.cpp +++ vm/vmcore/src/init/properties.cpp @@ -67,6 +67,54 @@ read_properties(char *fname, Properties apr_file_close(f); } +void +properties_set_string_property(PropertiesHandle ph, const char* key, const char* value) +{ + Properties* p = (Properties*)ph; + add_pair_to_properties(*p, key, value); +} + +PropertiesIteratorHandle +properties_iterator_create(PropertiesHandle ph) +{ + Properties* p = (Properties*)ph; + Properties::Iterator* it = p->getNewIterator(); + it->next(); + return (PropertiesIteratorHandle)it; +} + +void +properties_iterator_destroy(PropertiesHandle ph, PropertiesIteratorHandle pih) +{ + Properties* p = (Properties*)ph; + Properties::Iterator* it = (Properties::Iterator*)pih; + p->destroyIterator(it); +} + +Boolean +properties_iterator_advance(PropertiesIteratorHandle pih) +{ + Properties::Iterator* it = (Properties::Iterator*)pih; + return it->next()!=NULL; +} + +const char* +properties_get_name(PropertiesIteratorHandle pih) +{ + Properties::Iterator* it = (Properties::Iterator*)pih; + Prop_entry* p = it->currentEntry(); + return p->key; +} + +const char* +properties_get_string_value(PropertiesIteratorHandle pih) +{ + + Properties::Iterator* it = (Properties::Iterator*)pih; + Prop_entry* p = it->currentEntry(); + return p->value->as_string(); +} + char *predefined_propeties[] = { // The following properties are added in define_undefined_predefined_properties @@ -77,7 +125,7 @@ char *predefined_propeties[] = "java.vm.specification.version=1.0", "java.vm.specification.vendor=Sun Microsystems Inc.", "java.vm.specification.name=Java Virtual Machine Specification", - "java.specification.version=1.4", + "java.specification.version=1.5", "java.specification.vendor=Sun Microsystems Inc.", "java.specification.name=Java Platform API Specification", "java.version=11.2.0", @@ -161,15 +209,21 @@ static char *load_full_api_files_path_na array_size *= 2; props = (char**)STD_REALLOC(props, array_size*sizeof(char*)); } + unsigned length; char_pos = strchr(jre_file_name, 0x0D); - if (char_pos != NULL) { - *char_pos = '\0'; - } else { + if (!char_pos) { char_pos = strchr(jre_file_name, 0x0A); + } + if (char_pos) { *char_pos = '\0'; + length = char_pos - jre_file_name + 1; + } else { + length = strlen(jre_file_name) + 1; } - int length = char_pos - jre_file_name + 1; char_pos = strchr(jre_file_name, '='); + if (!char_pos) { + DIE("Malformed bootclasspath entry: " << jre_file_name); + } *char_pos = '\0'; props[props_count] = (char*)STD_MALLOC(length * sizeof(char)); memcpy(props[props_count], jre_file_name, length); diff --git vm/vmcore/src/init/vm.cpp vm/vmcore/src/init/vm.cpp index 8bbd9e7..62253b8 100644 --- vm/vmcore/src/init/vm.cpp +++ vm/vmcore/src/init/vm.cpp @@ -182,7 +182,7 @@ void DestroyVM() { ClassLoader::PrintUnloadingStats(); #ifdef VM_STATS - vm_stats_total.print(); + VM_Statistics::get_vm_stats().print(); #endif //VM_STATS // Unloads all system native libraries @@ -251,6 +251,8 @@ #endif // PLATFORM_POSIX true, FALSE}, {"vm.use_verifier", "Use verifier.", true, TRUE}, + {"vm.jvmti.enabled", "Whether JVMTI mode is enabled.", + true, FALSE}, {"vm.cleanupOnExit", "Excplicitly free VM resources before exit.", true, FALSE}, {"vm.bootclasspath.appendclasspath", "Append classpath to the bootclasspath", diff --git vm/vmcore/src/init/vm_init.cpp vm/vmcore/src/init/vm_init.cpp index 15090fd..30ed564 100644 --- vm/vmcore/src/init/vm_init.cpp +++ vm/vmcore/src/init/vm_init.cpp @@ -89,6 +89,7 @@ #ifdef LIB_DEPENDENT_OPTS static Class *class_initialize_by_name(const char *classname) { + ASSERT_RAISE_AREA; Global_Env* env = VM_Global_State::loader_env; String *s = env->string_pool.lookup(classname); @@ -105,6 +106,7 @@ static Class *class_initialize_by_name(c void lib_dependent_opts() { + ASSERT_RAISE_AREA; class_initialize_by_name("java/lang/Math"); } //lib_dependent_opts @@ -134,42 +136,31 @@ static void bootstrap_initial_java_class * j.l.reflect.AnnotatedElement, GenericDeclaration and Type as per Java 5 */ env->StartVMBootstrap(); - Class *class_java_lang_Object = preload_class(env, env->JavaLangObject_String); + env->JavaLangObject_Class = preload_class(env, env->JavaLangObject_String); env->java_io_Serializable_Class = preload_class(env, env->Serializable_String); - Class *AnnotatedElement_Class = preload_class(env, "java/lang/reflect/AnnotatedElement"); - Class *GenericDeclaration_Class = preload_class(env, "java/lang/reflect/GenericDeclaration"); - Class *Type_Class = preload_class(env, "java/lang/reflect/Type"); env->JavaLangClass_Class = preload_class(env, env->JavaLangClass_String); - env->JavaLangObject_Class = class_java_lang_Object; env->FinishVMBootstrap(); - // Now create the java_lang_Class instances for these three classes. + // Now create the java_lang_Class instance. create_instance_for_class(env, env->JavaLangClass_Class); - create_instance_for_class(env, env->java_io_Serializable_Class); - create_instance_for_class(env, AnnotatedElement_Class); - create_instance_for_class(env, GenericDeclaration_Class); - create_instance_for_class(env, Type_Class); - create_instance_for_class(env, env->JavaLangObject_Class); - - // during bootstrapping suspend status never matters, - // so we can enable or disable any way we like. -salikh 2005-05-10 - jvmti_send_class_load_event(env, env->JavaLangObject_Class); - jvmti_send_class_prepare_event(env->JavaLangObject_Class); - jvmti_send_class_load_event(env, env->java_io_Serializable_Class); - jvmti_send_class_prepare_event(env->java_io_Serializable_Class); - jvmti_send_class_load_event(env, AnnotatedElement_Class); - jvmti_send_class_prepare_event(AnnotatedElement_Class); - jvmti_send_class_load_event(env, GenericDeclaration_Class); - jvmti_send_class_prepare_event(GenericDeclaration_Class); - jvmti_send_class_load_event(env, Type_Class); - jvmti_send_class_prepare_event(Type_Class); - jvmti_send_class_load_event(env, env->JavaLangClass_Class); - jvmti_send_class_prepare_event(env->JavaLangClass_Class); - -#ifdef VM_STATS - // Account for the 3 classes loaded before env->JavaLangObject_Class is set. - env->JavaLangObject_Class->num_allocations += 6; - env->JavaLangObject_Class->num_bytes_allocated += (6 * env->JavaLangClass_Class->instance_data_size); + + ClassTable* table = env->bootstrap_class_loader->GetLoadedClasses(); + unsigned num = 0; + for (ClassTable::const_iterator it = table->begin(), end = table->end(); + it != end; ++it, ++num) + { + Class* booted = (*it).second; + if (booted != env->JavaLangClass_Class) { + create_instance_for_class(env, booted); + } + jvmti_send_class_load_event(env, booted); + jvmti_send_class_prepare_event(booted); + } + + #ifdef VM_STATS + // Account for the classes loaded before env->JavaLangObject_Class is set. + env->JavaLangObject_Class->num_allocations += num; + env->JavaLangObject_Class->num_bytes_allocated += (num * env->JavaLangClass_Class->instance_data_size); #endif //VM_STATS TRACE2("init", "bootstrapping initial java classes complete"); } // bootstrap_initial_java_classes @@ -189,7 +180,7 @@ static bool initialize_system_class_load return false; jobject scl = jenv->CallStaticObjectMethod(cl, gcl); - if (exn_get()) + if (exn_raised()) return false; if(scl) { @@ -205,6 +196,8 @@ static bool init_thread_object(JNIEnv *) bool vm_init(Global_Env *env) { + ASSERT_RAISE_AREA; + if(vm_is_initialized) return false; assert(hythread_is_suspend_enabled()); @@ -420,12 +413,9 @@ #endif if(!res) { WARN("Fail to initialize system class loader."); } - if(exn_get()) { - tmn_suspend_disable(); - Java_java_lang_Throwable *exc = ((ObjectHandle)exn_get())->object; + if(exn_raised()) { print_uncaught_exception_message(stderr, - "system class loader initialisation", exc); - tmn_suspend_enable(); + "system class loader initialisation", exn_get()); } exn_clear(); // Ignore any exception that might have occured TRACE2("init", "system class loader initialized"); diff --git vm/vmcore/src/init/vm_main.cpp vm/vmcore/src/init/vm_main.cpp index 1827855..5093956 100644 --- vm/vmcore/src/init/vm_main.cpp +++ vm/vmcore/src/init/vm_main.cpp @@ -348,7 +348,7 @@ #endif initialize_properties(p_env, env.properties); // Enable interpreter by default if TI should be enabled - p_env->TI->setInterpreterState(p_env); + p_env->TI->setExecutionMode(p_env); parse_vm_arguments(p_env); @@ -624,13 +624,14 @@ void interrupt_handler(int UNREF x) } JIT_Handle vm_load_jit(const char* file_name, apr_dso_handle_t** handle) { - if (vm_is_a_jit_dll(file_name)) { + //if (vm_is_a_jit_dll(file_name)) { Dll_JIT* jit = new Dll_JIT(file_name); handle[0]=jit->get_lib_handle(); vm_add_jit(jit); return (JIT_Handle)jit; - } + /*} + printf("not a jit\n"); handle[0]=NULL; - return 0; + return 0;*/ } diff --git vm/vmcore/src/interpreter/interp_imports.cpp vm/vmcore/src/interpreter/interp_imports.cpp index 8ad852e..dac4d3d 100644 --- vm/vmcore/src/interpreter/interp_imports.cpp +++ vm/vmcore/src/interpreter/interp_imports.cpp @@ -21,6 +21,7 @@ #include <stdlib.h> #include "mon_enter_exit.h" #include "interpreter.h" #include "interpreter_imports.h" +#include "jit_intf.h" VMEXPORT void vm_monitor_enter_wrapper(ManagedObject *obj) { vm_monitor_enter(obj); @@ -30,6 +31,11 @@ VMEXPORT void vm_monitor_exit_wrapper(Ma vm_monitor_exit(obj); } +VMEXPORT void class_throw_linking_error_for_interpreter(Class_Handle ch, + unsigned index, unsigned opcode) { + class_throw_linking_error(ch, index, opcode); +} + extern struct JNIEnv_Internal *jni_native_intf; VMEXPORT struct JNIEnv_Internal* get_jni_native_intf() { diff --git vm/vmcore/src/jit/compile.cpp vm/vmcore/src/jit/compile.cpp index 424df0a..4ca7c90 100644 --- vm/vmcore/src/jit/compile.cpp +++ vm/vmcore/src/jit/compile.cpp @@ -21,6 +21,7 @@ #define LOG_DOMAIN "vm.core" #include "cxxlog.h" #include "vm_log.h" +#include "apr_strings.h" #include "lock_manager.h" #include "classloader.h" #include "method_lookup.h" @@ -29,24 +30,17 @@ #include "native_overrides.h" #include "jit_intf_cpp.h" #include "em_intf.h" #include "heap.h" - - -#include "vm_stats.h" #include "vm_strings.h" - #include "compile.h" #include "jit_runtime_support.h" #include "lil_code_generator.h" #include "stack_iterator.h" #include "interpreter.h" -extern bool parallel_jit; - -#ifndef NDEBUG +#include "vm_stats.h" #include "dump.h" -extern bool dump_stubs; -#endif +extern bool parallel_jit; #define METHOD_NAME_BUF_SIZE 512 @@ -363,7 +357,7 @@ #ifdef VM_STATS #endif // Push M2nFrame - cs = lil_parse_onto_end(cs, "push_m2n %0i, %1i, handles; locals 2;", method, FRAME_JNI); + cs = lil_parse_onto_end(cs, "push_m2n %0i, %1i, handles; locals 3;", method, FRAME_JNI); assert(cs); // Allocate space for handles @@ -518,8 +512,8 @@ #endif lil_npc_to_fp(vm_get_rt_support_addr(VM_RT_MONITOR_EXIT_STATIC))); } else { cs = lil_parse_onto_end(cs, - "ld i0,[l0+%0i:ref];" - "out managed:ref:void; o0=i0; call %1i;", + "ld l0,[l0+%0i:ref];" + "out managed:ref:void; o0=l0; call %1i;", oh_get_handle_offset(0), lil_npc_to_fp(vm_get_rt_support_addr(VM_RT_MONITOR_EXIT))); } @@ -543,16 +537,20 @@ #endif } //***** Part 11: Rethrow exception - unsigned eoo = (unsigned)(POINTER_SIZE_INT)&((VM_thread*)0)->p_exception_object; + unsigned eoo = (unsigned)(POINTER_SIZE_INT)&((VM_thread*)0)->thread_exception.exc_object; + unsigned eco = (unsigned)(POINTER_SIZE_INT)&((VM_thread*)0)->thread_exception.exc_class; cs = lil_parse_onto_end(cs, "l0=ts;" - "ld l0,[l0+%0i:ref];" - "jc l0=0,no_exn;" + "ld l2,[l0+%0i:ref];" + "jc l2!=0,_exn_raised;" + "ld l2,[l0+%1i:ref];" + "jc l2=0,_no_exn;" + ":_exn_raised;" "m2n_save_all;" "out platform::void;" - "call.noret %1i;" - ":no_exn;", - eoo, rethrow_current_thread_exception); + "call.noret %2i;" + ":_no_exn;", + eoo, eco, exn_rethrow); assert(cs); //***** Part 12: Restore return variable, pop_m2n, return @@ -568,15 +566,16 @@ #endif //***** Now generate code assert(lil_is_valid(cs)); + NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs); #ifndef NDEBUG - NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs, "jni_stub", dump_stubs); -#else - NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs, "", false); + char buf[100]; + apr_snprintf(buf, sizeof(buf)-1, "jni_stub.%s::%s", class_get_name(clss), method_get_name(method)); + DUMP_STUB(addr, buf, lil_cs_get_code_size(cs)); #endif #ifdef VM_STATS - vm_stats_total.jni_stub_bytes += lil_cs_get_code_size(cs); + VM_Statistics::get_vm_stats().jni_stub_bytes += lil_cs_get_code_size(cs); #endif lil_free_code_stub(cs); @@ -641,7 +640,7 @@ static JIT_Result compile_prepare_native { TRACE2("compile", "compile_prepare_native_method(" << method_get_name(method) << ")"); #ifdef VM_STATS - vm_stats_total.num_native_methods++; + VM_Statistics::get_vm_stats().num_native_methods++; #endif assert(method->is_native()); @@ -689,7 +688,17 @@ JIT_Result compile_do_compilation_jit(Me } OpenMethodExecutionParams flags = {0}; + jvmti_get_compilation_flags(&flags); flags.exe_insert_write_barriers = gc_requires_barriers(); + + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if ( ti->isEnabled() ) { + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT)) + flags.exe_notify_field_access = true; + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT)) + flags.exe_notify_field_modification = true; + } + Compilation_Handle ch; ch.env = VM_Global_State::loader_env; ch.jit = jit; @@ -724,7 +733,6 @@ JIT_Result compile_do_compilation_jit(Me } // Call TI callbacks - DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (ti->isEnabled() && ti->getPhase() == JVMTI_PHASE_LIVE) { jvmti_send_compiled_method_load_event(method); } @@ -735,6 +743,7 @@ JIT_Result compile_do_compilation_jit(Me // Assumes that GC is disabled, but a GC-safe point static JIT_Result compile_do_compilation(Method* method, JIT_Flags flags) { + ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); class_initialize_ex(method->get_class()); @@ -748,9 +757,13 @@ static JIT_Result compile_do_compilation method->unlock(); return JIT_SUCCESS; } else if (method->get_state()==Method::ST_NotCompiled && exn_raised()) { + method->unlock(); return JIT_FAILURE; +#ifndef _EM64T_ } else if(!check_available_stack_size(get_default_stack_size()/100)) { + method->unlock(); return JIT_FAILURE; +#endif } if (method->is_native()) { @@ -776,66 +789,32 @@ static JIT_Result compile_do_compilation // otherwise we create with default constructor. // Then we try to set the cause of the exception to the current thread exception if there is one. // In all cases we ignore any further sources of exceptions and try to proceed anyway. -static ManagedObject* compile_make_exception(const char* name, Method* method) -{ // FIXME: prototype should be changed to getrid of managed objects as parameters. +static jthrowable compile_make_exception(const char* name, Method* method) +{ // FIXME: prototype should be changed to getrid of managed objects . // Now it works in gc disabled mode because of prototype. assert(!hythread_is_suspend_enabled()); - ObjectHandle old_exn = oh_allocate_local_handle(); - old_exn->object = get_current_thread_exception(); - clear_current_thread_exception(); - Global_Env* env = VM_Global_State::loader_env; - String* exc_str = env->string_pool.lookup(name); - - tmn_suspend_enable(); - Class *exc_clss = env->bootstrap_class_loader->LoadVerifyAndPrepareClass(env, exc_str); - assert(exc_clss); - Method* constr = class_lookup_method(exc_clss, env->Init_String, env->FromStringConstructorDescriptor_String); - tmn_suspend_disable(); - - jvalue args[2]; - ObjectHandle msg = oh_allocate_local_handle(); - ObjectHandle res = oh_allocate_local_handle(); - - if (constr) { - const char* c = method->get_class()->name->bytes; - const char* m = method->get_name()->bytes; - const char* d = method->get_descriptor()->bytes; - size_t sz = 25+strlen(c)+strlen(m)+strlen(d); - char* msg_raw = (char*)STD_MALLOC(sz); - assert(msg_raw); - sprintf(msg_raw, "Error compiling method %s.%s%s", c, m, d); - assert(strlen(msg_raw) < sz); - - msg->object = string_create_from_utf8(msg_raw, (unsigned)strlen(msg_raw)); - assert(msg->object); - STD_FREE(msg_raw); - res->object = class_alloc_new_object(exc_clss); - assert(res->object); - args[0].l = (jobject) res; - args[1].l = (jobject) msg; - vm_execute_java_method_array((jmethodID)constr, 0, args); - } else { - res->object = class_alloc_new_object_and_run_default_constructor(exc_clss); - assert(res->object); - } - // Ignore any exceptions from constructor - clear_current_thread_exception(); - if (old_exn->object) { - Method* init = class_lookup_method_recursive(exc_clss, env->InitCause_String, env->InitCauseDescriptor_String); - if (init) { - args[0].l = res; - args[1].l = old_exn; - vm_execute_java_method_array((jmethodID) init, 0, args); - } - // Ignore any exceptions from setting cause - clear_current_thread_exception(); - } - return res->object; + jthrowable old_exc = exn_get(); + exn_clear(); + + const char* c = method->get_class()->name->bytes; + const char* m = method->get_name()->bytes; + const char* d = method->get_descriptor()->bytes; + size_t sz = 25+strlen(c)+strlen(m)+strlen(d); + char* msg_raw = (char*)STD_MALLOC(sz); + assert(msg_raw); + sprintf(msg_raw, "Error compiling method %s.%s%s", c, m, d); + assert(strlen(msg_raw) < sz); + + jthrowable new_exc = exn_create(name, msg_raw, old_exc); + exn_clear(); + STD_FREE(msg_raw); + + return new_exc; } NativeCodePtr compile_jit_a_method(Method* method) { - { // Start of block with GcFrames + ASSERT_RAISE_AREA; TRACE2("compile", "compile_jit_a_method " << method ); ASSERT_NO_INTERPRETER; @@ -857,6 +836,9 @@ NativeCodePtr compile_jit_a_method(Metho assert(&gc == p_TLS_vmthread->gc_frames); INFO2("compile.code", "Compiled method " << method << ", entry " << method->get_code_addr()); + + if (method->get_pending_breakpoints() != 0) + jvmti_set_pending_breakpoints(method); return entry_point; } @@ -865,21 +847,16 @@ NativeCodePtr compile_jit_a_method(Metho INFO2("compile", "Could not compile " << method); const char* exn_class; - - ManagedObject *cause = get_current_thread_exception(); - if (!cause) { + if (!exn_raised()) { if (method->is_native()) { method->set_state(Method::ST_NotCompiled); exn_class = "java/lang/UnsatisfiedLinkError"; } else { exn_class = "java/lang/InternalError"; } - ManagedObject* exn = compile_make_exception(exn_class, method); - set_current_thread_exception(exn); + jthrowable exn = compile_make_exception(exn_class, method); + exn_raise_object(exn); } - } // GcFrames destroyed here, should be before rethrowing exception - rethrow_current_thread_exception(); - ASSERT(0, "Control flow should never reach this point"); return NULL; } //compile_jit_a_method @@ -907,13 +884,10 @@ NativeCodePtr compile_do_instrumentation assert(cs && lil_is_valid(cs)); // TODO: 2 & 3 parameters should be removed from the method signature // since it makes sense for debugging only -#ifndef NDEBUG - NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs, - "compile_do_instrumentation", dump_stubs); -#else - NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs, - "compile_do_instrumentation", false); -#endif + NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "compile_do_instrumentation", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } //compile_do_instrumentation @@ -939,4 +913,35 @@ void count_method_calls(CodeChunkInfo *c } //count_method_calls +// Adding dynamic generated code info to global list +// Is used in JVMTI and native frames interface +DynamicCode* compile_get_dynamic_code_list(void) +{ + return VM_Global_State::loader_env->dcList; +} + +// Adding dynamic generated code info to global list +void compile_add_dynamic_generated_code_chunk(const char* name, const void* address, jint length) +{ + DynamicCode** pdcList = &VM_Global_State::loader_env->dcList; + // FIXME linked list modification without synchronization + DynamicCode *dc = (DynamicCode *)STD_MALLOC(sizeof(DynamicCode)); + assert(dc); + dc->name = name; + dc->address = address; + dc->length = length; + dc->next = *pdcList; + *pdcList = dc; +} + +void compile_clear_dynamic_code_list(DynamicCode* list) +{ + while (list) + { + DynamicCode* next = list->next; + STD_FREE(list); + list = next; + } +} + ////////////////////////////////////////////////////////////////////////// diff --git vm/vmcore/src/jit/dll_jit.cpp vm/vmcore/src/jit/dll_jit.cpp index 26e2566..1454c32 100644 --- vm/vmcore/src/jit/dll_jit.cpp +++ vm/vmcore/src/jit/dll_jit.cpp @@ -54,12 +54,15 @@ _get_native_location_for_bc(NULL), _get_local_var(NULL), _set_local_var(NULL) { + apr_status_t stat; + char buf[1024]; memset((void *) &jit_flags, 0, sizeof(JIT_Flags)); apr_pool_create(&pool, 0); apr_dso_handle_t *handle; - if (apr_dso_load(&handle, dll_filename, pool) != APR_SUCCESS) + if ((stat = apr_dso_load(&handle, dll_filename, pool)) != APR_SUCCESS) { - WARN("Failure to open JIT dll " << dll_filename); + WARN("Failure to open JIT dll " << dll_filename << stat); + printf("apr code: %s\n", apr_dso_error(handle, buf, 1024)); return; } diff --git vm/vmcore/src/jit/dump.cpp vm/vmcore/src/jit/dump.cpp index b83b185..71c5454 100644 --- vm/vmcore/src/jit/dump.cpp +++ vm/vmcore/src/jit/dump.cpp @@ -31,22 +31,22 @@ #include "port_disasm.h" const char * dump_file_name = "file.dump"; int dump(const char * code, const char * name, unsigned int length) { - apr_pool_t * pool; - port_disassembler_t * disassembler; - apr_file_t * file; + static apr_pool_t * pool = NULL; + static port_disassembler_t * disassembler; + static apr_file_t * file = NULL; apr_status_t stat; - if ((stat = apr_pool_create(&pool, NULL)) != APR_SUCCESS) { + if (!pool && (stat = apr_pool_create(&pool, NULL)) != APR_SUCCESS) { return stat; } - if ((stat = port_disassembler_create(&disassembler, pool)) != APR_SUCCESS) { + if (!disassembler && (stat = port_disassembler_create(&disassembler, pool)) != APR_SUCCESS) { apr_pool_destroy(pool); return stat; } - if ((stat = apr_file_open(&file, dump_file_name, - APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_APPEND, + if (!file && (stat = apr_file_open(&file, dump_file_name, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE /*| APR_FOPEN_APPEND*/, APR_FPROT_UREAD | APR_FPROT_UWRITE, pool)) != APR_SUCCESS) { apr_pool_destroy(pool); return stat; @@ -56,7 +56,7 @@ int dump(const char * code, const char * port_disasm_to_file(disassembler, code, length, file); apr_file_printf(file, "Function dump end: %s\n", name); - apr_pool_destroy(pool); +// apr_pool_destroy(pool); return APR_SUCCESS; } diff --git vm/vmcore/src/jit/jit_runtime_support.cpp vm/vmcore/src/jit/jit_runtime_support.cpp index 7f28f48..d171d17 100644 --- vm/vmcore/src/jit/jit_runtime_support.cpp +++ vm/vmcore/src/jit/jit_runtime_support.cpp @@ -40,6 +40,7 @@ #include "platform.h" #include "Class.h" #include "environment.h" #include "exceptions.h" +#include "exceptions_jit.h" #include "open/gc.h" #include "ini.h" #include "jit_runtime_support.h" @@ -52,7 +53,6 @@ #include "method_lookup.h" #include "object_layout.h" #include "object_handles.h" #include "vm_arrays.h" -#include "vm_stats.h" #include "vm_strings.h" #include "vm_synch.h" #include "vm_threads.h" @@ -61,19 +61,10 @@ #include "open/bytecodes.h" #include "open/vm_util.h" #include "jvmti_interface.h" - #include "compile.h" -// TODO: FIXME: We should not include internal stuff -#ifdef _IPF_ -#include "../m2n_ipf_internal.h" -#elif defined _EM64T_ -#include "../m2n_em64t_internal.h" -#else -#include "../m2n_ia32_internal.h" -#endif - -extern bool dump_stubs; +#include "dump.h" +#include "vm_stats.h" // macro that gets the offset of a certain field within a struct or class type #define OFFSET(Struct, Field) \ @@ -88,49 +79,45 @@ #define SIZE(Struct, Field) \ /////////////////////////////////////////////////////////// // New Object and New Array +Vector_Handle vm_rt_new_vector(Class *vector_class, int length) { + ASSERT_THROW_AREA; + Vector_Handle result; + BEGIN_RAISE_AREA; + result = vm_new_vector(vector_class, length); + END_RAISE_AREA; + exn_rethrow_if_pending(); + return result; +} -// Create a multidimensional array -// The M2nFrame arguments holds the number of dimensions and lengths for each one -// Returns -1 if there is a negative size -static Vector_Handle rth_multianewarrayhelper() +Vector_Handle +vm_rt_multianewarray_recursive(Class *c, + int *dims_array, + unsigned dims) { -#ifdef VM_STATS - vm_stats_total.num_multianewarray++; -#endif + ASSERT_THROW_AREA; + Vector_Handle result; + BEGIN_RAISE_AREA; + result = vm_multianewarray_recursive(c, dims_array, dims); + END_RAISE_AREA; + exn_rethrow_if_pending(); + return result; +} -#ifdef _EM64T_ - return (Vector_Handle)NULL; -#else - M2nFrame* m2nf = m2n_get_last_frame(); - const unsigned max_dim = 255; - int lens[max_dim]; - -#ifdef _IPF_ - Class* c = (Class*)*m2n_get_arg_word(m2nf, 0); - unsigned dims = (unsigned)(*m2n_get_arg_word(m2nf, 1) & 0xFFFFffff); - assert(dims<=max_dim); - for(unsigned i=0; i<dims; i++) { - int len = (int)(*m2n_get_arg_word(m2nf, i+2) & 0xFFFFffff); - if (len<0) return (Vector_Handle)-1; - lens[dims-i-1] = (int)len; - } -#else - // FIXME: em64t not tested - POINTER_SIZE_INT* p_args = m2n_get_args(m2nf); - unsigned dims = p_args[1]; - assert(dims<=max_dim); - uint32* lens_base = (uint32*)(p_args+2); - for(unsigned i=0; i<dims; i++) { - int len = lens_base[dims-i-1]; - if (len<0) return (Vector_Handle)-1; - lens[i] = len; - } - Class* c = (Class*)p_args[0]; -#endif - return vm_multianewarray_recursive(c, lens, dims); -#endif // _EM64T_ +Vector_Handle vm_rt_new_vector_using_vtable_and_thread_pointer( + int length, Allocation_Handle vector_handle, void *tp) { + ASSERT_THROW_AREA; + Vector_Handle result; + BEGIN_RAISE_AREA; + result = vm_new_vector_using_vtable_and_thread_pointer(length, vector_handle, tp); + END_RAISE_AREA; + exn_rethrow_if_pending(); + return result; } +// Create a multidimensional array +// Doesn't return if exception occured +Vector_Handle rth_multianewarrayhelper(); + // Multianewarray helper static NativeCodePtr rth_get_lil_multianewarray(int* dyn_count) { @@ -143,18 +130,19 @@ static NativeCodePtr rth_get_lil_multian cs = lil_parse_onto_end(cs, "inc [%0i:pint];", dyn_count); assert(cs); } - cs = lil_parse_onto_end(cs, + cs = lil_parse_onto_end(cs, "push_m2n 0, 0;" "out platform::ref;" "call %0i;" "pop_m2n;" - "jc r=%1i:ref,negsize;" - "ret;" - ":negsize;" - "tailcall %2i;", - rth_multianewarrayhelper, (POINTER_SIZE_INT)-1, lil_npc_to_fp(exn_get_rth_throw_negative_array_size())); + "ret;", + rth_multianewarrayhelper); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_multianewarray", dump_stubs); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "multianewarray", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -166,6 +154,7 @@ static NativeCodePtr rth_get_lil_multian static ManagedObject * rth_ldc_ref_helper(Class *c, unsigned cp_index) { + ASSERT_THROW_AREA; Const_Pool *cp = c->const_pool; if (cp_is_string(cp, cp_index)) { @@ -175,15 +164,22 @@ static ManagedObject * rth_ldc_ref_helpe { assert(!hythread_is_suspend_enabled()); hythread_suspend_enable(); - Class *objClass = class_resolve_class(c, cp_index); + + Class *objClass = NULL; + BEGIN_RAISE_AREA; + objClass = class_resolve_class(c, cp_index); + END_RAISE_AREA; + hythread_suspend_disable(); if (objClass) { return struct_Class_to_java_lang_Class(objClass); } if (!exn_raised()) { + BEGIN_RAISE_AREA; class_throw_linking_error(c, cp_index, 0); + END_RAISE_AREA; } else { - exn_throw(exn_get()); + exn_rethrow(); } } exn_throw_by_name("java/lang/InternalError", "Unsupported ldc argument"); @@ -212,7 +208,10 @@ static NativeCodePtr rth_get_lil_ldc_ref "ret;", p_instantiate_ref); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_ldc_ref", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "ldc_ref", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -236,28 +235,28 @@ enum RthTypeTestNull { RTTN_NoNullCheck, enum RthTypeTestResult { RTTR_ReturnOutcome, RTTR_ThrowStub, RTTR_ThrowInline }; typedef void (*RthTypeTestStatsUpdate)(ManagedObject*, Class*); -static LilCodeStub* rth_gen_lil_type_test(LilCodeStub* cs, RthTypeTestNull null, RthTypeTestResult res, Class* type, - int* dyn_count, RthTypeTestStatsUpdate update_fn) +static LilCodeStub* rth_gen_lil_type_test(LilCodeStub* cs, RthTypeTestNull null, + RthTypeTestResult res, Class* type) { // We need to get the vtable in more than one place below // Here are some macros to helper smooth over the compressed vtables const POINTER_SIZE_INT vtable_off = object_get_vtable_offset(); const POINTER_SIZE_INT vtable_add = vm_vtable_pointers_are_compressed() ? vm_get_vtable_base() : 0; - // Update Stats -#ifdef VM_STATS - assert(dyn_count); - cs = lil_parse_onto_end(cs, "inc [%0i:pint]; in2out platform:void; call %1i;", dyn_count, update_fn); - if (!cs) return NULL; -#endif // Setup locals cs = lil_parse_onto_end(cs, (type ? "locals 1;" : "locals 2;")); - if (!cs) return NULL; + assert(cs); // Null check if (null!=RTTN_NoNullCheck) { - cs = lil_parse_onto_end(cs, (null==RTTN_NullMember ? "jc i0=%0i:ref,success;" : "jc i0=%0i:ref,failed;"), Class::managed_null); - if (!cs) return NULL; + if (null==RTTN_NullMember) { + cs = lil_parse_onto_end(cs, "jc i0!=%0i:ref,null_check_faild;", Class::managed_null); + cs = lil_parse_onto_end(cs, (res==RTTR_ReturnOutcome ? "r=1:g4; ret;" : "r=i0; ret;")); + cs = lil_parse_onto_end(cs, ":null_check_faild;"); + } else { + cs = lil_parse_onto_end(cs, "jc i0=%0i:ref,failed;", Class::managed_null); + } + assert(cs); } // Fast sequence @@ -265,19 +264,18 @@ #endif const POINTER_SIZE_INT depth_off = (POINTER_SIZE_INT)&((Class*)NULL)->depth; const POINTER_SIZE_INT supertable_off = (POINTER_SIZE_INT)&((VTable*)NULL)->superclasses; bool do_slow = true; - bool success_before = false; if (type) { if (type->is_suitable_for_fast_instanceof) { cs = lil_parse_onto_end(cs, vm_vtable_pointers_are_compressed() ? "ld l0,[i0+%0i:g4],zx;" : "ld l0,[i0+%0i:pint];", - vtable_off); - if (!cs) return NULL; + vtable_off); + assert(cs); cs = lil_parse_onto_end(cs, "ld l0,[l0+%1i:pint];" "jc l0!=%2i,failed;", vtable_add+supertable_off+sizeof(Class*)*(type->depth-1), type); - if (!cs) return NULL; do_slow = false; + assert(cs); } } else { cs = lil_parse_onto_end(cs, @@ -285,24 +283,21 @@ #endif "jc l0=0,slowpath;" "ld l1,[i1+%1i:g4],zx;", is_fast_off, depth_off); - if (!cs) return NULL; + assert(cs); cs = lil_parse_onto_end(cs, vm_vtable_pointers_are_compressed() ? "ld l0,[i0+%0i:g4],zx;" : "ld l0,[i0+%0i:pint];", vtable_off); - if (!cs) return NULL; + assert(cs); cs = lil_parse_onto_end(cs, "ld l0,[l0+%0i*l1+%1i:pint];" "jc l0!=i1,failed;", sizeof(Class*), vtable_add+supertable_off-sizeof(Class*)); // -4/8 because we want to index with depth-1 - if (!cs) return NULL; - success_before = true; + assert(cs); } - //*** Success, if before slowpath - if (success_before) { - cs = lil_parse_onto_end(cs, (res==RTTR_ReturnOutcome ? ":success; r=1:g4; ret;" : ":success; r=i0; ret;")); - if (!cs) return NULL; - } + //*** Success, before slow path + cs = lil_parse_onto_end(cs, (res==RTTR_ReturnOutcome ? "r=1:g4; ret;" : "r=i0; ret;")); + assert(cs); //*** Slow sequence const POINTER_SIZE_INT clss_off = (POINTER_SIZE_INT)&((VTable*)NULL)->clss; @@ -311,25 +306,24 @@ #endif cs = lil_parse_onto_end(cs, ":slowpath;" "out platform:pint,pint:g4;"); - if (!cs) return NULL; + assert(cs); cs = lil_parse_onto_end(cs, vm_vtable_pointers_are_compressed() ? "ld l0,[i0+%0i:g4],zx;" : "ld l0,[i0+%0i:pint];", vtable_off); - if (!cs) return NULL; + assert(cs); cs = lil_parse_onto_end(cs, "ld o0,[l0+%0i:pint];" "o1=i1;" "call %1i;", vtable_add+clss_off, p_subclass); - if (!cs) return NULL; - cs = lil_parse_onto_end(cs, (res==RTTR_ReturnOutcome ? "ret;" : success_before ? "jc r!=0,success;" : "jc r=0,failed;")); - if (!cs) return NULL; - } - - //*** Success, if after slowpath - if (!success_before) { - cs = lil_parse_onto_end(cs, (res==RTTR_ReturnOutcome ? ":success; r=1:g4; ret;" : ":success; r=i0; ret;")); - if (!cs) return NULL; + assert(cs); + if (res==RTTR_ReturnOutcome) { + cs = lil_parse_onto_end(cs, "ret;"); + } else { + cs = lil_parse_onto_end(cs, "jc r=0,failed;"); + cs = lil_parse_onto_end(cs, "r=i0; ret;"); + } + assert(cs); } //*** Failure @@ -339,46 +333,60 @@ #endif GenericFunctionPointer thrw = lil_npc_to_fp(exn_get_rth_throw_class_cast_exception()); cs = lil_parse_onto_end(cs, (res==RTTR_ThrowStub ? ":failed; tailcall %0i;" : ":failed; call.noret %0i;"), thrw); } - if (!cs) return NULL; + assert(cs && lil_is_valid(cs)); return cs; } -// General stats update #ifdef VM_STATS +// General stats update static void rth_type_test_update_stats(VTable* sub, Class* super) { - vm_stats_total.num_type_checks ++; + VM_Statistics::get_vm_stats().num_type_checks ++; if (sub->clss == super) - vm_stats_total.num_type_checks_equal_type ++; + VM_Statistics::get_vm_stats().num_type_checks_equal_type ++; if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_type_checks_fast_decision ++; + VM_Statistics::get_vm_stats().num_type_checks_fast_decision ++; else if (super->is_array) - vm_stats_total.num_type_checks_super_is_array ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_array ++; else if (class_is_interface(super)) - vm_stats_total.num_type_checks_super_is_interface ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_interface ++; else if (super->depth >= vm_max_fast_instanceof_depth()) - vm_stats_total.num_type_checks_super_is_too_deep ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_too_deep ++; } -#endif // Checkcast stats update static void rth_update_checkcast_stats(ManagedObject* o, Class* super) { -#ifdef VM_STATS - vm_stats_total.num_checkcast ++; + VM_Statistics::get_vm_stats().num_checkcast ++; if (o == (ManagedObject*)Class::managed_null) { - vm_stats_total.num_checkcast_null++; + VM_Statistics::get_vm_stats().num_checkcast_null++; } else { if (o->vt()->clss == super) - vm_stats_total.num_checkcast_equal_type ++; + VM_Statistics::get_vm_stats().num_checkcast_equal_type ++; if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_checkcast_fast_decision ++; + VM_Statistics::get_vm_stats().num_checkcast_fast_decision ++; rth_type_test_update_stats(o->vt(), super); } -#endif // VM_STATS } +// Instanceof stats update +static void rth_update_instanceof_stats(ManagedObject* o, Class* super) +{ + VM_Statistics::get_vm_stats().num_instanceof++; + super->num_instanceof_slow++; + if (o == (ManagedObject*)Class::managed_null) { + VM_Statistics::get_vm_stats().num_instanceof_null++; + } else { + if (o->vt()->clss == super) + VM_Statistics::get_vm_stats().num_instanceof_equal_type ++; + if (super->is_suitable_for_fast_instanceof) + VM_Statistics::get_vm_stats().num_instanceof_fast_decision ++; + rth_type_test_update_stats(o->vt(), super); + } +} +#endif // VM_STATS + // Checkcast helper static NativeCodePtr rth_get_lil_checkcast(int* dyn_count) { @@ -386,33 +394,26 @@ static NativeCodePtr rth_get_lil_checkca if (!addr) { LilCodeStub* cs = lil_parse_code_stub("entry 0:rth:ref,pint:ref;"); - cs = rth_gen_lil_type_test(cs, RTTN_NullMember, RTTR_ThrowStub, NULL, dyn_count, rth_update_checkcast_stats); + +#ifdef VM_STATS + if (dyn_count) { + cs = lil_parse_onto_end(cs, "inc [%0i:pint]; in2out platform:void; call %1i;", dyn_count, rth_update_checkcast_stats); + assert(cs); + } +#endif + + cs = rth_gen_lil_type_test(cs, RTTN_NullMember, RTTR_ThrowStub, NULL); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_checkcast", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_checkcast", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } return addr; } -// Instanceof stats update -static void rth_update_instanceof_stats(ManagedObject* o, Class* super) -{ -#ifdef VM_STATS - vm_stats_total.num_instanceof++; - super->num_instanceof_slow++; - if (o == (ManagedObject*)Class::managed_null) { - vm_stats_total.num_instanceof_null++; - } else { - if (o->vt()->clss == super) - vm_stats_total.num_instanceof_equal_type ++; - if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_instanceof_fast_decision ++; - rth_type_test_update_stats(o->vt(), super); - } -#endif // VM_STATS -} - // Instanceof Helper static NativeCodePtr rth_get_lil_instanceof(int* dyn_count) { @@ -420,9 +421,17 @@ static NativeCodePtr rth_get_lil_instanc if (!addr) { LilCodeStub* cs = lil_parse_code_stub("entry 0:rth:ref,pint:g4;"); - cs = rth_gen_lil_type_test(cs, RTTN_NullNotMember, RTTR_ReturnOutcome, NULL, dyn_count, rth_update_instanceof_stats); +#ifdef VM_STATS + assert(dyn_count); + cs = lil_parse_onto_end(cs, "inc [%0i:pint]; in2out platform:void; call %1i;", dyn_count, rth_update_instanceof_stats); + assert(cs); +#endif + cs = rth_gen_lil_type_test(cs, RTTN_NullNotMember, RTTR_ReturnOutcome, NULL); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_instanceof", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_instanceof", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -437,7 +446,7 @@ static NativeCodePtr rth_get_lil_instanc static Class* rth_aastore(ManagedObject* elem, int idx, Vector_Handle array) { #ifdef VM_STATS - vm_stats_total.num_aastore ++; + VM_Statistics::get_vm_stats().num_aastore ++; #endif // VM_STATS Global_Env *env = VM_Global_State::loader_env; @@ -454,11 +463,11 @@ #endif // VM_STATS #ifdef VM_STATS VTable* vt = get_vector_vtable(array); if (vt == cached_object_array_vtable_ptr) - vm_stats_total.num_aastore_test_object_array++; + VM_Statistics::get_vm_stats().num_aastore_test_object_array++; if (elem->vt()->clss == array_class->array_element_class) - vm_stats_total.num_aastore_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_equal_type ++; if (array_class->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_fast_decision ++; #endif // VM_STATS if (class_is_subtype_fast(elem->vt(), array_class->array_element_class)) { STORE_REFERENCE((ManagedObject*)array, get_vector_element_address_ref(array, idx), (ManagedObject*)elem); @@ -468,7 +477,7 @@ #endif // VM_STATS } else { // elem is null. We don't have to check types for a null reference. We also don't have to record stores of null references. #ifdef VM_STATS - vm_stats_total.num_aastore_null ++; + VM_Statistics::get_vm_stats().num_aastore_null ++; #endif // VM_STATS if (VM_Global_State::loader_env->compress_references) { COMPRESSED_REFERENCE* elem_ptr = (COMPRESSED_REFERENCE*)get_vector_element_address_ref(array, idx); @@ -507,7 +516,10 @@ #endif p_aastore, lil_npc_to_fp(exn_get_rth_throw_lazy_trampoline())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_aastore", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_aastore", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -517,7 +529,7 @@ #endif static bool rth_aastore_test(ManagedObject* elem, Vector_Handle array) { #ifdef VM_STATS - vm_stats_total.num_aastore_test++; + VM_Statistics::get_vm_stats().num_aastore_test++; #endif // VM_STATS ManagedObject* null_ref = (ManagedObject*)Class::managed_null; @@ -526,7 +538,7 @@ #endif // VM_STATS } if (elem == null_ref) { #ifdef VM_STATS - vm_stats_total.num_aastore_test_null++; + VM_Statistics::get_vm_stats().num_aastore_test_null++; #endif // VM_STATS return true; } @@ -534,7 +546,7 @@ #endif // VM_STATS VTable* vt = get_vector_vtable(array); if (vt == cached_object_array_vtable_ptr) { #ifdef VM_STATS - vm_stats_total.num_aastore_test_object_array++; + VM_Statistics::get_vm_stats().num_aastore_test_object_array++; #endif // VM_STATS return true; } @@ -545,9 +557,9 @@ #endif // VM_STATS #ifdef VM_STATS if (elem->vt()->clss == array_class->array_element_class) - vm_stats_total.num_aastore_test_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_test_equal_type ++; if (array_class->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_test_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_test_fast_decision ++; #endif // VM_STATS return (class_is_subtype_fast(elem->vt(), array_class->array_element_class) ? true : false); } //rth_aastore_test @@ -572,7 +584,10 @@ #endif "ret;", p_aastore_test); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_aastore_test", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_aastore_test", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -592,7 +607,7 @@ static NativeCodePtr rth_get_lil_throw_l if (!addr) { void (*p_throw_linking_error)(Class_Handle ch, unsigned index, unsigned opcode) = - class_throw_linking_error; + vm_rt_class_throw_linking_error; LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:pint,g4,g4:void;"); assert(cs); if (dyn_count) { @@ -606,7 +621,10 @@ static NativeCodePtr rth_get_lil_throw_l "call.noret %0i;", p_throw_linking_error); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_throw_linking_exception", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_throw_linking_exception", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -625,26 +643,26 @@ static void* rth_get_interface_vtable(Ma assert(clss); unsigned num_intfc = clss->n_intfc_table_entries; #ifdef VM_STATS - vm_stats_total.num_invokeinterface_calls++; + VM_Statistics::get_vm_stats().num_invokeinterface_calls++; switch(num_intfc) { - case 1: vm_stats_total.num_invokeinterface_calls_size_1++; break; - case 2: vm_stats_total.num_invokeinterface_calls_size_2++; break; - default: vm_stats_total.num_invokeinterface_calls_size_many++; break; + case 1: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_1++; break; + case 2: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_2++; break; + default: VM_Statistics::get_vm_stats().num_invokeinterface_calls_size_many++; break; } - if(num_intfc > vm_stats_total.invokeinterface_calls_size_max) - vm_stats_total.invokeinterface_calls_size_max = num_intfc; + if(num_intfc > VM_Statistics::get_vm_stats().invokeinterface_calls_size_max) + VM_Statistics::get_vm_stats().invokeinterface_calls_size_max = num_intfc; #endif for(unsigned i = 0; i < num_intfc; i++) { Class* intfc = clss->intfc_table_descriptors[i]; if(intfc == iid) { #ifdef VM_STATS switch(i) { - case 0: vm_stats_total.num_invokeinterface_calls_searched_1++; break; - case 1: vm_stats_total.num_invokeinterface_calls_searched_2++; break; - default: vm_stats_total.num_invokeinterface_calls_searched_many++; break; + case 0: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_1++; break; + case 1: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_2++; break; + default: VM_Statistics::get_vm_stats().num_invokeinterface_calls_searched_many++; break; } - if(i > vm_stats_total.invokeinterface_calls_searched_max) - vm_stats_total.invokeinterface_calls_searched_max = i; + if(i > VM_Statistics::get_vm_stats().invokeinterface_calls_searched_max) + VM_Statistics::get_vm_stats().invokeinterface_calls_searched_max = i; #endif unsigned char **table = clss->vtable->intfc_table->entry[i].table; return (void *)table; @@ -679,7 +697,10 @@ static NativeCodePtr rth_get_lil_get_int "ret;", Class::managed_null, p_get_ivtable, lil_npc_to_fp(exn_get_rth_throw_incompatible_class_change_exception())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_get_interface_vtable", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_get_interface_vtable", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -693,13 +714,33 @@ static NativeCodePtr rth_get_lil_get_int static POINTER_SIZE_INT is_class_initialized(Class *clss) { #ifdef VM_STATS - vm_stats_total.num_is_class_initialized++; + VM_Statistics::get_vm_stats().num_is_class_initialized++; clss->num_class_init_checks++; #endif // VM_STATS assert(!hythread_is_suspend_enabled()); return clss->state == ST_Initialized; } //is_class_initialized +void vm_rt_class_initialize(Class *clss) +{ + ASSERT_THROW_AREA; + BEGIN_RAISE_AREA; + class_initialize(clss); + END_RAISE_AREA; + exn_rethrow_if_pending(); +} + +// It's a rutime helper. So exception throwed from it. +void vm_rt_class_throw_linking_error(Class_Handle ch, unsigned index, unsigned opcode) +{ + ASSERT_THROW_AREA; + BEGIN_RAISE_AREA; + class_throw_linking_error(ch, index, opcode); + END_RAISE_AREA; + exn_rethrow_if_pending(); +} + + // Initialise class helper static NativeCodePtr rth_get_lil_initialize_class(int* dyn_count) { @@ -708,13 +749,14 @@ static NativeCodePtr rth_get_lil_initial if (!addr) { POINTER_SIZE_INT (*p_is_inited)(Class*) = is_class_initialized; void (*p_init)(Class*) = class_initialize; - void (*p_rethrow)() = rethrow_current_thread_exception; + void (*p_rethrow)() = exn_rethrow; LilCodeStub* cs = lil_parse_code_stub("entry 0:rth:pint:void;"); assert(cs); - if (dyn_count) { - cs = lil_parse_onto_end(cs, "inc [%0i:pint];", dyn_count); - assert(cs); - } +#ifdef VM_STATS + assert(dyn_count); + cs = lil_parse_onto_end(cs, "inc [%0i:pint];", dyn_count); + assert(cs); +#endif cs = lil_parse_onto_end(cs, "in2out platform:pint;" "call %0i;" @@ -725,19 +767,26 @@ static NativeCodePtr rth_get_lil_initial "m2n_save_all;" "in2out platform:void;" "call %2i;" - "locals 1;" + "locals 2;" "l0 = ts;" - "ld l0, [l0 + %3i:ref];" - "jc l0 != 0,_exn_raised;" + "ld l1, [l0 + %3i:ref];" + "jc l1 != 0,_exn_raised;" + "ld l1, [l0 + %4i:ref];" + "jc l1 != 0,_exn_raised;" "pop_m2n;" "ret;" ":_exn_raised;" "out platform::void;" - "call.noret %4i;", + "call.noret %5i;", p_is_inited, FRAME_JNI, p_init, - OFFSET(VM_thread, p_exception_object), p_rethrow); + OFFSET(VM_thread, thread_exception.exc_object), + OFFSET(VM_thread, thread_exception.exc_class), + p_rethrow); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_get_initialize_class", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_get_initialize_class", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -780,7 +829,10 @@ static NativeCodePtr rth_get_lil_f2i(int "ret;", p_f2i); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_f2i", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_f2i", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -830,7 +882,10 @@ static NativeCodePtr rth_get_lil_f2l(int "ret;", p_f2l); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_f2l", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_f2l", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -872,7 +927,10 @@ static NativeCodePtr rth_get_lil_d2i(int "ret;", p_d2i); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_d2i", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_d2i", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -922,7 +980,10 @@ static NativeCodePtr rth_get_lil_d2l(int "ret;", p_d2l); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_d2l", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_d2l", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -952,7 +1013,10 @@ static NativeCodePtr rth_get_lil_lshl(in "ret;", p_lshl); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lshl", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lshl", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -982,7 +1046,10 @@ static NativeCodePtr rth_get_lil_lshr(in "ret;", p_lshr); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lshr", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lshr", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1012,7 +1079,10 @@ static NativeCodePtr rth_get_lil_lushr(i "ret;", p_lushr); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lushr", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lushr", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1042,7 +1112,10 @@ static NativeCodePtr rth_get_lil_lmul(in "ret;", p_lmul); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lmul", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lmul", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1076,7 +1149,10 @@ static NativeCodePtr rth_get_lil_lrem(in "tailcall %1i;", p_lrem, lil_npc_to_fp(exn_get_rth_throw_arithmetic())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lrem", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lrem", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1110,7 +1186,10 @@ static NativeCodePtr rth_get_lil_ldiv(in "tailcall %1i;", p_ldiv, lil_npc_to_fp(exn_get_rth_throw_arithmetic())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_ldiv", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_ldiv", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1144,7 +1223,10 @@ static NativeCodePtr rth_get_lil_ludiv(i "tailcall %1i;", p_ludiv, lil_npc_to_fp(exn_get_rth_throw_arithmetic())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_ludiv", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_ludiv", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1173,7 +1255,10 @@ static NativeCodePtr rth_get_lil_ldiv_co "ret;", divisor_offset, p_ldiv); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_ldiv_const", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_ldiv_const", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1202,7 +1287,10 @@ static NativeCodePtr rth_get_lil_lrem_co "ret;", divisor_offset, p_lrem); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_lrem_const", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_lrem_const", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1232,7 +1320,10 @@ static NativeCodePtr rth_get_lil_imul(in "ret;", p_imul); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_imul", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_imul", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1266,7 +1357,10 @@ static NativeCodePtr rth_get_lil_irem(in "tailcall %1i;", p_irem, lil_npc_to_fp(exn_get_rth_throw_arithmetic())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_irem", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_irem", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1300,7 +1394,10 @@ static NativeCodePtr rth_get_lil_idiv(in "tailcall %1i;", p_idiv, lil_npc_to_fp(exn_get_rth_throw_arithmetic())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_idiv", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_idiv", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1361,7 +1458,10 @@ static NativeCodePtr rth_get_lil_frem(in "ret;", p_frem); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_frem", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_frem", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1391,7 +1491,10 @@ static NativeCodePtr rth_get_lil_fdiv(in "ret;", p_fdiv); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_fdiv", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_fdiv", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1421,7 +1524,10 @@ static NativeCodePtr rth_get_lil_drem(in "ret;", p_drem); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_drem", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_drem", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1451,7 +1557,10 @@ static NativeCodePtr rth_get_lil_ddiv(in "ret;", p_ddiv); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_ddiv", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_ddiv", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } @@ -1479,7 +1588,10 @@ #ifdef VM_STATS "tailcall %1i;", dyncount, lil_npc_to_fp(stub)); assert(cs && lil_is_valid(cs)); - wrapper = LilCodeGenerator::get_platform()->compile(cs, name, dump_stubs); + wrapper = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(wrapper, name, lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); wrappers.add(stub, 0, wrapper); @@ -1509,7 +1621,10 @@ static NativeCodePtr rth_get_lil_gc_safe "ret;", hythread_safe_point_ptr); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_gc_safe_point", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_gc_safe_point", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -1533,8 +1648,10 @@ static NativeCodePtr rth_get_lil_gc_thre "ret;", thread_get_suspend_request_offset()); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, - "rth_get_lil_gc_thread_suspend_flag_ptr", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_get_lil_gc_thread_suspend_flag_ptr", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); */ //assert(0); @@ -1544,6 +1661,8 @@ static NativeCodePtr rth_get_lil_gc_thre static void * rth_resolve(Class_Handle klass, unsigned cp_idx, JavaByteCodes opcode) { + ASSERT_THROW_AREA; + Compilation_Handle comp_handle; comp_handle.env = VM_Global_State::loader_env; comp_handle.jit = NULL; @@ -1587,7 +1706,7 @@ static void * rth_resolve(Class_Handle k hythread_suspend_disable(); if (class_needs_initialization(that_class)) { assert(!exn_raised()); - class_initialize_ex(that_class); + vm_rt_class_initialize(that_class); } return ret; } @@ -1599,7 +1718,7 @@ static void * rth_resolve(Class_Handle k hythread_suspend_disable(); if (class_needs_initialization(that_class)) { assert(!exn_raised()); - class_initialize_ex(that_class); + vm_rt_class_initialize(that_class); } return ret; } @@ -1609,7 +1728,7 @@ static void * rth_resolve(Class_Handle k hythread_suspend_disable(); if (ret == NULL) { - class_throw_linking_error(klass, cp_idx, opcode); + vm_rt_class_throw_linking_error(klass, cp_idx, opcode); assert(false); // must be unreachanble } return ret; @@ -1636,16 +1755,19 @@ static NativeCodePtr rth_get_lil_resolve "ret;", (void*)&rth_resolve); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_resolve", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_resolve", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } static NativeCodePtr rth_get_lil_jvmti_method_enter_callback(int * dyn_count) { - static NativeCodePtr addr = NULL; - if (addr) { - return addr; - } + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } void (*jvmti_method_enter_callback_ptr)(Method_Handle) = jvmti_method_enter_callback; LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:pint:void;"); assert(cs); @@ -1661,7 +1783,10 @@ static NativeCodePtr rth_get_lil_jvmti_m "ret;", jvmti_method_enter_callback_ptr); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_jvmti_method_enter_callback", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_jvmti_method_enter_callback", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -1688,30 +1813,120 @@ static NativeCodePtr rth_get_lil_jvmti_m "ret;", jvmti_method_exit_callback_ptr); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_jvmti_method_exit_callback", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_jvmti_method_exit_callback", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } +static NativeCodePtr rth_get_lil_jvmti_field_access_callback(int * dyn_count) { + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + void (*jvmti_field_access_callback_ptr)(Field_Handle, Method_Handle, + jlocation, jobject*) = jvmti_field_access_callback; + + LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:pint,pint,g8,pint:void;"); + assert(cs); + if (dyn_count) { + cs = lil_parse_onto_end(cs, "inc [%0i:pint];", dyn_count); + assert(cs); + } + cs = lil_parse_onto_end(cs, + "push_m2n 0, 0;" + "in2out platform:void;" + "call %0i;" + "pop_m2n;" + "ret;", + jvmti_field_access_callback_ptr); + assert(cs && lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_jvmti_field_access_callback", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; + + //static NativeCodePtr addr = NULL; + //if (addr) { + // return addr; + // } + //LilCodeStub* cs = lil_parse_code_stub( + // "entry 0:managed:pint,pint,g8,pint:void;" + // "push_m2n 0, 0;" + // "in2out platform:void;" + // "call %0i;" + // "pop_m2n;" + // "ret;", + // jvmti_field_access_callback); + //assert(cs && lil_is_valid(cs)); + //addr = LilCodeGenerator::get_platform()->compile(cs, "rth_jvmti_field_access_callback", dump_stubs); + //lil_free_code_stub(cs); + //return addr; +} + +static NativeCodePtr rth_get_lil_jvmti_field_modification_callback(int * dyn_count) { + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } +void (*jvmti_field_modification_callback_ptr)(Field_Handle, Method_Handle, + jlocation, jobject*, jvalue*) = jvmti_field_modification_callback; + LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:pint,pint,g8,pint,pint:void;"); + assert(cs); + if (dyn_count) { + cs = lil_parse_onto_end(cs, "inc [%0i:pint];", dyn_count); + assert(cs); + } + cs = lil_parse_onto_end(cs, + "push_m2n 0, 0;" + "in2out platform:void;" + "call %0i;" + "pop_m2n;" + "ret;", + jvmti_field_modification_callback_ptr); + assert(cs && lil_is_valid(cs)); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "rth_jvmti_field_modification_callback", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; + + //static NativeCodePtr addr = NULL; + //if (addr) { + // return addr; + //} + //LilCodeStub* cs = lil_parse_code_stub( + // "entry 0:managed:pint,pint,g8,pint,pint:void;" + // "push_m2n 0, 0;" + // "in2out platform:void;" + // "call %0i;" + // "pop_m2n;" + // "ret;", + // jvmti_field_modification_callback); + //assert(cs && lil_is_valid(cs)); + //addr = LilCodeGenerator::get_platform()->compile(cs, "rth_jvmti_field_modification_callback", dump_stubs); + //lil_free_code_stub(cs); + //return addr; +} NativeCodePtr rth_get_lil_helper(VM_RT_SUPPORT f) { int* dyn_count = NULL; #ifdef VM_STATS - dyn_count = vm_stats_total.rt_function_calls.lookup_or_add((void*)f, 0, NULL); + dyn_count = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)f, 0, NULL); #endif switch(f) { - // Object creation - case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: - return NULL; - case VM_RT_NEW_VECTOR_USING_VTABLE: - return NULL; case VM_RT_MULTIANEWARRAY_RESOLVED: return rth_get_lil_multianewarray(dyn_count); case VM_RT_LDC_STRING: return rth_get_lil_ldc_ref(dyn_count); - // Exceptions + // Exceptions case VM_RT_THROW: case VM_RT_THROW_SET_STACK_TRACE: return rth_wrap_exn_throw(dyn_count, "rth_throw", exn_get_rth_throw()); @@ -1727,18 +1942,7 @@ #endif return rth_wrap_exn_throw(dyn_count, "rth_throw_array_store", exn_get_rth_throw_array_store()); case VM_RT_THROW_LINKING_EXCEPTION: return rth_get_lil_throw_linking_exception(dyn_count); - // Synchronisation - case VM_RT_MONITOR_ENTER: - case VM_RT_MONITOR_ENTER_NO_EXC: - return NULL; - case VM_RT_MONITOR_EXIT: - case VM_RT_MONITOR_EXIT_NON_NULL: - return NULL; - case VM_RT_MONITOR_ENTER_STATIC: - return NULL; - case VM_RT_MONITOR_EXIT_STATIC: - return NULL; - // Type tests + // Type tests case VM_RT_CHECKCAST: return rth_get_lil_checkcast(dyn_count); case VM_RT_INSTANCEOF: @@ -1747,23 +1951,25 @@ #endif return rth_get_lil_aastore(dyn_count); case VM_RT_AASTORE_TEST: return rth_get_lil_aastore_test(dyn_count); - // Misc + // Misc case VM_RT_GET_INTERFACE_VTABLE_VER0: return rth_get_lil_get_interface_vtable(dyn_count); case VM_RT_INITIALIZE_CLASS: return rth_get_lil_initialize_class(dyn_count); - case VM_RT_GC_HEAP_WRITE_REF: - return NULL; case VM_RT_GC_SAFE_POINT: return rth_get_lil_gc_safe_point(dyn_count); case VM_RT_GC_GET_THREAD_SUSPEND_FLAG_PTR: return rth_get_lil_gc_thread_suspend_flag_ptr(dyn_count); - // JVMTI + // JVMTI case VM_RT_JVMTI_METHOD_ENTER_CALLBACK: return rth_get_lil_jvmti_method_enter_callback(dyn_count); case VM_RT_JVMTI_METHOD_EXIT_CALLBACK: return rth_get_lil_jvmti_method_exit_callback(dyn_count); - // Non-VM + case VM_RT_JVMTI_FIELD_ACCESS_CALLBACK: + return rth_get_lil_jvmti_field_access_callback(dyn_count); + case VM_RT_JVMTI_FIELD_MODIFICATION_CALLBACK: + return rth_get_lil_jvmti_field_modification_callback(dyn_count); + // Non-VM case VM_RT_F2I: return rth_get_lil_f2i(dyn_count); case VM_RT_F2L: @@ -1807,12 +2013,9 @@ #endif return rth_get_lil_drem(dyn_count); case VM_RT_DDIV: return rth_get_lil_ddiv(dyn_count); - case VM_RT_CHAR_ARRAYCOPY_NO_EXC: - return NULL; case VM_RT_RESOLVE: return rth_get_lil_resolve(dyn_count); default: - ABORT("Unexpected helper id"); return NULL; } } @@ -1827,37 +2030,42 @@ #endif // begin Java object allocation /** - * intermediary function for allocation slow path to check - * for out of memory conditions. Throws OutOfMemoryError - * if allocation function returns null. + * Intermediary function called from rintime helpers for + * slow path allocation to check for out of memory conditions. + * Throws OutOfMemoryError if allocation function returns null. */ void *vm_malloc_with_thread_pointer( unsigned size, Allocation_Handle ah, void *tp) { + ASSERT_THROW_AREA; assert(!hythread_is_suspend_enabled()); void *result = gc_alloc(size,ah,tp); if (!result) { - exn_throw(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_throw_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return 0; // whether this return is reached or not is solved via is_unwindable state } return result; } - - -// This function is deprecated. -ManagedObject *class_alloc_new_object_or_null(Class * UNREF c) +ManagedObject* vm_rt_class_alloc_new_object(Class *c) { - return NULL; -} //class_alloc_new_object_or_null + ASSERT_THROW_AREA; + ManagedObject* result; + BEGIN_RAISE_AREA; + result = class_alloc_new_object(c); + END_RAISE_AREA; + exn_rethrow_if_pending(); + return result; +} ManagedObject *class_alloc_new_object(Class *c) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); //hythread_suspend_disable(); assert(strcmp(c->name->bytes, "java/lang/Class")); #ifdef VM_STATS - vm_stats_total.num_class_alloc_new_object++; + VM_Statistics::get_vm_stats().num_class_alloc_new_object++; c->num_allocations++; c->num_bytes_allocated += get_instance_data_size(c); #endif //VM_STATS @@ -1865,7 +2073,7 @@ #endif //VM_STATS gc_alloc(c->instance_data_size, c->allocation_handle, vm_get_gc_thread_local()); if (!o) { - exn_throw( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); //hythread_suspend_enable(); return 0; // whether this return is reached or not is solved via is_unwindable state @@ -1874,13 +2082,13 @@ #endif //VM_STATS return o; } //class_alloc_new_object - ManagedObject *class_alloc_new_object_using_vtable(VTable *vtable) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); assert(strcmp(vtable->clss->name->bytes, "java/lang/Class")); #ifdef VM_STATS - vm_stats_total.num_class_alloc_new_object++; + VM_Statistics::get_vm_stats().num_class_alloc_new_object++; vtable->clss->num_allocations++; vtable->clss->num_bytes_allocated += vtable->allocated_size; #endif //VM_STATS @@ -1889,28 +2097,24 @@ #endif //VM_STATS gc_alloc(vtable->allocated_size, vtable->clss->allocation_handle, vm_get_gc_thread_local()); if (!o) { - exn_throw( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); return NULL; // reached by interpreter and from JNI } return o; } //class_alloc_new_object_using_vtable - - ManagedObject *class_alloc_new_object_and_run_default_constructor(Class *clss) { return class_alloc_new_object_and_run_constructor(clss, 0, 0); } //class_alloc_new_object_and_run_default_constructor - - - ManagedObject * class_alloc_new_object_and_run_constructor(Class *clss, Method *constructor, uint8 *constructor_args) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); assert(strcmp(clss->name->bytes, "java/lang/Class")); @@ -1918,7 +2122,7 @@ class_alloc_new_object_and_run_construct obj->object = (ManagedObject*) gc_alloc(clss->instance_data_size, clss->allocation_handle, vm_get_gc_thread_local()); if (!obj->object) { - exn_throw_only( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); return 0; // should never be reached } @@ -2020,33 +2224,33 @@ #endif //VM_STATS static void update_general_type_checking_stats(VTable *sub, Class *super) { #ifdef VM_STATS - vm_stats_total.num_type_checks ++; + VM_Statistics::get_vm_stats().num_type_checks ++; if (sub->clss == super) - vm_stats_total.num_type_checks_equal_type ++; + VM_Statistics::get_vm_stats().num_type_checks_equal_type ++; if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_type_checks_fast_decision ++; + VM_Statistics::get_vm_stats().num_type_checks_fast_decision ++; else if (super->is_array) - vm_stats_total.num_type_checks_super_is_array ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_array ++; else if (class_is_interface(super)) - vm_stats_total.num_type_checks_super_is_interface ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_interface ++; else if (super->depth >= vm_max_fast_instanceof_depth()) - vm_stats_total.num_type_checks_super_is_too_deep ++; + VM_Statistics::get_vm_stats().num_type_checks_super_is_too_deep ++; #endif // VM_STATS } void vm_instanceof_update_stats(ManagedObject *obj, Class *super) { #ifdef VM_STATS - vm_stats_total.num_instanceof++; + VM_Statistics::get_vm_stats().num_instanceof++; super->num_instanceof_slow++; if (obj == (ManagedObject *)Class::managed_null) - vm_stats_total.num_instanceof_null++; + VM_Statistics::get_vm_stats().num_instanceof_null++; else { if (obj->vt()->clss == super) - vm_stats_total.num_instanceof_equal_type ++; + VM_Statistics::get_vm_stats().num_instanceof_equal_type ++; if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_instanceof_fast_decision ++; + VM_Statistics::get_vm_stats().num_instanceof_fast_decision ++; update_general_type_checking_stats(obj->vt(), super); } #endif @@ -2055,15 +2259,15 @@ #endif void vm_checkcast_update_stats(ManagedObject *obj, Class *super) { #ifdef VM_STATS - vm_stats_total.num_checkcast ++; + VM_Statistics::get_vm_stats().num_checkcast ++; if (obj == (ManagedObject *)Class::managed_null) - vm_stats_total.num_checkcast_null++; + VM_Statistics::get_vm_stats().num_checkcast_null++; else { if (obj->vt()->clss == super) - vm_stats_total.num_checkcast_equal_type ++; + VM_Statistics::get_vm_stats().num_checkcast_equal_type ++; if (super->is_suitable_for_fast_instanceof) - vm_stats_total.num_checkcast_fast_decision ++; + VM_Statistics::get_vm_stats().num_checkcast_fast_decision ++; update_general_type_checking_stats(obj->vt(), super); } #endif @@ -2406,23 +2610,23 @@ LilCodeStub *gen_lil_typecheck_stub_spec void vm_aastore_test_update_stats(ManagedObject *elem, Vector_Handle array) { #ifdef VM_STATS - vm_stats_total.num_aastore_test++; + VM_Statistics::get_vm_stats().num_aastore_test++; if (elem == (ManagedObject *)Class::managed_null) { - vm_stats_total.num_aastore_test_null ++; + VM_Statistics::get_vm_stats().num_aastore_test_null ++; return; } VTable *vt = get_vector_vtable(array); if (vt == cached_object_array_vtable_ptr) { - vm_stats_total.num_aastore_test_object_array++; + VM_Statistics::get_vm_stats().num_aastore_test_object_array++; return; } Class *array_class = vt->clss; if (elem->vt()->clss == array_class->array_element_class) - vm_stats_total.num_aastore_test_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_test_equal_type ++; if (array_class->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_test_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_test_fast_decision ++; update_general_type_checking_stats(elem->vt(), array_class->array_element_class); #endif } @@ -2525,23 +2729,23 @@ int __stdcall vm_instanceof(ManagedObjec assert(!hythread_is_suspend_enabled()); #ifdef VM_STATS - vm_stats_total.num_instanceof++; + VM_Statistics::get_vm_stats().num_instanceof++; c->num_instanceof_slow++; #endif ManagedObject *null_ref = (ManagedObject *)Class::managed_null; if (obj == null_ref) { #ifdef VM_STATS - vm_stats_total.num_instanceof_null++; + VM_Statistics::get_vm_stats().num_instanceof_null++; #endif return 0; } assert(obj->vt()); #ifdef VM_STATS if (obj->vt()->clss == c) - vm_stats_total.num_instanceof_equal_type ++; + VM_Statistics::get_vm_stats().num_instanceof_equal_type ++; if (c->is_suitable_for_fast_instanceof) - vm_stats_total.num_instanceof_fast_decision ++; + VM_Statistics::get_vm_stats().num_instanceof_fast_decision ++; #endif // VM_STATS return class_is_subtype_fast(obj->vt(), c); } //vm_instanceof @@ -2562,7 +2766,7 @@ vm_aastore_test(ManagedObject *elem, Vector_Handle array) { #ifdef VM_STATS - vm_stats_total.num_aastore_test++; + VM_Statistics::get_vm_stats().num_aastore_test++; #endif // VM_STATS ManagedObject *null_ref = (ManagedObject *)Class::managed_null; @@ -2571,7 +2775,7 @@ #endif // VM_STATS } if (elem == null_ref) { #ifdef VM_STATS - vm_stats_total.num_aastore_test_null++; + VM_Statistics::get_vm_stats().num_aastore_test_null++; #endif // VM_STATS return 1; } @@ -2579,7 +2783,7 @@ #endif // VM_STATS VTable *vt = get_vector_vtable(array); if (vt == cached_object_array_vtable_ptr) { #ifdef VM_STATS - vm_stats_total.num_aastore_test_object_array++; + VM_Statistics::get_vm_stats().num_aastore_test_object_array++; #endif // VM_STATS return 1; } @@ -2590,9 +2794,9 @@ #endif // VM_STATS #ifdef VM_STATS if (elem->vt()->clss == array_class->array_element_class) - vm_stats_total.num_aastore_test_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_test_equal_type ++; if (array_class->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_test_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_test_fast_decision ++; #endif // VM_STATS return class_is_subtype_fast(elem->vt(), array_class->array_element_class); } //vm_aastore_test @@ -2604,7 +2808,7 @@ void * __stdcall vm_rt_aastore(ManagedObject *elem, int idx, Vector_Handle array) { #ifdef VM_STATS - vm_stats_total.num_aastore ++; + VM_Statistics::get_vm_stats().num_aastore ++; #endif // VM_STATS Global_Env *env = VM_Global_State::loader_env; @@ -2618,11 +2822,11 @@ #endif // VM_STATS assert(array_class); assert(array_class->is_array); #ifdef VM_STATS - // XXX - Should update vm_stats_total.num_aastore_object_array + // XXX - Should update VM_Statistics::get_vm_stats().num_aastore_object_array if (elem->vt()->clss == array_class->array_element_class) - vm_stats_total.num_aastore_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_equal_type ++; if (array_class->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_fast_decision ++; #endif // VM_STATS if (class_is_subtype_fast(elem->vt(), array_class->array_element_class)) { STORE_REFERENCE((ManagedObject *)array, get_vector_element_address_ref(array, idx), (ManagedObject *)elem); @@ -2631,7 +2835,7 @@ #endif // VM_STATS } } else { #ifdef VM_STATS - vm_stats_total.num_aastore_null ++; + VM_Statistics::get_vm_stats().num_aastore_null ++; #endif // VM_STATS // elem is null. We don't have to check types for a null reference. We also don't have to record stores of null references. if (VM_Global_State::loader_env->compress_references) { @@ -2680,36 +2884,42 @@ VMEXPORT void * vm_create_helper_for_fun { static const char * lil_stub = "entry 0:stdcall:pint:pint;" // the single argument is 'void*' - "push_m2n 0, 0;" // create m2n frame + "push_m2n 0, %0i;" // create m2n frame "out stdcall::void;" - "call %0i;" // call hythread_suspend_enable() + "call %1i;" // call hythread_suspend_enable() "in2out stdcall:pint;" // reloads input arg into output - "call %1i;" // call the foo - "locals 2;" // + "call %2i;" // call the foo + "locals 3;" // "l0 = r;" // save result "out stdcall::void;" - "call %2i;" // call hythread_suspend_disable() + "call %3i;" // call hythread_suspend_disable() "l1 = ts;" - "ld l1, [l1 + %3i:ref];" - "jc l1 != 0,_exn_raised;" // test whether an exception happened + "ld l2, [l1 + %4i:ref];" + "jc l2 != 0,_exn_raised;" // test whether an exception happened + "ld l2, [l1 + %5i:ref];" + "jc l2 != 0,_exn_raised;" // test whether an exception happened "pop_m2n;" // pop out m2n frame "r = l0;" // no exceptions pending, restore .. "ret;" // ret value and exit ":_exn_raised;" // "out platform::void;" // - "call.noret %4i;"; // re-throw exception + "call.noret %6i;"; // re-throw exception - void * fptr_rethrow = (void*)&rethrow_current_thread_exception; + void * fptr_rethrow = (void*)&exn_rethrow; void * fptr_suspend_enable = (void*)&hythread_suspend_enable; void * fptr_suspend_disable = (void*)&hythread_suspend_disable; LilCodeStub* cs = lil_parse_code_stub( - lil_stub, + lil_stub, FRAME_COMPILATION, fptr_suspend_enable, (void*)fptr, fptr_suspend_disable, - OFFSET(VM_thread, p_exception_object), fptr_rethrow); + OFFSET(VM_thread, thread_exception.exc_object), + OFFSET(VM_thread, thread_exception.exc_class), + fptr_rethrow); assert(lil_is_valid(cs)); - void * addr = LilCodeGenerator::get_platform()->compile(cs, - "generic_wrapper", dump_stubs); + void * addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "generic_wrapper", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; }; diff --git vm/vmcore/src/jit/native_overrides.cpp vm/vmcore/src/jit/native_overrides.cpp index 3ef09e9..2dd0946 100644 --- vm/vmcore/src/jit/native_overrides.cpp +++ vm/vmcore/src/jit/native_overrides.cpp @@ -50,10 +50,7 @@ #include "platform_core_natives.h" // *** This is for the newInstance override #include "exceptions.h" -#ifndef NDEBUG #include "dump.h" -extern bool dump_stubs; -#endif int readinternal_override_lil(JNIEnv *jenv, Java_java_io_FileInputStream * UNREF pThis, @@ -301,10 +298,9 @@ static NativeCodePtr fast_array_copy() addr = (NativeCodePtr)stub; assert(stub_size >= (unsigned)(s-stub)); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "stub.fast_array_copy", s - stub); -#endif + + DUMP_STUB(stub, "stub.fast_array_copy", s - stub); + return addr; } diff --git vm/vmcore/src/jni/jni.cpp vm/vmcore/src/jni/jni.cpp index c66db9f..9488261 100644 --- vm/vmcore/src/jni/jni.cpp +++ vm/vmcore/src/jni/jni.cpp @@ -27,7 +27,6 @@ #include "lock_manager.h" #include "Class.h" #include "classloader.h" #include "environment.h" -#include "exception.h" #include "object_handles.h" #include "open/types.h" #include "open/vm_util.h" @@ -381,7 +380,57 @@ jclass JNICALL DefineClass(JNIEnv *jenv, Global_Env* env = VM_Global_State::loader_env; ClassLoader* cl; if (loader != NULL) + { + if(name) + { + jclass clazz = GetObjectClass(jenv, loader); + jmethodID meth_id = GetMethodID(jenv, clazz, "findLoadedClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + if (NULL == meth_id) + { + jobject exn = exn_get(); + tmn_suspend_disable(); + Class *exn_class = exn->object->vt()->clss; + assert(exn_class); + bool f = exn_class != env->java_lang_OutOfMemoryError_Class; + tmn_suspend_enable(); + if(f) + DIE("Fatal: an access to findLoadedClass method of java.lang.Class is not provided"); + // OutOfMemoryError should be rethrown after this JNI method exits + return 0; + } + jstring str = NewStringUTF(jenv, name); + if (NULL == str) + { + // the only OutOfMemoryError can be a reason to be here; it will be rethrown after this JNI method exits + return 0; + } + jobject obj = CallObjectMethod(jenv, loader, meth_id, str); + if(obj) + { + jthrowable exn; + if(exn_raised()) + { + // pending exception will be rethrown after the JNI method exits + return 0; + } + else + { + static const char* mess_templ = "duplicate class definition: "; + static unsigned mess_templ_len = strlen(mess_templ); + unsigned mess_size = mess_templ_len + strlen(name) + 1; // 1 is for trailing '\0' + char* err_mess = (char*)STD_ALLOCA(mess_size); + sprintf(err_mess, "%s%s", mess_templ, name); + exn = exn_create("java/lang/LinkageError", err_mess); + } + + assert(exn); + jint UNUSED ok = Throw(jenv, exn); + assert(ok == 0); + return 0; + } + } cl = class_loader_lookup(loader); + } else cl = env->bootstrap_class_loader; @@ -410,21 +459,15 @@ jclass JNICALL DefineClass(JNIEnv *jenv, } else { - jthrowable exn; - if(exn_raised()) - { - exn = exn_get(); - exn_clear(); + if (exn_raised()) { + return 0; + } else if(res_name) { + jthrowable exn = (jthrowable)class_get_error(cl, res_name->bytes); + exn_raise_object(exn); + } else { + exn_raise_by_name("java/lang/LinkageError", + "defineClass failed for unnamed class", NULL); } - else if(res_name) - exn = (jthrowable)class_get_error(cl, res_name->bytes); - else - exn = exn_create("java/lang/LinkageError", - "defineClass failed for unnamed class"); - - assert(exn); - jint UNUSED ok = Throw(jenv, exn); - assert(ok == 0); return 0; } } //DefineClass @@ -438,7 +481,9 @@ jclass JNICALL FindClass(JNIEnv* env_ext char *ch = strchr(name, '.'); if (NULL != ch) { - ThrowNew_Quick(env_ext, "java/lang/NoClassDefFoundError", name); + ThrowNew_Quick(env_ext, + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + name); return NULL; } @@ -491,9 +536,7 @@ jint JNICALL Throw(JNIEnv * UNREF env, j TRACE2("jni", "Throw called"); assert(hythread_is_suspend_enabled()); if(obj) { - tmn_suspend_disable(); //---------------------------------v - set_current_thread_exception(((ObjectHandle)obj)->object); - tmn_suspend_enable(); //---------------------------------^ + exn_raise_object(obj); return 0; } else { return -1; @@ -520,12 +563,7 @@ jint JNICALL ThrowNew(JNIEnv *env, jclas jobject obj = NewObjectA(env, clazz, init_id, args); env->DeleteLocalRef(str); if(obj && !ExceptionOccurred(env)) { - tmn_suspend_disable(); //---------------------------------v - - ObjectHandle h = (ObjectHandle)obj; - set_current_thread_exception(h->object); - - tmn_suspend_enable(); //---------------------------------^ + exn_raise_object(obj); return 0; } else { return -1; @@ -544,20 +582,21 @@ jint JNICALL ThrowNew_Quick(JNIEnv *env, return result; } // ThrowNew_Quick +//FIXME LAZY EXCEPTION (2006.05.15) +// chacks usage of this function and replace by lazy jthrowable JNICALL ExceptionOccurred(JNIEnv * UNREF env) { TRACE2("jni", "ExceptionOccurred called"); assert(hythread_is_suspend_enabled()); #ifdef _DEBUG tmn_suspend_disable(); - ManagedObject *obj = get_current_thread_exception(); - if (NULL == obj) + if (!exn_raised()) { TRACE2("jni", "Exception occured, no exception"); } else { - TRACE2("jni", "Exception occured, class = " << obj->vt()->clss->name->bytes); + TRACE2("jni", "Exception occured, class = " << exn_get_name()); } tmn_suspend_enable(); #endif @@ -575,10 +614,8 @@ void JNICALL ExceptionDescribe(JNIEnv * assert(hythread_is_suspend_enabled()); if (exn_raised()) { tmn_suspend_disable(); //---------------------------------v - ManagedObject* exn = get_current_thread_exception(); - const char *name = exn->vt()->clss->name->bytes; - fprintf(stderr, "JNI.ExceptionDescribe: %s:\n", name); - exn_print_stack_trace(stderr, exn); + fprintf(stderr, "JNI.ExceptionDescribe: %s:\n", exn_get_name()); + exn_print_stack_trace(stderr, exn_get()); tmn_suspend_enable(); //---------------------------------^ } } //ExceptionDescribe @@ -589,17 +626,16 @@ void JNICALL ExceptionClear(JNIEnv * UNR assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); #ifdef _DEBUG - ManagedObject *obj = get_current_thread_exception(); - if (NULL == obj) + if (!exn_raised()) { TRACE2("jni", "Exception clear, no exception"); } else { - TRACE2("jni", "Exception clear, class = " << obj->vt()->clss->name->bytes); + TRACE2("jni", "Exception clear, class = " << exn_get_name()); } #endif - clear_current_thread_exception(); + exn_clear(); tmn_suspend_enable(); } //ExceptionClear @@ -660,7 +696,7 @@ jobject JNICALL NewLocalRef(JNIEnv *env, if (NULL == h) { tmn_suspend_enable(); - exn_raise_only( + exn_raise_object( (jthrowable)(((JNIEnv_Internal*)env)->vm->vm_env->java_lang_OutOfMemoryError)); return NULL; } @@ -1108,15 +1144,13 @@ VMEXPORT jmethodID JNICALL FromReflected if (clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class) { - static Method* m = class_lookup_method(clss, "getHandle", "()Ljava/lang/Object;"); - jobject handle = CallObjectMethodA(env, method, (jmethodID)m, 0); - return (jmethodID) reflection_jobject_to_Class_Member(handle, clss); + static jmethodID m = (jmethodID)class_lookup_method(clss, "getId", "()J"); + return (jmethodID) ((POINTER_SIZE_INT) CallLongMethodA(env, method, m, 0)); } else if (clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class) { - static Method* m = class_lookup_method(clss, "getHandle", "()Ljava/lang/Object;"); - jobject handle = CallObjectMethodA(env, method, (jmethodID)m, 0); - return (jmethodID) reflection_jobject_to_Class_Member(handle, clss); + static jmethodID m = (jmethodID)class_lookup_method(clss, "getId", "()J"); + return (jmethodID) ((POINTER_SIZE_INT) CallLongMethodA(env, method, m, 0)); } else return NULL; @@ -1129,9 +1163,8 @@ VMEXPORT jfieldID JNICALL FromReflectedF if (clss == VM_Global_State::loader_env->java_lang_reflect_Field_Class) { - static Method* m = class_lookup_method(clss, "getHandle", "()Ljava/lang/Object;"); - jobject handle = CallObjectMethodA(env, field, (jmethodID)m, 0); - return (jfieldID) reflection_jobject_to_Class_Member(handle, clss); + static jmethodID m = (jmethodID)class_lookup_method(clss, "getId", "()J"); + return (jfieldID) ((POINTER_SIZE_INT) CallLongMethodA(env, field, m, 0)); } else return NULL; @@ -1351,15 +1384,12 @@ jdouble gc_double_NEGATIVE_INFINITY = 0; static void check_for_unexpected_exception(){ assert(hythread_is_suspend_enabled()); - tmn_suspend_disable(); - ManagedObject * exc; - if ((exc = get_current_thread_exception())) { + if (exn_raised()) { fprintf(stderr, "Error initializing java machine\n"); fprintf(stderr, "Uncaught and unexpected exception\n"); - print_uncaught_exception_message(stderr, "static initializing", exc); + print_uncaught_exception_message(stderr, "static initializing", exn_get()); vm_exit(1); } - tmn_suspend_enable(); } void global_object_handles_init(){ @@ -1455,7 +1485,7 @@ void global_object_handles_init(){ #ifdef USE_NATIVE_ISARRAY field_name = env->string_pool.lookup("isArray"); field_descr = env->string_pool.lookup("()Z"); - gsig_ClassisArray = env->sig_table.lookup(field_name, field_descr); + //gsig_ClassisArray = env->sig_table.lookup(field_name, field_descr); #endif //#ifndef USE_NATIVE_ISARRAY assert(hythread_is_suspend_enabled()); } diff --git vm/vmcore/src/jni/jni_array.cpp vm/vmcore/src/jni/jni_array.cpp index faeb54a..7ef75da 100644 --- vm/vmcore/src/jni/jni_array.cpp +++ vm/vmcore/src/jni/jni_array.cpp @@ -64,6 +64,7 @@ jarray JNICALL NewObjectArray(JNIEnv * U jclass elementClass, jobject initialElement) { + ASSERT_RAISE_AREA; TRACE2("jni", "NewObjectArray called"); assert(hythread_is_suspend_enabled()); ObjectHandle elem_handle = (ObjectHandle)initialElement; diff --git vm/vmcore/src/jni/jni_field.cpp vm/vmcore/src/jni/jni_field.cpp index 0684979..5ec5053 100644 --- vm/vmcore/src/jni/jni_field.cpp +++ vm/vmcore/src/jni/jni_field.cpp @@ -36,24 +36,6 @@ #include "ini.h" #include "exceptions.h" -static bool ensure_initialised(JNIEnv* env, Class* clss) -{ - assert(hythread_is_suspend_enabled()); - if(clss->state != ST_Initialized) { - class_initialize_from_jni(clss); - if(clss->state == ST_Error) { - if (!exn_raised()) // If exception is already raised, no need to - // throw new one, just return instead - { - env->Throw(class_get_error_cause(clss)); - } - return false; - } - } - return true; -} - - jfieldID JNICALL GetFieldID(JNIEnv *env, jclass clazz, const char *name, diff --git vm/vmcore/src/jni/jni_method.cpp vm/vmcore/src/jni/jni_method.cpp index 60843fd..b78fc16 100644 --- vm/vmcore/src/jni/jni_method.cpp +++ vm/vmcore/src/jni/jni_method.cpp @@ -38,25 +38,6 @@ #include "vm_threads.h" #include "ini.h" #include "nogc.h" -static bool ensure_initialised(JNIEnv* env, Class* clss) -{ - assert(hythread_is_suspend_enabled()); - if(clss->state != ST_Initialized) { - class_initialize_from_jni(clss); - if(clss->state == ST_Error) { - if (!exn_raised()) // If exception is already raised, no need to - // throw new one, just return instead - { - env->Throw(class_get_error_cause(clss)); - } - return false; - } - } - return true; -} - - - jmethodID JNICALL GetMethodID(JNIEnv *env, jclass clazz, diff --git vm/vmcore/src/jni/jni_utils.cpp vm/vmcore/src/jni/jni_utils.cpp index 08cedb2..3dc9dab 100644 --- vm/vmcore/src/jni/jni_utils.cpp +++ vm/vmcore/src/jni/jni_utils.cpp @@ -41,7 +41,6 @@ #include "nogc.h" #include "m2n.h" -#include "exception.h" #include "stack_trace.h" Class_Handle jni_get_class_handle(JNIEnv* UNREF jenv, jclass clazz) @@ -59,15 +58,15 @@ jclass jni_class_from_handle(JNIEnv* UNR jobject jni_class_loader_from_handle(JNIEnv*, ClassLoaderHandle clh) { if (!clh) return NULL; - tmn_suspend_disable(); + hythread_suspend_disable(); ManagedObject* obj = clh->GetLoader(); if( !obj ) { - tmn_suspend_enable(); + hythread_suspend_enable(); return NULL; } ObjectHandle res = oh_allocate_local_handle(); res->object = obj; - tmn_suspend_enable(); + hythread_suspend_enable(); return (jobject)res; } @@ -77,9 +76,9 @@ ClassLoaderHandle class_loader_lookup(jo ObjectHandle h = (ObjectHandle)loader; - tmn_suspend_disable(); //---------------------------------v + hythread_suspend_disable(); //---------------------------------v ClassLoader* cl = ClassLoader::LookupLoader(h->object); - tmn_suspend_enable(); //---------------------------------^ + hythread_suspend_enable(); //---------------------------------^ return cl; } //class_loader_lookup @@ -95,9 +94,9 @@ ClassLoaderHandle class_loader_find_if_e { ObjectHandle h = (ObjectHandle)loader; - tmn_suspend_disable(); //---------------------------------v + hythread_suspend_disable(); //---------------------------------v ClassLoader* cl = ClassLoader::FindByObject(h->object); - tmn_suspend_enable(); //---------------------------------^ + hythread_suspend_enable(); //---------------------------------^ return cl; } //class_loader_find_if_exists @@ -251,7 +250,7 @@ char* ParameterTypesToMethodSignature (J if (NULL == sig) { //throw_exception_from_jni (env, "java/lang/OutOfMemoryError", name); - exn_raise_only(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return (char *)0; } @@ -597,11 +596,11 @@ jboolean IsNullRef(jobject jobj) ObjectHandle h = (ObjectHandle)jobj; - tmn_suspend_disable(); //---------------------------------v + hythread_suspend_disable(); //---------------------------------v jboolean ret = (h->object == NULL) ? true : false; - tmn_suspend_enable(); //---------------------------------^ + hythread_suspend_enable(); //---------------------------------^ return ret; } @@ -652,13 +651,13 @@ void throw_exception_from_jni(JNIEnv *je void array_copy_jni(JNIEnv* jenv, jobject src, jint src_off, jobject dst, jint dst_off, jint count) { ArrayCopyResult res; - tmn_suspend_disable(); + hythread_suspend_disable(); if (src && dst) { res = array_copy(((ObjectHandle)src)->object, src_off, ((ObjectHandle)dst)->object, dst_off, count); } else { res = ACR_NullPointer; } - tmn_suspend_enable(); + hythread_suspend_enable(); jclass tclass = NULL; switch (res) { case ACR_Okay: @@ -683,6 +682,7 @@ Boolean class_is_subclass(Class_Handle s jclass FindClass(JNIEnv* env_ext, String* name) { + ASSERT_RAISE_AREA; TRACE2("jni", "FindClass called, name = " << name->bytes); #ifdef _DEBUG @@ -774,9 +774,9 @@ jobject CreateNewThrowable(JNIEnv* jenv, jvalue res; assert(hythread_is_suspend_enabled()); - tmn_suspend_disable(); + hythread_suspend_disable(); vm_execute_java_method_array((jmethodID) initCause, &res, initArgs); - tmn_suspend_enable(); + hythread_suspend_enable(); } return obj; @@ -784,15 +784,35 @@ jobject CreateNewThrowable(JNIEnv* jenv, jobject create_default_instance(Class* clss) { - tmn_suspend_disable(); + hythread_suspend_disable(); jobject h = oh_allocate_local_handle(); ManagedObject *new_obj = class_alloc_new_object_and_run_default_constructor(clss); if (new_obj == NULL) { - tmn_suspend_enable(); + hythread_suspend_enable(); assert(exn_raised()); return NULL; } h->object = new_obj; - tmn_suspend_enable(); + hythread_suspend_enable(); return h; } + +bool ensure_initialised(JNIEnv* env, Class* clss) +{ + ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); + + if(clss->state != ST_Initialized) { + class_initialize_from_jni(clss); + if(clss->state == ST_Error) { + // If exception is already raised, no need to + // throw new one, just return instead + if (!exn_raised()) + { + env->Throw(class_get_error_cause(clss)); + } + return false; + } + } + return true; +} diff --git vm/vmcore/src/jvmti/jvmti.cpp vm/vmcore/src/jvmti/jvmti.cpp index adb7f86..6f77cc7 100644 --- vm/vmcore/src/jvmti/jvmti.cpp +++ vm/vmcore/src/jvmti/jvmti.cpp @@ -262,6 +262,7 @@ jint JNICALL create_jvmti_environment(Ja memset(&newenv->global_events, 0, sizeof(newenv->global_events)); memset(&newenv->event_threads, 0, sizeof(newenv->event_threads)); + LMAutoUnlock lock(&vm->vm_env->TI->TIenvs_lock); vm->vm_env->TI->addEnvironment(newenv); *env = newenv; TRACE2("jvmti", "New environment added: " << newenv); @@ -269,7 +270,7 @@ jint JNICALL create_jvmti_environment(Ja return JNI_OK; } -void DebugUtilsTI::setInterpreterState(Global_Env *p_env) +void DebugUtilsTI::setExecutionMode(Global_Env *p_env) { const char *interp_property = properties_get_string_property((PropertiesHandle)&p_env->properties, "vm.use_interpreter"); @@ -287,8 +288,9 @@ void DebugUtilsTI::setInterpreterState(G !strncmp(option, "-agentpath:", 11) || !strncmp(option, "-Xrun", 5)) { - TRACE2("jvmti", "Enabling interpreter by default because jvmti is enabled"); - add_pair_to_properties(p_env->properties, "vm.use_interpreter", "true"); + TRACE2("jvmti", "Enabling EM JVMTI mode"); + // add_pair_to_properties(p_env->properties, "vm.use_interpreter", "true"); + add_pair_to_properties(p_env->properties, "vm.jvmti.enabled", "true"); break; } } @@ -297,10 +299,11 @@ void DebugUtilsTI::setInterpreterState(G DebugUtilsTI::DebugUtilsTI() : agent_counter(1), brkpntlst(NULL), + access_watch_list(NULL), + modification_watch_list(NULL), status(false), agents(NULL), p_TIenvs(NULL), - dcList(NULL), MAX_NOTIFY_LIST(1000), loadListNumber(0), prepareListNumber(0), @@ -723,3 +726,22 @@ jvmtiError jvmti_translate_jit_error(Ope return JVMTI_ERROR_INTERNAL; } } + +void jvmti_get_compilation_flags(OpenMethodExecutionParams *flags) +{ + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + + if (!ti->isEnabled()) + return; + + flags->exe_do_code_mapping = flags->exe_do_local_var_mapping = 1; + + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_ENTRY)) + flags->exe_notify_method_entry = 1; + + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_EXIT) || + ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION)) + flags->exe_notify_method_exit = 1; + +} + diff --git vm/vmcore/src/jvmti/jvmti_break.cpp vm/vmcore/src/jvmti/jvmti_break.cpp old mode 100644 new mode 100755 index e553e3a..57abf62 --- vm/vmcore/src/jvmti/jvmti_break.cpp +++ vm/vmcore/src/jvmti/jvmti_break.cpp @@ -31,6 +31,13 @@ #include "cxxlog.h" #include "interpreter_exports.h" #include "interpreter_imports.h" #include "suspend_checker.h" +#include "jit_intf_cpp.h" +#include "encoder.h" + +#define INSTRUMENTATION_BYTE_HLT 0xf4 // HLT instruction +#define INSTRUMENTATION_BYTE_CLI 0xfa // CLI instruction +#define INSTRUMENTATION_BYTE_INT3 0xcc // INT 3 instruction +#define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_INT3 #include "open/jthread.h" @@ -40,38 +47,44 @@ #include "open/hythread_ext.h" // Returns breakpoint ID received from executing engine on creating of the // breakpoint VMEXPORT void* -jvmti_process_breakpoint_event(jmethodID method, jlocation location) +jvmti_process_interpreter_breakpoint_event(jmethodID method, jlocation location) { - TRACE2("jvmti-break", "BREAKPOINT occured, location = " << location); - NativeObjectHandles handles; + TRACE2("jvmti.break", "BREAKPOINT occured, location = " << location); ObjectHandle hThread = oh_allocate_local_handle(); hThread->object = (Java_java_lang_Thread *)jthread_get_java_thread(hythread_self())->object; tmn_suspend_enable(); - // FIXME: lock breakpoint table - DebugUtilsTI *ti = VM_Global_State::loader_env->TI; - BreakPoint *bp = ti->find_breakpoint(method, location); + + ti->brkpntlst_lock._lock(); + + BreakPoint *bp = ti->find_first_bpt(method, location); assert(bp); // Can't be bytecode without breakpoint - assert(bp->envs); // Can't be breakpoint with no environments + assert(bp->env); // Can't be breakpoint with no environments void *id = bp->id; - for (TIEnvList *el = bp->envs; NULL != el;) + do { - TIEnv *env = el->env; - el = el->next; + TIEnv *env = bp->env; + BreakPoint *next_bp = ti->find_next_bpt(bp, method, location); + if (env->global_events[JVMTI_EVENT_BREAKPOINT - JVMTI_MIN_EVENT_TYPE_VAL]) { jvmtiEventBreakpoint func = (jvmtiEventBreakpoint)env->get_event_callback(JVMTI_EVENT_BREAKPOINT); if (NULL != func) { JNIEnv *jni_env = (JNIEnv *)jni_native_intf; - TRACE2("jvmti-break", "Calling global breakpoint callback method = " << + TRACE2("jvmti.break", "Calling interpreter global breakpoint callback method = " << ((Method*)method)->get_name() << " location = " << location); + + ti->brkpntlst_lock._unlock(); func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - TRACE2("jvmti-break", "Finished global breakpoint callback method = " << + ti->brkpntlst_lock._lock(); + + TRACE2("jvmti.break", "Finished interpreter global breakpoint callback method = " << ((Method*)method)->get_name() << " location = " << location); } + bp = next_bp; continue; // Don't send local events } @@ -86,21 +99,292 @@ jvmti_process_breakpoint_event(jmethodID if (NULL != func) { JNIEnv *jni_env = (JNIEnv *)jni_native_intf; - TRACE2("jvmti-break", "Calling local breakpoint callback method = " << + TRACE2("jvmti.break", "Calling interpreter local breakpoint callback method = " << ((Method*)method)->get_name() << " location = " << location); + + ti->brkpntlst_lock._unlock(); func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - TRACE2("jvmti-break", "Finished local breakpoint callback method = " << + ti->brkpntlst_lock._lock(); + + TRACE2("jvmti.break", "Finished interpreter local breakpoint callback method = " << ((Method*)method)->get_name() << " location = " << location); } } + + et = next_et; } - } + + bp = next_bp; + } while(bp); + + ti->brkpntlst_lock._unlock(); tmn_suspend_disable(); oh_discard_local_handle(hThread); return id; } +ConditionCode get_condition_code(InstructionDisassembler::CondJumpType jump_type) +{ + // Right now InstructionDisassembler::CondJumpType enum values are + // equal to enums in ia32/em64t encoder, so this statement is ok + return (ConditionCode)jump_type; +} + +bool jvmti_send_jit_breakpoint_event(Registers *regs) +{ +#if PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 + // Int3 exception address points to the instruction after it + NativeCodePtr native_location = (NativeCodePtr)(((POINTER_SIZE_INT)regs->get_ip()) - 1); +#else + NativeCodePtr native_location = (NativeCodePtr)regs->get_ip(); +#endif + + TRACE2("jvmti.break", "BREAKPOINT occured, location = " << native_location); + + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled()) + return false; + + ti->brkpntlst_lock._lock(); + BreakPoint *bp = ti->find_first_bpt(native_location); + if (NULL == bp) + { + ti->brkpntlst_lock._unlock(); + return false; + } + + assert(ti->isEnabled()); + assert(!interpreter_enabled()); + + ObjectHandle hThread = oh_allocate_local_handle(); + hThread->object = (Java_java_lang_Thread *)jthread_get_java_thread(hythread_self())->object; + tmn_suspend_enable(); + + void *id = bp->id; + jbyte original_byte = (POINTER_SIZE_INT)id; + // Copy disassembler instance in case a breakpoint is deleted + // inside of callbacks + InstructionDisassembler idisasm(*bp->disasm); + + do + { + TIEnv *env = bp->env; + jlocation location = bp->location; + jmethodID method = bp->method; + BreakPoint *next_bp = ti->find_next_bpt(bp, native_location); + + if (env->global_events[JVMTI_EVENT_BREAKPOINT - JVMTI_MIN_EVENT_TYPE_VAL]) + { + jvmtiEventBreakpoint func = (jvmtiEventBreakpoint)env->get_event_callback(JVMTI_EVENT_BREAKPOINT); + if (NULL != func) + { + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + TRACE2("jvmti.break", "Calling JIT global breakpoint callback method = " << + ((Method*)method)->get_name() << " location = " << location); + + ti->brkpntlst_lock._unlock(); + func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); + ti->brkpntlst_lock._lock(); + + TRACE2("jvmti.break", "Finished JIT global breakpoint callback method = " << + ((Method*)method)->get_name() << " location = " << location); + } + bp = next_bp; + continue; // Don't send local events + } + + TIEventThread *next_et; + for (TIEventThread *et = env->event_threads[JVMTI_EVENT_BREAKPOINT - JVMTI_MIN_EVENT_TYPE_VAL]; + NULL != et; et = next_et) + { + next_et = et->next; + if (et->thread == hythread_self()) + { + jvmtiEventBreakpoint func = (jvmtiEventBreakpoint)env->get_event_callback(JVMTI_EVENT_BREAKPOINT); + if (NULL != func) + { + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + TRACE2("jvmti.break", "Calling JIT local breakpoint callback method = " << + ((Method*)method)->get_name() << " location = " << location); + + ti->brkpntlst_lock._unlock(); + func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); + ti->brkpntlst_lock._lock(); + + TRACE2("jvmti.break", "Finished JIT local breakpoint callback method = " << + ((Method*)method)->get_name() << " location = " << location); + } + } + + et = next_et; + } + + bp = next_bp; + } while(bp); + + // Now we need to return back to normal code execution, it is + // necessary to execute the original instruction The idea is to + // recreate the original instriction in a special thread local + // buffer followed by a jump to an instruction next after it. In + // case the instruction was a relative jump or call it requires + // special handling. + InstructionDisassembler::Type type = idisasm.get_type(); + + VM_thread *vm_thread = p_TLS_vmthread; + jbyte *instruction_buffer = vm_thread->jvmti_jit_breakpoints_handling_buffer; + jbyte *interrupted_instruction = (jbyte *)native_location; + jint instruction_length = idisasm.get_length_with_prefix(); + + switch(type) + { + case InstructionDisassembler::UNKNOWN: + { + char *next_instruction = (char *)interrupted_instruction + + instruction_length; + + // Copy original instruction to the exeuction buffer + *instruction_buffer = original_byte; + memcpy(instruction_buffer + 1, interrupted_instruction + 1, + instruction_length - 1); + + // Create JMP $next_instruction instruction in the execution buffer + jump((char *)instruction_buffer + instruction_length, + next_instruction); + break; + } + case InstructionDisassembler::RELATIVE_JUMP: + { + jint instruction_length = idisasm.get_length_with_prefix(); + char *jump_target = (char *)idisasm.get_jump_target_address(); + + // Create JMP to the absolute address which conditional jump + // had in the execution buffer + jump((char *)instruction_buffer, jump_target); + break; + } + case InstructionDisassembler::RELATIVE_COND_JUMP: + { + char *code = (char *)instruction_buffer; + InstructionDisassembler::CondJumpType jump_type = + idisasm.get_cond_jump_type(); + char *next_instruction = (char *)interrupted_instruction + + instruction_length; + char *jump_target = (char *)idisasm.get_jump_target_address(); + + // Create a conditional JMP of the same type over 1 + // instruction forward, the next instruction is JMP to the + // $next_instruction + code = branch8(code, get_condition_code(jump_type), Imm_Opnd(size_8, 0)); + char *branch_address = code - 1; + + code = jump(code, next_instruction); + jint offset = code - branch_address - 1; + *branch_address = offset; + + jump(code, jump_target); + break; + } + case InstructionDisassembler::ABSOLUTE_CALL: + case InstructionDisassembler::RELATIVE_CALL: + { + jbyte *next_instruction = interrupted_instruction + instruction_length; + char *jump_target = (char *)idisasm.get_jump_target_address(); + char *code = (char *)instruction_buffer; + + // Push "return address" to the $next_instruction + code = push(code, Imm_Opnd((POINTER_SIZE_INT)next_instruction)); + + // Jump to the target address of the call instruction + jump(code, jump_target); + break; + } + } + + // Set exception or signal return address to the instruction buffer +#ifndef _EM64T_ + regs->eip = (POINTER_SIZE_INT)instruction_buffer; +#else + regs->rip = (POINTER_SIZE_INT)instruction_buffer; +#endif + + ti->brkpntlst_lock._unlock(); + + tmn_suspend_disable(); + oh_discard_local_handle(hThread); + + return true; +} + +jvmtiError jvmti_set_jit_mode_breakpoint(BreakPoint *bp) +{ + // Find native location in the method code + NativeCodePtr np = NULL; + Method *m = (Method *)bp->method; + + for (CodeChunkInfo* cci = m->get_first_JIT_specific_info(); cci; cci = cci->_next) + { + JIT *jit = cci->get_jit(); + OpenExeJpdaError res = jit->get_native_location_for_bc(m, + (uint16)bp->location, &np); + if (res == EXE_ERROR_NONE) + break; + } + + if (NULL == np) + return JVMTI_ERROR_INTERNAL; + + TRACE2("jvmti.break", "SetBreakpoint instrumenting native location " << np); + + bp->native_location = np; + bp->disasm = new InstructionDisassembler(np); + + jbyte *target_instruction = (jbyte *)np; + bp->id = (void *)(POINTER_SIZE_INT)*target_instruction; + *target_instruction = (jbyte)INSTRUMENTATION_BYTE; + + return JVMTI_ERROR_NONE; +} + +void jvmti_set_pending_breakpoints(Method *method) +{ + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled()) + return; + + assert(method->get_pending_breakpoints() > 0); + + LMAutoUnlock lock(&ti->brkpntlst_lock); + + jmethodID mid = (jmethodID)method; + BreakPoint *bp = ti->find_first_bpt(mid); + assert(bp); + + jlocation *locations = (jlocation *)STD_MALLOC(sizeof(jlocation) * + method->get_pending_breakpoints()); + assert(locations); + uint32 location_count = 0; + + do + { + // It is necessary to set breakpoints only once for each + // location, so we need to filter out duplicate breakpoints + for (uint32 iii = 0; iii < location_count; iii++) + if (bp->location == locations[iii]) + continue; + + jvmti_set_jit_mode_breakpoint(bp); + locations[location_count++] = bp->location; + + method->remove_pending_breakpoint(); + bp = ti->find_next_bpt(bp, mid); + } + while(NULL != bp); + + assert(method->get_pending_breakpoints() == 0); + STD_FREE(locations); +} + /* * Set Breakpoint * @@ -130,7 +414,7 @@ jvmtiSetBreakpoint(jvmtiEnv* env, return JVMTI_ERROR_INVALID_METHODID; Method *m = (Method*) method; - TRACE2("jvmti-break", "SetBreakpoint method = " << m->get_class()->name->bytes << "." << + TRACE2("jvmti.break", "SetBreakpoint method = " << m->get_class()->name->bytes << "." << m->get_name()->bytes << " " << m->get_descriptor()->bytes); #if defined (__INTEL_COMPILER) @@ -138,9 +422,8 @@ #pragma warning( push ) #pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type #endif - if (location < 0 || unsigned(location) >= m->get_byte_code_size()) { + if (location < 0 || unsigned(location) >= m->get_byte_code_size()) return JVMTI_ERROR_INVALID_LOCATION; - } #if defined (__INTEL_COMPILER) #pragma warning( pop ) @@ -159,48 +442,56 @@ #endif TIEnv *p_env = (TIEnv *)env; DebugUtilsTI *ti = p_env->vm->vm_env->TI; - BreakPoint *bp = ti->find_breakpoint(method, location); + LMAutoUnlock lock(&ti->brkpntlst_lock); + BreakPoint *bp = ti->find_breakpoint(method, location, p_env); - // Find breakpoint for this location if it exists already - if (NULL == bp) - { - errorCode = _allocate(sizeof(BreakPoint), (unsigned char **)&bp); - if (JVMTI_ERROR_NONE != errorCode) - return errorCode; + if (NULL != bp) + return JVMTI_ERROR_DUPLICATE; + + errorCode = _allocate(sizeof(BreakPoint), (unsigned char **)&bp); + if (JVMTI_ERROR_NONE != errorCode) + return errorCode; - TIEnvList *el; - errorCode = _allocate(sizeof(TIEnvList), (unsigned char **)&el); - if (JVMTI_ERROR_NONE != errorCode) + bp->method = method; + bp->location = location; + bp->env = p_env; + bp->disasm = NULL; + + BreakPoint *other_bp = ti->get_other_breakpoint_same_location(method, location, p_env); + + if (NULL == other_bp) // No more environments set breakpoints here + { + if (interpreter_enabled()) + bp->id = interpreter.interpreter_ti_set_breakpoint(method, location); + else { - _deallocate((unsigned char *)bp); - return errorCode; - } - bp->method = method; - bp->location = location; - bp->next = 0; - bp->envs = 0; + Method *m = (Method *)method; - el->env = p_env; - bp->add_env(el); - ti->add_breakpoint(bp); + if (m->get_state() == Method::ST_Compiled) + errorCode = jvmti_set_jit_mode_breakpoint(bp); + else + { + TRACE2("jvmti.break", "Skipping setting breakpoing in method " << + m->get_class()->name->bytes << "." << + m->get_name()->bytes << " " << m->get_descriptor()->bytes << + " because it is not compiled yet"); + m->insert_pending_breakpoint(); + } - bp->id = interpreter.interpreter_ti_set_breakpoint(method, location); + if (errorCode != JVMTI_ERROR_NONE) + return JVMTI_ERROR_INTERNAL; + } } else { - if (NULL != bp->find_env(p_env)) - return JVMTI_ERROR_DUPLICATE; - - TIEnvList *el; - errorCode = _allocate(sizeof(TIEnvList), (unsigned char **)&el); - if (JVMTI_ERROR_NONE != errorCode) - return errorCode; - - el->env = p_env; - bp->add_env(el); + bp->id = other_bp->id; + if (NULL != bp->disasm) + bp->disasm = new InstructionDisassembler(*bp->disasm); } - TRACE2("jvmti-break", "SetBreakpoint successfull"); + ti->add_breakpoint(bp); + + TRACE2("jvmti.break", "SetBreakpoint successfull"); return JVMTI_ERROR_NONE; } @@ -232,7 +523,7 @@ jvmtiClearBreakpoint(jvmtiEnv* env, return JVMTI_ERROR_INVALID_METHODID; Method *m = (Method*) method; - TRACE2("jvmti-break", "ClearBreakpoint method = " << m->get_class()->name->bytes << "." << + TRACE2("jvmti.break", "ClearBreakpoint method = " << m->get_class()->name->bytes << "." << m->get_name()->bytes << " " << m->get_descriptor()->bytes); #if defined (__INTEL_COMPILER) @@ -240,9 +531,8 @@ #pragma warning( push ) #pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type #endif - if (location < 0 || unsigned(location) >= m->get_byte_code_size()) { + if (location < 0 || unsigned(location) >= m->get_byte_code_size()) return JVMTI_ERROR_INVALID_LOCATION; - } #if defined (__INTEL_COMPILER) #pragma warning( pop ) @@ -262,23 +552,33 @@ #endif TIEnv *p_env = (TIEnv *)env; DebugUtilsTI *ti = p_env->vm->vm_env->TI; - BreakPoint *bp = ti->find_breakpoint(method, location); + LMAutoUnlock lock(&ti->brkpntlst_lock); + BreakPoint *bp = ti->find_breakpoint(method, location, p_env); if (NULL == bp) return JVMTI_ERROR_NOT_FOUND; - TIEnvList *el = bp->find_env(p_env); - if (NULL == el) - return JVMTI_ERROR_NOT_FOUND; - - if (NULL == bp->envs->next) // No more environments set breakpoints here + if (NULL == ti->get_other_breakpoint_same_location(method, location, p_env)) { - interpreter.interpreter_ti_clear_breakpoint(method, location, bp->id); + // No more environments set breakpoints here + if (interpreter_enabled()) + interpreter.interpreter_ti_clear_breakpoint(method, location, bp->id); + else + { + Method *m = (Method *)method; + + if (m->get_state() == Method::ST_Compiled) + { + jbyte *target_instruction = (jbyte *)bp->native_location; + *target_instruction = (POINTER_SIZE_INT)bp->id; + } + else + m->remove_pending_breakpoint(); + } } - bp->remove_env(el); - if (NULL == bp->envs) - ti->remove_breakpoint(bp); + ti->remove_breakpoint(bp); + TRACE2("jvmti.break", "ClearBreakpoint successfull"); return JVMTI_ERROR_NONE; } diff --git vm/vmcore/src/jvmti/jvmti_capability.cpp vm/vmcore/src/jvmti/jvmti_capability.cpp index 979897c..81a31c1 100644 --- vm/vmcore/src/jvmti/jvmti_capability.cpp +++ vm/vmcore/src/jvmti/jvmti_capability.cpp @@ -31,8 +31,8 @@ #include "interpreter_exports.h" static const jvmtiCapabilities jvmti_supported_interpreter_capabilities = { 0, // can_tag_objects - 0, // can_generate_field_modification_events - 0, // can_generate_field_access_events + 1, // can_generate_field_modification_events + 1, // can_generate_field_access_events 1, // can_get_bytecodes 1, // can_get_synthetic_attribute 1, // can_get_owned_monitor_info @@ -52,8 +52,8 @@ static const jvmtiCapabilities jvmti_sup 1, // can_generate_breakpoint_events 1, // can_suspend 0, // can_redefine_any_class - 0, // can_get_current_thread_cpu_time - 0, // can_get_thread_cpu_time + 1, // can_get_current_thread_cpu_time + 1, // can_get_thread_cpu_time 1, // can_generate_method_entry_events 1, // can_generate_method_exit_events 1, // can_generate_all_class_hook_events @@ -68,8 +68,8 @@ static const jvmtiCapabilities jvmti_sup static const jvmtiCapabilities jvmti_supported_jit_capabilities = { 0, // can_tag_objects - 0, // can_generate_field_modification_events - 0, // can_generate_field_access_events + 1, // can_generate_field_modification_events + 1, // can_generate_field_access_events 1, // can_get_bytecodes 1, // can_get_synthetic_attribute 1, // can_get_owned_monitor_info @@ -86,13 +86,13 @@ static const jvmtiCapabilities jvmti_sup 0, // can_generate_single_step_events 1, // can_generate_exception_events 1, // can_generate_frame_pop_events - 0, // can_generate_breakpoint_events + 1, // can_generate_breakpoint_events 1, // can_suspend 0, // can_redefine_any_class - 0, // can_get_current_thread_cpu_time - 0, // can_get_thread_cpu_time - 0, // can_generate_method_entry_events - 0, // can_generate_method_exit_events + 1, // can_get_current_thread_cpu_time + 1, // can_get_thread_cpu_time + 1, // can_generate_method_entry_events + 1, // can_generate_method_exit_events 1, // can_generate_all_class_hook_events 1, // can_generate_compiled_method_load_events 0, // can_generate_monitor_events @@ -128,8 +128,8 @@ static const jvmtiCapabilities jvmti_ena 0, // can_generate_breakpoint_events 1, // can_suspend 0, // can_redefine_any_class - 0, // can_get_current_thread_cpu_time - 0, // can_get_thread_cpu_time + 1, // can_get_current_thread_cpu_time + 1, // can_get_thread_cpu_time 0, // can_generate_method_entry_events 0, // can_generate_method_exit_events 1, // can_generate_all_class_hook_events @@ -266,6 +266,12 @@ jvmtiAddCapabilities(jvmtiEnv* env, if (capabilities_ptr->can_generate_exception_events) ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT); + if (capabilities_ptr->can_generate_field_access_events) + ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT); + + if (capabilities_ptr->can_generate_field_modification_events) + ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT); + return JVMTI_ERROR_NONE; } @@ -309,6 +315,7 @@ jvmtiRelinquishCapabilities(jvmtiEnv* en } DebugUtilsTI* ti = ti_env->vm->vm_env->TI; + ti->TIenvs_lock._lock(); ti_env = ti->getEnvironments(); while (NULL != ti_env) @@ -323,6 +330,8 @@ jvmtiRelinquishCapabilities(jvmtiEnv* en ti_env = next_env; } + ti->TIenvs_lock._unlock(); + // Now removed_ptr contains capabilities removed from all environments if (removed_caps.can_generate_method_entry_events) ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_ENTRY); @@ -342,6 +351,12 @@ jvmtiRelinquishCapabilities(jvmtiEnv* en if (removed_caps.can_generate_exception_events) ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT); + if (removed_caps.can_generate_field_access_events) + ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT); + + if (removed_caps.can_generate_field_modification_events) + ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT); + return JVMTI_ERROR_NONE; } diff --git vm/vmcore/src/jvmti/jvmti_class.cpp vm/vmcore/src/jvmti/jvmti_class.cpp index e4a8404..bca76ff 100644 --- vm/vmcore/src/jvmti/jvmti_class.cpp +++ vm/vmcore/src/jvmti/jvmti_class.cpp @@ -29,6 +29,7 @@ #include "jvmti_utils.h" #include "Class.h" #include "object_handles.h" #include "jni_utils.h" +#include "jvmti_internal.h" #include "open/vm_util.h" #include "vm_strings.h" #include "environment.h" @@ -318,6 +319,9 @@ jvmtiGetClassSignature( jvmtiEnv* env, CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + /** * Get class from handle, set error if need it */ @@ -377,6 +381,9 @@ jvmtiGetClassStatus(jvmtiEnv* env, jclas CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, status_ptr, &errorCode); @@ -443,6 +450,9 @@ jvmtiGetSourceFileName(jvmtiEnv* env, jc CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_source_file_name); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, res, &errorCode); @@ -483,6 +493,9 @@ jvmtiGetClassModifiers(jvmtiEnv* env, jc CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, modifiers_ptr, &errorCode); @@ -516,6 +529,9 @@ jvmtiGetClassMethods(jvmtiEnv* env, jcla CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, method_count_ptr, methods_ptr, &errorCode); @@ -557,6 +573,9 @@ jvmtiGetClassFields(jvmtiEnv* env, jclas CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, field_count_ptr, fields_ptr, &errorCode); @@ -598,6 +617,9 @@ jvmtiGetImplementedInterfaces(jvmtiEnv* CHECK_EVERYTHING(); + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), klass, interface_count_ptr, interfaces_ptr, &errorCode); @@ -647,6 +669,9 @@ jvmtiIsInterface(jvmtiEnv* env, jclass h CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, is_interface_ptr, &errorCode); @@ -676,6 +701,9 @@ jvmtiIsArrayClass(jvmtiEnv* env, jclass CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* cl = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, is_array_class_ptr, &errorCode); @@ -704,6 +732,9 @@ jvmtiError JNICALL jvmtiGetClassLoader(j CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* clss = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, classloader_ptr, &errorCode); @@ -741,6 +772,9 @@ jvmtiGetSourceDebugExtension(jvmtiEnv* e CHECK_EVERYTHING(); + if (! is_valid_class_object(handle)) + return JVMTI_ERROR_INVALID_CLASS; + Class* clss = get_class_from_handle(env, jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, source_debug_extension_ptr, &errorCode); diff --git vm/vmcore/src/jvmti/jvmti_dasm.cpp vm/vmcore/src/jvmti/jvmti_dasm.cpp new file mode 100644 index 0000000..67b8075 --- /dev/null +++ vm/vmcore/src/jvmti/jvmti_dasm.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander V. Astapchuk + * @version $Revision: $ + */ +/** + * @file + * @brief Disassembler for JVMTI implementation. + */ +#include "jvmti_dasm.h" +#include "dec_base.h" + +void InstructionDisassembler::disasm(const NativeCodePtr addr, + InstructionDisassembler * pidi) +{ + assert(pidi != NULL); + Inst inst; + pidi->len = DecoderBase::decode(addr, &inst); + if (pidi->len == 0) { + // Something wrong happened + pidi->type = OPCODEERROR; + return; + } + + pidi->target = (NativeCodePtr)inst.direct_addr; + pidi->type = UNKNOWN; + + if (inst.mn == Mnemonic_CALL && + inst.odesc->opnds[0].kind == OpndKind_Imm) { + pidi->type = RELATIVE_CALL; + } + else if (inst.mn == Mnemonic_JMP && + inst.odesc->opnds[0].kind == OpndKind_Imm) { + pidi->type = RELATIVE_JUMP; + } + else if (is_jcc(inst.mn)) { + // relative Jcc is the only possible variant + assert(inst.odesc->opnds[0].kind == OpndKind_Imm); + pidi->cond_jump_type = (CondJumpType)(inst.mn-Mnemonic_Jcc); + assert(pidi->cond_jump_type < CondJumpType_Count); + pidi->type = RELATIVE_COND_JUMP; + } +} diff --git vm/vmcore/src/jvmti/jvmti_event.cpp vm/vmcore/src/jvmti/jvmti_event.cpp old mode 100644 new mode 100755 index 951f2bb..dcd7b8c --- vm/vmcore/src/jvmti/jvmti_event.cpp +++ vm/vmcore/src/jvmti/jvmti_event.cpp @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Gregory Shimansky * @version $Revision: 1.1.2.2.4.5 $ - */ + */ /* * JVMTI events API */ @@ -35,6 +35,7 @@ #include "open/jthread.h" #include "suspend_checker.h" #include "jit_intf_cpp.h" #include "vm_log.h" +#include "compile.h" /* * Set Event Callbacks @@ -448,19 +449,6 @@ void jvmti_send_dynamic_code_generated_e } } -void jvmti_add_dynamic_generated_code_chunk(const char *name, const void *address, jint length) -{ - DynamicCode *dcList = VM_Global_State::loader_env->TI->getDynamicCodeList(); - // FIXME linked list modification without synchronization - DynamicCode *dc = (DynamicCode *)STD_MALLOC(sizeof(DynamicCode)); - assert(dc); - dc->name = name; - dc->address = address; - dc->length = length; - dc->next = dcList; - dcList = dc; -} - /* * Generate Events * @@ -563,7 +551,7 @@ jvmtiGenerateEvents(jvmtiEnv* env, else { // FIXME: linked list usage without sync - for (DynamicCode *dcList = ((TIEnv *)env)->vm->vm_env->TI->getDynamicCodeList(); + for (DynamicCode *dcList = compile_get_dynamic_code_list(); NULL != dcList; dcList = dcList->next) jvmti_send_dynamic_code_generated_event(dcList->name, dcList->address, dcList->length); } @@ -573,6 +561,8 @@ jvmtiGenerateEvents(jvmtiEnv* env, VMEXPORT void jvmti_process_method_entry_event(jmethodID method) { + SuspendDisabledChecker sdc; + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() ) return; @@ -583,6 +573,7 @@ jvmti_process_method_entry_event(jmethod if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_ENTRY)) return; + tmn_suspend_enable(); jvmtiEvent event_type = JVMTI_EVENT_METHOD_ENTRY; hythread_t curr_thread = hythread_self(); @@ -618,10 +609,13 @@ jvmti_process_method_entry_event(jmethod ti_env = next_env; } + tmn_suspend_disable(); } VMEXPORT void jvmti_process_method_exit_event(jmethodID method, jboolean was_popped_by_exception, jvalue ret_val) { + SuspendDisabledChecker sdc; + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() ) return; @@ -632,6 +626,7 @@ jvmti_process_method_exit_event(jmethodI if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_EXIT)) return; + tmn_suspend_enable(); jvmtiEvent event_type = JVMTI_EVENT_METHOD_EXIT; hythread_t curr_native_thread = hythread_self(); @@ -666,11 +661,18 @@ jvmti_process_method_exit_event(jmethodI } if (interpreter_enabled()) + { + tmn_suspend_disable(); return; + } if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION)) + { + tmn_suspend_disable(); return; + } + VM_thread *curr_thread = p_TLS_vmthread; jvmti_frame_pop_listener *fpl = curr_thread->frame_pop_listener; jvmti_frame_pop_listener **prev_fpl = &curr_thread->frame_pop_listener; @@ -691,6 +693,8 @@ jvmti_process_method_exit_event(jmethodI prev_fpl = &fpl->next; fpl = fpl->next; } + + tmn_suspend_disable(); } VMEXPORT void @@ -759,6 +763,126 @@ jvmti_process_single_step_event(jmethodI } } +VMEXPORT void jvmti_process_field_access_event(Field_Handle field, + jmethodID method, jlocation location, jobject* object) +{ + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled() ) + return; + + if (JVMTI_PHASE_LIVE != ti->getPhase()) + return; + + if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT)) + return; + + // get field class + //Type_Info_Handle field_type = field_get_type_info_of_field_value(field); + //Class_Handle clss = type_info_get_class(field_type); + //ASSERT(clss, "Can't get class handle for field type."); + //jclass field_klass = struct_Class_to_java_lang_Class_Handle(clss); + + // field_klass seems to be declaring class, not the field type + jclass field_klass = struct_Class_to_java_lang_Class_Handle(field->get_class()); + + jvmtiEvent event_type = JVMTI_EVENT_FIELD_ACCESS; + hythread_t curr_thread = hythread_self(); + TIEnv *ti_env = ti->getEnvironments(); + TIEnv *next_env; + while (NULL != ti_env) + { + next_env = ti_env->next; + // check that event is enabled in this environment. + if (!ti_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL]) { + TIEventThread *thr = ti_env->event_threads[event_type - JVMTI_MIN_EVENT_TYPE_VAL]; + while (thr) + { + if (thr->thread == curr_thread) + break; + thr = thr->next; + } + + if (!thr) + { + ti_env = next_env; + continue; + } + } + + // event is enabled in this environment + jthread thread = getCurrentThread(); + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + jvmtiEnv *jvmti_env = (jvmtiEnv*) ti_env; + + if (NULL != ti_env->event_table.FieldAccess) + ti_env->event_table.FieldAccess(jvmti_env, jni_env, thread, + method, location, field_klass, *object, (jfieldID) field); + ti_env = next_env; + } +} // jvmti_process_field_access_event + +VMEXPORT void jvmti_process_field_modification_event(Field_Handle field, + jmethodID method, jlocation location, jobject* object, jvalue new_value) +{ + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled() ) + return; + + if (JVMTI_PHASE_LIVE != ti->getPhase()) + return; + + if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT)) + return; + + // get field class + //Type_Info_Handle field_type = field_get_type_info_of_field_value(field); + //Class_Handle clss = type_info_get_class(field_type); + //ASSERT(clss, "Can't get class handle for field type."); + //jclass field_klass = struct_Class_to_java_lang_Class_Handle(clss); + + // field_klass seems to be declaring class, not the field type + jclass field_klass = struct_Class_to_java_lang_Class_Handle(field->get_class()); + + // get signature type + char signature_type = (char) field->get_java_type(); + + jvmtiEvent event_type = JVMTI_EVENT_FIELD_MODIFICATION; + hythread_t curr_thread = hythread_self(); + TIEnv *ti_env = ti->getEnvironments(); + TIEnv *next_env; + while (NULL != ti_env) + { + next_env = ti_env->next; + // check that event is enabled in this environment. + if (!ti_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL]) { + TIEventThread *thr = ti_env->event_threads[event_type - JVMTI_MIN_EVENT_TYPE_VAL]; + while (thr) + { + if (thr->thread == curr_thread) + break; + thr = thr->next; + } + + if (!thr) + { + ti_env = next_env; + continue; + } + } + + // event is enabled in this environment + jthread thread = getCurrentThread(); + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + jvmtiEnv *jvmti_env = (jvmtiEnv*) ti_env; + + if (NULL != ti_env->event_table.FieldModification) + ti_env->event_table.FieldModification(jvmti_env, jni_env, thread, + method, location, field_klass, *object, (jfieldID) field, + signature_type, new_value); + ti_env = next_env; + } +} // jvmti_process_field_modification_event + /* * Send Exception event */ @@ -789,7 +913,7 @@ void jvmti_send_exception_event(jthrowab next_env = ti_env->next; if (!ti_env->global_events[JVMTI_EVENT_EXCEPTION - JVMTI_MIN_EVENT_TYPE_VAL]) { - // No global event set; then check thread specific events. + // No global event set; then check thread specific events. TIEventThread *thr = ti_env->event_threads[JVMTI_EVENT_EXCEPTION - JVMTI_MIN_EVENT_TYPE_VAL]; @@ -823,17 +947,16 @@ void jvmti_send_exception_event(jthrowab } ti_env = next_env; } - - curr_thread->ti_exception_callback_pending = false; } -void jvmti_interpreter_exception_event_callback_call(void) +void jvmti_interpreter_exception_event_callback_call( + ManagedObject *exc, Method *method, jlocation location, + Method *catch_method, jlocation catch_location) { - assert(exn_raised()); + assert(!exn_raised()); SuspendDisabledChecker sdc; VM_thread *curr_thread = p_TLS_vmthread; - curr_thread->ti_exception_callback_pending = false; DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled()) @@ -845,30 +968,23 @@ void jvmti_interpreter_exception_event_c if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) return; - jthrowable exn_object = exn_get(); - - clear_current_thread_exception(); - - jlocation location, catch_location; - Method *method, *catch_method; + assert(!exn_raised()); - interpreter.interpreter_st_get_interrupted_method(&method, - &location); - interpreter.interpreter_st_get_catch_method(&catch_method, - &catch_location, exn_object); + ObjectHandle exception = oh_allocate_local_handle(); + exception->object = exc; - jvmti_send_exception_event(exn_object, method, location, + jvmti_send_exception_event((jthrowable) exception, method, location, catch_method, catch_location); assert(!hythread_is_suspend_enabled()); - if (!exn_raised()) - set_current_thread_exception(exn_object->object); + assert(!exn_raised()); } ManagedObject *jvmti_jit_exception_event_callback_call(ManagedObject *exn_object, JIT *jit, Method *method, NativeCodePtr native_location, JIT *catch_jit, Method *catch_method, NativeCodePtr native_catch_location) { + assert(!exn_raised()); SuspendDisabledChecker sdc; DebugUtilsTI *ti = VM_Global_State::loader_env->TI; @@ -927,6 +1043,173 @@ ManagedObject *jvmti_jit_exception_event return exception->object; } +ManagedObject *jvmti_exception_catch_event_callback_call(ManagedObject *exn, + Method *catch_method, jlocation catch_location) +{ + assert(!exn_raised()); + SuspendDisabledChecker sec; + + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + assert(ti->isEnabled()); + + hythread_t curr_thread = hythread_self(); + + // Create local handles frame + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + + ObjectHandle exn_object = oh_allocate_local_handle(); + exn_object->object = exn; + + ObjectHandle hThread = oh_allocate_local_handle(); + hThread->object = (Java_java_lang_Thread *)jthread_get_java_thread(hythread_self())->object; + + TIEnv *ti_env = ti->getEnvironments(); + TIEnv *next_env; + while (NULL != ti_env) + { + next_env = ti_env->next; + if (!ti_env->global_events[JVMTI_EVENT_EXCEPTION_CATCH - + JVMTI_MIN_EVENT_TYPE_VAL]) { + // No global event set; then check thread specific events. + TIEventThread *thr = + ti_env->event_threads[JVMTI_EVENT_EXCEPTION_CATCH - + JVMTI_MIN_EVENT_TYPE_VAL]; + + while (thr) + { + if (thr->thread == curr_thread) + break; + thr = thr->next; + } + + if (!thr) + { + ti_env = next_env; + continue; + } + } + jvmtiEventExceptionCatch func = + (jvmtiEventExceptionCatch)ti_env->get_event_callback(JVMTI_EVENT_EXCEPTION_CATCH); + if (NULL != func) { + + tmn_suspend_enable(); + assert(hythread_is_suspend_enabled()); + + func((jvmtiEnv *)ti_env, jni_env, + reinterpret_cast<jthread>(hThread), + reinterpret_cast<jmethodID>(catch_method), + catch_location, exn_object); + tmn_suspend_disable(); + } + ti_env = next_env; + } + + return exn_object->object; +} + +ManagedObject *jvmti_jit_exception_catch_event_callback_call(ManagedObject *exn_object, + JIT *catch_jit, Method *catch_method, NativeCodePtr native_catch_location) +{ + assert(!exn_raised()); + SuspendDisabledChecker sdc; + + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled()) + return exn_object; + + if (JVMTI_PHASE_LIVE != ti->getPhase()) + return exn_object; + + if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) + return exn_object; + + uint16 bc = 0; + jlocation catch_location; + + OpenExeJpdaError result = catch_jit->get_bc_location_for_native( + catch_method, native_catch_location, &bc); + TRACE2("jvmti.event.exn", + "Exception method = " << (Method_Handle)catch_method << " location " << bc); + if (EXE_ERROR_NONE != result) + WARN("JIT " << catch_jit << + " get_bc_location_for_native returned error " << + result << " for exception method " << (Method_Handle)catch_method << + " location " << native_catch_location); + catch_location = bc; + + exn_object = jvmti_exception_catch_event_callback_call(exn_object, + catch_method, catch_location); + + return exn_object; +} + +void jvmti_interpreter_exception_catch_event_callback_call( + ManagedObject *exc, Method *catch_method, jlocation catch_location) +{ + assert(!exn_raised()); + SuspendDisabledChecker sdc; + + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled()) + return; + + if (JVMTI_PHASE_LIVE != ti->getPhase()) + return; + + if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) + return; + + jvmti_exception_catch_event_callback_call(exc, catch_method, catch_location); + assert(!exn_raised()); +} + +void jvmti_send_contended_enter_or_entered_monitor_event(jobject obj, + bool isEnter) +{ + assert(hythread_is_suspend_enabled()); + DebugUtilsTI *ti = VM_Global_State::loader_env->TI; + if (!ti->isEnabled()) { + return; + } + + JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + + tmn_suspend_disable(); + // Create local handles frame + NativeObjectHandles lhs; + ObjectHandle hThread = oh_allocate_local_handle(); + hThread->object = (Java_java_lang_Thread *)jthread_get_java_thread(hythread_self())->object; + tmn_suspend_enable(); + + TIEnv *ti_env = ti->getEnvironments(); + TIEnv *next_env; + while (NULL != ti_env) + { + next_env = ti_env->next; + if (isEnter && ti_env->global_events[JVMTI_EVENT_MONITOR_CONTENDED_ENTER - + JVMTI_MIN_EVENT_TYPE_VAL]) + { + jvmtiEventMonitorContendedEnter func = (jvmtiEventMonitorContendedEnter) + ti_env->get_event_callback(JVMTI_EVENT_MONITOR_CONTENDED_ENTER); + if (NULL != func) + { + func((jvmtiEnv*)ti_env, jni_env, (jthread)hThread, obj); + } + } + else if (! isEnter && ti_env->global_events[JVMTI_EVENT_MONITOR_CONTENDED_ENTERED - + JVMTI_MIN_EVENT_TYPE_VAL]) + { + jvmtiEventMonitorContendedEntered func = (jvmtiEventMonitorContendedEntered) + ti_env->get_event_callback(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED); + if (NULL != func) + { + func((jvmtiEnv*)ti_env, jni_env, (jthread)hThread, obj); + } + } + ti_env = next_env; + } +} + void jvmti_send_class_load_event(const Global_Env* env, Class* clss) { assert(hythread_is_suspend_enabled()); @@ -1033,7 +1316,7 @@ void jvmti_send_class_file_load_hook_eve input_len, input_class, &output_len, &output_class); // make redefined class an input for the next agent if( output_class ) { - input_len = output_len; + input_len = output_len; input_class = last_redef = output_class; output_len = 0; output_class = NULL; @@ -1227,7 +1510,6 @@ void jvmti_send_waited_monitor_event(job process_jvmti_event(JVMTI_EVENT_MONITOR_WAITED, 1, monitor, is_timed_out); } - void jvmti_send_contended_enter_or_entered_monitor_event(jobject monitor, int isEnter) { TRACE2("jvmti.monitor.enter", "Monitor enter event, monitor = " << monitor << " is enter= " << isEnter); diff --git vm/vmcore/src/jvmti/jvmti_extension.cpp vm/vmcore/src/jvmti/jvmti_extension.cpp index 401ff67..5b65f2e 100644 --- vm/vmcore/src/jvmti/jvmti_extension.cpp +++ vm/vmcore/src/jvmti/jvmti_extension.cpp @@ -15,7 +15,7 @@ */ /** * @author Gregory Shimansky - * @version $Revision: 1.1.2.1.4.5 $ + * @version $Revision$ */ /* * JVMTI extensions API @@ -40,13 +40,25 @@ static const jint extensions_number = 0; static void free_allocated_extension_array(jvmtiExtensionFunctionInfo *array, jint number) { - for (int iii = 0; iii < number; iii++) + for (int iii = 0; iii <= number; iii++) { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - _deallocate((unsigned char *)array[iii].params->name); - _deallocate((unsigned char *)array[iii].params); - _deallocate((unsigned char *)array[iii].errors); + if (array[iii].id) + _deallocate((unsigned char *)array[iii].id); + if (array[iii].short_description) + _deallocate((unsigned char *)array[iii].short_description); + if (array[iii].errors) + _deallocate((unsigned char *)array[iii].errors); + + if (array[iii].params) + { + for (int jjj = 0; jjj < array[iii].param_count; jjj++) + { + if (array[iii].params[jjj].name) + _deallocate((unsigned char *)array[iii].params[jjj].name); + } + + _deallocate((unsigned char *)array[iii].params); + } } _deallocate((unsigned char *)array); } @@ -84,89 +96,89 @@ jvmtiGetExtensionFunctions(jvmtiEnv* env *extension_count_ptr = extensions_number; if (0 == extensions_number) + { *extensions = NULL; - else + return JVMTI_ERROR_NONE; + } + + jvmtiExtensionFunctionInfo *array; + size_t arr_size = sizeof(jvmtiExtensionFunctionInfo)*extensions_number; + errorCode = _allocate(arr_size, (unsigned char **)&array); + + if (JVMTI_ERROR_NONE != errorCode) + return errorCode; + + memset(array, 0, arr_size); + + JvmtiExtension *ex = jvmti_extension_list; + for (int iii = 0; iii < extensions_number; iii++) { - jvmtiExtensionFunctionInfo *array; - errorCode = _allocate(sizeof(jvmtiExtensionFunctionInfo) * - extensions_number, (unsigned char **)&array); + jvmtiExtensionFunctionInfo *info = &ex->info; + + array[iii].func = info->func; + array[iii].param_count = info->param_count; + array[iii].error_count = info->error_count; + errorCode = _allocate(strlen(info->id) + 1, + (unsigned char **)&(array[iii].id)); if (JVMTI_ERROR_NONE != errorCode) + { + free_allocated_extension_array(array, iii); return errorCode; + } - JvmtiExtension *ex = jvmti_extension_list; - for (int iii = 0; iii < extensions_number; iii++) + errorCode = _allocate(strlen(info->short_description) + 1, + (unsigned char **)&(array[iii].short_description)); + if (JVMTI_ERROR_NONE != errorCode) { - jvmtiExtensionFunctionInfo *info = &ex->info; - - array[iii].func = info->func; - array[iii].param_count = info->param_count; - array[iii].error_count = info->error_count; + free_allocated_extension_array(array, iii); + return errorCode; + } - errorCode = _allocate(strlen(info->id) + 1, - (unsigned char **)&(array[iii].id)); - if (JVMTI_ERROR_NONE != errorCode) - { - free_allocated_extension_array(array, iii); - return errorCode; - } + errorCode = _allocate(info->param_count * sizeof(jvmtiParamInfo), + (unsigned char **)&(array[iii].params)); + if (JVMTI_ERROR_NONE != errorCode) + { + free_allocated_extension_array(array, iii); + return errorCode; + } - errorCode = _allocate(strlen(info->short_description) + 1, - (unsigned char **)&(array[iii].short_description)); - if (JVMTI_ERROR_NONE != errorCode) - { - _deallocate((unsigned char *)array[iii].id); - free_allocated_extension_array(array, iii); - return errorCode; - } + errorCode = _allocate(info->error_count * sizeof(jvmtiError), + (unsigned char **)&(array[iii].errors)); + if (JVMTI_ERROR_NONE != errorCode) + { + free_allocated_extension_array(array, iii); + return errorCode; + } - errorCode = _allocate(info->param_count * sizeof(jvmtiParamInfo), - (unsigned char **)&(array[iii].params)); - if (JVMTI_ERROR_NONE != errorCode) - { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - free_allocated_extension_array(array, iii); - return errorCode; - } + memset(array[iii].params, 0, + info->param_count * sizeof(jvmtiParamInfo)); - errorCode = _allocate(strlen(info->params->name) + 1, - (unsigned char **)&(array[iii].params->name)); - if (JVMTI_ERROR_NONE != errorCode) - { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - _deallocate((unsigned char *)array[iii].params); - free_allocated_extension_array(array, iii); - return errorCode; - } + for (int jjj = 0; jjj < info->param_count; jjj++) + { + array[iii].params[jjj] = info->params[jjj]; - errorCode = _allocate(info->error_count * sizeof(jvmtiError), - (unsigned char **)&(array[iii].errors)); + errorCode = _allocate(strlen(info->params[jjj].name) + 1, + (unsigned char **)&(array[iii].params[jjj].name)); if (JVMTI_ERROR_NONE != errorCode) { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - _deallocate((unsigned char *)array[iii].params->name); - _deallocate((unsigned char *)array[iii].params); + array[iii].params[jjj].name = NULL; free_allocated_extension_array(array, iii); return errorCode; } - strcpy(array[iii].id, info->id); - strcpy(array[iii].short_description, info->short_description); - strcpy(array[iii].params->name, info->params->name); - memcpy(array[iii].params, info->params, - info->param_count * sizeof(jvmtiParamInfo)); - memcpy(array[iii].errors, info->errors, - info->error_count * sizeof(jvmtiError)); - - ex = ex->next; + strcpy(array[iii].params[jjj].name, info->params[jjj].name); } - *extensions = array; + strcpy(array[iii].id, info->id); + strcpy(array[iii].short_description, info->short_description); + memcpy(array[iii].errors, info->errors, + info->error_count * sizeof(jvmtiError)); + + ex = ex->next; } + *extensions = array; return JVMTI_ERROR_NONE; } @@ -183,12 +195,23 @@ static const jint extensions_events_numb static void free_allocated_extension_event_array(jvmtiExtensionEventInfo *array, jint number) { - for (int iii = 0; iii < number; iii++) + for (jint iii = 0; iii <= number; iii++) { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - _deallocate((unsigned char *)array[iii].params->name); - _deallocate((unsigned char *)array[iii].params); + if (array[iii].id) + _deallocate((unsigned char *)array[iii].id); + if (array[iii].short_description) + _deallocate((unsigned char *)array[iii].short_description); + + if (array[iii].params) + { + for (jint jjj = 0; jjj < array[iii].param_count; jjj++) + { + if (array[iii].params[jjj].name) + _deallocate((unsigned char *)array[iii].params[jjj].name); + } + + _deallocate((unsigned char *)array[iii].params); + } } _deallocate((unsigned char *)array); } @@ -226,74 +249,78 @@ jvmtiGetExtensionEvents(jvmtiEnv* env, *extension_count_ptr = extensions_events_number; if (0 == extensions_events_number) + { *extensions = NULL; - else + return JVMTI_ERROR_NONE; + } + + jvmtiExtensionEventInfo *array; + size_t arr_size = sizeof(jvmtiExtensionEventInfo)*extensions_events_number; + errorCode = _allocate(arr_size, (unsigned char **)&array); + + if (JVMTI_ERROR_NONE != errorCode) + return errorCode; + + memset(array, 0, arr_size); + + JvmtiExcensionEvent *ex = jvmti_exntension_event_list; + for (int iii = 0; iii < extensions_events_number; iii++) { - jvmtiExtensionEventInfo *array; - errorCode = _allocate(sizeof(jvmtiExtensionEventInfo) * - extensions_events_number, (unsigned char **)&array); + jvmtiExtensionEventInfo *info = &ex->info; + + array[iii].extension_event_index = info->extension_event_index; + array[iii].param_count = info->param_count; + errorCode = _allocate(strlen(info->id) + 1, + (unsigned char **)&(array[iii].id)); if (JVMTI_ERROR_NONE != errorCode) + { + free_allocated_extension_event_array(array, iii); return errorCode; + } - JvmtiExcensionEvent *ex = jvmti_exntension_event_list; - for (int iii = 0; iii < extensions_events_number; iii++) + errorCode = _allocate(strlen(info->short_description) + 1, + (unsigned char **)&(array[iii].short_description)); + if (JVMTI_ERROR_NONE != errorCode) { - jvmtiExtensionEventInfo *info = &ex->info; - - array[iii].extension_event_index = info->extension_event_index; - array[iii].param_count = info->param_count; + free_allocated_extension_event_array(array, iii); + return errorCode; + } - errorCode = _allocate(strlen(info->id) + 1, - (unsigned char **)&(array[iii].id)); - if (JVMTI_ERROR_NONE != errorCode) - { - free_allocated_extension_event_array(array, iii); - return errorCode; - } + errorCode = _allocate(info->param_count * sizeof(jvmtiParamInfo), + (unsigned char **)&(array[iii].params)); + if (JVMTI_ERROR_NONE != errorCode) + { + free_allocated_extension_event_array(array, iii); + return errorCode; + } - errorCode = _allocate(strlen(info->short_description) + 1, - (unsigned char **)&(array[iii].short_description)); - if (JVMTI_ERROR_NONE != errorCode) - { - _deallocate((unsigned char *)array[iii].id); - free_allocated_extension_event_array(array, iii); - return errorCode; - } + memset(array[iii].params, 0, + info->param_count * sizeof(jvmtiParamInfo)); - errorCode = _allocate(info->param_count * sizeof(jvmtiParamInfo), - (unsigned char **)&(array[iii].params)); - if (JVMTI_ERROR_NONE != errorCode) - { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - free_allocated_extension_event_array(array, iii); - return errorCode; - } + for (int jjj = 0; jjj < info->param_count; jjj++) + { + array[iii].params[jjj] = info->params[jjj]; - errorCode = _allocate(strlen(info->params->name) + 1, - (unsigned char **)&(array[iii].params->name)); + errorCode = _allocate(strlen(info->params[jjj].name) + 1, + (unsigned char **)&(array[iii].params[jjj].name)); if (JVMTI_ERROR_NONE != errorCode) { - _deallocate((unsigned char *)array[iii].id); - _deallocate((unsigned char *)array[iii].short_description); - _deallocate((unsigned char *)array[iii].params); + array[iii].params[jjj].name = NULL; free_allocated_extension_event_array(array, iii); return errorCode; } - strcpy(array[iii].id, info->id); - strcpy(array[iii].short_description, info->short_description); - strcpy(array[iii].params->name, info->params->name); - memcpy(array[iii].params, info->params, - info->param_count * sizeof(jvmtiParamInfo)); - - ex = ex->next; + strcpy(array[iii].params[jjj].name, info->params[jjj].name); } - *extensions = array; + strcpy(array[iii].id, info->id); + strcpy(array[iii].short_description, info->short_description); + + ex = ex->next; } + *extensions = array; return JVMTI_ERROR_NONE; } diff --git vm/vmcore/src/jvmti/jvmti_field.cpp vm/vmcore/src/jvmti/jvmti_field.cpp index fa7527e..9c7f479 100644 --- vm/vmcore/src/jvmti/jvmti_field.cpp +++ vm/vmcore/src/jvmti/jvmti_field.cpp @@ -26,6 +26,7 @@ #include "Class.h" #include "object_handles.h" #include "vm_strings.h" #include "jvmti_utils.h" +#include "jvmti_internal.h" #include "cxxlog.h" #include "suspend_checker.h" @@ -55,7 +56,9 @@ jvmtiGetFieldName(jvmtiEnv* env, CHECK_EVERYTHING(); - if( !klass ) return JVMTI_ERROR_NULL_POINTER; + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + if( !field ) return JVMTI_ERROR_INVALID_FIELDID; // (25) char* fld_name; @@ -119,7 +122,9 @@ jvmtiGetFieldDeclaringClass(jvmtiEnv* en CHECK_EVERYTHING(); - if( !klass ) return JVMTI_ERROR_NULL_POINTER; + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + if( !field ) return JVMTI_ERROR_INVALID_FIELDID; if( !declaring_class_ptr ) return JVMTI_ERROR_NULL_POINTER; @@ -156,7 +161,9 @@ jvmtiGetFieldModifiers(jvmtiEnv* env, CHECK_EVERYTHING(); - if( !klass ) return JVMTI_ERROR_NULL_POINTER; + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + if( !field ) return JVMTI_ERROR_INVALID_FIELDID; if( !modifiers_ptr ) return JVMTI_ERROR_NULL_POINTER; @@ -198,7 +205,9 @@ jvmtiIsFieldSynthetic(jvmtiEnv* env, CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_synthetic_attribute); - if( !klass ) return JVMTI_ERROR_NULL_POINTER; + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + if( !field ) return JVMTI_ERROR_INVALID_FIELDID; if( !is_synthetic_ptr ) return JVMTI_ERROR_NULL_POINTER; diff --git vm/vmcore/src/jvmti/jvmti_general.cpp vm/vmcore/src/jvmti/jvmti_general.cpp index 58448d8..408c32d 100644 --- vm/vmcore/src/jvmti/jvmti_general.cpp +++ vm/vmcore/src/jvmti/jvmti_general.cpp @@ -80,6 +80,10 @@ jvmtiDisposeEnvironment(jvmtiEnv* env) CHECK_EVERYTHING(); + TIEnv *p_env = (TIEnv *)env; + DebugUtilsTI *ti = p_env->vm->vm_env->TI; + LMAutoUnlock lock(&ti->TIenvs_lock); + // Disable all global events for this environment int iii; for (iii = JVMTI_MIN_EVENT_TYPE_VAL; iii < JVMTI_MAX_EVENT_TYPE_VAL; iii++) @@ -102,8 +106,12 @@ jvmtiDisposeEnvironment(jvmtiEnv* env) _deallocate((unsigned char *)threads); } + // Remove all breakpoints set by this environment + ti->brkpntlst_lock._lock(); + ti->remove_all_breakpoints_env(p_env); + ti->brkpntlst_lock._unlock(); + // Remove all capabilities for this environment - TIEnv *p_env = (TIEnv *)env; jvmtiRelinquishCapabilities(env, &p_env->posessed_capabilities); // Remove environment from the global list diff --git vm/vmcore/src/jvmti/jvmti_internal.cpp vm/vmcore/src/jvmti/jvmti_internal.cpp new file mode 100644 index 0000000..8b3240f --- /dev/null +++ vm/vmcore/src/jvmti/jvmti_internal.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Gregory Shimansky + * @version $Revision: $ + */ +/* + * JVMTI internal functions + */ + +#define LOG_DOMAIN "jvmti.internal" +#include "cxxlog.h" + +#include "environment.h" +#include "jvmti_internal.h" + +static Boolean is_valid_instance(jobject obj, Class* clss) +{ + if (NULL == obj) + return false; + + tmn_suspend_disable(); //---------------------------------v + ObjectHandle h = (ObjectHandle)obj; + ManagedObject *mo = h->object; + + // Check that reference pointer points to the heap + if (mo < (ManagedObject *)Class::heap_base || + mo > (ManagedObject *)Class::heap_end) + { + tmn_suspend_enable(); + return false; + } + + // Check that object is an instance of java.lang.Thread or extends it + if (mo->vt() == NULL) + { + tmn_suspend_enable(); + return false; + } + + Class *object_clss = mo->vt()->clss; + Boolean result = class_is_subtype_fast(object_clss->vtable, clss); + tmn_suspend_enable(); //---------------------------------^ + + return result; +} + +Boolean is_valid_thread_object(jthread thread) +{ + return is_valid_instance(thread, VM_Global_State::loader_env->java_lang_Thread_Class); +} + +Boolean is_valid_thread_group_object(jthreadGroup group) +{ + return is_valid_instance(group, VM_Global_State::loader_env->java_lang_ThreadGroup_Class); +} + +Boolean is_valid_class_object(jclass klass) +{ + return is_valid_instance(klass, VM_Global_State::loader_env->JavaLangClass_Class); +} diff --git vm/vmcore/src/jvmti/jvmti_locals.cpp vm/vmcore/src/jvmti/jvmti_locals.cpp old mode 100644 new mode 100755 index e4fc115..4eba49e --- vm/vmcore/src/jvmti/jvmti_locals.cpp +++ vm/vmcore/src/jvmti/jvmti_locals.cpp @@ -102,33 +102,38 @@ GetLocal_checkArgs(jvmtiEnv* env, return JVMTI_ERROR_NONE; } -#define GET_JIT_FRAME_CONTEXT \ - StackIterator *si = si_create_from_native(vm_thread); \ - while (depth > 0 && !si_is_past_end(si)) \ - { \ - if (get_method(si)) \ - depth -= 1 + si_get_inline_depth(si); \ - si_goto_previous(si); \ - } \ - if (si_is_native(si)) \ - { \ - if (thread_suspended) \ - jthread_resume(thread); \ - si_free(si); \ - return JVMTI_ERROR_OPAQUE_FRAME; \ - } \ - \ - if (si_is_past_end(si)) \ - { \ - if (thread_suspended) \ - jthread_resume(thread); \ - si_free(si); \ - return JVMTI_ERROR_NO_MORE_FRAMES; \ - } \ - \ - JitFrameContext *jfc = si_get_jit_context(si); \ - CodeChunkInfo *cci = si_get_code_chunk_info(si); \ - JIT *jit = cci->get_jit(); \ +#define GET_JIT_FRAME_CONTEXT \ + StackIterator *si = si_create_from_native(vm_thread); \ + \ + if (!si_get_method(si)) /* Skip native VM frame */ \ + si_goto_previous(si); \ + \ + while (depth > 0 && !si_is_past_end(si)) \ + { \ + if (si_get_method(si)) \ + depth -= 1 + si_get_inline_depth(si); \ + si_goto_previous(si); \ + } \ + \ + if (si_is_past_end(si)) \ + { \ + if (thread_suspended) \ + jthread_resume(thread); \ + si_free(si); \ + return JVMTI_ERROR_NO_MORE_FRAMES; \ + } \ + \ + if (si_is_native(si)) \ + { \ + if (thread_suspended) \ + jthread_resume(thread); \ + si_free(si); \ + return JVMTI_ERROR_OPAQUE_FRAME; \ + } \ + \ + JitFrameContext *jfc = si_get_jit_context(si); \ + CodeChunkInfo *cci = si_get_code_chunk_info(si); \ + JIT *jit = cci->get_jit(); \ Method *method = cci->get_method(); jvmtiError JNICALL @@ -183,7 +188,7 @@ jvmtiGetLocalObject(jvmtiEnv* env, else { GET_JIT_FRAME_CONTEXT; - ObjectHandle obj; + ManagedObject *obj; tmn_suspend_disable(); OpenExeJpdaError result = jit->get_local_var(method, jfc, slot, @@ -193,7 +198,7 @@ jvmtiGetLocalObject(jvmtiEnv* env, if (result == EXE_ERROR_NONE) { ObjectHandle oh = oh_allocate_local_handle(); - oh->object = obj->object; + oh->object = obj; *value_ptr = oh; } tmn_suspend_enable(); diff --git vm/vmcore/src/jvmti/jvmti_method.cpp vm/vmcore/src/jvmti/jvmti_method.cpp index 7d140b7..c753d28 100644 --- vm/vmcore/src/jvmti/jvmti_method.cpp +++ vm/vmcore/src/jvmti/jvmti_method.cpp @@ -427,13 +427,13 @@ jvmtiGetLocalVariableTable(jvmtiEnv* env */ for( index = 0; index < count; index++) { - String *name, *type; + String *name, *type, *generic_type; jvmtiLocalVariableEntry* entry = *table_ptr + index; method_ptr->get_local_var_entry(index, &(entry->start_location), &(entry->length), &(entry->slot), - &name, &type); + &name, &type, &generic_type); // allocate memory for name len = get_utf8_length_of_8bit( (const uint8*)name->bytes, name->len); result = _allocate( len + 1, (unsigned char**)&pointer ); @@ -456,8 +456,20 @@ jvmtiGetLocalVariableTable(jvmtiEnv* env entry->signature = pointer; // set variable slot - // set variable generic_signature - entry->generic_signature = NULL; + if (generic_type) { + // allocate memory for generic_signature + len = get_utf8_length_of_8bit( (const uint8*)generic_type->bytes, generic_type->len); + result = _allocate( len + 1, (unsigned char**)&pointer ); + if( result != JVMTI_ERROR_NONE ) { + return result; + } + // copy variable generic_signature + utf8_from_8bit( pointer, (const uint8*)generic_type->bytes, generic_type->len); + // set variable generic_signature + entry->generic_signature = pointer; + } else { + entry->generic_signature = NULL; + } } return JVMTI_ERROR_NONE; @@ -515,10 +527,11 @@ jvmtiGetBytecodes(jvmtiEnv* env, TIEnv *p_env = (TIEnv *)env; DebugUtilsTI *ti = p_env->vm->vm_env->TI; + LMAutoUnlock lock(&ti->brkpntlst_lock); + if (!ti->have_breakpoint(method)) return JVMTI_ERROR_NONE; - // There are breakpoint in this method for (BreakPoint* bpt = ti->find_first_bpt(method); bpt; bpt = ti->find_next_bpt(bpt, method)) { @@ -664,6 +677,14 @@ void jvmti_method_enter_callback(Method_ void jvmti_method_exit_callback(Method_Handle method, jvalue* return_value) { - jvmti_process_method_exit_event(reinterpret_cast<jmethodID>(method), - JNI_FALSE, *return_value); + Method *m = reinterpret_cast<Method *>(method); + jmethodID mid = reinterpret_cast<jmethodID>(method); + + if (m->get_return_java_type() != JAVA_TYPE_VOID) + jvmti_process_method_exit_event(mid, JNI_FALSE, *return_value); + else + { + jvalue jv = { 0 }; + jvmti_process_method_exit_event(mid, JNI_FALSE, jv); + } } diff --git vm/vmcore/src/jvmti/jvmti_stack.cpp vm/vmcore/src/jvmti/jvmti_stack.cpp index bc569c0..4198e02 100644 --- vm/vmcore/src/jvmti/jvmti_stack.cpp +++ vm/vmcore/src/jvmti/jvmti_stack.cpp @@ -54,7 +54,7 @@ jint get_thread_stack_depth(VM_thread *t while (!si_is_past_end(si)) { - method = get_method(si); + method = si_get_method(si); if (method) depth += 1 + si_get_inline_depth(si); @@ -69,10 +69,10 @@ jint get_thread_stack_depth(VM_thread *t Class *clss = method_get_class(method); assert(clss); - if (strcmp(method_get_name(method), "runImpl") == 0 && + if (strcmp(method_get_name(method), "run") == 0 && strcmp(class_get_name(clss), "java/lang/VMStart$MainThread") == 0) { - skip = 4; + skip = 3; } } @@ -186,14 +186,14 @@ jvmtiGetStackTrace(jvmtiEnv* env, StackIterator *si = si_create_from_native(vm_thread); jint count = 0; jint stack_depth = 0; - jint max_depth = depth - skip; + jint max_depth = depth; while (!si_is_past_end(si) && count < max_frame_count && count < max_depth) { jint inlined_depth = si_get_inline_depth(si); if (stack_depth + inlined_depth >= start) { - Method *method = get_method(si); + Method *method = si_get_method(si); if (NULL != method) { CodeChunkInfo *cci = si_get_code_chunk_info(si); @@ -249,9 +249,10 @@ jvmtiGetStackTrace(jvmtiEnv* env, reinterpret_cast<jmethodID>(method); count++; } + + stack_depth++; } } - stack_depth++; si_goto_previous(si); } @@ -693,7 +694,7 @@ jvmtiGetFrameLocation(jvmtiEnv* env, jint inlined_depth = si_get_inline_depth(si); if (stack_depth + inlined_depth >= depth) { - Method *method = get_method(si); + Method *method = si_get_method(si); if (NULL != method) { CodeChunkInfo *cci = si_get_code_chunk_info(si); @@ -744,10 +745,11 @@ jvmtiGetFrameLocation(jvmtiEnv* env, frame_found = true; break; } + + stack_depth++; } } - stack_depth++; si_goto_previous(si); } @@ -836,7 +838,7 @@ jvmtiNotifyFramePop(jvmtiEnv* env, jint current_depth = 0; while (!si_is_past_end(si) && current_depth < depth) { - if (get_method(si)) + if (si_get_method(si)) current_depth += 1 + si_get_inline_depth(si); si_goto_previous(si); @@ -853,7 +855,7 @@ jvmtiNotifyFramePop(jvmtiEnv* env, while (!si_is_past_end(si)) { - if (get_method(si)) + if (si_get_method(si)) current_depth += 1 + si_get_inline_depth(si); si_goto_previous(si); diff --git vm/vmcore/src/jvmti/jvmti_thread.cpp vm/vmcore/src/jvmti/jvmti_thread.cpp index 9465cb0..cd8dd7c 100644 --- vm/vmcore/src/jvmti/jvmti_thread.cpp +++ vm/vmcore/src/jvmti/jvmti_thread.cpp @@ -38,42 +38,12 @@ #include "mon_enter_exit.h" #include "interpreter_exports.h" #include "environment.h" #include "suspend_checker.h" +#include "stack_iterator.h" #define MAX_JVMTI_ENV_NUMBER 10 static JNIEnv * jvmti_test_jenv = jni_native_intf; -Boolean is_valid_thread_object(jthread thread) -{ - if (NULL == thread){ - return false; - } - - tmn_suspend_disable(); //---------------------------------v - ObjectHandle h = (ObjectHandle)thread; - ManagedObject *mo = h->object; - - // Check that reference pointer points to the heap - if (mo < (ManagedObject *)Class::heap_base || - mo > (ManagedObject *)Class::heap_end){ - tmn_suspend_enable(); - return false; - } - - // Check that object is an instance of java.lang.Thread or extends it - if (mo->vt() == NULL){ - tmn_suspend_enable(); - return false; - } - - Class *object_clss = mo->vt()->clss; - Class *thread_class = VM_Global_State::loader_env->java_lang_Thread_Class; - Boolean result = class_is_subtype_fast(object_clss->vtable, thread_class); - tmn_suspend_enable(); //---------------------------------^ - - return result; -} - /* * Get Thread State * @@ -832,7 +802,7 @@ jvmtiGetThreadLocalStorage(jvmtiEnv* env } if ((state & JVMTI_THREAD_STATE_ALIVE) == 0){ return JVMTI_ERROR_THREAD_NOT_ALIVE; -} + } *data_ptr = NULL; @@ -863,3 +833,4 @@ jvmtiGetThreadLocalStorage(jvmtiEnv* env return JVMTI_ERROR_NONE; } + diff --git vm/vmcore/src/jvmti/jvmti_thread_group.cpp vm/vmcore/src/jvmti/jvmti_thread_group.cpp index 7ccde42..c6f1005 100644 --- vm/vmcore/src/jvmti/jvmti_thread_group.cpp +++ vm/vmcore/src/jvmti/jvmti_thread_group.cpp @@ -110,9 +110,8 @@ jvmtiGetThreadGroupInfo(jvmtiEnv* env, CHECK_EVERYTHING(); - if (group == NULL) - { // TBD group is not a thread object - return JVMTI_ERROR_INVALID_THREAD; + if (! is_valid_thread_group_object(group)) { + return JVMTI_ERROR_INVALID_THREAD_GROUP; } if (info_ptr == NULL) @@ -161,8 +160,8 @@ jvmtiGetThreadGroupChildren(jvmtiEnv* en CHECK_EVERYTHING(); - if (group == NULL){ // TBD group is not a thread object - return JVMTI_ERROR_INVALID_THREAD; + if (! is_valid_thread_group_object(group)) { + return JVMTI_ERROR_INVALID_THREAD_GROUP; } if (thread_count_ptr == NULL || threads_ptr == NULL || diff --git vm/vmcore/src/jvmti/jvmti_timer.cpp vm/vmcore/src/jvmti/jvmti_timer.cpp index cbdc4de..b6babf4 100644 --- vm/vmcore/src/jvmti/jvmti_timer.cpp +++ vm/vmcore/src/jvmti/jvmti_timer.cpp @@ -27,6 +27,27 @@ #include "time.h" #include "cxxlog.h" #include "port_sysinfo.h" #include "suspend_checker.h" +#include "jvmti_internal.h" +#include "open/jthread.h" +#include "jvmti.h" +#include <apr_time.h> + +/** +* Sets field values to provided jvmtiTimerInfo structure. +*/ +static inline void fill_timer_info(jvmtiTimerInfo* info_ptr) +{ + info_ptr->max_value = 0xffffffffffffffffULL; // max unsigned long long + info_ptr->may_skip_forward = JNI_FALSE; + info_ptr->may_skip_backward = JNI_FALSE; + +#ifdef PLATFORM_POSIX + // linux api provides only total cpu time measurement :( + info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; +#elif PLATFORM_NT + info_ptr->kind = JVMTI_TIMER_USER_CPU; +#endif +} /* * Get Current Thread CPU Timer Information @@ -45,6 +66,7 @@ jvmtiGetCurrentThreadCpuTimerInfo(jvmtiE jvmtiTimerInfo* UNREF info_ptr) { TRACE2("jvmti.timer", "GetCurrentThreadCpuTimerInfo called"); + // TRACE("GetCurrentThreadCpuTimerInfo called"); SuspendEnabledChecker sec; /* * Check given env & current phase. @@ -53,9 +75,14 @@ jvmtiGetCurrentThreadCpuTimerInfo(jvmtiE CHECK_EVERYTHING(); - //TBD + CHECK_CAPABILITY(can_get_current_thread_cpu_time); + + if (NULL == info_ptr) + return JVMTI_ERROR_NULL_POINTER; + + fill_timer_info(info_ptr); - return JVMTI_NYI; + return JVMTI_ERROR_NONE; } /* @@ -70,17 +97,23 @@ jvmtiGetCurrentThreadCpuTime(jvmtiEnv* e jlong* UNREF nanos_ptr) { TRACE2("jvmti.timer", "GetCurrentThreadCpuTime called"); + IDATA status; SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; - CHECK_EVERYTHING(); - //TBD + CHECK_CAPABILITY(can_get_current_thread_cpu_time); - return JVMTI_NYI; + if (NULL == nanos_ptr) + return JVMTI_ERROR_NULL_POINTER; + status=jthread_get_thread_cpu_time(jthread_self(),nanos_ptr); + if (status!=TM_ERROR_NONE) + return JVMTI_ERROR_INTERNAL; + + return JVMTI_ERROR_NONE; } /* @@ -105,9 +138,14 @@ jvmtiGetThreadCpuTimerInfo(jvmtiEnv* env CHECK_EVERYTHING(); - //TBD + CHECK_CAPABILITY(can_get_thread_cpu_time); + + if (NULL == info_ptr) + return JVMTI_ERROR_NULL_POINTER; - return JVMTI_NYI; + fill_timer_info(info_ptr); + + return JVMTI_ERROR_NONE; } /* @@ -123,7 +161,8 @@ jvmtiGetThreadCpuTime(jvmtiEnv* env, jlong* UNREF nanos_ptr) { TRACE2("jvmti.timer", "GetThreadCpuTime called"); - SuspendEnabledChecker sec; + IDATA status; + SuspendEnabledChecker sec; /* * Check given env & current phase. */ @@ -131,9 +170,44 @@ jvmtiGetThreadCpuTime(jvmtiEnv* env, CHECK_EVERYTHING(); - //TBD + CHECK_CAPABILITY(can_get_thread_cpu_time); - return JVMTI_NYI; + if (NULL == nanos_ptr) + return JVMTI_ERROR_NULL_POINTER; + + if (NULL != thread) + { + if (!is_valid_thread_object(thread)) + return JVMTI_ERROR_INVALID_THREAD; + } + else + thread = jthread_self(); + + // lock thread manager to avoid occasional change of thread state + hythread_global_lock(); + + int state;// =thread_get_thread_state(thread); + jvmtiError err=jvmtiGetThreadState(env,thread,&state); + if (err != JVMTI_ERROR_NONE){ + return err; + } + switch (state) + { + case JVMTI_THREAD_STATE_TERMINATED: // thread is terminated + case JVMTI_JAVA_LANG_THREAD_STATE_NEW: // thread is new + hythread_global_unlock(); + return JVMTI_ERROR_THREAD_NOT_ALIVE; + default: // thread is alive + status=jthread_get_thread_cpu_time(thread,nanos_ptr); + + break; + } + + hythread_global_unlock(); + if (status!=TM_ERROR_NONE) + return JVMTI_ERROR_INTERNAL; + + return JVMTI_ERROR_NONE; } /* @@ -159,9 +233,12 @@ jvmtiGetTimerInfo(jvmtiEnv* env, CHECK_EVERYTHING(); - //TBD + if (NULL == info_ptr) + return JVMTI_ERROR_NULL_POINTER; + + fill_timer_info(info_ptr); - return JVMTI_NYI; + return JVMTI_ERROR_NONE; } /* @@ -188,12 +265,10 @@ jvmtiGetTime(jvmtiEnv* env, { return JVMTI_ERROR_NULL_POINTER; } + // get time in milliseconds + apr_time_t apr_time = apr_time_now(); - time_t value = 0; - - time( &value ); - - *nanos_ptr = value * 1000000000UL; + *nanos_ptr = ((jlong) apr_time) * 1000ULL; // convert to nanos return JVMTI_ERROR_NONE; } diff --git vm/vmcore/src/jvmti/jvmti_watch.cpp vm/vmcore/src/jvmti/jvmti_watch.cpp index a6d3a49..67ebd5a 100644 --- vm/vmcore/src/jvmti/jvmti_watch.cpp +++ vm/vmcore/src/jvmti/jvmti_watch.cpp @@ -13,18 +13,225 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** +/** * @author Gregory Shimansky * @version $Revision: 1.1.2.1.4.4 $ - */ + */ /* * JVMTI watchpoints API */ +#define LOG_DOMAIN "jvmti.watch" + +//#include "environment.h" +//#include "jvmti_direct.h" +//#include "jvmti_utils.h" +//#include "jvmti_internal.h" +//#include "cxxlog.h" +//#include "suspend_checker.h" + +#include <string.h> +#include "Class.h" +#include "vm_strings.h" #include "jvmti_direct.h" +#include "Class.h" +#include "object_handles.h" #include "jvmti_utils.h" #include "cxxlog.h" + +#include "jvmti_interface.h" #include "suspend_checker.h" +#include "jvmti_internal.h" +#include "environment.h" + + +enum Watch_Type +{ + ACCESS, + MODIFICATION +}; + +static jvmtiError set_field_watch(jvmtiEnv* env, jclass klass, jfieldID field, Watch_Type watch_type) +{ + SuspendEnabledChecker sec; + /* + * Check given env & current phase. + */ + jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; + + CHECK_EVERYTHING(); + + switch (watch_type) + { + case ACCESS: + CHECK_CAPABILITY(can_generate_field_access_events); + break; + + case MODIFICATION: + CHECK_CAPABILITY(can_generate_field_modification_events); + break; + } + + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + + if (! field) + return JVMTI_ERROR_INVALID_FIELDID; + + TIEnv *p_env = (TIEnv *)env; + DebugUtilsTI *ti = p_env->vm->vm_env->TI; + + Watch** p_watch_list; + switch (watch_type) + { + case ACCESS: + p_watch_list = ti->get_access_watch_list(); + break; + + case MODIFICATION: + p_watch_list = ti->get_modification_watch_list(); + break; + } + + // Find watch for this field if it exists already + Watch *w = ti->find_watch(p_watch_list, field); + + jvmtiError errorCode; + + if (NULL == w) + { + errorCode = _allocate(sizeof(Watch), (unsigned char **)&w); + if (JVMTI_ERROR_NONE != errorCode) + return errorCode; + + TIEnvList *el; + errorCode = _allocate(sizeof(TIEnvList), (unsigned char **)&el); + if (JVMTI_ERROR_NONE != errorCode) + { + _deallocate((unsigned char *)w); + return errorCode; + } + + w->field = field; + w->next = NULL; + w->envs = NULL; + + el->env = p_env; + w->add_env(el); + ti->add_watch(p_watch_list, w); + + // enable field tracking + switch (watch_type) + { + case ACCESS: + ((Field*) field)->set_track_access(true); + break; + + case MODIFICATION: + ((Field*) field)->set_track_modification(true); + break; + } + } + else + { + if (NULL != w->find_env(p_env)) + return JVMTI_ERROR_DUPLICATE; + + TIEnvList *el; + errorCode = _allocate(sizeof(TIEnvList), (unsigned char **)&el); + if (JVMTI_ERROR_NONE != errorCode) + return errorCode; + + el->env = p_env; + w->add_env(el); + } + + switch (watch_type) + { + case ACCESS: + TRACE("SetFieldAccessWatch successfull"); + break; + + case MODIFICATION: + TRACE("SetFieldModificationWatch successfull"); + break; + } + + return JVMTI_ERROR_NONE; +} // set_field_watch + +static jvmtiError clear_field_watch(jvmtiEnv* env, jclass klass, jfieldID field, Watch_Type watch_type) +{ + SuspendEnabledChecker sec; + /* + * Check given env & current phase. + */ + jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; + + CHECK_EVERYTHING(); + + switch (watch_type) + { + case ACCESS: + CHECK_CAPABILITY(can_generate_field_access_events); + break; + + case MODIFICATION: + CHECK_CAPABILITY(can_generate_field_modification_events); + break; + } + + if (! is_valid_class_object(klass)) + return JVMTI_ERROR_INVALID_CLASS; + + if (! field) + return JVMTI_ERROR_INVALID_FIELDID; + + TIEnv *p_env = (TIEnv *)env; + DebugUtilsTI *ti = p_env->vm->vm_env->TI; + + Watch** p_watch_list; + switch (watch_type) + { + case ACCESS: + p_watch_list = ti->get_access_watch_list(); + break; + + case MODIFICATION: + p_watch_list = ti->get_modification_watch_list(); + break; + } + + // Find watch for this field if it exists already + Watch *w = ti->find_watch(p_watch_list, field); + + if (NULL == w) + return JVMTI_ERROR_NOT_FOUND; + + TIEnvList *el = w->find_env(p_env); + if (NULL == el) + return JVMTI_ERROR_NOT_FOUND; + + w->remove_env(el); + if (NULL == w->envs) + { + // disable field tracking + switch (watch_type) + { + case ACCESS: + ((Field*) field)->set_track_access(false); + break; + + case MODIFICATION: + ((Field*) field)->set_track_modification(false); + break; + } + + ti->remove_watch(p_watch_list, w); + } + + return JVMTI_ERROR_NONE; +} // clear_field_watch /* * Set Field Access Watch @@ -36,21 +243,12 @@ #include "suspend_checker.h" */ jvmtiError JNICALL jvmtiSetFieldAccessWatch(jvmtiEnv* env, - jclass UNREF klass, - jfieldID UNREF field) + jclass klass, + jfieldID field) { - TRACE2("jvmti.watch", "SetFieldAccessWatch called"); - SuspendEnabledChecker sec; - /* - * Check given env & current phase. - */ - jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; - - CHECK_EVERYTHING(); - - //TBD + TRACE("SetFieldAccessWatch called"); - return JVMTI_NYI; + return set_field_watch(env, klass, field, ACCESS); } /* @@ -63,21 +261,12 @@ jvmtiSetFieldAccessWatch(jvmtiEnv* env, */ jvmtiError JNICALL jvmtiClearFieldAccessWatch(jvmtiEnv* env, - jclass UNREF klass, - jfieldID UNREF field) + jclass klass, + jfieldID field) { - TRACE2("jvmti.watch", "ClearFieldAccessWatch called"); - SuspendEnabledChecker sec; - /* - * Check given env & current phase. - */ - jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; - - CHECK_EVERYTHING(); + TRACE("ClearFieldAccessWatch called"); - //TBD - - return JVMTI_NYI; + return clear_field_watch(env, klass, field, ACCESS); } /* @@ -90,21 +279,12 @@ jvmtiClearFieldAccessWatch(jvmtiEnv* env */ jvmtiError JNICALL jvmtiSetFieldModificationWatch(jvmtiEnv* env, - jclass UNREF klass, - jfieldID UNREF field) + jclass klass, + jfieldID field) { - TRACE2("jvmti.watch", "SetFieldModificationWatch called"); - SuspendEnabledChecker sec; - /* - * Check given env & current phase. - */ - jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; - - CHECK_EVERYTHING(); - - //TBD + TRACE("SetFieldModificationWatch called"); - return JVMTI_NYI; + return set_field_watch(env, klass, field, MODIFICATION); } /* @@ -118,20 +298,29 @@ jvmtiSetFieldModificationWatch(jvmtiEnv* */ jvmtiError JNICALL jvmtiClearFieldModificationWatch(jvmtiEnv* env, - jclass UNREF klass, - jfieldID UNREF field) + jclass klass, + jfieldID field) { - TRACE2("jvmti.watch", "ClearFieldModificationWatch called"); - SuspendEnabledChecker sec; - /* - * Check given env & current phase. - */ - jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; + TRACE("ClearFieldModificationWatch called"); - CHECK_EVERYTHING(); - - //TBD + return clear_field_watch(env, klass, field, MODIFICATION); +} - return JVMTI_NYI; +void jvmti_field_access_callback(Field_Handle field, + Method_Handle method, + jlocation location, + jobject* object) +{ + jvmti_process_field_access_event(field, (jmethodID) method, location, + object); } +void jvmti_field_modification_callback(Field_Handle field, + Method_Handle method, + jlocation location, + jobject* object, + jvalue* new_value) +{ + jvmti_process_field_modification_event(field, (jmethodID) method, location, + object, *new_value); +} diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java old mode 100644 new mode 100755 index 47af843..916b83f --- vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java @@ -15,8 +15,14 @@ */ package java.lang; +import static org.apache.harmony.vm.ClassFormat.ACC_ANNOTATION; +import static org.apache.harmony.vm.ClassFormat.ACC_ENUM; +import static org.apache.harmony.vm.ClassFormat.ACC_INTERFACE; +import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC; + import java.io.InputStream; import java.io.Serializable; +import java.lang.ref.SoftReference; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -26,9 +32,13 @@ import java.lang.reflect.Modifier; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.GenericSignatureFormatError; +import java.lang.reflect.MalformedParameterizedTypeException; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; import java.net.URL; import java.security.AccessController; @@ -37,18 +47,42 @@ import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Map; + + +import org.apache.harmony.lang.reflect.parser.InterimClassGenericDecl; +import org.apache.harmony.lang.reflect.parser.Parser; +import org.apache.harmony.lang.reflect.parser.Parser.SignatureKind; +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimType; +import org.apache.harmony.lang.reflect.parser.InterimClassType; +import org.apache.harmony.lang.reflect.parser.InterimTypeParameter; + +import org.apache.harmony.lang.reflect.repository.TypeVariableRepository; +import org.apache.harmony.lang.reflect.repository.ParameterizedTypeRepository; + +import org.apache.harmony.lang.reflect.support.AuxiliaryChecker; +import org.apache.harmony.lang.reflect.support.AuxiliaryLoader; +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; +import org.apache.harmony.lang.reflect.support.AuxiliaryCreator; +import org.apache.harmony.lang.reflect.support.AuxiliaryUtil; + +import org.apache.harmony.lang.reflect.implementation.TypeVariableImpl; +import org.apache.harmony.lang.reflect.implementation.ParameterizedTypeImpl; + import org.apache.harmony.lang.RuntimePermissionCollection; import org.apache.harmony.lang.reflect.Reflection; import org.apache.harmony.vm.VMStack; +import org.apache.harmony.vm.VMGenericsAndAnnotations; /** * @com.intel.drl.spec_ref * - * @author Evgueni Brevnov + * @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov * @version $Revision: 1.1.2.2.4.5 $ */ //public final class Class implements Serializable { @@ -63,6 +97,18 @@ public final class Class<T> implements S // TODO make it soft reference transient ReflectionData reflectionData; + transient SoftReference<GACache> softCache; + + private GACache getCache() { + GACache cache = null; + if (softCache != null) { + cache = softCache.get(); + } + if (cache == null) { + softCache = new SoftReference<GACache>(cache = new GACache()); + } + return cache; + } /** * Only VM can instantiate this class. @@ -73,7 +119,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public static Class forName(String name) throws ClassNotFoundException { + public static Class<?> forName(String name) throws ClassNotFoundException { return forName(name, true, VMClassRegistry.getClassLoader(VMStack .getCallerClass(0))); } @@ -81,7 +127,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public static Class forName(String name, boolean initialize, + public static Class<?> forName(String name, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException { Class clazz = null; int i = 0; @@ -171,57 +217,75 @@ public final class Class<T> implements S } /** - * @com.intel.drl.spec_ref + * package private to access from the java.lang.ClassLoader class. + */ + static volatile boolean disableAssertions = + VMExecutionEngine.getAssertionStatus(null, false, 0) <= 0; + + /** + * @com.intel.drl.spec_ref */ public boolean desiredAssertionStatus() { - if (!ClassLoader.enableAssertions) { + if (disableAssertions) { return false; } - ClassLoader classLoader = VMClassRegistry.getClassLoader(this); - String topLevelName = getTopLevelClassName(); - int systemStatus = 0; - if (classLoader != null) { - synchronized (classLoader.classAssertionStatus) { - Object status = classLoader.classAssertionStatus - .get(topLevelName); + + ClassLoader loader = VMClassRegistry.getClassLoader(this); + if (loader == null) { + // system class, status is controlled via cmdline only + return VMExecutionEngine.getAssertionStatus(this, true, 0) > 0; + } + + // First check exact class name + String name = null; + Map<String, Boolean> m = loader.classAssertionStatus; + if (m != null && m.size() != 0) + { + name = getTopLevelClassName(); + Boolean status = m.get(name); + if (status != null) { + return status.booleanValue(); + } + } + if (!loader.clearAssertionStatus) { + int systemStatus = VMExecutionEngine.getAssertionStatus(this, false, 0); + if (systemStatus != 0) { + return systemStatus > 0; + } + } + + // Next try (super)packages name(s) recursively + m = loader.packageAssertionStatus; + if (m != null && m.size() != 0) { + if (name == null) { + name = getName(); + } + name = getParentName(name); + // if this class is in the default package, + // it is checked in the 1st iteration + do { + Boolean status = m.get(name); if (status != null) { - return ((Boolean)status).booleanValue(); - } - systemStatus = VMExecutionEngine - .getAssertionStatus(topLevelName); - if (systemStatus != 0) { - return systemStatus > 0; - } - while ( (topLevelName = getParentName(topLevelName)).length() > 0) { - status = classLoader.packageAssertionStatus - .get(topLevelName); - if (status != null) { - return ((Boolean)status).booleanValue(); - } - } - while ( (topLevelName = getParentName(topLevelName)).length() > 0) { - if ( (systemStatus = VMExecutionEngine - .getAssertionStatus(topLevelName)) != 0) { - return systemStatus > 0; - } + return status.booleanValue(); } - return classLoader.defaultAssertionStatus; - } + } while ( (name = getParentName(name)).length() > 0); } - // classLoader == null - do { - if ( (systemStatus = VMExecutionEngine - .getAssertionStatus(topLevelName)) != 0) { + if (!loader.clearAssertionStatus) { + int systemStatus = VMExecutionEngine.getAssertionStatus(this, true, + loader.defaultAssertionStatus); + if (systemStatus != 0) { return systemStatus > 0; } - } while ( (topLevelName = getParentName(topLevelName)).length() > 0); - return false; + } + + // Finally check the default status + return loader.defaultAssertionStatus > 0; } /** * @com.intel.drl.spec_ref * - * Note: We don't check member acces permission for each super class. + * Note: We don't check member access permission for each super class. * Java 1.5 API specification doesn't require this check. */ public Class[] getClasses() { @@ -229,10 +293,27 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicClasses == null) { - reflectionData.initPublicClasses(); + Class clss = this; + ArrayList<Class> classes = null; + while (clss != null) { + Class[] declared = VMClassRegistry.getDeclaredClasses(clss); + if (declared.length != 0) { + if (classes == null) { + classes = new ArrayList<Class>(); + } + for (Class c : declared) { + if (Modifier.isPublic(c.getModifiers())) { + classes.add(c); + } + } + } + clss = clss.getSuperclass(); + } + if (classes == null) { + return new Class[0]; + } else { + return classes.toArray(new Class[classes.size()]); } - return (Class[])reflectionData.publicClasses.clone(); } /** @@ -254,27 +335,27 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Class getComponentType() { + public Class<?> getComponentType() { return VMClassRegistry.getComponentType(this); } /** * @com.intel.drl.spec_ref */ - public Constructor getConstructor(Class[] argumentTypes) + public Constructor<T> getConstructor(Class... argumentTypes) throws NoSuchMethodException { if (reflectionData == null) { initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicConstructors == null) { - reflectionData.initPublicConstructors(); - } - for (int i = 0; i < reflectionData.publicConstructors.length; i++) { - Constructor c = reflectionData.publicConstructors[i]; - if (isTypeMatches(argumentTypes, c.getParameterTypes())) { - return Reflection.copyConstructor(c); - } + Constructor<T> ctors[] = reflectionData.getPublicConstructors(); + for (int i = 0; i < ctors.length; i++) { + Constructor<T> c = ctors[i]; + try { + if (isTypeMatches(argumentTypes, c.getParameterTypes())) { + return Reflection.copyConstructor(c); + } + } catch (LinkageError ignore) {} } throw new NoSuchMethodException(getName() + printMethodSignature(argumentTypes)); @@ -289,10 +370,7 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicConstructors == null) { - reflectionData.initPublicConstructors(); - } - return Reflection.copyConstructors(reflectionData.publicConstructors); + return Reflection.copyConstructors(reflectionData.getPublicConstructors()); } /** @@ -303,16 +381,13 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.DECLARED); - if (reflectionData.declaredClasses == null) { - reflectionData.initDeclaredClasses(); - } - return (Class[])reflectionData.declaredClasses.clone(); + return VMClassRegistry.getDeclaredClasses(this); } /** * @com.intel.drl.spec_ref */ - public Constructor getDeclaredConstructor(Class[] argumentTypes) + public Constructor<T> getDeclaredConstructor(Class... argumentTypes) throws NoSuchMethodException { if (reflectionData == null) { initReflectionData(); @@ -373,7 +448,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Method getDeclaredMethod(String methodName, Class[] argumentTypes) + public Method getDeclaredMethod(String methodName, Class... argumentTypes) throws NoSuchMethodException { if (reflectionData == null) { initReflectionData(); @@ -404,7 +479,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Class getDeclaringClass() { + public Class<?> getDeclaringClass() { return VMClassRegistry.getDeclaringClass(this); } @@ -416,11 +491,8 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicFields == null) { - reflectionData.initPublicFields(); - } - for (int i = 0; i < reflectionData.publicFields.length; i++) { - Field f = reflectionData.publicFields[i]; + Field[] ff = reflectionData.getPublicFields(); + for (Field f : ff) { if (fieldName.equals(f.getName())) { return Reflection.copyField(f); } @@ -436,10 +508,7 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicFields == null) { - reflectionData.initPublicFields(); - } - return Reflection.copyFields(reflectionData.publicFields); + return Reflection.copyFields(reflectionData.getPublicFields()); } /** @@ -452,17 +521,14 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Method getMethod(String methodName, Class[] argumentTypes) + public Method getMethod(String methodName, Class... argumentTypes) throws NoSuchMethodException { if (reflectionData == null) { initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicMethods == null) { - reflectionData.initPublicMethods(); - } return Reflection - .copyMethod(findMatchingMethod(reflectionData.publicMethods, + .copyMethod(findMatchingMethod(reflectionData.getPublicMethods(), methodName, argumentTypes)); } @@ -474,24 +540,31 @@ public final class Class<T> implements S initReflectionData(); } checkMemberAccess(Member.PUBLIC); - if (reflectionData.publicMethods == null) { - reflectionData.initPublicMethods(); - } - return Reflection.copyMethods(reflectionData.publicMethods); + return Reflection.copyMethods(reflectionData.getPublicMethods()); } /** * @com.intel.drl.spec_ref */ public int getModifiers() { - return VMClassRegistry.getModifiers(this); + if (reflectionData == null) { + initReflectionData(); + } + int mods = reflectionData.modifiers; + if (mods == -1) { + mods = reflectionData.modifiers = VMClassRegistry.getModifiers(this); + } + return mods; } /** * @com.intel.drl.spec_ref */ public String getName() { - return VMClassRegistry.getName(this); + if (reflectionData == null) { + initReflectionData(); + } + return reflectionData.name; } /** @@ -570,7 +643,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Class getSuperclass() { + public Class<? super T> getSuperclass() { return VMClassRegistry.getSuperclass(this); } @@ -584,7 +657,7 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public boolean isAssignableFrom(Class clazz) { + public boolean isAssignableFrom(Class<?> clazz) { return VMClassRegistry.isAssignableFrom(this, clazz); } @@ -599,7 +672,7 @@ public final class Class<T> implements S * @com.intel.drl.spec_ref */ public boolean isInterface() { - return VMClassRegistry.isInterface(this); + return (getModifiers() & ACC_INTERFACE) != 0; } /** @@ -612,9 +685,9 @@ public final class Class<T> implements S /** * @com.intel.drl.spec_ref */ - public Object newInstance() throws InstantiationException, + public T newInstance() throws InstantiationException, IllegalAccessException { - Object newInstance = null; + T newInstance = null; if (reflectionData == null) { initReflectionData(); } @@ -626,9 +699,9 @@ public final class Class<T> implements S try { if (reflectionData.defaultConstructor == null) { reflectionData.initDefaultConstructor(); - final Constructor c = reflectionData.defaultConstructor; + final Constructor<T> c = reflectionData.defaultConstructor; try { - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { c.setAccessible(true); @@ -648,7 +721,7 @@ public final class Class<T> implements S reflectionData.defaultConstructor.getDeclaringClass(), reflectionData.defaultConstructor.getModifiers() ); - newInstance = reflectionData.defaultConstructor.newInstance(null); + newInstance = reflectionData.defaultConstructor.newInstance(); } catch (NoSuchMethodException e) { throw new InstantiationException(e.getMessage() + " method not found"); @@ -704,12 +777,10 @@ public final class Class<T> implements S String getPackageName() { - if (reflectionData != null) { - return reflectionData.packageName; + if (reflectionData == null) { + initReflectionData(); } - String className = getName(); - int dotPosition = className.lastIndexOf('.'); - return dotPosition == -1 ? "" : className.substring(0, dotPosition); + return reflectionData.packageName; } void setProtectionDomain(ProtectionDomain protectionDomain) { @@ -726,12 +797,14 @@ public final class Class<T> implements S .getDeclaringClass()) { return matcher; } - if (methodName.equals(m.getName()) - && isTypeMatches(argumentTypes, m.getParameterTypes()) - && (matcher == null || matcher.getReturnType() - .isAssignableFrom(m.getReturnType()))) { - matcher = m; - } + try { + if (methodName.equals(m.getName()) + && isTypeMatches(argumentTypes, m.getParameterTypes()) + && (matcher == null || matcher.getReturnType() + .isAssignableFrom(m.getReturnType()))) { + matcher = m; + } + } catch (LinkageError ignore) {} } if (matcher == null) { throw new NoSuchMethodException(methodName.toString() @@ -777,13 +850,13 @@ public final class Class<T> implements S return resource; } - private Constructor getDeclaredConstructorInternal(Class[] argumentTypes) + private Constructor<T> getDeclaredConstructorInternal(Class[] argumentTypes) throws NoSuchMethodException { if (reflectionData.declaredConstructors == null) { reflectionData.initDeclaredConstructors(); } for (int i = 0; i < reflectionData.declaredConstructors.length; i++) { - Constructor c = reflectionData.declaredConstructors[i]; + Constructor<T> c = reflectionData.declaredConstructors[i]; if (isTypeMatches(argumentTypes, c.getParameterTypes())) { return c; } @@ -799,113 +872,350 @@ public final class Class<T> implements S } - /* IBM SPECIFIC PART*/ + /* VMI SPECIFIC PART*/ final ClassLoader getClassLoaderImpl() { return VMClassRegistry.getClassLoader(this); } - static final native Class[] getStackClasses(int maxDepth, boolean stopAtPrivileged); + static final Class[] getStackClasses(int maxDepth, + boolean stopAtPrivileged) { + return VMStack.getClasses(maxDepth, stopAtPrivileged); + } + + /* END OF VMI SPECIFIC PART */ /** - * TODO - provide real implementation - * @param annotationType - * @return - */ - public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getDeclaredAnnotations() { + Annotation[] declared = getCache().getDeclaredAnnotations(); + Annotation aa[] = new Annotation[declared.length]; + System.arraycopy(declared, 0, aa, 0, declared.length); + return aa; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getAnnotations() { + Annotation[] all = getCache().getAllAnnotations(); + Annotation aa[] = new Annotation[all.length]; + System.arraycopy(all, 0, aa, 0, all.length); + return aa; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + for (Annotation aa : getCache().getAllAnnotations()) { + if(annotationClass == aa.annotationType()) { + return (A)aa; + } + } + return null; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + for (Annotation aa : getCache().getAllAnnotations()) { + if(annotationClass == aa.annotationType()) { + return true; + } + } return false; } /** - * TODO - provide real implementation - * @param annotationType - * @return - */ - public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + * + * @com.intel.drl.spec_ref + * + **/ + @SuppressWarnings("unchecked") + public T[] getEnumConstants() { + if (isEnum()) { + try { + final Method values = getMethod("values"); + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + values.setAccessible(true); + return null; + } + }); + return (T[]) values.invoke(null); + } catch (Exception ignore) {} + } return null; } /** - * TODO - provide real implementatoin - * @return - */ - public Annotation[] getAnnotations() { - return new Annotation[0]; + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isEnum() { + return (getModifiers() & ACC_ENUM) != 0; } /** - * TODO - provide real implementatoin - * @return - */ - public Annotation[] getDeclaredAnnotations() { - return new Annotation[0]; + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isAnnotation() { + return (getModifiers() & ACC_ANNOTATION) != 0; } /** - * TODO - provide real implementatoin - * @return - */ - public TypeVariable<?>[] getTypeParameters() { - return new TypeVariable<?>[0]; + * + * @com.intel.drl.spec_ref + * + **/ + @SuppressWarnings("unchecked") + public <U> Class<? extends U> asSubclass(Class<U> clazz) throws ClassCastException { + if (!VMClassRegistry.isAssignableFrom(clazz, this)) { + throw new ClassCastException(toString()); + } + + return (Class<? extends U>)this; } - /* END OF IBM SPECIFIC PART */ + /** + * + * @com.intel.drl.spec_ref + * + **/ + @SuppressWarnings("unchecked") + public T cast(Object obj) throws ClassCastException { + if (obj != null && !VMClassRegistry.isInstance(this, obj)) { + throw new ClassCastException(obj.getClass().toString()); + } + return (T) obj; + } - private final class ReflectionData { + /** + * + * @com.intel.drl.spec_ref + * + **/ + public TypeVariable<Class<T>>[] getTypeParameters() throws GenericSignatureFormatError { + return (TypeVariable<Class<T>>[])getCache().getTypeParameters().clone(); + } - Class[] declaredClasses; + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Method getEnclosingMethod() { + Member m = VMClassRegistry.getEnclosingMember(this); // see VMClassRegistry.getEnclosingMember() spec + return m instanceof Method? (Method)m : null; + } - Constructor[] declaredConstructors; + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Constructor<?> getEnclosingConstructor() { + Member m = VMClassRegistry.getEnclosingMember(this); // see VMClassRegistry.getEnclosingMember() spec + return m instanceof Constructor ? (Constructor<?>)m : null; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Type[] getGenericInterfaces() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (isArray()) { + return new Type[]{Cloneable.class, Serializable.class}; + } + if (isPrimitive()) { + return new Type[0]; + } + + return (Type[])getCache().getGenericInterfaces().clone(); + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Type getGenericSuperclass() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + String tmp; + if (isInterface() || ((tmp = getCanonicalName()) != null && tmp.equals("java.lang.Object")) || isPrimitive()) { + return null; + } + if (isArray()) { + return (Type) Object.class; + } + + Class clazz = getSuperclass(); + if (clazz.getTypeParameters().length == 0) { + return (Type) clazz; + } + + return getCache().getGenericSuperclass(); + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Class<?> getEnclosingClass() { + return VMClassRegistry.getEnclosingClass(this); // see VMClassRegistry.getEnclosingClass() spec + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isMemberClass() { + return getDeclaringClass() != null; // see Class.getDeclaringClass() spec + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isLocalClass() { + return VMClassRegistry.getEnclosingMember(this) != null && !isAnonymousClass(); // see CFF spec, #4.8.6, first paragraph and VMClassRegistry.getEnclosingMember() spec + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isAnonymousClass() { + return getSimpleName().length() == 0; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isSynthetic() { + return (getModifiers() & ACC_SYNTHETIC) != 0; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public String getCanonicalName() { + if (isLocalClass() || isAnonymousClass()) { + return null; + } + if (isArray()) { + String res = getComponentType().getCanonicalName(); + return res != null ? res + "[]" : null; + } + + StringBuffer sb = new StringBuffer(getPackageName()); + ArrayList<String> sympleNames = new ArrayList<String>(); + Class clss = this; + while ((clss = clss.getDeclaringClass()) != null) { + if (clss.isLocalClass() || clss.isAnonymousClass()) { + return null; + } + sympleNames.add(clss.getSimpleName()); + } + if (sb.length() > 0) { + sb.append("."); + } + for (int i = sympleNames.size() - 1; i > -1 ; i--) { + sb.append(sympleNames.get(i)).append("."); + } + sb.append(getSimpleName()); + + return sb.toString(); + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public String getSimpleName() { +// TODO: the method result should be reusible + return VMClassRegistry.getSimpleName(this); + } + + + private final class ReflectionData { + + String name; + + int modifiers = -1; + + Constructor<T>[] declaredConstructors; Field[] declaredFields; Method[] declaredMethods; - Constructor defaultConstructor; - + Constructor<T> defaultConstructor; + String packageName; - Class[] publicClasses; - - Constructor[] publicConstructors; + Constructor<T>[] publicConstructors; Field[] publicFields; Method[] publicMethods; - + public ReflectionData() { - packageName = Class.getParentName(Class.this.getName()); + name = VMClassRegistry.getName(Class.this); + packageName = Class.getParentName(name); } - - public synchronized void initDeclaredClasses() { - if (declaredClasses == null) { - declaredClasses = VMClassRegistry - .getDeclaredClasses(Class.this); - } - } - - public synchronized void initDeclaredConstructors() { + + public void initDeclaredConstructors() { if (declaredConstructors == null) { declaredConstructors = VMClassRegistry .getDeclaredConstructors(Class.this); } } - public synchronized void initDeclaredFields() { + public void initDeclaredFields() { if (declaredFields == null) { declaredFields = VMClassRegistry .getDeclaredFields(Class.this); } } - public synchronized void initDeclaredMethods() { + public void initDeclaredMethods() { if (declaredMethods == null) { declaredMethods = VMClassRegistry .getDeclaredMethods(Class.this); } } - public synchronized void initDefaultConstructor() + public void initDefaultConstructor() throws NoSuchMethodException { if (defaultConstructor == null) { defaultConstructor = Class.this @@ -913,68 +1223,32 @@ public final class Class<T> implements S } } - public synchronized void initPublicClasses() { - if (publicClasses != null) { - return; - } - if (declaredClasses == null) { - initDeclaredClasses(); - } - - int size = declaredClasses.length; - Class superClass = Class.this.getSuperclass(); - if (superClass != null) { - if (superClass.reflectionData == null) { - superClass.initReflectionData(); - } - if (superClass.reflectionData.publicClasses == null) { - superClass.reflectionData.initPublicClasses(); - } - // most likely this size is enough - size += superClass.reflectionData.publicClasses.length; - } - - ArrayList classes = new ArrayList(size); - for (int i = 0; i < declaredClasses.length; i++) { - Class c = declaredClasses[i]; - if (Modifier.isPublic(c.getModifiers())) { - classes.add(c); - } - } - - if (superClass != null) { - classes.addAll(Arrays - .asList(superClass.reflectionData.publicClasses)); - } - - publicClasses = (Class[])classes.toArray(new Class[classes.size()]); - } - - public synchronized void initPublicConstructors() { + public synchronized Constructor<T>[] getPublicConstructors() { if (publicConstructors != null) { - return; + return publicConstructors; } if (declaredConstructors == null) { initDeclaredConstructors(); } - ArrayList constructors = new ArrayList(declaredConstructors.length); + ArrayList<Constructor<T>> constructors = + new ArrayList<Constructor<T>>(declaredConstructors.length); for (int i = 0; i < declaredConstructors.length; i++) { - Constructor c = declaredConstructors[i]; + Constructor<T> c = declaredConstructors[i]; if (Modifier.isPublic(c.getModifiers())) { constructors.add(c); } } - publicConstructors = (Constructor[])constructors - .toArray(new Constructor[constructors.size()]); + return publicConstructors = constructors.toArray( + new Constructor[constructors.size()]); } /** * Stores public fields in order they should be searched by * getField(name) method. */ - public synchronized void initPublicFields() { + public synchronized Field[] getPublicFields() { if (publicFields != null) { - return; + return publicFields; } if (declaredFields == null) { initDeclaredFields(); @@ -983,118 +1257,247 @@ public final class Class<T> implements S // initialize public fields of the super class int size = declaredFields.length; Class superClass = Class.this.getSuperclass(); + Field[] superFields = null; if (superClass != null) { if (superClass.reflectionData == null) { superClass.initReflectionData(); } - if (superClass.reflectionData.publicFields == null) { - superClass.reflectionData.initPublicFields(); - } - size += superClass.reflectionData.publicFields.length; + superFields = superClass.reflectionData.getPublicFields(); + size += superFields.length; } - // add public fields of this class - LinkedHashSet fields = new LinkedHashSet(size); - if (Class.this.isInterface()) { - fields.addAll(Arrays.asList(declaredFields)); - } else { - for (int i = 0; i < declaredFields.length; i++) { - Field f = declaredFields[i]; - if (Modifier.isPublic(f.getModifiers())) { - fields.add(f); - } + // add public fields of this class + Collection<Field> fields = new LinkedHashSet<Field>(size); + for (Field f : declaredFields) { + if (Modifier.isPublic(f.getModifiers())) { + fields.add(f); } } - + // initialize and add fields of the super interfaces Class[] interfaces = Class.this.getInterfaces(); - for (int j = 0; j < interfaces.length; j++) { - Class interf = interfaces[j]; - if (interf.reflectionData == null) { - interf.initReflectionData(); + for (Class ci : interfaces) { + if (ci.reflectionData == null) { + ci.initReflectionData(); } - if (interf.reflectionData.publicFields == null) { - interf.reflectionData.initPublicFields(); + Field[] fi = ci.reflectionData.getPublicFields(); + for (Field f : fi) { + fields.add(f); } - fields.addAll(Arrays.asList(interf.reflectionData.publicFields)); - } - + } + // add public fields of the super class - if (superClass != null) { - fields.addAll(Arrays - .asList(superClass.reflectionData.publicFields)); + if (superFields != null) { + for (Field f : superFields) { + if (Modifier.isPublic(f.getModifiers())) { + fields.add(f); + } + } } - - publicFields = (Field[])fields.toArray(new Field[fields - .size()]); + + // maybe publicFields better be set atomically + // instead of access synchronization? + return publicFields = fields.toArray(new Field[fields.size()]); } - public synchronized void initPublicMethods() { + public synchronized Method[] getPublicMethods() { if (publicMethods != null) { - return; + return publicMethods; } if (declaredMethods == null) { initDeclaredMethods(); } - + // initialize public methods of the super class int size = declaredMethods.length; Class superClass = Class.this.getSuperclass(); + Method[] superPublic = null; if (superClass != null) { if (superClass.reflectionData == null) { superClass.initReflectionData(); } - if (superClass.reflectionData.publicMethods == null) { - superClass.reflectionData.initPublicMethods(); - } - // most likely this size is enough - size += superClass.reflectionData.publicMethods.length; + superPublic = superClass.reflectionData.getPublicMethods(); + size += superPublic.length; } - // the storage for public methods - ArrayList methods = new ArrayList(size); - // the set of names of public methods - HashSet methodNames = new HashSet(size); - - // add public methods of this class - if (Class.this.isInterface()) { - // every interface method is public - for (int i = 0; i < declaredMethods.length; i++) { - methods.add(declaredMethods[i]); - methodNames.add(declaredMethods[i].getName()); - } - } else { - for (int i = 0; i < declaredMethods.length; i++) { - Method m = declaredMethods[i]; - if (Modifier.isPublic(m.getModifiers())) { - methods.add(m); - methodNames.add(m.getName()); + // add methods of the super interfaces + Class[] interfaces = Class.this.getInterfaces(); + Method[][] intf = null; + if (interfaces.length != 0) { + intf = new Method[interfaces.length][]; + for (int i = 0; i < interfaces.length; i++) { + Class ci = interfaces[i]; + if (ci.reflectionData == null) { + ci.initReflectionData(); } + intf[i] = ci.reflectionData.getPublicMethods(); + size += intf[i].length; } } + // maybe publicMethods better be set atomically + // instead of access synchronization? + return publicMethods = Reflection.mergePublicMethods(declaredMethods, superPublic, intf, size); + } + } + private final class GACache { + + private Annotation[] allAnnotations; + private Annotation[] declaredAnnotations; + private Type[] genericInterfaces; + private Type genericSuperclass; + private TypeVariable[] typeParameters; + + public synchronized Annotation[] getAllAnnotations() { + if (allAnnotations != null) { + return allAnnotations; + } + if (declaredAnnotations == null) { + declaredAnnotations = VMGenericsAndAnnotations + .getDeclaredAnnotations(Class.this); + } + + // look for inherited annotations + Class superClass = Class.this.getSuperclass(); if (superClass != null) { - // add public methods of the super class - mergeMethods(methodNames, methods, - superClass.reflectionData.publicMethods); + Annotation[] sa = superClass.getCache().getAllAnnotations(); + if (sa.length != 0) { + final int size = declaredAnnotations.length; + Annotation[] all = new Annotation[size + sa.length]; + System.arraycopy(declaredAnnotations, 0, all, 0, size); + int pos = size; + next: for (Annotation s : sa) { + if (s.annotationType().isAnnotationPresent(Inherited.class)) { + for (int i = 0; i < size; i++) { + if (all[i].annotationType() == s.annotationType()) { + // overriden by declared annotation + continue next; + } + } + all[pos++] = s; + } + } + allAnnotations = new Annotation[pos]; + System.arraycopy(all, 0, allAnnotations, 0, pos); + return allAnnotations; + } } + return allAnnotations = declaredAnnotations; + } - // add methods of the super interfaces - Class[] interfaces = Class.this.getInterfaces(); - for (int j = 0; j < interfaces.length; j++) { - Class interf = interfaces[j]; - if (interf.reflectionData == null) { - interf.initReflectionData(); + public Annotation[] getDeclaredAnnotations() { + if (declaredAnnotations == null) { + declaredAnnotations = VMGenericsAndAnnotations + .getDeclaredAnnotations(Class.this); + } + return declaredAnnotations; + } + + public synchronized Type[] getGenericInterfaces() { + if (genericInterfaces != null) { + return genericInterfaces; + } + + //So, here it can be only ParameterizedType or ordinary reference class type elements. + if (Class.this.isArray()) { + return genericInterfaces = new Type[]{Cloneable.class, Serializable.class}; + } + if (genericInterfaces == null) { + Object startPoint = (Object) Class.this; // It should be this class itself because, for example, an interface may be a parameterized type with parameters which are the generic parameters of this class + String signature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(Class.this)); // getting this class signature + if (signature == null) { + return genericInterfaces = Class.this.getInterfaces(); } - if (interf.reflectionData.publicMethods == null) { - interf.reflectionData.initPublicMethods(); + InterimClassGenericDecl decl = (InterimClassGenericDecl) Parser.parseSignature(signature, SignatureKind.CLASS_SIGNATURE, (GenericDeclaration)startPoint); //GenericSignatureFormatError can be thrown here + InterimType[] superInterfaces = decl.superInterfaces; + if (superInterfaces == null) { + return genericInterfaces = Class.this.getInterfaces(); + } + int l = superInterfaces.length; + genericInterfaces = new Type[l]; + for (int i = 0; i < l; i++) { + if (superInterfaces[i] instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) superInterfaces[i], ((InterimParameterizedType) superInterfaces[i]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) superInterfaces[i], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) superInterfaces[i]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + //check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) superInterfaces[i], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) superInterfaces[i], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) superInterfaces[i], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) superInterfaces[i], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) superInterfaces[i], signature, startPoint); + } + genericInterfaces[i] = (Type) pType; + } else if (superInterfaces[i] instanceof InterimClassType) { + try { + if(Class.this.getClass().getClassLoader() != null){ + genericInterfaces[i] = (Type) Class.this.getClass().getClassLoader().findClass(AuxiliaryFinder.transform(((InterimClassType)superInterfaces[i]).classTypeName.substring(1).replace('/', '.'))); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } else { + genericInterfaces[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(AuxiliaryFinder.transform(((InterimClassType)superInterfaces[i]).classTypeName.substring(1).replace('/', '.'))); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)superInterfaces[i]).classTypeName.substring(1).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else { + // Internal Error + } } - mergeMethods(methodNames, methods, - interf.reflectionData.publicMethods); } + return genericInterfaces; + } - publicMethods = (Method[])methods - .toArray(new Method[methods.size()]); + public Type getGenericSuperclass() { + //So, here it can be only ParameterizedType or ordinary reference class type + if (genericSuperclass == null) { + Object startPoint = (Object) Class.this; // It should be this class itself because, for example, superclass may be a parameterized type with parameters which are the generic parameters of this class + String signature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(Class.this)); // getting this class signature + if (signature == null) { + return genericSuperclass = Class.this.getSuperclass(); + } + InterimClassGenericDecl decl = (InterimClassGenericDecl) Parser.parseSignature(signature, SignatureKind.CLASS_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + InterimType superClassType = decl.superClass; + if (superClassType == null) { + return genericSuperclass = Class.this.getSuperclass(); + } + if (superClassType instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) superClassType, ((InterimParameterizedType) superClassType).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) superClassType, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) superClassType).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + //check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) superClassType, startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) superClassType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) superClassType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) superClassType, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) superClassType, signature, startPoint); + } + genericSuperclass = (Type) pType; + } else if (superClassType instanceof InterimClassType) { + try { + genericSuperclass = (Type) Class.this.getClass().getClassLoader().findClass(AuxiliaryFinder.transform(((InterimClassType)superClassType).classTypeName.substring(1).replace('/', '.'))); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)superClassType).classTypeName.substring(1).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else { + // Internal Error + } + } + return genericSuperclass; } /** @@ -1132,5 +1535,30 @@ public final class Class<T> implements S } } } + + public synchronized TypeVariable[] getTypeParameters() { + //So, here it can be only TypeVariable elements. + if (typeParameters == null) { + Object startPoint = (Object) Class.this; + String signature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(Class.this)); // getting this class signature + if (signature == null) { + return typeParameters = new TypeVariable[0]; + } + InterimClassGenericDecl decl = (InterimClassGenericDecl) Parser.parseSignature(signature, SignatureKind.CLASS_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + InterimTypeParameter[] pTypeParameters = decl.typeParameters; + if (pTypeParameters == null) { + return typeParameters = new TypeVariable[0]; + } + int l = pTypeParameters.length; + typeParameters = new TypeVariable[l]; + for (int i = 0; i < l; i++) { + String tvName = pTypeParameters[i].typeParameterName; + TypeVariable variable = new TypeVariableImpl((GenericDeclaration)Class.this, tvName, decl.typeParameters[i]); + TypeVariableRepository.registerTypeVariable(variable, tvName, startPoint); + typeParameters[i] = variable; + } + } + return typeParameters; + } } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ClassLoader.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ClassLoader.java index 8ccd4a3..c4fc90f 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ClassLoader.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ClassLoader.java @@ -21,11 +21,10 @@ import java.io.InputStream; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; +import java.nio.ByteBuffer; import java.net.URLClassLoader; import java.security.AccessController; import java.security.CodeSource; -import java.security.PermissionCollection; -import java.security.Policy; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; @@ -56,11 +55,6 @@ public abstract class ClassLoader { private ProtectionDomain defaultDomain; /** - * package private to access from the java.lang.Class class. - */ - static boolean enableAssertions = false; - - /** * system default class loader. It is initialized while * getSystemClassLoader(..) method is executing. */ @@ -80,54 +74,56 @@ public abstract class ClassLoader { /** * package private to access from the java.lang.Class class. The following * mapping is used <String name, Boolean flag>, where name - class name, - * flag - true if assertion is enabled, false if desabled. + * flag - true if assertion is enabled, false if disabled. */ - HashMap classAssertionStatus = null; + Hashtable<String, Boolean> classAssertionStatus; /** * package private to access from the java.lang.Class class. The following * mapping is used <String name, Object[] signers>, where name - class name, * signers - array of signers. */ - Hashtable classSigners = null; + Hashtable<String, Object[]> classSigners; /** * package private to access from the java.lang.Class class. */ - boolean defaultAssertionStatus = false; + int defaultAssertionStatus; + boolean clearAssertionStatus; /** * package private to access from the java.lang.Class class. The following * mapping is used <String name, Boolean flag>, where name - package name, - * flag - true if assertion is enabled, false if desabled. + * flag - true if assertion is enabled, false if disabled. */ - HashMap packageAssertionStatus = new HashMap(); + Hashtable<String, Boolean> packageAssertionStatus; /** * packages defined by this class loader are stored in this hash. The * following mapping is used <String name, Package pkg>, where name - * package name, pkg - corresponding package. */ - private final HashMap definedPackages = new HashMap(); + private final HashMap<String, Package> definedPackages; + + /** + * The following mapping is used <String binaryClassName, Class clazz>, where binaryClassName - class name, + * clazz - corresponding class. + */ + private Hashtable<String, Class<?>> initiatedClasses = new Hashtable<String, Class<?>>(); /** * package private to access from the java.lang.Class class. The following * mapping is used <String name, Certificate[] certificates>, where name - * the name of a package, certificates - array of certificates. */ - private final Hashtable packageCertificates = new Hashtable(); + private final Hashtable<String, Certificate[]> packageCertificates = + new Hashtable<String, Certificate[]>(); /** * parent class loader */ private final ClassLoader parentClassLoader; - static { - // Check whether we should enable assertions - enableAssertions = VMExecutionEngine.getAssertionStatus(null) > 0 - ? true : false; - } - /** * @com.intel.drl.spec_ref */ @@ -149,7 +145,7 @@ public abstract class ClassLoader { parentClassLoader = parent; // this field is used to determine whether class loader was initialized // properly. - classAssertionStatus = new HashMap(); + definedPackages = new HashMap<String, Package>(); } /** @@ -206,7 +202,7 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - public static Enumeration getSystemResources(String name) + public static Enumeration<URL> getSystemResources(String name) throws IOException { //assert systemClassLoader != null; // TODO XXX: use systemClassLoader field instead of @@ -218,11 +214,10 @@ public abstract class ClassLoader { * @com.intel.drl.spec_ref */ public void clearAssertionStatus() { - synchronized (classAssertionStatus) { - defaultAssertionStatus = false; - packageAssertionStatus = new HashMap(); - classAssertionStatus = new HashMap(); - } + clearAssertionStatus = true; + defaultAssertionStatus = -1; + packageAssertionStatus = null; + classAssertionStatus = null; } /** @@ -267,11 +262,12 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - public final Enumeration getResources(String name) throws IOException { + public Enumeration<URL> getResources(String name) throws IOException { checkInitialized(); ClassLoader cl = this; - final ArrayList foundResources = new ArrayList(); - Enumeration resourcesEnum; + final ArrayList<Enumeration<URL>> foundResources = + new ArrayList<Enumeration<URL>>(); + Enumeration<URL> resourcesEnum; do { resourcesEnum = cl.findResources(name); if (resourcesEnum != null && resourcesEnum.hasMoreElements()) { @@ -282,7 +278,7 @@ public abstract class ClassLoader { if (resourcesEnum != null && resourcesEnum.hasMoreElements()) { foundResources.add(resourcesEnum); } - return new Enumeration() { + return new Enumeration<URL>() { private int position = foundResources.size() - 1; @@ -297,10 +293,10 @@ public abstract class ClassLoader { return false; } - public Object nextElement() { + public URL nextElement() { while (position >= 0) { try { - return ((Enumeration)foundResources.get(position)) + return (foundResources.get(position)) .nextElement(); } catch (NoSuchElementException e) { } @@ -314,7 +310,7 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - public Class loadClass(String name) throws ClassNotFoundException { + public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } @@ -323,10 +319,13 @@ public abstract class ClassLoader { */ public void setClassAssertionStatus(String name, boolean flag) { if (name != null) { - synchronized (classAssertionStatus) { - enableAssertions = true; - classAssertionStatus.put(name, Boolean.valueOf(flag)); + Class.disableAssertions = false; + synchronized (definedPackages) { + if (classAssertionStatus == null) { + classAssertionStatus = new Hashtable<String, Boolean>(); + } } + classAssertionStatus.put(name, Boolean.valueOf(flag)); } } @@ -334,10 +333,10 @@ public abstract class ClassLoader { * @com.intel.drl.spec_ref */ public void setDefaultAssertionStatus(boolean flag) { - synchronized (classAssertionStatus) { - enableAssertions = true; - defaultAssertionStatus = flag; + if (flag) { + Class.disableAssertions = false; } + defaultAssertionStatus = flag ? 1 : -1; } /** @@ -349,16 +348,19 @@ public abstract class ClassLoader { if (name == null) { name = ""; } - synchronized (classAssertionStatus) { - enableAssertions = true; - packageAssertionStatus.put(name, Boolean.valueOf(flag)); + Class.disableAssertions = false; + synchronized (definedPackages) { + if (packageAssertionStatus == null) { + packageAssertionStatus = new Hashtable<String, Boolean>(); + } } + packageAssertionStatus.put(name, Boolean.valueOf(flag)); } /** * @com.intel.drl.spec_ref */ - protected final Class defineClass(byte[] data, int offset, int len) + protected final Class<?> defineClass(byte[] data, int offset, int len) throws ClassFormatError { return defineClass(null, data, offset, len); } @@ -366,7 +368,7 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected final Class defineClass(String name, byte[] data, int offset, int len) + protected final Class<?> defineClass(String name, byte[] data, int offset, int len) throws ClassFormatError { return defineClass(name, data, offset, len, null); } @@ -374,13 +376,23 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected final synchronized Class defineClass(String name, byte[] data, + protected final Class<?> defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain) + throws ClassFormatError { + byte[] data = b.array(); + return defineClass(name, data, 0, data.length, protectionDomain); + } + + /** + * @com.intel.drl.spec_ref + */ + protected final synchronized Class<?> defineClass(String name, byte[] data, int offset, int len, ProtectionDomain domain) throws ClassFormatError { checkInitialized(); if (offset < 0 || len < 0 || offset + len > data.length) { - throw new IndexOutOfBoundsException("Check your arguments"); + throw new IndexOutOfBoundsException( + "Either offset or len is outside of the data array"); } if (domain == null) { if (defaultDomain == null) { @@ -394,13 +406,13 @@ public abstract class ClassLoader { if (name != null) { if (name.startsWith("java.")) { throw new SecurityException( - "It is not allowed to define classes inside the java.* package"); + "It is not allowed to define classes inside the java.* package: " + name); } int lastDot = name.lastIndexOf('.'); packageName = lastDot == -1 ? "" : name.substring(0, lastDot); certs = getCertificates(packageName, domain.getCodeSource()); } - Class clazz = VMClassRegistry + Class<?> clazz = VMClassRegistry .defineClass(name, this, data, offset, len); clazz.setProtectionDomain(domain); if (certs != null) { @@ -421,7 +433,7 @@ public abstract class ClassLoader { throw new IllegalArgumentException("Package " + name + "has been already defined."); } - Package pkg = new Package(name, specTitle, specVersion, specVendor, + Package pkg = new Package(this, name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase); synchronized (definedPackages) { definedPackages.put(name, pkg); @@ -432,7 +444,7 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected Class findClass(String name) throws ClassNotFoundException { + protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException("Can not find class " + name); } @@ -446,8 +458,8 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected final Class findLoadedClass(String name) { - return VMClassRegistry.findLoadedClass(name, this); + protected final Class<?> findLoadedClass(String name) { + return initiatedClasses.get(name); } /** @@ -460,14 +472,14 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected Enumeration findResources(String name) throws IOException { + protected Enumeration<URL> findResources(String name) throws IOException { return EmptyEnum.getInstance(); } /** * @com.intel.drl.spec_ref */ - protected final Class findSystemClass(String name) + protected final Class<?> findSystemClass(String name) throws ClassNotFoundException { // assert systemClassLoader != null; // TODO XXX: use systemClassLoader field instead of @@ -502,18 +514,18 @@ public abstract class ClassLoader { */ protected Package[] getPackages() { checkInitialized(); - ArrayList packages = new ArrayList(); + ArrayList<Package> packages = new ArrayList<Package>(); fillPackages(packages); - return (Package[])packages.toArray(new Package[packages.size()]); + return packages.toArray(new Package[packages.size()]); } /** * @com.intel.drl.spec_ref */ - protected Class loadClass(String name, boolean resolve) + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { checkInitialized(); - Class clazz = findLoadedClass(name); + Class<?> clazz = findLoadedClass(name); if (clazz == null) { if (parentClassLoader == null) { clazz = VMClassRegistry.findLoadedClass(name, null); @@ -525,18 +537,22 @@ public abstract class ClassLoader { } if (clazz == null) { clazz = findClass(name); + if (clazz == null) { + throw new ClassNotFoundException(name); + } } } if (resolve) { resolveClass(clazz); } + initiatedClasses.put(clazz.getName(), clazz); return clazz; } /** * @com.intel.drl.spec_ref */ - protected final void resolveClass(Class clazz) { + protected final void resolveClass(Class<?> clazz) { if (clazz == null) { throw new NullPointerException(); } @@ -546,13 +562,13 @@ public abstract class ClassLoader { /** * @com.intel.drl.spec_ref */ - protected final void setSigners(Class clazz, Object[] signers) { + protected final void setSigners(Class<?> clazz, Object[] signers) { checkInitialized(); String name = clazz.getName(); try { ClassLoader classLoader = VMClassRegistry.getClassLoader(clazz); if (classLoader.classSigners == null) { - classLoader.classSigners = new Hashtable(); + classLoader.classSigners = new Hashtable<String, Object[]>(); } classLoader.classSigners.put(name, signers); } catch (NullPointerException e) { @@ -578,7 +594,7 @@ public abstract class ClassLoader { * actions. */ private void checkInitialized() { - if (classAssertionStatus == null) { + if (definedPackages == null) { throw new SecurityException( "Class loader was not initialized properly."); } @@ -625,19 +641,18 @@ public abstract class ClassLoader { String className = System.getProperty("java.system.class.loader"); if (className != null) { try { - final Class userClassLoader = systemClassLoader + final Class<?> userClassLoader = systemClassLoader .loadClass(className); if (ClassLoader.class.isAssignableFrom(userClassLoader)) { throw new Error(userClassLoader.toString() + " must inherit java.lang.ClassLoader"); } - systemClassLoader = (ClassLoader)AccessController - .doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { + systemClassLoader = AccessController + .doPrivileged(new PrivilegedExceptionAction<ClassLoader>() { + public ClassLoader run() throws Exception { Constructor c = userClassLoader - .getConstructor(new Class[] { ClassLoader.class }); - return c - .newInstance(new Object[] { systemClassLoader }); + .getConstructor(ClassLoader.class); + return (ClassLoader)c.newInstance(systemClassLoader); } }); } catch (ClassNotFoundException e) { @@ -651,7 +666,7 @@ public abstract class ClassLoader { /** * Helper method for the getPackages() method. */ - private void fillPackages(ArrayList packages) { + private void fillPackages(ArrayList<Package> packages) { if (parentClassLoader == null) { packages.addAll(BootstrapLoader.getPackages()); } else { @@ -697,7 +712,7 @@ public abstract class ClassLoader { if (str.length() == 0) { return new String[0]; } - ArrayList res = new ArrayList(); + ArrayList<String> res = new ArrayList<String>(); int in = 0; int curPos = 0; int i = str.indexOf(sep); @@ -717,13 +732,13 @@ public abstract class ClassLoader { res.add(s); } - return (String[]) res.toArray(new String[in]); + return res.toArray(new String[in]); } /* IBM SPECIFIC PART */ static final ClassLoader getStackClassLoader(int depth) { - Class clazz = VMStack.getCallerClass(depth); + Class<?> clazz = VMStack.getCallerClass(depth); return clazz != null ? VMClassRegistry.getClassLoader(clazz) : null; } @@ -777,7 +792,8 @@ public abstract class ClassLoader { private static URLClassLoader resourceFinder = null; - private static final HashMap systemPackages = new HashMap(); + private static final HashMap<String, Package> systemPackages = + new HashMap<String, Package>(); /** * This class contains static methods only. So it should not be @@ -793,7 +809,7 @@ public abstract class ClassLoader { return resourceFinder.findResource(name); } - public static Enumeration findResources(String name) throws IOException { + public static Enumeration<URL> findResources(String name) throws IOException { if (resourceFinder == null) { initResourceFinder(); } @@ -807,7 +823,7 @@ public abstract class ClassLoader { } } - public static Collection getPackages() { + public static Collection<Package> getPackages() { synchronized (systemPackages) { updatePackages(); return systemPackages.values(); @@ -823,7 +839,7 @@ public abstract class ClassLoader { // like we do below: String st[] = fracture(bootstrapPath, File.pathSeparator); int l = st.length; - ArrayList urlList = new ArrayList(); + ArrayList<URL> urlList = new ArrayList<URL>(); for (int i = 0; i < l; i++) { try { urlList.add(new File(st[i]).toURI().toURL()); @@ -849,7 +865,7 @@ public abstract class ClassLoader { } String jarURL = packages[i][1]; - systemPackages.put(name, new Package(name, jarURL)); + systemPackages.put(name, new Package(null, name, jarURL)); } } } @@ -859,7 +875,7 @@ public abstract class ClassLoader { private static URLClassLoader instance; static { - ArrayList urlList = new ArrayList(); + ArrayList<URL> urlList = new ArrayList<URL>(); // TODO avoid security checking? String extDirs = System.getProperty("java.ext.dirs", ""); @@ -889,6 +905,7 @@ public abstract class ClassLoader { } urlList.add(new File(st[i]).toURI().toURL()); } catch (MalformedURLException e) { + assert false: e.toString(); } } instance = URLClassLoader.newInstance((URL[])urlList diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/Compiler.java vm/vmcore/src/kernel_classes/javasrc/java/lang/Compiler.java index 7e74abf..68bcb63 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/Compiler.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/Compiler.java @@ -45,7 +45,9 @@ public final class Compiler { * * @api2vm */ - public static native Object command(Object obj); + public static Object command(Object obj) { + throw new UnsupportedOperationException("Not implemented"); + } /** * This method satisfies the requirements of the specification for the @@ -54,7 +56,9 @@ public final class Compiler { * * @api2vm */ - public static native boolean compileClass(Class clazz); + public static boolean compileClass(Class<?> clazz) { + throw new UnsupportedOperationException("Not implemented"); + } /** * This method satisfies the requirements of the specification for the @@ -63,7 +67,9 @@ public final class Compiler { * * @api2vm */ - public static native boolean compileClasses(String name); + public static boolean compileClasses(String name){ + throw new UnsupportedOperationException("Not implemented"); + } /** * This method satisfies the requirements of the specification for the @@ -71,7 +77,9 @@ public final class Compiler { * * @api2vm */ - public static native void disable(); + public static void disable() { + throw new UnsupportedOperationException("Not implemented"); + } /** * This method satisfies the requirements of the specification for the @@ -79,5 +87,7 @@ public final class Compiler { * * @api2vm */ - public static native void enable(); + public static void enable() { + throw new UnsupportedOperationException("Not implemented"); + } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/Object.java vm/vmcore/src/kernel_classes/javasrc/java/lang/Object.java index 67128c9..f088f76 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/Object.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/Object.java @@ -30,7 +30,7 @@ public class Object { private static final int TM_ERROR_INTERRUPT = 52; private static final int TM_ERROR_ILLEGAL_STATE = 118; - public final Class getClass() { + public final Class<? extends Object> getClass() { return VMClassRegistry.getClass(this); } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/Package.java vm/vmcore/src/kernel_classes/javasrc/java/lang/Package.java index 81d2d1f..8a751c2 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/Package.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/Package.java @@ -14,7 +14,7 @@ * limitations under the License. */ /** - * @author Evgueni Brevnov, Alexey V. Varlamov + * @author Evgueni Brevnov, Alexey V. Varlamov, Serguei S. Zapreyev * @version $Revision: 1.1.2.2.4.4 $ */ @@ -31,33 +31,94 @@ import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.lang.ref.SoftReference; +import java.lang.reflect.AnnotatedElement; +import java.lang.annotation.Annotation; +import org.apache.harmony.vm.VMGenericsAndAnnotations; import org.apache.harmony.vm.VMStack; /** * @com.intel.drl.spec_ref */ -public class Package { +public class Package implements AnnotatedElement { + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getDeclaredAnnotations() { + Class pc = null; + try { + //default package cannot be annotated + pc = Class.forName(getName() + ".package-info", false, loader); + } catch (ClassNotFoundException _) { + return new Annotation[0]; + } + return VMGenericsAndAnnotations.getDeclaredAnnotations(pc); // get all annotations directly present on this element + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + Annotation aa[] = getAnnotations(); + for (int i = 0; i < aa.length; i++) { + if(aa[i].annotationType().equals(annotationClass)) { + return (A) aa[i]; + } + } + return null; + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + return getAnnotation(annotationClass) != null; + } + + /** + * The defining loader. + */ + private final ClassLoader loader; /** * A map of {url<String>, attrs<Manifest>} pairs for caching * attributes of bootsrap jars. */ - private static final Map jarCache = new Hashtable(); + private static SoftReference<Map<String, Manifest>> jarCache; /** * An url of a source jar, for deffered attributes initialization. * After the initialization, if any, is reset to null. */ private String jar; - + private String implTitle; private String implVendor; private String implVersion; - private String name; + private final String name; private URL sealBase; @@ -68,10 +129,11 @@ public class Package { private String specVersion; /** - * name can not be null. + * Name must not be null. */ - Package(String packageName, String sTitle, String sVersion, String sVendor, + Package(ClassLoader ld, String packageName, String sTitle, String sVersion, String sVendor, String iTitle, String iVersion, String iVendor, URL base) { + loader = ld; name = packageName; specTitle = sTitle; specVersion = sVersion; @@ -87,7 +149,8 @@ public class Package { * resolve optional attributes only if such value is requested. * Name must not be null. */ - Package(String packageName, String jar) { + Package(ClassLoader ld, String packageName, String jar) { + loader = ld; name = packageName; this.jar = jar; } @@ -109,7 +172,7 @@ public class Package { ClassLoader callerLoader = VMClassRegistry.getClassLoader(VMStack .getCallerClass(0)); if (callerLoader == null) { - Collection pkgs = ClassLoader.BootstrapLoader.getPackages(); + Collection<Package> pkgs = ClassLoader.BootstrapLoader.getPackages(); return (Package[]) pkgs.toArray(new Package[pkgs.size()]); } return callerLoader.getPackages(); @@ -253,22 +316,33 @@ public class Package { */ private void init() { try { - final URL sealURL = new URL(jar); - Manifest manifest = (Manifest)jarCache.get(jar); + Map<String, Manifest> map = null; + Manifest manifest = null; + URL sealURL = null; + if (jarCache != null && (map = jarCache.get()) != null) { + manifest = map.get(jar); + } if (manifest == null) { - manifest = (Manifest)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() + final URL url = sealURL = new URL(jar); + manifest = AccessController.doPrivileged( + new PrivilegedAction<Manifest>() { + public Manifest run() { try { - return ((JarURLConnection)sealURL + return ((JarURLConnection)url .openConnection()).getManifest(); } catch (Exception e) { return new Manifest(); } } }); - jarCache.put(jar, manifest); + if (map == null) { + map = new Hashtable<String, Manifest>(); + if (jarCache == null) { + jarCache = new SoftReference<Map<String, Manifest>>(map); + } + } + map.put(jar, manifest); } Attributes mainAttrs = manifest.getMainAttributes(); @@ -301,8 +375,9 @@ public class Package { String sealed = (sealed = pkgAttrs .getValue(Attributes.Name.SEALED)) == null ? mainAttrs .getValue(Attributes.Name.SEALED) : sealed; - sealBase = Boolean.valueOf(sealed).booleanValue() ? sealURL - : null; + if (Boolean.valueOf(sealed).booleanValue()) { + sealBase = sealURL != null ? sealURL : new URL(jar); + } } catch (Exception e) {} jar = null; } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/System.java vm/vmcore/src/kernel_classes/javasrc/java/lang/System.java index 93718d5..05570a8 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/System.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/System.java @@ -22,15 +22,16 @@ import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.InputStream; import java.io.PrintStream; +import java.io.IOException; import java.security.SecurityPermission; import java.util.Collections; -import java.util.Hashtable; import java.util.Map; import java.util.Properties; import java.util.PropertyPermission; +import java.nio.channels.spi.SelectorProvider; +import java.nio.channels.Channel; import org.apache.harmony.lang.RuntimePermissionCollection; -import org.apache.harmony.misc.SystemUtils; import org.apache.harmony.vm.VMStack; /** @@ -41,10 +42,6 @@ import org.apache.harmony.vm.VMStack; */ public final class System { - static { - initNanoTime(); - } - /** * This class can not be instantiated. */ @@ -87,7 +84,9 @@ public final class System { /** * @com.intel.drl.spec_ref */ - public static native long currentTimeMillis(); + public static long currentTimeMillis() { + return VMExecutionEngine.currentTimeMillis(); + } /** * @com.intel.drl.spec_ref @@ -108,29 +107,24 @@ public final class System { */ public static String getenv(String name) { if (name == null) { - throw new NullPointerException(); + throw new NullPointerException("name should not be null"); } SecurityManager sm = securityManager; if (sm != null) { sm.checkPermission(new RuntimePermission("getenv." + name)); } - return getenvUnsecure(name); + return VMExecutionEngine.getenv(name); } - // FIXME: MODIFY THE SIGNATURE FOR 1.5 /** * @com.intel.drl.spec_ref */ - public static Map getenv() { + public static Map<String, String> getenv() { SecurityManager sm = securityManager; if (sm != null) { sm.checkPermission(RuntimePermissionCollection.GETENV_PERMISSION); } - Map envMap = getenvUnsecure(); - if (envMap == null) { - envMap = new Hashtable(); - } - return Collections.unmodifiableMap(envMap); + return Collections.unmodifiableMap(VMExecutionEngine.getenv()); } /** @@ -192,18 +186,9 @@ public final class System { return VMMemoryManager.getIdentityHashCode(object); } -/* -// ######################################################################################### -// ############################### 1.5 extention start ##################################### -// ######################################################################################### - -//import java.nio.channels.spi.SelectorProvider; //move this above later -//import java.nio.channels.Channel; //move this above later -//import java.io.IOException; //move this above later - - / ** + /** * @com.intel.drl.spec_ref - * / + */ public static Channel inheritedChannel() throws IOException{ //XXX:does it mean the permission of the "access to the channel"? //If YES then this checkPermission must be removed because it should be presented into java.nio.channels.spi.SelectorProvider.inheritedChannel() @@ -216,49 +201,39 @@ public final class System { return SelectorProvider.provider().inheritedChannel(); } -// ######################################################################################### -// ############################### 1.5 extention end ####################################### -// ######################################################################################### -*/ - /** * @com.intel.drl.spec_ref */ public static void load(String filename) { Runtime.getRuntime().load0( - filename, - VMClassRegistry.getClassLoader(VMStack - .getCallerClass(0)), true); + filename, + VMClassRegistry.getClassLoader(VMStack.getCallerClass(0)), + true); } public static void loadLibrary(String libname) { Runtime.getRuntime().loadLibrary0( - libname, - VMClassRegistry - .getClassLoader(VMStack - .getCallerClass(0)), true); + libname, + VMClassRegistry.getClassLoader(VMStack.getCallerClass(0)), + true); } /** - * @com.intel.drl.spec_ref Note: Only Windows and Linux operating systems - * are supported by current version + * @com.intel.drl.spec_ref */ public static String mapLibraryName(String libname) { - switch (SystemUtils.getOS()) { - case SystemUtils.OS_WINDOWS: - return libname + ".dll"; - case SystemUtils.OS_LINUX: - return "lib" + libname + ".so"; - default: - throw new UnsupportedOperationException( - "The operation is supported for Windows and Linux operating systems only"); + if (libname == null) { + throw new NullPointerException("libname should not be empty"); } + return VMExecutionEngine.mapLibraryName(libname); } /** * @com.intel.drl.spec_ref */ - public static native long nanoTime(); + public static long nanoTime() { + return VMExecutionEngine.nanoTime(); + } /** * @com.intel.drl.spec_ref @@ -310,9 +285,10 @@ public final class System { /** * @com.intel.drl.spec_ref */ - public static synchronized void setProperties(Properties props) { - if (securityManager != null) { - securityManager.checkPropertiesAccess(); + public static void setProperties(Properties props) { + SecurityManager sm = securityManager; + if (sm != null) { + sm.checkPropertiesAccess(); } systemProperties = props; } @@ -368,7 +344,7 @@ public final class System { // crash while initialization of main Thread object // // Correct fix of the problem is closing out and err print streams on VM - // exit for example, in Runtime.exit(). Another bug prevents us of doing + // exit for example, in Runtime.exit(). Another bug prevents us of doing // such thing return new PrintStream(new FilterOutputStream(new FileOutputStream( FileDescriptor.err)), true); @@ -398,11 +374,12 @@ public final class System { * Returns system properties without security checks. Initializes the system * properties if it isn't done yet. */ - private static synchronized Properties getPropertiesUnsecure() { - if (systemProperties == null) { - systemProperties = VMExecutionEngine.getProperties(); + private static Properties getPropertiesUnsecure() { + Properties sp = systemProperties; + if (sp == null) { + systemProperties = sp = VMExecutionEngine.getProperties(); } - return systemProperties; + return sp; } /** @@ -420,25 +397,12 @@ public final class System { */ private static native void setOutUnsecure(PrintStream out); - // FIXME: MODIFY THE SIGNATURE FOR 1.5 - /** - * Returns enviromnent variables to values map without any security checks - */ - private static native Map getenvUnsecure(); - - /** - * Returns the value of the environment variable specified by - * <code>name</code> argument or <code>null</code> if it is not set - */ - private static native String getenvUnsecure(String name); - - /** - * Initializes nanosecond system timer - */ - private static native void initNanoTime(); - /** - * To rethrow without mentioning within throws clause. + * Helps to throw an arbitrary throwable without mentioning within + * <code>throw</code> clause and so bypass + * exception checking by a compiler. + * + * @see java.lang.Class#newInstance() */ native static void rethrow(Throwable tr); } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/Thread.java vm/vmcore/src/kernel_classes/javasrc/java/lang/Thread.java index 6cb383c..2ced331 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/Thread.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/Thread.java @@ -111,7 +111,7 @@ public class Thread implements Runnable * Maps <code>ThreadLocal</code> object to value. Lazy initialization is * used to avoid circular dependance. */ - private Map localValues = null; + private Map<ThreadLocal<Object>, Object> localValues = null; /** * Uncaught exception handler for this thread @@ -381,8 +381,6 @@ public class Thread implements Runnable /** * @com.intel.drl.spec_ref */ -/* - // XXX for 5.0: wait for VM interfaces implemented public static Map<Thread, StackTraceElement[]> getAllStackTraces() { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { @@ -391,22 +389,37 @@ public class Thread implements Runnable securityManager .checkPermission(RuntimePermissionCollection.MODIFY_THREAD_GROUP_PERMISSION); } - Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>(liveThreads.length); - Thread[] liveThreads = VMThreadManager.getLiveThreads(); - for (int i = 0; i < liveThreads.length; i++) { - Object stackHandler = VMStack.getStackState(liveThreads[i]); - StackTraceElement[] ste = VMStack.getStackTrace(stackHandler); - if (liveThreads[i].isAlive()) { - StackTraceElement[] ste = VMStack.getStackTrace(stackHandler); - if (ste == null) { - ste = new StackTraceElement[0]; - } + + // find the initial ThreadGroup in the tree + ThreadGroup parent = new ThreadGroup(currentThread().getThreadGroup(), "Temporary"); + ThreadGroup newParent = parent.getParent(); + parent.destroy(); + while (newParent != null) { + parent = newParent; + newParent = parent.getParent(); + } + int threadsCount = parent.activeCount() + 1; + int count; + Thread[] liveThreads; + while (true) { + liveThreads = new Thread[threadsCount]; + count = parent.enumerate(liveThreads); + if (count == threadsCount) { + threadsCount *= 2; + } else { + break; + } + } + Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>(count + 1); + for (int i = 0; i < count; i++) { + StackTraceElement[] ste = liveThreads[i].getStackTrace(); + if (ste.length != 0) { map.put(liveThreads[i], ste); } } return map; } -*/ + /** * @com.intel.drl.spec_ref */ @@ -467,15 +480,12 @@ public class Thread implements Runnable .checkPermission(RuntimePermissionCollection.GET_STACK_TRACE_PERMISSION); } } - if (!this.isAlive()) { - return new StackTraceElement[0]; + StackTraceElement ste[] = VMStack.getThreadStackTrace(this); + if (ste != null) { + return ste; + } else { + return new StackTraceElement[0]; } - // TODO: correct after the interfaces to VM for 1.5 are approved. - // For now VMStack.getStackState() returns - // stack information of the currently executing thread. - // Here we need VMStack.getStackState(this); - Object stackHandler = VMStack.getStackState(); - return VMStack.getStackTrace(stackHandler); } /** @@ -703,8 +713,7 @@ public class Thread implements Runnable -// for 5.0 -/* public enum State { + public enum State { NEW, RUNNABLE, BLOCKED, @@ -713,13 +722,29 @@ public class Thread implements Runnable TERMINATED } - *//** + /** * @com.intel.drl.spec_ref - *//* - public State getState() { - return VMThreadManager.getState(); + */ + public Thread.State getState() { + + int state = (VMThreadManager.getState(this)); + + if (0 != (state & VMThreadManager.JVMTI_THREAD_STATE_TERMINATED)) { + return State.TERMINATED; + } else if (0 != (state & VMThreadManager.JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT)) { + return State.TIMED_WAITING; + } else if (0 != (state & VMThreadManager.JVMTI_THREAD_STATE_WAITING) + || 0 != (state & VMThreadManager.JVMTI_THREAD_STATE_PARKED)) { + return State.WAITING; + } else if (0 != (state & VMThreadManager.JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER)) { + return State.BLOCKED; + } else if (0 != (state & VMThreadManager.JVMTI_THREAD_STATE_ALIVE)) { + return State.RUNNABLE; + } else { + return State.NEW; + } } -*/ + /** * @com.intel.drl.spec_ref */ @@ -822,9 +847,9 @@ public class Thread implements Runnable * This nethod is designed to provide <code>ThreadLocal</code> * functionality. */ - void setThreadLocal(ThreadLocal local, Object value) { + void setThreadLocal(ThreadLocal<Object> local, Object value) { if (localValues == null) { - localValues = new HashMap(); + localValues = new HashMap<ThreadLocal<Object>, Object>(); } localValues.put(local, value); } @@ -837,10 +862,10 @@ public class Thread implements Runnable * This nethod is designed to provide <code>ThreadLocal</code> * functionality. */ - Object getThreadLocal(ThreadLocal local) { + Object getThreadLocal(ThreadLocal<Object> local) { Object value; if (localValues == null) { - localValues = new HashMap(); + localValues = new HashMap<ThreadLocal<Object>, Object>(); value = local.initialValue(); localValues.put(local, value); return value; @@ -859,7 +884,7 @@ public class Thread implements Runnable * This nethod is designed to provide <code>ThreadLocal</code> * functionality. */ - void removeLocalValue(ThreadLocal local) { + void removeLocalValue(ThreadLocal<Object> local) { if (localValues != null) { localValues.remove(local); } @@ -874,17 +899,17 @@ public class Thread implements Runnable * This method should be called from <code>Thread</code>'s constructor. */ private void initializeInheritableLocalValues(Thread parent) { - Map parentLocalValues = parent.localValues; + Map<ThreadLocal<Object>, Object> parentLocalValues = parent.localValues; if (parentLocalValues == null) { - return; + return; } - localValues = new HashMap(parentLocalValues.size()); - for (Iterator it = parentLocalValues.keySet().iterator(); it.hasNext();) { - Object local = it.next(); + localValues = new HashMap<ThreadLocal<Object>, Object>(parentLocalValues.size()); + for (Iterator<ThreadLocal<Object>> it = parentLocalValues.keySet().iterator(); it.hasNext();) { + ThreadLocal<Object> local = it.next(); if (local instanceof InheritableThreadLocal) { Object parentValue = parentLocalValues.get(local); - localValues.put(local, ((InheritableThreadLocal)local) - .childValue(parentValue)); + InheritableThreadLocal<Object> iLocal = (InheritableThreadLocal<Object>) local; + localValues.put(local, iLocal.childValue(parentValue)); } } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java index 59833dd..d65d980 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java @@ -60,18 +60,22 @@ public class ThreadGroup implements Thre /** * List of subgroups of this thread group */ - private LinkedList groups = new LinkedList(); + private LinkedList<ThreadGroup> groups = new LinkedList<ThreadGroup>(); /** * Parent thread group of this thread group. * + * FIXME: this field must be private. It is changed to package-private + * to be accessible from FT SecurityManager class. Both SecurityManager + * and ThreadGroup are considered as non-Kernel by FT, but ThreadGroup + * is Kernel now in DRL. */ ThreadGroup parent; /** * All threads in the group. */ - private WeakHashMap threads = new WeakHashMap(); + private WeakHashMap<Thread, ThreadGroup> threads = new WeakHashMap<Thread, ThreadGroup>(); /** * @com.intel.drl.spec_ref @@ -92,15 +96,16 @@ public class ThreadGroup implements Thre this.name = name; this.parent = parent; this.daemon = parent.daemon; + this.maxPriority = parent.maxPriority; parent.add(this); } /** - * This constructor is used to create main thread group + * This constructor is used to create the system thread group */ ThreadGroup() { this.parent = null; - this.name = "System"; + this.name = "system"; this.daemon = false; } @@ -178,9 +183,13 @@ public class ThreadGroup implements Thre throw new IllegalThreadStateException( "The thread group " + name + " is already destroyed!"); } - nonsecureDestroy(); - if (parent != null) { - parent.remove(this); + if (!nonsecureDestroy()) { + throw new IllegalThreadStateException("The thread group " + name + + " contains non-empty subgroups"); + } else { + if (parent != null) { + parent.remove(this); + } } } @@ -302,12 +311,15 @@ public class ThreadGroup implements Thre /** * @com.intel.drl.spec_ref */ - public final void setMaxPriority(int priority) { + public synchronized final void setMaxPriority(int priority) { checkAccess(); if (priority > Thread.MAX_PRIORITY || priority < Thread.MIN_PRIORITY) { return; } - nonsecureSetMaxPriority(priority); + this.maxPriority = (parent != null && parent.maxPriority < priority) + ? parent.maxPriority + : priority; + nonsecureSetMaxPriority(this.maxPriority); } /** @@ -512,19 +524,29 @@ public class ThreadGroup implements Thre /** * Destroys this thread group without any security checks. We add this - * method to avoid calls to the checkAccess() method on subgroups - */ - private synchronized void nonsecureDestroy() { - if (!threads.isEmpty()) { - throw new IllegalThreadStateException( - "The thread group " + name + " is not empty!"); - } - for (Iterator it = ((List)groups.clone()).iterator(); it.hasNext();) { - ((ThreadGroup) it.next()).nonsecureDestroy(); - it.remove(); - } - destroyed = true; - } + * method to avoid calls to the checkAccess() method on subgroups. + * All non-empty subgroups are removed recursievely. + * If at least one subgroup is not empty, IllegalThreadStateException + * will be thrown. + * @return false if this ThreadGroup is not empty + */ + private synchronized boolean nonsecureDestroy() { + boolean thisGroupIsEmpty = true; + if (!threads.isEmpty()) { + return false; + } + for (Iterator<ThreadGroup> it = groups.iterator(); it.hasNext();) { + if (it.next().nonsecureDestroy()) { + it.remove(); + } else { + thisGroupIsEmpty = false; + } + } + if (groups.isEmpty()) { + destroyed = true; + } + return thisGroupIsEmpty; + } /** * Interrupts this thread group without any security checks. We add this @@ -558,16 +580,11 @@ public class ThreadGroup implements Thre * Sets the maximum priority allowed for this thread group and its subgroups. * We add this method to avoid calls to the checkAccess() method on subgroups */ - private void nonsecureSetMaxPriority(int priority) { - maxPriority = (parent != null && parent.maxPriority < priority) - ? parent.maxPriority : priority; - List groupsListCopy = null; // a copy of subgroups list - synchronized (this) { - groupsListCopy = (List)groups.clone(); - } - for (Iterator it = groupsListCopy.iterator(); it.hasNext();) { - ((ThreadGroup)it.next()).setMaxPriority(maxPriority); + private synchronized void nonsecureSetMaxPriority(int priority) { + for (Iterator it = ((List)groups.clone()).iterator(); it.hasNext();) { + ((ThreadGroup)it.next()).nonsecureSetMaxPriority(priority); } + this.maxPriority = priority; } /** diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadWeakRef.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadWeakRef.java index 3ac7e7a..261d566 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadWeakRef.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadWeakRef.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +/** + * @author Artem Aliev + */ package java.lang; import java.lang.ref.WeakReference; diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/VMClassRegistry.java vm/vmcore/src/kernel_classes/javasrc/java/lang/VMClassRegistry.java index bc8be6c..e09cb18 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/VMClassRegistry.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/VMClassRegistry.java @@ -23,6 +23,8 @@ package java.lang; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Member; + /** * Provides the class information methods required for the @@ -39,6 +41,46 @@ import java.lang.reflect.Method; * @api2vm */ final class VMClassRegistry { + /** + * This method satisfies the requirements of the specification for the + * {@link Class#getSimpleName() Class.getSimpleName()} + * method. + * + * @param clazz a class to perform an operation on. + * @return the simple name of the specified class + * + * @api2vm + */ + static native String getSimpleName(Class<?> clazz); + + /** + * Returns the nearest enclosing class of the specified Class instance, + * or <code>null</code> if the specified class is a top-level class. + * <br>This information is gathered from corresponding class-file structures + * (either EnclosingMethod or InnerClasses attribute, if any present). + * + * @param clazz a class to perform an operation on. + * @return the immediately enclosing class of the specified class or null + * + * @api2vm + */ + static native Class getEnclosingClass(Class<?> clazz); + + /** + * If the specified class is a local or anonymous class defined + * within a method or constructor, returns that closest + * enclosing reflection member. Otherwise returns <code>null</code>. + * Note, instance initializers and static initializers + * are not reflectable and will never be considered. + * <br>This information is gathered from corresponding class-file structure + * (EnclosingMethod attribute, if present). + * + * @param clazz a class to perform an operation on. + * @return the immediately enclosing member for the specified class or null + * + * @api2vm + */ + static native Member getEnclosingMember(Class<?> clazz); /** * This class is not supposed to be instantiated. @@ -64,7 +106,7 @@ final class VMClassRegistry { * name defined in the data array. * @api2vm */ - static native Class defineClass(String name, ClassLoader classLoader, + static native Class<?> defineClass(String name, ClassLoader classLoader, byte[] data, int off, int len) throws ClassFormatError; /** @@ -84,28 +126,28 @@ final class VMClassRegistry { * class loader will be searched. * @api2vm */ - static native Class findLoadedClass(String name, ClassLoader loader); + static native Class<?> findLoadedClass(String name, ClassLoader loader); /** * This method satisfies the requirements of the specification for the * {@link Object#getClass() Object.getClass()} method. * @api2vm */ - static native Class getClass(Object obj); + static native Class<? extends Object> getClass(Object obj); /** * This method satisfies the requirements of the specification for the * {@link Class#getClassLoader() Class.getClassLoader()} method. * @api2vm */ - static native ClassLoader getClassLoader(Class clazz); + static native ClassLoader getClassLoader(Class<?> clazz); /** * This method satisfies the requirements of the specification for the * {@link Class#getComponentType() Class.getComponentType()} method. * @api2vm */ - static native Class getComponentType(Class clazz); + static native Class<?> getComponentType(Class clazz); /** * This method satisfies the requirements of the specification for the @@ -121,7 +163,7 @@ final class VMClassRegistry { * method. * @api2vm */ - static native Constructor[] getDeclaredConstructors(Class clazz); + static native <U> Constructor<U>[] getDeclaredConstructors(Class<U> clazz); /** * This method satisfies the requirements of the specification for the @@ -142,7 +184,7 @@ final class VMClassRegistry { * {@link Class#getDeclaringClass() Class.getDeclaringClass()} method. * @api2vm */ - static native Class getDeclaringClass(Class clazz); + static native Class<?> getDeclaringClass(Class clazz); /** * This method satisfies the requirements of the specification for the @@ -170,7 +212,7 @@ final class VMClassRegistry { * {@link Class#getSuperclass() Class.getSuperclass()} method. * @api2vm */ - static native Class getSuperclass(Class clazz); + static native <U> Class<? super U> getSuperclass(Class<U> clazz); /** * This method returns a list describing the system packages, @@ -215,7 +257,7 @@ final class VMClassRegistry { * Class.isAssignableFrom(Class cls)} method. * @api2vm */ - static native boolean isAssignableFrom(Class clazz, Class fromClazz); + static native boolean isAssignableFrom(Class clazz, Class<?> fromClazz); //XXX: does it have any sense? /** * This method satisfies the requirements of the specification for the @@ -227,13 +269,6 @@ final class VMClassRegistry { /** * This method satisfies the requirements of the specification for the - * {@link Class#isInterface() Class.isInterface()} method. - * @api2vm - */ - static native boolean isInterface(Class clazz); - - /** - * This method satisfies the requirements of the specification for the * {@link Class#isPrimitive() Class.isPrimitive()} method. * @api2vm */ @@ -249,7 +284,7 @@ final class VMClassRegistry { * @throws LinkageError if linking fails. * @api2vm */ - static native void linkClass(Class clazz); + static native void linkClass(Class<?> clazz); /** * This method is used for the diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/VMExecutionEngine.java vm/vmcore/src/kernel_classes/javasrc/java/lang/VMExecutionEngine.java index b42c9f2..a6364da 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/VMExecutionEngine.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/VMExecutionEngine.java @@ -19,6 +19,7 @@ */ package java.lang; +import java.util.Map; import java.util.Properties; import java.util.Vector; @@ -37,7 +38,7 @@ final class VMExecutionEngine { /** * keeps Runnable objects of the shutdown sequence */ - private static Vector shutdownActions = new Vector(); + private static Vector<Runnable> shutdownActions = new Vector<Runnable>(); /** * This class is not supposed to be instantiated. @@ -68,8 +69,7 @@ final class VMExecutionEngine { * @api2vm */ static void exit(int status, boolean needFinalization) { - exit(status, needFinalization, (Runnable[])shutdownActions - .toArray(new Runnable[shutdownActions.size()])); + exit(status, needFinalization, shutdownActions.toArray(new Runnable[0])); } @@ -97,22 +97,28 @@ final class VMExecutionEngine { /** * This method provides an information about the assertion status specified - * via command line options. + * via command line options. * <p> - * The name parameter can be either fully qualified class name or package - * name. Null argument can be used to check if any assertion was - * specified through command line options. This method should not perform - * recursive checking (parent packages shouldn't be searched). - * <p> - * <b>Note:</b> This method is used for the - * {@link Class#desiredAssertionStatus() Class.desiredAssertionStatus()} - * method implementation. + * + * @see java.lang.Class#desiredAssertionStatus() * - * @param name fully qualified class or package name delimited by dots + * @param clss the class to be initialized with the assertion status. Note, + * assertion status is applicable to top-level classes only, therefore + * any member/local class passed is a subject to conversion to corresponding + * top-level declaring class. Also, <code>null</code> argument can be used to + * check if any assertion was specified through command line options. + * @param recursive controls whether this method should check exact match + * with name of the class, or check (super)packages recursively + * (most specific one has precedence). + * @param defaultStatus if no specific package setting found, + * this value may override command-line defaults. This parameter is + * actual only when <code>recursive == true</code>. + * @see java.lang.ClassLoader#setDefaultAssertionStatus(boolean) * @return 0 - unspecified, < 0 - false, > 0 - true * @api2vm */ - static native int getAssertionStatus(String name); + static native int getAssertionStatus(Class clss, boolean recursive, + int defaultStatus); /** * This method satisfies the requirements of the specification for the @@ -168,4 +174,38 @@ final class VMExecutionEngine { * @api2vm */ static native void traceMethodCalls(boolean enable); + + /** + * Returns the current system time in milliseconds since + * the Unix epoch (midnight, 1 Jan, 1970). + * @api2vm + */ + static native long currentTimeMillis(); + + /** + * Returns the current value of a system timer with the best accuracy + * the OS can provide, in nanoseconds. + * @api2vm + */ + static native long nanoTime(); + + /** + * Returns the value of the environment variable specified by + * <code>name</code> argument or <code>null</code> if it is not set. + * @api2vm + */ + static native String getenv(String name); + + /** + * Returns the whole environment as a name-value mapping. + * May return empty map. + * @api2vm + */ + static native Map<String, String> getenv(); + + /** + * Returns platform-specific name of the specified library. + * @api2vm + */ + static native String mapLibraryName(String libname); } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/VMStart.java vm/vmcore/src/kernel_classes/javasrc/java/lang/VMStart.java index c476239..cbb0efe 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/VMStart.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/VMStart.java @@ -126,7 +126,8 @@ class VMStart { throw new NoSuchMethodError( "The method main must be declared public, static, and void."); } - AccessController.doPrivileged(new PrivilegedAction() { + // the class itself may be non-public + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { mainMethod.setAccessible(true); return null; diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/VMThreadManager.java vm/vmcore/src/kernel_classes/javasrc/java/lang/VMThreadManager.java index 1e6bd56..783859c 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/VMThreadManager.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/VMThreadManager.java @@ -43,6 +43,28 @@ final class VMThreadManager { public static final int TM_ERROR_INTERRUPT = 52; public static final int TM_ERROR_ILLEGAL_STATE = 51; + + /** + * JVMTI constants + */ + public static final int JVMTI_THREAD_STATE_ALIVE = 0x0001; + public static final int JVMTI_THREAD_STATE_TERMINATED = 0x0002; + public static final int JVMTI_THREAD_STATE_RUNNABLE = 0x0004; + public static final int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400; + public static final int JVMTI_THREAD_STATE_WAITING = 0x0080; + public static final int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; + public static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; + public static final int JVMTI_THREAD_STATE_SLEEPING = 0x0040; + public static final int JVMTI_THREAD_STATE_IN_OBJECT_WAIT = 0x0100; + public static final int JVMTI_THREAD_STATE_PARKED = 0x0200; + public static final int JVMTI_THREAD_STATE_SUSPENDED = 0x100000; + public static final int JVMTI_THREAD_STATE_INTERRUPTED = 0x200000; + public static final int JVMTI_THREAD_STATE_IN_NATIVE = 0x400000; + public static final int JVMTI_THREAD_STATE_VENDOR_1 = 0x10000000; + public static final int JVMTI_THREAD_STATE_VENDOR_2 = 0x20000000; + public static final int JVMTI_THREAD_STATE_VENDOR_3 = 0x40000000; + + /** * This class is not supposed to be instantiated. */ @@ -231,5 +253,10 @@ final class VMThreadManager { */ static native int attach(java.lang.Thread thread); + /** + * Returns the state of the given thread as described by JVMTI spec + * @api2vm + */ + static native int getState(java.lang.Thread thread); } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/PhantomReference.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/PhantomReference.java index 31b3c2d..d84c9dd 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/PhantomReference.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/PhantomReference.java @@ -23,19 +23,19 @@ package java.lang.ref; /** * @com.intel.drl.spec_ref */ -public class PhantomReference extends Reference { +public class PhantomReference<T> extends Reference<T> { /** * @com.intel.drl.spec_ref */ - public PhantomReference(Object referent, ReferenceQueue q) { + public PhantomReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } /** * @com.intel.drl.spec_ref */ - public Object get() { + public T get() { return null; } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/Reference.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/Reference.java index ff2e10e..46982df 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/Reference.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/Reference.java @@ -23,25 +23,23 @@ package java.lang.ref; /** * @com.intel.drl.spec_ref */ -public abstract class Reference { +public abstract class Reference<T> { - volatile Object referent; + private volatile T referent; - ReferenceQueue queue; + ReferenceQueue<? super T> queue; Reference next; - Reference(Object referent) { - initReference(referent); + Reference(T referent) { + this.referent = referent; } - Reference(Object referent, ReferenceQueue q) { + Reference(T referent, ReferenceQueue<? super T> q) { this.queue = q; - initReference(referent); + this.referent = referent; } - native void initReference(Object referent); - /** * @com.intel.drl.spec_ref */ @@ -64,7 +62,7 @@ public abstract class Reference { /** * @com.intel.drl.spec_ref */ - public Object get() { + public T get() { return referent; } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/ReferenceQueue.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/ReferenceQueue.java index cd8ef97..d192ce9 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/ReferenceQueue.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/ReferenceQueue.java @@ -23,9 +23,9 @@ package java.lang.ref; /** * @com.intel.drl.spec_ref */ -public class ReferenceQueue extends Object { +public class ReferenceQueue<T> extends Object { - private Reference firstReference; + private Reference<? extends T> firstReference; /** * @com.intel.drl.spec_ref @@ -36,10 +36,11 @@ public class ReferenceQueue extends Obje /** * @com.intel.drl.spec_ref */ - public synchronized Reference poll() { + @SuppressWarnings("unchecked") + public synchronized Reference<? extends T> poll() { if (firstReference == null) return null; - Reference ref = firstReference; + Reference<? extends T> ref = firstReference; firstReference = (firstReference.next == firstReference ? null : firstReference.next); ref.next = null; @@ -49,13 +50,14 @@ public class ReferenceQueue extends Obje /** * @com.intel.drl.spec_ref */ - public synchronized Reference remove(long timeout) + @SuppressWarnings("unchecked") + public synchronized Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException { if (firstReference == null) wait(timeout); if (firstReference == null) return null; - Reference ref = firstReference; + Reference<? extends T> ref = firstReference; firstReference = (firstReference.next == firstReference ? null : firstReference.next); ref.next = null; @@ -65,11 +67,11 @@ public class ReferenceQueue extends Obje /** * @com.intel.drl.spec_ref */ - public Reference remove() throws InterruptedException { + public Reference<? extends T> remove() throws InterruptedException { return remove(0L); } - synchronized boolean enqueue(Reference ref) { + synchronized boolean enqueue(Reference<? extends T> ref) { ref.next = (firstReference == null ? ref : firstReference); firstReference = ref; notify(); diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/SoftReference.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/SoftReference.java index 1cc7253..af792af 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/SoftReference.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/SoftReference.java @@ -23,26 +23,26 @@ package java.lang.ref; /** * @com.intel.drl.spec_ref */ -public class SoftReference extends Reference { +public class SoftReference<T> extends Reference<T> { /** * @com.intel.drl.spec_ref */ - public SoftReference(Object referent) { + public SoftReference(T referent) { super(referent); } /** * @com.intel.drl.spec_ref */ - public SoftReference(Object referent, ReferenceQueue q) { + public SoftReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } /** * @com.intel.drl.spec_ref */ - public Object get() { + public T get() { return super.get(); } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/WeakReference.java vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/WeakReference.java index 32b38a8..8bf52c6 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/WeakReference.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/ref/WeakReference.java @@ -23,19 +23,19 @@ package java.lang.ref; /** * @com.intel.drl.spec_ref */ -public class WeakReference extends Reference { +public class WeakReference<T> extends Reference<T> { /** * @com.intel.drl.spec_ref */ - public WeakReference(Object referent) { + public WeakReference(T referent) { super(referent); } /** * @com.intel.drl.spec_ref */ - public WeakReference(Object referent, ReferenceQueue q) { + public WeakReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/AccessibleObject.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/AccessibleObject.java index 2c047e7..cacecfb 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/AccessibleObject.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/AccessibleObject.java @@ -14,19 +14,56 @@ * limitations under the License. */ /** - * @author Evgueni Brevnov + * @author Evgueni Brevnov, Serguei S. Zapreyev * @version $Revision: 1.1.2.2.4.4 $ */ package java.lang.reflect; +import java.lang.annotation.Annotation; + import org.apache.harmony.lang.reflect.ReflectPermissionCollection; import org.apache.harmony.lang.reflect.Reflection; /** * @com.intel.drl.spec_ref */ -public class AccessibleObject { +public class AccessibleObject implements AnnotatedElement { + /** + * + * @com.intel.drl.spec_ref + * + **/ + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + return getAnnotation(annotationClass) == null ? false : true; // it seems to be correct for Method, Constructor, Field type object + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getAnnotations() { + return getDeclaredAnnotations(); // it seems to be correct for Method, Constructor, Field type object + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public Annotation[] getDeclaredAnnotations() { + return (Annotation[]) null; // because of the method is overwritten in the Method, Constructor, Field classes + } + + /** + * + * @com.intel.drl.spec_ref + * + **/ + public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { + return (T) null; // because of the method is overwritten in the Method, Constructor, Field classes + } /** * one dimensional array @@ -133,7 +170,7 @@ public class AccessibleObject { * @param obj the class which name should be appended to the buffer * @throws NullPointerException if any of the arguments is null */ - void appendArrayType(StringBuffer sb, Class obj) { + void appendArrayType(StringBuilder sb, Class<?> obj) { Class simplified = obj.getComponentType(); if (simplified == null) { sb.append(obj.getName()); @@ -172,7 +209,7 @@ public class AccessibleObject { * @param objs array of classes to print the names * @throws NullPointerException if any of the arguments is null */ - void appendArrayType(StringBuffer sb, Class[] objs) { + void appendArrayType(StringBuilder sb, Class[] objs) { if (objs.length > 0) { appendArrayType(sb, objs[0]); for (int i = 1; i < objs.length; i++) { @@ -185,6 +222,72 @@ public class AccessibleObject { /** * Appends names of the specified array classes to the buffer. The array * elements may represent a simple type, a reference type or an array type. + * Output format: java.lang.Object[], java.io.File, void + * + * @param sb buffer + * @param objs array of classes to print the names + * @throws NullPointerException if any of the arguments is null + */ + void appendArrayGenericType(StringBuilder sb, Type[] objs) { + if (objs.length > 0) { + appendGenericType(sb, objs[0]); + for (int i = 1; i < objs.length; i++) { + sb.append(','); + appendGenericType(sb, objs[i]); + } + } + } + + /** + * Appends the generic type representation to the buffer. + * + * @param sb buffer + * @param obj the generic type which representation should be appended to the buffer + * @throws NullPointerException if any of the arguments is null + */ + void appendGenericType(StringBuilder sb, Type obj) { + if (obj instanceof TypeVariable) { + sb.append(((TypeVariable)obj).getName()); + } else if (obj instanceof ParameterizedType) { + sb.append(obj.toString()); + } else if (obj instanceof GenericArrayType) { //XXX: is it a working branch? + Type simplified = ((GenericArrayType)obj).getGenericComponentType(); + appendGenericType(sb, simplified); + sb.append("[]"); + } else if (obj instanceof Class) { + Class c = ((Class<?>)obj); if (c.isArray()){ String as[] = c.getName().split("\\["); + int len = as.length-1; + if (as[len].length() > 1){ sb.append(as[len].substring(1, as[len].length()-1)); + } else { + char ch = as[len].charAt(0); + if (ch == 'I') + sb.append("int"); + else if (ch == 'B') + sb.append("byte"); + else if (ch == 'J') + sb.append("long"); + else if (ch == 'F') + sb.append("float"); + else if (ch == 'D') + sb.append("double"); + else if (ch == 'S') + sb.append("short"); + else if (ch == 'C') + sb.append("char"); + else if (ch == 'Z') + sb.append("boolean"); + else if (ch == 'V') //XXX: is it a working branch? + sb.append("void"); + } + for (int i = 0; i < len; i++){ sb.append("[]"); + } } else { + sb.append(c.getName()); } + } + } + + /** + * Appends names of the specified array classes to the buffer. The array + * elements may represent a simple type, a reference type or an array type. * In case if the specified array element represents an array type its * internal will be appended to the buffer. * Output format: [Ljava.lang.Object;, java.io.File, void @@ -193,7 +296,7 @@ public class AccessibleObject { * @param objs array of classes to print the names * @throws NullPointerException if any of the arguments is null */ - void appendSimpleType(StringBuffer sb, Class[] objs) { + void appendSimpleType(StringBuilder sb, Class<?>[] objs) { if (objs.length > 0) { sb.append(objs[0].getName()); for (int i = 1; i < objs.length; i++) { @@ -212,7 +315,7 @@ public class AccessibleObject { */ private void setAccessible0(boolean flag) throws SecurityException { if (flag && this instanceof Constructor - && ((Constructor)this).getDeclaringClass() == Class.class) { + && ((Constructor<?>)this).getDeclaringClass() == Class.class) { throw new SecurityException( "Can not make the java.lang.Class class constructor accessible"); } @@ -220,42 +323,6 @@ public class AccessibleObject { } /** - * Returns the signature-alike name representation of the class or interface. - * - * @param c class to request the signature - * @return the signature-alike name of the class or interface - */ - static String getClassSignature(Class c) { - StringBuffer buf = new StringBuffer(); - while (c.isArray()) { - buf.append('['); - c = c.getComponentType(); - } - - if (!c.isPrimitive()) - buf.append('L').append(c.getName().replace('.', '/')).append(';'); - else if (c == int.class) - buf.append('I'); - else if (c == byte.class) - buf.append('B'); - else if (c == long.class) - buf.append('J'); - else if (c == float.class) - buf.append('F'); - else if (c == double.class) - buf.append('D'); - else if (c == short.class) - buf.append('S'); - else if (c == char.class) - buf.append('C'); - else if (c == boolean.class) - buf.append('Z'); - else if (c == void.class) - buf.append('V'); - return buf.toString(); - } - - /** * Ensures that actual parameters are compartible with types of * formal parameters. For reference types, argument can be either * null or assignment-compatible with formal type. @@ -264,7 +331,7 @@ public class AccessibleObject { * @param args runtime arguments * @throws IllegalArgumentException if arguments are incompartible */ - static void checkInvokationArguments(Class[] types, Object[] args) { + static void checkInvokationArguments(Class<?>[] types, Object[] args) { if ((args == null) ? types.length != 0 : args.length != types.length) { throw new IllegalArgumentException( diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Array.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Array.java index ed4a642..74dd0e7 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Array.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Array.java @@ -196,7 +196,7 @@ public final class Array { /** * @com.intel.drl.spec_ref */ - public static Object newInstance(Class componentType, int length) + public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException { return newInstance(componentType, new int[] { length }); } @@ -204,7 +204,7 @@ public final class Array { /** * @com.intel.drl.spec_ref */ - public static Object newInstance(Class componentType, int[] dimensions) + public static Object newInstance(Class<?> componentType, int[] dimensions) throws IllegalArgumentException, NegativeArraySizeException { if (componentType == null) { throw new NullPointerException(); diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Constructor.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Constructor.java index d0d68a9..98b4ca8 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Constructor.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Constructor.java @@ -14,20 +14,174 @@ * limitations under the License. */ /** - * @author Evgueni Brevnov + * @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov * @version $Revision: 1.1.2.2.4.4 $ */ package java.lang.reflect; +import static org.apache.harmony.vm.ClassFormat.ACC_VARARGS; +import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC; + +import java.lang.annotation.Annotation; import java.util.Arrays; +import org.apache.harmony.lang.reflect.parser.Parser; +import org.apache.harmony.lang.reflect.parser.Parser.SignatureKind; +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimTypeVariable; +import org.apache.harmony.lang.reflect.parser.InterimType; +import org.apache.harmony.lang.reflect.parser.InterimClassType; +import org.apache.harmony.lang.reflect.parser.InterimTypeParameter; +import org.apache.harmony.lang.reflect.parser.InterimGenericArrayType; +import org.apache.harmony.lang.reflect.parser.InterimConstructorGenericDecl; + +import org.apache.harmony.lang.reflect.repository.TypeVariableRepository; +import org.apache.harmony.lang.reflect.repository.ParameterizedTypeRepository; + +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; +import org.apache.harmony.lang.reflect.support.AuxiliaryCreator; +import org.apache.harmony.lang.reflect.support.AuxiliaryChecker; +import org.apache.harmony.lang.reflect.support.AuxiliaryLoader; +import org.apache.harmony.lang.reflect.support.AuxiliaryUtil; + +import org.apache.harmony.lang.reflect.implementation.TypeVariableImpl; +import org.apache.harmony.lang.reflect.implementation.ParameterizedTypeImpl; + import org.apache.harmony.vm.VMStack; +import org.apache.harmony.vm.VMGenericsAndAnnotations; /** - * @com.intel.drl.spec_ref - */ -public final class Constructor extends AccessibleObject implements Member { +* @com.intel.drl.spec_ref +*/ +public final class Constructor<T> extends AccessibleObject implements Member, GenericDeclaration { + + /** + * @com.intel.drl.spec_ref + */ + public boolean isVarArgs() { + return (getModifiers() & ACC_VARARGS) != 0; + } + + /** + * @com.intel.drl.spec_ref + */ + public Annotation[][] getParameterAnnotations() { + Annotation a[][] = data.getParameterAnnotations(); + Annotation aa[][] = new Annotation[a.length][]; + for (int i = 0; i < a.length; i++ ) { + aa[i] = new Annotation[a[i].length]; + System.arraycopy(a[i], 0, aa[i], 0, a[i].length); + } + return aa; + } + + /** + * @com.intel.drl.spec_ref + */ + public Annotation[] getDeclaredAnnotations() { + Annotation a[] = data.getDeclaredAnnotations(); + Annotation aa[] = new Annotation[a.length]; + System.arraycopy(a, 0, aa, 0, a.length); + return aa; + } + + /** + * @com.intel.drl.spec_ref + */ + public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + Annotation aa[] = data.getDeclaredAnnotations(); + for (int i = 0; i < aa.length; i++) { + if(aa[i].annotationType() == annotationClass) { + return (A) aa[i]; + } + } + return null; + } + + /** + * @com.intel.drl.spec_ref + */ + public Type[] getGenericExceptionTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericExceptionTypes == null) { + data.initGenericExceptionTypes(); + } + + return (Type[])data.genericExceptionTypes.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public Type[] getGenericParameterTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericParameterTypes == null) { + data.initGenericParameterTypes(); + } + + return (Type[])data.genericParameterTypes.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public TypeVariable<Constructor<T>>[] getTypeParameters() throws GenericSignatureFormatError { + if (data.typeParameters == null) { + data.initTypeParameters(); + } + return (TypeVariable<Constructor<T>>[])data.typeParameters.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public String toGenericString() { + StringBuilder sb = new StringBuilder(80); + // data initialization + if (data.genericParameterTypes == null) { + data.initGenericParameterTypes(); + } + if (data.genericExceptionTypes == null) { + data.initGenericExceptionTypes(); + } + // append modifiers if any + int modifier = getModifiers(); + if (modifier != 0) { + sb.append(Modifier.toString(modifier & ~ACC_VARARGS)).append(' '); + } + // append type parameters + if (data.typeParameters != null && data.typeParameters.length > 0) { + sb.append('<'); + for (int i = 0; i < data.typeParameters.length; i++) { + appendGenericType(sb, data.typeParameters[i]); + if (i < data.typeParameters.length - 1) { + sb.append(", "); + } + } + sb.append("> "); + } + // append constructor name + appendArrayType(sb, getDeclaringClass()); + // append parameters + sb.append('('); + appendArrayGenericType(sb, data.genericParameterTypes); + sb.append(')'); + // append exeptions if any + if (data.genericExceptionTypes.length > 0) { + sb.append(" throws "); + appendArrayGenericType(sb, data.genericExceptionTypes); + } + return sb.toString(); + } + + /** + * @com.intel.drl.spec_ref + */ + public boolean isSynthetic() { + return (getModifiers() & ACC_SYNTHETIC) != 0; + } /** * cache of the constructor data @@ -39,52 +193,41 @@ public final class Constructor extends A * * @param c original constructor */ - Constructor(Constructor c) { + Constructor(Constructor <T> c) { data = c.data; isAccessible = c.isAccessible; } /** - * Only VM should call this constructor - * - * @param obj constructor handler + * Only VM should call this constructor. + * String parameters must be interned. * @api2vm */ - Constructor(Object obj) { - data = new ConstructorData(obj); + Constructor(long id, Class<T> clss, String name, String desc, int m) { + data = new ConstructorData(id, clss, name, desc, m); } /** - * TODO : fix gmj - */ - public boolean isSynthetic() { - return false; - } - - /** * Called by VM to obtain this constructor's handle. * * @return handle for this constructor * @api2vm */ - Object getHandle() { - return data.id; + long getId() { + return data.vm_member_id; } /** * @com.intel.drl.spec_ref */ public boolean equals(Object obj) { - try { - // Sole comparison by id is not enough because there are constructors - // created through JNI. That constructors have different ids. + if (obj instanceof Constructor) { Constructor another = (Constructor)obj; - if (data.id == another.data.id){ + if (data.vm_member_id == another.data.vm_member_id){ + assert getDeclaringClass() == another.getDeclaringClass() + && Arrays.equals(getParameterTypes(), another.getParameterTypes()); return true; } - return getDeclaringClass().equals(another.getDeclaringClass()) - && Arrays.equals(getParameterTypes(), another.getParameterTypes()); - } catch (RuntimeException e) { } return false; } @@ -92,30 +235,21 @@ public final class Constructor extends A /** * @com.intel.drl.spec_ref */ - public Class getDeclaringClass() { - if (data.declaringClass == null) { - data.initDeclaringClass(); - } + public Class<T> getDeclaringClass() { return data.declaringClass; } /** * @com.intel.drl.spec_ref */ - public Class[] getExceptionTypes() { - if (data.exceptionTypes == null) { - data.initExceptionTypes(); - } - return (Class[])data.exceptionTypes.clone(); + public Class<?>[] getExceptionTypes() { + return (Class[])data.getExceptionTypes().clone(); } /** * @com.intel.drl.spec_ref */ public int getModifiers() { - if (data.modifiers == -1) { - data.initModifiers(); - } return data.modifiers; } @@ -123,20 +257,14 @@ public final class Constructor extends A * @com.intel.drl.spec_ref */ public String getName() { - if (data.name == null) { - data.initName(); - } - return data.name; + return data.getName(); } /** * @com.intel.drl.spec_ref */ - public Class[] getParameterTypes() { - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - return (Class[])data.parameterTypes.clone(); + public Class<?>[] getParameterTypes() { + return (Class[])data.getParameterTypes().clone(); } /** @@ -149,7 +277,7 @@ public final class Constructor extends A /** * @com.intel.drl.spec_ref */ - public Object newInstance(Object[] args) throws InstantiationException, + public T newInstance(Object... args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (Modifier.isAbstract(getDeclaringClass().getModifiers())) { @@ -158,10 +286,7 @@ public final class Constructor extends A } // check parameter validity - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - checkInvokationArguments(data.parameterTypes, args); + checkInvokationArguments(data.getParameterTypes(), args); if (!isAccessible) { reflectExporter.checkMemberAccess(VMStack.getCallerClass(0), @@ -169,36 +294,32 @@ public final class Constructor extends A getDeclaringClass(), getModifiers()); } - return VMReflection.newClassInstance(data.id, args); + return (T)VMReflection.newClassInstance(data.vm_member_id, args); } /** * @com.intel.drl.spec_ref */ public String toString() { - StringBuffer sb = new StringBuffer(); - // data initialization - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - if (data.exceptionTypes == null) { - data.initExceptionTypes(); - } + StringBuilder sb = new StringBuilder(80); // append modifiers if any int modifier = getModifiers(); if (modifier != 0) { - sb.append(Modifier.toString(modifier)).append(' '); + // VARARGS incorrectly recognized + final int MASK = ~ACC_VARARGS; + sb.append(Modifier.toString(modifier & MASK)).append(' '); } // append constructor name appendArrayType(sb, getDeclaringClass()); // append parameters sb.append('('); - appendArrayType(sb, data.parameterTypes); + appendArrayType(sb, data.getParameterTypes()); sb.append(')'); // append exeptions if any - if (data.exceptionTypes.length > 0) { + Class[] exn = data.getExceptionTypes(); + if (exn.length > 0) { sb.append(" throws "); - appendSimpleType(sb, data.exceptionTypes); + appendSimpleType(sb, exn); } return sb.toString(); } @@ -206,22 +327,12 @@ public final class Constructor extends A /* NON API SECTION */ /** - * Reconstructs the signature of this constructor. + * This method is used by serialization mechanism. * * @return the signature of the constructor */ String getSignature() { - //XXX: seems, it may be more effective to realize this request via - //API2VM interface, i.e. just to obtain the signature of the constructor descriptor - //from the class file. - StringBuffer buf = new StringBuffer().append('('); - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - for (int i = 0; i < data.parameterTypes.length; i++) - buf.append(getClassSignature(data.parameterTypes[i])); - buf.append(")V"); - return buf.toString().replace('/','.'); + return data.descriptor; } /** @@ -233,82 +344,264 @@ public final class Constructor extends A * constructor handle which is used to retrieve all necessary * information about this constructor object */ - final Object id; - + final long vm_member_id; + /** - * declaring class + * constructor generic signature */ - Class declaringClass; + String constrSignature; /** - * constructor exceptions + * constructor generic declaration */ - Class[] exceptionTypes; + InterimConstructorGenericDecl constrGenDecl; - /** - * constructor modifiers - */ - int modifiers = -1; + Annotation[] declaredAnnotations; + + final Class<T> declaringClass; + + Class<?>[] exceptionTypes; + + Type[] genericExceptionTypes; + + Type[] genericParameterTypes; + + final int modifiers; - /** - * constructor name - */ String name; - /** - * constructor parameters - */ - Class[] parameterTypes; + Annotation[][] parameterAnnotations; + + Class<?>[] parameterTypes; + + TypeVariable<Constructor<T>>[] typeParameters; + final String descriptor; /** * @param obj constructor handler */ - public ConstructorData(Object obj) { - id = obj; + public ConstructorData(long vm_id, Class<T> clss, String name, String desc, int mods) { + vm_member_id = vm_id; + declaringClass = clss; + this.name = null; + modifiers = mods; + descriptor = desc; } - - /** - * initializes declaring class - */ - public synchronized void initDeclaringClass() { - if (declaringClass == null) { - declaringClass = VMReflection.getDeclaringClass(id); + + String getName() { + if (name == null) { + name = declaringClass.getName(); + } + return name; + } + + public Annotation[] getDeclaredAnnotations() { + if (declaredAnnotations == null) { + declaredAnnotations = VMGenericsAndAnnotations + .getDeclaredAnnotations(vm_member_id); } + return declaredAnnotations; } /** * initializes exeptions */ - public synchronized void initExceptionTypes() { + public Class[] getExceptionTypes() { if (exceptionTypes == null) { - exceptionTypes = VMReflection.getExceptionTypes(id); + exceptionTypes = VMReflection.getExceptionTypes(vm_member_id); } + return exceptionTypes; } /** - * initializes modifiers + * initializes generalized exeptions */ - public synchronized void initModifiers() { - if (modifiers == -1) { - modifiers = VMReflection.getModifiers(id); + public synchronized void initGenericExceptionTypes() { + //So, here it can be ParameterizedType or TypeVariable or ordinary reference class type elements. + if (genericExceptionTypes == null) { + Object startPoint = Constructor.this; + if (constrSignature == null) { + constrSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (constrSignature == null) { + genericExceptionTypes = getExceptionTypes(); + return; + } + } + if (constrGenDecl == null) { + // constrSignature&constrGenDecl is also the "hard" way to rethrow GenericSignatureFormatError each time for a while + constrGenDecl = (InterimConstructorGenericDecl) Parser.parseSignature(constrSignature, SignatureKind.CONSTRUCTOR_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimType[] throwns = constrGenDecl.throwns; + if (throwns == null) { + genericExceptionTypes = getExceptionTypes(); + return; + } + int l = throwns.length; + genericExceptionTypes = new Type[l]; + for (int i = 0; i < l; i++) { + if (throwns[i] instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) throwns[i], ((InterimParameterizedType) throwns[i]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) throwns[i], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) throwns[i]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + //check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) throwns[i], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) throwns[i], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) throwns[i], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) throwns[i], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) throwns[i], ((InterimParameterizedType) throwns[i]).signature, startPoint); + } + genericExceptionTypes[i] = (Type) pType; + } else if (throwns[i] instanceof InterimClassType) { + try { + genericExceptionTypes[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)throwns[i]).classTypeName.substring(1).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)throwns[i]).classTypeName.substring(1).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else if (throwns[i] instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) throwns[i]).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + genericExceptionTypes[i] = (Type) null; + break; + } + } + genericExceptionTypes[i] = (Type) variable; + } else { + // Internal Error + } + } } } /** - * initializes name + * initializes generalized parameters */ - public synchronized void initName() { - if (name == null) { - name = VMReflection.getName(id); + public synchronized void initGenericParameterTypes() { + //So, here it can be ParameterizedType or TypeVariable or ordinary reference class type elements. + if (genericParameterTypes == null) { + Object startPoint = Constructor.this; + if (constrSignature == null) { + constrSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (constrSignature == null) { + genericParameterTypes = getParameterTypes(); + return; + } + } + if (constrGenDecl == null) { + constrGenDecl = (InterimConstructorGenericDecl) Parser.parseSignature(constrSignature, SignatureKind.CONSTRUCTOR_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimType[] methodParameters = constrGenDecl.methodParameters; + if (methodParameters == null) { + genericParameterTypes = new Type[0]; + return; + } + int l = methodParameters.length; + genericParameterTypes = new Type[l]; + for (int i = 0; i < l; i++) { + if (methodParameters[i] instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) methodParameters[i], ((InterimParameterizedType) methodParameters[i]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) methodParameters[i], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) methodParameters[i]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + //check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) methodParameters[i], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) methodParameters[i], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) methodParameters[i], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) methodParameters[i], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) methodParameters[i], ((InterimParameterizedType) methodParameters[i]).signature, startPoint); + } + genericParameterTypes[i] = (Type) pType; + } else if (methodParameters[i] instanceof InterimClassType) { + try { + genericParameterTypes[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)methodParameters[i]).classTypeName.substring((((InterimClassType)methodParameters[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)methodParameters[i]).classTypeName.substring((((InterimClassType)methodParameters[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else if (methodParameters[i] instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) methodParameters[i]).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + genericParameterTypes[i] = (Type) null; + continue; + } + } + genericParameterTypes[i] = (Type) variable; + } else if (methodParameters[i] instanceof InterimGenericArrayType) { + genericParameterTypes[i] = AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType) methodParameters[i], startPoint); + } else { + // Internal Error + } + } } } + public Annotation[][] getParameterAnnotations() { + if (parameterAnnotations == null) { + parameterAnnotations = VMGenericsAndAnnotations + .getParameterAnnotations(vm_member_id); + } + return parameterAnnotations; + } + /** * initializes parameters */ - public synchronized void initParameterTypes() { + public Class[] getParameterTypes() { if (parameterTypes == null) { - parameterTypes = VMReflection.getParameterTypes(id); + parameterTypes = VMReflection.getParameterTypes(vm_member_id); + } + return parameterTypes; + } + + /** + * initializes type parameters + */ + public synchronized void initTypeParameters() { + //So, here it can be only TypeVariable elements. + if (typeParameters == null) { + Object startPoint = Constructor.this; + if (constrSignature == null) { + constrSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (constrSignature == null) { + typeParameters = new TypeVariable[0]; + return; + } + } + if (constrGenDecl == null) { + constrGenDecl = (InterimConstructorGenericDecl) Parser.parseSignature(constrSignature, SignatureKind.CONSTRUCTOR_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimTypeParameter[] pTypeParameters = constrGenDecl.typeParameters; + if (pTypeParameters == null) { + typeParameters = new TypeVariable[0]; + return; + } + int l = pTypeParameters.length; + typeParameters = new TypeVariable[l]; + for (int i = 0; i < l; i++) { + String tvName = pTypeParameters[i].typeParameterName; + TypeVariable variable = new TypeVariableImpl((GenericDeclaration)Constructor.this, tvName, constrGenDecl.typeParameters[i]); + TypeVariableRepository.registerTypeVariable(variable, tvName, startPoint); + typeParameters[i] = variable; + } } } } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Field.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Field.java index 51f30f0..486695f 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Field.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Field.java @@ -14,20 +14,153 @@ * limitations under the License. */ /** - * @author Evgueni Brevnov + * @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov * @version $Revision: 1.1.2.2.4.4 $ */ package java.lang.reflect; +import static org.apache.harmony.vm.ClassFormat.ACC_ENUM; +import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC; + +import java.lang.annotation.Annotation; + +import org.apache.harmony.lang.reflect.parser.InterimFieldGenericDecl; +import org.apache.harmony.lang.reflect.parser.Parser; +import org.apache.harmony.lang.reflect.parser.Parser.SignatureKind; +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimTypeVariable; +import org.apache.harmony.lang.reflect.parser.InterimGenericArrayType; +import org.apache.harmony.lang.reflect.parser.InterimGenericType; + +import org.apache.harmony.lang.reflect.repository.TypeVariableRepository; +import org.apache.harmony.lang.reflect.repository.ParameterizedTypeRepository; + +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; +import org.apache.harmony.lang.reflect.support.AuxiliaryCreator; +import org.apache.harmony.lang.reflect.support.AuxiliaryChecker; +import org.apache.harmony.lang.reflect.support.AuxiliaryUtil; + +import org.apache.harmony.lang.reflect.implementation.ParameterizedTypeImpl; + import org.apache.harmony.vm.VMStack; +import org.apache.harmony.vm.VMGenericsAndAnnotations; /** - * @com.intel.drl.spec_ref - */ +* @com.intel.drl.spec_ref +*/ public final class Field extends AccessibleObject implements Member { /** + * @com.intel.drl.spec_ref + */ + public Annotation[] getDeclaredAnnotations() { + Annotation a[] = data.getAnnotations(); + Annotation aa[] = new Annotation[a.length]; + System.arraycopy(a, 0, aa, 0, a.length); + return aa; + } + + /** + * @com.intel.drl.spec_ref + */ + public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + Annotation aa[] = data.getAnnotations(); + for (int i = 0; i < aa.length; i++) { + if(aa[i].annotationType() == annotationClass) { + return (T) aa[i]; + } + } + return null; + } + + /** + * @com.intel.drl.spec_ref + */ + public Type getGenericType() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericType == null) { + Object startPoint = data.declaringClass; + String signature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(data.vm_member_id)); + if (signature == null) { + return data.genericType = (Type)data.getType(); + } + InterimFieldGenericDecl decl = (InterimFieldGenericDecl) Parser.parseSignature(signature, SignatureKind.FIELD_SIGNATURE, (GenericDeclaration)startPoint); + InterimGenericType fldType = decl.fieldType; + if (fldType instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) fldType).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + return (Type) null; + } + } + data.genericType = (Type) variable; + return (Type) variable; + } else if (fldType instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) fldType, ((InterimParameterizedType) fldType).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) fldType, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) fldType).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) fldType, startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) fldType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) fldType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) fldType, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) fldType, ((InterimParameterizedType) fldType).signature, startPoint); + } + data.genericType = (Type) pType; + return pType; + } else if (fldType instanceof InterimGenericArrayType) { + return AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType) fldType, startPoint); + } else { + return data.genericType = (Type)data.getType(); + } + } + return data.genericType; + } + + /** + * @com.intel.drl.spec_ref + */ + public String toGenericString() { + StringBuilder sb = new StringBuilder(80); + // append modifiers if any + int modifier = getModifiers(); + if (modifier != 0) { + sb.append(Modifier.toString(modifier)).append(' '); + } + // append generic type + appendGenericType(sb, getGenericType()); + sb.append(' '); + // append full field name + sb.append(getDeclaringClass().getName()).append('.').append(getName()); + return sb.toString(); + } + + /** + * @com.intel.drl.spec_ref + */ + public boolean isSynthetic() { + return (getModifiers() & ACC_SYNTHETIC) != 0; + } + + /** + * @com.intel.drl.spec_ref + */ + public boolean isEnumConstant() { + return (getModifiers() & ACC_ENUM) != 0; + } + + /** * cache of the field data */ private final FieldData data; @@ -44,19 +177,11 @@ public final class Field extends Accessi /** * Only VM should call this constructor. - * - * @param obj field handler + * String parameters must be interned. * @api2vm */ - Field(Object obj) { - data = new FieldData(obj); - } - - /** - * TODO : fix gmj - */ - public boolean isSynthetic() { - return false; + Field(long id, Class clss, String name, String desc, int m) { + data = new FieldData(id, clss, name, desc, m); } /** @@ -65,21 +190,21 @@ public final class Field extends Accessi * @return handle for this field * @api2vm */ - Object getHandle() { - return data.id; + long getId() { + return data.vm_member_id; } /** * @com.intel.drl.spec_ref */ public boolean equals(Object obj) { - try { - // Sole comparison by id is not enought because there are fields created - // through JNI. That fields have different ids. - return data.id == ((Field)obj).data.id - || (getDeclaringClass().equals( ((Field)obj).getDeclaringClass()) - && getName().equals( ((Field)obj).getName())); - } catch (RuntimeException e) { + if (obj instanceof Field) { + Field that = (Field)obj; + if (data.vm_member_id == that.data.vm_member_id) { + assert getDeclaringClass() == that.getDeclaringClass() + && getName() == that.getName(); + return true; + } } return false; } @@ -90,7 +215,7 @@ public final class Field extends Accessi public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - return VMReflection.getFieldValue(obj, data.id); + return VMField.getObject(obj, data.vm_member_id); } /** @@ -99,10 +224,7 @@ public final class Field extends Accessi public boolean getBoolean(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - if (getType() == Boolean.TYPE) { - return ((Boolean)VMReflection.getFieldValue(obj, data.id)).booleanValue(); - } - throw getIllegalArgumentException(Boolean.TYPE); + return VMField.getBoolean(obj, data.vm_member_id); } /** @@ -111,10 +233,7 @@ public final class Field extends Accessi public byte getByte(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - if (getType() == Byte.TYPE) { - return ((Number)VMReflection.getFieldValue(obj, data.id)).byteValue(); - } - throw getIllegalArgumentException(Byte.TYPE); + return VMField.getByte(obj, data.vm_member_id); } /** @@ -123,19 +242,13 @@ public final class Field extends Accessi public char getChar(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - if (getType() == Character.TYPE) { - return ((Character)VMReflection.getFieldValue(obj, data.id)).charValue(); - } - throw getIllegalArgumentException(Character.TYPE); + return VMField.getChar(obj, data.vm_member_id); } /** * @com.intel.drl.spec_ref */ - public Class getDeclaringClass() { - if (data.declaringClass == null) { - data.initDeclaringClass(); - } + public Class<?> getDeclaringClass() { return data.declaringClass; } @@ -145,14 +258,7 @@ public final class Field extends Accessi public double getDouble(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - Class type = getType(); - if (type.isPrimitive() && type != Boolean.TYPE) { - if (type == Character.TYPE) { - return ((Character)VMReflection.getFieldValue(obj, data.id)).charValue(); - } - return ((Number)VMReflection.getFieldValue(obj, data.id)).doubleValue(); - } - throw getIllegalArgumentException(Double.TYPE); + return VMField.getDouble(obj, data.vm_member_id); } /** @@ -161,14 +267,7 @@ public final class Field extends Accessi public float getFloat(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - Class type = getType(); - if (type.isPrimitive() && type != Double.TYPE && type != Boolean.TYPE) { - if (type == Character.TYPE) { - return ((Character)VMReflection.getFieldValue(obj, data.id)).charValue(); - } - return ((Number)VMReflection.getFieldValue(obj, data.id)).floatValue(); - } - throw getIllegalArgumentException(Float.TYPE); + return VMField.getFloat(obj, data.vm_member_id); } /** @@ -177,14 +276,7 @@ public final class Field extends Accessi public int getInt(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - Class type = getType(); - if (type == Integer.TYPE || type == Short.TYPE || type == Byte.TYPE) { - return ((Number)VMReflection.getFieldValue(obj, data.id)).intValue(); - } - if (type == Character.TYPE) { - return ((Character)VMReflection.getFieldValue(obj, data.id)).charValue(); - } - throw getIllegalArgumentException(Integer.TYPE); + return VMField.getInt(obj, data.vm_member_id); } /** @@ -193,24 +285,13 @@ public final class Field extends Accessi public long getLong(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - Class type = getType(); - if (type == Long.TYPE || type == Integer.TYPE || type == Short.TYPE - || type == Byte.TYPE) { - return ((Number)VMReflection.getFieldValue(obj, data.id)).longValue(); - } - if (type == Character.TYPE) { - return ((Character)VMReflection.getFieldValue(obj, data.id)).charValue(); - } - throw getIllegalArgumentException(Long.TYPE); + return VMField.getLong(obj, data.vm_member_id); } /** * @com.intel.drl.spec_ref */ public int getModifiers() { - if (data.modifiers == -1) { - data.initModifiers(); - } return data.modifiers; } @@ -218,9 +299,6 @@ public final class Field extends Accessi * @com.intel.drl.spec_ref */ public String getName() { - if (data.name == null) { - data.initName(); - } return data.name; } @@ -230,21 +308,14 @@ public final class Field extends Accessi public short getShort(Object obj) throws IllegalArgumentException, IllegalAccessException { obj = checkGet(VMStack.getCallerClass(0), obj); - Class type = getType(); - if (type == Short.TYPE || type == Byte.TYPE) { - return ((Number)VMReflection.getFieldValue(obj, data.id)).shortValue(); - } - throw getIllegalArgumentException(Short.TYPE); + return VMField.getShort(obj, data.vm_member_id); } /** * @com.intel.drl.spec_ref */ - public Class getType() { - if (data.type == null) { - data.initType(); - } - return data.type; + public Class<?> getType() { + return data.getType(); } /** @@ -259,50 +330,8 @@ public final class Field extends Accessi */ public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { - // check that input is valid obj = checkSet(VMStack.getCallerClass(0), obj); - // is this field primitive? - if (!getType().isPrimitive()) { - //can this value be converted to the type of the field? - //(The null reference can always be converted to any reference type.) - if (value == null || getType().isInstance(value)) { - VMReflection.setFieldValue(obj, data.id, value); - return; - } - } else { // this field is primitive - if (value instanceof Number) { - if (value instanceof Integer) { - setIntNoObjectCheck(obj, ((Integer)value).intValue()); - return; - } else if (value instanceof Float) { - setFloatNoObjectCheck(obj, ((Float)value).floatValue()); - return; - } else if (value instanceof Double) { - setDoubleNoObjectCheck(obj, ((Double)value).doubleValue()); - return; - } else if (value instanceof Long) { - setLongNoObjectCheck(obj, ((Long)value).longValue()); - return; - } else if (value instanceof Short) { - setShortNoObjectCheck(obj, ((Short)value).shortValue()); - return; - } else if (value instanceof Byte) { - setByteNoObjectCheck(obj, ((Byte)value).byteValue()); - return; - } - } else if (value instanceof Boolean) { - setBooleanNoObjectCheck(obj, ((Boolean)value).booleanValue()); - return; - } else if (value instanceof Character) { - setCharNoObjectCheck(obj, ((Character)value).charValue()); - return; - } - } - // the specified value doesn't correspond to any primitive type - throw new IllegalArgumentException( - "The specified value can not be converted to a " - + getType().getName() - + " type by an unwrapping, identity and widening conversions"); + VMField.setObject(obj, data.vm_member_id, value); } /** @@ -311,7 +340,7 @@ public final class Field extends Accessi public void setBoolean(Object obj, boolean value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setBooleanNoObjectCheck(obj, value); + VMField.setBoolean(obj, data.vm_member_id, value); } /** @@ -320,7 +349,7 @@ public final class Field extends Accessi public void setByte(Object obj, byte value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setByteNoObjectCheck(obj, value); + VMField.setByte(obj, data.vm_member_id, value); } /** @@ -329,7 +358,7 @@ public final class Field extends Accessi public void setChar(Object obj, char value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setCharNoObjectCheck(obj, value); + VMField.setChar(obj, data.vm_member_id, value); } /** @@ -338,7 +367,7 @@ public final class Field extends Accessi public void setDouble(Object obj, double value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setDoubleNoObjectCheck(obj, value); + VMField.setDouble(obj, data.vm_member_id, value); } /** @@ -347,7 +376,7 @@ public final class Field extends Accessi public void setFloat(Object obj, float value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setFloatNoObjectCheck(obj, value); + VMField.setFloat(obj, data.vm_member_id, value); } /** @@ -356,7 +385,7 @@ public final class Field extends Accessi public void setInt(Object obj, int value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setIntNoObjectCheck(obj, value); + VMField.setInt(obj, data.vm_member_id, value); } /** @@ -365,7 +394,7 @@ public final class Field extends Accessi public void setLong(Object obj, long value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setLongNoObjectCheck(obj, value); + VMField.setLong(obj, data.vm_member_id, value); } /** @@ -374,14 +403,14 @@ public final class Field extends Accessi public void setShort(Object obj, short value) throws IllegalArgumentException, IllegalAccessException { obj = checkSet(VMStack.getCallerClass(0), obj); - setShortNoObjectCheck(obj, value); + VMField.setShort(obj, data.vm_member_id, value); } /** * @com.intel.drl.spec_ref */ public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(80); // append modifiers if any int modifier = getModifiers(); if (modifier != 0) { @@ -443,237 +472,55 @@ public final class Field extends Accessi } /** - * Constructs IllegalArgumentException - * - * @param targetType type to construct exception for - * @return constructed exception - */ - private IllegalArgumentException getIllegalArgumentException(Class targetType) { - return new IllegalArgumentException( - "The field value can not be converted to a \"" - + targetType.getName() + "\" type by a widening conversion"); - } - - /** - * Sets boolean value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setBooleanNoObjectCheck(Object obj, boolean value) - throws IllegalArgumentException { - if (getType() == Boolean.TYPE) { - VMReflection.setFieldValue(obj, data.id, Boolean.valueOf(value)); - return; - } - throw new IllegalArgumentException( - "The specified value can not be assigned to the field of a \"" - + getType().getName() + "\" type"); - } - - /** - * Sets byte value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setByteNoObjectCheck(Object obj, byte value) - throws IllegalArgumentException { - if (getType() == Byte.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Byte(value)); - return; - } - setShortNoObjectCheck(obj, value); - } - - /** - * Sets char value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setCharNoObjectCheck(Object obj, char value) - throws IllegalArgumentException { - if (getType() == Character.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Character(value)); - return; - } - setIntNoObjectCheck(obj, value); - } - - /** - * Sets double value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setDoubleNoObjectCheck(Object obj, double value) - throws IllegalArgumentException { - if (getType() == Double.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Double(value)); - return; - } - throw new IllegalArgumentException( - "The specified value can not be converted to a \"" - + getType().getName() - + "\" type by a primitive widening conversion"); - } - - /** - * Sets float value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setFloatNoObjectCheck(Object obj, float value) - throws IllegalArgumentException { - if (getType() == Float.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Float(value)); - return; - } - setDoubleNoObjectCheck(obj, value); - } - - /** - * Sets int value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setIntNoObjectCheck(Object obj, int value) - throws IllegalArgumentException { - if (getType() == Integer.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Integer(value)); - return; - } - setLongNoObjectCheck(obj, value); - } - - /** - * Sets long value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setLongNoObjectCheck(Object obj, long value) - throws IllegalArgumentException { - if (getType() == Long.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Long(value)); - return; - } - setFloatNoObjectCheck(obj, value); - } - - /** - * Sets short value with out obj checking - * - * @param obj object - * @param value new value - * @throws IllegalArgumentException if value is not valid - */ - private void setShortNoObjectCheck(Object obj, short value) - throws IllegalArgumentException { - if (getType() == Short.TYPE) { - VMReflection.setFieldValue(obj, data.id, new Short(value)); - return; - } - setIntNoObjectCheck(obj, value); - } - - /** - * Reconstructs the signature of this field. + * This method is used by serialization mechanism. * * @return the signature of the field */ String getSignature() { - //XXX: May it be more effective to realize this request via - //API2VM interface, i.e. just to obtain the signature of the field descriptor - //from the class file? - if (data.type == null) { - data.initType(); - } - return getClassSignature(data.type); + return data.descriptor; } /** * Keeps an information about this field */ - private class FieldData { + private static class FieldData { + + final String name; + final Class declaringClass; + final int modifiers; + private Class<?> type; + private Annotation[] declaredAnnotations; + Type genericType; + final String descriptor; /** * field handle which is used to retrieve all necessary information * about this field object */ - final Object id; + final long vm_member_id; - /** - * declaring class - */ - Class declaringClass; - - /** - * field modifiers - */ - int modifiers = -1; - - /** - * field name - */ - String name; - - /** - * field type - */ - Class type; - - /** -| * @param obj field handler - */ - public FieldData(Object obj) { - id = obj; + FieldData(long vm_id, Class clss, String name, String desc, int mods) { + vm_member_id = vm_id; + declaringClass = clss; + this.name = name; + modifiers = mods; + descriptor = desc; } - /** - * initializes declaring class - */ - public synchronized void initDeclaringClass() { - if (declaringClass == null) { - declaringClass = VMReflection.getDeclaringClass(id); - } - } - - /** - * initializes modifiers - */ - public synchronized void initModifiers() { - if (modifiers == -1) { - modifiers = VMReflection.getModifiers(id); - } - } - - /** - * initializes name - */ - public synchronized void initName() { - if (name == null) { - name = VMReflection.getName(id); + Annotation[] getAnnotations() { + if (declaredAnnotations == null) { + declaredAnnotations = VMGenericsAndAnnotations + .getDeclaredAnnotations(vm_member_id); } + return declaredAnnotations; } - - /** - * initializes type - */ - public synchronized void initType() { + + Class<?> getType() { if (type == null) { - type = VMReflection.getFieldType(id); + type = VMReflection.getFieldType(vm_member_id); } + return type; } } + } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Method.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Method.java index 6569976..31e2a20 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Method.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/Method.java @@ -14,20 +14,249 @@ * limitations under the License. */ /** - * @author Evgueni Brevnov + * @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov * @version $Revision: 1.1.2.2.4.4 $ */ package java.lang.reflect; +import static org.apache.harmony.vm.ClassFormat.ACC_BRIDGE; +import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC; +import static org.apache.harmony.vm.ClassFormat.ACC_VARARGS; + +import java.lang.annotation.Annotation; import java.util.Arrays; +import org.apache.harmony.lang.reflect.parser.Parser; +import org.apache.harmony.lang.reflect.parser.Parser.SignatureKind; +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimTypeVariable; +import org.apache.harmony.lang.reflect.parser.InterimType; +import org.apache.harmony.lang.reflect.parser.InterimClassType; +import org.apache.harmony.lang.reflect.parser.InterimTypeParameter; +import org.apache.harmony.lang.reflect.parser.InterimGenericArrayType; +import org.apache.harmony.lang.reflect.parser.InterimMethodGenericDecl; + +import org.apache.harmony.lang.reflect.repository.TypeVariableRepository; +import org.apache.harmony.lang.reflect.repository.ParameterizedTypeRepository; + +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; +import org.apache.harmony.lang.reflect.support.AuxiliaryCreator; +import org.apache.harmony.lang.reflect.support.AuxiliaryChecker; +import org.apache.harmony.lang.reflect.support.AuxiliaryLoader; +import org.apache.harmony.lang.reflect.support.AuxiliaryUtil; + +import org.apache.harmony.lang.reflect.implementation.TypeVariableImpl; +import org.apache.harmony.lang.reflect.implementation.ParameterizedTypeImpl; + import org.apache.harmony.vm.VMStack; +import org.apache.harmony.vm.VMGenericsAndAnnotations; /** - * @com.intel.drl.spec_ref - */ -public final class Method extends AccessibleObject implements Member { +* @com.intel.drl.spec_ref +*/ +public final class Method extends AccessibleObject implements Member, GenericDeclaration { + + /** + * @com.intel.drl.spec_ref + */ + public boolean isBridge() { + return (getModifiers() & ACC_BRIDGE) != 0; + } + + /** + * @com.intel.drl.spec_ref + */ + public boolean isVarArgs() { + return (getModifiers() & ACC_VARARGS) != 0; + } + + /** + * @com.intel.drl.spec_ref + */ + public Annotation[][] getParameterAnnotations() { + Annotation a[][] = data.getParameterAnnotations(); + Annotation aa[][] = new Annotation[a.length][]; + for (int i = 0; i < a.length; i++ ) { + aa[i] = new Annotation[a[i].length]; + System.arraycopy(a[i], 0, aa[i], 0, a[i].length); + } + return aa; + } + + /** + * @com.intel.drl.spec_ref + */ + public Annotation[] getDeclaredAnnotations() { + Annotation a[] = data.getDeclaredAnnotations(); + Annotation aa[] = new Annotation[a.length]; + System.arraycopy(a, 0, aa, 0, a.length); + return aa; + } + + /** + * @com.intel.drl.spec_ref + */ + public <A extends Annotation> A getAnnotation(Class<A> annotationClass) { + if(annotationClass == null) { + throw new NullPointerException(); + } + Annotation aa[] = data.getDeclaredAnnotations(); + for (int i = 0; i < aa.length; i++) { + if(aa[i].annotationType() == annotationClass) { + return (A) aa[i]; + } + } + return null; + } + + /** + * @com.intel.drl.spec_ref + */ + public Type[] getGenericExceptionTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericExceptionTypes == null) { + data.initGenericExceptionTypes(); + } + + return (Type[])data.genericExceptionTypes.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public Type[] getGenericParameterTypes() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericParameterTypes == null) { + data.initGenericParameterTypes(); + } + + return (Type[])data.genericParameterTypes.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public Type getGenericReturnType() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { + if (data.genericReturnType == null) { + Object startPoint = this; + if (data.methSignature == null) { + data.methSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(data.vm_member_id)); + if (data.methSignature == null) { + data.genericReturnType = (Type)getReturnType(); + return data.genericReturnType; + } + } + if (data.methGenDecl == null) { + data.methGenDecl = (InterimMethodGenericDecl) Parser.parseSignature(data.methSignature, SignatureKind.METHOD_SIGNATURE, (GenericDeclaration)startPoint); + } + InterimType mthdType = data.methGenDecl.returnValue; + if (mthdType instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) mthdType).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + return (Type) null; // compatible behaviour + } + } + data.genericReturnType = (Type) variable; + return (Type) variable; + } else if (mthdType instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) mthdType, ((InterimParameterizedType) mthdType).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) mthdType, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) mthdType).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) mthdType, startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) mthdType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) mthdType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) mthdType, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) mthdType, ((InterimParameterizedType) mthdType).signature, startPoint); + } + data.genericReturnType = (Type) pType; + return (Type) pType; + } else if (mthdType instanceof InterimGenericArrayType) { + return AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType) mthdType, startPoint); + } else { + return getReturnType(); + } + } + return data.genericReturnType; + } + + /** + * @com.intel.drl.spec_ref + */ + public TypeVariable<Method>[] getTypeParameters() throws GenericSignatureFormatError { + if (data.typeParameters == null) { + data.initTypeParameters(); + } + return (TypeVariable<Method>[])data.typeParameters.clone(); + } + + /** + * @com.intel.drl.spec_ref + */ + public String toGenericString() { + StringBuilder sb = new StringBuilder(80); + // data initialization + if (data.genericParameterTypes == null) { + data.initGenericParameterTypes(); + } + if (data.genericExceptionTypes == null) { + data.initGenericExceptionTypes(); + } + // append modifiers if any + int modifier = getModifiers(); + if (modifier != 0) { + sb.append(Modifier.toString(modifier & ~(ACC_BRIDGE + ACC_VARARGS))).append(' '); + } + // append type parameters + if (data.typeParameters != null && data.typeParameters.length > 0) { + sb.append('<'); + for (int i = 0; i < data.typeParameters.length; i++) { + appendGenericType(sb, data.typeParameters[i]); + if (i < data.typeParameters.length - 1) { + sb.append(", "); + } + } + sb.append("> "); + } + // append return type + appendGenericType(sb, getGenericReturnType()); + sb.append(' '); + // append method name + appendArrayType(sb, getDeclaringClass()); + sb.append("."+getName()); + // append parameters + sb.append('('); + appendArrayGenericType(sb, data.genericParameterTypes); + sb.append(')'); + // append exeptions if any + if (data.genericExceptionTypes.length > 0) { + sb.append(" throws "); + appendArrayGenericType(sb, data.genericExceptionTypes); + } + return sb.toString(); + } + + /** + * @com.intel.drl.spec_ref + */ + public boolean isSynthetic() { + return (getModifiers() & ACC_SYNTHETIC) != 0; + } + + /** + * @com.intel.drl.spec_ref + */ + public Object getDefaultValue() { + return VMGenericsAndAnnotations.getDefaultValue(data.vm_member_id); + } /** * cache of the method data @@ -45,48 +274,37 @@ public final class Method extends Access } /** - * Only VM should call this constructor - * - * @param obj method handle + * Only VM should call this constructor. + * String parameters must be interned. * @api2vm */ - Method(Object obj) { - data = new MethodData(obj); + Method(long id, Class clss, String name, String desc, int m) { + data = new MethodData(id, clss, name, desc, m); } /** - * TODO : fix gmj - */ - public boolean isSynthetic() { - return false; - } - - /** * Called by VM to obtain this method's handle. * * @return handle for this method * @api2vm */ - Object getHandle() { - return data.id; + long getId() { + return data.vm_member_id; } /** * @com.intel.drl.spec_ref */ public boolean equals(Object obj) { - try { - // Sole comparison by method id is not enough because there are methods - // created through JNI. That methods have different ids. + if (obj instanceof Method) { Method another = (Method)obj; - if (data.id == another.data.id){ + if (data.vm_member_id == another.data.vm_member_id){ + assert getDeclaringClass() == another.getDeclaringClass() + && getName() == another.getName() + && getReturnType() == another.getReturnType() + && Arrays.equals(getParameterTypes(), another.getParameterTypes()); return true; } - return getDeclaringClass().equals(another.getDeclaringClass()) - && getName().equals(another.getName()) - && getReturnType().equals(another.getReturnType()) - && Arrays.equals(getParameterTypes(), another.getParameterTypes()); - } catch (RuntimeException e) { } return false; } @@ -94,30 +312,21 @@ public final class Method extends Access /** * @com.intel.drl.spec_ref */ - public Class getDeclaringClass() { - if (data.declaringClass == null) { - data.initDeclaringClass(); - } + public Class<?> getDeclaringClass() { return data.declaringClass; } /** * @com.intel.drl.spec_ref */ - public Class[] getExceptionTypes() { - if (data.exceptionTypes == null) { - data.initExceptionTypes(); - } - return (Class[])data.exceptionTypes.clone(); + public Class<?>[] getExceptionTypes() { + return (Class[])data.getExceptionTypes().clone(); } /** * @com.intel.drl.spec_ref */ public int getModifiers() { - if (data.modifiers == -1) { - data.initModifiers(); - } return data.modifiers; } @@ -125,30 +334,21 @@ public final class Method extends Access * @com.intel.drl.spec_ref */ public String getName() { - if (data.name == null) { - data.initName(); - } return data.name; } /** * @com.intel.drl.spec_ref */ - public Class[] getParameterTypes() { - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - return (Class[])data.parameterTypes.clone(); + public Class<?>[] getParameterTypes() { + return (Class[])data.getParameterTypes().clone(); } /** * @com.intel.drl.spec_ref */ - public Class getReturnType() { - if (data.returnType == null) { - data.initReturnType(); - } - return data.returnType; + public Class<?> getReturnType() { + return data.getReturnType(); } /** @@ -161,17 +361,14 @@ public final class Method extends Access /** * @com.intel.drl.spec_ref */ - public Object invoke(Object obj, Object[] args) + public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { obj = checkObject(getDeclaringClass(), getModifiers(), obj); // check parameter validity - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - checkInvokationArguments(data.parameterTypes, args); + checkInvokationArguments(data.getParameterTypes(), args); if (!isAccessible) { reflectExporter.checkMemberAccess( @@ -180,25 +377,20 @@ public final class Method extends Access getModifiers() ); } - return VMReflection.invokeMethod(obj, data.id, args); + return VMReflection.invokeMethod(data.vm_member_id, obj, args); } /** * @com.intel.drl.spec_ref */ public String toString() { - StringBuffer sb = new StringBuffer(); - // initialize data - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - if (data.exceptionTypes == null) { - data.initExceptionTypes(); - } + StringBuilder sb = new StringBuilder(); // append modifiers if any int modifier = getModifiers(); if (modifier != 0) { - sb.append(Modifier.toString(modifier)).append(' '); + // BRIDGE & VARARGS recognized incorrectly + final int MASK = ~(ACC_BRIDGE + ACC_VARARGS); + sb.append(Modifier.toString(modifier & MASK)).append(' '); } // append return type appendArrayType(sb, getReturnType()); @@ -207,12 +399,13 @@ public final class Method extends Access sb.append(getDeclaringClass().getName()).append('.').append(getName()); // append parameters sb.append('('); - appendArrayType(sb, data.parameterTypes); + appendArrayType(sb, data.getParameterTypes()); sb.append(')'); // append exeptions if any - if (data.exceptionTypes.length > 0) { + Class[] exn = data.getExceptionTypes(); + if (exn.length > 0) { sb.append(" throws "); - appendSimpleType(sb, data.exceptionTypes); + appendSimpleType(sb, exn); } return sb.toString(); } @@ -220,26 +413,12 @@ public final class Method extends Access /* NON API SECTION */ /** - * Reconstructs the signature of this method. + * This method is required by serialization mechanism. * * @return the signature of the method */ String getSignature() { - //XXX: seems, it may be more effective to realize this request via - //API2VM interface, i.e. just to obtain the signature of the method descriptor - //from the class file. - StringBuffer buf = new StringBuffer().append('('); - if (data.parameterTypes == null) { - data.initParameterTypes(); - } - for (int i = 0; i < data.parameterTypes.length; i++) - buf.append(getClassSignature(data.parameterTypes[i])); - buf.append(')'); - if (data.returnType == null) { - data.initReturnType(); - } - buf.append(getClassSignature(data.returnType)); - return buf.toString().replace('/','.'); + return data.descriptor; } /** @@ -251,97 +430,283 @@ public final class Method extends Access * method handle which is used to retrieve all necessary information * about this method object */ - final Object id; + final long vm_member_id; - /** - * declaring class - */ - Class declaringClass; + Annotation[] declaredAnnotations; - /** - * method exeptions - */ - Class[] exceptionTypes; + final Class<?> declaringClass; + + private Class<?>[] exceptionTypes; + + Type[] genericExceptionTypes; + + Type[] genericParameterTypes; + + Type genericReturnType; + + String methSignature; /** - * method modifiers + * method generic declaration */ - int modifiers = -1; + InterimMethodGenericDecl methGenDecl; + + final int modifiers; + + final String name; + + final String descriptor; /** - * method name + * declared method annotations */ - String name; + Annotation[][] parameterAnnotations; /** * method parameters */ - Class[] parameterTypes; + Class<?>[] parameterTypes; /** * method return type */ - Class returnType; + private Class<?> returnType; + + /** + * method type parameters + */ + TypeVariable<Method>[] typeParameters; /** * @param obj method handler */ - public MethodData(Object obj) { - id = obj; + public MethodData(long vm_id, Class clss, String name, String desc, int mods) { + vm_member_id = vm_id; + declaringClass = clss; + this.name = name; + modifiers = mods; + descriptor = desc; } - /** - * initializes declaring class - */ - public synchronized void initDeclaringClass() { - if (declaringClass == null) { - declaringClass = VMReflection.getDeclaringClass(id); + public Annotation[] getDeclaredAnnotations() { + if (declaredAnnotations == null) { + declaredAnnotations = VMGenericsAndAnnotations + .getDeclaredAnnotations(vm_member_id); } + return declaredAnnotations; } - + /** * initializes exeptions */ - public synchronized void initExceptionTypes() { + public Class<?>[] getExceptionTypes() { if (exceptionTypes == null) { - exceptionTypes = VMReflection.getExceptionTypes(id); + exceptionTypes = VMReflection.getExceptionTypes(vm_member_id); } + return exceptionTypes; } /** - * initializes modifiers + * initializes generalized exeptions */ - public synchronized void initModifiers() { - if (modifiers == -1) { - modifiers = VMReflection.getModifiers(id); + public synchronized void initGenericExceptionTypes() { + // So, here it can be ParameterizedType or TypeVariable or ordinary reference class type elements. + if (genericExceptionTypes == null) { + Object startPoint = Method.this; + if (methSignature == null) { + methSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (methSignature == null) { + genericExceptionTypes = getExceptionTypes(); + return; + } + } + if (methGenDecl == null) { + methGenDecl = (InterimMethodGenericDecl) Parser.parseSignature(methSignature, SignatureKind.METHOD_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimType[] throwns = methGenDecl.throwns; + if (throwns == null) { + genericExceptionTypes = getExceptionTypes(); + return; + } + int l = throwns.length; + genericExceptionTypes = new Type[l]; + for (int i = 0; i < l; i++) { + if (throwns[i] instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) throwns[i], ((InterimParameterizedType) throwns[i]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) throwns[i], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) throwns[i]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) throwns[i], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) throwns[i], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) throwns[i], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) throwns[i], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) throwns[i], ((InterimParameterizedType) throwns[i]).signature, startPoint); + } + genericExceptionTypes[i] = (Type) pType; + } else if (throwns[i] instanceof InterimClassType) { + try { + genericExceptionTypes[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)throwns[i]).classTypeName.substring((((InterimClassType)throwns[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)throwns[i]).classTypeName.substring((((InterimClassType)throwns[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else if (throwns[i] instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) throwns[i]).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + genericExceptionTypes[i] = (Type) null; + break; + } + } + genericExceptionTypes[i] = (Type) variable; + } else { + // Internal Error + } + } } } /** - * initializes name + * initializes generalized parameters */ - public synchronized void initName() { - if (name == null) { - name = VMReflection.getName(id); + public synchronized void initGenericParameterTypes() { + // So, here it can be ParameterizedType or TypeVariable or ordinary reference class type elements. + if (genericParameterTypes == null) { + Object startPoint = Method.this; + if (methSignature == null) { + methSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (methSignature == null) { + genericParameterTypes = getParameterTypes(); + return; + } + } + if (methGenDecl == null) { + methGenDecl = (InterimMethodGenericDecl) Parser.parseSignature(methSignature, SignatureKind.METHOD_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimType[] methodParameters = methGenDecl.methodParameters; + if (methodParameters == null) { + genericParameterTypes = new Type[0]; + return; + } + int l = methodParameters.length; + genericParameterTypes = new Type[l]; + for (int i = 0; i < l; i++) { + if (methodParameters[i] instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) methodParameters[i], ((InterimParameterizedType) methodParameters[i]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) methodParameters[i], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) methodParameters[i]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) methodParameters[i], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) methodParameters[i], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) methodParameters[i], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) methodParameters[i], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) methodParameters[i], ((InterimParameterizedType) methodParameters[i]).signature, startPoint); + } + genericParameterTypes[i] = (Type) pType; + } else if (methodParameters[i] instanceof InterimClassType) { + try { + genericParameterTypes[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)methodParameters[i]).classTypeName.substring((((InterimClassType)methodParameters[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)methodParameters[i]).classTypeName.substring((((InterimClassType)methodParameters[i]).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } else if (methodParameters[i] instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) methodParameters[i]).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + genericParameterTypes[i] = (Type) null; + continue; + } + } + genericParameterTypes[i] = (Type) variable; + } else if (methodParameters[i] instanceof InterimGenericArrayType) { + genericParameterTypes[i] = AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType) methodParameters[i], startPoint); + } else { + // Internal Error + } + } + } + } + + + public Annotation[][] getParameterAnnotations() { + if (parameterAnnotations == null) { + parameterAnnotations = VMGenericsAndAnnotations + .getParameterAnnotations(vm_member_id); } + return parameterAnnotations; } /** * initializes parameters */ - public synchronized void initParameterTypes() { + public Class[] getParameterTypes() { if (parameterTypes == null) { - parameterTypes = VMReflection.getParameterTypes(id); + parameterTypes = VMReflection.getParameterTypes(vm_member_id); } + return parameterTypes; } /** * initializes return type */ - public synchronized void initReturnType() { + public Class<?> getReturnType() { if (returnType == null) { - returnType = VMReflection.getMethodReturnType(id); + returnType = VMReflection.getMethodReturnType(vm_member_id); + } + return returnType; + } + + /** + * initializes type parameters + */ + public synchronized void initTypeParameters() { + // So, here it can be only TypeVariable elements. + if (typeParameters == null) { + Object startPoint = Method.this; + if (methSignature == null) { + methSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(vm_member_id)); // getting this method signature + if (methSignature == null) { + typeParameters = new TypeVariable[0]; + return; + } + } + if (methGenDecl == null) { + methGenDecl = (InterimMethodGenericDecl) Parser.parseSignature(methSignature, SignatureKind.METHOD_SIGNATURE, (GenericDeclaration)startPoint); // GenericSignatureFormatError can be thrown here + } + InterimTypeParameter[] pTypeParameters = methGenDecl.typeParameters; + if (pTypeParameters == null) { + typeParameters = new TypeVariable[0]; + return; + } + int l = pTypeParameters.length; + typeParameters = new TypeVariable[l]; + for (int i = 0; i < l; i++) { + String tvName = pTypeParameters[i].typeParameterName; + TypeVariable variable = new TypeVariableImpl((GenericDeclaration)Method.this, tvName, methGenDecl.typeParameters[i]); + TypeVariableRepository.registerTypeVariable(variable, tvName, startPoint); + typeParameters[i] = variable; + } } } } + } diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/ReflectExporter.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/ReflectExporter.java index 3840f6a..debca8b 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/ReflectExporter.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/ReflectExporter.java @@ -27,8 +27,8 @@ import org.apache.harmony.lang.reflect.R */ class ReflectExporter implements ReflectAccessor { - public Constructor copyConstructor(Constructor c) { - return new Constructor(c); + public <T> Constructor<T> copyConstructor(Constructor<T> c) { + return new Constructor<T>(c); } public Field copyField(Field f) { @@ -38,6 +38,46 @@ class ReflectExporter implements Reflect public Method copyMethod(Method m) { return new Method(m); } + + public Method[] mergePublicMethods(Method[] declared, + Method[] superPublic, Method[][] intf, int estimate) { + Method[] store = new Method[estimate]; + int size = 0; + for (Method m : declared) { + if (Modifier.isPublic(m.getModifiers())) { + store[size++] = m; + } + } + if (superPublic != null) { + nextSuper: for (Method m : superPublic) { + for (int i = 0; i < size; i++) { + if (m.getName() == store[i].getName() + && m.getSignature() == store[i].getSignature()) { + continue nextSuper; + } + } + store[size++] = m; + } + } + if (intf != null) { + for (Method[] mi : intf) { + nextIntf: for (Method m : mi) { + for (int i = 0; i < size; i++) { + if (m.getName() == store[i].getName() + && m.getSignature() == store[i].getSignature()) { + continue nextIntf; + } + } + store[size++] = m; + } + } + } + Method[] real = new Method[size]; + System.arraycopy(store, 0, real, 0, size); + + return real; + } + public void checkMemberAccess(Class callerClass, Class declaringClass, Class runtimeClass, int memberModifiers) @@ -55,8 +95,8 @@ class ReflectExporter implements Reflect * NON EXPORTED */ - private boolean allowAccess(Class callerClass, Class declaringClass, - Class runtimeClass, int memberModifiers) { + private boolean allowAccess(Class<?> callerClass, Class<?> declaringClass, + Class<?> runtimeClass, int memberModifiers) { // it is allways safe to access members from the class declared in the // same top level class as the declaring class if (hasSameTopLevelClass(declaringClass, callerClass)) { @@ -92,7 +132,7 @@ class ReflectExporter implements Reflect // check access to protected members through hierarchy if (Modifier.isProtected(memberModifiers)) { - Class outerClass = callerClass; + Class<?> outerClass = callerClass; // scan from the caller to the top level class do { // find closest enclouser class which extends declaring class @@ -112,7 +152,7 @@ class ReflectExporter implements Reflect return false; } - private boolean allowClassAccess(Class callee, Class caller) { + private boolean allowClassAccess(Class<?> callee, Class<?> caller) { if (callee == null || callee == caller) { return true; } @@ -126,7 +166,7 @@ class ReflectExporter implements Reflect return false; } - private boolean hasSameTopLevelClass(Class class1, Class class2) { + private boolean hasSameTopLevelClass(Class<?> class1, Class<?> class2) { Class topClass; while ( (topClass = class1.getDeclaringClass()) != null) { class1 = topClass; @@ -137,7 +177,7 @@ class ReflectExporter implements Reflect return class1 == class2; } - private boolean hasSamePackage(Class class1, Class class2) { + private boolean hasSamePackage(Class<?> class1, Class<?> class2) { final String pkg1 = class1.getName(); final String pkg2 = class2.getName(); int i1 = pkg1.lastIndexOf('.'); diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMField.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMField.java new file mode 100644 index 0000000..2c88af7 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMField.java @@ -0,0 +1,90 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ +package java.lang.reflect; + +final class VMField { + + /** + * This class is not supposed to be instantiated. + */ + private VMField() { + } + + /** + * Obtaines a value of the field with specified identifier. If the + * <code>id</code> argument corresponds to a static field then the + * <code>object</code> argument must be null. The value of a static field + * will be returned in this case. If the <code>id</code> argument + * corresponds to non-static field then object's field value will be + * returned. + * <p> + * This method is used for the {@link Field#get(Object) Field.get(Object obj)} + * method implementation. + * <p> + * + * @param object the object to get a field value from. + * @param id an identifier of the caller class. + * @return a value of the object. The values of primitive type are wrapped + * by corresponding object from the <code>java.lang</code> package. + * @throws ExceptionInInitializerError if initialization fails. + * @api2vm + */ + static native Object getObject(Object object, long field_id); + + static native boolean getBoolean(Object object, long field_id); + static native char getChar(Object object, long field_id); + static native byte getByte(Object object, long field_id); + static native short getShort(Object object, long field_id); + static native int getInt(Object object, long field_id); + static native long getLong(Object object, long field_id); + static native float getFloat(Object object, long field_id); + static native double getDouble(Object object, long field_id); + + + /** + * Sets a value for the field with specified identifier. If the + * <code>id</code> argument corresponds to a static field then the + * <code>object</code> argument must be null. An attempt to set a new value + * to a static field will be made in this case. If the <code>id</code> + * argument corresponds to a non-static field then an attempt to assign new + * value to object's field will be made. + * <p> + * This method is used for the {@link Field#set(Object, Object) + * Field.set(Object obj, Object value)} method implementation. + * <p> + * + * @param object the object to set a field value in. + * @param id an identifier of the caller class. + * @param value a new field value. If the field has primitive type then the + * value argument should be unwrapped. + * @throws ExceptionInInitializerError if initialization fails. + * @api2vm + */ + static native void setObject(Object object, long field_id, Object value); + + static native void setBoolean(Object object, long field_id, boolean value); + static native void setChar(Object object, long field_id, char value); + static native void setByte(Object object, long field_id, byte value); + static native void setShort(Object object, long field_id, short value); + static native void setInt(Object object, long field_id, int value); + static native void setLong(Object object, long field_id, long value); + static native void setFloat(Object object, long field_id, float value); + static native void setDouble(Object object, long field_id, double value); +} diff --git vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMReflection.java vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMReflection.java index 71edf67..fce7ce1 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMReflection.java +++ vm/vmcore/src/kernel_classes/javasrc/java/lang/reflect/VMReflection.java @@ -48,23 +48,13 @@ final class VMReflection { /** * This method satisfies the requirements of the specification for the - * {@link Member#getDeclaringClass() Member.getDeclaringClass()} method. But - * it takes one additional id parameter. - * - * @param id an identifier of the caller class. - * @api2vm - */ - static native Class getDeclaringClass(Object id); - - /** - * This method satisfies the requirements of the specification for the * {@link Method#getExceptionTypes() Method.getExceptionTypes()} method. But * it takes one additional id parameter. * * @param id an identifier of the caller class. * @api2vm */ - static native Class[] getExceptionTypes(Object id); + static native Class<?>[] getExceptionTypes(long id); /** * This method satisfies the requirements of the specification for the @@ -74,29 +64,7 @@ final class VMReflection { * @param id an identifier of the caller class. * @api2vm */ - static native Class getFieldType(Object id); - - /** - * Obtaines a value of the field with specified identifier. If the - * <code>id</code> argument corresponds to a static field then the - * <code>object</code> argument must be null. The value of a static field - * will be returned in this case. If the <code>id</code> argument - * corresponds to non-static field then object's field value will be - * returned. - * <p> - * This method is used for the {@link Field#get(Object) Field.get(Object obj)} - * method implementation. - * <p> - * <b>Note:</b> Under design yet. Subjected to change. - * - * @param object the object to get a field value from. - * @param id an identifier of the caller class. - * @return a value of the object. The values of primitive type are wrapped - * by corresponding object from the <code>java.lang</code> package. - * @throws ExceptionInInitializerError if initialization fails. - * @api2vm - */ - static native Object getFieldValue(Object object, Object id); + static native Class<?> getFieldType(long id); /** * This method satisfies the requirements of the specification for the @@ -106,27 +74,7 @@ final class VMReflection { * @param id an identifier of the caller class. * @api2vm */ - static native Class getMethodReturnType(Object id); - - /** - * This method satisfies the requirements of the specification for the - * {@link Member#getModifiers() Member.getModifiers()} method. But it takes - * one additional id parameter. - * - * @param id an identifier of the caller class. - * @api2vm - */ - static native int getModifiers(Object id); - - /** - * This method satisfies the requirements of the specification for the - * {@link Member#getName() Member.getName()} method. But it takes one - * additional id parameter. - * - * @param id an identifier of the caller class. - * @api2vm - */ - static native String getName(Object id); + static native Class<?> getMethodReturnType(long id); /** * This method satisfies the requirements of the specification for the @@ -136,7 +84,7 @@ final class VMReflection { * @param id an identifier of the caller class. * @api2vm */ - static native Class[] getParameterTypes(Object id); + static native Class<?>[] getParameterTypes(long id); /** * This method satisfies the requirements of the specification for the @@ -164,7 +112,7 @@ final class VMReflection { * @param id the identifier of the method to be invoked. * @api2vm */ - static native Object invokeMethod(Object object, Object id, Object[] args) + static native Object invokeMethod(long id, Object object, Object... args) throws InvocationTargetException; /** @@ -181,7 +129,7 @@ final class VMReflection { * <b>Note:</b> Under design yet. Subjected to change. * @api2vm */ - static native Object newArrayInstance(Class type, int[] dimensions); + static native Object newArrayInstance(Class<?> type, int[] dimensions); /** * This method satisfies the requirements of the specification for the @@ -203,28 +151,7 @@ final class VMReflection { * @param id the identifier of the method to be invoked. * @api2vm */ - static native Object newClassInstance(Object id, Object[] args) + static native Object newClassInstance(long id, Object... args) throws InvocationTargetException; - /** - * Sets a value for the field with specified identifier. If the - * <code>id</code> argument corresponds to a static field then the - * <code>object</code> argument must be null. An attempt to set a new value - * to a static field will be made in this case. If the <code>id</code> - * argument corresponds to a non-static field then an attempt to assign new - * value to object's field will be made. - * <p> - * This method is used for the {@link Field#set(Object, Object) - * Field.set(Object obj, Object value)} method implementation. - * <p> - * <b>Note:</b> Under design yet. Subjected to change. - * - * @param object the object to set a field value in. - * @param id an identifier of the caller class. - * @param value a new field value. If the field has primitive type then the - * value argument should be unwrapped. - * @throws ExceptionInInitializerError if initialization fails. - * @api2vm - */ - static native void setFieldValue(Object object, Object id, Object value); } diff --git vm/vmcore/src/kernel_classes/javasrc/java/security/AccessControlContext.java vm/vmcore/src/kernel_classes/javasrc/java/security/AccessControlContext.java index c0ced35..dbb85c6 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/security/AccessControlContext.java +++ vm/vmcore/src/kernel_classes/javasrc/java/security/AccessControlContext.java @@ -64,7 +64,7 @@ public final class AccessControlContext } if (context.length != 0) { // remove dup entries - ArrayList a = new ArrayList(); + ArrayList<ProtectionDomain> a = new ArrayList<ProtectionDomain>(); for (int i = 0; i < context.length; i++) { if (context[i] != null && !a.contains(context[i])) { a.add(context[i]); diff --git vm/vmcore/src/kernel_classes/javasrc/java/security/AccessController.java vm/vmcore/src/kernel_classes/javasrc/java/security/AccessController.java index 7b42cea..36a7370 100644 --- vm/vmcore/src/kernel_classes/javasrc/java/security/AccessController.java +++ vm/vmcore/src/kernel_classes/javasrc/java/security/AccessController.java @@ -45,12 +45,13 @@ public final class AccessController { * stored. ((ArrayList)contexts.get(Thread.currentThread())).lastElement() - * is reference to the latest context passed to the doPrivileged() call. */ - private static final WeakHashMap contexts = new WeakHashMap(); + private static final WeakHashMap<Thread, ArrayList<AccessControlContext>> + contexts = new WeakHashMap<Thread, ArrayList<AccessControlContext>>(); /** * @com.intel.drl.spec_ref */ - public static Object doPrivileged(PrivilegedAction action) { + public static <T> T doPrivileged(PrivilegedAction<T> action) { if (action == null) { throw new NullPointerException("action can not be null"); } @@ -60,7 +61,7 @@ public final class AccessController { /** * @com.intel.drl.spec_ref */ - public static Object doPrivileged(PrivilegedAction action, + public static <T> T doPrivileged(PrivilegedAction<T> action, AccessControlContext context) { if (action == null) { throw new NullPointerException("action can not be null"); @@ -71,7 +72,7 @@ public final class AccessController { /** * @com.intel.drl.spec_ref */ - public static Object doPrivileged(PrivilegedExceptionAction action) + public static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws PrivilegedActionException { if (action == null) { throw new NullPointerException("action can not be null"); @@ -82,7 +83,7 @@ public final class AccessController { /** * @com.intel.drl.spec_ref */ - public static Object doPrivileged(PrivilegedExceptionAction action, + public static <T> T doPrivileged(PrivilegedExceptionAction<T> action, AccessControlContext context) throws PrivilegedActionException { if (action == null) { throw new NullPointerException("action can not be null"); @@ -97,19 +98,19 @@ public final class AccessController { * The pushed context is then investigated in the {@link getContext()} * which is called in the {@link checkPermission}. */ - private static Object doPrivilegedImpl(PrivilegedExceptionAction action, + private static <T> T doPrivilegedImpl(PrivilegedExceptionAction<T> action, AccessControlContext context) throws PrivilegedActionException { Thread currThread = Thread.currentThread(); - ArrayList a = null; + ArrayList<AccessControlContext> a = null; try { // currThread==null means that VM warm up is in progress if (currThread != null && contexts != null) { synchronized (contexts) { - a = (ArrayList) contexts.get(currThread); + a = contexts.get(currThread); if (a == null) { - a = new ArrayList(); + a = new ArrayList<AccessControlContext>(); contexts.put(currThread, a); } } @@ -148,7 +149,7 @@ public final class AccessController { * The pushed context is then investigated in the {@link getContext()} * which is called in the {@link checkPermission}. */ - private static Object doPrivilegedImpl(PrivilegedAction action, + private static <T> T doPrivilegedImpl(PrivilegedAction<T> action, AccessControlContext context) { Thread currThread = Thread.currentThread(); @@ -163,12 +164,12 @@ public final class AccessController { return action.run(); } - ArrayList a = null; + ArrayList<AccessControlContext> a = null; try { synchronized (contexts) { - a = (ArrayList) contexts.get(currThread); + a = contexts.get(currThread); if (a == null) { - a = new ArrayList(); + a = new ArrayList<AccessControlContext>(); contexts.put(currThread, a); } } @@ -227,7 +228,7 @@ public final class AccessController { */ private static AccessControlContext buildContext(Class[] trace) { - ArrayList a = new ArrayList(); + ArrayList<ProtectionDomain> a = new ArrayList<ProtectionDomain>(); for (int i = 0; i < trace.length; i++) { ProtectionDomain pd = DoSecure.doSecure_getProtectionDomain(trace[i]); @@ -239,18 +240,18 @@ public final class AccessController { ProtectionDomain[] stack = new ProtectionDomain[a.size()]; a.toArray(stack); - AccessControlContext that; - Thread currThread = Thread.currentThread(); if (currThread == null || contexts == null) { // Big boo time. No need to check anything ? return new AccessControlContext(stack); } - ArrayList threadContexts; + ArrayList<AccessControlContext> threadContexts; synchronized (contexts) { - threadContexts = (ArrayList) contexts.get(currThread); + threadContexts = contexts.get(currThread); } + + AccessControlContext that; if ((threadContexts == null) || (threadContexts.size() == 0)) { // We were not in doPrivileged method, so // have inherited context here @@ -258,8 +259,7 @@ public final class AccessController { } else { // We were in doPrivileged method, so // Use context passed to the doPrivileged() - that = (AccessControlContext) threadContexts - .get(threadContexts.size() - 1); + that = threadContexts.get(threadContexts.size() - 1); } if (that != null && that.combiner != null) { @@ -297,7 +297,7 @@ public final class AccessController { * @param klass * @return klass.getProtectionDomain() */ - private static ProtectionDomain doSecure_getProtectionDomain(Class klass) { + private static ProtectionDomain doSecure_getProtectionDomain(Class<?> klass) { return klass.getProtectionDomain(); } } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/fortress/security/SecurityUtils.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/fortress/security/SecurityUtils.java index 2d76ef8..62ee768 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/fortress/security/SecurityUtils.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/fortress/security/SecurityUtils.java @@ -41,7 +41,8 @@ public final class SecurityUtils { // A map used to store inherited contexts.<br> // A thread is used as a key for the map and AccessControlContext // passed to the putContext is used as a value. - private static WeakHashMap map = new WeakHashMap(); + private static WeakHashMap<Thread, AccessControlContext> map = + new WeakHashMap<Thread, AccessControlContext>(); /** * This method to be invoked in the Thread's constructor. The first argument @@ -104,8 +105,7 @@ public final class SecurityUtils { */ synchronized (map) { - AccessControlContext ctx = (AccessControlContext) map.get(thread); - return ctx; + return map.get(thread); } } } \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java index d267cd0..d998642 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/kernel/vm/VM.java @@ -76,7 +76,7 @@ public final class VM { /* PACKAGE PRIVATE */ - static final ClassLoader getStackClassLoader(int depth) { + public static final ClassLoader getStackClassLoader(int depth) { Class clazz = VMStack.getCallerClass(depth); return clazz != null ? getClassLoader(clazz) : null; } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/ClassLoaderInfo.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/ClassLoaderInfo.java index e0ee32b..970a3ba 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/ClassLoaderInfo.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/ClassLoaderInfo.java @@ -31,7 +31,7 @@ public class ClassLoaderInfo { if (parentClassLoader == null) { systemLoaders = new ClassLoader[] { systemClassLoader }; } else { - ArrayList loaders = new ArrayList(); + ArrayList<ClassLoader> loaders = new ArrayList<ClassLoader>(); loaders.add(systemClassLoader); do { loaders.add(parentClassLoader); @@ -72,7 +72,7 @@ public class ClassLoaderInfo { * loader or on of its ancestors, false otherwise. This method * returns true if defining class loader is null. */ - public static boolean hasSystemClassLoader(Class clazz) { + public static boolean hasSystemClassLoader(Class<?> clazz) { for (int i = 0; i < systemLoaders.length; i++) { ClassLoader loader = clazz.getClassLoader(); if (loader == null || loader == systemLoaders[i]) { diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationFactory.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationFactory.java new file mode 100644 index 0000000..7903aa6 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationFactory.java @@ -0,0 +1,322 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.annotation; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.annotation.IncompleteAnnotationException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import static org.apache.harmony.lang.annotation.AnnotationMember.ARRAY; +import static org.apache.harmony.lang.annotation.AnnotationMember.ERROR; + +/** + * The annotation implementation based on dynamically generated proxy instances. + * It conforms to all requirements stated in public APIs, see in particular + * {@link java.lang.reflect.AnnotatedElement java.lang.reflect.AnnotatedElement} + * and {@link java.lang.annotation.Annotation java.lang.annotation.Annotation}. + * Namely, annotation instances are immutable and serializable; they provide + * conforming access to annotation member values and required implementations of + * methods declared in Annotation interface. + * + * @see org.apache.harmony.lang.annotation.AnnotationMember + * @see java.lang.annotation.Annotation + * + * @author Alexey V. Varlamov, Serguei S. Zapreyev + * @version $Revision$ + */ +@SuppressWarnings({"serial"}) +public final class AnnotationFactory implements InvocationHandler, Serializable { + + private static final transient + Map<Class<? extends Annotation>, AnnotationMember[]> + cache = new WeakHashMap<Class<? extends Annotation>, AnnotationMember[]>(); + + /** + * Reflects specified annotation type and returns an array + * of member element definitions with default values. + */ + public static AnnotationMember[] getElementsDescription(Class<? extends Annotation> annotationType ) { + AnnotationMember[] desc = cache.get(annotationType); + if (desc == null) { + if (!annotationType.isAnnotation()) { + throw new IllegalArgumentException("Type is not annotation: " + + annotationType.getName()); + } + Method[] m = annotationType.getDeclaredMethods(); + desc = new AnnotationMember[m.length]; + int idx = 0; + for(Method element : m) { + String name = element.getName(); + Class<?> type = element.getReturnType(); + try { + desc[idx] = new AnnotationMember(name, + element.getDefaultValue(), type, element); + } catch (Throwable t) { + desc[idx] = new AnnotationMember(name, t, type, element); + } + idx++; + } + cache.put(annotationType, desc); + } + return desc; + } + + /** + * Provides a new annotation instance. + * @param annotationType the annotation type definition + * @param elements name-value pairs representing elements of the annotation + * @return a new annotation instance + */ + public static Annotation createAnnotation( + Class<? extends Annotation> annotationType, + AnnotationMember[] elements) + { + AnnotationFactory antn = new AnnotationFactory(annotationType, elements); + return (Annotation)Proxy.newProxyInstance( annotationType.getClassLoader(), + new Class[]{annotationType}, antn); + } + + private final Class<? extends Annotation> klazz; + private AnnotationMember[] elements; + + /** + * New instances should not be created directly, use factory method + * {@link #createAnnotation(Class, AnnotationMember[]) createAnnotation()} + * instead. + * + * @param klzz class defining the annotation type + * @param values actual element values + */ + private AnnotationFactory(Class<? extends Annotation> klzz, AnnotationMember[] values) { + klazz = klzz; + AnnotationMember[] defs = getElementsDescription(klazz); + if (values == null) { + elements = defs; + } else { + //merge default and actual values + elements = new AnnotationMember[defs.length]; + next: for (int i = elements.length - 1; i >= 0; i-- ){ + for (AnnotationMember val : values){ + if (val.name.equals(defs[i].name)) { + elements[i] = val.setDefinition(defs[i]); + continue next; + } + } + elements[i] = defs[i]; + } + } + } + + /** + * Reads the object, obtains actual member definitions for the annotation type, + * and merges deserialized values with the new definitions. + */ + private void readObject(ObjectInputStream os) throws IOException, + ClassNotFoundException { + os.defaultReadObject(); + // Annotation type members can be changed arbitrarily + // So there may be zombi elements from the previous life; + // they hardly fit into this new annotation's incarnation, + // as we have no defining methods for them. + // Reasonably just drop such elements, + // but seems better to keep them for compatibility + AnnotationMember[] defs = getElementsDescription(klazz); + AnnotationMember[] old = elements; + List<AnnotationMember> merged = new ArrayList<AnnotationMember>( + defs.length + old.length); + nextOld: for (AnnotationMember el1 : old) { + for (AnnotationMember el2 : defs) { + if (el2.name.equals(el1.name)) { + continue nextOld; + } + } + merged.add(el1); //phantom element + } + nextNew: for (AnnotationMember def : defs){ + for (AnnotationMember val : old){ + if (val.name.equals(def.name)) { + // nothing to do about cached errors (if any) + // anyway they remain relevant to values + merged.add(val.setDefinition(def)); + continue nextNew; + } + } + merged.add(def); // brand new element + } + elements = merged.toArray(new AnnotationMember[merged.size()]); + } + + /** + * Returns true if the specified object represents the same annotation instance. + * That is, if it implements the same annotation type and + * returns the same element values. + * <br>Note, actual underlying implementation mechanism does not matter - it may + * differ completely from this class. + * @return true if the passed object is equivalent annotation instance, + * false otherwise. + * @see org.apache.harmony.lang.annotation.AnnotationMember#equals(Object) + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!klazz.isInstance(obj)) { + return false; + } + Object handler = null; + if (Proxy.isProxyClass(obj.getClass()) + && (handler = Proxy.getInvocationHandler(obj)) instanceof AnnotationFactory ) { + AnnotationFactory other = (AnnotationFactory) handler; + if (elements.length != other.elements.length) { + return false; + } + next: for (AnnotationMember el1 : elements){ + for (AnnotationMember el2 : other.elements) { + if (el1.equals(el2)) { + continue next; + } + } + return false; + } + return true; + } else { + // encountered foreign annotation implementaton + // so have to obtain element values via invocation + // of corresponding methods + for (final AnnotationMember el : elements) { + if (el.tag == ERROR) { + // undefined value is incomparable (transcendent) + return false; + } + try { + if (!el.definingMethod.isAccessible()) { + AccessController.doPrivileged(new PrivilegedAction<Object>(){ + public Object run() { + try { + el.definingMethod.setAccessible(true); + } catch (Exception ignore) {} + return null; + } + }); + } + Object otherValue = el.definingMethod.invoke(obj); + if (otherValue != null ) { + if (el.tag == ARRAY) { + if (!el.equalArrayValue(otherValue)) { + return false; + } + } else { + if (!el.value.equals(otherValue)) { + return false; + } + } + } else if (el.value != AnnotationMember.NO_VALUE) { + return false; + } + } catch (Throwable e) { + return false; + } + } + return true; + } + } + + /** + * Returns a hash code composed as a sum of hash codes of member elements, + * including elements with default values. + * @see org.apache.harmony.lang.annotation.AnnotationMember#hashCode() + */ + public int hashCode() { + int hash = 0; + for (AnnotationMember element : elements) { + hash += element.hashCode(); + } + return hash; + } + + /** + * Provides detailed description of this annotation instance, + * including all member name-values pairs. + * @return string representation of this annotation + */ + public String toString() { + String res = "@" + klazz.getName() + "("; + for(int i = 0; i < elements.length; i++) { + if ( i != 0 ) { + res += ", "; + } + res += elements[i].toString();; + } + return res + ")"; + } + + /** + * Processes a method invocation request to this annotation instance. + * Recognizes the methods declared in the + * {@link java.lang.annotation.Annotation java.lang.annotation.Annotation} + * interface, and member-defining methods of the implemented annotation type. + * @throws IllegalArgumentException If the specified method is none of the above + * @return the invocation result + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + String name = method.getName(); + Class[] params = method.getParameterTypes(); + if (params.length == 0) { + if ("annotationType".equals(name)) { + return klazz; + } else if ("toString".equals(name)) { + return toString(); + } else if ("hashCode".equals(name)) { + return hashCode(); + } + + // this must be element value request + AnnotationMember element = null; + for (AnnotationMember el : elements) { + if (name.equals(el.name)) { + element = el; + break; + } + } + if (element == null || !method.equals(element.definingMethod)) { + throw new IllegalArgumentException(method.toString()); + } else { + Object value = element.validateValue(); + if (value == null) { + throw new IncompleteAnnotationException(klazz, name); + } + return value; + } + } else if (params.length == 1 && params[0] == Object.class && "equals".equals(name)){ + return Boolean.valueOf(equals(args[0])); + } + throw new IllegalArgumentException( + "Invalid method for annotation type: " + method); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationMember.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationMember.java new file mode 100644 index 0000000..3387967 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/annotation/AnnotationMember.java @@ -0,0 +1,386 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.annotation; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.annotation.AnnotationTypeMismatchException; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * This class represents member element of an annotation. + * It consists of name and value, supplemented with element + * definition information (such as declared type of element). + * <br>The value may be one of the following types: + * <ul> + * <li> boxed primitive + * <li> Class + * <li> enum constant + * <li> annotation (nested) + * <li> one-dimensional array of the above + * <li> Throwable + * </ul> + * The last type is specific for this implementation; a Throwable value + * means that the error occured during parsing or resolution of corresponding + * class-data structures and throwing is delayed until the element + * is requested for value. + * + * @see org.apache.harmony.lang.annotation.AnnotationFactory + * + * @author Alexey V. Varlamov, Serguei S. Zapreyev + * @version $Revision$ + */ +@SuppressWarnings({"serial"}) +public class AnnotationMember implements Serializable { + + /** + * Tag description of a Throwable value type. + */ + protected static final char ERROR = '!'; + + /** + * Tag description of an array value type. + */ + protected static final char ARRAY = '['; + + /** + * Tag description of all value types except arrays and Throwables. + */ + protected static final char OTHER = '*'; + +// public static final char INT = 'I'; +// public static final char CHAR = 'C'; +// public static final char DOUBLE = 'D'; +// public static final char FLOAT = 'F'; +// public static final char BYTE = 'B'; +// public static final char LONG = 'J'; +// public static final char SHORT = 'S'; +// public static final char BOOL = 'Z'; +// public static final char CLASS = 'c'; +// public static final char ENUM = 'e'; +// public static final char ANTN = '@'; + + private enum DefaultValues {NO_VALUE} + + /** + * Singleton representing missing element value. + */ + protected static final Object NO_VALUE = DefaultValues.NO_VALUE; + + protected final String name; + protected final Object value; // a primitive value is wrapped to the corresponding wrapper class + protected final char tag; + // no sense to serialize definition info as it can be changed arbitrarily + protected transient Class<?> elementType; + protected transient Method definingMethod; + + + /** + * Creates a new element with specified name and value. + * Definition info will be provided later when this + * element becomes actual annotation member. + * @param name element name, must not be null + * @param val element value, should be of addmissible type, + * as specified in the description of this class + * + * @see #setDefinition(AnnotationMember) + */ + public AnnotationMember(String name, Object val) { + this.name = name; + value = val == null ? NO_VALUE : val; + if (value instanceof Throwable) { + tag = ERROR; + } else if (value.getClass().isArray()) { + tag = ARRAY; + } else { + tag = OTHER; + } + } + + /** + * Creates the completely defined element. + * @param name element name, must not be null + * @param value element value, should be of addmissible type, + * as specified in the description of this class + * @param m element-defining method, reflected on the annotation type + * @param type declared type of this element + * (return type of the defining method) + */ + public AnnotationMember(String name, Object val, Class type, Method m) { + this(name, val); + + definingMethod = m; + + if (type == int.class) { + elementType = Integer.class; + } else if (type == boolean.class) { + elementType = Boolean.class; + } else if (type == char.class) { + elementType = Character.class; + } else if (type == float.class) { + elementType = Float.class; + } else if (type == double.class) { + elementType = Double.class; + } else if (type == long.class) { + elementType = Long.class; + } else if (type == short.class) { + elementType = Short.class; + } else if (type == byte.class) { + elementType = Byte.class; + } else { + elementType = type; + } + } + + /** + * Fills in element's definition info and returns this. + */ + protected AnnotationMember setDefinition(AnnotationMember copy) { + definingMethod = copy.definingMethod; + elementType = copy.elementType; + return this; + } + + /** + * Returns readable description of this annotation value. + */ + public String toString() { + if (tag == ARRAY) { + StringBuilder sb = new StringBuilder(80); + sb.append(name).append("=["); + int len = Array.getLength(value); + for (int i = 0; i < len; i++) { + if (i != 0) sb.append(", "); + sb.append(Array.get(value, i)); + } + return sb.append("]").toString(); + } else { + return name+ "=" +value; + } + } + + /** + * Returns true if the specified object represents equal element + * (equivalent name-value pair). + * <br> A special case is the contained Throwable value; it is considered + * transcendent so no other element would be equal. + * @return true if passed object is equivalent element representation, + * false otherwise + * @see #equalArrayValue(Object) + * @see java.lang.annotation.Annotation#equals(Object) + */ + public boolean equals(Object obj) { + if (obj == this) { + // not a mere optimization, + // this is needed for consistency with hashCode() + return true; + } + if (obj instanceof AnnotationMember) { + AnnotationMember that = (AnnotationMember)obj; + if (name.equals(that.name) && tag == that.tag) { + if (tag == ARRAY) { + return equalArrayValue(that.value); + } else if (tag == ERROR) { + // undefined value is incomparable (transcendent) + return false; + } else { + return value.equals(that.value); + } + } + } + return false; + } + + /** + * Returns true if the contained value and a passed object are equal arrays, + * false otherwise. Appropriate overloaded method of Arrays.equals() + * is used for equality testing. + * @see java.util.Arrays#equals(java.lang.Object[], java.lang.Object[]) + * @return true if the value is array and is equal to specified object, + * false otherwise + */ + public boolean equalArrayValue(Object otherValue) { + if (value instanceof Object[] && otherValue instanceof Object[]) { + return Arrays.equals((Object[])value, (Object[])otherValue); + } + Class type = value.getClass(); + if (type != otherValue.getClass()) { + return false; + } + if (type == int[].class) { + return Arrays.equals((int[])value, (int[])otherValue); + } else if (type == byte[].class) { + return Arrays.equals((byte[])value, (byte[])otherValue); + } else if (type == short[].class) { + return Arrays.equals((short[])value, (short[])otherValue); + } else if (type == long[].class) { + return Arrays.equals((long[])value, (long[])otherValue); + } else if (type == char[].class) { + return Arrays.equals((char[])value, (char[])otherValue); + } else if (type == boolean[].class) { + return Arrays.equals((boolean[])value, (boolean[])otherValue); + } else if (type == float[].class) { + return Arrays.equals((float[])value, (float[])otherValue); + } else if (type == double[].class) { + return Arrays.equals((double[])value, (double[])otherValue); + } + return false; + } + + /** + * Computes hash code of this element. The formula is as follows: + * <code> (name.hashCode() * 127) ^ value.hashCode() </code> + * <br>If value is an array, one of overloaded Arrays.hashCode() + * methods is used. + * @return the hash code + * @see java.util.Arrays#hashCode(java.lang.Object[]) + * @see java.lang.annotation.Annotation#hashCode() + */ + public int hashCode() { + int hash = name.hashCode() * 127; + if (tag == ARRAY) { + Class type = value.getClass(); + if (type == int[].class) { + return hash ^ Arrays.hashCode((int[])value); + } else if (type == byte[].class) { + return hash ^ Arrays.hashCode((byte[])value); + } else if (type == short[].class) { + return hash ^ Arrays.hashCode((short[])value); + } else if (type == long[].class) { + return hash ^ Arrays.hashCode((long[])value); + } else if (type == char[].class) { + return hash ^ Arrays.hashCode((char[])value); + } else if (type == boolean[].class) { + return hash ^ Arrays.hashCode((boolean[])value); + } else if (type == float[].class) { + return hash ^ Arrays.hashCode((float[])value); + } else if (type == double[].class) { + return hash ^ Arrays.hashCode((double[])value); + } + return hash ^ Arrays.hashCode((Object[])value); + } else { + return hash ^ value.hashCode(); + } + } + + /** + * Throws contained error (if any) with a renewed stack trace. + */ + public void rethrowError() throws Throwable { + if (tag == ERROR) { + // need to throw cloned exception for thread safety + // besides it is better to provide actual stack trace + // rather than recorded during parsing + + // first check for expected types + if (value instanceof TypeNotPresentException) { + TypeNotPresentException tnpe = (TypeNotPresentException)value; + throw new TypeNotPresentException(tnpe.typeName(), tnpe.getCause()); + } else if (value instanceof EnumConstantNotPresentException) { + EnumConstantNotPresentException ecnpe = (EnumConstantNotPresentException)value; + throw new EnumConstantNotPresentException(ecnpe.enumType(), ecnpe.constantName()); + } else if (value instanceof ArrayStoreException) { + ArrayStoreException ase = (ArrayStoreException)value; + throw new ArrayStoreException(ase.getMessage()); + } + // got some other error, have to go with deep cloning + // via serialization mechanism + Throwable error = (Throwable)value; + StackTraceElement[] ste = error.getStackTrace(); + ByteArrayOutputStream bos = new ByteArrayOutputStream( + ste == null ? 512 : (ste.length + 1) * 80); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(error); + oos.flush(); + oos.close(); + ByteArrayInputStream bis = new ByteArrayInputStream(bos + .toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bis); + error = (Throwable)ois.readObject(); + ois.close(); + + throw error; + } + } + + /** + * Validates contained value against its member definition + * and if ok returns the value. + * Otherwise, if the value type mismatches definition + * or the value itself describes an error, + * throws appropriate exception. + * <br> Note, this method may return null if this element was constructed + * with such value. + * + * @see #rethrowError() + * @see #copyValue() + * @return actual valid value or null if no value + */ + public Object validateValue() throws Throwable { + if (tag == ERROR) { + rethrowError(); + } + if (value == NO_VALUE) { + return null; + } + if (elementType == value.getClass() + || elementType.isInstance(value)) { // nested annotation value + return copyValue(); + } else { + throw new AnnotationTypeMismatchException(definingMethod, + value.getClass().getName()); + } + + } + + + /** + * Provides mutation-safe access to contained value. That is, caller is free + * to modify the returned value, it will not affect the contained data value. + * @return cloned value if it is mutable or the original immutable value + */ + public Object copyValue() throws Throwable + { + if (tag != ARRAY || Array.getLength(value) == 0) { + return value; + } + Class type = value.getClass(); + if (type == int[].class) { + return ((int[])value).clone(); + } else if (type == byte[].class) { + return ((byte[])value).clone(); + } else if (type == short[].class) { + return ((short[])value).clone(); + } else if (type == long[].class) { + return ((long[])value).clone(); + } else if (type == char[].class) { + return ((char[])value).clone(); + } else if (type == boolean[].class) { + return ((boolean[])value).clone(); + } else if (type == float[].class) { + return ((float[])value).clone(); + } else if (type == double[].class) { + return ((double[])value).clone(); + } + return ((Object[])value).clone(); + } +} diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/ReflectAccessor.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/ReflectAccessor.java index 272ec49..b4ac5bf 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/ReflectAccessor.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/ReflectAccessor.java @@ -25,13 +25,16 @@ import java.lang.reflect.Method; */ public interface ReflectAccessor { - public Constructor copyConstructor(Constructor c); + public <T> Constructor<T> copyConstructor(Constructor<T> c); public Field copyField(Field f); public Method copyMethod(Method m); - public void checkMemberAccess(Class callerClass, Class declaringClass, - Class runtimeClass, int memberModifiers) + public void checkMemberAccess(Class<?> callerClass, Class<?> declaringClass, + Class<?> runtimeClass, int memberModifiers) throws IllegalAccessException; + + public Method[] mergePublicMethods(Method[] declared, + Method[] superPublic, Method[][] intf, int estimate); } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/Reflection.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/Reflection.java index be01fc7..fa223fb 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/Reflection.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/Reflection.java @@ -31,12 +31,12 @@ public class Reflection { reflectAccessor = accessor; } - public static Constructor copyConstructor(Constructor c) { + public static <T> Constructor<T> copyConstructor(Constructor<T> c) { return reflectAccessor.copyConstructor(c); } - public static Constructor[] copyConstructors(Constructor[] cs) { - Constructor[] ret = new Constructor[cs.length]; + public static <T> Constructor<T>[] copyConstructors(Constructor<T>[] cs) { + Constructor<T>[] ret = new Constructor[cs.length]; for (int i = 0; i < cs.length; i++) { ret[i] = reflectAccessor.copyConstructor(cs[i]); } @@ -75,4 +75,10 @@ public class Reflection { reflectAccessor.checkMemberAccess(callerClass, declarinClass, runtimeClass, memberModifiers); } + + public static Method[] mergePublicMethods(Method[] declared, + Method[] superPublic, Method[][] intf, int estimate) { + return reflectAccessor.mergePublicMethods(declared, superPublic, intf, estimate); + } + } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/GenericArrayTypeImpl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/GenericArrayTypeImpl.java new file mode 100644 index 0000000..36a7afb --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/GenericArrayTypeImpl.java @@ -0,0 +1,83 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.implementation; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.2 $ + */ +public final class GenericArrayTypeImpl implements GenericArrayType { + private final Type nextLayer; + + public GenericArrayTypeImpl(Type nextLayer) { + this.nextLayer = nextLayer; + } + + public boolean equals(Object other) { + //return super.equals(other); + if (!(other instanceof GenericArrayTypeImpl)) { + return false; + } + Type next = nextLayer; + Type next2 = ((GenericArrayTypeImpl)other).nextLayer; + while (next instanceof GenericArrayTypeImpl && next2 instanceof GenericArrayTypeImpl) { + if (!next.equals(next2)) { + return false; + } + next = ((GenericArrayTypeImpl)next).nextLayer; + next2 = ((GenericArrayTypeImpl)next2).nextLayer; + } + if (next.getClass().isInstance(next2)) { + return next.equals(next2); + } + return false; + } + + public Type getGenericComponentType() { + return nextLayer; + } + + public int hashCode() { + //return super.hashCode(); + int res = 0; + Type next = nextLayer; + while (next instanceof GenericArrayType) { + res += 1; + next = ((GenericArrayTypeImpl)next).nextLayer; + } + return res ^ next.hashCode(); + } + + public String toString() { + // TODO: this body should be reimplemented effectively. + StringBuffer sb = new StringBuffer(); + if(nextLayer instanceof GenericArrayType){ + sb.append(getGenericComponentType().toString()); + } else { + if(nextLayer instanceof Class){ + sb.append(((Class)nextLayer).getName()); + } else { + sb.append(nextLayer.toString()); + } + } + sb.append("[]"); + return sb.toString(); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/ParameterizedTypeImpl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/ParameterizedTypeImpl.java new file mode 100644 index 0000000..6bbc927 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/ParameterizedTypeImpl.java @@ -0,0 +1,104 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.implementation; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.lang.reflect.Type; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.2 $ + */ +public final class ParameterizedTypeImpl implements ParameterizedType { + private final Type[] args; + private final Type rawType; + private final Type typeOwner; + + public ParameterizedTypeImpl(Type[] args, Type rawType, Type typeOwner) { + this.args = args; + this.rawType = rawType; + this.typeOwner = typeOwner; + } + + public boolean equals(Object other) { + Type[] arr; + if (other == null || !(other instanceof ParameterizedType) || args.length != (arr = ((ParameterizedType)other).getActualTypeArguments()).length) { + return false; + } + for (int i = 0; i < args.length; i++) { + if (!args[i].equals(arr[i])) { + return false; + } + } + return rawType.equals(((ParameterizedType)other).getRawType()) && typeOwner.equals(((ParameterizedType)other).getOwnerType()); + } + + public Type[] getActualTypeArguments() { + return (Type[])args.clone(); + } + + public Type getOwnerType() { + return typeOwner; + } + + public Type getRawType() { + return rawType; + } + + public int hashCode() { + //return super.hashCode(); + int ah = 0; + for(int i = 0; i < args.length; i++) { + ah += args[i].hashCode(); + } + return ah ^ rawType.hashCode() ^ typeOwner.hashCode(); + } + + public String toString() { + // TODO: this body should be reimplemented effectively. + StringBuffer sb = new StringBuffer(); + if (typeOwner!=null) { + sb.append((typeOwner instanceof Class ? ((Class)typeOwner).getName() : typeOwner.toString())+"."+((Class)getRawType()).getSimpleName()); + } else { + sb.append(((Class)getRawType()).getName()); + } + if (args.length > 0) { + sb.append("<"); + for (int i = 0; i < args.length; i++) { + if (i != 0) { + sb.append(", "); + } + if (args[i] instanceof Class) { + sb.append(((Class)args[i]).getName()); + } else if (args[i] instanceof ParameterizedType) { + sb.append(args[i].toString()); + } else if (args[i] instanceof TypeVariable) { + sb.append(args[i].toString()); + } else if (args[i] instanceof WildcardType) { + sb.append(args[i].toString()); + } else if (args[i] instanceof GenericArrayType) { + sb.append(args[i].toString()); + } + } + sb.append(">"); + } + return sb.toString(); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/TypeVariableImpl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/TypeVariableImpl.java new file mode 100644 index 0000000..2c3ac48 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/TypeVariableImpl.java @@ -0,0 +1,180 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.implementation; + +import java.lang.reflect.TypeVariable; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Type; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; + +import org.apache.harmony.lang.reflect.support.*; +import org.apache.harmony.lang.reflect.parser.*; +import org.apache.harmony.lang.reflect.repository.*; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.2 $ + */ +public final class TypeVariableImpl<D extends GenericDeclaration> implements TypeVariable<D> { + private Type[] bounds; + private final D genericDeclaration; + private final String name; + private final InterimTypeParameter pTypeParameter; + + /** + * @param genericDeclaration declaration where a type variable is declared + * @param name type variable name + * @param pTypeParameter type variable intermediate representation + * @api2vm + */ + public TypeVariableImpl(D genericDeclaration, String name, InterimTypeParameter pTypeParameter) { + Class klass = null; + if (genericDeclaration instanceof Class) { + klass = (Class)genericDeclaration; + } else { + klass = (genericDeclaration instanceof Method ? ((Method)genericDeclaration).getDeclaringClass() : ((Constructor)genericDeclaration).getDeclaringClass()); + } + + while (klass != null) { + // TODO: it should be revised to provide the correct classloader for resolving. + AuxiliaryLoader.ersatzLoader.resolve(klass); + klass = klass.getDeclaringClass(); + } + + this.genericDeclaration = genericDeclaration; + this.name = AuxiliaryFinder.transform(name); + this.bounds = null; // Creating a type variable must not cause the creation of corresponding bounds. So, the creation should be initiated at a moment of first getBounds invocation. + this.pTypeParameter = pTypeParameter; + } + + public boolean equals(Object other) { + // XXX: The bounds comparing seems to be not actual here because + // 1. equality of variables is defined by belonging to the same declaration and a parameter's names coincedence + // 2. creating a type variable must not cause the creation of corresponding bounds + // Therefore we seem not to have to initiate bounds creation here. + // Nevertheless, we can just compare bound reflections within contents of both pTypeParameter fields (type variable intermediate representations) + + //return other != null && other instanceof TypeVariable && ((TypeVariable)other).name.equals(name) && ((TypeVariable)other).genericDeclaration.equals(genericDeclaration) ? true : false; + return other != null && other instanceof TypeVariable && ((TypeVariable)other).getName().equals(name) && + ( genericDeclaration instanceof Class ? + ((Class)genericDeclaration).equals((Class)((TypeVariable)other).getGenericDeclaration()) : + ( genericDeclaration instanceof Method ? + ((Method)genericDeclaration).equals((Method)((TypeVariable)other).getGenericDeclaration()) : + ((Constructor)genericDeclaration).equals((Constructor)((TypeVariable)other).getGenericDeclaration()) ) ); + } + + public Type[] getBounds() { + // It's time for real bounds creation. + if (bounds == null) { + Object startPoint = null; + if (this.genericDeclaration instanceof Class) { + startPoint = (Object) this.genericDeclaration; + } else if (this.genericDeclaration instanceof Method) { + startPoint = (Object) ((Method)this.genericDeclaration).getDeclaringClass(); + } else if (this.genericDeclaration instanceof Constructor) { + startPoint = (Object) ((Constructor)this.genericDeclaration).getDeclaringClass(); + } + + int l = pTypeParameter.interfaceBounds.length + 1; + bounds = new Type[l]; + if (pTypeParameter.classBound == null) { + bounds[0] = (Type) Object.class; + } else { + if (pTypeParameter.classBound instanceof InterimParameterizedType) { + java.lang.reflect.ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) pTypeParameter.classBound, ((InterimParameterizedType) pTypeParameter.classBound).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) pTypeParameter.classBound, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) pTypeParameter.classBound).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) pTypeParameter.classBound, startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) pTypeParameter.classBound, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) pTypeParameter.classBound, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) pTypeParameter.classBound, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) pTypeParameter.classBound, ((InterimParameterizedType) pTypeParameter.classBound).signature, startPoint); + } + bounds[0] = (Type) pType; + } else if (pTypeParameter.classBound instanceof InterimClassType) { + try { + bounds[0] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)pTypeParameter.classBound).classTypeName.substring(1).replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)pTypeParameter.classBound).classTypeName.substring(1).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } + } + for (int i = 1; i < l; i++) { + if (pTypeParameter.interfaceBounds[i - 1] instanceof InterimParameterizedType) { + java.lang.reflect.ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], ((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1]).signature, startPoint); + if (pType == null) { + try { + AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1]).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1], ((InterimParameterizedType) pTypeParameter.interfaceBounds[i - 1]).signature, startPoint); + } + bounds[i] = (Type) pType; + } else if (pTypeParameter.interfaceBounds[i - 1] instanceof InterimClassType) { + try { + bounds[i] = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)pTypeParameter.interfaceBounds[i - 1]).classTypeName.substring(1).replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)pTypeParameter.interfaceBounds[i - 1]).classTypeName.substring(1).replace('/', '.'), e); + } catch (ExceptionInInitializerError e) { + } catch (LinkageError e) { + } + } + } + } + return (Type[])bounds.clone(); + } + + public D getGenericDeclaration() { + return genericDeclaration; + } + + public String getName() { + return name; + } + + public int hashCode() { + //return super.hashCode(); + return getName().hashCode() ^ + ( genericDeclaration instanceof Class ? + ((Class)genericDeclaration).getName().hashCode() : + (genericDeclaration instanceof Method ? + ((Method)genericDeclaration).hashCode() : + ((Constructor)genericDeclaration).hashCode())); + } + + public String toString() { + return name; + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/WildcardTypeImpl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/WildcardTypeImpl.java new file mode 100644 index 0000000..d39dfac --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/implementation/WildcardTypeImpl.java @@ -0,0 +1,150 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.implementation; + +import java.lang.reflect.WildcardType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.MalformedParameterizedTypeException; + +import org.apache.harmony.lang.reflect.parser.InterimWildcardType; +import org.apache.harmony.lang.reflect.parser.InterimClassType; +import org.apache.harmony.lang.reflect.support.AuxiliaryCreator; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.2 $ + */ +public final class WildcardTypeImpl implements WildcardType { + private final Object startPoint; + private Type[] lowerBounds; + private Type[] upperBounds; + private final InterimWildcardType wildCardTypeBillet; + + public WildcardTypeImpl(InterimWildcardType billet, Object startPoint) { + this.upperBounds = null; + this.lowerBounds = null; + this.wildCardTypeBillet = billet; + this.startPoint = startPoint; // XXX: It seems to be a temporary decision to introduce startPoint + // It's not thought of finally. For example, it's not clear + // how can it influence on the WildcardTypeRepository.java + // ( "? extends TVAR" may be not equal to "? extends TVAR" + // because of first TVAR and second TVAR may be different type variables + // with the same name but I don't take it into account now in the repository algorithm + // I check there only the sugnatures equality :( . + } + + public boolean equals(Object other) { + //return super.equals(other); + if (!(other instanceof WildcardTypeImpl)) { + return false; + } + boolean res = true; + Type atl[] = (lowerBounds == null ? getLowerBounds() : lowerBounds); + Type atl2[] = (((WildcardTypeImpl)other).lowerBounds == null ? ((WildcardTypeImpl)other).getLowerBounds() : ((WildcardTypeImpl)other).lowerBounds); + if (atl.length != atl2.length) { + return false; + } + for(int i = 0; i < atl.length; i++) { + res = res && atl[i].equals(atl2[i]); + } + Type atu[] = (upperBounds == null ? getUpperBounds() : upperBounds); + Type atu2[] = (((WildcardTypeImpl)other).upperBounds == null ? ((WildcardTypeImpl)other).getUpperBounds() : ((WildcardTypeImpl)other).upperBounds); + if (atu.length != atu2.length) { + return false; + } + for(int i = 0; i < atu.length; i++) { + res = res && atu[i].equals(atu2[i]); + } + return res; + } + + public Type[] getLowerBounds() throws TypeNotPresentException, MalformedParameterizedTypeException { + if (lowerBounds == null) { + if (wildCardTypeBillet.boundsType == false) { + int l = wildCardTypeBillet.bounds.length; + lowerBounds = new Type[l]; + for (int i = 0; i < l; i++) { + // it can be InterimTypeVariable or InterimParameterizedType or InterimClassType. + // The MalformedParameterizedTypeException and TypeNotPresentException should be raised here if it needs. + try { + lowerBounds[i] = AuxiliaryCreator.createTypeArg(wildCardTypeBillet.bounds[i], this.startPoint); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)wildCardTypeBillet.bounds[i]).classTypeName.substring(1).replace('/', '.'), e); // ClassNotFoundException may appear here only for InterimClassType, see AuxiliaryCreator.createTypeArg. + } + } + } else { + lowerBounds = new Type[0]; + } + } + return (Type[])this.lowerBounds.clone(); + } + + public Type[] getUpperBounds() throws TypeNotPresentException, MalformedParameterizedTypeException { + if (upperBounds == null) { + if (wildCardTypeBillet.boundsType) { + int l = wildCardTypeBillet.bounds.length; + upperBounds = new Type[l]; + for (int i = 0; i < l; i++) { + // it can be InterimTypeVariable or InterimParameterizedType or InterimClassType. + // The MalformedParameterizedTypeException and TypeNotPresentException should be raised here if it needs. + try { + upperBounds[i] = AuxiliaryCreator.createTypeArg(wildCardTypeBillet.bounds[i], this.startPoint); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)wildCardTypeBillet.bounds[i]).classTypeName.substring(1).replace('/', '.'), e); // ClassNotFoundException may appear here only for InterimClassType, see AuxiliaryCreator.createTypeArg. + } + } + } else { + upperBounds = new Type[1]; + upperBounds[0] = (Type) Object.class; + } + } + return (Type[])this.upperBounds.clone(); + } + + public int hashCode() { + //return super.hashCode(); + int res = 0; + Type atl[] = (lowerBounds == null ? getLowerBounds() : lowerBounds); + for(int i = 0; i < atl.length; i++) { + res ^= atl[i].hashCode(); + } + Type atu[] = (upperBounds == null ? getUpperBounds() : upperBounds); + for(int i = 0; i < atu.length; i++) { + res ^= atu[i].hashCode(); + } + return res; + } + + public String toString() { + // TODO: this body should be reimplemented effectively. + StringBuffer sb = new StringBuffer(); + sb.append("?"); Type at[] = (lowerBounds == null ? getLowerBounds() : lowerBounds); + if (at.length != 0) { + if (at[0] instanceof Class) { + sb.append(" super "+((Class)at[0]).getName()); } else { sb.append(" super "+((TypeVariable)at[0]).getName()); } + return sb.toString(); + } + at = (upperBounds == null ? getUpperBounds() : upperBounds); + if (at[0] instanceof Class) { + String ts = ((Class)at[0]).getName(); + if (!ts.equals("java.lang.Object")) { + sb.append(" extends "+ts); + } } else { sb.append(" extends "+((TypeVariable)at[0]).getName()); } + return sb.toString(); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassGenericDecl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassGenericDecl.java new file mode 100644 index 0000000..9f45d6f --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassGenericDecl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimClassGenericDecl implements InterimGenericDeclaration { + public InterimType superClass; + public InterimType superInterfaces[]; + public InterimTypeParameter typeParameters[]; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassType.java new file mode 100644 index 0000000..fe23c8c --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimClassType.java @@ -0,0 +1,25 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimClassType implements InterimType { + public String classTypeName; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimConstructorGenericDecl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimConstructorGenericDecl.java new file mode 100644 index 0000000..8e08be0 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimConstructorGenericDecl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimConstructorGenericDecl implements InterimGenericDeclaration { + public InterimType methodParameters[]; + public InterimType throwns[]; + public InterimTypeParameter typeParameters[]; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimFieldGenericDecl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimFieldGenericDecl.java new file mode 100644 index 0000000..711129e --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimFieldGenericDecl.java @@ -0,0 +1,25 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimFieldGenericDecl implements InterimGenericDeclaration { + public InterimGenericType fieldType; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericArrayType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericArrayType.java new file mode 100644 index 0000000..e3de34c --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericArrayType.java @@ -0,0 +1,25 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimGenericArrayType implements InterimGenericType, InterimType { + public InterimType nextLayer; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericDeclaration.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericDeclaration.java new file mode 100644 index 0000000..021714f --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericDeclaration.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public interface InterimGenericDeclaration { +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericType.java new file mode 100644 index 0000000..6f64a2a --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimGenericType.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public interface InterimGenericType { +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimMethodGenericDecl.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimMethodGenericDecl.java new file mode 100644 index 0000000..aee2118 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimMethodGenericDecl.java @@ -0,0 +1,28 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimMethodGenericDecl implements InterimGenericDeclaration { + public InterimType methodParameters[]; + public InterimType returnValue; + public InterimType throwns[]; + public InterimTypeParameter typeParameters[]; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimParameterizedType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimParameterizedType.java new file mode 100644 index 0000000..a3c7e86 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimParameterizedType.java @@ -0,0 +1,29 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class InterimParameterizedType implements InterimGenericType, InterimType { + public String currentClauseName; // XXX: It seems to be superfluous but it's been used in AuxiliaryFinder + public InterimType ownerType; + public InterimType parameters[]; + public InterimClassType rawType; + public String signature; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimType.java new file mode 100644 index 0000000..674c707 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimType.java @@ -0,0 +1,24 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public interface InterimType { +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeParameter.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeParameter.java new file mode 100644 index 0000000..b6f33c4 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeParameter.java @@ -0,0 +1,27 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public class InterimTypeParameter { + public InterimType classBound; + public InterimType interfaceBounds[]; + public String typeParameterName; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeVariable.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeVariable.java new file mode 100644 index 0000000..8da3167 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimTypeVariable.java @@ -0,0 +1,25 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public class InterimTypeVariable implements InterimGenericType, InterimType { + public String typeVariableName; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimWildcardType.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimWildcardType.java new file mode 100644 index 0000000..8a7cf7e --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/InterimWildcardType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public class InterimWildcardType implements InterimType { + public InterimType bounds[]; + public boolean boundsType; +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/Parser.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/Parser.java new file mode 100644 index 0000000..0fcbd5e --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/Parser.java @@ -0,0 +1,39 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +import java.lang.reflect.GenericSignatureFormatError; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public class Parser { + + public static enum SignatureKind { + FIELD_SIGNATURE(2), + METHOD_SIGNATURE(3), + CONSTRUCTOR_SIGNATURE(4), + CLASS_SIGNATURE(1); + SignatureKind(int value) { this.value = value; } + private final int value; + public int value() { return value; } + }; + public static InterimGenericDeclaration parseSignature(String signature, SignatureKind kind, java.lang.reflect.GenericDeclaration startPoint) throws GenericSignatureFormatError { + return SignatureParser.parseSignature(signature, kind.value()); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureLexer2.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureLexer2.java new file mode 100644 index 0000000..42a2348 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureLexer2.java @@ -0,0 +1,519 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.parser; + +import antlr.TokenStream; +import antlr.TokenStreamException; +import antlr.Token; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + * + * NOTE. Initially this Signature Parser was created and debugged using lex and yacc on Linux: + * + * -bash-3.00$ uname -a + * Linux nstdrlel8.ins.intel.com 2.6.9-11.ELsmp #1 SMP Fri May 20 18:25:30 EDT 2005 x86_64 x86_64 x86_64 GNU/Linux + * -bash-3.00$ which yacc + * /usr/bin/yacc + * -bash-3.00$ which lex + * /usr/bin/lex + * -bash-3.00$ lex --version + * lex version 2.5.4 + * + * then it was rewritten for ANTLR 2.7.5 (http://www.antlr.org/) and redebugged: + * + * // $ANTLR 2.7.5 (20050128): "signature.g" -> "SignatureParser.java"$ + */ +public final class SignatureLexer2 extends antlr.CharScanner implements SignatureParserTokenTypes, TokenStream + { + +String ident = null; // to keep previous symbol if it's identifier + +int prevLexeme = -1;// to distinguish ID and TVAR + +int stackDepth = 0; // the current acheived depth of the parsered nested parameterized types chain (ParameterizedType1<ParameterizedType2<...>;ParameterizedType3<...>>;) +int Lflag2; // to distinguish ID and TBASE +int Lflag3; // to distinguish ID and TBASE +int trnglsCount = 0; + +boolean DEBUGGING = false; + +String sgntr; +int ind; +int lexlen; + +public SignatureLexer2(String sig) { + sgntr = sig; + ind = 0; + lexlen = 0; +} + +public Token nextToken() throws TokenStreamException { + if (ind >= sgntr.length()) { + return new MToken(MToken.EOF_TYPE, "the end"); + } + if (DEBUGGING) { + //System.out.println("nextToken1:"+sgntr); + //System.out.println("nextToken1:"+sgntr.charAt(ind)); + } + MToken theRetToken=null; + try { + switch ( sgntr.charAt(ind) ) { + case '*': + { + if (DEBUGGING) { + System.out.println(".............lex:STAR_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = STAR_SIGN; + theRetToken=new MToken(STAR_SIGN, "*"); + ind++; + break; + } + case '+': + { + if (DEBUGGING) { + System.out.println(".............lex:PLUS_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = PLUS_SIGN; + theRetToken=new MToken(PLUS_SIGN, "+"); + ind++; + break; + } + case '-': + { + if (DEBUGGING) { + System.out.println(".............lex:MINUS_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = MINUS_SIGN; + theRetToken=new MToken(MINUS_SIGN, "-"); + ind++; + break; + } + case '[': + { + if (DEBUGGING) { + System.out.println(".............lex:SQUAREOPEN_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = SQUAREOPEN_SIGN; + theRetToken=new MToken(SQUAREOPEN_SIGN, "["); + ind++; + break; + } + case ':': + { + if (DEBUGGING) { + System.out.println(".............lex:COLON_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = COLON_SIGN; + theRetToken=new MToken(COLON_SIGN, ":"); + ind++; + break; + } + case '.': + { + if (DEBUGGING) { + System.out.println(".............lex:DOT_OR_DOLLAR_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = DOT_OR_DOLLAR_SIGN; + theRetToken=new MToken(DOT_OR_DOLLAR_SIGN, "."); + ind++; + break; + } + case '<': + { + if (DEBUGGING) { + System.out.println(".............lex:TRIANGLEOPEN_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + if (Lflag2 == 1) trnglsCount++; + prevLexeme = TRIANGLEOPEN_SIGN; + theRetToken=new MToken(TRIANGLEOPEN_SIGN, "<"); + ind++; + break; + } + case '>': + { + if (DEBUGGING) { + System.out.println(".............lex:TRIANGLECLOSE_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + if (Lflag2 == 1) trnglsCount--; + prevLexeme = TRIANGLECLOSE_SIGN; + theRetToken=new MToken(TRIANGLECLOSE_SIGN, ">"); + ind++; + break; + } + case '^': + { + if (DEBUGGING) { + System.out.println(".............lex:CNTRL_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + Lflag2 = 0; + prevLexeme = CNTRL_SIGN; + theRetToken=new MToken(CNTRL_SIGN, "^"); + ind++; + break; + } + case ';': + { + if (DEBUGGING) { + System.out.println(".............lex:SEMICOLON_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + if (Lflag2 == 1 && trnglsCount == 0) { + Lflag3 = 0; + } + prevLexeme = SEMICOLON_SIGN; + theRetToken=new MToken(SEMICOLON_SIGN, ";"); + ind++; + break; + } + case '(': + { + if (DEBUGGING) { + System.out.println(".............lex:RINGOPEN_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + Lflag2 = 1; + prevLexeme = RINGOPEN_SIGN; + theRetToken=new MToken(RINGOPEN_SIGN, "("); + ind++; + break; + } + case ')': + { + if (DEBUGGING) { + System.out.println(".............lex:RINGCLOSE_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = RINGCLOSE_SIGN; + theRetToken=new MToken(RINGCLOSE_SIGN, ")"); + ind++; + break; + } + case 'V': + { + if (Lflag2 == 1 && trnglsCount == 0 && prevLexeme != PACKAGE_SPECIFIER && prevLexeme != DOT_OR_DOLLAR_SIGN) { + if (DEBUGGING) { + System.out.println(".............lex:VOIDTYPE" ); + } + prevLexeme = VOIDTYPE; + theRetToken=new MToken(VOIDTYPE, "V"); + ind++; + } else if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + ind += lexlen - 1; + theRetToken=new MToken(ID_COLON, ident); + } else if (isIDwoL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + ind += lexlen; + theRetToken=new MToken(ID, ident); + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + case 'B': case 'C': + case 'D': case 'F': + case 'I': case 'J': + case 'S': case 'Z': + { + if (Lflag2 == 1 && Lflag3 != 1) { + if (DEBUGGING) { + System.out.println(".............lex:TBASE: \""+ String.valueOf(sgntr.charAt(ind))+"\""); + } + if (ind == sgntr.length()-1 || sgntr.charAt(ind+1) == '^'){ + prevLexeme = RETURN_BASE_TYPE ; + theRetToken=new MToken(RETURN_BASE_TYPE , String.valueOf(sgntr.charAt(ind))); + } else { + prevLexeme = TBASE ; + theRetToken=new MToken(TBASE , String.valueOf(sgntr.charAt(ind))); + } + ind++; + } else if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + theRetToken=new MToken(ID_COLON, ident); + ind += lexlen - 1; + } else if (isIDwoL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + theRetToken=new MToken(ID, ident); + ind += lexlen; + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + case 'T': + { + if (isTV()) { + if (prevLexeme == PACKAGE_SPECIFIER || prevLexeme == DOT_OR_DOLLAR_SIGN) { + ident = sgntr.substring(ind, ind+lexlen-1);// - ";" + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID ; + theRetToken=new MToken(ID , ident); + ind += lexlen - 1; + } else { + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:TVAR:\""+ident+"\""); + } + prevLexeme = TVAR; + theRetToken=new MToken(TVAR, ident); + ind += lexlen; + } + } else if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + theRetToken=new MToken(ID_COLON, ident); + ind += lexlen - 1; + } else if (isIDwoL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + theRetToken=new MToken(ID, ident); + ind += lexlen; + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + case 'L': + { + if (isPACKAGE_SPECIFIER()) { + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:PACKAGE_SPECIFIER:\""+ident+"\""); + } + if (Lflag2 == 1) { + Lflag3 = 1; + } + prevLexeme = PACKAGE_SPECIFIER ; + theRetToken=new MToken(PACKAGE_SPECIFIER , ident); + ind += lexlen; + } else if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + theRetToken=new MToken(ID_COLON, ident); + ind += lexlen - 1; + } else if (isIDwL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + theRetToken=new MToken(ID, ident); + ind += lexlen; + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + case '$': + { + if (prevLexeme == TRIANGLECLOSE_SIGN) { + if (DEBUGGING) { + System.out.println(".............lex:DOT_OR_DOLLAR_SIGN:\""+String.valueOf(sgntr.charAt(ind))+"\""); + } + prevLexeme = DOT_OR_DOLLAR_SIGN; + theRetToken=new MToken(DOT_OR_DOLLAR_SIGN, "$"); + ind++; + } else if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + theRetToken=new MToken(ID_COLON, ident); + ind += lexlen - 1; + } else if (isIDwoL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + theRetToken=new MToken(ID, ident); + ind += lexlen; + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + case 'A': case 'E': case 'G': case 'H': + case 'K': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'U': + case 'W': case 'X': case 'Y': case '\\': + case '_': case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': + case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': + case 't': case 'u': case 'v': case 'w': + case 'x': case 'y': case 'z': + { + if (isID_COLON()){ + ident = sgntr.substring(ind, ind+lexlen-1); // last ":" should be recovered in stream + if (DEBUGGING) { + System.out.println(".............lex:ID_COLON:\""+ident+"\""); + } + prevLexeme = ID_COLON; + theRetToken=new MToken(ID_COLON, ident); + ind += lexlen - 1; + } else if (isIDwoL()){ + ident = sgntr.substring(ind, ind+lexlen); + if (DEBUGGING) { + System.out.println(".............lex:ID:\""+ident+"\""); + } + prevLexeme = ID; + theRetToken=new MToken(ID, ident); + ind += lexlen; + } else { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + break; + } + default: + { + theRetToken=new MToken(MToken.INVALID_TYPE, "figvam"); + throw new Exception(); + } + } + if (DEBUGGING) { + //new Throwable().printStackTrace(); + System.out.println("------------nextToken2:\""+theRetToken.getText()+"\""); + //System.out.println("nextToken2:"+theRetToken.getType()); + //System.out.println("nextToken2:"+ind); + } + return theRetToken; + } + catch (Exception e) { + /**/e.printStackTrace(); + /**/System.err.println("===nextToken===: "+e.toString()); + throw new TokenStreamException(e.getMessage()); + } + } + + private boolean isTV() { + if (DEBUGGING) { + System.out.println(".............isTV:"+ind); + } + String ns = sgntr.substring(ind).replaceFirst("T((\\\\[a-f0-9]{3})|[A-Za-z_$]){1}((\\\\[a-f0-9]{3})|[A-Za-z_$0-9])*;" , "#"); + if (ns.charAt(0) == '#') { + int i = sgntr.indexOf(ns.substring(1), ind); + lexlen = (i == ind)? sgntr.length() - ind : i - ind; + return true; + } + return false; + } + + private boolean isIDwoL() { + if (DEBUGGING) { + System.out.println(".............isIDwoL:"+ind+"|"+sgntr); + } + String ns = sgntr.substring(ind).replaceFirst("((\\\\[a-f0-9]{3})|[A-KM-Za-z_$]){1}((\\\\[a-f0-9]{3})|[A-Za-z_$0-9])*" , "#"); + if (ns.charAt(0) == '#') { + int i = sgntr.indexOf(ns.substring(1), ind); + lexlen = (i == ind)? sgntr.length() - ind : i - ind; + return true; + } + return false; + } + + private boolean isID_COLON() { + if (DEBUGGING) { + System.out.println(".............isID_COLON:"+ind); + } + String ns = sgntr.substring(ind).replaceFirst("((\\\\[a-f0-9]{3})|[A-Za-z_$]){1}((\\\\[a-f0-9]{3})|[A-Za-z_$0-9])*::" , "#"); + if (ns.charAt(0) == '#') { + int i = sgntr.indexOf(ns.substring(1), ind); + lexlen = (i == ind)? sgntr.length() - ind : i - ind; + return true; + } + return false; + } + + private boolean isPACKAGE_SPECIFIER() { + if (DEBUGGING) { + System.out.println(".............isPACKAGE_SPECIFIER:"+ind); + } + String ns = sgntr.substring(ind).replaceFirst("L((\\\\[a-f0-9]{3})|[A-Za-z_$]){1}((\\\\[a-f0-9]{3})|[A-Za-z_$0-9/])*/" , "#"); + if (ns.charAt(0) == '#') { + int i = sgntr.indexOf(ns.substring(1), ind); + lexlen = (i == ind)? sgntr.length() - ind : i - ind; + return true; + } + return false; + } + + private boolean isIDwL() { + if (DEBUGGING) { + System.out.println(".............isIDwL:"+ind); + } + String ns = sgntr.substring(ind).replaceFirst("L((\\\\[a-f0-9]{3})|[A-Za-z_$0-9])*" , "#"); + if (ns.charAt(0) == '#') { + int i = sgntr.indexOf(ns.substring(1), ind); + lexlen = (i == ind)? sgntr.length() - ind : i - ind; + return true; + } + return false; + } +} + +class MToken extends Token { + String txt; + + public MToken(int t, String txt) { + super(); + super.type = t; + setText(txt); + } + + public String getText() { + return txt; + } + + public void setText(String t) { + txt = t; + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParser.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParser.java new file mode 100644 index 0000000..1c7c5f6 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParser.java @@ -0,0 +1,2719 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // $ANTLR 2.7.5 (20050128): "signature.g" -> "SignatureParser.java"$ + +package org.apache.harmony.lang.reflect.parser; + +import java.util.ArrayList; +import java.io.StringBufferInputStream; +import java.io.IOException; +import java.lang.reflect.GenericSignatureFormatError; +import org.apache.harmony.lang.reflect.parser.*; + +import antlr.TokenBuffer; +import antlr.TokenStreamException; +import antlr.TokenStreamIOException; +import antlr.ANTLRException; +import antlr.LLkParser; +import antlr.Token; +import antlr.TokenStream; +import antlr.RecognitionException; +import antlr.NoViableAltException; +import antlr.MismatchedTokenException; +import antlr.SemanticException; +import antlr.ParserSharedInputState; +import antlr.collections.impl.BitSet; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.3 $ + * + * NOTE 1. This signature.g was created and debugged using + * -bash-3.00$ uname -a + * Linux nstdrlel8.ins.intel.com 2.6.9-11.ELsmp #1 SMP Fri May 20 18:25:30 EDT 2005 x86_64 x86_64 x86_64 GNU/Linux + * -bash-3.00$ which yacc + * /usr/bin/yacc + * -bash-3.00$ which lex + * /usr/bin/lex + * -bash-3.00$ lex --version + * lex version 2.5.4 + * + * then it was rewritten for ANTLR 2.7.5 + * + * + * To generate java code of signature syntax parser (consisting of SignatureParser.java and SignatureParserTokenTypes.java) + * you should + * - enter to ...\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser directory: + * cd C:\IJE\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser + * - set pointer to ANTLR: + * set CLASSPATH=C:\Documents and Settings\szapreye\My Documents\ANTLR\antlr-2.7.5.jar;. + * - start 1.5 java VM: + * java antlr.Tool signature.g + * + * It provides the creation of SignatureParser.java and SignatureParserTokenTypes.java which in joining with lexer (SignatureLexer2.java) + * arrange the generic signature attribute parser. + * + */ +public class SignatureParser extends antlr.LLkParser implements SignatureParserTokenTypes + { + +private SignatureLexer2 lexer; +private int declType; // prescribed (predefined in parser's args) type of the parsered declaration +private static final int CLASSoDECL = 1; //Parser.SignatureKind.CLASS_SIGNATURE.value(); +private static final int FIELDoDECL = 2; //Parser.SignatureKind.FIELD_SIGNATURE.value(); +private static final int METHODoDECL = 3; //Parser.SignatureKind.METHOD_SIGNATURE.value(); +private static final int CONSTRUCTORoDECL = 4; //Parser.SignatureKind.CONSTRUCTOR_SIGNATURE.value(); + +private ArrayList<InterimTypeParameter> genParamList = null; // to accumulate generic parameters +private ArrayList<InterimType> boundList = null; // to accumulate bounds of a generic parameter +private ArrayList<InterimType> methParamList = null; // to accumulate method's or constructor's parameters +private ArrayList<InterimType> thrownList = null; // to accumulate exceptions thrown by a method/constructor +private ArrayList<InterimType> implList = null; // to accumulate implements-clauses of a class decl + +private InterimClassGenericDecl classDecl = null; +private InterimFieldGenericDecl fieldDecl = null; +private InterimMethodGenericDecl methodDecl = null; +private InterimConstructorGenericDecl constructorDecl = null; + +private InterimTypeParameter currentTypeParameter = null; +private int Yflag1 = 0; // to mark the start of generic type parameters processing +private int Yflag2 = 0; // to mark the start of method's/constructor's throws-part processing +class PTStack { // stack of parsered nested parameterized types + String gatheredStr; // packageSpecifier / packageSpecifier + ID / packageSpecifier + ID {+ "$"ID} + int gthrdStrLen; // length of the allocated gatheredStr; + int wrappInWildcard; // -1 - not to wrapp; 1 - lower; 0 - upper + int typeKind; // previous level type kind: 1 - InterimParameterizedType; 0 - InterimClassType + InterimClassType rawType; // InterimClassType + InterimType owner; // InterimParameterizedType or InterimClassType + ArrayList<InterimType> args; // InterimParameterizedType or InterimClassType or InterimTypeVariable or InterimWildcardType + int sigBegin; // start of the signature of the current nested parameterized type within CTPTsignature + int sigEnd; // finish of the signature of the current nested parameterized type within CTPTsignature + int dim; // to indicate the number of consequent "[" symbols. ATTENTION: it used for all types: TVAR, TBASE, RETURN_BASE_TYPE, class type, parameterized type + PTStack nextLevel; +}; +private PTStack stack; +private PTStack currentStackElem; // points to the current processed level element of the nested parameterized types chain + +private String CTPTsignature; // accumulated signature of the current parsered parameterized type, it's used for parameterized types repository +private int sigInd; +private int sigLen; + +private InterimType/*InterimGenericType*/ highLevelType; // the rolled up reference (InterimParameterizedType or InterimClassType) + +private int i; +private InterimType prsrT; +private int len; +private PTStack p1, p2, currentStackElemCopy; +private InterimClassType upper; +private char t; +////////////////////////////////////////////////////////////////////////////////////////////////////// +private void throwGenericSignatureFormatError() throws GenericSignatureFormatError { + + prntS(" throwGenericSignatureFormatError"); + + clean(); + throw new GenericSignatureFormatError(); +} +private void clean() { + int i; + PTStack p1 = null; + PTStack p2 = null; + + prntS(" clean"); + + genParamList = null; + boundList = null; + methParamList = null; + thrownList = null; + for (i = 0; i <= lexer.stackDepth; i++) { + if (i == 0) { + p1 = stack; + } else { + p1 = p1.nextLevel; + } + p1.args = null; + } + for (i = 0; i <= lexer.stackDepth; i++) { + if (i == 0) { + p1 = stack; + } + p2 = p1.nextLevel; + p1.nextLevel = null; + p1 = p2; + } + stack = null; + // XXX: How can we clear the memory allocated for currentStackElem.rawType and currentStackElem.owner? + // Will it be done by VM's gc somehow later or should we invoke some JNI's method + // or should we just invoke System.gc through JNI? + CTPTsignature = null; +} +private void addElemToGenParamList(InterimTypeParameter ref) { //XXX: maybe, use genParamList.add(ref) everywhere instead of addElemToGenParamList(ref), remove addElemToGenParamList at all + prntS(" addElemToGenParamList"); + + if(genParamList == null) { + genParamList = new ArrayList<InterimTypeParameter>(); + } + genParamList.add(ref); +} +private void addElemToBoundList(InterimType ref) { + prntS(" addElemToBoundList"); + + if(boundList == null) { + boundList = new ArrayList<InterimType>(); + } + boundList.add(ref); +} +private void addElemToMethParamList(Object ref) { + prntSO(" addElemToMethParamList", ref); + + if(methParamList == null) { + methParamList = new ArrayList<InterimType>(); + } + methParamList.add((InterimType)ref); +} +private void addElemToTypeArgsList(InterimType ref) { + prntS(" addElemToTypeArgsList"); + + // find the previous element for the current stack's element: + PTStack p1 = stack, p2 = null; + + while (p1 != currentStackElem){ + p2 = p1; + p1 = p1.nextLevel; + } + + // add the value to the args list of the found stack's element: + if(p2.args == null) { + p2.args = new ArrayList(); + } + p2.args.add(ref); + + // clean the current stack's element to be ready for new reference parsering: + currentStackElem.gatheredStr = null; + currentStackElem.args = null; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; // value should not be myfreed because a pointer to the later used java object was there + currentStackElem.owner = null; // value should not be myfreed because a pointer to the later used java object was there + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; +} +private void addElemToThrownList(InterimType ref) { + prntS(" addElemToThrownList"); + + if(thrownList == null) { + thrownList = new ArrayList<InterimType>(); + } + thrownList.add(ref); +} +private void addElemToImplList(InterimType ref) { + prntS(" addElemToImplList"); + + if(implList == null) { + implList = new ArrayList<InterimType>(); + } + implList.add(ref); +} +private void addToGatheredStr(PTStack stackElem, String part) { + if(stackElem.gatheredStr != null) { + prntSSS(" addToGatheredStr", stackElem.gatheredStr, part); + } else { + prntSS(" addToGatheredStr", part); + } + + if(stackElem.gatheredStr == null) { + stackElem.gatheredStr = ""; + } + stackElem.gatheredStr = stackElem.gatheredStr + part; + prntSS(">->->->-> ", stackElem.gatheredStr); +} +private int addToSignature(String part) { + int res = sigInd; + + prntS(" start addToSignature"); + if(CTPTsignature == null) { + CTPTsignature = ""; + } + res = CTPTsignature.length(); + CTPTsignature = CTPTsignature + part; + sigInd += part.length(); + + prntS(" end addToSignature"); + return res; +} +private void createTypeParameterName(String name) { + prntS(" createTypeParameterName"); + + currentTypeParameter = new InterimTypeParameter(); + currentTypeParameter.typeParameterName = name; +} +private InterimClassType createInterimClassType(String reference) { + InterimClassType res; + + prntS(" createInterimClassType"); + + res = new InterimClassType(); + res.classTypeName = reference; + return res; +} +private InterimTypeVariable createInterimTypeVariable(String tVariableName) { + prntSS(" createInterimTypeVariable", tVariableName); + + InterimTypeVariable obj; + + obj = new InterimTypeVariable(); + obj.typeVariableName = tVariableName; + return obj; +} +private InterimParameterizedType createInterimParameterizedType(String signature, PTStack stackElem) { + InterimParameterizedType obj; + + prntS(" createInterimParameterizedType"); + + obj = new InterimParameterizedType(); + obj.signature = signature; + obj.rawType = stackElem.rawType; + obj.ownerType = stackElem.owner; + if (stackElem.args != null) { + obj.parameters = stackElem.args.toArray(new InterimType[stackElem.args.size()]); + } else { + obj.parameters = new InterimType[0]; + } + + return obj; +} +private InterimWildcardType createInterimWildcardType(int boundsType, InterimType[] bounds, int boundsInd) { + InterimWildcardType obj; + + prntS(" createInterimWildcardType"); + + obj = new InterimWildcardType(); + obj.boundsType = boundsType == 0; + obj.bounds = bounds; + + return obj; +} +private InterimGenericArrayType createInterimGenericArrayType(InterimType nextL) { + InterimGenericArrayType obj; + + prntS(" createInterimGenericArrayType"); + + obj = new InterimGenericArrayType(); + obj.nextLayer = /*(InterimGenericType)*/nextL; + + return obj; +} +private String getBaseTypeName(char c) { + switch (c) + { + case 'I': + return "int"; + case 'F': + return "float"; + case 'D': + return "double"; + case 'J': + return "long"; + case 'S': + return "short"; + case 'Z': + return "boolean"; + case 'B': + return "byte"; + case 'C': + return "char"; + } + throwGenericSignatureFormatError(); + return "UNKNOWN"; +} +private void prntS(String str) { + if (lexer.DEBUGGING){ + System.out.println("|"+str+"|"); + } +} +void prntSS(String str1, String str2) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+str2+"|"); + } +} +void prntSSS(String str1, String str2, String str3) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+str2+"|"+str3+"|"); + } +} +void prntSD(String str1, long num) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+num+"|"); + } +} +void prntSO(String str1, Object o) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+o+"|"); + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////// +public static InterimGenericDeclaration parseSignature(String st, int kind) { + InterimGenericDeclaration res = null; + SignatureLexer2 lexer = new SignatureLexer2(st); //?StringReader + SignatureParser parser = new SignatureParser(lexer); + // Parse the input + try { + parser.pr__DECL(kind, lexer); + } + catch(RecognitionException e) { + e.printStackTrace(); + System.err.println("signature syntax error: "+e); + parser.throwGenericSignatureFormatError(); // signature syntax error! + } + catch(antlr.TokenStreamException e) { + e.printStackTrace(); + System.err.println("TokenStreamException: "+e); + parser.throwGenericSignatureFormatError(); + } + parser.prntS("zzzzzzzzzzzzzzzzzz3"); + + switch (kind) + { + case CLASSoDECL: + res = (InterimGenericDeclaration)parser.classDecl; + break; + case FIELDoDECL: + res = (InterimGenericDeclaration)parser.fieldDecl; + break; + case METHODoDECL: + res = (InterimGenericDeclaration)parser.methodDecl; + break; + case CONSTRUCTORoDECL: + res = (InterimGenericDeclaration)parser.constructorDecl; + break; + } + parser.clean(); + parser.prntSO("zzzzzzzzzzzzzzzzzz4", res); + + return res; +} + +protected SignatureParser(TokenBuffer tokenBuf, int k) { + super(tokenBuf,k); + tokenNames = _tokenNames; +} + +public SignatureParser(TokenBuffer tokenBuf) { + this(tokenBuf,1); +} + +protected SignatureParser(TokenStream lexer, int k) { + super(lexer,k); + tokenNames = _tokenNames; +} + +public SignatureParser(TokenStream lexer) { + this(lexer,1); +} + +public SignatureParser(ParserSharedInputState state) { + super(state,1); + tokenNames = _tokenNames; +} + + public final void pr__DECL( + int kind, Object lex + ) throws RecognitionException, TokenStreamException { + + + lexer = (SignatureLexer2)lex; + //lexer.DEBUGGING = true; + declType = kind; + stack = new PTStack(); + stack.gatheredStr = null; + stack.gthrdStrLen = 0; + stack.typeKind = 0; + stack.wrappInWildcard = -1; + stack.rawType = null; + stack.owner = null; + stack.args = null; + stack.sigBegin = -1; + stack.sigEnd = -1; + stack.dim = 0; + stack.nextLevel = null; + + // to be reenterable: + CTPTsignature = null; + sigInd = 0; + sigLen = 0; + currentStackElem = stack; + genParamList = null; + boundList = null; + methParamList = null; + thrownList = null; + implList = null; + Yflag2 = 0; + currentTypeParameter = null; + + // Clean lex's environment to provide reenterability: + lexer.prevLexeme = -1; + lexer.Lflag2 = 0; + lexer.Lflag3 = 0; + lexer.stackDepth = 0; + lexer.ident = null; + + + try { // for error handling + if (((LA(1)==TRIANGLEOPEN_SIGN||LA(1)==ID||LA(1)==PACKAGE_SPECIFIER))&&(declType==CLASSoDECL)) { + pr__CLASS_DECL(); + if ( inputState.guessing==0 ) { + prntSS(" pr__DECL 1 :", "m1.getText()"); + } + } + else if (((_tokenSet_0.member(LA(1))))&&(declType==FIELDoDECL)) { + pr__FIELD_DECL(); + if ( inputState.guessing==0 ) { + + // it's time to create InterimFieldGenericDecl and to fill fieldDecl + fieldDecl = new InterimFieldGenericDecl(); + + // set fieldType field of InterimFieldGenericDecl object: + fieldDecl.fieldType = (InterimGenericType)highLevelType; + + highLevelType = null; + + prntSS(" pr__DECL 2 :", "m2.getText()"); + + } + } + else if (((LA(1)==TRIANGLEOPEN_SIGN||LA(1)==RINGOPEN_SIGN))&&(declType==METHODoDECL)) { + pr__METHOD_DECL(); + if ( inputState.guessing==0 ) { + prntSS(" pr__DECL 3:", "m3.getText()"); + } + } + else if (((LA(1)==TRIANGLEOPEN_SIGN||LA(1)==RINGOPEN_SIGN))&&(declType==CONSTRUCTORoDECL)) { + pr__CONSTRUCTOR_DECL(); + if ( inputState.guessing==0 ) { + prntSS(" pr__DECL 4 :", "m4.getText()"); + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__CLASS_DECL() throws RecognitionException, TokenStreamException { + + + try { // for error handling + switch ( LA(1)) { + case TRIANGLEOPEN_SIGN: + { + pr__FORMAL_TYPE_PARAMETERS_DECL(); + if ( inputState.guessing==0 ) { + prntSS(" ### 1:", "m6.getText()"); + } + pr__CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===1==="); + // actually, it's pr__SUPERCLASSoSIGNATURE + + // it's time to create InterimClassGenericDecl and to fill classDecl + classDecl = new InterimClassGenericDecl(); + + // set superClass field of InterimClassGenericDecl object: + classDecl.superClass = (InterimType)highLevelType; + + highLevelType = null; + + // set typeParameters field of InterimClassGenericDecl object: + classDecl.typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + + // clean the genParamList: + genParamList = null; + + prntSS(" ### 2:", "m7.getText()"); + + } + pr__SUPERINTERFACE_SIGNATURES(); + if ( inputState.guessing==0 ) { + + prntS(" ===2==="); + // set superInterfaces field of InterimClassGenericDecl object: + classDecl.superInterfaces = (implList == null ? new InterimType[0] : implList.toArray(new InterimType[implList.size()])); + + // clean the implList: + implList = null; + + prntSS(" pr__CLASS_DECL 1 :", "m8.getText()"); + + } + break; + } + case ID: + case PACKAGE_SPECIFIER: + { + pr__CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + if (declType == CLASSoDECL) { + prntS(" ===3.1==="); + // actually, it's pr__SUPERCLASSoSIGNATURE + + // it's time to create InterimClassGenericDecl and to fill classDecl + classDecl = new InterimClassGenericDecl(); + + // set superClass field of InterimClassGenericDecl object: + classDecl.superClass = (InterimType)highLevelType; + + highLevelType = null; + } else { // it's FIELDoDECL + prntS(" ===3.2==="); + // actually, it's field type signature (instead the pr__FIELD_DECL which does not work really) + + // it's time to create InterimFieldGenericDecl and to fill fieldDecl + fieldDecl = new InterimFieldGenericDecl(); + + // set superClass field of InterimFieldGenericDecl object: + fieldDecl.fieldType = (InterimGenericType)highLevelType; + + highLevelType = null; + } + + prntSS(" ### 3:", "m9.getText()"); + + } + pr__SUPERINTERFACE_SIGNATURES(); + if ( inputState.guessing==0 ) { + + if (declType == CLASSoDECL) { + // set superInterfaces field of InterimClassGenericDecl object: + classDecl.superInterfaces = (implList == null ? new InterimType[0] : implList.toArray(new InterimType[implList.size()])); + + // clean the implList: + implList = null; + + prntSS(" pr__CLASS_DECL 2 :", "m10.getText()"); + } else { + prntSS(" pr__CLASS_DECL 2 (+++ for FIELDoDECL +++) :", "m10.getText()"); + } + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__FIELD_DECL() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__FIELD_DECL:", "m5.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__METHOD_DECL() throws RecognitionException, TokenStreamException { + + + try { // for error handling + boolean synPredMatched48 = false; + if (((LA(1)==RINGOPEN_SIGN))) { + int _m48 = mark(); + synPredMatched48 = true; + inputState.guessing++; + try { + { + pr__M_P_AND_R_T(); + pr__THROWN_SIGNATURE(); + } + } + catch (RecognitionException pe) { + synPredMatched48 = false; + } + rewind(_m48); + inputState.guessing--; + } + if ( synPredMatched48 ) { + pr__M_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" ### 25:", "m59.getText()"); + } + pr__THROWN_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_DECL 2 :prntSS", "m60.getText()"); + } + } + else if ((LA(1)==RINGOPEN_SIGN)) { + pr__M_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_DECL 1 :", "m58.getText()"); + } + } + else { + boolean synPredMatched50 = false; + if (((LA(1)==TRIANGLEOPEN_SIGN))) { + int _m50 = mark(); + synPredMatched50 = true; + inputState.guessing++; + try { + { + pr__F_T_P_AND_M_P_AND_R_T(); + pr__THROWN_SIGNATURE(); + } + } + catch (RecognitionException pe) { + synPredMatched50 = false; + } + rewind(_m50); + inputState.guessing--; + } + if ( synPredMatched50 ) { + pr__F_T_P_AND_M_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" ### 26:", "m62.getText()"); + } + pr__THROWN_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_DECL 4 :", "m63.getText()"); + } + } + else if ((LA(1)==TRIANGLEOPEN_SIGN)) { + pr__F_T_P_AND_M_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_DECL 3 :", "m61.getText()"); + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__CONSTRUCTOR_DECL() throws RecognitionException, TokenStreamException { + + + try { // for error handling + boolean synPredMatched41 = false; + if (((LA(1)==RINGOPEN_SIGN))) { + int _m41 = mark(); + synPredMatched41 = true; + inputState.guessing++; + try { + { + pr__C_P_AND_R_T(); + pr__THROWN_SIGNATURE(); + } + } + catch (RecognitionException pe) { + synPredMatched41 = false; + } + rewind(_m41); + inputState.guessing--; + } + if ( synPredMatched41 ) { + pr__C_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" ### 23:", "m53.getText()"); + } + pr__THROWN_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CONSTRUCTOR_DECL 2 :prntSS", "m54.getText()"); + } + } + else if ((LA(1)==RINGOPEN_SIGN)) { + pr__C_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CONSTRUCTOR_DECL 1 :", "m52.getText()"); + } + } + else { + boolean synPredMatched43 = false; + if (((LA(1)==TRIANGLEOPEN_SIGN))) { + int _m43 = mark(); + synPredMatched43 = true; + inputState.guessing++; + try { + { + pr__F_T_P_AND_C_P_AND_R_T(); + pr__THROWN_SIGNATURE(); + } + } + catch (RecognitionException pe) { + synPredMatched43 = false; + } + rewind(_m43); + inputState.guessing--; + } + if ( synPredMatched43 ) { + pr__F_T_P_AND_C_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" ### 24:", "m56.getText()"); + } + pr__THROWN_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CONSTRUCTOR_DECL 4 :", "m57.getText()"); + } + } + else if ((LA(1)==TRIANGLEOPEN_SIGN)) { + pr__F_T_P_AND_C_P_AND_R_T(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CONSTRUCTOR_DECL 3 :", "m55getText()"); + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__FIELD_TYPE_SIGNATURE() throws RecognitionException, TokenStreamException { + + Token m23 = null; + + try { // for error handling + switch ( LA(1)) { + case ID: + case PACKAGE_SPECIFIER: + { + pr__CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__FIELD_TYPE_SIGNATURE 1 :", "m21.getText()"); + } + break; + } + case SQUAREOPEN_SIGN: + { + pr__ARRAY_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===9==="); + if (Yflag1 == 1) { + throwGenericSignatureFormatError(); // array type is not permissible within a generic params decl + } + if (currentStackElem.wrappInWildcard != -1) { + throwGenericSignatureFormatError(); // array type is not permissible within a wild card + } + prntSS(" pr__FIELD_TYPE_SIGNATURE 2 :", "m22.getText()"); + + } + break; + } + case TVAR: + { + m23 = LT(1); + match(TVAR); + if ( inputState.guessing==0 ) { + + prntS(" ===10==="); + // grow the signature if it needs: + if(CTPTsignature != null){ + currentStackElem.sigEnd = addToSignature(m23.getText()) + m23.getText().length(); + } + + // to exclude first (official) "T" symbol (and last ";" symbol): + prsrT = (InterimType)createInterimTypeVariable(m23.getText().substring(1, m23.getText().length()-1)); + + // if there is wildcard indicator then InterimTypeVariable should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + if (Yflag1 == 1) { // within generic params decl (class'/method's/constructor's) + if(lexer.stackDepth == 0){ // not within parameterized type + if(boundList == null){ + addElemToBoundList(prsrT); // first (i.e. "extends") bound, consequently, TVAR is permissible here + } else { + throwGenericSignatureFormatError(); // non-first (i.e. "implements") bound, consequently, TVAR is not permissible as such bound + } + } else { // within parameterized type which appears within gen params decl + // put the InterimTypeVariable on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } else { + // so, for other places of using ... + if(lexer.stackDepth == 0){ // not within parameterized type + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } else { // within parameterized type which appears not within gen params decl + // put the InterimTypeVariable on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } + prntSS(" pr__FIELD_TYPE_SIGNATURE 3 :", m23.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_2); + } else { + throw ex; + } + } + } + + public final void pr__FORMAL_TYPE_PARAMETERS_DECL() throws RecognitionException, TokenStreamException { + + Token m11 = null; + Token m13 = null; + + try { // for error handling + m11 = LT(1); + match(TRIANGLEOPEN_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===4==="); + Yflag1 = 1; // start of generic parameters parsing + prntSS(" ### 4:", m11.getText()); + + } + pr__FORMAL_TYPE_PARAMETERS(); + if ( inputState.guessing==0 ) { + prntSS(" ### 5:", "m12.getText()"); + } + m13 = LT(1); + match(TRIANGLECLOSE_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===5==="); + Yflag1 = 0; // finish of generic parameters parsing + prntSS(" pr__FORMAL_TYPE_PARAMETERS_DECL:", m13.getText()); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_3); + } else { + throw ex; + } + } + } + + public final void pr__CLASS_TYPE_SIGNATURE() throws RecognitionException, TokenStreamException { + + Token m25 = null; + + try { // for error handling + pr__REFERENCE(); + if ( inputState.guessing==0 ) { + prntSS(" ### 10:", "m24.getText()"); + } + m25 = LT(1); + match(SEMICOLON_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===11==="); + // XXX: seems, the entire code fragment below can be easily simplified + + // roll up the reference (InterimClassType or InterimParameterizedType) to put on the layer above or to return as a final result: + if (lexer.stackDepth == 0) { + prntS(" ===111==="); + if(currentStackElem.typeKind == 0) { // InterimClassType + // return the InterimClassType as a result of a reference rolling up: + prsrT = (InterimType)createInterimClassType(currentStackElem.gatheredStr); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } else { //InterimParameterizedType + if(Yflag2 == 1){ // within the throws + throwGenericSignatureFormatError(); // here InterimParameterizedType is prohibited. + } + + // return the InterimParameterizedType as a result of a reference rolling up: + addToSignature(";"); + currentStackElem.sigEnd += 1; + len = sigInd - currentStackElem.sigBegin - 1; //to eliminate everywhere the last semicolon sign + prsrT = (InterimType)createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } + + // it's time to clean entire CTPTsignature for finally rolled up high level reference: + if (CTPTsignature != null) { + CTPTsignature = null; + sigInd = 0; + sigLen = 0; + } + + // clean the current stack's element to be ready for new reference parsering: + currentStackElem.gatheredStr = null; + currentStackElem.args = null; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; //value should not be mefreed because a pointer to the later used java object was there + currentStackElem.owner = null; //value should not be mefreed because a pointer to the later used java object was there + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; + } else { + prntS(" ===112==="); + if(currentStackElem.typeKind == 0) { // InterimClassType + addToSignature(";"); + currentStackElem.sigEnd += 1; + prsrT = createInterimClassType(currentStackElem.gatheredStr); + + // if there is wildcard indicator then InterimClassType should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put the InterimClassType/InterimWildcardType on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } else { // InterimParameterizedType + addToSignature(";"); + currentStackElem.sigEnd += 1; + len = sigInd - currentStackElem.sigBegin -1; //to eliminate everywhere the last semicolon sign + prsrT = (InterimType)createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + + // if there is wildcard indicator then InterimParameterizedType should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + // put the InterimParameterizedType/InterimWildcardType on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } + + // It's time to clear currentStackElem.gatheredStr: + currentStackElem.gatheredStr = null; + // It's time also to clear currentStackElem.rawType: + currentStackElem.rawType = null; + + prntSS(" pr__CLASS_TYPE_SIGNATURE:", m25.getText()); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_2); + } else { + throw ex; + } + } + } + + public final void pr__SUPERINTERFACE_SIGNATURES() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + _loop37: + do { + if ((LA(1)==ID||LA(1)==PACKAGE_SPECIFIER)) { + pr__SUPERINTERFACE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__SUPERINTERFACE_SIGNATURES 1 :", "m50.getText()"); + } + } + else { + break _loop37; + } + + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__FORMAL_TYPE_PARAMETERS() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + int _cnt7=0; + _loop7: + do { + if ((LA(1)==ID_COLON||LA(1)==ID)) { + pr__FORMAL_TYPE_PARAMETER(); + if ( inputState.guessing==0 ) { + prntSS(" pr__FORMAL_TYPE_PARAMETERS 1 :", "m14.getText()"); + } + } + else { + if ( _cnt7>=1 ) { break _loop7; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt7++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_4); + } else { + throw ex; + } + } + } + + public final void pr__FORMAL_TYPE_PARAMETER() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__ID_WITH_COLON(); + if ( inputState.guessing==0 ) { + prntSS(" ### 7:", /*lexer.ident*/"m141.getText()"); + } + pr__CLASS_OR_INTERFACE_BOUNDS(); + if ( inputState.guessing==0 ) { + + prntS(" ===6==="); + // set classBound field of InterimTypeParameter object: + currentTypeParameter.classBound = (InterimType)boundList.get(0); // the first elem is extends-clause + boundList.remove(0); + + // set interfaceBounds field of InterimTypeParameter object: + currentTypeParameter.interfaceBounds = boundList.toArray(new InterimType[boundList.size()]); + + // clean the boundList before a possible re-using: + boundList = null; + + // add the prepared InterimTypeParameter object to genParamList: + addElemToGenParamList(currentTypeParameter); + + prntSS(" pr__FORMAL_TYPE_PARAMETER:", "m15.getText()"); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_5); + } else { + throw ex; + } + } + } + + public final void pr__ID_WITH_COLON() throws RecognitionException, TokenStreamException { + + Token m151 = null; + Token m16 = null; + + try { // for error handling + switch ( LA(1)) { + case ID_COLON: + { + m151 = LT(1); + match(ID_COLON); + if ( inputState.guessing==0 ) { + + prntS(" ===7==="); + String ts1 = m151.getText(); + String ts2 = ts1.substring(0, ts1.length()-2); + + createTypeParameterName(ts2); + addElemToBoundList(createInterimClassType("Ljava/lang/Object")); // Object is supposed if extends clause is empty (example: PARAMNAME::...;) + + prntSS(" pr__ID_WITH_COLON 1 :", ts2); + + } + break; + } + case ID: + { + m16 = LT(1); + match(ID); + if ( inputState.guessing==0 ) { + + prntS(" ===8==="); + createTypeParameterName(m16.getText()); + + prntSS(" pr__ID_WITH_COLON 2 :", m16.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_6); + } else { + throw ex; + } + } + } + + public final void pr__CLASS_OR_INTERFACE_BOUNDS() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + int _cnt12=0; + _loop12: + do { + if ((LA(1)==COLON_SIGN)) { + pr__BOUND(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CLASS_OR_INTERFACE_BOUNDS 1 :", "m18.getText()"); + } + } + else { + if ( _cnt12>=1 ) { break _loop12; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt12++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_5); + } else { + throw ex; + } + } + } + + public final void pr__BOUND() throws RecognitionException, TokenStreamException { + + Token m19 = null; + + try { // for error handling + m19 = LT(1); + match(COLON_SIGN); + if ( inputState.guessing==0 ) { + prntSS(" ### 9:", m19.getText()); + } + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===8.1==="); + addElemToBoundList((InterimType)highLevelType); // add the gathered regular type to bounds-list + + highLevelType = null; + + prntSS(" pr__BOUND:", "m20.getText()"); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_7); + } else { + throw ex; + } + } + } + + public final void pr__ARRAY_TYPE_SIGNATURE() throws RecognitionException, TokenStreamException { + + Token m46 = null; + + try { // for error handling + m46 = LT(1); + match(SQUAREOPEN_SIGN); + if ( inputState.guessing==0 ) { + + currentStackElem.dim += 1; + + prntSS(" ### 21:", m46.getText()); + + } + pr__TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__ARRAY_TYPE_SIGNATURE:", "m47.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_2); + } else { + throw ex; + } + } + } + + public final void pr__REFERENCE() throws RecognitionException, TokenStreamException { + + + try { // for error handling + boolean synPredMatched18 = false; + if (((LA(1)==ID))) { + int _m18 = mark(); + synPredMatched18 = true; + inputState.guessing++; + try { + { + pr__SIMPLE_CLASS_TYPE_SIGNATURE(); + pr__CLASS_TYPE_SIGNATURE_SUFFIXES(); + } + } + catch (RecognitionException pe) { + synPredMatched18 = false; + } + rewind(_m18); + inputState.guessing--; + } + if ( synPredMatched18 ) { + pr__SIMPLE_CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" ### 10:", "m27.getText()"); + } + pr__CLASS_TYPE_SIGNATURE_SUFFIXES(); + if ( inputState.guessing==0 ) { + prntSS(" pr__REFERENCE 2 :", "m28.getText()"); + } + } + else if ((LA(1)==ID)) { + pr__SIMPLE_CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__REFERENCE 1 :", "m26.getText()"); + } + } + else { + boolean synPredMatched20 = false; + if (((LA(1)==PACKAGE_SPECIFIER))) { + int _m20 = mark(); + synPredMatched20 = true; + inputState.guessing++; + try { + { + pr__P_S_AND_S_C_T(); + pr__CLASS_TYPE_SIGNATURE_SUFFIXES(); + } + } + catch (RecognitionException pe) { + synPredMatched20 = false; + } + rewind(_m20); + inputState.guessing--; + } + if ( synPredMatched20 ) { + pr__P_S_AND_S_C_T(); + if ( inputState.guessing==0 ) { + prntSS(" ### 11:", "m29.getText()"); + } + pr__CLASS_TYPE_SIGNATURE_SUFFIXES(); + if ( inputState.guessing==0 ) { + prntSS(" pr__REFERENCE 3 :", "m30.getText()"); + } + } + else if ((LA(1)==PACKAGE_SPECIFIER)) { + pr__P_S_AND_S_C_T(); + if ( inputState.guessing==0 ) { + prntSS(" pr__REFERENCE 4 :", "m31.getText()"); + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_8); + } else { + throw ex; + } + } + } + + public final void pr__SIMPLE_CLASS_TYPE_SIGNATURE() throws RecognitionException, TokenStreamException { + + Token m34 = null; + Token m35 = null; + Token m37 = null; + Token m371 = null; + + try { // for error handling + boolean synPredMatched24 = false; + if (((LA(1)==ID))) { + int _m24 = mark(); + synPredMatched24 = true; + inputState.guessing++; + try { + { + match(ID); + match(TRIANGLEOPEN_SIGN); + } + } + catch (RecognitionException pe) { + synPredMatched24 = false; + } + rewind(_m24); + inputState.guessing--; + } + if ( synPredMatched24 ) { + m34 = LT(1); + match(ID); + if ( inputState.guessing==0 ) { + + prntS(" ===13==="); + String ts1 = m34.getText(); + int tl = ts1.length(); + if (currentStackElem.rawType == null){ // so it's the non-inner class id + prntS(" ===131==="); + // create the owner: + currentStackElem.owner = null; // owner is absent for package level class + + // grow the gatheredStr: + if(currentStackElem.gatheredStr == null){ // so, we should check the existence of "L" at the begin of ID because it is the begin of the reference + // (for remembering: any "T..." identifier can not be considered as TVAR within + // this being parsered pr__SIMPLE_CLASS_TYPE_SIGNATURE rule, especially, if we are + // within generic parameters declaration parsering, where a TVAR using is prohibited) + if(ts1.charAt(0) != 'L'){ + throwGenericSignatureFormatError(); + } + addToGatheredStr(currentStackElem, ts1); // so, it's "L"<class ID> here + } else { //so, it is the reference like <package name>/<non-inner class name> (because rawType == null && gatheredStr == null) + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> here + } + + // grow the signature (like the gatheredStr growing): + if(currentStackElem.sigBegin == -1){ + currentStackElem.sigBegin = addToSignature(ts1); // so, it's "L"<class ID> added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + tl; + } else { + currentStackElem.sigEnd = addToSignature(ts1) + tl; // so, it's <class ID> added to CTPTsignature, + // consequently the "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> is there regarding the current parsered reference + } + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + + // we know "<...>" follows further, so the type becames InterimParameterizedType now: + currentStackElem.typeKind = 1; + } else { // so it's the regular inner class id + prntS(" ===132==="); + // create the owner: + if(currentStackElem.typeKind == 0 && currentStackElem.args == null){ + prntS(" ===1321==="); + //if (currentStackElem.owner != null) { + // // so, we have created InterimClassType some times for the previous parts (IDs) + // // and we should provide that each InterimClassType object should be deleted by GC when the next one is being created + // // because the only last preceding may to be used as owner of the first InterimParameterizedType object which arises + // // while a reference is parsered. + // // So, can/should we do anything special (I don't see such features within JNI) to destroy the previouse InterimClassType + // // object which becames superflouos + // // just when the next one appeares? Or GC will remove such objects because there will not be any references for them + // // within the java code. + // ???<<< (*env)->ReleaseObject(..., currentStackElem.owner, ...); >>>??? + //} + currentStackElem.owner = createInterimClassType(/*currentStackElem.rawType*/currentStackElem.gatheredStr); + } else { + //printf(" %s %d %d %d\n", "===1322===", currentStackElem.typeKind, currentStackElem.args); + currentStackElem.typeKind = 1; // at least one args was not equal to null at a previous stage, so we deal with the parameterized type from that time + len = sigInd - currentStackElem.sigBegin/* + 1*/; + currentStackElem.owner = createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin+len), currentStackElem); + currentStackElem.args = null; + } + + // grow the gatheredStr: + addToGatheredStr(currentStackElem, "$"); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" here + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> here + + // grow the signature (like the gatheredStr growing): + currentStackElem.sigEnd = addToSignature("$") + 1; // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" gathered in CTPTsignature + currentStackElem.sigEnd = addToSignature(ts1) + tl; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> gathered in CTPTsignature + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + + // we know "<...>" follows further, so the type becames InterimParameterizedType now: + currentStackElem.typeKind = 1; + } + prntSS(" ### 13:", ts1); + + } + m35 = LT(1); + match(TRIANGLEOPEN_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===14==="); + // grow the signature: + currentStackElem.sigEnd = addToSignature("<") + 1; + + // It's the time to clean the arguments list of including class: + if (currentStackElem.args != null) { + currentStackElem.args = null; + } + + currentStackElemCopy = currentStackElem; + currentStackElem = new PTStack(); + currentStackElemCopy.nextLevel = currentStackElem; + lexer.stackDepth++; //to reflect a level of argument nesting + currentStackElem.gatheredStr = null; + currentStackElem.gthrdStrLen = 0; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; + currentStackElem.owner = null; + currentStackElem.args = null; + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; + + prntSS(" ### 14:", m35.getText()); + + } + pr__TYPE_ARGUMENTS(); + if ( inputState.guessing==0 ) { + prntSS(" ### 15:", "m36.getText()"); + } + m37 = LT(1); + match(TRIANGLECLOSE_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===15==="); + // grow the signature: + currentStackElem.sigEnd = addToSignature(">") + 1; + + // find the previous element for the current stack's element: + p1 = stack; + while (p1 != currentStackElem){ + p2 = p1; + p1 = p1.nextLevel; + } + p2.nextLevel = null; + lexer.stackDepth--; // to reflect a level of argument nesting + + // return to previous stack element: + currentStackElem = p2; + p2 = null; + + // in any case, the being finished reference is of InterimParametrizedType because it has "<...>" + currentStackElem.typeKind = 1; + + // free memory of the being left stack's element: + p1.gatheredStr = null; + p1 = null; + + prntSS(" pr__SIMPLE_CLASS_TYPE_SIGNATURE 1 :", m37.getText()); + + } + } + else if ((LA(1)==ID)) { + m371 = LT(1); + match(ID); + if ( inputState.guessing==0 ) { + + prntS(" ===16==="); + String ts1 = m371.getText(); + int tl = ts1.length(); + if (currentStackElem.rawType == null){ // so it's the non-inner class id + prntSS(" ===160===", ts1); + // create the owner: + currentStackElem.owner = null; // owner is absent for package level class + + // grow the gatheredStr: + if(currentStackElem.gatheredStr == null){ // so, we should check the existence of "L" at the begin of ID because it is the begin of the reference + // (for remembering: any "T..." identifier can not be considered as TVAR within + // this being parsered pr__SIMPLE_CLASS_TYPE_SIGNATURE rule, especially, if we are + // within generic parameters declaration parsering, where a TVAR using is prohibited) + if(ts1.charAt(0) != 'L'){ + throwGenericSignatureFormatError(); + } + addToGatheredStr(currentStackElem, ts1); // so, it's "L"<class ID> here + } else { + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> here + } + + // grow the signature (like the gatheredStr growing): + if(currentStackElem.sigBegin == -1){ + currentStackElem.sigBegin = addToSignature(ts1); // so, it's "L"<class ID> added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + tl; + } else { + currentStackElem.sigEnd = addToSignature(ts1) + tl; // so, it's <class ID> added to CTPTsignature, + // consequently the "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> is there regarding the current parsered reference + } + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + } else { //so it's the regular inner class id + prntSS(" ===161===", ts1); + // create the owner: + if(currentStackElem.typeKind == 0 && currentStackElem.args == null){ + //if (currentStackElem.owner != null) { + // // so, we have created InterimClassType some times for the previous parts (IDs) + // // and we should provide that each InterimClassType object should be deleted by GC when the next one is being created + // // because the only last preceding may to be used as owner of the first InterimParameterizedType object which arises + // // while a reference is parsered. + // // So, can/should we do anything special (I don't see such features within JNI) to destroy the previouse InterimClassType + // // object which becames superflouos + // // just when the next one appeares? Or GC will remove such objects because there will not be any references for them + // // within the java code. + // ???<<< (*env)->ReleaseObject(..., currentStackElem.owner, ...); >>>??? + //} + currentStackElem.owner = createInterimClassType(/*currentStackElem.rawType*/currentStackElem.gatheredStr); + } else { + currentStackElem.typeKind = 1; // at least one args was not equal to null at a previous stage + //len = currentStackElem.sigEnd - currentStackElem.sigBegin + 1; + len = sigInd - currentStackElem.sigBegin/* + 1*/; + currentStackElem.owner = createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + } + + // grow the gatheredStr: + addToGatheredStr(currentStackElem, "$"); //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" here + addToGatheredStr(currentStackElem, ts1); //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> here + + // grow the signature (like the gatheredStr growing): + currentStackElem.sigEnd = addToSignature("$") + 1; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" gathered in CTPTsignature + currentStackElem.sigEnd = addToSignature(ts1) + tl; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> gathered in CTPTsignature + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + } + prntSS(" pr__SIMPLE_CLASS_TYPE_SIGNATURE 2:", ts1); + + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_9); + } else { + throw ex; + } + } + } + + public final void pr__CLASS_TYPE_SIGNATURE_SUFFIXES() throws RecognitionException, TokenStreamException { + + Token m44 = null; + + try { // for error handling + { + int _cnt32=0; + _loop32: + do { + if ((LA(1)==DOT_OR_DOLLAR_SIGN)) { + m44 = LT(1); + match(DOT_OR_DOLLAR_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===21==="); + //// seems, I have just done it in pr__SIMPLE_CLASS_TYPE_SIGNATURE + //// grow the signature: + //currentStackElem.sigEnd = addToSignature("$") + 1; + + prntSS(" ### 20:", m44.getText()); + + } + pr__SIMPLE_CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__CLASS_TYPE_SIGNATURE_SUFFIXES 2 :", "m45.getText()"); + } + } + else { + if ( _cnt32>=1 ) { break _loop32; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt32++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_8); + } else { + throw ex; + } + } + } + + public final void pr__P_S_AND_S_C_T() throws RecognitionException, TokenStreamException { + + Token m32 = null; + + try { // for error handling + m32 = LT(1); + match(PACKAGE_SPECIFIER); + if ( inputState.guessing==0 ) { + + prntS(" ===12==="); + + // to start of gathering all info within gatheredStr about the being parsered reference: + addToGatheredStr(currentStackElem, m32.getText()); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/" here + + // to start of gathering all info within CTPTsignature about the being parsered reference: + currentStackElem.sigBegin = addToSignature(m32.getText()); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/" added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + m32.getText().length(); + + prntSS(">->->->-> ", currentStackElem.gatheredStr); + prntSS(" ### 12:", m32.getText()); + + } + pr__SIMPLE_CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__P_S_AND_S_C_T:", "m33.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_9); + } else { + throw ex; + } + } + } + + public final void pr__TYPE_ARGUMENTS() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + int _cnt27=0; + _loop27: + do { + if ((_tokenSet_10.member(LA(1)))) { + pr__TYPE_ARGUMENT(); + if ( inputState.guessing==0 ) { + prntSS(" pr__TYPE_ARGUMENTS 1 :", "m38.getText()"); + } + } + else { + if ( _cnt27>=1 ) { break _loop27; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt27++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_4); + } else { + throw ex; + } + } + } + + public final void pr__TYPE_ARGUMENT() throws RecognitionException, TokenStreamException { + + Token m39 = null; + + try { // for error handling + switch ( LA(1)) { + case STAR_SIGN: + { + m39 = LT(1); + match(STAR_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===17==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("*") + 1; + + // so, it's "unrestricted" wildcard. + // add the wildcard to the args list of the stack's element of the previous layer: + upper = createInterimClassType("Ljava/lang/Object"); + addElemToTypeArgsList(createInterimWildcardType(0 /* i.e. extends Object */, new InterimType[]{(InterimType)upper}, 1)); + + prntSS(" pr__TYPE_ARGUMENT 1 :", m39.getText()); + + } + break; + } + case ID: + case TVAR: + case PACKAGE_SPECIFIER: + case SQUAREOPEN_SIGN: + { + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__TYPE_ARGUMENT 2 :", "m40.getText()"); + } + break; + } + case PLUS_SIGN: + case MINUS_SIGN: + { + pr__WILDCARD_INDICATOR(); + if ( inputState.guessing==0 ) { + prntSS(" ### 17:", "m41.getText()"); + } + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__TYPE_ARGUMENT 3 :", "m42.getText()"); + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_11); + } else { + throw ex; + } + } + } + + public final void pr__WILDCARD_INDICATOR() throws RecognitionException, TokenStreamException { + + Token m43 = null; + + try { // for error handling + switch ( LA(1)) { + case PLUS_SIGN: + { + match(PLUS_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===18==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("+") + 1; + + // so, it's "restricted" wildcard : + currentStackElem.wrappInWildcard = 0; // upper + + prntS(" pr__WILDCARD_INDICATOR 1 "); + + } + break; + } + case MINUS_SIGN: + { + m43 = LT(1); + match(MINUS_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===19==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("-") + 1; + + // so, it's "restricted" wildcard: + currentStackElem.wrappInWildcard = 1; // lower + + prntSS(" pr__WILDCARD_INDICATOR 2 :", m43.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_0); + } else { + throw ex; + } + } + } + + public final void pr__TYPE_SIGNATURE() throws RecognitionException, TokenStreamException { + + Token m49 = null; + + try { // for error handling + switch ( LA(1)) { + case ID: + case TVAR: + case PACKAGE_SPECIFIER: + case SQUAREOPEN_SIGN: + { + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__TYPE_SIGNATURE 1 :", "m48.getText()"); + } + break; + } + case TBASE: + { + m49 = LT(1); + match(TBASE); + if ( inputState.guessing==0 ) { + + prsrT = createInterimClassType(getBaseTypeName(m49.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + + prntSS(" pr__TYPE_SIGNATURE 2 :", m49.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_2); + } else { + throw ex; + } + } + } + + public final void pr__SUPERINTERFACE_SIGNATURE() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===22==="); + addElemToImplList((InterimType)highLevelType); // add the gathered regular type to implements-list + + highLevelType = null; + + prntSS(" pr__SUPERINTERFACE_SIGNATURE:", "m51.getText()"); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_12); + } else { + throw ex; + } + } + } + + public final void pr__C_P_AND_R_T() throws RecognitionException, TokenStreamException { + + Token m557 = null; + + try { // for error handling + pr__METHOD_PARAMETERS(); + if ( inputState.guessing==0 ) { + prntSS(" ### 241:", "m556.getText()"); + } + m557 = LT(1); + match(VOIDTYPE); + if ( inputState.guessing==0 ) { + + prntSS(" pr__C_P_AND_R_T :", "m557.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + public final void pr__THROWN_SIGNATURE() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__THROWNS(); + if ( inputState.guessing==0 ) { + + prntS(" ===32==="); + // set throwns field of InterimMethodGenericDecl/InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).throwns = (InterimType[])thrownList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).throwns = thrownList.toArray(new InterimType[thrownList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).throwns = thrownList.toArray(new InterimType[thrownList.size()]); + } + + // clean the thrownList: + thrownList = null; + + prntSS(" pr__THROWN_SIGNATURE:", "m82.getText()"); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__F_T_P_AND_C_P_AND_R_T() throws RecognitionException, TokenStreamException { + + Token m559 = null; + + try { // for error handling + pr__F_T_P_AND_M_P(); + if ( inputState.guessing==0 ) { + prntSS(" ### 29:", "m558.getText()"); + } + m559 = LT(1); + match(VOIDTYPE); + if ( inputState.guessing==0 ) { + + prntSS(" pr__F_T_P_AND_C_P_AND_R_T :", "m559.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + public final void pr__METHOD_PARAMETERS() throws RecognitionException, TokenStreamException { + + Token m76 = null; + Token m77 = null; + Token m73 = null; + Token m75 = null; + + try { // for error handling + boolean synPredMatched57 = false; + if (((LA(1)==RINGOPEN_SIGN))) { + int _m57 = mark(); + synPredMatched57 = true; + inputState.guessing++; + try { + { + match(RINGOPEN_SIGN); + match(RINGCLOSE_SIGN); + } + } + catch (RecognitionException pe) { + synPredMatched57 = false; + } + rewind(_m57); + inputState.guessing--; + } + if ( synPredMatched57 ) { + m76 = LT(1); + match(RINGOPEN_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===29==="); + // create InterimMethodGenericDecl or InterimConstructorGenericDecl: + if (declType == METHODoDECL) { + methodDecl = new InterimMethodGenericDecl(); + } else { + constructorDecl = new InterimConstructorGenericDecl(); + } + + prntSS(" ### 32:", m76.getText()); + + } + m77 = LT(1); + match(RINGCLOSE_SIGN); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_PARAMETERS 2 :", m77.getText()); + } + } + else if ((LA(1)==RINGOPEN_SIGN)) { + m73 = LT(1); + match(RINGOPEN_SIGN); + if ( inputState.guessing==0 ) { + + prntS(" ===27==="); + // create InterimMethodGenericDecl or InterimConstructorGenericDecl: + if (declType == METHODoDECL) { + methodDecl = new InterimMethodGenericDecl(); + } else { + constructorDecl = new InterimConstructorGenericDecl(); + } + + prntSS(" ### 30:", m73.getText()); + + } + pr__PARAMETERS_LIST(); + if ( inputState.guessing==0 ) { + + prntS(" ===28==="); + // set methodParameters field of InterimMethodGenericDecl/InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).methodParameters = (InterimType[])methParamList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).methodParameters = methParamList.toArray(new InterimType[methParamList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).methodParameters = methParamList.toArray(new InterimType[methParamList.size()]); + } + + // clean the methParamList: + methParamList = null; + + prntSS(" ### 31:", "m74.getText()"); + + } + m75 = LT(1); + match(RINGCLOSE_SIGN); + if ( inputState.guessing==0 ) { + prntSS(" pr__METHOD_PARAMETERS 1 :", m75.getText()); + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_14); + } else { + throw ex; + } + } + } + + public final void pr__F_T_P_AND_M_P() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__FORMAL_TYPE_PARAMETERS_DECL(); + if ( inputState.guessing==0 ) { + prntSS(" ### 28:", "m66.getText()"); + } + pr__METHOD_PARAMETERS(); + if ( inputState.guessing==0 ) { + + prntS(" ===23==="); + // set typeParameters field of InterimMethodGenericDecl or InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).typeParameters = (InterimTypeParameter[])genParamList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + } + + // clean the genParamList: + genParamList = null; + + prntSS(" pr__F_T_P_AND_M_P :", "m67.getText()"); + + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_14); + } else { + throw ex; + } + } + } + + public final void pr__M_P_AND_R_T() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__METHOD_PARAMETERS(); + if ( inputState.guessing==0 ) { + prntSS(" ### 27:", "m64.getText()"); + } + pr__RETURN_TYPE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__M_P_AND_R_T :", "m65.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + public final void pr__F_T_P_AND_M_P_AND_R_T() throws RecognitionException, TokenStreamException { + + + try { // for error handling + pr__F_T_P_AND_M_P(); + if ( inputState.guessing==0 ) { + prntSS(" ### 29:", "m68.getText()"); + } + pr__RETURN_TYPE(); + if ( inputState.guessing==0 ) { + prntSS(" pr__F_T_P_AND_M_P_AND_R_T :", "m69.getText()"); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + public final void pr__RETURN_TYPE() throws RecognitionException, TokenStreamException { + + Token m70 = null; + Token m72 = null; + + try { // for error handling + switch ( LA(1)) { + case VOIDTYPE: + { + m70 = LT(1); + match(VOIDTYPE); + if ( inputState.guessing==0 ) { + + prntS(" ===24==="); + if (declType == METHODoDECL) { + // put void return type into the method decl: + methodDecl.returnValue = (InterimType)createInterimClassType("void"); + } + + prntSS(" pr__RETURN_TYPE 1 :", m70.getText()); + + } + break; + } + case ID: + case TVAR: + case PACKAGE_SPECIFIER: + case SQUAREOPEN_SIGN: + case TBASE: + { + pr__TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===25==="); + // put return type into the method decl: + methodDecl.returnValue = (InterimType)highLevelType; + + highLevelType = null; + + prntSS(" pr__RETURN_TYPE 2 :", "m71.getText()"); + + } + break; + } + case RETURN_BASE_TYPE: + { + m72 = LT(1); + match(RETURN_BASE_TYPE); + if ( inputState.guessing==0 ) { + + prntS(" ===26==="); + prsrT = createInterimClassType(getBaseTypeName(m72.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put base return type into the method decl: + methodDecl.returnValue = prsrT; + + prntSS(" pr__RETURN_TYPE 3 :", m72.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + public final void pr__PARAMETERS_LIST() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + int _cnt60=0; + _loop60: + do { + if ((_tokenSet_15.member(LA(1)))) { + pr__PARAMETER(); + if ( inputState.guessing==0 ) { + prntSS(" pr__PARAMETERS_LIST 2 :", "m78.getText()"); + } + } + else { + if ( _cnt60>=1 ) { break _loop60; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt60++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_16); + } else { + throw ex; + } + } + } + + public final void pr__PARAMETER() throws RecognitionException, TokenStreamException { + + Token m80 = null; + + try { // for error handling + switch ( LA(1)) { + case ID: + case TVAR: + case PACKAGE_SPECIFIER: + case SQUAREOPEN_SIGN: + { + pr__FIELD_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===30==="); + // put base type into the method params list: + addElemToMethParamList(highLevelType); + + highLevelType = null; + + prntSS(" pr__PARAMETER 1 :", "m79.getText()"); + + } + break; + } + case TBASE: + { + m80 = LT(1); + match(TBASE); + if ( inputState.guessing==0 ) { + + prntS(" ===31==="); + prsrT = createInterimClassType(getBaseTypeName(m80.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put base type into the method params list: + addElemToMethParamList(prsrT); + + prntSS(" pr__PARAMETER 2 :", m80.getText()); + + } + break; + } + default: + { + throw new NoViableAltException(LT(1), getFilename()); + } + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_17); + } else { + throw ex; + } + } + } + + public final void pr__THROWNS() throws RecognitionException, TokenStreamException { + + + try { // for error handling + { + int _cnt65=0; + _loop65: + do { + if ((LA(1)==CNTRL_SIGN)) { + pr__THROWN(); + if ( inputState.guessing==0 ) { + prntSS(" pr__THROWNS 2 :", "m83.getText()"); + } + } + else { + if ( _cnt65>=1 ) { break _loop65; } else {throw new NoViableAltException(LT(1), getFilename());} + } + + _cnt65++; + } while (true); + } + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_1); + } else { + throw ex; + } + } + } + + public final void pr__THROWN() throws RecognitionException, TokenStreamException { + + Token m84 = null; + Token m86 = null; + Token m87 = null; + + try { // for error handling + boolean synPredMatched68 = false; + if (((LA(1)==CNTRL_SIGN))) { + int _m68 = mark(); + synPredMatched68 = true; + inputState.guessing++; + try { + { + match(CNTRL_SIGN); + pr__CLASS_TYPE_SIGNATURE(); + } + } + catch (RecognitionException pe) { + synPredMatched68 = false; + } + rewind(_m68); + inputState.guessing--; + } + if ( synPredMatched68 ) { + m84 = LT(1); + match(CNTRL_SIGN); + if ( inputState.guessing==0 ) { + + Yflag2 = 1; // so, we are within throws part + + prntSS(" ### 35:", m84.getText()); + + } + pr__CLASS_TYPE_SIGNATURE(); + if ( inputState.guessing==0 ) { + + prntS(" ===33==="); + // put the InterimClassType or InterimParameterizedType to the throwns list: + addElemToThrownList((InterimType)highLevelType); + + highLevelType = null; + + prntSS(" pr__THROWN 1 :", "m85.getText()"); + + } + } + else if ((LA(1)==CNTRL_SIGN)) { + m86 = LT(1); + match(CNTRL_SIGN); + if ( inputState.guessing==0 ) { + prntSS(" ### 36:", m86.getText()); + } + m87 = LT(1); + match(TVAR); + if ( inputState.guessing==0 ) { + + prntS(" ===34==="); + assert(currentStackElem.dim == 0); + + // put the InterimTypeVariable to the throwns list: + // to exclude first (official) "T" symbol (and last ";" symbol): + System.out.println(m87.getText()+"|"+m87.getText().length()); + addElemToThrownList((InterimType)createInterimTypeVariable(m87.getText().substring(1, m87.getText().length()-1))); + + prntSS(" pr__THROWN 2 :", m87.getText()); + + } + } + else { + throw new NoViableAltException(LT(1), getFilename()); + } + + } + catch (RecognitionException ex) { + if (inputState.guessing==0) { + reportError(ex); + recover(ex,_tokenSet_13); + } else { + throw ex; + } + } + } + + + public static final String[] _tokenNames = { + "<0>", + "EOF", + "<2>", + "NULL_TREE_LOOKAHEAD", + "TRIANGLEOPEN_SIGN", + "TRIANGLECLOSE_SIGN", + "ID_COLON", + "ID", + "COLON_SIGN", + "TVAR", + "SEMICOLON_SIGN", + "PACKAGE_SPECIFIER", + "STAR_SIGN", + "PLUS_SIGN", + "MINUS_SIGN", + "DOT_OR_DOLLAR_SIGN", + "SQUAREOPEN_SIGN", + "TBASE", + "VOIDTYPE", + "RETURN_BASE_TYPE", + "RINGOPEN_SIGN", + "RINGCLOSE_SIGN", + "CNTRL_SIGN" + }; + + private static final long[] mk_tokenSet_0() { + long[] data = { 68224L, 0L}; + return data; + } + public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0()); + private static final long[] mk_tokenSet_1() { + long[] data = { 2L, 0L}; + return data; + } + public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1()); + private static final long[] mk_tokenSet_2() { + long[] data = { 6519778L, 0L}; + return data; + } + public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2()); + private static final long[] mk_tokenSet_3() { + long[] data = { 1050752L, 0L}; + return data; + } + public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3()); + private static final long[] mk_tokenSet_4() { + long[] data = { 32L, 0L}; + return data; + } + public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4()); + private static final long[] mk_tokenSet_5() { + long[] data = { 224L, 0L}; + return data; + } + public static final BitSet _tokenSet_5 = new BitSet(mk_tokenSet_5()); + private static final long[] mk_tokenSet_6() { + long[] data = { 256L, 0L}; + return data; + } + public static final BitSet _tokenSet_6 = new BitSet(mk_tokenSet_6()); + private static final long[] mk_tokenSet_7() { + long[] data = { 480L, 0L}; + return data; + } + public static final BitSet _tokenSet_7 = new BitSet(mk_tokenSet_7()); + private static final long[] mk_tokenSet_8() { + long[] data = { 1024L, 0L}; + return data; + } + public static final BitSet _tokenSet_8 = new BitSet(mk_tokenSet_8()); + private static final long[] mk_tokenSet_9() { + long[] data = { 33792L, 0L}; + return data; + } + public static final BitSet _tokenSet_9 = new BitSet(mk_tokenSet_9()); + private static final long[] mk_tokenSet_10() { + long[] data = { 96896L, 0L}; + return data; + } + public static final BitSet _tokenSet_10 = new BitSet(mk_tokenSet_10()); + private static final long[] mk_tokenSet_11() { + long[] data = { 96928L, 0L}; + return data; + } + public static final BitSet _tokenSet_11 = new BitSet(mk_tokenSet_11()); + private static final long[] mk_tokenSet_12() { + long[] data = { 2178L, 0L}; + return data; + } + public static final BitSet _tokenSet_12 = new BitSet(mk_tokenSet_12()); + private static final long[] mk_tokenSet_13() { + long[] data = { 4194306L, 0L}; + return data; + } + public static final BitSet _tokenSet_13 = new BitSet(mk_tokenSet_13()); + private static final long[] mk_tokenSet_14() { + long[] data = { 985728L, 0L}; + return data; + } + public static final BitSet _tokenSet_14 = new BitSet(mk_tokenSet_14()); + private static final long[] mk_tokenSet_15() { + long[] data = { 199296L, 0L}; + return data; + } + public static final BitSet _tokenSet_15 = new BitSet(mk_tokenSet_15()); + private static final long[] mk_tokenSet_16() { + long[] data = { 2097152L, 0L}; + return data; + } + public static final BitSet _tokenSet_16 = new BitSet(mk_tokenSet_16()); + private static final long[] mk_tokenSet_17() { + long[] data = { 2296448L, 0L}; + return data; + } + public static final BitSet _tokenSet_17 = new BitSet(mk_tokenSet_17()); + + } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParserTokenTypes.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParserTokenTypes.java new file mode 100644 index 0000000..4c5cf27 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/SignatureParserTokenTypes.java @@ -0,0 +1,79 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// $ANTLR 2.7.5 (20050128): "signature.g" -> "SignatureParser.java"$ + +package org.apache.harmony.lang.reflect.parser; + +import java.util.ArrayList; +import java.io.StringBufferInputStream; +import java.io.IOException; +import java.lang.reflect.GenericSignatureFormatError; +import org.apache.harmony.lang.reflect.parser.*; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + * + * NOTE 1. This signature.g was created and debugged using + * -bash-3.00$ uname -a + * Linux nstdrlel8.ins.intel.com 2.6.9-11.ELsmp #1 SMP Fri May 20 18:25:30 EDT 2005 x86_64 x86_64 x86_64 GNU/Linux + * -bash-3.00$ which yacc + * /usr/bin/yacc + * -bash-3.00$ which lex + * /usr/bin/lex + * -bash-3.00$ lex --version + * lex version 2.5.4 + * + * then it was rewritten for ANTLR 2.7.5 + * + * + * To generate java code of signature syntax parser (consisting of SignatureParser.java and SignatureParserTokenTypes.java) + * you should + * - enter to ...\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser directory: + * cd C:\IJE\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser + * - set pointer to ANTLR: + * set CLASSPATH=C:\Documents and Settings\szapreye\My Documents\ANTLR\antlr-2.7.5.jar;. + * - start 1.5 java VM: + * java antlr.Tool signature.g + * + * It provides the creation of SignatureParser.java and SignatureParserTokenTypes.java which in joining with lexer (SignatureLexer2.java) + * arrange the generic signature attribute parser. + */ + +public interface SignatureParserTokenTypes { + int EOF = 1; + int NULL_TREE_LOOKAHEAD = 3; + int TRIANGLEOPEN_SIGN = 4; + int TRIANGLECLOSE_SIGN = 5; + int ID_COLON = 6; + int ID = 7; + int COLON_SIGN = 8; + int TVAR = 9; + int SEMICOLON_SIGN = 10; + int PACKAGE_SPECIFIER = 11; + int STAR_SIGN = 12; + int PLUS_SIGN = 13; + int MINUS_SIGN = 14; + int DOT_OR_DOLLAR_SIGN = 15; + int SQUAREOPEN_SIGN = 16; + int TBASE = 17; + int VOIDTYPE = 18; + int RETURN_BASE_TYPE = 19; + int RINGOPEN_SIGN = 20; + int RINGCLOSE_SIGN = 21; + int CNTRL_SIGN = 22; +} diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/signature.g vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/signature.g new file mode 100644 index 0000000..85a4fe8 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/parser/signature.g @@ -0,0 +1,1249 @@ +header { +package org.apache.harmony.lang.reflect.parser; + +import java.util.ArrayList; +import java.io.StringBufferInputStream; +import java.io.IOException; +import java.lang.reflect.GenericSignatureFormatError; +import org.apache.harmony.lang.reflect.parser.*; +} + +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.2 $ + * + * NOTE 1. This signature.g was created and debugged using + * -bash-3.00$ uname -a + * Linux nstdrlel8.ins.intel.com 2.6.9-11.ELsmp #1 SMP Fri May 20 18:25:30 EDT 2005 x86_64 x86_64 x86_64 GNU/Linux + * -bash-3.00$ which yacc + * /usr/bin/yacc + * -bash-3.00$ which lex + * /usr/bin/lex + * -bash-3.00$ lex --version + * lex version 2.5.4 + * + * then it was rewritten for ANTLR 2.7.5 + * + * + * To generate java code of signature syntax parser (consisting of SignatureParser.java and SignatureParserTokenTypes.java) + * you should + * - enter to ...\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser directory: + * cd C:\IJE\tiger-dev\vm\vmcore\src\kernel_classes\javasrc\org\apache\harmony\lang\reflect\parser + * - set pointer to ANTLR: + * set CLASSPATH=C:\Documents and Settings\szapreye\My Documents\ANTLR\antlr-2.7.5.jar;. + * - start 1.5 java VM: + * java antlr.Tool signature.g + * + * It provides the creation of SignatureParser.java and SignatureParserTokenTypes.java which in joining with lexer (SignatureLexer2.java) + * arrange the generic signature attribute parser. + * + */ + +class SignatureParser extends Parser; + +// SignatureParser class members: +{ +private SignatureLexer2 lexer; +private int declType; // prescribed (predefined in parser's args) type of the parsered declaration +private static final int CLASSoDECL = 1; //Parser.SignatureKind.CLASS_SIGNATURE.value(); +private static final int FIELDoDECL = 2; //Parser.SignatureKind.FIELD_SIGNATURE.value(); +private static final int METHODoDECL = 3; //Parser.SignatureKind.METHOD_SIGNATURE.value(); +private static final int CONSTRUCTORoDECL = 4; //Parser.SignatureKind.CONSTRUCTOR_SIGNATURE.value(); + +private ArrayList<InterimTypeParameter> genParamList = null; // to accumulate generic parameters +private ArrayList<InterimType> boundList = null; // to accumulate bounds of a generic parameter +private ArrayList<InterimType> methParamList = null; // to accumulate method's or constructor's parameters +private ArrayList<InterimType> thrownList = null; // to accumulate exceptions thrown by a method/constructor +private ArrayList<InterimType> implList = null; // to accumulate implements-clauses of a class decl + +private InterimClassGenericDecl classDecl = null; +private InterimFieldGenericDecl fieldDecl = null; +private InterimMethodGenericDecl methodDecl = null; +private InterimConstructorGenericDecl constructorDecl = null; + +private InterimTypeParameter currentTypeParameter = null; +private int Yflag1 = 0; // to mark the start of generic type parameters processing +private int Yflag2 = 0; // to mark the start of method's/constructor's throws-part processing +class PTStack { // stack of parsered nested parameterized types + String gatheredStr; // packageSpecifier / packageSpecifier + ID / packageSpecifier + ID {+ "$"ID} + int gthrdStrLen; // length of the allocated gatheredStr; + int wrappInWildcard; // -1 - not to wrapp; 1 - lower; 0 - upper + int typeKind; // previous level type kind: 1 - InterimParameterizedType; 0 - InterimClassType + InterimClassType rawType; // InterimClassType + InterimType owner; // InterimParameterizedType or InterimClassType + ArrayList<InterimType> args; // InterimParameterizedType or InterimClassType or InterimTypeVariable or InterimWildcardType + int sigBegin; // start of the signature of the current nested parameterized type within CTPTsignature + int sigEnd; // finish of the signature of the current nested parameterized type within CTPTsignature + int dim; // to indicate the number of consequent "[" symbols. ATTENTION: it used for all types: TVAR, TBASE, RETURN_BASE_TYPE, class type, parameterized type + PTStack nextLevel; +}; +private PTStack stack; +private PTStack currentStackElem; // points to the current processed level element of the nested parameterized types chain + +private String CTPTsignature; // accumulated signature of the current parsered parameterized type, it's used for parameterized types repository +private int sigInd; +private int sigLen; + +private InterimType/*InterimGenericType*/ highLevelType; // the rolled up reference (InterimParameterizedType or InterimClassType) + +private int i; +private InterimType prsrT; +private int len; +private PTStack p1, p2, currentStackElemCopy; +private InterimClassType upper; +private char t; +////////////////////////////////////////////////////////////////////////////////////////////////////// +private void throwGenericSignatureFormatError() throws GenericSignatureFormatError { + + prntS(" throwGenericSignatureFormatError"); + + clean(); + throw new GenericSignatureFormatError(); +} +private void clean() { + int i; + PTStack p1 = null; + PTStack p2 = null; + + prntS(" clean"); + + genParamList = null; + boundList = null; + methParamList = null; + thrownList = null; + for (i = 0; i <= lexer.stackDepth; i++) { + if (i == 0) { + p1 = stack; + } else { + p1 = p1.nextLevel; + } + p1.args = null; + } + for (i = 0; i <= lexer.stackDepth; i++) { + if (i == 0) { + p1 = stack; + } + p2 = p1.nextLevel; + p1.nextLevel = null; + p1 = p2; + } + stack = null; + // XXX: How can we clear the memory allocated for currentStackElem.rawType and currentStackElem.owner? + // Will it be done by VM's gc somehow later or should we invoke some JNI's method + // or should we just invoke System.gc through JNI? + CTPTsignature = null; +} +private void addElemToGenParamList(InterimTypeParameter ref) { //XXX: maybe, use genParamList.add(ref) everywhere instead of addElemToGenParamList(ref), remove addElemToGenParamList at all + prntS(" addElemToGenParamList"); + + if(genParamList == null) { + genParamList = new ArrayList<InterimTypeParameter>(); + } + genParamList.add(ref); +} +private void addElemToBoundList(InterimType ref) { + prntS(" addElemToBoundList"); + + if(boundList == null) { + boundList = new ArrayList<InterimType>(); + } + boundList.add(ref); +} +private void addElemToMethParamList(Object ref) { + prntSO(" addElemToMethParamList", ref); + + if(methParamList == null) { + methParamList = new ArrayList<InterimType>(); + } + methParamList.add((InterimType)ref); +} +private void addElemToTypeArgsList(InterimType ref) { + prntS(" addElemToTypeArgsList"); + + // find the previous element for the current stack's element: + PTStack p1 = stack, p2 = null; + + while (p1 != currentStackElem){ + p2 = p1; + p1 = p1.nextLevel; + } + + // add the value to the args list of the found stack's element: + if(p2.args == null) { + p2.args = new ArrayList(); + } + p2.args.add(ref); + + // clean the current stack's element to be ready for new reference parsering: + currentStackElem.gatheredStr = null; + currentStackElem.args = null; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; // value should not be myfreed because a pointer to the later used java object was there + currentStackElem.owner = null; // value should not be myfreed because a pointer to the later used java object was there + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; +} +private void addElemToThrownList(InterimType ref) { + prntS(" addElemToThrownList"); + + if(thrownList == null) { + thrownList = new ArrayList<InterimType>(); + } + thrownList.add(ref); +} +private void addElemToImplList(InterimType ref) { + prntS(" addElemToImplList"); + + if(implList == null) { + implList = new ArrayList<InterimType>(); + } + implList.add(ref); +} +private void addToGatheredStr(PTStack stackElem, String part) { + if(stackElem.gatheredStr != null) { + prntSSS(" addToGatheredStr", stackElem.gatheredStr, part); + } else { + prntSS(" addToGatheredStr", part); + } + + if(stackElem.gatheredStr == null) { + stackElem.gatheredStr = ""; + } + stackElem.gatheredStr = stackElem.gatheredStr + part; + prntSS(">->->->-> ", stackElem.gatheredStr); +} +private int addToSignature(String part) { + int res = sigInd; + + prntS(" start addToSignature"); + if(CTPTsignature == null) { + CTPTsignature = ""; + } + res = CTPTsignature.length(); + CTPTsignature = CTPTsignature + part; + sigInd += part.length(); + + prntS(" end addToSignature"); + return res; +} +private void createTypeParameterName(String name) { + prntS(" createTypeParameterName"); + + currentTypeParameter = new InterimTypeParameter(); + currentTypeParameter.typeParameterName = name; +} +private InterimClassType createInterimClassType(String reference) { + InterimClassType res; + + prntS(" createInterimClassType"); + + res = new InterimClassType(); + res.classTypeName = reference; + return res; +} +private InterimTypeVariable createInterimTypeVariable(String tVariableName) { + prntSS(" createInterimTypeVariable", tVariableName); + + InterimTypeVariable obj; + + obj = new InterimTypeVariable(); + obj.typeVariableName = tVariableName; + return obj; +} +private InterimParameterizedType createInterimParameterizedType(String signature, PTStack stackElem) { + InterimParameterizedType obj; + + prntS(" createInterimParameterizedType"); + + obj = new InterimParameterizedType(); + obj.signature = signature; + obj.rawType = stackElem.rawType; + obj.ownerType = stackElem.owner; + if (stackElem.args != null) { + obj.parameters = stackElem.args.toArray(new InterimType[stackElem.args.size()]); + } else { + obj.parameters = new InterimType[0]; + } + + return obj; +} +private InterimWildcardType createInterimWildcardType(int boundsType, InterimType[] bounds, int boundsInd) { + InterimWildcardType obj; + + prntS(" createInterimWildcardType"); + + obj = new InterimWildcardType(); + obj.boundsType = boundsType == 0; + obj.bounds = bounds; + + return obj; +} +private InterimGenericArrayType createInterimGenericArrayType(InterimType nextL) { + InterimGenericArrayType obj; + + prntS(" createInterimGenericArrayType"); + + obj = new InterimGenericArrayType(); + obj.nextLayer = /*(InterimGenericType)*/nextL; + + return obj; +} +private String getBaseTypeName(char c) { + switch (c) + { + case 'I': + return "int"; + case 'F': + return "float"; + case 'D': + return "double"; + case 'J': + return "long"; + case 'S': + return "short"; + case 'Z': + return "boolean"; + case 'B': + return "byte"; + case 'C': + return "char"; + } + throwGenericSignatureFormatError(); + return "UNKNOWN"; +} +private void prntS(String str) { + if (lexer.DEBUGGING){ + System.out.println("|"+str+"|"); + } +} +void prntSS(String str1, String str2) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+str2+"|"); + } +} +void prntSSS(String str1, String str2, String str3) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+str2+"|"+str3+"|"); + } +} +void prntSD(String str1, long num) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+num+"|"); + } +} +void prntSO(String str1, Object o) { + if (lexer.DEBUGGING){ + System.out.println("|"+str1+"|"+o+"|"); + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////// +public static InterimGenericDeclaration parseSignature(String st, int kind) { + InterimGenericDeclaration res = null; + SignatureLexer2 lexer = new SignatureLexer2(st); //?StringReader + SignatureParser parser = new SignatureParser(lexer); + // Parse the input + try { + parser.pr__DECL(kind, lexer); + } + catch(RecognitionException e) { + e.printStackTrace(); + System.err.println("signature syntax error: "+e); + parser.throwGenericSignatureFormatError(); // signature syntax error! + } + catch(antlr.TokenStreamException e) { + e.printStackTrace(); + System.err.println("TokenStreamException: "+e); + parser.throwGenericSignatureFormatError(); + } + parser.prntS("zzzzzzzzzzzzzzzzzz3"); + + switch (kind) + { + case CLASSoDECL: + res = (InterimGenericDeclaration)parser.classDecl; + break; + case FIELDoDECL: + res = (InterimGenericDeclaration)parser.fieldDecl; + break; + case METHODoDECL: + res = (InterimGenericDeclaration)parser.methodDecl; + break; + case CONSTRUCTORoDECL: + res = (InterimGenericDeclaration)parser.constructorDecl; + break; + } + parser.clean(); + parser.prntSO("zzzzzzzzzzzzzzzzzz4", res); + + return res; +} +} + + +pr__DECL +[int kind, Object lex] +{ + lexer = (SignatureLexer2)lex; + //lexer.DEBUGGING = true; + declType = kind; + stack = new PTStack(); + stack.gatheredStr = null; + stack.gthrdStrLen = 0; + stack.typeKind = 0; + stack.wrappInWildcard = -1; + stack.rawType = null; + stack.owner = null; + stack.args = null; + stack.sigBegin = -1; + stack.sigEnd = -1; + stack.dim = 0; + stack.nextLevel = null; + + // to be reenterable: + CTPTsignature = null; + sigInd = 0; + sigLen = 0; + currentStackElem = stack; + genParamList = null; + boundList = null; + methParamList = null; + thrownList = null; + implList = null; + Yflag2 = 0; + currentTypeParameter = null; + + // Clean lex's environment to provide reenterability: + lexer.prevLexeme = -1; + lexer.Lflag2 = 0; + lexer.Lflag3 = 0; + lexer.stackDepth = 0; + lexer.ident = null; +} + : {declType==CLASSoDECL}? m1:pr__CLASS_DECL {prntSS(" pr__DECL 1 :", "m1.getText()");} + | {declType==FIELDoDECL}? m2:pr__FIELD_DECL { + // it's time to create InterimFieldGenericDecl and to fill fieldDecl + fieldDecl = new InterimFieldGenericDecl(); + + // set fieldType field of InterimFieldGenericDecl object: + fieldDecl.fieldType = (InterimGenericType)highLevelType; + + highLevelType = null; + + prntSS(" pr__DECL 2 :", "m2.getText()"); + } + | {declType==METHODoDECL}? m3:pr__METHOD_DECL {prntSS(" pr__DECL 3:", "m3.getText()");} + | {declType==CONSTRUCTORoDECL}? m4:pr__CONSTRUCTOR_DECL {prntSS(" pr__DECL 4 :", "m4.getText()");} + ; +pr__FIELD_DECL: m5:pr__FIELD_TYPE_SIGNATURE {prntSS(" pr__FIELD_DECL:", "m5.getText()");} + ; +pr__CLASS_DECL: m6:pr__FORMAL_TYPE_PARAMETERS_DECL {prntSS(" ### 1:", "m6.getText()");} m7:pr__CLASS_TYPE_SIGNATURE { + prntS(" ===1==="); + // actually, it's pr__SUPERCLASSoSIGNATURE + + // it's time to create InterimClassGenericDecl and to fill classDecl + classDecl = new InterimClassGenericDecl(); + + // set superClass field of InterimClassGenericDecl object: + classDecl.superClass = (InterimType)highLevelType; + + highLevelType = null; + + // set typeParameters field of InterimClassGenericDecl object: + classDecl.typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + + // clean the genParamList: + genParamList = null; + + prntSS(" ### 2:", "m7.getText()"); + } m8:pr__SUPERINTERFACE_SIGNATURES { + prntS(" ===2==="); + // set superInterfaces field of InterimClassGenericDecl object: + classDecl.superInterfaces = (implList == null ? new InterimType[0] : implList.toArray(new InterimType[implList.size()])); + + // clean the implList: + implList = null; + + prntSS(" pr__CLASS_DECL 1 :", "m8.getText()"); + } + | m9:pr__CLASS_TYPE_SIGNATURE { + if (declType == CLASSoDECL) { + prntS(" ===3.1==="); + // actually, it's pr__SUPERCLASSoSIGNATURE + + // it's time to create InterimClassGenericDecl and to fill classDecl + classDecl = new InterimClassGenericDecl(); + + // set superClass field of InterimClassGenericDecl object: + classDecl.superClass = (InterimType)highLevelType; + + highLevelType = null; + } else { // it's FIELDoDECL + prntS(" ===3.2==="); + // actually, it's field type signature (instead the pr__FIELD_DECL which does not work really) + + // it's time to create InterimFieldGenericDecl and to fill fieldDecl + fieldDecl = new InterimFieldGenericDecl(); + + // set superClass field of InterimFieldGenericDecl object: + fieldDecl.fieldType = (InterimGenericType)highLevelType; + + highLevelType = null; + } + + prntSS(" ### 3:", "m9.getText()"); + } m10:pr__SUPERINTERFACE_SIGNATURES { + if (declType == CLASSoDECL) { + // set superInterfaces field of InterimClassGenericDecl object: + classDecl.superInterfaces = (implList == null ? new InterimType[0] : implList.toArray(new InterimType[implList.size()])); + + // clean the implList: + implList = null; + + prntSS(" pr__CLASS_DECL 2 :", "m10.getText()"); + } else { + prntSS(" pr__CLASS_DECL 2 (+++ for FIELDoDECL +++) :", "m10.getText()"); + } + } + ; +pr__FORMAL_TYPE_PARAMETERS_DECL: m11:TRIANGLEOPEN_SIGN { + prntS(" ===4==="); + Yflag1 = 1; // start of generic parameters parsing + prntSS(" ### 4:", m11.getText()); + } + m12:pr__FORMAL_TYPE_PARAMETERS {prntSS(" ### 5:", "m12.getText()");} m13:TRIANGLECLOSE_SIGN { + prntS(" ===5==="); + Yflag1 = 0; // finish of generic parameters parsing + prntSS(" pr__FORMAL_TYPE_PARAMETERS_DECL:", m13.getText()); + } + ; +pr__FORMAL_TYPE_PARAMETERS: ( m14:pr__FORMAL_TYPE_PARAMETER {prntSS(" pr__FORMAL_TYPE_PARAMETERS 1 :", "m14.getText()");} )+ + ; +pr__FORMAL_TYPE_PARAMETER: m141:pr__ID_WITH_COLON {prntSS(" ### 7:", /*lexer.ident*/"m141.getText()");} m15:pr__CLASS_OR_INTERFACE_BOUNDS { + prntS(" ===6==="); + // set classBound field of InterimTypeParameter object: + currentTypeParameter.classBound = (InterimType)boundList.get(0); // the first elem is extends-clause + boundList.remove(0); + + // set interfaceBounds field of InterimTypeParameter object: + currentTypeParameter.interfaceBounds = boundList.toArray(new InterimType[boundList.size()]); + + // clean the boundList before a possible re-using: + boundList = null; + + // add the prepared InterimTypeParameter object to genParamList: + addElemToGenParamList(currentTypeParameter); + + prntSS(" pr__FORMAL_TYPE_PARAMETER:", "m15.getText()"); + } + ; +pr__ID_WITH_COLON: m151:ID_COLON { + prntS(" ===7==="); + String ts1 = m151.getText(); + String ts2 = ts1.substring(0, ts1.length()-2); + + createTypeParameterName(ts2); + addElemToBoundList(createInterimClassType("Ljava/lang/Object")); // Object is supposed if extends clause is empty (example: PARAMNAME::...;) + + prntSS(" pr__ID_WITH_COLON 1 :", ts2); + } + | m16:ID { + prntS(" ===8==="); + createTypeParameterName(m16.getText()); + + prntSS(" pr__ID_WITH_COLON 2 :", m16.getText()); + } + ; +pr__CLASS_OR_INTERFACE_BOUNDS: ( m18:pr__BOUND {prntSS(" pr__CLASS_OR_INTERFACE_BOUNDS 1 :", "m18.getText()");} )+ + ; +pr__BOUND: m19:COLON_SIGN {prntSS(" ### 9:", m19.getText());} m20:pr__FIELD_TYPE_SIGNATURE { + prntS(" ===8.1==="); + addElemToBoundList((InterimType)highLevelType); // add the gathered regular type to bounds-list + + highLevelType = null; + + prntSS(" pr__BOUND:", "m20.getText()"); + } + ; +pr__FIELD_TYPE_SIGNATURE: m21:pr__CLASS_TYPE_SIGNATURE {prntSS(" pr__FIELD_TYPE_SIGNATURE 1 :", "m21.getText()");} + | m22:pr__ARRAY_TYPE_SIGNATURE { + prntS(" ===9==="); + if (Yflag1 == 1) { + throwGenericSignatureFormatError(); // array type is not permissible within a generic params decl + } + if (currentStackElem.wrappInWildcard != -1) { + throwGenericSignatureFormatError(); // array type is not permissible within a wild card + } + prntSS(" pr__FIELD_TYPE_SIGNATURE 2 :", "m22.getText()"); + } + | m23:TVAR { + prntS(" ===10==="); + // grow the signature if it needs: + if(CTPTsignature != null){ + currentStackElem.sigEnd = addToSignature(m23.getText()) + m23.getText().length(); + } + + // to exclude first (official) "T" symbol (and last ";" symbol): + prsrT = (InterimType)createInterimTypeVariable(m23.getText().substring(1, m23.getText().length()-1)); + + // if there is wildcard indicator then InterimTypeVariable should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + if (Yflag1 == 1) { // within generic params decl (class'/method's/constructor's) + if(lexer.stackDepth == 0){ // not within parameterized type + if(boundList == null){ + addElemToBoundList(prsrT); // first (i.e. "extends") bound, consequently, TVAR is permissible here + } else { + throwGenericSignatureFormatError(); // non-first (i.e. "implements") bound, consequently, TVAR is not permissible as such bound + } + } else { // within parameterized type which appears within gen params decl + // put the InterimTypeVariable on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } else { + // so, for other places of using ... + if(lexer.stackDepth == 0){ // not within parameterized type + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } else { // within parameterized type which appears not within gen params decl + // put the InterimTypeVariable on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } + prntSS(" pr__FIELD_TYPE_SIGNATURE 3 :", m23.getText()); + } /*SEMICOLON_SIGN {prntS(" ===10.2===");}*/ + ; +pr__CLASS_TYPE_SIGNATURE: m24:pr__REFERENCE {prntSS(" ### 10:", "m24.getText()");} m25:SEMICOLON_SIGN { + prntS(" ===11==="); + // XXX: seems, the entire code fragment below can be easily simplified + + // roll up the reference (InterimClassType or InterimParameterizedType) to put on the layer above or to return as a final result: + if (lexer.stackDepth == 0) { + prntS(" ===111==="); + if(currentStackElem.typeKind == 0) { // InterimClassType + // return the InterimClassType as a result of a reference rolling up: + prsrT = (InterimType)createInterimClassType(currentStackElem.gatheredStr); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } else { //InterimParameterizedType + if(Yflag2 == 1){ // within the throws + throwGenericSignatureFormatError(); // here InterimParameterizedType is prohibited. + } + + // return the InterimParameterizedType as a result of a reference rolling up: + addToSignature(";"); + currentStackElem.sigEnd += 1; + len = sigInd - currentStackElem.sigBegin - 1; //to eliminate everywhere the last semicolon sign + prsrT = (InterimType)createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + } + + // it's time to clean entire CTPTsignature for finally rolled up high level reference: + if (CTPTsignature != null) { + CTPTsignature = null; + sigInd = 0; + sigLen = 0; + } + + // clean the current stack's element to be ready for new reference parsering: + currentStackElem.gatheredStr = null; + currentStackElem.args = null; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; //value should not be mefreed because a pointer to the later used java object was there + currentStackElem.owner = null; //value should not be mefreed because a pointer to the later used java object was there + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; + } else { + prntS(" ===112==="); + if(currentStackElem.typeKind == 0) { // InterimClassType + addToSignature(";"); + currentStackElem.sigEnd += 1; + prsrT = createInterimClassType(currentStackElem.gatheredStr); + + // if there is wildcard indicator then InterimClassType should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put the InterimClassType/InterimWildcardType on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } else { // InterimParameterizedType + addToSignature(";"); + currentStackElem.sigEnd += 1; + len = sigInd - currentStackElem.sigBegin -1; //to eliminate everywhere the last semicolon sign + prsrT = (InterimType)createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + + // if there is wildcard indicator then InterimParameterizedType should be "rolled up" by InterimWildcardType + if (currentStackElem.wrappInWildcard != -1) { + prsrT = (InterimType)createInterimWildcardType(currentStackElem.wrappInWildcard, new InterimType[]{(InterimType)prsrT}, 1); + } + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + // put the InterimParameterizedType/InterimWildcardType on the layer above of the stack of parsered nested parameterized types: + addElemToTypeArgsList(prsrT); + } + } + + // It's time to clear currentStackElem.gatheredStr: + currentStackElem.gatheredStr = null; + // It's time also to clear currentStackElem.rawType: + currentStackElem.rawType = null; + + prntSS(" pr__CLASS_TYPE_SIGNATURE:", m25.getText()); + } + ; +pr__REFERENCE: (pr__SIMPLE_CLASS_TYPE_SIGNATURE pr__CLASS_TYPE_SIGNATURE_SUFFIXES)=> m27:pr__SIMPLE_CLASS_TYPE_SIGNATURE {prntSS(" ### 10:", "m27.getText()");} m28:pr__CLASS_TYPE_SIGNATURE_SUFFIXES {prntSS(" pr__REFERENCE 2 :", "m28.getText()");} + | m26:pr__SIMPLE_CLASS_TYPE_SIGNATURE {prntSS(" pr__REFERENCE 1 :", "m26.getText()");} + | (pr__P_S_AND_S_C_T pr__CLASS_TYPE_SIGNATURE_SUFFIXES)=> m29:pr__P_S_AND_S_C_T {prntSS(" ### 11:", "m29.getText()");} m30:pr__CLASS_TYPE_SIGNATURE_SUFFIXES {prntSS(" pr__REFERENCE 3 :", "m30.getText()");} + | m31:pr__P_S_AND_S_C_T {prntSS(" pr__REFERENCE 4 :", "m31.getText()");} + ; +pr__P_S_AND_S_C_T: m32:PACKAGE_SPECIFIER { + prntS(" ===12==="); + + // to start of gathering all info within gatheredStr about the being parsered reference: + addToGatheredStr(currentStackElem, m32.getText()); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/" here + + // to start of gathering all info within CTPTsignature about the being parsered reference: + currentStackElem.sigBegin = addToSignature(m32.getText()); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/" added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + m32.getText().length(); + + prntSS(">->->->-> ", currentStackElem.gatheredStr); + prntSS(" ### 12:", m32.getText()); + } + m33:pr__SIMPLE_CLASS_TYPE_SIGNATURE {prntSS(" pr__P_S_AND_S_C_T:", "m33.getText()");} + ; +pr__SIMPLE_CLASS_TYPE_SIGNATURE: (ID TRIANGLEOPEN_SIGN)=> m34:ID { + prntS(" ===13==="); + String ts1 = m34.getText(); + int tl = ts1.length(); + if (currentStackElem.rawType == null){ // so it's the non-inner class id + prntS(" ===131==="); + // create the owner: + currentStackElem.owner = null; // owner is absent for package level class + + // grow the gatheredStr: + if(currentStackElem.gatheredStr == null){ // so, we should check the existence of "L" at the begin of ID because it is the begin of the reference + // (for remembering: any "T..." identifier can not be considered as TVAR within + // this being parsered pr__SIMPLE_CLASS_TYPE_SIGNATURE rule, especially, if we are + // within generic parameters declaration parsering, where a TVAR using is prohibited) + if(ts1.charAt(0) != 'L'){ + throwGenericSignatureFormatError(); + } + addToGatheredStr(currentStackElem, ts1); // so, it's "L"<class ID> here + } else { //so, it is the reference like <package name>/<non-inner class name> (because rawType == null && gatheredStr == null) + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> here + } + + // grow the signature (like the gatheredStr growing): + if(currentStackElem.sigBegin == -1){ + currentStackElem.sigBegin = addToSignature(ts1); // so, it's "L"<class ID> added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + tl; + } else { + currentStackElem.sigEnd = addToSignature(ts1) + tl; // so, it's <class ID> added to CTPTsignature, + // consequently the "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> is there regarding the current parsered reference + } + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + + // we know "<...>" follows further, so the type becames InterimParameterizedType now: + currentStackElem.typeKind = 1; + } else { // so it's the regular inner class id + prntS(" ===132==="); + // create the owner: + if(currentStackElem.typeKind == 0 && currentStackElem.args == null){ + prntS(" ===1321==="); + //if (currentStackElem.owner != null) { + // // so, we have created InterimClassType some times for the previous parts (IDs) + // // and we should provide that each InterimClassType object should be deleted by GC when the next one is being created + // // because the only last preceding may to be used as owner of the first InterimParameterizedType object which arises + // // while a reference is parsered. + // // So, can/should we do anything special (I don't see such features within JNI) to destroy the previouse InterimClassType + // // object which becames superflouos + // // just when the next one appeares? Or GC will remove such objects because there will not be any references for them + // // within the java code. + // ???<<< (*env)->ReleaseObject(..., currentStackElem.owner, ...); >>>??? + //} + currentStackElem.owner = createInterimClassType(/*currentStackElem.rawType*/currentStackElem.gatheredStr); + } else { + //printf(" %s %d %d %d\n", "===1322===", currentStackElem.typeKind, currentStackElem.args); + currentStackElem.typeKind = 1; // at least one args was not equal to null at a previous stage, so we deal with the parameterized type from that time + len = sigInd - currentStackElem.sigBegin/* + 1*/; + currentStackElem.owner = createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin+len), currentStackElem); + currentStackElem.args = null; + } + + // grow the gatheredStr: + addToGatheredStr(currentStackElem, "$"); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" here + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> here + + // grow the signature (like the gatheredStr growing): + currentStackElem.sigEnd = addToSignature("$") + 1; // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" gathered in CTPTsignature + currentStackElem.sigEnd = addToSignature(ts1) + tl; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> gathered in CTPTsignature + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + + // we know "<...>" follows further, so the type becames InterimParameterizedType now: + currentStackElem.typeKind = 1; + } + prntSS(" ### 13:", ts1); + } m35:TRIANGLEOPEN_SIGN { + prntS(" ===14==="); + // grow the signature: + currentStackElem.sigEnd = addToSignature("<") + 1; + + // It's the time to clean the arguments list of including class: + if (currentStackElem.args != null) { + currentStackElem.args = null; + } + + currentStackElemCopy = currentStackElem; + currentStackElem = new PTStack(); + currentStackElemCopy.nextLevel = currentStackElem; + lexer.stackDepth++; //to reflect a level of argument nesting + currentStackElem.gatheredStr = null; + currentStackElem.gthrdStrLen = 0; + currentStackElem.wrappInWildcard = -1; + currentStackElem.typeKind = 0; + currentStackElem.rawType = null; + currentStackElem.owner = null; + currentStackElem.args = null; + currentStackElem.sigBegin = -1; + currentStackElem.sigEnd = -1; + currentStackElem.dim = 0; + currentStackElem.nextLevel = null; + + prntSS(" ### 14:", m35.getText()); + } m36:pr__TYPE_ARGUMENTS {prntSS(" ### 15:", "m36.getText()");} m37:TRIANGLECLOSE_SIGN { + prntS(" ===15==="); + // grow the signature: + currentStackElem.sigEnd = addToSignature(">") + 1; + + // find the previous element for the current stack's element: + p1 = stack; + while (p1 != currentStackElem){ + p2 = p1; + p1 = p1.nextLevel; + } + p2.nextLevel = null; + lexer.stackDepth--; // to reflect a level of argument nesting + + // return to previous stack element: + currentStackElem = p2; + p2 = null; + + // in any case, the being finished reference is of InterimParametrizedType because it has "<...>" + currentStackElem.typeKind = 1; + + // free memory of the being left stack's element: + p1.gatheredStr = null; + p1 = null; + + prntSS(" pr__SIMPLE_CLASS_TYPE_SIGNATURE 1 :", m37.getText()); + } + | m371:ID { + prntS(" ===16==="); + String ts1 = m371.getText(); + int tl = ts1.length(); + if (currentStackElem.rawType == null){ // so it's the non-inner class id + prntSS(" ===160===", ts1); + // create the owner: + currentStackElem.owner = null; // owner is absent for package level class + + // grow the gatheredStr: + if(currentStackElem.gatheredStr == null){ // so, we should check the existence of "L" at the begin of ID because it is the begin of the reference + // (for remembering: any "T..." identifier can not be considered as TVAR within + // this being parsered pr__SIMPLE_CLASS_TYPE_SIGNATURE rule, especially, if we are + // within generic parameters declaration parsering, where a TVAR using is prohibited) + if(ts1.charAt(0) != 'L'){ + throwGenericSignatureFormatError(); + } + addToGatheredStr(currentStackElem, ts1); // so, it's "L"<class ID> here + } else { + addToGatheredStr(currentStackElem, ts1); // so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> here + } + + // grow the signature (like the gatheredStr growing): + if(currentStackElem.sigBegin == -1){ + currentStackElem.sigBegin = addToSignature(ts1); // so, it's "L"<class ID> added to CTPTsignature + currentStackElem.sigEnd = currentStackElem.sigBegin + tl; + } else { + currentStackElem.sigEnd = addToSignature(ts1) + tl; // so, it's <class ID> added to CTPTsignature, + // consequently the "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID> is there regarding the current parsered reference + } + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + } else { //so it's the regular inner class id + prntSS(" ===161===", ts1); + // create the owner: + if(currentStackElem.typeKind == 0 && currentStackElem.args == null){ + //if (currentStackElem.owner != null) { + // // so, we have created InterimClassType some times for the previous parts (IDs) + // // and we should provide that each InterimClassType object should be deleted by GC when the next one is being created + // // because the only last preceding may to be used as owner of the first InterimParameterizedType object which arises + // // while a reference is parsered. + // // So, can/should we do anything special (I don't see such features within JNI) to destroy the previouse InterimClassType + // // object which becames superflouos + // // just when the next one appeares? Or GC will remove such objects because there will not be any references for them + // // within the java code. + // ???<<< (*env)->ReleaseObject(..., currentStackElem.owner, ...); >>>??? + //} + currentStackElem.owner = createInterimClassType(/*currentStackElem.rawType*/currentStackElem.gatheredStr); + } else { + currentStackElem.typeKind = 1; // at least one args was not equal to null at a previous stage + //len = currentStackElem.sigEnd - currentStackElem.sigBegin + 1; + len = sigInd - currentStackElem.sigBegin/* + 1*/; + currentStackElem.owner = createInterimParameterizedType(CTPTsignature.substring(currentStackElem.sigBegin, currentStackElem.sigBegin + len), currentStackElem); + currentStackElem.args = null; + } + + // grow the gatheredStr: + addToGatheredStr(currentStackElem, "$"); //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" here + addToGatheredStr(currentStackElem, ts1); //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> here + + // grow the signature (like the gatheredStr growing): + currentStackElem.sigEnd = addToSignature("$") + 1; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$" gathered in CTPTsignature + currentStackElem.sigEnd = addToSignature(ts1) + tl; //so, it's "L"[A-Za-z][A-Za-z0-9"/"]*"/"<class ID>{"$"<class ID>}"$"<class ID> gathered in CTPTsignature + + // create the raw type: + currentStackElem.rawType = createInterimClassType(currentStackElem.gatheredStr); + } + prntSS(" pr__SIMPLE_CLASS_TYPE_SIGNATURE 2:", ts1); + } + ; +pr__TYPE_ARGUMENTS: ( m38:pr__TYPE_ARGUMENT {prntSS(" pr__TYPE_ARGUMENTS 1 :", "m38.getText()");} )+ + ; +pr__TYPE_ARGUMENT: m39:STAR_SIGN { + prntS(" ===17==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("*") + 1; + + // so, it's "unrestricted" wildcard. + // add the wildcard to the args list of the stack's element of the previous layer: + upper = createInterimClassType("Ljava/lang/Object"); + addElemToTypeArgsList(createInterimWildcardType(0 /* i.e. extends Object */, new InterimType[]{(InterimType)upper}, 1)); + + prntSS(" pr__TYPE_ARGUMENT 1 :", m39.getText()); + } + | m40:pr__FIELD_TYPE_SIGNATURE {prntSS(" pr__TYPE_ARGUMENT 2 :", "m40.getText()");} + | m41:pr__WILDCARD_INDICATOR {prntSS(" ### 17:", "m41.getText()");} m42:pr__FIELD_TYPE_SIGNATURE {prntSS(" pr__TYPE_ARGUMENT 3 :", "m42.getText()");} + ; +pr__WILDCARD_INDICATOR: PLUS_SIGN { + prntS(" ===18==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("+") + 1; + + // so, it's "restricted" wildcard : + currentStackElem.wrappInWildcard = 0; // upper + + prntS(" pr__WILDCARD_INDICATOR 1 "); + } + | m43:MINUS_SIGN { + prntS(" ===19==="); + // grow the signature inconditionally because a wildcard is always the argument of : + currentStackElem.sigEnd = addToSignature("-") + 1; + + // so, it's "restricted" wildcard: + currentStackElem.wrappInWildcard = 1; // lower + + prntSS(" pr__WILDCARD_INDICATOR 2 :", m43.getText()); + } + ; +pr__CLASS_TYPE_SIGNATURE_SUFFIXES: ( m44:DOT_OR_DOLLAR_SIGN { + prntS(" ===21==="); + //// seems, I have just done it in pr__SIMPLE_CLASS_TYPE_SIGNATURE + //// grow the signature: + //currentStackElem.sigEnd = addToSignature("$") + 1; + + prntSS(" ### 20:", m44.getText()); + } m45:pr__SIMPLE_CLASS_TYPE_SIGNATURE {prntSS(" pr__CLASS_TYPE_SIGNATURE_SUFFIXES 2 :", "m45.getText()");})+ + ; +pr__ARRAY_TYPE_SIGNATURE: m46:SQUAREOPEN_SIGN { + currentStackElem.dim += 1; + + prntSS(" ### 21:", m46.getText()); + } m47:pr__TYPE_SIGNATURE {prntSS(" pr__ARRAY_TYPE_SIGNATURE:", "m47.getText()");} + ; +pr__TYPE_SIGNATURE: m48:pr__FIELD_TYPE_SIGNATURE {prntSS(" pr__TYPE_SIGNATURE 1 :", "m48.getText()");} + | m49:TBASE { + prsrT = createInterimClassType(getBaseTypeName(m49.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + highLevelType = /*(InterimGenericType)*/(InterimType)prsrT; + + prntSS(" pr__TYPE_SIGNATURE 2 :", m49.getText()); + } + ; +pr__SUPERINTERFACE_SIGNATURES: ( m50:pr__SUPERINTERFACE_SIGNATURE {prntSS(" pr__SUPERINTERFACE_SIGNATURES 1 :", "m50.getText()");} )* + ; +pr__SUPERINTERFACE_SIGNATURE: m51:pr__CLASS_TYPE_SIGNATURE { + prntS(" ===22==="); + addElemToImplList((InterimType)highLevelType); // add the gathered regular type to implements-list + + highLevelType = null; + + prntSS(" pr__SUPERINTERFACE_SIGNATURE:", "m51.getText()"); + } + ; +//pr__CONSTRUCTOR_DECL: (pr__METHOD_PARAMETERS pr__THROWN_SIGNATURE)=> m53:pr__METHOD_PARAMETERS {prntSS(" ### 23:", "m53.getText()");} m54:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 2 :", "m54.getText()");} +// | m52:pr__METHOD_PARAMETERS {prntSS(" pr__CONSTRUCTOR_DECL 1 :", "m52.getText()");} +// | (pr__F_T_P_AND_M_P pr__THROWN_SIGNATURE)=> m56:pr__F_T_P_AND_M_P {prntSS(" ### 24:", "m56.getText()");} m57:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 4 :", "m57.getText()");} +// | m55:pr__F_T_P_AND_M_P {prntSS(" pr__CONSTRUCTOR_DECL 3 :", "m55.getText()");} +// ; +//pr__CONSTRUCTOR_DECL: (pr__METHOD_PARAMETERS pr__THROWN_SIGNATURE)=> m53:pr__METHOD_PARAMETERS {prntSS(" ### 23:", "m53.getText()");} VOIDTYPE m54:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 2 :", "m54.getText()");} +// | m52:pr__METHOD_PARAMETERS {prntSS(" pr__CONSTRUCTOR_DECL 1 :", "m52.getText()");} VOIDTYPE +// | (pr__F_T_P_AND_M_P pr__THROWN_SIGNATURE)=> m56:pr__F_T_P_AND_M_P {prntSS(" ### 24:", "m56.getText()");} VOIDTYPE m57:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 4 :", "m57.getText()");} +// | m55:pr__F_T_P_AND_M_P {prntSS(" pr__CONSTRUCTOR_DECL 3 :", "m55.getText()");} VOIDTYPE +// ; +pr__CONSTRUCTOR_DECL: (pr__C_P_AND_R_T pr__THROWN_SIGNATURE)=> m53:pr__C_P_AND_R_T {prntSS(" ### 23:", "m53.getText()");} m54:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 2 :prntSS", "m54.getText()");} + | m52:pr__C_P_AND_R_T {prntSS(" pr__CONSTRUCTOR_DECL 1 :", "m52.getText()");} + | (pr__F_T_P_AND_C_P_AND_R_T pr__THROWN_SIGNATURE)=> m56:pr__F_T_P_AND_C_P_AND_R_T {prntSS(" ### 24:", "m56.getText()");} m57:pr__THROWN_SIGNATURE {prntSS(" pr__CONSTRUCTOR_DECL 4 :", "m57.getText()");} + | m55:pr__F_T_P_AND_C_P_AND_R_T {prntSS(" pr__CONSTRUCTOR_DECL 3 :", "m55getText()");} + ; +pr__C_P_AND_R_T: m555:pr__METHOD_PARAMETERS {prntSS(" ### 241:", "m556.getText()");} m557:VOIDTYPE { + prntSS(" pr__C_P_AND_R_T :", "m557.getText()");} + ; +pr__F_T_P_AND_C_P_AND_R_T: m558:pr__F_T_P_AND_M_P {prntSS(" ### 29:", "m558.getText()");} m559:VOIDTYPE { + prntSS(" pr__F_T_P_AND_C_P_AND_R_T :", "m559.getText()");} + ; +pr__METHOD_DECL: (pr__M_P_AND_R_T pr__THROWN_SIGNATURE)=> m59:pr__M_P_AND_R_T {prntSS(" ### 25:", "m59.getText()");} m60:pr__THROWN_SIGNATURE {prntSS(" pr__METHOD_DECL 2 :prntSS", "m60.getText()");} + | m58:pr__M_P_AND_R_T {prntSS(" pr__METHOD_DECL 1 :", "m58.getText()");} + | (pr__F_T_P_AND_M_P_AND_R_T pr__THROWN_SIGNATURE)=> m62:pr__F_T_P_AND_M_P_AND_R_T {prntSS(" ### 26:", "m62.getText()");} m63:pr__THROWN_SIGNATURE {prntSS(" pr__METHOD_DECL 4 :", "m63.getText()");} + | m61:pr__F_T_P_AND_M_P_AND_R_T {prntSS(" pr__METHOD_DECL 3 :", "m61.getText()");} + ; +pr__M_P_AND_R_T: m64:pr__METHOD_PARAMETERS {prntSS(" ### 27:", "m64.getText()");} m65:pr__RETURN_TYPE {prntSS(" pr__M_P_AND_R_T :", "m65.getText()");} + ; +pr__F_T_P_AND_M_P: m66:pr__FORMAL_TYPE_PARAMETERS_DECL {prntSS(" ### 28:", "m66.getText()");} m67:pr__METHOD_PARAMETERS { + prntS(" ===23==="); + // set typeParameters field of InterimMethodGenericDecl or InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).typeParameters = (InterimTypeParameter[])genParamList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).typeParameters = genParamList.toArray(new InterimTypeParameter[genParamList.size()]); + } + + // clean the genParamList: + genParamList = null; + + prntSS(" pr__F_T_P_AND_M_P :", "m67.getText()"); + } + ; +pr__F_T_P_AND_M_P_AND_R_T: m68:pr__F_T_P_AND_M_P {prntSS(" ### 29:", "m68.getText()");} m69:pr__RETURN_TYPE {prntSS(" pr__F_T_P_AND_M_P_AND_R_T :", "m69.getText()");} + ; +pr__RETURN_TYPE: m70:VOIDTYPE { + prntS(" ===24==="); + if (declType == METHODoDECL) { + // put void return type into the method decl: + methodDecl.returnValue = (InterimType)createInterimClassType("void"); + } + + prntSS(" pr__RETURN_TYPE 1 :", m70.getText()); + } + | m71:pr__TYPE_SIGNATURE { + prntS(" ===25==="); + // put return type into the method decl: + methodDecl.returnValue = (InterimType)highLevelType; + + highLevelType = null; + + prntSS(" pr__RETURN_TYPE 2 :", "m71.getText()"); + } + | m72:RETURN_BASE_TYPE { + prntS(" ===26==="); + prsrT = createInterimClassType(getBaseTypeName(m72.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put base return type into the method decl: + methodDecl.returnValue = prsrT; + + prntSS(" pr__RETURN_TYPE 3 :", m72.getText()); + } + ; +pr__METHOD_PARAMETERS: (RINGOPEN_SIGN RINGCLOSE_SIGN) => m76:RINGOPEN_SIGN { + prntS(" ===29==="); + // create InterimMethodGenericDecl or InterimConstructorGenericDecl: + if (declType == METHODoDECL) { + methodDecl = new InterimMethodGenericDecl(); + } else { + constructorDecl = new InterimConstructorGenericDecl(); + } + + prntSS(" ### 32:", m76.getText()); + } m77:RINGCLOSE_SIGN {prntSS(" pr__METHOD_PARAMETERS 2 :", m77.getText());} + | m73:RINGOPEN_SIGN { + prntS(" ===27==="); + // create InterimMethodGenericDecl or InterimConstructorGenericDecl: + if (declType == METHODoDECL) { + methodDecl = new InterimMethodGenericDecl(); + } else { + constructorDecl = new InterimConstructorGenericDecl(); + } + + prntSS(" ### 30:", m73.getText()); + } m74:pr__PARAMETERS_LIST { + prntS(" ===28==="); + // set methodParameters field of InterimMethodGenericDecl/InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).methodParameters = (InterimType[])methParamList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).methodParameters = methParamList.toArray(new InterimType[methParamList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).methodParameters = methParamList.toArray(new InterimType[methParamList.size()]); + } + + // clean the methParamList: + methParamList = null; + + prntSS(" ### 31:", "m74.getText()"); + } m75:RINGCLOSE_SIGN {prntSS(" pr__METHOD_PARAMETERS 1 :", m75.getText());} + ; +pr__PARAMETERS_LIST: ( m78:pr__PARAMETER {prntSS(" pr__PARAMETERS_LIST 2 :", "m78.getText()");} )+ + ; +pr__PARAMETER: m79:pr__FIELD_TYPE_SIGNATURE { + prntS(" ===30==="); + // put base type into the method params list: + addElemToMethParamList(highLevelType); + + highLevelType = null; + + prntSS(" pr__PARAMETER 1 :", "m79.getText()"); + } + | m80:TBASE { + prntS(" ===31==="); + prsrT = createInterimClassType(getBaseTypeName(m80.getText().charAt(0))); + + // if there is dimention indicator then InterimTypeVariable should be "rolled up" by InterimGenericArrayType + if (currentStackElem.dim > 0) { + for (i = 0; i < currentStackElem.dim; i++ ) { + prsrT = (InterimType)createInterimGenericArrayType(prsrT); + } + } + currentStackElem.dim = 0; + + // put base type into the method params list: + addElemToMethParamList(prsrT); + + prntSS(" pr__PARAMETER 2 :", m80.getText()); + } + ; +pr__THROWN_SIGNATURE: m82:pr__THROWNS { + prntS(" ===32==="); + // set throwns field of InterimMethodGenericDecl/InterimConstructorGenericDecl object: + //(declType == METHODoDECL ? methodDecl : constructorDecl).throwns = (InterimType[])thrownList.toArray(); + if (declType == METHODoDECL) { + ((InterimMethodGenericDecl)methodDecl).throwns = thrownList.toArray(new InterimType[thrownList.size()]); + } else { + ((InterimConstructorGenericDecl)constructorDecl).throwns = thrownList.toArray(new InterimType[thrownList.size()]); + } + + // clean the thrownList: + thrownList = null; + + prntSS(" pr__THROWN_SIGNATURE:", "m82.getText()"); + } + ; +pr__THROWNS: ( m83:pr__THROWN {prntSS(" pr__THROWNS 2 :", "m83.getText()");} )+ + ; +pr__THROWN: (CNTRL_SIGN pr__CLASS_TYPE_SIGNATURE)=> m84:CNTRL_SIGN { + Yflag2 = 1; // so, we are within throws part + + prntSS(" ### 35:", m84.getText()); + } m85:pr__CLASS_TYPE_SIGNATURE { + prntS(" ===33==="); + // put the InterimClassType or InterimParameterizedType to the throwns list: + addElemToThrownList((InterimType)highLevelType); + + highLevelType = null; + + prntSS(" pr__THROWN 1 :", "m85.getText()"); + } + | m86:CNTRL_SIGN {prntSS(" ### 36:", m86.getText());} m87:TVAR { + prntS(" ===34==="); + assert(currentStackElem.dim == 0); + + // put the InterimTypeVariable to the throwns list: + // to exclude first (official) "T" symbol (and last ";" symbol): + System.out.println(m87.getText()+"|"+m87.getText().length()); + addElemToThrownList((InterimType)createInterimTypeVariable(m87.getText().substring(1, m87.getText().length()-1))); + + prntSS(" pr__THROWN 2 :", m87.getText()); + } /*SEMICOLON_SIGN {prntS(" ===34.2===");} //XXX: should be eliminated again!*/ + ; diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/ParameterizedTypeRepository.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/ParameterizedTypeRepository.java new file mode 100644 index 0000000..97d30a4 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/ParameterizedTypeRepository.java @@ -0,0 +1,298 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.repository; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; + +import org.apache.harmony.lang.reflect.parser.*; +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * (This all should be considered as an experimental approach which could be changed on + * java.lang.ref using) + * + * ParameterizedTypeRepository provides the keeping iformation about a parameterized types. + * + * For now the following approach for keeping is realized. + * A concreet PT instance is included into repository if somebody do the *first* request for + * the reflect's method like Class.getGenericSuperclass()->Class.ReflectionData.initGenericSuperclass() + * (Field.getGenericType()->Field.FieldData.initGenericType() + * Method.getGenericReturnType()->Class.MethodData.initGenericReturnType() + * ... + * Constructor.getGenericParameterTypes()->Class.ConstructorData.initGenericParameterTypes() + * ... + * ). If the identical PT is accessed anyhow then the pointer from repository is used. However, + * further it can be removed from the repository if the cache is full under the new instance including. + * Then if reflect's request for such PT using the earlier used interface methods then the pointers + * to such instance kept within the Method/Constructor/Field/Class instances are returned just if it is + * absent within repository. But if we use other Method/Constructor/Field/Class instances to access + * to some instance of the same PT type which has been removed from repository then the new + * exemplar of instance is included into repository and the pointer to it is replicated if it needs + * into the new Method/Constructor/Field/Class instances. + * + * Maybe, it would be more convinient to realize another repository implementation + * where the accumulative approach will be used. + * It might be realized using just java.lang.ref. + * + * Note1. The inserted on 01.26.06 cache3 may significantly slow the algorithm but + * it needs to provide the functional completeness of repository because we should distinguish + * the entries with equals signatures if there are TVARs which are only homonym ones, i.e. + * they are parameters of different generic declarations. + */ +public final class ParameterizedTypeRepository { + + static final class ParameterizedTypeCache { + + /** + * This class realizes the ParameterizedType repository which + * is just a cache. When the cache is exceeded at that time this experimental original cache algorithm (which, if + * it will justify hopes, should be combined in one for all type repositories here) rewrites the worst entity + * which can't be copied any more only recreated (as equal, of course). If the cache has an entity which + * the reflect supporting algorithm supposes to include there than the cache's algorithm copies the existing entity. + * If the cache is not full and an entity does not exist than there the cache's algorithm + * creates preliminary an entity and inserts it there. + * So, an earlier created type variable exists while the cache's algorithm has pointer[s] of it + * within the cache (entity has not removed yet during cleanings) + * or user's java code keeps pointer[s] of this type variable. + */ + + private static class TVSSynchro { + }; + + private static int cacheLenght = 2048; + private static String cache[] = new String[cacheLenght]; + private static ParameterizedType cache2[] = new ParameterizedType[cacheLenght]; + private static InterimParameterizedType cache3[] = new InterimParameterizedType[cacheLenght]; + private static Object cache4[] = new Object[cacheLenght]; + private static int counter = 0; + private static int worth[] = new int[cacheLenght]; + + /** + * To delete the worst entry. + */ + static int deleteParameterizedType() { + int min = -1; + int min2 = -1; + + synchronized (TVSSynchro.class) { + float minWorth = ((worth[0] >> 16) > 0 ? (worth[0] & 0xFFFF) / worth[0] >> 16 : worth[0]); + int minWorth2 = worth[0]; + float tmp; + int i = 0; + for (; i < cacheLenght; i++) { + try { + if ((tmp = (worth[i] & 0xFFFF) / worth[i] >> 16) <= minWorth) { + min = i; + minWorth = tmp; + } + } catch (ArithmeticException _) { + if ((tmp = worth[i]) <= minWorth2) { + min2 = i; + minWorth2 = (int) tmp; + } + } + } + if (i == cacheLenght && min == -1) { + min = min2; + } + cache[min] = null; + cache2[min] = null; + cache3[min] = null; + cache4[min] = null; + worth[min] = 0; + } + return min; + } + + /** + * To create new cache entry + */ + static int insertParameterizedType(ParameterizedType parameterizedType, InterimParameterizedType prsrdParameterizedType, String signature, Object startPoint, int ip) { + synchronized (TVSSynchro.class) { + if (ip < 0) { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (null == cache[ind]) { + cache[ind] = signature; + cache2[ind] = parameterizedType; + cache3[ind] = prsrdParameterizedType; + cache4[ind] = startPoint; + worth[ind] = 1; + return ind; + } + } + return insertParameterizedType(parameterizedType, prsrdParameterizedType, signature, startPoint, deleteParameterizedType()); + } else { + cache[ip] = signature; + cache2[ip] = parameterizedType; + cache3[ip] = prsrdParameterizedType; + cache4[ip] = startPoint; + + boolean flg = false; + short sv = (short) (worth[ip] & 0xFFFF); + if (sv == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ip] = (sv + 1) | (worth[ip] & 0xFFFF0000); + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + } + } + return ip; + } + + /** + * To return ParameterizedType of cache. + */ + static ParameterizedType valueParameterizedType(InterimParameterizedType parameterizedType, String signature, Object startPoint) { + synchronized (TVSSynchro.class) { + boolean flg = false; + if (counter == cacheLenght) { // Do smoke, it's time for reordering + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + short sv1 = (short) (worth[ind] >> 16); + if (sv1 == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ind] = worth[ind] & 0xFFFF | ((sv1 + 1) << 16); + } + } catch(NullPointerException _) { + } + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + counter = 0; + } else { + counter++; + } + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (signature.equals(cache[ind]) && arePTEqual(cache3[ind], cache4[ind], parameterizedType, startPoint)) { + return cache2[ind]; + } + } + } catch (NullPointerException _) { + } + } + return null; + } + } + + /** + * This method provides the comparing of two InterimParameterizedType entities. + * + * @param parameterizedType1 a InterimParameterizedType entity. + * @param startPoint1 a generic declaration which the seeking of any type variable definition used within parameterizedType1 should be started from. + * @param parameterizedType2 another InterimParameterizedType entity. + * @param startPoint2 a generic declaration which the seeking of any type variable definition used within parameterizedType2 should be started from. + */ + static boolean arePTEqual(InterimParameterizedType parameterizedType1, Object startPoint1, InterimParameterizedType parameterizedType2, Object startPoint2) { + // Remember that the signatures for being compared InterimParameterizedType-s are equal! + + // So, we need to compare only the rests: + InterimType params1[] = parameterizedType1.parameters; + InterimType params2[] = parameterizedType2.parameters; + for (int i = 0; i < params1.length; i++) { + if (params1[i] instanceof InterimTypeVariable && !areTVEqual((InterimTypeVariable)params1[i], startPoint1, (InterimTypeVariable)params2[i], startPoint2)) { + return false; + } + if (params1[i] instanceof InterimParameterizedType && !arePTEqual((InterimParameterizedType)params1[i], startPoint1, (InterimParameterizedType)params2[i], startPoint2)) { + return false; + } + if (params1[i] instanceof InterimWildcardType && !WildcardTypeRepository.areWCEqual((InterimWildcardType)params1[i], startPoint1, (InterimWildcardType)params2[i], startPoint2)) { + return false; + } + } + if (parameterizedType1.ownerType != null && parameterizedType1.ownerType instanceof InterimParameterizedType) { + return arePTEqual((InterimParameterizedType)parameterizedType1.ownerType, startPoint1, (InterimParameterizedType)parameterizedType2.ownerType, startPoint2); + } + return true; + } + + /** + * This method provides the comparing of two InterimTypeVariable entities. + * + * @param typeVariable1 a InterimTypeVariable entity. + * @param startPoint1 a generic declaration which the seeking of typeVariable1 type variable definition should be started from. + * @param typeVariable2 another InterimTypeVariable entity. + * @param startPoint2 a generic declaration which the seeking of typeVariable2 type variable definition should be started from. + */ + static boolean areTVEqual(InterimTypeVariable typeVariable1, Object startPoint1, InterimTypeVariable typeVariable2, Object startPoint2) { + if (AuxiliaryFinder.findTypeVariable(typeVariable1.typeVariableName, startPoint1) == AuxiliaryFinder.findTypeVariable(typeVariable2.typeVariableName, startPoint2)) { + return true; + } + return false; + } + + /** + * This method returns a registered type variable if it exists within the repository. + * + * @param ParameterizedTypeName a parameterized type. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable or null if it does not exist within repository. + */ + public static ParameterizedType findParameterizedType(InterimParameterizedType parameterizedType, Object startPoint) { + return ParameterizedTypeCache.valueParameterizedType(parameterizedType, parameterizedType.signature, startPoint); + } + + /** + * This method returns a registered type variable if it exists within the repository. + * + * @param ParameterizedTypeName a parameterized type. + * @param signature a signature of a parameterized type. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable or null if it does not exist within repository. + */ + public static ParameterizedType findParameterizedType(InterimParameterizedType parameterizedType, String signature, Object startPoint) { + return ParameterizedTypeCache.valueParameterizedType(parameterizedType, signature, startPoint); + } + + /** + * This method registers a parameterized type within the repository. + * + * @param ParameterizedType a type variable. + * @param ParameterizedTypeName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + */ + public static void registerParameterizedType(ParameterizedType parameterizedType, InterimParameterizedType prsrdParameterizedType, String signature, Object startPoint) { + ParameterizedTypeCache.insertParameterizedType(parameterizedType, prsrdParameterizedType, signature, startPoint, -1); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/TypeVariableRepository.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/TypeVariableRepository.java new file mode 100644 index 0000000..465f53a --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/TypeVariableRepository.java @@ -0,0 +1,223 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.repository; + +import java.lang.reflect.TypeVariable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericDeclaration; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * (This all should be considered as an experimental approach which could be changed on + * java.lang.ref using) + * + * TypeVariableRepository keeps iformation about type variables. + * + * For now the following approach for keeping is realized. + * A concreet TV instance is included into repository if somebody do the *first* request for + * the reflect's method like Method.getGenericReturnType()->Class.MethodData.initGenericReturnType() + * (Field.getGenericType()->Field.FieldData.initGenericType() + * Method.getGenericExceptionTypes()->Class.MethodData.initGenericExceptionTypes() + * ... + * Constructor.getGenericParameterTypes()->Class.ConstructorData.initGenericParameterTypes() + * ... + * ). If the identical TV is accessed anyhow then the pointer from repository is used. However, + * further it can be removed from the repository if the cache is full under the new instance including. + * Then if reflect's request for such TV using the earlier used interface methods then the pointers + * to such instance kept within the Method/Constructor/Field/Class instances are returned just if it is + * absent within repository. But if we use other Method/Constructor/Field/Class instances to access + * to some instance of the same TV type which has been removed from repository then the new + * exemplar of instance is included into repository and the pointer to it is replicated if it needs + * into the new Method/Constructor/Field/Class instances. + * Another way to recreate some TV entry within repository is the AuxiliaryFinder.findTypeVariable() method + * which can recreate the removed instance getting it within Method/Constructor/Field/Class instances + * which were used to acces to the mentioned TV earlier. + * + * Maybe, it would be more convinient to realize another repository implementation + * where the accumulative approach will be used. + * + */ +public final class TypeVariableRepository { + + static final class TypeVariableCache { + + /** + * This class realizes the TypeVariable repository which + * is just a cache. When the cache is exceeded at that time this experimental original cache algorithm (which, if + * it will justify hopes, should be combined in one for all type repositories here) rewrites the worst entity + * which can't be copied any more only recreated (as equal, of course). If the cache has an entity which + * the reflect supporting algorithm supposes to include there than the cache's algorithm copies the existing entity. + * If the cache is not full and an entity does not exist than there the cache's algorithm + * creates preliminary an entity and inserts it there. + * So, an earlier created type variable exists while the cache's algorithm has pointer[s] of it + * within the cache (entity has not removed yet during cleanings) + * or user's java code keeps pointer[s] of this type variable. + */ + + private static class TVSSynchro { + }; + + private static int cacheLenght = 2048; + private static TypeVariable cache[] = new TypeVariable[cacheLenght]; + private static int counter = 0; + private static int worth[] = new int[cacheLenght]; + + /** + * To delete the worst entry. + */ + static int deleteTypeVariable() { + int min = -1; + int min2 = -1; + + synchronized (TVSSynchro.class) { + float minWorth = ((worth[0] >> 16) > 0 ? (worth[0] & 0xFFFF) / worth[0] >> 16 : worth[0]); + int minWorth2 = worth[0]; + float tmp; + int i = 0; + for (; i < cacheLenght; i++) { + try { + if ((tmp = (worth[i] & 0xFFFF) / worth[i] >> 16) <= minWorth) { + min = i; + minWorth = tmp; + } + } catch (ArithmeticException _) { + if ((tmp = worth[i]) <= minWorth2) { + min2 = i; + minWorth2 = (int) tmp; + } + } + } + if (i == cacheLenght && min == -1) { + min = min2; + } + cache[min] = null; + worth[min] = 0; + } + return min; + } + + /** + * To create new cache entry + */ + static int insertTypeVariable(TypeVariable typeVariable, int ip) { + synchronized (TVSSynchro.class) { + if (ip < 0) { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (null == cache[ind]) { + cache[ind] = typeVariable; + worth[ind] = 1; + return ind; + } + } + return insertTypeVariable(typeVariable, deleteTypeVariable()); + } else { + cache[ip] = typeVariable; + + boolean flg = false; + short sv = (short) (worth[ip] & 0xFFFF); + if (sv == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ip] = (sv + 1) | (worth[ip] & 0xFFFF0000); + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + } + } + return ip; + } + + /** + * To return TypeVariable of cache. + */ + static TypeVariable valueTypeVariable(String typeVariableName, GenericDeclaration decl) { + synchronized (TVSSynchro.class) { + boolean flg = false; + if (counter == cacheLenght) { // Do smoke, it's time for reordering + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + short sv1 = (short) (worth[ind] >> 16); + if (sv1 == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ind] = worth[ind] & 0xFFFF | ((sv1 + 1) << 16); + } + } catch(NullPointerException _) { + } + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + counter = 0; + } else { + counter++; + } + } + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (typeVariableName.equals(cache[ind].getName()) && decl.equals(cache[ind].getGenericDeclaration())) { + return cache[ind]; + } + } + } catch (NullPointerException _) { + } + return null; + } + } + + /** + * This method returns a registered type variable if it exists within the repository. + * + * @param typeVariableName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable or null if it does not exist within repository. + */ + public static TypeVariable findTypeVariable(String typeVariableName, Object startPoint) { + return TypeVariableCache.valueTypeVariable(typeVariableName, (GenericDeclaration) startPoint); + } + + /** + * This method registers a type variable within the repository. + * + * @param typeVariable a type variable. + * @param typeVariableName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + */ + public static void registerTypeVariable(TypeVariable typeVariable, String typeVariableName, Object startPoint) { + TypeVariableCache.insertTypeVariable(typeVariable, -1); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/WildcardTypeRepository.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/WildcardTypeRepository.java new file mode 100644 index 0000000..3fe45c3 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/repository/WildcardTypeRepository.java @@ -0,0 +1,283 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.repository; + +import java.lang.reflect.WildcardType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; + +import org.apache.harmony.lang.reflect.parser.*; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * (This all should be considered as an experimental approach which could be changed on + * java.lang.ref using) + * + * WildcardTypeRepository keeps iformation about wild cards. + * + * For now the following approach for keeping is realized. + * A concreet WC instance is included into repository if somebody do the *first* request for + * the reflect's method like Class.getGenericSuperclass()->Class.ReflectionData.initGenericSuperclass() + * (Field.getGenericType()->Field.FieldData.initGenericType() + * Method.getGenericReturnType()->Class.MethodData.initGenericReturnType() + * ... + * Constructor.getGenericParameterTypes()->Class.ConstructorData.initGenericParameterTypes() + * ... + * ) and there are ParameterizedTypes with wild cards. + * The wild card creation and allocation within repository is located within AuxiliaryCreator.createTypeArg method. + * If the identical WC is accessed anyhow then the pointer from repository is used. However, + * further it can be removed from the repository if the cache is full under the new instance including. + * Then if reflect's request for such WC using the earlier used interface methods then the pointers + * to such instance kept within the Method/Constructor/Field/Class instances are returned just if it is + * absent within repository. But if we access anyhow to some instance of the same WC type which has + * been removed from repository then the new exemplar of instance is created and included into + * repository and the pointer to it is replicated if it needs. + * + * Maybe, it would be more convinient to realize another repository implementation + * where the accumulative approach will be used. + * + * Note1. The inserted on 01.27.06 cache3 may significantly slow the algorithm but + * it needs to provide the functional completeness of repository because we should distinguish + * the entries with equals signatures if there are TVARs which are only homonym ones, i.e. + * they are parameters of different generic declarations. + */ +public final class WildcardTypeRepository { + + static final class WildcardTypeCache { + + /** + * This class realizes the WildcardType repository which + * is just a cache. When the cache is exceeded at that time this experimental original cache algorithm (which, if + * it will justify hopes, should be combined in one for all type repositories here) rewrites the worst entity + * which can't be copied any more only recreated (as equal, of course). If the cache has an entity which + * the reflect supporting algorithm supposes to include there than the cache's algorithm copies the existing entity. + * If the cache is not full and an entity does not exist than there the cache's algorithm + * creates preliminary an entity and inserts it there. + * So, an earlier created type variable exists while the cache's algorithm has pointer[s] of it + * within the cache (entity has not removed yet during cleanings) + * or user's java code keeps pointer[s] of this type variable. + */ + + private static class TVSSynchro { + }; + + private static int cacheLenght = 2048; + private static String cache[] = new String[cacheLenght]; + private static WildcardType cache2[] = new WildcardType[cacheLenght]; + private static InterimWildcardType cache3[] = new InterimWildcardType[cacheLenght]; + private static Object cache4[] = new Object[cacheLenght]; + private static int counter = 0; + private static int worth[] = new int[cacheLenght]; + + /** + * To delete the worst entry. + */ + static int deleteWildcardType() { + int min = -1; + int min2 = -1; + + synchronized (TVSSynchro.class) { + float minWorth = ((worth[0] >> 16) > 0 ? (worth[0] & 0xFFFF) / worth[0] >> 16 : worth[0]); + int minWorth2 = worth[0]; + float tmp; + int i = 0; + for (; i < cacheLenght; i++) { + try { + if ((tmp = (worth[i] & 0xFFFF) / worth[i] >> 16) <= minWorth) { + min = i; + minWorth = tmp; + } + } catch (ArithmeticException _) { + if ((tmp = worth[i]) <= minWorth2) { + min2 = i; + minWorth2 = (int) tmp; + } + } + } + if (i == cacheLenght && min == -1) { + min = min2; + } + cache[min] = null; + cache2[min] = null; + cache3[min] = null; + cache4[min] = null; + worth[min] = 0; + } + return min; + } + + /** + * To create new cache entry + */ + static int insertWildcardType(WildcardType wildcardType, InterimWildcardType prsrdWildcardType, String signature, Object startPoint, int ip) { + synchronized (TVSSynchro.class) { + if (ip < 0) { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (null == cache[ind]) { + cache[ind] = signature; + cache2[ind] = wildcardType; + cache3[ind] = prsrdWildcardType; + cache4[ind] = startPoint; + worth[ind] = 1; + return ind; + } + } + return insertWildcardType(wildcardType, prsrdWildcardType, signature, startPoint, deleteWildcardType()); + } else { + cache[ip] = signature; + cache2[ip] = wildcardType; + cache3[ip] = prsrdWildcardType; + cache4[ip] = startPoint; + + boolean flg = false; + short sv = (short) (worth[ip] & 0xFFFF); + if (sv == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ip] = (sv + 1) | (worth[ip] & 0xFFFF0000); + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + } + } + return ip; + } + + /** + * To return WildcardType of cache. + */ + static WildcardType valueWildcardType(InterimWildcardType wildcard, String signature, Object startPoint) { + synchronized (TVSSynchro.class) { + boolean flg = false; + if (counter == cacheLenght) { // Do smoke, it's time for reordering + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + short sv1 = (short) (worth[ind] >> 16); + if (sv1 == Short.MAX_VALUE - 1){ + flg = true; // to reduce + } + worth[ind] = worth[ind] & 0xFFFF | ((sv1 + 1) << 16); + } + } catch(NullPointerException _) { + } + if (flg) { + try { + for (int ind = 0; ind < cacheLenght ; ind++) { // reducing + short sv1 = (short) (worth[ind] >> 16); + short sv2 = (short) (worth[ind] & 0xFFFF); + worth[ind] = (sv2 == 1 ? 1 : sv2 >> 2) | (((sv1 == 1 ? 1 : sv1 >> 2) + 1) << 16); + } + } catch (NullPointerException _) { + } + } + counter = 0; + } else { + counter++; + } + } + try { + for (int ind = 0; ind < cacheLenght ; ind++) { + if (signature.equals(cache[ind]) && areWCEqual(cache3[ind], cache4[ind], wildcard, startPoint)) { + return cache2[ind]; + } + } + } catch (NullPointerException _) { + } + return null; + } + } + + /** + * This method provides the comparing of two InterimWildcardType entities. + * + * @param wildcard1 a InterimWildcardType entity. + * @param startPoint1 a generic declaration which the seeking of any type variable definition used within wildcard1 should be started from. + * @param wildcard2 another InterimWildcardType entity. + * @param startPoint2 a generic declaration which the seeking of any type variable definition used within wildcard2 should be started from. + */ + static boolean areWCEqual(InterimWildcardType wildcard1, Object startPoint1, InterimWildcardType wildcard2, Object startPoint2) { + // Remember that the signatures for being compared InterimWildcardType-s are equal! + + // So, we need to compare only the rests: + InterimType bounds1[] = wildcard1.bounds; + InterimType bounds2[] = wildcard2.bounds; + for (int i = 0; i < bounds1.length; i++) { + if (bounds1[i] instanceof InterimTypeVariable && !ParameterizedTypeRepository.areTVEqual((InterimTypeVariable)bounds1[i], startPoint1, (InterimTypeVariable)bounds2[i], startPoint2)) { + return false; + } else if (bounds1[i] instanceof InterimParameterizedType && !ParameterizedTypeRepository.arePTEqual((InterimParameterizedType)bounds1[i], startPoint1, (InterimParameterizedType)bounds1[i], startPoint2)) { + return false; + } + } + return true; + } + + /** + * This method returns a registered type variable if it exists within the repository. + * + * @param WildcardTypeName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable or null if it does not exist within repository. + */ + public static WildcardType findWildcardType(InterimWildcardType wildcard, String signature, Object startPoint) { + return WildcardTypeCache.valueWildcardType(wildcard, signature, startPoint); + } + + /** + * This method returns a registered type variable if it exists within the repository. + * + * @param WildcardTypeName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable or null if it does not exist within repository. + */ + public static String recoverWildcardSignature(InterimWildcardType wildcard) { + String res = ""; + res = res+(wildcard.boundsType == true ? "+" : "-"); + if (wildcard.bounds[0] instanceof InterimParameterizedType) { + res = res+((InterimParameterizedType)wildcard.bounds[0]).signature; + } else if (wildcard.bounds[0] instanceof InterimTypeVariable) { + res = res+((InterimTypeVariable) wildcard.bounds[0]).typeVariableName; + } else { //ClassType + res = res+((InterimClassType) wildcard.bounds[0]).classTypeName; + } + return res; + } + + /** + * This method registers a type variable within the repository. + * + * @param WildcardType a type variable. + * @param WildcardTypeName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + */ + public static void registerWildcardType(WildcardType wildcard, InterimWildcardType prsrdWildcardType, String signature, Object startPoint) { + WildcardTypeCache.insertWildcardType(wildcard, prsrdWildcardType, signature, startPoint, -1); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryChecker.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryChecker.java new file mode 100644 index 0000000..9d2e7ad --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryChecker.java @@ -0,0 +1,105 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.support; + +import java.lang.reflect.MalformedParameterizedTypeException; + +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimClassType; +import org.apache.harmony.lang.reflect.parser.*; + +import org.apache.harmony.vm.VMGenericsAndAnnotations; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * AuxiliaryChecker provides kinds of check. + */ +public final class AuxiliaryChecker { + + /** + * This method checks the correspondence of the formal parameter number and the actual argument number. + * + * @param ppType a parsered information produced from a parameterized type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return an array of Type objects representing the actual type arguments to this type. + */ + public static void checkArgsNumber(InterimParameterizedType ppType, Object startPoint) throws MalformedParameterizedTypeException { + // XXX: reprogram method (for example, to improve the preloop and the loop) + InterimParameterizedType currentBit = ppType; + InterimType currentBitArgs[] = currentBit.parameters; + + InterimClassType currentClass = currentBit.rawType; + Class klazz = null; + AuxiliaryLoader loader = AuxiliaryLoader.ersatzLoader; + try{ + klazz = loader.findClass(AuxiliaryFinder.transform(currentClass.classTypeName.substring(1).replace('/', '.'))); + } catch (Throwable e) { + + } + + String ccSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(klazz)); + + InterimClassGenericDecl decl; + if (ccSignature != null) { + decl = (InterimClassGenericDecl) Parser.parseSignature(ccSignature, Parser.SignatureKind.CLASS_SIGNATURE, (java.lang.reflect.GenericDeclaration)startPoint); + + if ((decl.typeParameters != null && currentBitArgs != null && decl.typeParameters.length != currentBitArgs.length) || (decl.typeParameters == null && currentBitArgs != null) || (decl.typeParameters != null && currentBitArgs == null)) { + throw new MalformedParameterizedTypeException(); + } + } else { + if (currentBitArgs != null && currentBitArgs.length > 0) { + throw new MalformedParameterizedTypeException(); + } + } + + while (currentBit.ownerType != null) { + InterimType pt = currentBit.ownerType; + if (pt instanceof InterimParameterizedType) { + currentBit = (InterimParameterizedType)currentBit.ownerType; + } else { + break; + } + currentBitArgs = currentBit.parameters; + + currentClass = currentBit.rawType; + klazz = null; + try{ + //klazz = ClassLoader.findClass(currentClass.classTypeName); + klazz = loader.findClass(AuxiliaryFinder.transform(currentClass.classTypeName.substring(1).replace('/', '.'))); + } catch (Throwable e) { + + } + + ccSignature = AuxiliaryUtil.toUTF8(VMGenericsAndAnnotations.getSignature(klazz)); + if (ccSignature != null) { + decl = (InterimClassGenericDecl) Parser.parseSignature(ccSignature, Parser.SignatureKind.CLASS_SIGNATURE, (java.lang.reflect.GenericDeclaration)startPoint); + + if ((decl.typeParameters != null && currentBitArgs != null && decl.typeParameters.length != currentBitArgs.length) || (decl.typeParameters == null && currentBitArgs != null) || (decl.typeParameters != null && currentBitArgs == null)) { + throw new MalformedParameterizedTypeException(); + } + } else { + if (currentBitArgs != null && currentBitArgs.length > 0) { + throw new MalformedParameterizedTypeException(); + } + } + } + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryCreator.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryCreator.java new file mode 100644 index 0000000..d51f4d1 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryCreator.java @@ -0,0 +1,221 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.support; + +import java.lang.reflect.Type; +import java.lang.reflect.GenericDeclaration; +import java.lang.TypeNotPresentException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.WildcardType; +import java.lang.reflect.TypeVariable; + +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimTypeVariable; +import org.apache.harmony.lang.reflect.parser.InterimGenericArrayType; +import org.apache.harmony.lang.reflect.support.AuxiliaryChecker; +import org.apache.harmony.lang.reflect.support.AuxiliaryFinder; +import org.apache.harmony.lang.reflect.repository.*; + +import org.apache.harmony.lang.reflect.parser.*; +import org.apache.harmony.lang.reflect.implementation.*; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * Finder provides kinds of finding. + */ +public final class AuxiliaryCreator { + + /** + * This method creates generic array type. + * + * @param ppType a parsered information produced from a generic array type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return a Type object representing a generic array type. + */ + public static Type createGenericArrayType(InterimGenericArrayType ppType, Object startPoint) { + InterimType nextLayer = ppType.nextLayer; + if (nextLayer instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) nextLayer, startPoint); + if (pType == null) { + try { + Class genClassDecl = AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) nextLayer, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) nextLayer).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) nextLayer, startPoint); //the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) nextLayer, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) nextLayer, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) nextLayer, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) nextLayer, ((InterimParameterizedType)nextLayer).signature, startPoint); + } + return new GenericArrayTypeImpl((Type) pType); + } else if (nextLayer instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) nextLayer).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + return (Type) null; // compatible behaviour + } + } + return new GenericArrayTypeImpl((Type) variable); + } else if (nextLayer instanceof InterimClassType) { + Type cType; + try { + cType = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)nextLayer).classTypeName.substring((((InterimClassType)nextLayer).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.')); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)nextLayer).classTypeName.substring((((InterimClassType)nextLayer).classTypeName.charAt(0)=='L'? 1 : 0)).replace('/', '.'), e); + } + return new GenericArrayTypeImpl(cType); + } else { // GenericArrayType again + return new GenericArrayTypeImpl(AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType)nextLayer, startPoint)); + } + } + + /** + * This method creates the owner's type for a parameterized type. + * + * @param ppType a parsered information produced from a parameterized type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return a created owner's type. + */ + public static Type createOwnerType(InterimParameterizedType ppType, Object startPoint) throws ClassNotFoundException { + // raise to owner level: + InterimType nextppType = ppType.ownerType; // XXX:???Can it be of InterimTypeVariable/InterimClassType type + if (nextppType == null) { + return null; + } + // create owner type + if (nextppType instanceof InterimParameterizedType) { + ParameterizedType pType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) nextppType, startPoint); + if (pType == null) { + try { + Class genClassDecl = AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) nextppType, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) nextppType).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType)nextppType, startPoint); // the MalformedParameterizedTypeException may raise here + try { + pType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) nextppType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) nextppType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) nextppType, startPoint)); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(e.getMessage(), e); + } + ParameterizedTypeRepository.registerParameterizedType(pType, (InterimParameterizedType) nextppType, ((InterimParameterizedType)nextppType).signature, startPoint); + } + return (Type) pType; + } else { //ClassType + return AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType) nextppType).classTypeName.substring(1).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } + } + + /** + * This method creates the raw type for a parameterized type. + * + * @param ppType a parsered information produced from a parameterized type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return a created raw type. + */ + public static Type createRawType(InterimParameterizedType ppType, Object startPoint) throws ClassNotFoundException { + return (Type) AuxiliaryFinder.findGenericClassDeclarationForParameterizedType(ppType, startPoint); // it may be null + } + + /** + * This method creates Type object representing the actual type argument. + * + * @param pType a parsered information of actual parameter. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return a Type object representing the actual type argument. + */ + public static Type createTypeArg(InterimType pType, Object startPoint) throws ClassNotFoundException { + Type res; + if (pType instanceof InterimParameterizedType) { + ParameterizedType cType = ParameterizedTypeRepository.findParameterizedType((InterimParameterizedType) pType, startPoint); + if (cType == null) { + try { + Class genClassDecl = AuxiliaryFinder.findGenericClassDeclarationForParameterizedType((InterimParameterizedType) pType, startPoint); + } catch(Throwable e) { + throw new TypeNotPresentException(((InterimParameterizedType) pType).rawType.classTypeName.substring(1).replace('/', '.'), e); + } + // check the correspondence of the formal parameter number and the actual argument number: + AuxiliaryChecker.checkArgsNumber((InterimParameterizedType) pType, startPoint); // the MalformedParameterizedTypeException may raise here + cType = new ParameterizedTypeImpl(AuxiliaryCreator.createTypeArgs((InterimParameterizedType) pType, startPoint), AuxiliaryCreator.createRawType((InterimParameterizedType) pType, startPoint), AuxiliaryCreator.createOwnerType((InterimParameterizedType) pType, startPoint)); + ParameterizedTypeRepository.registerParameterizedType(cType, (InterimParameterizedType) pType, ((InterimParameterizedType)pType).signature, startPoint); + } + res = (Type) cType; + } else if (pType instanceof InterimTypeVariable) { + String tvName = ((InterimTypeVariable) pType).typeVariableName; + TypeVariable variable = TypeVariableRepository.findTypeVariable(tvName, startPoint); + if (variable == null) { + variable = AuxiliaryFinder.findTypeVariable(tvName, startPoint); + if (variable == null) { + return (Type) null; + } + } + res = (Type) variable; + } else if (pType instanceof InterimWildcardType) { + WildcardType wType = WildcardTypeRepository.findWildcardType((InterimWildcardType) pType, WildcardTypeRepository.recoverWildcardSignature((InterimWildcardType) pType), startPoint); + if (wType == null) { + // The MalformedParameterizedTypeException and TypeNotPresentException should not be raised yet. + // These ones can be produced only via WildcardType.getUpperBounds() or WildcardType.getLowerBounds. + wType = new WildcardTypeImpl((InterimWildcardType) pType, startPoint); + WildcardTypeRepository.registerWildcardType(wType, (InterimWildcardType) pType, WildcardTypeRepository.recoverWildcardSignature((InterimWildcardType) pType), startPoint); + } + res = (Type) wType; + } else if (pType instanceof InterimGenericArrayType) { + res = AuxiliaryCreator.createGenericArrayType((InterimGenericArrayType)pType, startPoint); + } else { // ClassType + res = (Type) AuxiliaryLoader.ersatzLoader.findClass(((InterimClassType)pType).classTypeName.substring(1).replace('/', '.')); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + } + return res; + } + + /** + * This method creates an array of Type objects representing the actual type arguments to this type. + * + * @param ppType a parsered information produced from a parameterized type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return an array of Type objects representing the actual type arguments to this type. + */ + public static Type[] createTypeArgs(InterimParameterizedType ppType, Object startPoint) { + InterimType args[] = ppType.parameters; + if (args == null) { + return new Type[0]; + } + int len = args.length; + Type res[] = new Type[len]; + for (int i = 0; i < len; i++) { + try { + res[i] = createTypeArg(args[i], startPoint); + } catch(ClassNotFoundException e) { + throw new TypeNotPresentException(((InterimClassType)args[i]).classTypeName.substring(1).replace('/', '.'), e); // ClassNotFoundException may appear here only for InterimClassType, see AuxiliaryCreator.createTypeArg. + } + } + return res; + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryFinder.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryFinder.java new file mode 100644 index 0000000..a8b4345 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryFinder.java @@ -0,0 +1,442 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.support; + +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.TypeVariable; +import org.apache.harmony.lang.reflect.parser.InterimParameterizedType; +import org.apache.harmony.lang.reflect.parser.InterimGenericType; +import org.apache.harmony.lang.reflect.repository.TypeVariableRepository; + +import org.apache.harmony.lang.reflect.parser.*; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * Finder provides kinds of finding. + */ + +/* + * ------------------------------------------------------------------------------------------------ + * TODO list: + * 1. Maybe, the work with TypeVariableRepository (at least in this class) will be removed at all + * if it will be so inefficient as now (see the marked on left by /STARSTAR/ code introduced on Junuary 25, 2006 + * ------------------------------------------------------------------------------------------------ + */ +public final class AuxiliaryFinder { + + /** + * This method returns the generic class declaration which a parameterized type is derived from. + * + * @param fldType a parsered information produced from a parameterized type signature. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found generic declaration for this type variable definition or null + * if a generic declaration for this type variable does not exist at all. + */ + public static Class findGenericClassDeclarationForParameterizedType(InterimParameterizedType fldType, Object startPoint) throws ClassNotFoundException { + Class klass = null; + if((klass = verifyParameterizedType(fldType, startPoint)) != null) return klass; +//############################################################################################################################################ +// The below fragment seems not to work after verifyParameterizedType implementation and the just above code line insertion +// but it should be retained until being 100% aware (just though the incorrect basing on $ is used here): +//FRAGMENT START V + InterimType ownerType = fldType.ownerType; + String binaryClassName = null; + String tmp = fldType.rawType.classTypeName.substring(1).replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "." + int ind; + if((ind = tmp.lastIndexOf('$')) != -1) { + binaryClassName = tmp.substring(ind + 1); + } else { + binaryClassName = tmp; + } + while (ownerType != null && ownerType instanceof InterimParameterizedType) { + tmp = ((InterimParameterizedType)ownerType).rawType.classTypeName.substring(1).replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "." + if((ind = tmp.lastIndexOf('$')) != -1) { + tmp = tmp.substring(ind + 1); + } else { + } + binaryClassName = tmp+"$"+binaryClassName; + ownerType = ((InterimParameterizedType)ownerType).ownerType; + } + if (ownerType != null && ownerType instanceof InterimClassType) { + tmp = ((InterimClassType)ownerType).classTypeName.substring(1).replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "." + binaryClassName = tmp+"$"+binaryClassName; + } else if (ownerType != null) { // BUG + int i = 0, j = 1; i = j/i; + } + klass = AuxiliaryLoader.ersatzLoader.findClass(binaryClassName); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one? + return klass; //it may be null +//FRAGMENT FINISH ^ +//############################################################################################################################################ + } + + /** + * This method returns generic declaration where a type variable is defined in. + * + * @param typeVariableName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found generic declaration for this type variable definition or null + * if a generic declaration for this type variable does not exist at all. + */ + public static GenericDeclaration findGenericDeclarationForTypeVariable(String typeVariableName, Object startPoint) { + // XXX: redesign after debugging to join all the common places below: + if (startPoint instanceof Field) { + Class klass = ((Field)startPoint).getDeclaringClass(); + TypeVariable va[] = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) klass; + } + } + } else { + while (klass != null) { + klass = klass.getDeclaringClass(); + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)) { + return (GenericDeclaration) klass; + } + } + } + } + return null; + } + } else if (startPoint instanceof Method || startPoint instanceof Constructor) { + TypeVariable va[] = (startPoint instanceof Method ? (Method)startPoint : (Constructor)startPoint).getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) startPoint; + } + } + } else { + Class klass = (startPoint instanceof Method) ? ((Method)startPoint).getDeclaringClass() : ((Constructor)startPoint).getDeclaringClass(); + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) klass; + } + } + } else { + while (klass != null) { + klass = klass.getDeclaringClass(); + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) klass; + } + } + } + } + return null; + } + } + } else if (startPoint instanceof Class) { + Class klass = (Class)startPoint; + TypeVariable va[] = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) klass; + } + } + } else { + while (klass != null) { + klass = klass.getDeclaringClass(); + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + return (GenericDeclaration) klass; + } + } + } + } + return null; + } + } + return null; + } + + /** + * This method returns TypeVariable corresponding to the name of type variable in the current scope. + * + * @param typeVariableName a name of a type variable. + * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search + * of a type variable declaration place. + * @return the found type variable. + */ + public static TypeVariable findTypeVariable(String typeVariableName, Object startPoint) { + // XXX: redesign after debugging to join all the common places below: + if (startPoint instanceof Field) { + Class klass = ((Field)startPoint).getDeclaringClass(); + TypeVariable va[] = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + while (klass != null) { + klass = klass.getDeclaringClass(); + /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository.findTypeVariable(typeVariableName, klass); + /**/if (variable != null) { + /**/ return variable; + /**/} + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)) { + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + } + return null; + } else if (startPoint instanceof Method || startPoint instanceof Constructor) { + TypeVariable va[]; + if (startPoint instanceof Method) { + va = ((Method)startPoint).getTypeParameters(); + } else { + va = ((Constructor)startPoint).getTypeParameters(); + } + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(transform(typeVariableName))){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, startPoint) == null) { // Yes, it may be very inefficient now (for example, ((Constructor/Method)startPoint).getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, startPoint); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + Class klass = (startPoint instanceof Method) ? ((Method)startPoint).getDeclaringClass() : ((Constructor)startPoint).getDeclaringClass(); + if (startPoint instanceof Method) { + klass = ((Method)startPoint).getDeclaringClass(); + } else { + klass = ((Constructor)startPoint).getDeclaringClass(); + } + /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository.findTypeVariable(typeVariableName, klass); + /**/if (variable != null) { + /**/ return variable; + /**/} + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(transform(typeVariableName))){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + while (klass != null) { + klass = klass.getDeclaringClass(); + /**/variable = TypeVariableRepository.findTypeVariable(typeVariableName, klass); + /**/if (variable != null) { + /**/ return variable; + /**/} + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(transform(typeVariableName))){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + } + return null; + } else if (startPoint instanceof Class) { + Class klass = (Class)startPoint; + TypeVariable va[] = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + while (klass != null) { + klass = klass.getDeclaringClass(); + /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository.findTypeVariable(typeVariableName, klass); + /**/if (variable != null) { + /**/ return variable; + /**/} + va = klass.getTypeParameters(); + if (va != null) { + for(int i = 0; i < va.length; i++){ + if(va[i].getName().equals(typeVariableName)){ + /**/if (TypeVariableRepository.findTypeVariable(typeVariableName, klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but + /**/ // after all the TV-repository's functionality implementation + /**/ // it will be time to improvement. + /**/ TypeVariableRepository.registerTypeVariable(va[i], typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then + /**/ // it was removed (since we did not find it into the invoking method of this method look there at line with + /**/ // TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition). + /**/ // As a consequence, we should reregistry it again as long as it become so popular again + /**/} + return va[i]; + } + } + } + } + return null; + } + return null; + } + + /** + * This method transforms String with Utf8 to String without Utf8. + * + * @return the transformed string. + */ + public static String transform(String ini) { + int ind; + if ((ind = ini.indexOf("\\")) != -1) { + String res = ind == 0 ? "" : ini.substring(0, ind); + String di1 = ini.substring(ind+2, ind+2+2); // to ommit \0 + String di2 = ini.substring(ind+6, ind+6+2); // to ommit the following \0 + String di3; + if (Integer.parseInt(di1.substring(0, 1), 16) < 0xE) { // range 0x0080 - 0x07ff , for example: \0ce\091 + res = res + new String(new char[]{(char)(((Integer.parseInt(di1, 16)&0x1f)<<6)+(Integer.parseInt(di2, 16)&0x3f))}); + return res + transform(ini.substring(ind+8)); + } else if (Integer.parseInt(di1.substring(0, 1), 16) < 0xd800 || Integer.parseInt(di1.substring(0, 1), 16) > 0xdfff){ // range 0x0800 - 0xffff , for example: \0ef\0bf\08f + di3 = ini.substring(ind+10, ind+10+2); // to ommit the following \0 + res = res + new String(new char[]{(char)(((Integer.parseInt(di1, 16)&0xf)<<12)+((Integer.parseInt(di2, 16)&0x3f)<<6)+(Integer.parseInt(di3, 16)&0x3f))}); + return res + transform(ini.substring(ind+12)); + } else { // range 0x10000 - 0x10FFFF (high-surrogates range = 0xd800-0xdbff; low-surrogates range = 0xdc00-0xdfff; ) , for example: \0ed\0a0\0b5\0ed\0be\0af + di3 = ini.substring(ind+10, ind+10+2); // to ommit the following \0 + String di4 = ini.substring(ind+14, ind+14+2); // to ommit the following \0 + String di5 = ini.substring(ind+18, ind+18+2); // to ommit the following \0 + String di6 = ini.substring(ind+22, ind+22+2); // to ommit the following \0 + res = res + new String(new char[]{(char)((((Integer.parseInt(di2, 16)&0xf) + ((Integer.parseInt(di2, 16)&0xf)!=0?1:0))<<16)+((Integer.parseInt(di3, 16)&0x3f)<<10)+((Integer.parseInt(di5, 16)&0xf)<<6)+(Integer.parseInt(di6, 16)&0x3f))}); + return res + transform(ini.substring(ind+24)); + } + } + return ini; + } + + /** + * To use in findGenericClassDeclarationForParameterizedType method. + */ + private static Class verifyParameterizedType(InterimParameterizedType fldType, Object startPoint) throws ClassNotFoundException { + Class klass = AuxiliaryLoader.ersatzLoader.findClass(fldType.rawType.classTypeName.substring(1).replace('/', '.')/*fldType.rawType.classTypeName*/); + if (fldType.currentClauseName != null && fldType.currentClauseName.length() > 0) { + return klass; // has been verified + } + + if(!klass.isLocalClass() && !klass.isMemberClass()){ + return klass; + } + String snm = klass.getSimpleName(); // It must not be anonymous because it is the parameterised one. + int i = fldType.rawType.classTypeName.lastIndexOf("$"+snm); + if(i == -1){ + return klass; + } + String rtnm = fldType.rawType.classTypeName.substring(0, i); + InterimParameterizedType newPT = null; + + if (fldType.ownerType == null) { + try{ + if (AuxiliaryLoader.ersatzLoader.findClass(rtnm.substring(1).replace('/', '.')) != null){ + // telescoping a final unit: + InterimClassType newCT = new InterimClassType(); + newCT.classTypeName = rtnm; + fldType.ownerType = (InterimType) newCT; + } + } catch(ClassNotFoundException _) { + return null; + } + return klass; + } else { + if (!rtnm.equals((fldType.ownerType instanceof InterimParameterizedType ? ((InterimParameterizedType)fldType.ownerType).rawType.classTypeName : ((InterimClassType)fldType.ownerType).classTypeName))) { + try{ + if (AuxiliaryLoader.ersatzLoader.findClass(rtnm.substring(1).replace('/', '.')) != null){ + // telescoping an intermediate unit: + newPT = new InterimParameterizedType(); +/* ### */ newPT.signature = fldType.signature.substring(0, fldType.signature.lastIndexOf("$"+snm)); //XXX: ??? + newPT.currentClauseName = snm; + newPT.parameters = null; + newPT.rawType = new InterimClassType(); + newPT.rawType.classTypeName = rtnm; + newPT.ownerType = fldType.ownerType; + verifyParameterizedType(newPT, startPoint); + fldType.ownerType = newPT; + } + } catch(ClassNotFoundException _) { + return null; + } + } + return klass; + } + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryLoader.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryLoader.java new file mode 100644 index 0000000..7619d4d --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryLoader.java @@ -0,0 +1,150 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.lang.reflect.support; + +import java.security.AccessController; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ + +/** + * Loader provides access to some of finding. + * + * (This should be considered as a temporary decision. A correct approach + * in using loader facilities should be implemented later.) + */ +public final class AuxiliaryLoader extends ClassLoader { + public static final AuxiliaryLoader ersatzLoader = new AuxiliaryLoader(); + + public Class findClass(final String classTypeName) + throws ClassNotFoundException { + if (classTypeName.equals("byte")) { + return byte.class; + } else if (classTypeName.equals("char")) { + return char.class; + } else if (classTypeName.equals("double")) { + return double.class; + } else if (classTypeName.equals("float")) { + return float.class; + } else if (classTypeName.equals("int")) { + return int.class; + } else if (classTypeName.equals("long")) { + return long.class; + } else if (classTypeName.equals("short")) { + return short.class; + } else if (classTypeName.equals("boolean")) { + return boolean.class; + } else if (classTypeName.equals("void")) { + return void.class; + } + ClassLoader cl = this.getClass().getClassLoader(); + if (cl == null) { + cl = AuxiliaryLoader.this.getSystemClassLoader(); + } + try { + return cl.loadClass(classTypeName); + } catch (Throwable _) { + Class c = (Class) AccessController + .doPrivileged(new java.security.PrivilegedAction() { + public Object run() { + // based on an empiric knowledge + ClassLoader cl = AuxiliaryLoader.this + .getSystemClassLoader(); + try { + java.lang.reflect.Method[] ms = cl.getClass() + .getDeclaredMethods(); + int i = 0; + for (; i < ms.length; i++) { + if (ms[i].getName().equals("loadClass") + && ms[i].getParameterTypes().length == 2 + && ms[i].getParameterTypes()[0] + .getName().equals( + "java.lang.String") + && ms[i].getParameterTypes()[1] + .getName() + .equals("boolean")) { + break; + } + } + ms[i].setAccessible(true); + return (Object) ms[i] + .invoke( + (Object) cl, + new Object[] { + (Object) AuxiliaryFinder + .transform(classTypeName), + new Boolean(false) }); + } catch (java.lang.IllegalAccessException e) { + System.err + .println("Error: AuxiliaryLoader.findClass(" + + classTypeName + + "): " + + e.toString()); + e.printStackTrace(); + } catch (java.lang.reflect.InvocationTargetException e) { + System.err + .println("Error: AuxiliaryLoader.findClass(" + + classTypeName + + "): " + + e.getTargetException() + .toString()); + e.getTargetException().printStackTrace(); + } catch (Exception e) { + System.err + .println("Error: AuxiliaryLoader.findClass(" + + classTypeName + + "): " + + e.toString()); + e.printStackTrace(); + } + return null; + } + }); + if (c == null) + throw new ClassNotFoundException(classTypeName); + return c; + } + } + + public void resolve(final Class c) { + AccessController.doPrivileged(new java.security.PrivilegedAction() { + public Object run() { + ClassLoader cl = AuxiliaryLoader.this.getClass().getClassLoader(); + if (cl == null) { + cl = AuxiliaryLoader.this.getSystemClassLoader(); + } + try { + java.lang.reflect.Method[] ms = cl.getClass() + .getDeclaredMethods(); + int i = 0; + for (; i < ms.length; i++) { + if (ms[i].getName().equals("loadClass")) { + break; + } + } + ms[i].setAccessible(true); + ms[i].invoke((Object) cl, new Object[] { + (Object) c.getCanonicalName(), (Object) true }); + } catch (java.lang.IllegalAccessException _) { + } catch (java.lang.reflect.InvocationTargetException _) { + } + return null; + } + }); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryUtil.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryUtil.java new file mode 100644 index 0000000..1976786 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/lang/reflect/support/AuxiliaryUtil.java @@ -0,0 +1,94 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.lang.reflect.support; + +/** + * @author Serguei S. Zapreyev + * @version $Revision: 1.1.2.1 $ + */ +public final class AuxiliaryUtil { + + /** + * For temporary using until I has problem with Character.codePointAt(int) using. + */ +/**/ private static int codePointAt(char[] a, int index) { +/**/ int ch1 = a[index]; // NullPointerException or IndexOutOfBoundsException may be arisen here +/**/ if (ch1 >= 0xD800 && ch1 <= 0xDBFF) { +/**/ if (index++ < a.length) { +/**/ int ch2 = a[index]; +/**/ if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) { +/**/ return ((ch1 - 0xD800) << 10 | (ch2 - 0xDC00)) + 65536; +/**/ } +/**/ } +/**/ } +/**/ return ch1; +/**/ } + + /** + * To transform to UTF8 representation. + */ + public static String toUTF8(String ini) { + if (ini == null) return ini; + StringBuffer sb = new StringBuffer(); + int cp; + int dgt; +/**/ char ca[] = ini.toCharArray(); + for (int i = 0; i < ini.length(); ) { +/**/ //if((cp = ini.codePointAt(i)) <= '\u007F') { +/**/ if((cp = codePointAt(ca, i)) <= '\u007F') { + sb.append(Character.toString((char)cp)); + i++; + } else if (cp <= '\u07FF') { + sb.append("\\0"); + dgt = 0xC0 + ((cp & 0x7C0) >> 6); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0"); + dgt = 0x80 + (cp & 0x3F); + sb.append(Integer.toString(dgt, 16)); + i++; + } else if (cp <= '\uFFFF') { + sb.append("\\0"); + dgt = 0xE0 + ((cp & 0xF000) >> 12); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0"); + dgt = 0x80 + ((cp & 0xFC0) >> 6); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0"); + dgt = 0x80 + (cp & 0x3F); + sb.append(Integer.toString(dgt, 16)); + i++; + } else { // > '\uFFFF' + sb.append("\\0ED"); + sb.append("\\0"); + dgt = 0xA0 + (((cp & 0xF0000) >> 16) - 1); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0"); + dgt = 0x80 + ((cp & 0xFC00) >> 10); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0ED"); + sb.append("\\0"); + dgt = 0xB0 + ((cp & 0x3C0) >> 6); + sb.append(Integer.toString(dgt, 16)); + sb.append("\\0"); + dgt = 0x80 + (cp & 0x3F); + sb.append(Integer.toString(dgt, 16)); + i += 2; + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/misc/EmptyEnum.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/misc/EmptyEnum.java index 5ea6f44..6508d85 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/misc/EmptyEnum.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/misc/EmptyEnum.java @@ -22,14 +22,15 @@ import java.util.NoSuchElementException; * @author Evgueni Brevnov, Roman S. Bushmanov * @version $Revision: 1.1.6.4 $ */ -public class EmptyEnum implements Enumeration { +public class EmptyEnum<T> implements Enumeration<T> { private static EmptyEnum emptyEnum; private EmptyEnum() { } - public static Enumeration getInstance() { + @SuppressWarnings("unchecked") + public static <U> Enumeration<U> getInstance() { if (emptyEnum == null) { emptyEnum = new EmptyEnum(); } @@ -40,7 +41,7 @@ public class EmptyEnum implements Enumer return false; } - public Object nextElement() throws NoSuchElementException { + public T nextElement() throws NoSuchElementException { throw new NoSuchElementException(); } } diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/ClassFormat.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/ClassFormat.java new file mode 100644 index 0000000..5d1de8f --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/ClassFormat.java @@ -0,0 +1,37 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.vm; + +/** + * + * + * @author Alexey V. Varlamov + * @version $Revision$ + */ +public class ClassFormat { + + public static final int ACC_BRIDGE = 0x0040; + + public static final int ACC_VARARGS = 0x0080; + + public static final int ACC_SYNTHETIC = 0x1000; + + public static final int ACC_ENUM = 0x4000; + + public static final int ACC_ANNOTATION = 0x2000; + + public static final int ACC_INTERFACE = 0x0200; +} diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMGenericsAndAnnotations.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMGenericsAndAnnotations.java new file mode 100644 index 0000000..1171d02 --- /dev/null +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMGenericsAndAnnotations.java @@ -0,0 +1,136 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.vm; + +import java.lang.annotation.Annotation; + +/** + * Provides the methods to get signatures used to encode Java programming + * language type information such as generic type and method declarations and + * parameterized types. + * <p> + * Provides also the methods to get annotations and their elements values. + * <p> + * This class must be implemented according to the common policy for porting + * interfaces - see the porting interface overview for more detailes. + * + * @author Serguei S. Zapreyev, Alexey V. Varlamov + * @version $Revision$ + * + * @api2vm + */ +public final class VMGenericsAndAnnotations { + + /** + * This class is not supposed to be instantiated. + */ + private VMGenericsAndAnnotations() { + } + + /** + * This method returns the String representation of a Signature + * attribute corresponding to {@link Method}, {@link Constructor} + * or {@link Field} object declaration. + * <p> + * @param id an identifier of a reflection member. + * @return the String representation of a Signature attribute or null + * if a caller's declaration does not use any generics. + * + * @api2vm + */ + public static native String getSignature(long id); + + /** + * This method returns the String representation of a Signature + * attribute corresponding to {@link Class} object declaration. + * <p> + * @param cls a class to be reflected. + * @return the String representation of a Signature attribute or null + * if a caller's declaration does not use any generics. + * + * @api2vm + */ + public static native String getSignature(Class cls); + + /** + * This method satisfies the requirements of the specification for the + * {@link Field#getDeclaredAnnotations() Field.getDeclaredAnnotations()}, + * {@link Method#getDeclaredAnnotations() Method.getDeclaredAnnotations()}, + * {@link Constructor#getDeclaredAnnotations() + * Constructor.getDeclaredAnnotations()} methods. + * <p> + * @param id an identifier of the caller (Field, or Method, + * or Constructor type). + * @return all annotations directly present on this element or zero-sized + * array if there are no annotations. + * @throws TypeNotPresentException if enum-valued or nested annotation member + * (of an annotation) refers to a class that is not accessible. + * @throws AnnotationFormatError if reading an annotation from a class file + * determines that the annotation is malformed. + * @api2vm + */ + public static native Annotation[] getDeclaredAnnotations(long id); + + /** + * This method satisfies the requirements of the specification for the + * {@link Class#getDeclaredAnnotations() Class.getDeclaredAnnotations()}. + * <p> + * @param clss annotated element of the Class type + * @return all annotations directly present on this element or zero-sized + * array if there are no annotations. + * @throws TypeNotPresentException if enum-valued or nested annotation member + * (of an annotation) refers to a class that is not accessible. + * @throws AnnotationFormatError if reading an annotation from a class file + * determines that the annotation is malformed. + * @api2vm + */ + public static native Annotation[] getDeclaredAnnotations(Class clss); + + /** + * This method satisfies the requirements of the specification for the + * {@link Method#getParameterAnnotations() Method.getParameterAnnotations()} + * and {@link Constructor#getParameterAnnotations() + * Constructor.getParameterAnnotations()} methods. + * <p> + * @param id an identifier of the caller (annotated element of the Method + * or Constructor type) class. + * @return an array of arrays that represent the annotations on the formal + * parameters, in declaration order, of the method represented by + * this Method object. Returns an array of length zero if the underlying method has + * no parameters. If the method has a parameter or more, a nested array of length + * zero is returned for each parameter with no annotations. + * @throws TypeNotPresentException if Class-valued member (of an annotation) + * referring to a class that is not accessible in this VM. + * @api2vm + */ + public static native Annotation[][] getParameterAnnotations(long id); + + /** + * This method satisfies the requirements of the specification for the + * {@link Method#getDefaultValue() Method.getDefaultValue()} method. + * But it takes one additional id parameter. + * <p> + * @param id an identifier of the caller (annotated element of the Method + * type) class. + * @return the default value for the annotation member represented by this + * Method instance or null. + * @throws TypeNotPresentException if the annotation is of type Class and + * no definition can be found for the default class value + * + * @api2vm + */ + public static native Object getDefaultValue(long id); +} diff --git vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java index 9d8a3eb..eb50fc4 100644 --- vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java +++ vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java @@ -119,4 +119,6 @@ public final class VMStack { * @api2vm */ static native ClassLoader getClassLoader(Class<?> clazz); + + public static native StackTraceElement[] getThreadStackTrace(Thread t); } diff --git vm/vmcore/src/kernel_classes/native/Runtime_lnx.cpp vm/vmcore/src/kernel_classes/native/Runtime_lnx.cpp index 9e122f8..398a801 100644 --- vm/vmcore/src/kernel_classes/native/Runtime_lnx.cpp +++ vm/vmcore/src/kernel_classes/native/Runtime_lnx.cpp @@ -163,8 +163,7 @@ void JNICALL Java_java_lang_Runtime_0002 if (envp != NULL) { lenEnvp += env->GetArrayLength(envp); } - int lenstrEnvpBeginAA = lenEnvp + 1; - char *strEnvpBeginAA[lenstrEnvpBeginAA]; + char *strEnvpBeginAA[lenEnvp + 1]; if (envp != NULL) { for ( i = 0; i < lenEnvp; i++ ) { jo = env->GetObjectArrayElement((jobjectArray)((jobject)envp), (jsize) i); @@ -177,14 +176,34 @@ void JNICALL Java_java_lang_Runtime_0002 } } - strEnvpBeginAA[lenstrEnvpBeginAA] = (char *) 0; // NULL pointer + strEnvpBeginAA[lenEnvp] = (char *) 0; // NULL pointer if (lenEnvp == 0) { execvp(argv[0], argv); } else { execve(argv[0], argv, strEnvpBeginAA); - // FIXME: fixme not strictly correct - execvp(argv[0], argv); + if(strchr(argv[0], '/') == NULL) { + char* curDir = NULL; + char* cmdPath = NULL; + char* dirs = NULL; + if ((dirs = getenv("PATH")) != NULL) { + int len = 0; + curDir = strtok(dirs, ":"); + while(curDir != NULL) { + if((len = strlen(curDir)) != 0) { + cmdPath = (char *)malloc(len+1+strlen(argv[0])+1); + *cmdPath = '\0'; + strcat(strcat(strcat(cmdPath, curDir), "/"), argv[0]); + if (fopen(cmdPath, "r") != NULL) { + execve(cmdPath, argv, strEnvpBeginAA); + //XXX: should we inform only of a last error among all possible execve atempts? + } + free(cmdPath); + } + curDir = strtok(NULL, ":"); + } + } + } } write(fildesInfo[1], &errno, sizeof(int)); INFO("Process initiation failed: " << strerror(errno)); diff --git vm/vmcore/src/kernel_classes/native/System_lnx.cpp vm/vmcore/src/kernel_classes/native/System_lnx.cpp deleted file mode 100644 index 295450f..0000000 --- vm/vmcore/src/kernel_classes/native/System_lnx.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Roman S. Bushmanov - * @version $Revision: 1.1.2.1.4.3 $ - */ - -#include <sys/time.h> -#include "java_lang_System.h" - -static jlong init_sec = 0; - -JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis - (JNIEnv *env, jclass clazz){ - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - - jlong retval = tv.tv_usec / 1000; - retval += (jlong)tv.tv_sec * 1000; - - return retval; -} - -JNIEXPORT jlong JNICALL Java_java_lang_System_nanoTime(JNIEnv *env, jclass cls){ - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - - return (jlong)(((jlong)tv.tv_sec - init_sec) * 1E9 + (jlong)tv.tv_usec * 1E3); -} - -JNIEXPORT void JNICALL Java_java_lang_System_initNanoTime(JNIEnv *env, jclass cls){ - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - - init_sec = tv.tv_sec; -} diff --git vm/vmcore/src/kernel_classes/native/System_win.cpp vm/vmcore/src/kernel_classes/native/System_win.cpp deleted file mode 100644 index f5c6c45..0000000 --- vm/vmcore/src/kernel_classes/native/System_win.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Roman S. Bushmanov - * @version $Revision: 1.1.2.1.4.3 $ - */ - -#include <time.h> -#include <windows.h> -#include <winbase.h> -#include "java_lang_System.h" - -static int supported = 0; -static double frequency; - -JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis - (JNIEnv *env, jclass clazz){ - - static jlong start_time_millis = 0; - - if (start_time_millis == 0){ - jlong tick_count = GetTickCount(); - jlong millis = tick_count % 1000; - jlong start_time = (jlong)time(0) * 1000; - start_time_millis = start_time - tick_count + millis; - return start_time + millis; - } - - return start_time_millis + GetTickCount(); -} - -JNIEXPORT jlong JNICALL Java_java_lang_System_nanoTime - (JNIEnv *env, jclass cls){ - if(supported){ - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return (jlong)((double)count.QuadPart / frequency * 1E9); - } - return (jlong)(GetTickCount() * 1E6); -} - - -JNIEXPORT void JNICALL Java_java_lang_System_initNanoTime - (JNIEnv *env, jclass cls){ - LARGE_INTEGER freq; - supported = QueryPerformanceFrequency(&freq); - if (supported){ - frequency = (double)freq.QuadPart; - } -} - diff --git vm/vmcore/src/kernel_classes/native/java_lang_Class.cpp vm/vmcore/src/kernel_classes/native/java_lang_Class.cpp deleted file mode 100644 index 412b9ab..0000000 --- vm/vmcore/src/kernel_classes/native/java_lang_Class.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Euguene Ostrovsky - * @version $Revision: 1.1.2.2.4.4 $ - */ - -/** - * @file java_lang_Class.cpp - * - * This file is a part of kernel class natives VM core component. - * It contains implementation for native methods of - * java.lang.Class kernel class. - */ - -#include "org_apache_harmony_vm_VMStack.h" - -#include "java_lang_Class.h" - -JNIEXPORT jobjectArray JNICALL Java_java_lang_Class_getStackClasses - (JNIEnv *jenv_ext, jclass, jint maxSize, jboolean considerPrivileged) -{ - // reuse similar method of org.apache.harmony.drl.vm.VMStack class - return Java_org_apache_harmony_vm_VMStack_getClasses(jenv_ext, NULL, maxSize, considerPrivileged); -} diff --git vm/vmcore/src/kernel_classes/native/java_lang_Class.h vm/vmcore/src/kernel_classes/native/java_lang_Class.h deleted file mode 100644 index 5de065a..0000000 --- vm/vmcore/src/kernel_classes/native/java_lang_Class.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Euguene Ostrovsky - * @version $Revision: 1.1.2.1.4.6 $ - */ - -/* - * THE FILE HAS BEEN AUTOGENERATED BY INTEL IJH TOOL. - * Please be aware that all changes made to this file manually - * will be overwritten by the tool if it runs again. - */ - -#include <jni.h> - - -/* Header for class java.lang.Class */ - -#ifndef _JAVA_LANG_CLASS_H -#define _JAVA_LANG_CLASS_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Static final fields */ - -#undef java_lang_Class_serialVersionUID -#define java_lang_Class_serialVersionUID 3206093459760846163LL - - -/* Native methods */ - -/* - * Method: java.lang.Class.getStackClasses(IZ)[Ljava/lang/Class; - */ -JNIEXPORT jobjectArray JNICALL -Java_java_lang_Class_getStackClasses(JNIEnv *, jclass, - jint, jboolean); - - -#ifdef __cplusplus -} -#endif - -#endif /* _JAVA_LANG_CLASS_H */ - diff --git vm/vmcore/src/kernel_classes/native/java_lang_System.cpp vm/vmcore/src/kernel_classes/native/java_lang_System.cpp index 8babdd0..f990063 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_System.cpp +++ vm/vmcore/src/kernel_classes/native/java_lang_System.cpp @@ -18,8 +18,6 @@ * @version $Revision: 1.1.2.1.4.3 $ */ -#include <stdlib.h> -#include <string.h> #include "java_lang_System.h" JNIEXPORT void JNICALL Java_java_lang_System_setErrUnsecure @@ -40,36 +38,6 @@ (JNIEnv *env, jclass clazz, jobject out) env->SetStaticObjectField(clazz, field_id, out); } -extern char **environ; - -JNIEXPORT jobject JNICALL Java_java_lang_System_getenvUnsecure__ -(JNIEnv *env, jclass clazz){ - jclass cls = env->FindClass("java/util/Hashtable"); - jmethodID ctr = env->GetMethodID(cls, "<init>", "()V"); - jmethodID mtd = env->GetMethodID(cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - jobject ret = env->NewObject(cls, ctr); - for (char **e = environ ; *e; ++e){ - int idx = strcspn(*e, "="); - char* key = new char[idx+1]; - strncpy(key, *e, idx); - key[idx]='\0'; - env->CallObjectMethod(ret, mtd, env->NewStringUTF(key), env->NewStringUTF(*e+idx+1)); - delete [] key; - } - return ret; -} - -JNIEXPORT jstring JNICALL Java_java_lang_System_getenvUnsecure__Ljava_lang_String_2 -(JNIEnv *env, jclass clazz, jstring name){ - const char *str = env->GetStringUTFChars(name, 0); - char *buf = getenv(str); - env->ReleaseStringUTFChars(name, str); - if (buf == NULL){ - return 0; - } - return env->NewStringUTF(buf); -} - JNIEXPORT void JNICALL Java_java_lang_System_rethrow (JNIEnv *env, jclass clazz, jthrowable thr){ env->Throw(thr); diff --git vm/vmcore/src/kernel_classes/native/java_lang_System.h vm/vmcore/src/kernel_classes/native/java_lang_System.h index 44136d5..4787de9 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_System.h +++ vm/vmcore/src/kernel_classes/native/java_lang_System.h @@ -41,18 +41,6 @@ #endif /* Native methods */ /* - * Method: java.lang.System.currentTimeMillis()J - */ -JNIEXPORT jlong JNICALL -Java_java_lang_System_currentTimeMillis(JNIEnv *, jclass); - -/* - * Method: java.lang.System.nanoTime()J - */ -JNIEXPORT jlong JNICALL -Java_java_lang_System_nanoTime(JNIEnv *, jclass); - -/* * Method: java.lang.System.setErrUnsecure(Ljava/io/PrintStream;)V */ JNIEXPORT void JNICALL @@ -74,25 +62,6 @@ Java_java_lang_System_setOutUnsecure(JNI jobject); /* - * Method: java.lang.System.getenvUnsecure()Ljava/util/Map; - */ -JNIEXPORT jobject JNICALL -Java_java_lang_System_getenvUnsecure__(JNIEnv *, jclass); - -/* - * Method: java.lang.System.getenvUnsecure(Ljava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL -Java_java_lang_System_getenvUnsecure__Ljava_lang_String_2(JNIEnv *, jclass, - jstring); - -/* - * Method: java.lang.System.initNanoTime()V - */ -JNIEXPORT void JNICALL -Java_java_lang_System_initNanoTime(JNIEnv *, jclass); - -/* * Method: java.lang.System.rethrow(Ljava/lang/Throwable;)V */ JNIEXPORT void JNICALL diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.cpp vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.cpp index 9e66df9..331255c 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.cpp +++ vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.cpp @@ -49,19 +49,22 @@ JNIEXPORT jclass JNICALL Java_java_lang_ const char* clssname = NULL; // obtain char * for the name if provided - if(name) + if(name) { clssname = GetStringUTFChars(jenv, name, NULL); - - if (name && NULL != strchr(clssname, '/')) - { - std::stringstream ss; - ss << "The name is expected in binary (canonical) form," - " therefore '/' symbols are not allowed: " << clssname; - - exn_raise_only( - exn_create("java/lang/NoClassDefFoundError", ss.str().c_str())); - - return NULL; + if (NULL != strchr(clssname, '/')) + { + std::stringstream ss; + ss << "The name is expected in binary (canonical) form," + " therefore '/' symbols are not allowed: " << clssname; + + ReleaseStringUTFChars(jenv, name, clssname); + exn_raise_object( + exn_create( + VM_Global_State::loader_env->JavaLangNoClassDefFoundError_String->bytes, + ss.str().c_str())); + + return NULL; + } } // obtain raw classfile data data pointer @@ -89,6 +92,8 @@ JNIEXPORT jclass JNICALL Java_java_lang_ JNIEXPORT jclass JNICALL Java_java_lang_VMClassRegistry_findLoadedClass (JNIEnv *jenv_ext, jclass, jstring name, jobject cl) { + ASSERT_RAISE_AREA; + // check the name is provided if (name == NULL) { ThrowNew_Quick(jenv_ext, "java/lang/NullPointerException", "null class name value."); @@ -329,6 +334,7 @@ JNIEXPORT jint JNICALL Java_java_lang_VM JNIEXPORT jstring JNICALL Java_java_lang_VMClassRegistry_getName (JNIEnv *jenv, jclass, jclass clazz) { + ASSERT_RAISE_AREA; Class* clss = jclass_to_struct_Class(clazz); String* str = class_get_java_name(clss, VM_Global_State::loader_env); return String_to_interned_jstring(str); @@ -418,6 +424,7 @@ JNIEXPORT jobjectArray JNICALL Java_java JNIEXPORT void JNICALL Java_java_lang_VMClassRegistry_initializeClass (JNIEnv *jenv, jclass unused, jclass clazz) { + ASSERT_RAISE_AREA; Class *clss = jni_get_class_handle(jenv, clazz); Java_java_lang_VMClassRegistry_linkClass(jenv, unused, clazz); if(jenv->ExceptionCheck()) @@ -484,18 +491,6 @@ JNIEXPORT jboolean JNICALL Java_java_lan /* * Class: java_lang_VMClassRegistry - * Method: isInterface - * Signature: (Ljava/lang/Class;)Z - */ -JNIEXPORT jboolean JNICALL Java_java_lang_VMClassRegistry_isInterface - (JNIEnv *jenv, jclass, jclass clazz) -{ - Class_Handle clss = jni_get_class_handle(jenv, clazz); - return (jboolean)(class_property_is_interface2(clss) ? JNI_TRUE : JNI_FALSE); -} - -/* - * Class: java_lang_VMClassRegistry * Method: isPrimitive * Signature: (Ljava/lang/Class;)Z */ @@ -571,3 +566,90 @@ JNIEXPORT void JNICALL Java_java_lang_VM // release char string ReleaseStringUTFChars(jenv, filename, str_filename); } + +/* +* Class: java_lang_VMClassRegistry +* Method: getEnclosingClass +* Signature: (Ljava/lang/Class;)Ljava/lang/Class; +*/ +JNIEXPORT jclass JNICALL Java_java_lang_VMClassRegistry_getEnclosingClass +(JNIEnv *, jclass, jclass jclazz) +{ + assert(jclazz); + Class* clazz = jclass_to_struct_Class(jclazz); + unsigned idx = clazz->enclosing_class_index; + if (!idx) { + idx = clazz->declaringclass_index; + } + if (idx) { + Class* outer_clss = class_resolve_class(clazz, idx); + if (outer_clss) { + return struct_Class_to_java_lang_Class_Handle(outer_clss); + } + if (!exn_raised()) { + exn_raise_object(class_get_linking_error(clazz, idx)); + } + } + return NULL; +} + +/* +* Class: java_lang_VMClassRegistry +* Method: getEnclosingMember +* Signature: (Ljava/lang/Class;)Ljava/lang/reflect/Member; +*/ +JNIEXPORT jobject JNICALL Java_java_lang_VMClassRegistry_getEnclosingMember +(JNIEnv *jenv, jclass, jclass jclazz) +{ + assert(jclazz); + Class* clazz = jclass_to_struct_Class(jclazz); + unsigned m_idx = clazz->enclosing_method_index; + if (m_idx) { + unsigned c_idx = clazz->enclosing_class_index; + ASSERT(c_idx, "No class for enclosing method"); + Class* outer_clss = class_resolve_class(clazz, c_idx); + if (outer_clss) + { + String* name = clazz->const_pool[m_idx].CONSTANT_NameAndType.name; + String* desc = clazz->const_pool[m_idx].CONSTANT_NameAndType.descriptor; + + TRACE("Looking for enclosing method: class="<<outer_clss->name->bytes + <<"; name="<<name->bytes<<"; desc="<<desc->bytes); + + Method* enclosing = class_lookup_method(outer_clss, name, desc); + if (enclosing) + { + if (enclosing->is_init()) + { + return reflection_reflect_constructor(jenv, enclosing); + } + else if (!enclosing->is_clinit()) + { + return reflection_reflect_method(jenv, enclosing); + } + } else { + //FIXME: check RI compatibility, provide detailed message + ThrowNew_Quick(jenv, "java/lang/NoSuchMethodException", + "Invalid enclosing method declared"); + } + } else if (!exn_raised()) { + exn_raise_object(class_get_linking_error(clazz, c_idx)); + } + } + return NULL; +} + +/* +* Class: java_lang_VMClassRegistry +* Method: getSimpleName +* Signature: (Ljava/lang/Class;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMClassRegistry_getSimpleName +(JNIEnv *, jclass, jclass jclazz) +{ + ASSERT_RAISE_AREA; + assert(jclazz); + Class* clazz = jclass_to_struct_Class(jclazz); + String* str = class_get_simple_name(clazz, VM_Global_State::loader_env); + return str ? String_to_interned_jstring(str) : NULL; +} diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.h vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.h index f5b2f07..3f020eb 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.h +++ vm/vmcore/src/kernel_classes/native/java_lang_VMClassRegistry.h @@ -175,13 +175,6 @@ Java_java_lang_VMClassRegistry_isInstanc jclass, jobject); /* - * Method: java.lang.VMClassRegistry.isInterface(Ljava/lang/Class;)Z - */ -JNIEXPORT jboolean JNICALL -Java_java_lang_VMClassRegistry_isInterface(JNIEnv *, jclass, - jclass); - -/* * Method: java.lang.VMClassRegistry.isPrimitive(Ljava/lang/Class;)Z */ JNIEXPORT jboolean JNICALL @@ -209,6 +202,23 @@ JNIEXPORT void JNICALL Java_java_lang_VMClassRegistry_loadLibrary(JNIEnv *, jclass, jstring, jobject); +/* +* Method: java.lang.VMClassRegistry.getEnclosingClass(Ljava/lang/Class;)Ljava/lang/Class; +*/ +JNIEXPORT jclass JNICALL Java_java_lang_VMClassRegistry_getEnclosingClass +(JNIEnv *, jclass, jclass); + +/* +* Method: java.lang.VMClassRegistry.getEnclosingMember(Ljava/lang/Class;)Ljava/lang/reflect/Member; +*/ +JNIEXPORT jobject JNICALL Java_java_lang_VMClassRegistry_getEnclosingMember +(JNIEnv *, jclass, jclass); + +/* +* Method: java.lang.VMClassRegistry.getSimpleName(Ljava/lang/Class;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMClassRegistry_getSimpleName +(JNIEnv *, jclass, jclass); #ifdef __cplusplus } diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.cpp vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.cpp old mode 100644 new mode 100755 index e3118c1..1a09eeb --- vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.cpp +++ vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.cpp @@ -26,13 +26,24 @@ * java.lang.VMExecutionEngine class. */ +#define LOG_DOMAIN "vm.kernel" +#include "cxxlog.h" + +#include <apr_env.h> #include <apr_file_io.h> -#include "environment.h" +#include <apr_time.h> + +#include "port_dso.h" +#include "port_env.h" #include "port_filepath.h" #include "port_sysinfo.h" +#include "port_timer.h" +#include "environment.h" #include "jni_utils.h" #include "properties.h" +#include "exceptions.h" #include "java_lang_VMExecutionEngine.h" +#include "assertion_registry.h" /* * Class: java_lang_VMExecutionEngine @@ -66,12 +77,53 @@ JNIEXPORT void JNICALL Java_java_lang_VM /* * Class: java_lang_VMExecutionEngine * Method: getAssertionStatus - * Signature: (Ljava/lang/String;)I + * Signature: (Ljava/lang/Class;ZI)I */ JNIEXPORT jint JNICALL Java_java_lang_VMExecutionEngine_getAssertionStatus - (JNIEnv *, jclass, jstring) + (JNIEnv * jenv, jclass, jclass jclss, jboolean recursive, jint defaultStatus) { - return 0; + Assertion_Status status = ASRT_UNSPECIFIED; + Global_Env* genv = ((JNIEnv_Internal*)jenv)->vm->vm_env; + Assertion_Registry* reg = genv->assert_reg; + if (!reg) { + return status; + } + + if(jclss) { + Class* clss = jclass_to_struct_Class(jclss); + while (clss->declaringclass_index) { + clss = class_get_declaring_class((Class_Handle)clss); + } + const char* name = class_get_java_name(clss, genv)->bytes; + bool system = (((void*)clss->class_loader) == ((void*)genv->bootstrap_class_loader)); + TRACE("check assert status for " << name << " system=" << system); + if (system || !recursive) { + status = reg->get_class_status(name); + } + TRACE("name checked: " << status); + if (recursive || system) { + if (status == ASRT_UNSPECIFIED) { + status = reg->get_package_status(name); + } + TRACE("pkg checked: " << status); + if (status == ASRT_UNSPECIFIED) { + if (defaultStatus != ASRT_UNSPECIFIED) { + status = (Assertion_Status)defaultStatus; + } else { + status = reg->is_enabled(system); + } + } + TRACE("default checked: " << status); + } + } else { + if (reg->classes || reg->packages || reg->enable_system) { + status = ASRT_ENABLED; + } else { + status = reg->enable_all; + } + } + TRACE("Resulting assertion status: " << status); + return status; } /* @@ -88,10 +140,12 @@ JNIEXPORT jint JNICALL Java_java_lang_VM /** * Adds property specified by key and val parameters to given Properties object. */ -static void PropPut(JNIEnv* jenv, jobject properties, const char* key, const char* val) +static bool PropPut(JNIEnv* jenv, jobject properties, const char* key, const char* val) { jobject key_string = NewStringUTF(jenv, key); + if (!key_string) return false; jobject val_string = val ? NewStringUTF(jenv, val) : NULL; + if (val && !val_string) return false; static jmethodID put_method = NULL; if (!put_method) { @@ -103,35 +157,14 @@ static void PropPut(JNIEnv* jenv, jobjec } CallObjectMethod(jenv, properties, put_method, key_string, val_string); + return !exn_raised(); } -static void insertSystemProperties(JNIEnv *jenv, jobject pProperties) +static void insertSystemProperties(JNIEnv *jenv, jobject pProperties, apr_pool_t *pp) { - static apr_pool_t *pp; - if (!pp) { - apr_pool_create(&pp, 0); - } - - // Now, insert all the default properties. - PropPut(jenv, pProperties, "user.language", "en"); - PropPut(jenv, pProperties, "user.region", "US"); - PropPut(jenv, pProperties, "file.encoding", "8859_1"); - //PropPut(jenv, pProperties, "file.encoding", apr_os_default_encoding(p)); - - PropPut(jenv, pProperties, "file.separator", PORT_FILE_SEPARATOR_STR); - PropPut(jenv, pProperties, "path.separator", PORT_PATH_SEPARATOR_STR); - PropPut(jenv, pProperties, "line.separator", APR_EOL_STR); - PropPut(jenv, pProperties, "os.arch", port_CPU_architecture()); - - char *os_name, *os_version; + char *os_name, *os_version, *path; port_OS_name_version(&os_name, &os_version, pp); - PropPut(jenv, pProperties, "os.name", os_name); - PropPut(jenv, pProperties, "os.version", os_version); - PropPut(jenv, pProperties, "java.vendor.url", "http://www.intel.com/"); - - char *path; apr_filepath_get(&path, APR_FILEPATH_NATIVE, pp); - PropPut(jenv, pProperties, "user.dir", path); const char *tmp; if (APR_SUCCESS != apr_temp_dir_get(&tmp, pp)) { tmp = "."; @@ -145,14 +178,33 @@ static void insertSystemProperties(JNIEn // TODO : fix this - it should come from Class.h PropPut(jenv, pProperties, "java.class.version", "49.0"); - //VM specified/APP specified properties are supported here. + // First, insert all the default properties. + if (!PropPut(jenv, pProperties, "user.language", "en") + || !PropPut(jenv, pProperties, "user.region", "US") + || !PropPut(jenv, pProperties, "file.encoding", "8859_1") + //PropPut(jenv, pProperties, "file.encoding", apr_os_default_encoding(p)); + || !PropPut(jenv, pProperties, "file.separator", PORT_FILE_SEPARATOR_STR) + || !PropPut(jenv, pProperties, "path.separator", PORT_PATH_SEPARATOR_STR) + || !PropPut(jenv, pProperties, "line.separator", APR_EOL_STR) + || !PropPut(jenv, pProperties, "os.arch", port_CPU_architecture()) + || !PropPut(jenv, pProperties, "os.name", os_name) + || !PropPut(jenv, pProperties, "os.version", os_version) + || !PropPut(jenv, pProperties, "java.vendor.url", "http://www.intel.com/") + || !PropPut(jenv, pProperties, "user.dir", path) + || !PropPut(jenv, pProperties, "java.tmpdir", tmp) + || !PropPut(jenv, pProperties, "java.class.version", "49.0") ) + { + return; + } + + // Next, add runtime specified properties. Properties::Iterator *iterator = VM_Global_State::loader_env->properties.getIterator(); const Prop_entry *next = NULL; while((next = iterator->next())){ - PropPut(jenv, pProperties, next->key, ((Prop_String*)next->value)->value); + if (!PropPut(jenv, pProperties, next->key, ((Prop_String*)next->value)->value)){ + break; + } } - - apr_pool_clear(pp); } //insertSystemProperties /* @@ -166,8 +218,13 @@ JNIEXPORT jobject JNICALL Java_java_lang jobject jprops = create_default_instance( VM_Global_State::loader_env->java_util_Properties_Class); - // set default VM properties - insertSystemProperties(jenv, jprops); + if (jprops) { + apr_pool_t *pp; + if (APR_SUCCESS == apr_pool_create(&pp, 0)) { + insertSystemProperties(jenv, jprops, pp); + apr_pool_destroy(pp); + } + } return jprops; } @@ -178,8 +235,9 @@ JNIEXPORT jobject JNICALL Java_java_lang * Signature: (Z)V */ JNIEXPORT void JNICALL Java_java_lang_VMExecutionEngine_traceInstructions - (JNIEnv *, jclass, jboolean) + (JNIEnv *jenv, jclass, jboolean) { + //ThrowNew_Quick(jenv, "java/lang/UnsupportedOperationException", NULL); return; } @@ -189,7 +247,102 @@ JNIEXPORT void JNICALL Java_java_lang_VM * Signature: (Z)V */ JNIEXPORT void JNICALL Java_java_lang_VMExecutionEngine_traceMethodCalls - (JNIEnv *, jclass, jboolean) + (JNIEnv *jenv, jclass, jboolean) { + //ThrowNew_Quick(jenv, "java/lang/UnsupportedOperationException", NULL); return; } + +/* +* Class: java_lang_VMExecutionEngine +* Method: currentTimeMillis +* Signature: ()J +*/ +JNIEXPORT jlong JNICALL Java_java_lang_VMExecutionEngine_currentTimeMillis +(JNIEnv *, jclass) { + return apr_time_now()/1000; +} + +/* +* Class: java_lang_VMExecutionEngine +* Method: nanoTime +* Signature: ()J +*/ +JNIEXPORT jlong JNICALL Java_java_lang_VMExecutionEngine_nanoTime +(JNIEnv *, jclass) { + return port_nanotimer(); +} + +/* +* Class: java_lang_VMExecutionEngine +* Method: getenv +* Signature: (Ljava/lang/String;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMExecutionEngine_getenv__Ljava_lang_String_2 +(JNIEnv *jenv, jclass, jstring jname) { + jstring res = NULL; + if(jname) { + const char* key = GetStringUTFChars(jenv, jname, NULL); + apr_pool_t *pp; + char* value; + if (APR_SUCCESS == apr_pool_create(&pp, 0) + && APR_SUCCESS == apr_env_get(&value, key, pp)) { + res = NewStringUTF(jenv, value); + apr_pool_destroy(pp); + } + ReleaseStringUTFChars(jenv, jname, key); + } + return res; +} + +/* +* Class: java_lang_VMExecutionEngine +* Method: getenv +* Signature: ()Ljava/util/Map; +*/ +JNIEXPORT jobject JNICALL Java_java_lang_VMExecutionEngine_getenv__ +(JNIEnv *jenv, jclass) { + Global_Env * genv = VM_Global_State::loader_env; + Class* mapClass = genv->LoadCoreClass("java/util/HashMap"); + jmethodID put = (jmethodID)class_lookup_method_recursive(mapClass, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + jobject jmap = create_default_instance(mapClass); + if (jmap) { + apr_pool_t *pp; + if (APR_SUCCESS == apr_pool_create(&pp, 0)) { + for (char **e = port_env_all(pp) ; *e; ++e){ + size_t idx = strcspn(*e, "="); + char* key = apr_pstrndup(pp, *e, idx); + jobject jkey = NewStringUTF(jenv, key); + if (!jkey) break; + jobject jval = NewStringUTF(jenv, *e+idx+1); + if (!jval) break; + CallObjectMethod(jenv, jmap, put, jkey, jval); + assert(!exn_raised()); + } + apr_pool_destroy(pp); + } + } + + return jmap; +} + +/* +* Class: java_lang_VMExecutionEngine +* Method: mapLibraryName +* Signature: (Ljava/lang/String;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMExecutionEngine_mapLibraryName +(JNIEnv *jenv, jclass, jstring jlibname) { + jstring res = NULL; + if(jlibname) { + const char* libname = GetStringUTFChars(jenv, jlibname, NULL); + apr_pool_t *pp; + if (APR_SUCCESS == apr_pool_create(&pp, 0)) { + res = NewStringUTF(jenv, port_dso_name_decorate(libname, pp)); + apr_pool_destroy(pp); + } + ReleaseStringUTFChars(jenv, jlibname, libname); + } + return res; +} diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.h vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.h index 21251a9..5a91628 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.h +++ vm/vmcore/src/kernel_classes/native/java_lang_VMExecutionEngine.h @@ -53,10 +53,10 @@ JNIEXPORT void JNICALL Java_java_lang_VM (JNIEnv *, jclass, jint, jboolean, jobjectArray); /* - * Method: java.lang.VMExecutionEngine.getAssertionStatus(Ljava/lang/String;)I + * Method: java.lang.VMExecutionEngine.getAssertionStatus(Ljava/lang/Class;ZI)I */ JNIEXPORT jint JNICALL Java_java_lang_VMExecutionEngine_getAssertionStatus - (JNIEnv *, jclass, jstring); + (JNIEnv *, jclass, jclass, jboolean, jint); /* * Method: java.lang.VMExecutionEngine.getAvailableProcessors()I @@ -90,6 +90,46 @@ JNIEXPORT void JNICALL Java_java_lang_VM +/* +* Class: java_lang_VMExecutionEngine +* Method: currentTimeMillis +* Signature: ()J +*/ +JNIEXPORT jlong JNICALL Java_java_lang_VMExecutionEngine_currentTimeMillis +(JNIEnv *, jclass); + +/* +* Class: java_lang_VMExecutionEngine +* Method: nanoTime +* Signature: ()J +*/ +JNIEXPORT jlong JNICALL Java_java_lang_VMExecutionEngine_nanoTime +(JNIEnv *, jclass); + +/* +* Class: java_lang_VMExecutionEngine +* Method: getenv +* Signature: (Ljava/lang/String;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMExecutionEngine_getenv__Ljava_lang_String_2 +(JNIEnv *, jclass, jstring); + +/* +* Class: java_lang_VMExecutionEngine +* Method: getenv +* Signature: ()Ljava/util/Map; +*/ +JNIEXPORT jobject JNICALL Java_java_lang_VMExecutionEngine_getenv__ +(JNIEnv *, jclass); + +/* +* Class: java_lang_VMExecutionEngine +* Method: mapLibraryName +* Signature: (Ljava/lang/String;)Ljava/lang/String; +*/ +JNIEXPORT jstring JNICALL Java_java_lang_VMExecutionEngine_mapLibraryName +(JNIEnv *, jclass, jstring); + #ifdef __cplusplus } #endif diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.cpp vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.cpp index fcefcd3..e4262b1 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.cpp +++ vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.cpp @@ -22,8 +22,10 @@ #define LOG_DOMAIN "kernel" #include "cxxlog.h" #include "java_lang_VMThreadManager.h" +#include "open/ti_thread.h" #include "open/hythread_ext.h" #include "open/jthread.h" +#include "open/ti_thread.h" #include "open/thread_externals.h" /* @@ -45,7 +47,7 @@ JNIEXPORT jobject JNICALL Java_java_lang JNIEXPORT jboolean JNICALL Java_java_lang_VMThreadManager_holdsLock (JNIEnv * UNREF jenv, jclass clazz, jobject monitor) { - return false;//jthread_holds_lock(jthread_self(), monitor); + return jthread_holds_lock(jthread_self(), monitor); } /* @@ -67,7 +69,7 @@ JNIEXPORT jint JNICALL Java_java_lang_VM JNIEXPORT jboolean JNICALL Java_java_lang_VMThreadManager_isInterrupted__ (JNIEnv * UNREF jenv, jclass clazz) { - return jthread_is_interrupted(jthread_self()); + return jthread_clear_interrupted(jthread_self()); } /* @@ -156,6 +158,7 @@ JNIEXPORT jint JNICALL Java_java_lang_VM (JNIEnv *jenv, jclass clazz, jobject thread, jlong stackSize, jboolean daemon, jint priority) { jthread_threadattr_t attrs; + attrs.daemon = daemon; attrs.priority = priority; attrs.stacksize = (jint)stackSize; @@ -250,6 +253,21 @@ JNIEXPORT jint JNICALL Java_java_lang_VM return jthread_timed_join(thread, millis, nanos); } +/* + * Class: java_lang_VMThreadManager + * Method: getState + * Signature: (Ljava/lang/Thread;)I + */ +JNIEXPORT jint JNICALL Java_java_lang_VMThreadManager_getState + (JNIEnv * UNREF jenv, jclass clazz, jobject jthread) +{ + jint state; + int stat; + + stat = jthread_get_state(jthread, &state); + assert(stat == TM_ERROR_NONE); + return state; +} /* diff --git vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.h vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.h index 84b5979..a3d8772 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.h +++ vm/vmcore/src/kernel_classes/native/java_lang_VMThreadManager.h @@ -27,8 +27,8 @@ #include <jni.h> /* Header for class java.lang.VMThreadManager */ -#ifndef _JAVA_LANG_VMTHREADMANAGER_H -#define _JAVA_LANG_VMTHREADMANAGER_H +#ifndef _Included_java_lang_VMThreadManager +#define _Included_java_lang_VMThreadManager #ifdef __cplusplus extern "C" { #endif @@ -48,6 +48,12 @@ JNIEXPORT jboolean JNICALL Java_java_lan (JNIEnv *, jclass, jobject); /* + * Method: java.lang.VMThreadManager.getState(Ljava/lang/Thread;)I + */ +JNIEXPORT jint JNICALL Java_java_lang_VMThreadManager_getState + (JNIEnv *, jclass, jobject); + +/* * Method: java.lang.VMThreadManager.interrupt(Ljava/lang/Thread;)I */ JNIEXPORT jint JNICALL Java_java_lang_VMThreadManager_interrupt diff --git vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.cpp vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.cpp deleted file mode 100644 index 675fb97..0000000 --- vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Euguene Ostrovsky - * @version $Revision: 1.1.2.1.4.5 $ - */ -#include "java_lang_ref_Reference.h" - -#include "object_handles.h" -#include "open/gc.h" - -#define LOG_DOMAIN "vm.accessors" -#include "cxxlog.h" - -JNIEXPORT -void JNICALL Java_java_lang_ref_Reference_initReference - (JNIEnv *env, jobject ref, jobject referent) -{ - - // FIXME salikh: field initialization may be done in java as well - jclass refClss = env->GetObjectClass(ref); - jfieldID referentField = env->GetFieldID(refClss, "referent", - "Ljava/lang/Object;"); - if (env->ExceptionOccurred()) { - env->ExceptionClear(); - DIE("Internal error: " - "cannot find referent field in java.lang.ref.Reference"); - } - - env->SetObjectField(ref, referentField, referent); -} diff --git vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.h vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.h deleted file mode 100644 index 416066c..0000000 --- vm/vmcore/src/kernel_classes/native/java_lang_ref_Reference.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @author Serguei S.Zapreyev - * @version $Revision: 1.1.2.1.4.4 $ - */ - -/* - * THIS HEADER FILE WAS GENERATED BY INTEL IJH TOOL. - * Please be aware that all the changes of this file - * will be overwritten by the tool when it runs again. - */ - -#include <jni.h> - - -/* Header for class java.lang.ref.Reference */ - -#ifndef _JAVA_LANG_REF_REFERENCE_H -#define _JAVA_LANG_REF_REFERENCE_H - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Native methods */ - -/* - * Method: java.lang.ref.Reference.initReference(Ljava/lang/Object;)V - */ -JNIEXPORT void JNICALL -Java_java_lang_ref_Reference_initReference(JNIEnv *, jobject, - jobject); - - -#ifdef __cplusplus -} -#endif - -#endif /* _JAVA_LANG_REF_REFERENCE_H */ - diff --git vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.cpp vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.cpp new file mode 100644 index 0000000..e80d694 --- /dev/null +++ vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.cpp @@ -0,0 +1,387 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +/** + * @file java_lang_reflect_VMField.cpp + * + * This file is a part of kernel class natives VM core component. + * It contains implementation for native methods of + * java.lang.reflect.VMField class. + */ + +#define LOG_DOMAIN "vm.core.reflection" +#include "cxxlog.h" +#include "vm_log.h" + +#include "reflection.h" +#include "environment.h" +#include "exceptions.h" +#include "primitives_support.h" +#include "jni_utils.h" + +#include "java_lang_reflect_VMField.h" + +// return value of a field of primitive type. +static jvalue read_primitive(JNIEnv* jenv, jfieldID field_id, jobject obj, char field_sig) +{ + jclass declaring_class = NULL; //unused + bool is_static = ((Field*) field_id)->is_static(); + jvalue primitive_value; + + switch (field_sig) { + case 'B': + primitive_value.b = (is_static) ? + GetStaticByteField(jenv, declaring_class, field_id) : + GetByteField(jenv, obj, field_id); + break; + case 'C': + primitive_value.c = (is_static) ? + GetStaticCharField(jenv, declaring_class, field_id) : + GetCharField(jenv, obj, field_id); + break; + case 'D': + primitive_value.d = (is_static) ? + GetStaticDoubleField(jenv, declaring_class, field_id) : + GetDoubleField(jenv, obj, field_id); + break; + case 'F': + primitive_value.f = (is_static) ? + GetStaticFloatField(jenv, declaring_class, field_id) : + GetFloatField(jenv, obj, field_id); + break; + case 'I': + primitive_value.i = (is_static) ? + GetStaticIntField(jenv, declaring_class, field_id) : + GetIntField(jenv, obj, field_id); + break; + case 'J': + primitive_value.j = (is_static) ? + GetStaticLongField(jenv, declaring_class, field_id) : + GetLongField(jenv, obj, field_id); + break; + case 'S': + primitive_value.s = (is_static) ? + GetStaticShortField(jenv, declaring_class, field_id) : + GetShortField(jenv, obj, field_id); + break; + case 'Z': + primitive_value.z = (is_static) ? + GetStaticBooleanField(jenv, declaring_class, field_id) : + GetBooleanField(jenv, obj, field_id); + break; + default: + ASSERT(0, "Unexpected type descriptor"); + } + + return primitive_value; +} + +static jvalue get_primitive_field(JNIEnv *jenv, jobject obj, jlong jmember, char to_type) +{ + Field_Handle field = (Field_Handle) ((POINTER_SIZE_INT) jmember); + + TRACE("read field value : " << field); + + char field_sig = field->get_descriptor()->bytes[0]; + jvalue result = read_primitive(jenv, (jfieldID)field, obj, field_sig); + if (!widen_primitive_jvalue(&result, field_sig, to_type) && !exn_raised()) { + ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", field->get_descriptor()->bytes); + } + return result; +} + +JNIEXPORT jboolean JNICALL Java_java_lang_reflect_VMField_getBoolean +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'Z').z; +} + +JNIEXPORT jbyte JNICALL Java_java_lang_reflect_VMField_getByte +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'B').b; +} + +JNIEXPORT jchar JNICALL Java_java_lang_reflect_VMField_getChar +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'C').c; +} + +JNIEXPORT jshort JNICALL Java_java_lang_reflect_VMField_getShort +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'S').s; +} + +JNIEXPORT jint JNICALL Java_java_lang_reflect_VMField_getInt +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'I').i; +} + +JNIEXPORT jlong JNICALL Java_java_lang_reflect_VMField_getLong +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'J').j; +} + +JNIEXPORT jfloat JNICALL Java_java_lang_reflect_VMField_getFloat +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'F').f; +} + +JNIEXPORT jdouble JNICALL Java_java_lang_reflect_VMField_getDouble +(JNIEnv *jenv, jclass, jobject obj, jlong jmember) +{ + return get_primitive_field(jenv, obj, jmember, 'D').d; +} + +/* + * Class: java_lang_reflect_VMField + * Method: getObject + * Signature: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMField_getObject + (JNIEnv *jenv, jclass, jobject obj, jlong member) +{ + Field_Handle field = (Field_Handle) ((POINTER_SIZE_INT) member); + TRACE("get field value : " << field); + + jobject retobj = NULL; + + if (field->get_field_type_desc()->is_primitive()) + { + char field_sig = field->get_descriptor()->bytes[0]; + jvalue primitive_value = read_primitive(jenv, (jfieldID)field, obj, field_sig); + if (!exn_raised()) { + retobj = wrap_primitive(jenv, primitive_value, field_sig); + } + } + else if (field->is_static()) + { + retobj = GetStaticObjectField(jenv, NULL, (jfieldID)field); + } + else + { + retobj = GetObjectField(jenv, obj, (jfieldID)field); + } + + return retobj; +} // Java_java_lang_reflect_VMField_getObject + +static void write_primitive(JNIEnv* jenv, Field* field, jobject obj, jvalue primitive_value, char value_sig) +{ + char field_sig = field->get_descriptor()->bytes[0]; + + if (! widen_primitive_jvalue(&primitive_value, value_sig, field_sig)) { + ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", + "Widening conversion failed"); + return; + } + + jclass declaring_class = NULL; //UNUSED + jfieldID field_id = (jfieldID) field; + bool is_static = field->is_static(); + + switch (field_sig) { + case 'B': + if (is_static) + SetStaticByteField(jenv, declaring_class, field_id, primitive_value.b); + else + SetByteField(jenv, obj, field_id, primitive_value.b); + + break; + case 'C': + if (is_static) + SetStaticCharField(jenv, declaring_class, field_id, primitive_value.c); + else + SetCharField(jenv, obj, field_id, primitive_value.c); + + break; + case 'D': + if (is_static) + SetStaticDoubleField(jenv, declaring_class, field_id, primitive_value.d); + else + SetDoubleField(jenv, obj, field_id, primitive_value.d); + + break; + case 'F': + if (is_static) + SetStaticFloatField(jenv, declaring_class, field_id, primitive_value.f); + else + SetFloatField(jenv, obj, field_id, primitive_value.f); + + break; + case 'I': + if (is_static) + SetStaticIntField(jenv, declaring_class, field_id, primitive_value.i); + else + SetIntField(jenv, obj, field_id, primitive_value.i); + + break; + case 'J': + if (is_static) + SetStaticLongField(jenv, declaring_class, field_id, primitive_value.j); + else + SetLongField(jenv, obj, field_id, primitive_value.j); + + break; + case 'S': + if (is_static) + SetStaticShortField(jenv, declaring_class, field_id, primitive_value.s); + else + SetShortField(jenv, obj, field_id, primitive_value.s); + + break; + case 'Z': + if (is_static) + SetStaticBooleanField(jenv, declaring_class, field_id, primitive_value.z); + else + SetBooleanField(jenv, obj, field_id, primitive_value.z); + + break; + default: + ASSERT(0, "Unexpected type descriptor"); + } + + return; +} + +/* + * Class: java_lang_reflect_VMField + * Method: setFieldValue + * Signature: (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V + */ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setObject + (JNIEnv *jenv, jclass, jobject obj, jlong jfield, jobject value) +{ + Field_Handle field = (Field_Handle) ((POINTER_SIZE_INT) jfield); + TRACE("set field value : " << field); + + if (field->get_field_type_desc()->is_primitive()) + { + char value_sig = value ? is_wrapper_class(jobject_to_struct_Class(value)->name->bytes) : 0; + if (!value_sig) { + // the value is not primitive + ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", + "The specified value cannot be unboxed to primitive"); + return; + } + jvalue primitive_value = unwrap_primitive(jenv, value, value_sig); + write_primitive(jenv, field, obj, primitive_value, value_sig); + return; + } + if (value) { + // check type + Class* value_clss = jobject_to_struct_Class(value); + Class* clss = field->get_field_type_desc()->load_type_desc(); + assert(clss); + if (!class_is_subtype_fast(value_clss->vtable, clss)) { + ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", + "The specified value cannot be converted to the field's type type by an identity or widening conversions"); + return; + } + } + + if (field->is_static()) + { + SetStaticObjectField(jenv, NULL, (jfieldID)field, value); + } + else + { + SetObjectField(jenv, obj, (jfieldID)field, value); + } +} + +// set value to field of primitive type +static void set_primitive_field(JNIEnv* jenv, jlong jfield, jobject obj, + jvalue primitive, char value_type) +{ + Field_Handle field = (Field_Handle) ((POINTER_SIZE_INT) jfield); + TRACE("set field value : " << field); + write_primitive(jenv, field, obj, primitive, value_type); +} + + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setBoolean +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jboolean value) +{ + jvalue primitive; + primitive.z = value; + set_primitive_field(jenv, jfield, obj, primitive, 'Z'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setChar +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jchar value) +{ + jvalue primitive; + primitive.c = value; + set_primitive_field(jenv, jfield, obj, primitive, 'C'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setByte +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jbyte value) +{ + jvalue primitive; + primitive.b = value; + set_primitive_field(jenv, jfield, obj, primitive, 'B'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setShort +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jshort value) +{ + jvalue primitive; + primitive.s = value; + set_primitive_field(jenv, jfield, obj, primitive, 'S'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setInt +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jint value) +{ + jvalue primitive; + primitive.i = value; + set_primitive_field(jenv, jfield, obj, primitive, 'I'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setLong +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jlong value) +{ + jvalue primitive; + primitive.j = value; + set_primitive_field(jenv, jfield, obj, primitive, 'J'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setFloat +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jfloat value) +{ + jvalue primitive; + primitive.f = value; + set_primitive_field(jenv, jfield, obj, primitive, 'F'); +} + +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setDouble +(JNIEnv *jenv, jclass, jobject obj, jlong jfield, jdouble value) +{ + jvalue primitive; + primitive.d = value; + set_primitive_field(jenv, jfield, obj, primitive, 'D'); +} diff --git vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.h vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.h new file mode 100644 index 0000000..34eb0dd --- /dev/null +++ vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMField.h @@ -0,0 +1,180 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +/* + * THE FILE HAS BEEN AUTOGENERATED BY INTEL IJH TOOL. + * Please be aware that all changes made to this file manually + * will be overwritten by the tool if it runs again. + */ + +#include <jni.h> +/* Header for class java.lang.reflect.VMField */ + +#ifndef _Included_java_lang_reflect_VMField +#define _Included_java_lang_reflect_VMField +#ifdef __cplusplus +extern "C" { +#endif + +/* Native methods */ +/* + * Method: java.lang.reflect.VMField.getObject(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMField_getObject + (JNIEnv *, jclass, jobject, jlong); +/* +* Class: java_lang_reflect_VMField +* Method: getBoolean +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)Z +*/ +JNIEXPORT jboolean JNICALL Java_java_lang_reflect_VMField_getBoolean +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getChar +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)C +*/ +JNIEXPORT jchar JNICALL Java_java_lang_reflect_VMField_getChar +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getByte +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)B +*/ +JNIEXPORT jbyte JNICALL Java_java_lang_reflect_VMField_getByte +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getShort +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)S +*/ +JNIEXPORT jshort JNICALL Java_java_lang_reflect_VMField_getShort +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getInt +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)I +*/ +JNIEXPORT jint JNICALL Java_java_lang_reflect_VMField_getInt +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getLong +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)J +*/ +JNIEXPORT jlong JNICALL Java_java_lang_reflect_VMField_getLong +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getFloat +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)F +*/ +JNIEXPORT jfloat JNICALL Java_java_lang_reflect_VMField_getFloat +(JNIEnv *, jclass, jobject, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: getDouble +* Signature: (Ljava/lang/Object;Ljava/lang/Object;)D +*/ +JNIEXPORT jdouble JNICALL Java_java_lang_reflect_VMField_getDouble +(JNIEnv *, jclass, jobject, jlong); + +/* + * Method: java.lang.reflect.VMField.setObject(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V + */ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setObject + (JNIEnv *, jclass, jobject, jlong, jobject); + +/* +* Class: java_lang_reflect_VMField +* Method: setBoolean +* Signature: (Ljava/lang/Object;Ljava/lang/Object;Z)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setBoolean +(JNIEnv *, jclass, jobject, jlong, jboolean); + +/* +* Class: java_lang_reflect_VMField +* Method: setChar +* Signature: (Ljava/lang/Object;Ljava/lang/Object;C)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setChar +(JNIEnv *, jclass, jobject, jlong, jchar); + +/* +* Class: java_lang_reflect_VMField +* Method: setByte +* Signature: (Ljava/lang/Object;Ljava/lang/Object;B)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setByte +(JNIEnv *, jclass, jobject, jlong, jbyte); + +/* +* Class: java_lang_reflect_VMField +* Method: setShort +* Signature: (Ljava/lang/Object;Ljava/lang/Object;S)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setShort +(JNIEnv *, jclass, jobject, jlong, jshort); + +/* +* Class: java_lang_reflect_VMField +* Method: setInt +* Signature: (Ljava/lang/Object;Ljava/lang/Object;I)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setInt +(JNIEnv *, jclass, jobject, jlong, jint); + +/* +* Class: java_lang_reflect_VMField +* Method: setLong +* Signature: (Ljava/lang/Object;Ljava/lang/Object;J)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setLong +(JNIEnv *, jclass, jobject, jlong, jlong); + +/* +* Class: java_lang_reflect_VMField +* Method: setFloat +* Signature: (Ljava/lang/Object;Ljava/lang/Object;F)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setFloat +(JNIEnv *, jclass, jobject, jlong, jfloat); + +/* +* Class: java_lang_reflect_VMField +* Method: setDouble +* Signature: (Ljava/lang/Object;Ljava/lang/Object;D)V +*/ +JNIEXPORT void JNICALL Java_java_lang_reflect_VMField_setDouble +(JNIEnv *, jclass, jobject, jlong, jdouble); + + +#ifdef __cplusplus +} +#endif +#endif diff --git vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.cpp vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.cpp index 69b1d77..a7dc5a3 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.cpp +++ vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.cpp @@ -39,49 +39,10 @@ #include "jni_utils.h" #include "java_lang_VMClassRegistry.h" #include "java_lang_reflect_VMReflection.h" -static jobject get_member_field(JNIEnv *jenv, Class* clss, jobject member, reflection_fields descriptor) -{ - TRACE("get member field : " << descriptor); - Field *field = get_reflection_field(clss, descriptor); - jobject value = GetObjectFieldOffset(jenv, member, field->get_offset()); - assert(value); - - return value; -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: getDeclaringClass - * Signature: (Ljava/lang/Object;)Ljava/lang/Class; - */ -JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getDeclaringClass - (JNIEnv *jenv, jclass, jobject member) -{ - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Field_Class, - "Unsupported type of member object"); - - return get_member_field(jenv, clss, member, DECLARING_CLASS); -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: getExceptionTypes - * Signature: (Ljava/lang/Object;)[Ljava/lang/Class; - */ JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getExceptionTypes - (JNIEnv *jenv, jclass, jobject member) + (JNIEnv *jenv, jclass, jlong member) { - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class, - "Unsupported type of member object"); - - Method* method = (Method*)reflection_jobject_to_Class_Member(member, clss); + Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member); jclass jlc_class = struct_Class_to_java_lang_Class_Handle( VM_Global_State::loader_env->JavaLangClass_Class); @@ -108,243 +69,54 @@ JNIEXPORT jobjectArray JNICALL Java_java return exceptionTypes; } -/* - * Class: java_lang_reflect_VMReflection - * Method: getModifiers - * Signature: (Ljava/lang/Object;)I - */ -JNIEXPORT jint JNICALL Java_java_lang_reflect_VMReflection_getModifiers - (JNIEnv * UNREF jenv, jclass, jobject member) -{ - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Field_Class, - "Unsupported type of member object"); - - return reflection_jobject_to_Class_Member(member, clss)->get_access_flags(); -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: getName - * Signature: (Ljava/lang/Object;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_java_lang_reflect_VMReflection_getName - (JNIEnv *jenv, jclass, jobject member) -{ - Class* clss = jobject_to_struct_Class(member); - - if (clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class) - { - Class* declaringClass = jclass_to_struct_Class( - get_member_field(jenv, clss, member, DECLARING_CLASS)); - String *str = class_get_java_name(declaringClass, VM_Global_State::loader_env); - jstring name = String_to_interned_jstring(str); - if (name == NULL) { - assert(exn_raised()); - } - return name; - } - else if (clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Field_Class) - { - return get_member_field(jenv, clss, member, NAME); - } - else - { - ASSERT(0, "Unsupported type of member object"); - return NULL; - } -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: getParameterTypes - * Signature: (Ljava/lang/Object;)[Ljava/lang/Class; - */ JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getParameterTypes - (JNIEnv *jenv, jclass, jobject member) + (JNIEnv *jenv, jclass, jlong member) { - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Constructor_Class - || clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class, - "Unsupported type of member object"); - - return reflection_get_parameter_types(jenv, clss, member); + Method_Handle mh = (Method_Handle) ((POINTER_SIZE_INT) member); + return reflection_get_parameter_types(jenv, mh); } -/* - * Class: java_lang_reflect_VMReflection - * Method: getMethodReturnType - * Signature: (Ljava/lang/Object;)Ljava/lang/Class; - */ JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getMethodReturnType - (JNIEnv *jenv, jclass, jobject member) + (JNIEnv *jenv, jclass, jlong member) { - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Method_Class, - "Unsupported type of member object"); - - Method_Handle method = (Method_Handle)reflection_jobject_to_Class_Member(member, clss); + Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member); Method_Signature_Handle msh = method_get_signature(method); Type_Info_Handle ret_type = method_ret_type_get_type_info(msh); - Class_Handle ret_clss = type_info_get_class(ret_type); - - if (!ret_clss) { - if (!exn_raised()) { - exn_raise_only((jthrowable) type_info_get_loading_error(ret_type)); - } - return NULL; - } - return struct_Class_to_java_lang_Class_Handle(ret_clss); + return descriptor_to_jclass(ret_type); } -/* - * Class: java_lang_reflect_VMReflection - * Method: getFieldType - * Signature: (Ljava/lang/Object;)Ljava/lang/Class; - */ JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getFieldType - (JNIEnv *jenv, jclass, jobject member) + (JNIEnv *jenv, jclass, jlong member) { - Class* clss = jobject_to_struct_Class(member); - - ASSERT(clss == VM_Global_State::loader_env->java_lang_reflect_Field_Class, - "Unsupported type of member object"); - - return get_member_field(jenv, clss, member, TYPE); + Field_Handle fh = (Field_Handle) ((POINTER_SIZE_INT) member); + Type_Info_Handle fti = field_get_type_info_of_field_value(fh); + return descriptor_to_jclass(fti); } -// return value of a field of primitive type. -static jobject get_primitive_field(JNIEnv* jenv, jfieldID field_id, jclass declaring_class, jobject obj) -{ - char field_sig = ((Field*) field_id)->get_descriptor()->bytes[0]; - bool is_static = ((Field*) field_id)->is_static(); - jvalue primitive_value; - - switch (field_sig) { - case 'B': - primitive_value.b = (is_static) ? - GetStaticByteField(jenv, declaring_class, field_id) : - GetByteField(jenv, obj, field_id); - break; - case 'C': - primitive_value.c = (is_static) ? - GetStaticCharField(jenv, declaring_class, field_id) : - GetCharField(jenv, obj, field_id); - break; - case 'D': - primitive_value.d = (is_static) ? - GetStaticDoubleField(jenv, declaring_class, field_id) : - GetDoubleField(jenv, obj, field_id); - break; - case 'F': - primitive_value.f = (is_static) ? - GetStaticFloatField(jenv, declaring_class, field_id) : - GetFloatField(jenv, obj, field_id); - break; - case 'I': - primitive_value.i = (is_static) ? - GetStaticIntField(jenv, declaring_class, field_id) : - GetIntField(jenv, obj, field_id); - break; - case 'J': - primitive_value.j = (is_static) ? - GetStaticLongField(jenv, declaring_class, field_id) : - GetLongField(jenv, obj, field_id); - break; - case 'S': - primitive_value.s = (is_static) ? - GetStaticShortField(jenv, declaring_class, field_id) : - GetShortField(jenv, obj, field_id); - break; - case 'Z': - primitive_value.z = (is_static) ? - GetStaticBooleanField(jenv, declaring_class, field_id) : - GetBooleanField(jenv, obj, field_id); - break; - default: - ASSERT(0, "Unexpected type descriptor"); - } - - if (exn_raised()) - return NULL; - - return wrap_primitive(jenv, primitive_value, field_sig); -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: getFieldValue - * Signature: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - */ -JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_getFieldValue - (JNIEnv *jenv, jclass, jobject obj, jobject member) -{ - Class* type = VM_Global_State::loader_env->java_lang_reflect_Field_Class; - Field* field = (Field*)reflection_jobject_to_Class_Member(member, type); - - jclass declaring_class = struct_Class_to_java_lang_Class_Handle(field->get_class()); - //get_member_field(jenv, type, member, DECLARING_CLASS); - - TRACE("get field value : " << field->get_class()->name->bytes << "." << field->get_name()->bytes); - - jobject retobj = NULL; - - if (field->get_field_type_desc()->is_primitive()) - { - retobj = get_primitive_field(jenv, (jfieldID)field, declaring_class, obj); - } - else if (field->is_static()) - { - retobj = GetStaticObjectField(jenv, declaring_class, (jfieldID)field); - } - else - { - retobj = GetObjectField(jenv, obj, (jfieldID)field); - } - - return retobj; -} // Java_java_lang_reflect_VMReflection_getFieldValue - /* * Returns false if no exception is set. If exception is set and is not - * an Error descendant, wraps it into new InvocationTargetException. + * an OOME instance, wraps it into new InvocationTargetException. */ -static bool rethrow_invocation_exception(JNIEnv* jenv) { - jthrowable exn = ExceptionOccurred(jenv); - if (!exn) +static bool rethrow_invocation_exception(JNIEnv* jenv) +{ + Class* exn_class = exn_get_class(); + if (!exn_class) return false; Global_Env* genv = VM_Global_State::loader_env; - if (exn == genv->java_lang_OutOfMemoryError) { + if (exn_class == genv->java_lang_OutOfMemoryError_Class) { return true; } - // API specifications only requires ExceptionInInitializerError - // to pass through intact, and says nothing about other Errors; - // but this is reasonable for any Error - Class* Error_class = genv->java_lang_Error_Class; - Class *exc_class = jobject_to_struct_Class(exn); - - while (exc_class && exc_class != Error_class) { - exc_class = exc_class->super_class; - } - - if (exc_class != Error_class) { - exn_clear(); - //static Class* ITE_class = genv->LoadCoreClass( - // genv->string_pool.lookup("java/lang/reflect/InvocationTargetException")); - jobject ite_exn = exn_create("java/lang/reflect/InvocationTargetException", exn); - if (!exn_raised()) { - exn_raise_only(ite_exn ? ite_exn : genv->java_lang_OutOfMemoryError); - } + jthrowable exn = exn_get(); + //FIXME need better handling for lazy exceptions + if (!exn) { + WARN("ATTENTION! Could not get cause exception from lazy machinery"); } - + exn_clear(); + //static Class* ITE_class = genv->LoadCoreClass( + // genv->string_pool.lookup("java/lang/reflect/InvocationTargetException")); + exn_raise_by_name("java/lang/reflect/InvocationTargetException", exn); return true; } @@ -420,22 +192,14 @@ static jobject invoke_primitive_method(J return wrap_primitive(jenv, result, (char)return_type); } -/* - * Class: java_lang_reflect_VMReflection - * Method: invokeMethod - * Signature: (Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; - */ JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_invokeMethod - (JNIEnv *jenv, jclass, jobject obj, jobject jmethod, jobjectArray args) + (JNIEnv *jenv, jclass, jlong member, jobject obj, jobjectArray args) { Class* type = VM_Global_State::loader_env->java_lang_reflect_Method_Class; - Method* method = (Method*)reflection_jobject_to_Class_Member(jmethod, type); + Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member); TRACE("invoke : " << method->get_class()->name->bytes << "." << method->get_name()->bytes << "()"); - jclass declaring_class = struct_Class_to_java_lang_Class_Handle(method->get_class()); - //get_member_field(jenv, type, jmethod, DECLARING_CLASS); - unsigned num_args = method->get_num_args(); jvalue *jvalue_args = (jvalue *)STD_ALLOCA(num_args * sizeof(jvalue)); if (!jobjectarray_to_jvaluearray(jenv, &jvalue_args, method, args)) { @@ -444,6 +208,12 @@ JNIEXPORT jobject JNICALL Java_java_lang jobject jresult; + // In a case of class initialization error, it must be thrown directly + if (!ensure_initialised(jenv, method->get_class())) { + assert(exn_raised()); + return NULL; + } + jclass declaring_class = struct_Class_to_java_lang_Class_Handle(method->get_class()); Java_Type return_type = method->get_return_java_type(); if (return_type != JAVA_TYPE_CLASS && return_type != JAVA_TYPE_ARRAY) { @@ -495,11 +265,6 @@ jobject createArray(JNIEnv *jenv, jclass return jarray; } -/* - * Class: java_lang_reflect_VMReflection - * Method: newArrayInstance - * Signature: (Ljava/lang/Class;[I)Ljava/lang/Object; - */ JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newArrayInstance (JNIEnv *jenv, jclass, jclass compType, jintArray jdims) { @@ -531,15 +296,10 @@ JNIEXPORT jobject JNICALL Java_java_lang return jarray; } -/* - * Class: java_lang_reflect_VMReflection - * Method: newClassInstance - * Signature: (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; - */ JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newClassInstance - (JNIEnv *jenv, jclass, jobject jconstr, jobjectArray args) + (JNIEnv *jenv, jclass, jlong member, jobjectArray args) { - Method* method = (Method*)reflection_jobject_to_Class_Member(jconstr, VM_Global_State::loader_env->java_lang_reflect_Constructor_Class); + Method_Handle method = (Method_Handle) ((POINTER_SIZE_INT) member); TRACE("new class instance : " << method->get_class()->name->bytes); @@ -550,7 +310,10 @@ JNIEXPORT jobject JNICALL Java_java_lang } jclass declaring_class = struct_Class_to_java_lang_Class_Handle(method->get_class()); - //get_member_field(jenv, VM_Global_State::loader_env->java_lang_reflect_Constructor_Class, jconstr, DECLARING_CLASS); + + // In a case of class initialization error, it must be thrown directly + if (!ensure_initialised(jenv, method->get_class())) + return NULL; // Create object jobject new_object = NewObjectA(jenv, declaring_class, (jmethodID) method, jvalue_args); @@ -563,126 +326,3 @@ JNIEXPORT jobject JNICALL Java_java_lang return new_object; } // Java_java_lang_reflect_VMReflection_newClassInstance - -// set value to field of primitive type -static void set_primitive_field(JNIEnv* jenv, Field* field, jclass declaring_class, jobject obj, jobject value) -{ - - // class of the value object: - jclass value_class = GetObjectClass(jenv, value); - assert(value_class); - - char value_sig = is_wrapper_class(jclass_to_struct_Class(value_class)->name->bytes); - - // If the value is not primitive - if ( value_sig == '\0' ) { - ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", - "unwrapping conversion failed"); - return; - } - - jvalue primitive_value = unwrap_primitive(jenv, value, value_sig); - - char field_sig = field->get_descriptor()->bytes[0]; - - if (! widen_primitive_jvalue(&primitive_value, value_sig, field_sig)) { - ThrowNew_Quick(jenv, "java/lang/IllegalArgumentException", - "widening conversion failed"); - return; - } - - jfieldID field_id = (jfieldID) field; - bool is_static = field->is_static(); - - switch (field_sig) { - case 'B': - if (is_static) - SetStaticByteField(jenv, declaring_class, field_id, primitive_value.b); - else - SetByteField(jenv, obj, field_id, primitive_value.b); - - break; - case 'C': - if (is_static) - SetStaticCharField(jenv, declaring_class, field_id, primitive_value.c); - else - SetCharField(jenv, obj, field_id, primitive_value.c); - - break; - case 'D': - if (is_static) - SetStaticDoubleField(jenv, declaring_class, field_id, primitive_value.d); - else - SetDoubleField(jenv, obj, field_id, primitive_value.d); - - break; - case 'F': - if (is_static) - SetStaticFloatField(jenv, declaring_class, field_id, primitive_value.f); - else - SetFloatField(jenv, obj, field_id, primitive_value.f); - - break; - case 'I': - if (is_static) - SetStaticIntField(jenv, declaring_class, field_id, primitive_value.i); - else - SetIntField(jenv, obj, field_id, primitive_value.i); - - break; - case 'J': - if (is_static) - SetStaticLongField(jenv, declaring_class, field_id, primitive_value.j); - else - SetLongField(jenv, obj, field_id, primitive_value.j); - - break; - case 'S': - if (is_static) - SetStaticShortField(jenv, declaring_class, field_id, primitive_value.s); - else - SetShortField(jenv, obj, field_id, primitive_value.s); - - break; - case 'Z': - if (is_static) - SetStaticBooleanField(jenv, declaring_class, field_id, primitive_value.z); - else - SetBooleanField(jenv, obj, field_id, primitive_value.z); - - break; - default: - ASSERT(0, "Unexpected type descriptor"); - } - - return; -} - -/* - * Class: java_lang_reflect_VMReflection - * Method: setFieldValue - * Signature: (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V - */ -JNIEXPORT void JNICALL Java_java_lang_reflect_VMReflection_setFieldValue - (JNIEnv *jenv, jclass, jobject obj, jobject jfield, jobject value) -{ - Class* type = VM_Global_State::loader_env->java_lang_reflect_Field_Class; - Field* field = (Field*)reflection_jobject_to_Class_Member(jfield, type); - jclass declaring_class = struct_Class_to_java_lang_Class_Handle(field->get_class()); - //get_member_field(jenv, type, jfield, DECLARING_CLASS); - - TRACE("set field value : " << field->get_class()->name->bytes << "." << field->get_name()->bytes); - - if (field->get_field_type_desc()->is_primitive()) - { - set_primitive_field(jenv, field, declaring_class, obj, value); - } - else if (field->is_static()) - { - SetStaticObjectField(jenv, declaring_class, (jfieldID)field, value); - } - else - { - SetObjectField(jenv, obj, (jfieldID)field, value); - } -} diff --git vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.h vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.h index b59e4f1..380c200 100644 --- vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.h +++ vm/vmcore/src/kernel_classes/native/java_lang_reflect_VMReflection.h @@ -41,90 +41,48 @@ #endif /* Native methods */ /* - * Method: java.lang.reflect.VMReflection.getDeclaringClass(Ljava/lang/Object;)Ljava/lang/Class; + * Method: java.lang.reflect.VMReflection.getExceptionTypes(J)[Ljava/lang/Class; */ -JNIEXPORT jclass JNICALL -Java_java_lang_reflect_VMReflection_getDeclaringClass(JNIEnv *, jclass, - jobject); +JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getExceptionTypes + (JNIEnv *, jclass, jlong); /* - * Method: java.lang.reflect.VMReflection.getExceptionTypes(Ljava/lang/Object;)[Ljava/lang/Class; + * Method: java.lang.reflect.VMReflection.getParameterTypes(J)[Ljava/lang/Class; */ -JNIEXPORT jobjectArray JNICALL -Java_java_lang_reflect_VMReflection_getExceptionTypes(JNIEnv *, jclass, - jobject); +JNIEXPORT jobjectArray JNICALL Java_java_lang_reflect_VMReflection_getParameterTypes + (JNIEnv *, jclass, jlong); /* - * Method: java.lang.reflect.VMReflection.getFieldType(Ljava/lang/Object;)Ljava/lang/Class; + * Method: java.lang.reflect.VMReflection.getMethodReturnType(J)Ljava/lang/Class; */ -JNIEXPORT jclass JNICALL -Java_java_lang_reflect_VMReflection_getFieldType(JNIEnv *, jclass, - jobject); +JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getMethodReturnType + (JNIEnv *, jclass, jlong); /* - * Method: java.lang.reflect.VMReflection.getFieldValue(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + * Method: java.lang.reflect.VMReflection.getFieldType(J)Ljava/lang/Class; */ -JNIEXPORT jobject JNICALL -Java_java_lang_reflect_VMReflection_getFieldValue(JNIEnv *, jclass, - jobject, jobject); +JNIEXPORT jclass JNICALL Java_java_lang_reflect_VMReflection_getFieldType + (JNIEnv *, jclass, jlong); /* - * Method: java.lang.reflect.VMReflection.getMethodReturnType(Ljava/lang/Object;)Ljava/lang/Class; - */ -JNIEXPORT jclass JNICALL -Java_java_lang_reflect_VMReflection_getMethodReturnType(JNIEnv *, jclass, - jobject); - -/* - * Method: java.lang.reflect.VMReflection.getModifiers(Ljava/lang/Object;)I - */ -JNIEXPORT jint JNICALL -Java_java_lang_reflect_VMReflection_getModifiers(JNIEnv *, jclass, - jobject); - -/* - * Method: java.lang.reflect.VMReflection.getName(Ljava/lang/Object;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL -Java_java_lang_reflect_VMReflection_getName(JNIEnv *, jclass, - jobject); - -/* - * Method: java.lang.reflect.VMReflection.getParameterTypes(Ljava/lang/Object;)[Ljava/lang/Class; - */ -JNIEXPORT jobjectArray JNICALL -Java_java_lang_reflect_VMReflection_getParameterTypes(JNIEnv *, jclass, - jobject); - -/* - * Method: java.lang.reflect.VMReflection.invokeMethod(Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; + * Method: java.lang.reflect.VMReflection.invokeMethod(JLjava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; * Throws: java.lang.reflect.InvocationTargetException */ -JNIEXPORT jobject JNICALL -Java_java_lang_reflect_VMReflection_invokeMethod(JNIEnv *, jclass, - jobject, jobject, jobjectArray); +JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_invokeMethod + (JNIEnv *, jclass, jlong, jobject, jobjectArray); /* * Method: java.lang.reflect.VMReflection.newArrayInstance(Ljava/lang/Class;[I)Ljava/lang/Object; */ -JNIEXPORT jobject JNICALL -Java_java_lang_reflect_VMReflection_newArrayInstance(JNIEnv *, jclass, - jclass, jintArray); +JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newArrayInstance + (JNIEnv *, jclass, jclass, jintArray); /* - * Method: java.lang.reflect.VMReflection.newClassInstance(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; + * Method: java.lang.reflect.VMReflection.newClassInstance(J[Ljava/lang/Object;)Ljava/lang/Object; * Throws: java.lang.reflect.InvocationTargetException */ -JNIEXPORT jobject JNICALL -Java_java_lang_reflect_VMReflection_newClassInstance(JNIEnv *, jclass, - jobject, jobjectArray); - -/* - * Method: java.lang.reflect.VMReflection.setFieldValue(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V - */ -JNIEXPORT void JNICALL -Java_java_lang_reflect_VMReflection_setFieldValue(JNIEnv *, jclass, - jobject, jobject, jobject); +JNIEXPORT jobject JNICALL Java_java_lang_reflect_VMReflection_newClassInstance + (JNIEnv *, jclass, jlong, jobjectArray); #ifdef __cplusplus diff --git vm/vmcore/src/kernel_classes/native/org_apache_harmony_util_concurrent_Atomics.h vm/vmcore/src/kernel_classes/native/org_apache_harmony_util_concurrent_Atomics.h index eb25d42..daef6d3 100644 --- vm/vmcore/src/kernel_classes/native/org_apache_harmony_util_concurrent_Atomics.h +++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_util_concurrent_Atomics.h @@ -122,31 +122,26 @@ Java_org_apache_harmony_util_concurrent_ /* * Method: org.apache.harmony.util.concurrent.Atomics.compareAndSetInt([IIII)Z */ -JNIEXPORT jboolean JNICALL -Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetInt___3IIII(JNIEnv *, jclass, - jintArray, jint, jint, jint); +JNIEXPORT jboolean JNICALL Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetInt___3IIII + (JNIEnv *, jobject, jintArray, jint, jint, jint); /* * Method: org.apache.harmony.util.concurrent.Atomics.compareAndSetBoolean([ZIZZ)Z */ -JNIEXPORT jboolean JNICALL -Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetBoolean___3ZIZZ(JNIEnv *, jclass, - jbooleanArray, jint, jboolean, jboolean); +JNIEXPORT jboolean JNICALL Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetBoolean___3ZIZZ + (JNIEnv *, jobject, jbooleanArray, jint, jboolean, jboolean); /* * Method: org.apache.harmony.util.concurrent.Atomics.compareAndSetLong([JIJJ)Z */ -JNIEXPORT jboolean JNICALL -Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetLong___3JIJJ(JNIEnv *, jclass, - jlongArray, jint, jlong, jlong); +JNIEXPORT jboolean JNICALL Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetLong___3JIJJ + (JNIEnv *, jobject, jlongArray, jint, jlong, jlong); /* * Method: org.apache.harmony.util.concurrent.Atomics.compareAndSetObject([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;)Z */ -JNIEXPORT jboolean JNICALL -Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetObject___3Ljava_lang_Object_2ILjava_lang_Object_2Ljava_lang_Object_2(JNIEnv *, jclass, - jobjectArray, jint, jobject, jobject); - +JNIEXPORT jboolean JNICALL Java_org_apache_harmony_util_concurrent_Atomics_compareAndSetObject___3Ljava_lang_Object_2ILjava_lang_Object_2Ljava_lang_Object_2 + (JNIEnv *, jobject, jobjectArray, jint, jobject, jobject); #ifdef __cplusplus } diff --git vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp new file mode 100644 index 0000000..e37ec0e --- /dev/null +++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +/** + * @file java_lang_VMClassRegistry.cpp + * + * This file is a part of kernel class natives VM core component. + * It contains implementation for native methods of + * java.lang.VMClassRegistry class. + */ +#define LOG_DOMAIN "vm.core.generics" +#include "cxxlog.h" + +#include "environment.h" +#include "Class.h" +#include "annotations.h" +#include "exceptions.h" +#include "jni_utils.h" +#include "vm_log.h" + +#include "org_apache_harmony_vm_VMGenericsAndAnnotations.h" + +JNIEXPORT jstring JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getSignature__J +(JNIEnv *jenv, jclass, jlong jmember) +{ + Class_Member* member = (Class_Member*) ((POINTER_SIZE_INT) jmember); + String* sig = member->get_signature(); + TRACE("Signature of " << member << " : " << sig); + return sig ? NewStringUTF(jenv, sig->bytes) : NULL; +} + +JNIEXPORT jstring JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getSignature__Ljava_lang_Class_2 +(JNIEnv *jenv, jclass, jclass jclazz) +{ + Class* clazz = jclass_to_struct_Class(jclazz); + String* sig = clazz->Signature; + TRACE("Signature of " << clazz << " : " << sig); + return sig ? NewStringUTF(jenv, sig->bytes) : NULL; +} + +JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__J +(JNIEnv *jenv, jclass, jlong jmember) +{ + Class_Member* member = (Class_Member*) ((POINTER_SIZE_INT) jmember); + TRACE("Requested annotations for member " << member); + return get_annotations(jenv, member->get_declared_annotations(), member->get_class()); +} + +JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__Ljava_lang_Class_2 +(JNIEnv *jenv, jclass, jclass jclazz) +{ + Class* clazz = jclass_to_struct_Class(jclazz); + TRACE("Requested annotations for class " << clazz); + return get_annotations(jenv, clazz->annotations, clazz); +} + +JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getParameterAnnotations +(JNIEnv *jenv, jclass, jlong jmethod) +{ + static Global_Env* genv = ((JNIEnv_Internal*)jenv)->vm->vm_env; + Method* method = (Method*) ((POINTER_SIZE_INT) jmethod); + Class* declaring_class = method->get_class(); + + static Class* array_class = genv->LoadCoreClass( + genv->string_pool.lookup("[Ljava/lang/annotation/Annotation;")); + + unsigned num = method->get_num_param_annotations(); + TRACE("Requested parameters annotations for method " << method + << "; num=" << num); + + jobjectArray array = NULL; + if (num == 0) { + unsigned nparams = (method->get_num_args() - (method->is_static() ? 0 : 1)); + if (nparams > 0) { + static Class* antn_class = ((JNIEnv_Internal*)jenv)->vm->vm_env->LoadCoreClass( + "java/lang/annotation/Annotation"); + array = NewObjectArray(jenv, nparams, + struct_Class_to_java_lang_Class_Handle(array_class), NewObjectArray(jenv, 0, + struct_Class_to_java_lang_Class_Handle(antn_class), NULL)); + if (!array) { + assert(exn_raised()); + return NULL; + } + return array; + } + } + + + array = NewObjectArray(jenv, num, + struct_Class_to_java_lang_Class_Handle(array_class), NULL); + + if (!array) { + assert(exn_raised()); + return NULL; + } + + for (unsigned i = 0; i < num; ++i) { + jobject element = get_annotations(jenv, method->get_param_annotations(i), declaring_class); + if (!element) { + assert(exn_raised()); + return NULL; + } else { + SetObjectArrayElement(jenv, array, i, element); + assert(!exn_raised()); + } + } + + return array; +} + +JNIEXPORT jobject JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDefaultValue +(JNIEnv *jenv, jclass, jlong jmethod) +{ + Method* method = (Method*) ((POINTER_SIZE_INT) jmethod); + TRACE("Requested default value for method " << method); + AnnotationValue* value = method->get_default_value(); + if (value) { + Class* antn_class = method->get_class(); + jthrowable error = NULL; + jobject jval = resolve_annotation_value(jenv, *value, antn_class, + method->get_name(), &error); + if (!jval && error) { + assert(!exn_raised()); + exn_raise_object(error); + } + assert(jval || exn_raised()); + return jval; + } + return NULL; +} diff --git vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.h vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.h new file mode 100644 index 0000000..4e869df --- /dev/null +++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.h @@ -0,0 +1,90 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +/* + * THE FILE HAS BEEN AUTOGENERATED BY THE IJH TOOL. + * Please be aware that all changes made to this file manually + * will be overwritten by the tool if it runs again. + */ + +#include <jni.h> + + +/* Header for class org.apache.harmony.vm.VMGenericsAndAnnotations */ + +#ifndef _ORG_APACHE_HARMONY_VM_VMGENERICSANDANNOTATIONS_H +#define _ORG_APACHE_HARMONY_VM_VMGENERICSANDANNOTATIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Native methods */ + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getSignature(J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getSignature__J(JNIEnv *, jclass, + jlong); + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getSignature(Ljava/lang/Class;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getSignature__Ljava_lang_Class_2(JNIEnv *, jclass, + jclass); + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getDeclaredAnnotations(J)[Ljava/lang/annotation/Annotation; + */ +JNIEXPORT jobjectArray JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__J(JNIEnv *, jclass, + jlong); + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getDeclaredAnnotations(Ljava/lang/Class;)[Ljava/lang/annotation/Annotation; + */ +JNIEXPORT jobjectArray JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__Ljava_lang_Class_2(JNIEnv *, jclass, + jclass); + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getParameterAnnotations(J)[[Ljava/lang/annotation/Annotation; + */ +JNIEXPORT jobjectArray JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getParameterAnnotations(JNIEnv *, jclass, + jlong); + +/* + * Method: org.apache.harmony.vm.VMGenericsAndAnnotations.getDefaultValue(J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL +Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDefaultValue(JNIEnv *, jclass, + jlong); + + +#ifdef __cplusplus +} +#endif + +#endif /* _ORG_APACHE_HARMONY_VM_VMGENERICSANDANNOTATIONS_H */ + diff --git vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp index 157a978..9a649d4 100644 --- vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp +++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp @@ -29,12 +29,14 @@ #define LOG_DOMAIN "kernel.stack" #include "cxxlog.h" +#include "open/jthread.h" #include "stack_trace.h" #include "jni_direct.h" #include "jni_utils.h" #include "environment.h" #include "exceptions.h" #include "vm_strings.h" +#include "thread_generic.h" #include "java_lang_VMClassRegistry.h" @@ -130,7 +132,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_ assert(hythread_is_suspend_enabled()); unsigned size; StackTraceFrame* frames; - st_get_trace(&size, &frames); + st_get_trace(get_thread_ptr(), &size, &frames); // The caller of the caller of this method is stored as a first element of the array. // For details look at the org/apache/harmony/vm/VMStack.java file. Thus skipping 2 frames. @@ -196,7 +198,7 @@ JNIEXPORT jobject JNICALL Java_org_apach { unsigned size; StackTraceFrame* frames; - st_get_trace(&size, &frames); + st_get_trace(get_thread_ptr(), &size, &frames); unsigned data_size = size * sizeof(StackTraceFrame); // pack trace into long[] array @@ -227,6 +229,7 @@ JNIEXPORT jobject JNICALL Java_org_apach JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMStack_getStackTrace (JNIEnv * jenv_ext, jclass, jobject state) { + ASSERT_RAISE_AREA; if (NULL == state) return NULL; @@ -379,3 +382,108 @@ JNIEXPORT jobject JNICALL Java_org_apach // reuse similar method in VMClassRegistry return Java_java_lang_VMClassRegistry_getClassLoader(jenv, NULL, clazz); } + +/* +* Class: org_apache_harmony_vm_VMStack +* Method: getThreadStackTrace +* Signature: (Ljava/lang/Thread;)[Ljava/lang/StackTraceElement; +*/ +JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMStack_getThreadStackTrace + (JNIEnv *jenv, jclass, jobject thread) +{ + unsigned size = 0; + StackTraceFrame* frames; + + VM_thread *p_thread = get_vm_thread_ptr_safe(jenv, thread); + if (p_thread != NULL) { + if (p_thread == get_thread_ptr()) { + st_get_trace(p_thread, &size, &frames); + } else { + jthread_suspend(thread); + st_get_trace(p_thread, &size, &frames); + jthread_resume(thread); + } + } + + if (0 == size) + return NULL; + + Global_Env* genv = VM_Global_State::loader_env; + + // skip the VMStart$MainThread if one exits from the bottom of the stack + // along with 2 reflection frames used to invoke method main + static String* starter_String = genv->string_pool.lookup("java/lang/VMStart$MainThread"); + Method_Handle method = frames[size-1].method; + assert(method); + // skip only for main application thread + if (!strcmp(method_get_name(method), "run") + && method->get_class()->name == starter_String) { + size -= size < 3 ? size : 3; + } + + assert(hythread_is_suspend_enabled()); + jclass ste = struct_Class_to_java_lang_Class_Handle(genv->java_lang_StackTraceElement_Class); + assert(ste); + + static jmethodID init = (jmethodID) class_lookup_method( + genv->java_lang_StackTraceElement_Class, genv->Init_String, + genv->string_pool.lookup("(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V")); + + jarray arr = jenv->NewObjectArray(size, ste, NULL); + if (!arr) { + assert(exn_raised()); + return NULL; + } + + tmn_suspend_disable(); + ObjectHandle strMethodName = oh_allocate_local_handle(); + ObjectHandle strClassName = oh_allocate_local_handle(); + tmn_suspend_enable(); + + for(unsigned i = 0; i < size; i++) { + Method_Handle method = frames[i].method; + NativeCodePtr ip = frames[i].ip; + int lineNumber; + const char* fileName; + + get_file_and_line(method, ip, &fileName, &lineNumber); + if (fileName == NULL) fileName = ""; + + jstring strFileName = jenv->NewStringUTF(fileName); + if (!strFileName) { + assert(exn_raised()); + return NULL; + } + + tmn_suspend_disable(); + // class name + String* className = class_get_java_name(method->get_class(), + VM_Global_State::loader_env); + strClassName->object = vm_instantiate_cp_string_resolved(className); + if (!strClassName->object) { + tmn_suspend_enable(); + assert(exn_raised()); + return NULL; + } + // method name + strMethodName->object = vm_instantiate_cp_string_resolved(method->get_name()); + if (!strMethodName->object) { + tmn_suspend_enable(); + assert(exn_raised()); + return NULL; + } + tmn_suspend_enable(); + + // creating StackTraceElement object + jobject obj = jenv->NewObject(ste, init, strClassName, strMethodName, + strFileName, lineNumber); + if (!obj) { + assert(exn_raised()); + return NULL; + } + + jenv->SetObjectArrayElement(arr, i, obj); + } + core_free(frames); + return arr; +} diff --git vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h index 8506283..255d298 100644 --- vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h +++ vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h @@ -74,6 +74,12 @@ JNIEXPORT jobject JNICALL Java_org_apache_harmony_vm_VMStack_getClassLoader(JNIEnv *, jclass, jclass); +/* + * Method: org_apache_harmony_vm_VMStack.getThreadStackTrace(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement; + */ +JNIEXPORT jobjectArray JNICALL +Java_org_apache_harmony_vm_VMStack_getThreadStackTrace(JNIEnv *, jclass, + jobject); #ifdef __cplusplus } diff --git vm/vmcore/src/object/object_handles.cpp vm/vmcore/src/object/object_handles.cpp index 2436125..29debdc 100644 --- vm/vmcore/src/object/object_handles.cpp +++ vm/vmcore/src/object/object_handles.cpp @@ -413,7 +413,7 @@ void free_local_object_handles(ObjectHan ObjectHandlesOld* h = (ObjectHandlesOld*)head; while(h!=(ObjectHandlesOld*)tail) { #ifdef VM_STATS - vm_stats_total.num_local_jni_handles++; + VM_Statistics::get_vm_stats().num_local_jni_handles++; #endif //VM_STATS ObjectHandlesOld* next = h->next; STD_FREE(h); @@ -425,16 +425,16 @@ void free_local_object_handles3(ObjectHa { ObjectHandlesNew* h = (ObjectHandlesNew*)head; #ifdef VM_STATS - vm_stats_total.num_free_local_called++; + VM_Statistics::get_vm_stats().num_free_local_called++; if(h != NULL) - vm_stats_total.num_free_local_called_free++; + VM_Statistics::get_vm_stats().num_free_local_called_free++; #endif //VM_STATS while(h) { #ifdef VM_STATS unsigned size = h->size; - vm_stats_total.num_local_jni_handles += size; - vm_stats_total.num_jni_handles_freed++; - vm_stats_total.num_jni_handles_wasted_refs += (h->capacity - size); + VM_Statistics::get_vm_stats().num_local_jni_handles += size; + VM_Statistics::get_vm_stats().num_jni_handles_freed++; + VM_Statistics::get_vm_stats().num_jni_handles_wasted_refs += (h->capacity - size); #endif //VM_STATS ObjectHandlesNew* next = h->next; STD_FREE(h); @@ -448,23 +448,23 @@ void free_local_object_handles2(ObjectHa ObjectHandlesNew* h = (ObjectHandlesNew*)head; assert(h); #ifdef VM_STATS - vm_stats_total.num_free_local_called++; + VM_Statistics::get_vm_stats().num_free_local_called++; if(h->next != NULL) - vm_stats_total.num_free_local_called_free++; + VM_Statistics::get_vm_stats().num_free_local_called_free++; #endif //VM_STATS while(h->next) { #ifdef VM_STATS unsigned size = h->size; - vm_stats_total.num_local_jni_handles += size; - vm_stats_total.num_jni_handles_freed++; - vm_stats_total.num_jni_handles_wasted_refs += (h->capacity - size); + VM_Statistics::get_vm_stats().num_local_jni_handles += size; + VM_Statistics::get_vm_stats().num_jni_handles_freed++; + VM_Statistics::get_vm_stats().num_jni_handles_wasted_refs += (h->capacity - size); #endif //VM_STATS ObjectHandlesNew* next = h->next; STD_FREE(h); h = next; } #ifdef VM_STATS - vm_stats_total.num_jni_handles_wasted_refs += (h->capacity - h->size); + VM_Statistics::get_vm_stats().num_jni_handles_wasted_refs += (h->capacity - h->size); #endif //VM_STATS } @@ -524,8 +524,8 @@ LilCodeStub* oh_gen_init_handle(LilCodeS unsigned offset = oh_get_handle_offset(handle_indx); if (null_check && VM_Global_State::loader_env->compress_references) { sprintf(buf, - "jc %s=%d:ref,%%n; st [%s+%d:ref],%s; j %%o; :%%g; st [%s+%d:ref],0; :%%g;", - val, (unsigned)(POINTER_SIZE_INT)Class::heap_base, base_var, offset, val, base_var, offset); + "jc %s=%p:ref,%%n; st [%s+%d:ref],%s; j %%o; :%%g; st [%s+%d:ref],0; :%%g;", + val, Class::heap_base, base_var, offset, val, base_var, offset); } else { sprintf(buf, "st [%s+%d:ref],%s;", base_var, offset, val); } diff --git vm/vmcore/src/object/vm_arrays.cpp vm/vmcore/src/object/vm_arrays.cpp index 4a2650d..28b98e6 100644 --- vm/vmcore/src/object/vm_arrays.cpp +++ vm/vmcore/src/object/vm_arrays.cpp @@ -76,15 +76,17 @@ int vector_length_offset() static Vector_Handle vm_anewarray_resolved_array_type(Class *arr_clss, int length) { #ifdef VM_STATS - vm_stats_total.num_anewarray++; + VM_Statistics::get_vm_stats().num_anewarray++; #endif + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); assert(!arr_clss->is_array_of_primitives); if (length < 0) { tmn_suspend_enable(); - throw_java_exception("java/lang/NegativeArraySizeException"); + exn_raise_by_name("java/lang/NegativeArraySizeException"); tmn_suspend_disable(); + return NULL; } unsigned sz = vm_array_size(arr_clss->vtable, length); @@ -93,10 +95,10 @@ #endif // VM does not support arrays of length >= MAXINT>>2 // GC does not support objects of length >= 1Gb tmn_suspend_enable(); - throw_java_exception("java/lang/OutOfMemoryError", + exn_raise_by_name("java/lang/OutOfMemoryError", "VM doesn't support arrays of the requested size"); tmn_suspend_disable(); - return NULL; // may be reached on interpreter or when called from jni + return NULL; } Vector_Handle object_array = (Vector_Handle )gc_alloc(sz, arr_clss->allocation_handle, vm_get_gc_thread_local()); @@ -106,9 +108,9 @@ #ifdef VM_STATS #endif //VM_STATS if (NULL == object_array) { - exn_throw( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); - return NULL; // may be reached on interpreter or when called from jni + return NULL; } set_vector_length(object_array, length); @@ -128,14 +130,15 @@ #endif //VM_STATS VMEXPORT // temporary solution for interpreter unplug Vector_Handle vm_new_vector_primitive(Class *vector_class, int length) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); // VM does not support arrays of length >= MAXINT>>2 if (length & TWO_HIGHEST_BITS_SET_MASK) { tmn_suspend_enable(); if (length < 0) { - throw_java_exception("java/lang/NegativeArraySizeException"); + exn_raise_by_name("java/lang/NegativeArraySizeException"); } else { - throw_java_exception("java/lang/OutOfMemoryError", + exn_raise_by_name("java/lang/OutOfMemoryError", "VM doesn't support arrays of the requested size"); } tmn_suspend_disable(); @@ -152,9 +155,9 @@ #ifdef VM_STATS #endif //VM_STATS if (NULL == vector) { - exn_throw( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); - return 0; // may be reached when interpreter is used + return 0; } set_vector_length(vector, length); @@ -165,11 +168,16 @@ #endif //VM_STATS VMEXPORT // temporary solution for interpreter unplug Vector_Handle vm_new_vector(Class *vector_class, int length) { + ASSERT_RAISE_AREA; + Vector_Handle returned_vector; + if(vector_class->is_array_of_primitives) { - return vm_new_vector_primitive(vector_class,length); + returned_vector = vm_new_vector_primitive(vector_class,length); } else { - return vm_anewarray_resolved_array_type(vector_class, length); + returned_vector = vm_anewarray_resolved_array_type(vector_class, length); } + + return returned_vector; } @@ -183,7 +191,7 @@ Vector_Handle vm_new_vector_or_null(Clas -void vm_new_vector_update_stats(Allocation_Handle vector_handle, POINTER_SIZE_INT length, void * UNREF tp) +void vm_new_vector_update_stats(int length, Allocation_Handle vector_handle, void * UNREF tp) { #ifdef VM_STATS if (0 != (length&TWO_HIGHEST_BITS_SET_MASK)) return; @@ -193,23 +201,22 @@ #ifdef VM_STATS vector_vtable->clss->num_bytes_allocated += sz; if (!get_prop_non_ref_array(vector_vtable->class_properties)) { - vm_stats_total.num_anewarray++; + VM_Statistics::get_vm_stats().num_anewarray++; } #endif //VM_STATS } - -Vector_Handle vm_new_vector_using_vtable_and_thread_pointer(Allocation_Handle vector_handle, int length, void *tp) +Vector_Handle vm_new_vector_using_vtable_and_thread_pointer(int length, Allocation_Handle vector_handle, void *tp) { assert( ! hythread_is_suspend_enabled()); // VM does not support arrays of length >= MAXINT>>2 if (length & TWO_HIGHEST_BITS_SET_MASK) { tmn_suspend_enable(); if (length < 0) { - throw_java_exception("java/lang/NegativeArraySizeException"); + exn_raise_by_name("java/lang/NegativeArraySizeException"); } else { - throw_java_exception("java/lang/OutOfMemoryError", + exn_raise_by_name("java/lang/OutOfMemoryError", "VM doesn't support arrays of the requested size"); } tmn_suspend_disable(); @@ -227,9 +234,9 @@ #endif //VM_STATS assert( ! hythread_is_suspend_enabled()); if (NULL == vector) { - exn_throw( + exn_raise_object( VM_Global_State::loader_env->java_lang_OutOfMemoryError); - return 0; // should never be reached + return NULL; } set_vector_length(vector, length); @@ -239,7 +246,7 @@ #endif //VM_STATS -Vector_Handle vm_new_vector_or_null_using_vtable_and_thread_pointer(Allocation_Handle vector_handle, int length, void *tp) +Vector_Handle vm_new_vector_or_null_using_vtable_and_thread_pointer(int length, Allocation_Handle vector_handle, void *tp) { // VM does not support arrays of length >= MAXINT>>2 if (0 != (length&TWO_HIGHEST_BITS_SET_MASK)) { @@ -259,7 +266,7 @@ #ifdef VM_STATSxxx // Functionality move vector_vtable->clss->num_bytes_allocated += sz; if (!get_prop_non_ref_array(vector_vtable->class_properties)) { - vm_stats_total.num_anewarray++; + VM_Statistics::get_vm_stats().num_anewarray++; } #endif //VM_STATS @@ -275,6 +282,7 @@ vm_multianewarray_recursive(Class *c, int *dims_array, unsigned dims) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); Global_Env *global_env = VM_Global_State::loader_env; int length = *dims_array; @@ -283,12 +291,11 @@ vm_multianewarray_recursive(Class *c, assert(c->name->bytes[0] == '['); assert(c->name->len > 1); + volatile Vector_Handle object_array = (Vector_Handle) vm_new_vector(c, length); + if(dims == 1) { - return (Vector_Handle)vm_new_vector(c, length); + return object_array; } else { - // Allocate an array of arrays. - volatile Vector_Handle object_array = - (Vector_Handle) vm_new_vector(c, length); assert(!hythread_is_suspend_enabled()); // Alexei // Since this function is called from a managed code @@ -350,8 +357,9 @@ vm_multianewarray_recursive(Class *c, // Vector_Handle vm_multianewarray_resolved(Class *cc, unsigned dims, ...) { +ASSERT_THROW_AREA; #ifdef VM_STATS - vm_stats_total.num_multianewarray++; + VM_Statistics::get_vm_stats().num_multianewarray++; #endif assert(!hythread_is_suspend_enabled()); @@ -364,13 +372,17 @@ #endif for(unsigned i = 0; i < dims; i++) { int d = va_arg(args, int); if (d < 0) { - throw_java_exception("java/lang/NegativeArraySizeException"); + exn_throw_by_name("java/lang/NegativeArraySizeException"); } dims_array[(dims - 1) - i] = d; } va_end(args); - Vector_Handle arr = vm_multianewarray_recursive(cc, dims_array, dims); + Vector_Handle arr; + BEGIN_RAISE_AREA; + arr = vm_multianewarray_recursive(cc, dims_array, dims); + END_RAISE_AREA; + exn_rethrow_if_pending(); return arr; } //vm_multianewarray_resolved @@ -435,7 +447,7 @@ ArrayCopyResult array_copy(ManagedObject register uint16 *src_addr = get_vector_element_address_uint16(src, srcOffset); #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_char); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_char); #endif // VM_STATS // 20030219 The length threshold 32 here works well for SPECjbb and should be reasonable for other applications. @@ -460,7 +472,7 @@ #endif // VM_STATS break; case 'B': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_byte); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_byte); #endif memmove(get_vector_element_address_int8(dst, dstOffset), get_vector_element_address_int8(src, srcOffset), @@ -468,7 +480,7 @@ #endif break; case 'Z': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_bool); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_bool); #endif memmove(get_vector_element_address_bool(dst, dstOffset), get_vector_element_address_bool(src, srcOffset), @@ -476,7 +488,7 @@ #endif break; case 'S': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_short); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_short); #endif memmove(get_vector_element_address_int16(dst, dstOffset), get_vector_element_address_int16(src, srcOffset), @@ -484,7 +496,7 @@ #endif break; case 'I': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_int); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_int); #endif // VM_STATS memmove(get_vector_element_address_int32(dst, dstOffset), get_vector_element_address_int32(src, srcOffset), @@ -492,7 +504,7 @@ #endif // VM_STATS break; case 'J': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_long); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_long); #endif // VM_STATS memmove(get_vector_element_address_int64(dst, dstOffset), get_vector_element_address_int64(src, srcOffset), @@ -500,7 +512,7 @@ #endif // VM_STATS break; case 'F': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_float); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_float); #endif // VM_STATS memmove(get_vector_element_address_f32(dst, dstOffset), get_vector_element_address_f32(src, srcOffset), @@ -508,7 +520,7 @@ #endif // VM_STATS break; case 'D': #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_double); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_double); #endif // VM_STATS memmove(get_vector_element_address_f64(dst, dstOffset), get_vector_element_address_f64(src, srcOffset), @@ -518,7 +530,7 @@ #endif // VM_STATS case '[': { #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_object); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_object); #endif // VM_STATS ManagedObject **src_body = (ManagedObject **)get_vector_element_address_ref(src, srcOffset); @@ -528,7 +540,7 @@ #endif // VM_STATS if(src_class == dst_class) { // If the types of arrays are the same, no type conflicts of array elements are possible. #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_object_same_type); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_object_same_type); #endif // VM_STATS if (VM_Global_State::loader_env->compress_references) { memmove(dst_body, src_body, length * sizeof(COMPRESSED_REFERENCE)); @@ -538,7 +550,7 @@ #endif // VM_STATS } else { // If the types are different, the arrays are different and no overlap of the source and destination is possible. #ifdef VM_STATS - increment_array_copy_counter(vm_stats_total.num_arraycopy_object_different_type); + increment_array_copy_counter(VM_Statistics::get_vm_stats().num_arraycopy_object_different_type); #endif // VM_STATS Class *dst_elem_clss = dst_class->array_element_class; assert(dst_elem_clss); diff --git vm/vmcore/src/reflection/annotations.cpp vm/vmcore/src/reflection/annotations.cpp new file mode 100644 index 0000000..426725d --- /dev/null +++ vm/vmcore/src/reflection/annotations.cpp @@ -0,0 +1,403 @@ +/* + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey V. Varlamov + * @version $Revision$ + */ + +#define LOG_DOMAIN "vm.core.annotations" +#include "cxxlog.h" + +#include <sstream> +#include <assert.h> + +#include "Class.h" +#include "annotations.h" +#include "jni.h" +#include "jni_utils.h" +#include "environment.h" +#include "reflection.h" +#include "exceptions.h" +#include "primitives_support.h" +#include "vm_log.h" + +jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss) +{ + unsigned num = table ? table->length : 0; + TRACE("annotations table size = " << num); + + static Class* antn_class = ((JNIEnv_Internal*)jenv)->vm->vm_env->LoadCoreClass( + "java/lang/annotation/Annotation"); + + jobjectArray array = NewObjectArray(jenv, num, + struct_Class_to_java_lang_Class_Handle(antn_class), NULL); + + if (!array) { + assert(exn_raised()); + return NULL; + } + + for (unsigned i = 0; i < num; ++i) { + jobject element = resolve_annotation(jenv, table->table[i], clss); + if (!element) { + assert(exn_raised()); + return NULL; + } else { + SetObjectArrayElement(jenv, array, i, element); + assert(!exn_raised()); + } + } + + return array; +} + +static Class* field_descriptor_to_type(JNIEnv* jenv, String* desc, Class* clss, + jthrowable* cause = NULL) +{ + Type_Info_Handle tih = (Type_Info_Handle) + type_desc_create_from_java_descriptor(desc->bytes, clss->class_loader); + if (tih) { + Class* type = type_info_get_class(tih); + if (type) { + return type; + } + + jthrowable jfailure; + if (exn_raised()) { + jfailure = exn_get(); + ASSERT(jfailure, "FIXME lazy exceptions handling"); + exn_clear(); + } else { + jfailure = (jthrowable)type_info_get_loading_error(tih); + } + jthrowable jnewfailure = exn_create("java/lang/TypeNotPresentException", + tih->get_type_name()->bytes, jfailure); + if (jnewfailure) { + if (cause) { + *cause = jnewfailure; + } else { + exn_raise_object(jnewfailure); + } + } else { + assert(exn_raised()); + } + } + else //malformed descriptor + { + std::stringstream ss; + ss << "Malformed type descriptor : " << desc->bytes; + ThrowNew_Quick(jenv, "java/lang/annotation/AnnotationFormatError", ss.str().c_str()); + } + + return NULL; +} + +jobject resolve_annotation(JNIEnv* jenv, Annotation* antn, Class* clss, jthrowable* cause) +{ + assert(antn); + // fail immediately if no annotation type found + Class* antn_type = field_descriptor_to_type(jenv, antn->type, clss); + if (!antn_type) { + return NULL; + } + if (!class_is_annotation(antn_type)) { + std::stringstream ss; + ss << "Non-annotation type : " << antn->type->bytes; + ThrowNew_Quick(jenv, "java/lang/annotation/AnnotationFormatError", ss.str().c_str()); + return NULL; + } + TRACE("Annotation type " << antn_type); + + static Global_Env* genv = ((JNIEnv_Internal*)jenv)->vm->vm_env; + static Class* factory_class = genv->LoadCoreClass( + "org/apache/harmony/lang/annotation/AnnotationFactory"); + static jmethodID factory_method = (jmethodID)class_lookup_method(factory_class, "createAnnotation", + "(Ljava/lang/Class;[Lorg/apache/harmony/lang/annotation/AnnotationMember;)" + "Ljava/lang/annotation/Annotation;"); + + static Class* element_class = genv->LoadCoreClass( + "org/apache/harmony/lang/annotation/AnnotationMember"); + static jmethodID element_ctor = (jmethodID)class_lookup_method(element_class, "<init>", + "(Ljava/lang/String;Ljava/lang/Object;)V"); + + unsigned num = antn->num_elements; + jobjectArray array = NULL; + if (num) { + jclass jelc = struct_Class_to_java_lang_Class_Handle(element_class); + array = NewObjectArray(jenv, num, jelc, NULL); + + if (!array) { + assert(exn_raised()); + return NULL; + } + + for (unsigned i = 0; i < num; ++i) { + jstring name = NewStringUTF(jenv, antn->elements[i].name->bytes); + if (name) { + jobject element = NULL; + jthrowable error = NULL; + jobject value = resolve_annotation_value(jenv, antn->elements[i].value, antn_type, + antn->elements[i].name, &error); + if (value) { + element = NewObject(jenv, jelc, element_ctor, name, value); + } else if (error) { + element = NewObject(jenv, jelc, element_ctor, name, error); + } + if (element) { + SetObjectArrayElement(jenv, array, i, element); + continue; + } + } + assert(exn_raised()); + return NULL; + } + } + return CallStaticObjectMethod(jenv, + struct_Class_to_java_lang_Class_Handle(factory_class), factory_method, + struct_Class_to_java_lang_Class_Handle(antn_type), array); +} // resolve_annotation + +static jobject process_enum_value(JNIEnv* jenv, AnnotationValue& value, Class* clss, + String* name, jthrowable* cause) +{ + TRACE("resolving enum type of annotation value : " << value.enum_const.type->bytes); + + // fail immediately if no enum type found + Class* enum_type = field_descriptor_to_type(jenv, value.enum_const.type, clss); + if (enum_type) { + if (class_is_enum(enum_type)) { + jobject enum_value = reflection_get_enum_value(jenv, enum_type, value.enum_const.name); + if (enum_value) { + return enum_value; + } else { + static Global_Env* genv = ((JNIEnv_Internal*)jenv)->vm->vm_env; + static Class* ECNPE_class = genv->LoadCoreClass( + "java/lang/EnumConstantNotPresentException"); + static jmethodID ECNPE_ctor = (jmethodID)class_lookup_method(ECNPE_class, "<init>", + "(Ljava/lang/Class;Ljava/lang/String;)V"); + jstring jname = NewStringUTF(jenv, value.enum_const.name->bytes); + if (jname) { + *cause = NewObject(jenv, + struct_Class_to_java_lang_Class_Handle(ECNPE_class), ECNPE_ctor, + struct_Class_to_java_lang_Class_Handle(enum_type), jname); + } + } + } else { + std::stringstream ss; + ss << "Invalid enum type " << enum_type->name->bytes + << " specified for value of element \'" << name->bytes << "\'"; + ThrowNew_Quick(jenv, "java/lang/annotation/AnnotationFormatError", ss.str().c_str()); + } + } + return NULL; +} + +static bool process_array_element(JNIEnv* jenv, AnnotationValue& value, Class* antn_type, + String* name, jthrowable* cause, + jarray array, unsigned idx, Class* type) +{ + Global_Env* genv = ((JNIEnv_Internal*)jenv)->vm->vm_env; + switch (value.tag) { + case AVT_INT: + { + if (type == genv->Int_Class) { + jint buf = (jint)value.const_value.i; + SetIntArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_BOOLEAN: + { + if (type == genv->Boolean_Class) { + jboolean buf = (jboolean)value.const_value.i; + SetBooleanArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_BYTE: + { + if (type == genv->Byte_Class) { + jbyte buf = (jbyte)value.const_value.i; + SetByteArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_SHORT: + { + if (type == genv->Short_Class) { + jshort buf = (jshort)value.const_value.i; + SetShortArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_CHAR: + { + if (type == genv->Char_Class) { + jchar buf = (jchar)value.const_value.i; + SetCharArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_LONG: + { + if (type == genv->Long_Class) { + jlong buf = (jlong)value.const_value.j; + SetLongArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_FLOAT: + { + if (type == genv->Float_Class) { + jfloat buf = (jfloat)value.const_value.f; + SetFloatArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + } + case AVT_DOUBLE: + { + if (type == genv->Double_Class) { + jdouble buf = (jdouble)value.const_value.d; + SetDoubleArrayRegion(jenv, array, (jsize)idx, (jsize)1, &buf); + return true; + } + + // primitive value type does not match array type + std::stringstream ss; + ss << "Encountered value tag \'" << (char)value.tag + << "\' does not match array type " << type->name->bytes << "[]"; + + *cause = CreateNewThrowable(jenv, genv->java_lang_ArrayStoreException_Class, + ss.str().c_str(), NULL); + } + default: + { + jobject jelement = resolve_annotation_value(jenv, value, antn_type, name, cause); + if (jelement) { + SetObjectArrayElement(jenv, array, idx, jelement); + if (exn_raised()) { + *cause = exn_get(); + exn_clear(); + } else { + return true; + } + } + } + } // switch + + assert(cause || exn_raised()); + return false; +} + + +jobject resolve_annotation_value(JNIEnv* jenv, AnnotationValue& value, Class* antn_type, + String* name, jthrowable* cause) +{ + TRACE("Resolving value of tag " << (char)value.tag); + jvalue jconst; + switch (value.tag) { + case AVT_INT: + case AVT_BOOLEAN: + case AVT_BYTE: + case AVT_SHORT: + case AVT_CHAR: + jconst.i = value.const_value.i; + return wrap_primitive(jenv, jconst, (char)value.tag); + case AVT_LONG: + jconst.j = value.const_value.j; + return wrap_primitive(jenv, jconst, (char)value.tag); + case AVT_FLOAT: + jconst.f = value.const_value.f; + return wrap_primitive(jenv, jconst, (char)value.tag); + case AVT_DOUBLE: + jconst.d = value.const_value.d; + return wrap_primitive(jenv, jconst, (char)value.tag); + + case AVT_STRING: + return NewStringUTF(jenv, value.const_value.string->bytes); + + case AVT_CLASS: + { + // preserve failure if no Class value found + Class* type = field_descriptor_to_type(jenv, value.class_name, antn_type, cause); + return type ? struct_Class_to_java_lang_Class_Handle(type) : NULL; + } + + case AVT_ANNOTN: + return resolve_annotation(jenv, value.nested, antn_type, cause); + + case AVT_ENUM: + return process_enum_value(jenv, value, antn_type, name, cause); + + case AVT_ARRAY: + { + // Need to find out class of array elements. + // As zero-sized arrays are legal, have to check return type + // of the element-defining method. + Class* arr_type = NULL; + unsigned i; + for (i = 0; i < antn_type->n_methods; i++) { + Method* m = antn_type->methods + i; + if (m->get_name() == name && m->get_num_args() == 1) + { + Type_Info_Handle tih = method_ret_type_get_type_info( + method_get_signature((Method_Handle)m)); + if (type_info_is_vector(tih)) { + arr_type = type_info_get_class(tih); + if (!arr_type) { + *cause= (jthrowable)type_info_get_loading_error(tih); + return NULL; + } + } + break; + } + } + if (!arr_type || arr_type->n_dimensions != 1) { + std::stringstream ss; + ss << "Invalid array value for element \'" << name->bytes << "\'"; + ThrowNew_Quick(jenv, "java/lang/annotation/AnnotationFormatError", ss.str().c_str()); + return NULL; + } + arr_type = arr_type->array_element_class; + + jclass jarr_type = struct_Class_to_java_lang_Class_Handle(arr_type); + jarray array = NewObjectArray(jenv, (jsize)value.array.length, jarr_type, NULL); + + if (!array) { + assert(exn_raised()); + return NULL; + } + + for (i = 0; i < value.array.length; ++i) { + if (!process_array_element(jenv, value.array.items[i], antn_type, + name, cause, array, i, arr_type)) + { + return NULL; + } + assert(!exn_raised()); + } + return array; + } + } // switch + + std::stringstream ss; + ss << "Unrecognized value tag \'" << (char)value.tag + << "\' for element \'" << name->bytes << "\'"; + ThrowNew_Quick(jenv, "java/lang/annotation/AnnotationFormatError", ss.str().c_str()); + + return NULL; +} // resolve_annotation_value + diff --git vm/vmcore/src/reflection/reflection.cpp vm/vmcore/src/reflection/reflection.cpp index f63baf7..87e0be5 100644 --- vm/vmcore/src/reflection/reflection.cpp +++ vm/vmcore/src/reflection/reflection.cpp @@ -34,63 +34,21 @@ #include "exceptions.h" #include "heap.h" #include "primitives_support.h" -Field* get_reflection_field(Class* clss, reflection_fields descriptor) -{ - Global_Env* genv = VM_Global_State::loader_env; - static String* extra_strings[][2] = { - {genv->string_pool.lookup("parameterTypes"), genv->string_pool.lookup("[Ljava/lang/Class;")}, - {genv->string_pool.lookup("exceptionTypes"), genv->string_pool.lookup("[Ljava/lang/Class;")}, - {genv->string_pool.lookup("declaringClass"), genv->string_pool.lookup("Ljava/lang/Class;")}, - {genv->string_pool.lookup("name"), genv->string_pool.lookup("Ljava/lang/String;")}, - {genv->string_pool.lookup("type"), genv->string_pool.lookup("Ljava/lang/Class;")}, - {genv->string_pool.lookup("vm_member"), genv->string_pool.lookup("J")}, - }; - - static Field* resolved[FIELDS_NUMBER]; - - Field *field = resolved[descriptor]; - if (!field) { - String* name = extra_strings[descriptor][0]; - String* sig = extra_strings[descriptor][1]; - TRACE("Resolving special class field : " << name->bytes); - field = class_lookup_field_recursive(clss, name, sig); - ASSERT(field, "Cannot find special class field : " << name->bytes << " / " << sig->bytes); - resolved[descriptor] = field; - } - - return field; -} - -Class_Member* reflection_jobject_to_Class_Member(jobject jmember, Class* type) -{ - Field *field = get_reflection_field(type, VM_MEMBER); - - tmn_suspend_disable(); - Byte *java_ref = (Byte *)jmember->object; - jlong member = *(jlong *)(java_ref + field->get_offset()); - tmn_suspend_enable(); - assert(member); - - return (Class_Member*) ((POINTER_SIZE_INT) member); -} - -static Class_Handle get_class(Type_Info_Handle type_info) { - Class_Handle clss = type_info_get_class(type_info); +jclass descriptor_to_jclass(Type_Info_Handle desc){ + Class_Handle clss = type_info_get_class(desc); if (!clss) { if (!exn_raised()) { - exn_raise_only((jthrowable) type_info_get_loading_error(type_info)); + exn_raise_object((jthrowable) type_info_get_loading_error(desc)); } + return NULL; } - return clss; + return struct_Class_to_java_lang_Class_Handle(clss); } // Set parameterTypes and exceptionTypes fields for Method or Constructor object -jobjectArray reflection_get_parameter_types(JNIEnv *jenv, Class* type, jobject jmethod, Method* method) +jobjectArray reflection_get_parameter_types(JNIEnv *jenv, Method* method) { - if (!method) { - method = (Method*)reflection_jobject_to_Class_Member(jmethod, type); - } jclass jlc_class = struct_Class_to_java_lang_Class_Handle(VM_Global_State::loader_env->JavaLangClass_Class); // Create an array of the argument types @@ -109,144 +67,68 @@ jobjectArray reflection_get_parameter_ty for (i = 0; i < nparams; i++) { Type_Info_Handle arg_type = method_args_get_type_info(msh, i+start); - Class_Handle arg_clss = get_class(arg_type); + jclass arg_clss = descriptor_to_jclass(arg_type); if (!arg_clss) return NULL; - SetObjectArrayElement(jenv, arg_types, i, struct_Class_to_java_lang_Class_Handle(arg_clss)); + SetObjectArrayElement(jenv, arg_types, i, arg_clss); } - // Set paramaterTypes field - //jfieldID parameterTypes_id = (jfieldID)get_reflection_field(type, PARAMETERS); - //SetObjectField(jenv, jmethod, parameterTypes_id, arg_types); - return arg_types; } -// Set name field for Method or Field object -static bool set_name_field(JNIEnv *jenv, String* value, jobject jmember, Class* type) -{ - jstring name = String_to_interned_jstring(value); - if (name == NULL) { - assert(exn_raised()); - return false; - } - - jfieldID name_id = (jfieldID)get_reflection_field(type, NAME); - SetObjectField(jenv, jmember, name_id, name); - - return true; -} - -// Set type field for Method or Field object -static bool set_type_field(JNIEnv *jenv, jobject jmember, Class* type, Type_Info_Handle type_info) -{ - Class_Handle clss = get_class(type_info); - if (!clss) { - return false; - } - jfieldID type_id = (jfieldID)get_reflection_field(type, TYPE); - SetObjectField(jenv, jmember, type_id, struct_Class_to_java_lang_Class_Handle(clss)); - return true; -} - // Construct object of member_class (Constructor, Field, Method). -// Set declaringClass field. static jobject reflect_member(JNIEnv *jenv, Class_Member* member, Class* type) { - Global_Env* genv = VM_Global_State::loader_env; - // Construct member object - tmn_suspend_disable(); - jobject jmember = oh_allocate_local_handle(); - ManagedObject *new_obj = class_alloc_new_object(type); - if (!new_obj) { - tmn_suspend_enable(); + ASSERT_RAISE_AREA; + static Global_Env* genv = VM_Global_State::loader_env; + static String* desc = genv->string_pool.lookup( + "(JLjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V"); + Method* member_constr = class_lookup_method(type, genv->Init_String, desc); + + jstring jname = String_to_interned_jstring(member->get_name()); + if (jname == NULL) { + assert(exn_raised()); return NULL; } - jmember->object = new_obj; - tmn_suspend_enable(); - - // Call constructor of member class on newly allocated object - // passing this object itself as a parameter - static String* descr = genv->string_pool.lookup("(Ljava/lang/Object;)V"); - Method* member_constr = class_lookup_method(type, genv->Init_String, descr); - jvalue args; - args.l = jmember; - CallVoidMethodA(jenv, jmember, (jmethodID)member_constr, &args); - if (exn_raised()) - return NULL; - - // Set vm_member field - jfieldID member_id = (jfieldID)get_reflection_field(type, VM_MEMBER); - jlong long_member = (jlong) ((POINTER_SIZE_INT) member); - SetLongField(jenv, jmember, member_id, long_member); - - // Set declaringClass field - jfieldID clazz_id = (jfieldID)get_reflection_field(type, DECLARING_CLASS); - SetObjectField(jenv, jmember, clazz_id, struct_Class_to_java_lang_Class_Handle(member->get_class())); - - return jmember; -} //reflect_member - -jobject reflection_reflect_method(JNIEnv *jenv, Method_Handle method) -{ - // Construct a java.lang.reflect.Method object - Class* type = VM_Global_State::loader_env->java_lang_reflect_Method_Class; - jobject jmethod = reflect_member(jenv, method, type); - if (!jmethod) { + jstring jdesc = String_to_interned_jstring(member->get_descriptor()); + if (jdesc == NULL) { assert(exn_raised()); return NULL; } - if (!set_name_field(jenv, method->get_name(), jmethod, type)) { + jvalue args[5]; + args[0].j = (jlong) ((POINTER_SIZE_INT) member); + args[1].l = struct_Class_to_java_lang_Class_Handle(member->get_class()); + args[2].l = jname; + args[3].l = jdesc; + args[4].i = (jint)member->get_access_flags(); + jobject jmember = NewObjectA(jenv, struct_Class_to_java_lang_Class_Handle(type), + (jmethodID)member_constr, args); + if (!jmember) { assert(exn_raised()); - return NULL; } - //Too early to try load classes for PARAMETERS and return TYPE. - //No need to set EXCEPTIONS in advance - it is almost never requested. + return jmember; +} //reflect_member - return jmethod; +jobject reflection_reflect_method(JNIEnv *jenv, Method_Handle method) +{ + return reflect_member(jenv, method, + VM_Global_State::loader_env->java_lang_reflect_Method_Class); } jobject reflection_reflect_constructor(JNIEnv *jenv, Method_Handle constructor) { - // Construct a java.lang.reflect.Constructor object - Class* type = VM_Global_State::loader_env->java_lang_reflect_Constructor_Class; - jobject jconst = reflect_member(jenv, constructor, type); - if (!jconst) - return NULL; - - //Too early to try load classes for PARAMETERS. - //No need to set EXCEPTIONS in advance - it is almost never requested. - //No need to set name in advance - it is useless for constructors. - - return jconst; + return reflect_member(jenv, constructor, + VM_Global_State::loader_env->java_lang_reflect_Constructor_Class); } jobject reflection_reflect_field(JNIEnv *jenv, Field_Handle field) { - assert(field); - // We do not reflect injected fields - if (field_is_injected(field)) return NULL; - - // Construct a java.lang.reflect.Field object - Class* type = VM_Global_State::loader_env->java_lang_reflect_Field_Class; - jobject jfield = reflect_member(jenv, field, type); - if (!jfield) - return NULL; - - if (!set_name_field(jenv, field->get_name(), jfield, type)) - return NULL; - - // Get type - Type_Info_Handle field_type = field_get_type_info_of_field_value(field); + //if (field_is_injected(field)) return NULL; - if (!set_type_field(jenv, jfield, type, field_type)) { - assert(exn_raised()); - return NULL; - } - - return jfield; + return reflect_member(jenv, field, + VM_Global_State::loader_env->java_lang_reflect_Field_Class); } jobjectArray reflection_get_class_interfaces(JNIEnv* jenv, jclass clazz) @@ -264,10 +146,8 @@ jobjectArray reflection_get_class_interf // Fill the array for (unsigned i = 0; i < intf_number; i++) { - jclass intf = jni_class_from_handle(jenv, class_get_implements(clss, i)); + jclass intf = struct_Class_to_java_lang_Class_Handle(class_get_implements(clss, i)); SetObjectArrayElement(jenv, arr, i, intf); - if (exn_raised()) - return NULL; } return arr; @@ -287,7 +167,7 @@ jobjectArray reflection_get_class_fields for (i = 0; i < num_fields; i++) { Field_Handle fh = class_get_field(clss, i); if (field_is_injected(fh)) continue; - if (class_is_array(clss) && 0 == strcmp("length", field_get_name(fh))) continue; + //if (class_is_array(clss) && 0 == strcmp("length", field_get_name(fh))) continue; num_res_fields++; } @@ -303,9 +183,13 @@ jobjectArray reflection_get_class_fields for(i = 0; i < num_fields; i++) { Field_Handle fh = class_get_field(clss, i); if (field_is_injected(fh)) continue; - if (class_is_array(clss) && 0 == strcmp("length", field_get_name(fh))) continue; + //if (class_is_array(clss) && 0 == strcmp("length", field_get_name(fh))) continue; jobject jfield = reflection_reflect_field(jenv, fh); + if (!jfield){ + assert(exn_raised()); + return NULL; + } SetObjectArrayElement(jenv, farray, num_res_fields, jfield); if (exn_raised()) return NULL; num_res_fields++; @@ -342,6 +226,10 @@ jobjectArray reflection_get_class_constr if (strcmp(method_get_name(mh), "<init>") != 0) continue; jobject jconst = reflection_reflect_constructor(jenv, mh); + if (!jconst){ + assert(exn_raised()); + return NULL; + } SetObjectArrayElement(jenv, carray, n_consts++, jconst); if (exn_raised()) return NULL; } @@ -384,6 +272,10 @@ jobjectArray reflection_get_class_method continue; jobject member = reflection_reflect_method(jenv, mh); + if (!member){ + assert(exn_raised()); + return NULL; + } SetObjectArrayElement(jenv, member_array, member_i, member); if (exn_raised()) return NULL; @@ -435,3 +327,30 @@ bool jobjectarray_to_jvaluearray(JNIEnv return true; } //jobjectarray_to_jvaluearray + +jobject reflection_get_enum_value(JNIEnv *jenv, Class* enum_type, String* name) +{ + ASSERT(class_is_enum(enum_type), "Requested Class is not ENUM: " + << enum_type->name->bytes); + + for (unsigned i=0; i<enum_type->n_fields; i++) { + if (enum_type->fields[i].get_name() == name) { +#ifndef NDEBUG + ASSERT(enum_type->fields[i].is_enum(), "Requested field is not ENUM: " << name->bytes); + const String* type = enum_type->name; + const String* desc = enum_type->fields[i].get_descriptor(); + if (desc->len != (type->len + 2) + || desc->bytes[0] != 'L' + || strncmp(desc->bytes + 1, type->bytes, type->len) + || desc->bytes[type->len + 1] != ';') + { + DIE("Invalid enum field descriptor: " << desc->bytes); + } +#endif + return GetStaticObjectField(jenv, 0, (jfieldID)(enum_type->fields + i)); + } + } + //public EnumConstantNotPresentException(Class<? extends Enum> enumType,String constantName) + //ThrowNew_Quick(jenv, "java.lang.EnumConstantNotPresentException", name->bytes); + return NULL; +} diff --git vm/vmcore/src/stack/stack_dump.cpp vm/vmcore/src/stack/stack_dump.cpp new file mode 100755 index 0000000..b246fe2 --- /dev/null +++ vm/vmcore/src/stack/stack_dump.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Vladimir Nenashev + * @version $Revision$ + */ + +#include "stack_dump.h" +#include "native_stack.h" +#include "vm_threads.h" +#include "port_malloc.h" +#include "jit_intf_cpp.h" +#include "Class.h" +#include "stack_trace.h" + +#ifdef PLATFORM_NT + +#ifndef NO_DBGHELP +#include <dbghelp.h> +#pragma comment(linker, "/defaultlib:dbghelp.lib") +#endif + +#else +#include <unistd.h> +#endif + +// Symbolic method info: method name, source file name and a line number of an instruction within the method +struct MethodInfo { + char* method_name; + char* file_name; + int line; +}; + +#ifdef PLATFORM_POSIX + +/** + * Find a module which a given IP address belongs to. + * Returns module file name and offset of an IP address from beginnig of the segment (used in addr2line tool) + */ +static char* get_module(native_module_t* info, jint num_modules, void* ip, POINTER_SIZE_INT* offset) { + for (int i = 0; i < num_modules; i++, info = info->next) { + for (int j = 0; j < info->seg_count; j++) { + if (info->segments[j].type != SEGMENT_TYPE_DATA) { + if ( (POINTER_SIZE_INT) info->segments[j].base <= (POINTER_SIZE_INT) ip && + (POINTER_SIZE_INT) ip < (POINTER_SIZE_INT) info->segments[j].base + info->segments[j].size) { + *offset = (POINTER_SIZE_INT) ip - (POINTER_SIZE_INT) info->segments[j].base; + return info->filename; + } + } + } + } + return NULL; +} +#endif + +static void st_get_c_method_info(MethodInfo* info, void* ip) { + info->method_name = NULL; + info->file_name = NULL; + info->line = -1; +#ifdef PLATFORM_NT +#ifndef NO_DBGHELP + if (!SymInitialize(GetCurrentProcess(), NULL, true)) { + return; + } + BYTE smBuf[sizeof(SYMBOL_INFO) + 2048]; + PSYMBOL_INFO pSymb = (PSYMBOL_INFO)smBuf; + pSymb->SizeOfStruct = sizeof(smBuf); + pSymb->MaxNameLen = 2048; + DWORD64 funcDispl; + if(SymFromAddr(GetCurrentProcess(), (DWORD64)ip, &funcDispl, pSymb)) { + info->method_name = (char*) STD_MALLOC(strlen(pSymb->Name) + 1); + strcpy(info->method_name, pSymb->Name); + } + DWORD lineOffset; + IMAGEHLP_LINE lineInfo; + if (SymGetLineFromAddr(GetCurrentProcess(), (DWORD)ip, &lineOffset, &lineInfo)) { + info->line = lineInfo.LineNumber; + info->file_name = (char*) STD_MALLOC(strlen(lineInfo.FileName) + 1); + strcpy(info->file_name, lineInfo.FileName); + + } +#else + return; +#endif +#else // PLATFORM_NT + jint num_modules; + native_module_t* modules; + if (!get_all_native_modules(&modules, &num_modules)) { + fprintf(stderr, "Warning: Cannot get modules info, no symbolic information will be provided\n"); + return; + } + + POINTER_SIZE_INT offset; + char* module = get_module(modules, num_modules, ip, &offset); + if (module) { + int pi[2]; + int po[2]; + pipe(pi); + pipe(po); + if (!fork()) { + close(po[0]); + close(pi[1]); + dup2(po[1], 1); + dup2(pi[0], 0); + execlp("addr2line", "addr2line", "-f", "-e", module, "-C", NULL); + fprintf(stderr, "Warning: Cannot run addr2line. No symbolic information will be available\n"); + printf("??\n??:0\n"); // Emulate addr2line output + exit(-1); + } else { + close(po[1]); + close(pi[0]); + char ip_str[9]; + sprintf(ip_str, "%08x\n", (uint32) offset); // !!!FIXME: WORKS FOR IA32 ONLY + write(pi[1], ip_str, 9); + close(pi[1]); + char buf[256]; + int status; + wait(&status); + int count = read(po[0], buf, 255); + close(po[0]); + if (count >= 0) { + while (isspace(buf[count-1])) { + count--; + } + buf[count] = '\0'; + int i = 0; + for (; i < count; i++) { + if (buf[i] == '\n') { // Function name is limited by '\n' + buf[i] = '\0'; + info->method_name = (char*) STD_MALLOC(strlen(buf) + 1); + strcpy(info->method_name, buf); + break; + } + } + char* fn = buf + i + 1; + for (; i < count && buf[i] != ':'; i++) // File name and line number are separated by ':' + ; + buf[i] = '\0'; + info->file_name = (char*) STD_MALLOC(strlen(fn) + 1); + strcpy(info->file_name, fn); + char* line = buf + i + 1; + info->line = atoi(line); + if (info->line == 0) { + info->line = -1; + } + } else { + fprintf(stderr, "read() failed during execution of addr2line\n"); + } + } + } +#endif +} + +static void st_get_java_method_info(MethodInfo* info, Method* m, void* ip) { + info->file_name = NULL; + info->line = -1; + info->method_name = NULL; + assert(m); + if (m->get_class()->src_file_name && m->get_class()->src_file_name->bytes) { + const char* fname = m->get_class()->src_file_name->bytes; + size_t flen = strlen(fname); + info->file_name = (char*) STD_MALLOC(flen + 1); + strcpy(info->file_name, fname); + } + + const char* mname = m->get_name()->bytes; + size_t mlen = strlen(mname); + const char* cname = m->get_class()->name->bytes; + size_t clen = strlen(cname); + const char* descr = m->get_descriptor()->bytes; + size_t dlen = strlen(descr); + + info->method_name = (char*) STD_MALLOC(mlen + clen + dlen + 2); + memcpy(info->method_name, cname, clen); + info->method_name[clen] = '.'; + memcpy(info->method_name + clen + 1, mname, mlen); + memcpy(info->method_name + clen + mlen + 1, descr, dlen); + info->method_name[clen + mlen + dlen + 1] = '\0'; + + const char* f; + get_file_and_line(m, ip, &f, &info->line); +} + +static void st_print_line(int count, MethodInfo* m) { + fprintf(stderr, "\t%d: %s (%s:%d)\n", + count, + m->method_name ? m->method_name : "??", + m->file_name ? m->file_name : "??", + m->line); + if (m->file_name) { + STD_FREE(m->file_name); + } + if (m->method_name) { + STD_FREE(m->method_name); + } +} + +void st_print_stack(Registers* regs) { + jint num_frames; + native_frame_t* frames; + num_frames = walk_native_stack_registers(regs, p_TLS_vmthread, -1, NULL); + frames = (native_frame_t*) STD_ALLOCA(sizeof(native_frame_t) * num_frames); + + num_frames = walk_native_stack_registers(regs, p_TLS_vmthread, num_frames, frames); + StackIterator* si = si_create_from_native(); + fprintf(stderr, "Stack trace:\n"); + for (int i = 0; i < num_frames; i++) { + static int count = 0; + MethodInfo m; + if (frames[i].java_depth == -1 && !native_is_ip_stub(frames[i].ip)) { // Pure native method + st_get_c_method_info(&m, frames[i].ip); + } else if (frames[i].java_depth == -1) { // Generated stub + fprintf(stderr, "\t%d: IP is 0x%08X <native code>\n", ++count, (POINTER_SIZE_INT) frames[i].ip); //FIXME: IA32 ONLY + continue; + } else { // Java/JNI native method + CodeChunkInfo* cci = si_get_code_chunk_info(si); + if (!cci) { // JNI native method + st_get_c_method_info(&m, frames[i].ip); + } else { // Java method + uint32 inlined_depth = si_get_inline_depth(si); + uint32 offset = (POINTER_SIZE_INT)si_get_ip(si) - (POINTER_SIZE_INT)cci->get_code_block_addr(); + for (uint32 j = 0; j < inlined_depth; j++) { + Method *real_method = cci->get_jit()->get_inlined_method(cci->get_inline_info(), offset, j); + st_get_java_method_info(&m, real_method, frames[i].ip); + st_print_line(++count, &m); + } + st_get_java_method_info(&m, cci->get_method(), frames[i].ip); + } + si_goto_previous(si); + } + st_print_line(++count, &m); + } + fprintf(stderr, "<end of stack trace>\n"); +} diff --git vm/vmcore/src/stack/stack_trace.cpp vm/vmcore/src/stack/stack_trace.cpp index 3737e2c..81ee4e3 100644 --- vm/vmcore/src/stack/stack_trace.cpp +++ vm/vmcore/src/stack/stack_trace.cpp @@ -27,44 +27,6 @@ #include "jit_intf_cpp.h" #include "method_lookup.h" -Method_Handle get_method(StackIterator* si) -{ - ASSERT_NO_INTERPRETER - CodeChunkInfo* cci = si_get_code_chunk_info(si); - if (cci) - return cci->get_method(); - else - return m2n_get_method(si_get_m2n(si)); -} - -uint32 si_get_inline_depth(StackIterator* si) -{ - // - // Here we assume that JIT data blocks can store only InlineInfo - // A better idea is to extend JIT_Data_Block with some type information - // Example: - // - // enum JIT_Data_Block_Type { InlineInfo, Empty } - // - // struct JIT_Data_Block { - // JIT_Data_Block *next; - // JIT_Data_Block_Type type; - // char bytes[1]; - // }; - // - // void *Method::allocate_JIT_data_block(size_t size, JIT *jit, JIT_Data_Block_Type) - // - - ASSERT_NO_INTERPRETER - CodeChunkInfo* cci = si_get_code_chunk_info(si); - if ( cci != NULL && cci->has_inline_info()) { - return cci->get_jit()->get_inline_depth( - cci->get_inline_info(), - (POINTER_SIZE_INT)si_get_ip(si) - (POINTER_SIZE_INT)cci->get_code_block_addr()); - } - return 0; -} - void get_file_and_line(Method_Handle mh, void *ip, const char **file, int *line) { Method *method = (Method*)mh; *file = class_get_source_file_name(method_get_class(method)); @@ -104,13 +66,13 @@ #if !defined(_IPF_) // appropriate callL #endif } -unsigned st_get_depth() +unsigned st_get_depth(VM_thread *p_vmthread) { ASSERT_NO_INTERPRETER - StackIterator* si = si_create_from_native(); + StackIterator* si = si_create_from_native(p_vmthread); unsigned depth = 0; while (!si_is_past_end(si)) { - if (get_method(si)) { + if (si_get_method(si)) { depth += 1 + si_get_inline_depth(si); } si_goto_previous(si); @@ -128,7 +90,7 @@ bool st_get_frame(unsigned target_depth, StackIterator* si = si_create_from_native(); unsigned depth = 0; while (!si_is_past_end(si)) { - stf->method = get_method(si); + stf->method = si_get_method(si); if (stf->method) { uint32 inlined_depth = si_get_inline_depth(si); if ( (target_depth >= depth) && @@ -167,25 +129,25 @@ static inline void *get_this(JIT *jit, M return NULL; } -void st_get_trace(unsigned* res_depth, StackTraceFrame** stfs) +void st_get_trace(VM_thread *p_vmthread, unsigned* res_depth, StackTraceFrame** stfs) { tmn_suspend_disable(); if (interpreter_enabled()) { - interpreter.interpreter_st_get_trace(res_depth, stfs); + interpreter.interpreter_st_get_trace(p_vmthread, res_depth, stfs); tmn_suspend_enable(); return; } - unsigned depth = st_get_depth(); + unsigned depth = st_get_depth(p_vmthread); StackTraceFrame* stf = st_alloc_frames(depth); assert(stf); *res_depth = depth; *stfs = stf; - StackIterator* si = si_create_from_native(); + StackIterator* si = si_create_from_native(p_vmthread); depth = 0; while (!si_is_past_end(si)) { - Method_Handle method = get_method(si); + Method_Handle method = si_get_method(si); if (method) { NativeCodePtr ip = si_get_ip(si); @@ -248,7 +210,7 @@ void st_print(FILE* f) unsigned depth = 0; while (!si_is_past_end(si)) { fprintf(f, " [%p] %p(%c): ", p_TLS_vmthread, si_get_ip(si), (si_is_native(si) ? 'n' : 'm')); - Method_Handle m = get_method(si); + Method_Handle m = si_get_method(si); if (m) { CodeChunkInfo* cci = si_get_code_chunk_info(si); diff --git vm/vmcore/src/thread/hythr/hythr.def vm/vmcore/src/thread/hythr/hythr.def deleted file mode 100644 index e69de29..0000000 diff --git vm/vmcore/src/thread/hythr/hythreads.cpp vm/vmcore/src/thread/hythr/hythreads.cpp deleted file mode 100644 index e69de29..0000000 diff --git vm/vmcore/src/thread/hythr/hythreads.h vm/vmcore/src/thread/hythr/hythreads.h deleted file mode 100644 index e69de29..0000000 diff --git vm/vmcore/src/thread/mon_enter_exit.cpp vm/vmcore/src/thread/mon_enter_exit.cpp index 02c8ea1..39acf4e 100644 --- vm/vmcore/src/thread/mon_enter_exit.cpp +++ vm/vmcore/src/thread/mon_enter_exit.cpp @@ -21,20 +21,44 @@ #define LOG_DOMAIN "enumeration" #include "cxxlog.h" +#include "platform_lowlevel.h" +#include <assert.h> + +//MVM +#include <iostream> + +using namespace std; + + +#include "open/types.h" +#include "open/jthread.h" +#include "object_layout.h" +#include "vm_threads.h" +#include "jit_runtime_support.h" #include "exceptions.h" + #include "mon_enter_exit.h" -#include "environment.h" #include "thread_generic.h" + +#include "object_generic.h" #include "vm_synch.h" +#include "vm_stats.h" +#include "object_handles.h" + +#include "vm_process.h" +//#include "java_mrte.h" #include "port_atomic.h" -#include "open/jthread.h" static void vm_monitor_exit_default(ManagedObject *p_obj); static void vm_monitor_enter_default(ManagedObject *p_obj); +static uint32 vm_monitor_try_enter_default(ManagedObject *p_obj); +static uint32 vm_monitor_try_exit_default(ManagedObject *p_obj); void (*vm_monitor_enter)(ManagedObject *p_obj) = 0; void (*vm_monitor_exit)(ManagedObject *p_obj) = 0; +uint32 (*vm_monitor_try_enter)(ManagedObject *p_obj) = 0; +uint32 (*vm_monitor_try_exit)(ManagedObject *p_obj) = 0; void vm_enumerate_root_set_mon_arrays() @@ -44,11 +68,15 @@ void vm_enumerate_root_set_mon_arrays() void vm_monitor_init() { vm_monitor_enter = vm_monitor_enter_default; + vm_monitor_try_enter = vm_monitor_try_enter_default; vm_monitor_exit = vm_monitor_exit_default; - } + vm_monitor_try_exit = vm_monitor_try_exit_default; +} static void vm_monitor_enter_default(ManagedObject *p_obj) { + assert(managed_object_is_valid(p_obj)); + // assert(!hythread_is_suspend_enabled()); assert(p_obj); jobject jobj = oh_allocate_local_handle(); @@ -59,11 +87,22 @@ static void vm_monitor_enter_default(Man static void vm_monitor_exit_default(ManagedObject *p_obj) { assert(managed_object_is_valid(p_obj)); + // + assert(!hythread_is_suspend_enabled()); + assert(p_obj); jobject jobj = oh_allocate_local_handle(); jobj->object = p_obj; jthread_monitor_exit(jobj); } +static uint32 vm_monitor_try_enter_default(ManagedObject *p_obj) { + return (uint32)hythread_thin_monitor_try_enter((hythread_thin_monitor_t *)((char *)p_obj+4)); +} + +static uint32 vm_monitor_try_exit_default(ManagedObject *p_obj) { + return (uint32)hythread_thin_monitor_exit((hythread_thin_monitor_t *)((char *)p_obj+4)); +} + // returns true if the object has its monitor taken... // asserts if the object header is ill-formed. diff --git vm/vmcore/src/thread/object_generic.cpp vm/vmcore/src/thread/object_generic.cpp index eb37dac..54a3896 100644 --- vm/vmcore/src/thread/object_generic.cpp +++ vm/vmcore/src/thread/object_generic.cpp @@ -66,8 +66,9 @@ void set_hash_bits(ManagedObject *p_obj) port_atomic_cas8(P_HASH_CONTENTION_BYTE(p_obj),hb, 0); } -long generic_hashcode(ManagedObject * p_obj) -{ +jint default_hashcode(Managed_Object_Handle obj) { + ManagedObject *p_obj = (ManagedObject*) obj; + if (!p_obj) return 0L; if ( *P_HASH_CONTENTION_BYTE(p_obj) & HASH_MASK) return *P_HASH_CONTENTION_BYTE(p_obj) & HASH_MASK; @@ -81,6 +82,11 @@ long generic_hashcode(ManagedObject * p_ return 0xff; } +long generic_hashcode(ManagedObject * p_obj) +{ + return (long) gc_get_hashcode0((Managed_Object_Handle) p_obj); +} + jint object_get_generic_hashcode(JNIEnv*, jobject jobj) { @@ -98,6 +104,7 @@ jint object_get_generic_hashcode(JNIEnv* jobject object_clone(JNIEnv *jenv, jobject jobj) { + ASSERT_RAISE_AREA; ManagedObject *result; assert(hythread_is_suspend_enabled()); if(!jobj) { @@ -116,7 +123,7 @@ jobject object_clone(JNIEnv *jenv, jobje size = vm_array_size(vt, length); result = (ManagedObject *) vm_new_vector_using_vtable_and_thread_pointer( - vt->clss->allocation_handle, length, vm_get_gc_thread_local()); + length, vt->clss->allocation_handle, vm_get_gc_thread_local()); } else { @@ -133,7 +140,7 @@ jobject object_clone(JNIEnv *jenv, jobje } if (result == NULL) { tmn_suspend_enable(); - exn_throw(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return NULL; } memcpy(result, h->object, size); diff --git vm/vmcore/src/thread/thread_generic.cpp vm/vmcore/src/thread/thread_generic.cpp old mode 100644 new mode 100755 index f81f36e..c8f5035 --- vm/vmcore/src/thread/thread_generic.cpp +++ vm/vmcore/src/thread/thread_generic.cpp @@ -77,6 +77,8 @@ #endif #ifdef _IPF_ #include "java_lang_thread_ipf.h" +#elif defined _EM64T_ +#include "java_lang_thread_em64t.h" #else #include "java_lang_thread_ia32.h" #endif @@ -135,6 +137,8 @@ IDATA vm_attach() { hythread_suspend_disable(); + init_stack_info(); + m2n_null_init(p_m2n); m2n_set_last_frame(p_m2n); diff --git vm/vmcore/src/thread/thread_manager.cpp vm/vmcore/src/thread/thread_manager.cpp old mode 100644 new mode 100755 index 49a2b92..86f8f13 --- vm/vmcore/src/thread/thread_manager.cpp +++ vm/vmcore/src/thread/thread_manager.cpp @@ -59,13 +59,13 @@ #include "tl/memory_pool.h" #include "open/vm_util.h" #include "suspend_checker.h" +#ifdef PLATFORM_NT // wjw -- following lines needs to be generic for all OSs -#ifndef PLATFORM_POSIX #include "java_lang_thread_nt.h" -#endif - -#ifdef _IPF_ +#elif defined _IPF_ #include "java_lang_thread_ipf.h" +#elif defined _EM64T_ +//#include "java_lang_thread_em64t.h" #else #include "java_lang_thread_ia32.h" #endif @@ -147,15 +147,17 @@ VM_thread *get_vm_thread_ptr_safe(JNIEnv VM_thread *get_thread_ptr_stub() { - - return NULL; + return get_vm_thread(hythread_self()); } vm_thread_accessor* get_thread_ptr = get_thread_ptr_stub; void init_TLS_data() { hythread_tls_alloc(&TLS_key_pvmthread); +#ifndef _EM64T_ get_thread_ptr = (vm_thread_accessor*) get_tls_helper(TLS_key_pvmthread); //printf ("init fast call %p\n", get_thread_ptr); +#endif + } void set_TLS_data(VM_thread *thread) { @@ -164,7 +166,9 @@ void set_TLS_data(VM_thread *thread) { } IDATA jthread_throw_exception(char* name, char* message) { - exn_throw_by_name(name); + ASSERT_RAISE_AREA; + jobject jthe = exn_create(name); + exn_raise_object(jthe); return 0; } diff --git vm/vmcore/src/util/em64t/base/compile_IA32.cpp vm/vmcore/src/util/em64t/base/compile_IA32.cpp deleted file mode 100644 index 3ebaf27..0000000 --- vm/vmcore/src/util/em64t/base/compile_IA32.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.5 $ - */ - - -#define LOG_DOMAIN "port.old" -#include "cxxlog.h" - -#include "platform.h" - -//MVM -#include <iostream> - -using namespace std; - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#include "lock_manager.h" -#include "open/types.h" -#include "Class.h" -#include "environment.h" -#include "method_lookup.h" -#include "stack_iterator.h" -#include "m2n.h" -#include "../m2n_em64t_internal.h" -#include "exceptions.h" -#include "jit_intf.h" -#include "jit_intf_cpp.h" -#include "jit_runtime_support.h" - -#include "encoder.h" - -#include "object_layout.h" -#include "nogc.h" - -#include "open/gc.h" - - -#include "open/vm_util.h" -#include "vm_synch.h" -#include "vm_threads.h" -#include "ini.h" -#include "vm_stats.h" - -#include "compile.h" -#include "lil.h" -#include "lil_code_generator.h" - -// Used by prepare_native_method() to compute the offsets of fields in structures -#define offset_of(type,member) ((size_t)(&((type *)0)->member)) - -extern bool dump_stubs; - -#define REWRITE_INVALID_TYPE 0 -#define REWRITE_PATCH_COMPILE_ME_STUB 1 -#define REWRITE_PATCH_CALLER 2 -#define REWRITE_PATCH_OLD_CODE_TO_REWRITER 3 - -void compile_flush_generated_code_block(Byte*, size_t) -{ - // Nothing to do on IA32 -} - - -void compile_flush_generated_code() -{ - // Nothing to do on IA32 -} - - -// FIXME: em64t not tested -static uint64* get_arg_word(unsigned num_arg_words, unsigned word) -{ - //return m2n_get_args(m2n_get_last_frame())+num_arg_words-word-1; - return NULL; -} - -void compile_protect_arguments(Method_Handle method, GcFrame* gc) -{ - assert(!hythread_is_suspend_enabled()); - Method_Signature_Handle msh = method_get_signature(method); - unsigned num_args = method_args_get_number(msh); - unsigned num_arg_words = ((Method*)method)->get_num_arg_bytes()>>2; - - unsigned cur_word = 0; - for(unsigned i=0; i<num_args; i++) { - Type_Info_Handle tih = method_args_get_type_info(msh, i); - switch (type_info_get_type(tih)) { - case VM_DATA_TYPE_INT64: - case VM_DATA_TYPE_UINT64: - case VM_DATA_TYPE_F8: - cur_word += 2; - break; - case VM_DATA_TYPE_INT8: - case VM_DATA_TYPE_UINT8: - case VM_DATA_TYPE_INT16: - case VM_DATA_TYPE_UINT16: - case VM_DATA_TYPE_INT32: - case VM_DATA_TYPE_UINT32: - case VM_DATA_TYPE_INTPTR: - case VM_DATA_TYPE_UINTPTR: - case VM_DATA_TYPE_F4: - case VM_DATA_TYPE_BOOLEAN: - case VM_DATA_TYPE_CHAR: - case VM_DATA_TYPE_UP: - cur_word++; - break; - case VM_DATA_TYPE_CLASS: - case VM_DATA_TYPE_ARRAY: - gc->add_object((ManagedObject**)get_arg_word(num_arg_words, cur_word)); - cur_word++; - break; - case VM_DATA_TYPE_MP: - gc->add_managed_pointer((ManagedPointer*)get_arg_word(num_arg_words, cur_word)); - break; - case VM_DATA_TYPE_VALUE: - { - // This should never cause loading - Class_Handle UNUSED c = type_info_get_class(tih); - assert(c); - DIE("This functionality is not currently supported"); - break; - } - default: - ABORT("Unexpected data type"); - } - } -} - - -// create_call_native_proc_stub() creates a customized stub that can be used to call a native procedure from managed code. -// Arguments used to customize the generated stub: -// - "proc_addr" - address of the native procedure (e.g., address of jit_a_method or delegate_invocation_work) -// - "stub_name" - name of the new stub. -// - "final_action" - action to take after calling "proc_addr". For example: -// - CNP_ReturnFinalAction - return after calling the native procedure (e.g. delegate Invoke) -// - CNP_JmpToRetAddrFinalAction - call the procedure whose address is returned by the native procedure (e.g. JIT compile method) -// - "return_type" - If CNP_ReturnFinalAction, the type returned by the called "proc_addr". NB: "proc_addr" MUST return any result -// in eax/edx as a long (int64) value; "return_type" determines what registers to set.from this value. -// -// On entry to the generated stub: -// - the stack contains arguments already pushed by a caller -// - eax contains a first argument to be passed to "proc_addr": e.g., a method handle. -// - ecx contains a stack adjustment value used to pop the arguments when "final_action" is CNP_ReturnFinalAction. -// This is also passed to "proc_addr" as a second argument. -// -void *create_call_native_proc_stub(char *proc_addr, char *stub_name, CNP_FinalAction final_action, CNP_ReturnType return_type) -{ - return NULL; -} //create_call_native_proc_stub - - -void patch_code_with_threads_suspended(Byte *code_block, Byte *new_code, size_t size) -{ - ABORT("Not supported"); // 20030203 Not supported on IA32 currently -} //patch_code_with_threads_suspended - - -Emitter_Handle gen_throw_if_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char* ss = (char*)emitter; - return (Emitter_Handle)ss; -} - - -// Convert a reference on the stack, if null, from a managed null (represented by heap_base) to an unmanaged one (NULL/0). Uses %eax. -Emitter_Handle gen_convert_managed_to_unmanaged_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char *ss = (char *)emitter; - return (Emitter_Handle)ss; -} //gen_convert_managed_to_unmanaged_null_ia32 - - -// Convert a reference on the stack, if null, from an unmanaged null (NULL/0) to an managed one (heap_base). Uses %eax. -Emitter_Handle gen_convert_unmanaged_to_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char *ss = (char *)emitter; - return (Emitter_Handle)ss; -} //gen_convert_unmanaged_to_managed_null_ia32 - -char *create_unboxer(Method *method) -{ - ABORT("Not implemented"); - return 0; -} //create_unboxer - -////////////////////////////////////////////////////////////////////////// -// Compile-Me Stubs - -NativeCodePtr compile_gen_compile_me(Method_Handle method) -{ - return NULL; -} //compile_gen_compile_me - - -void gen_native_hashcode(Emitter_Handle h, Method *m); -unsigned native_hashcode_fastpath_size(Method *m); -void gen_native_system_currenttimemillis(Emitter_Handle h, Method *m); -unsigned native_getccurrenttime_fastpath_size(Method *m); -void gen_native_readinternal(Emitter_Handle h, Method *m); -unsigned native_readinternal_fastpath_size(Method *m); -void gen_native_newinstance(Emitter_Handle h, Method *m); -unsigned native_newinstance_fastpath_size(Method *m); -// ****** 10/09/2003 above are additions to bring original on par with LIL -void gen_native_getclass_fastpath(Emitter_Handle h, Method *m); -unsigned native_getclass_fastpath_size(Method *m); - -void gen_native_arraycopy_fastpath(Emitter_Handle h, Method *m); -unsigned native_arraycopy_fastpath_size(Method *m); - -static Stub_Override_Entry _stub_override_entries_base[] = { - {"java/lang/VMSystem", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", gen_native_arraycopy_fastpath, native_arraycopy_fastpath_size}, - {"java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", gen_native_arraycopy_fastpath, native_arraycopy_fastpath_size}, - {"java/lang/Object", "getClass", "()Ljava/lang/Class;", gen_native_getclass_fastpath, native_getclass_fastpath_size}, - // ****** 10/09/2003: below are additions to bring baseline on par with LIL - {"java/lang/System", "currentTimeMillis", "()J", gen_native_system_currenttimemillis, native_getccurrenttime_fastpath_size}, - {"java/io/FileInputStream", "readInternal", "(I[BII)I", gen_native_readinternal, native_readinternal_fastpath_size}, -#ifndef PLATFORM_POSIX - // because of threading, this override will not work on Linux! - {"java/lang/Class", "newInstance", "()Ljava/lang/Object;", gen_native_newinstance, native_newinstance_fastpath_size}, -#endif - {"java/lang/VMSystem", "identityHashCode", "(Ljava/lang/Object;)I", gen_native_hashcode, native_hashcode_fastpath_size} -}; - -Stub_Override_Entry *stub_override_entries = &(_stub_override_entries_base[0]); - -int sizeof_stub_override_entries = sizeof(_stub_override_entries_base) / sizeof(_stub_override_entries_base[0]); - - diff --git vm/vmcore/src/util/em64t/base/compile_em64t.cpp vm/vmcore/src/util/em64t/base/compile_em64t.cpp new file mode 100644 index 0000000..6467e53 --- /dev/null +++ vm/vmcore/src/util/em64t/base/compile_em64t.cpp @@ -0,0 +1,298 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision$ + */ + +#include "open/types.h" +#include "open/vm_util.h" +#include "environment.h" +#include "encoder.h" +#include "object_handles.h" +#include "vm_threads.h" +#include "compile.h" + +#include "nogc.h" +#include "m2n.h" +#include "../m2n_em64t_internal.h" + +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" + +#include "dump.h" +#include "vm_stats.h" + +void compile_flush_generated_code_block(Byte*, size_t) { + // Nothing to do on EM64T +} + +void compile_flush_generated_code() { + // Nothing to do on EM64T +} + +void patch_code_with_threads_suspended(Byte * UNREF code_block, Byte * UNREF new_code, size_t UNREF size) { + ABORT("Not supported on EM64T currently"); +} + +void compile_protect_arguments(Method_Handle method, GcFrame * gc) { + const unsigned MAX_GP = 6; + const unsigned MAX_FP = 8; + // adress of the top of m2n frame + uint64 * const m2n_base_addr = (uint64 *)m2n_get_frame_base(m2n_get_last_frame()); + // 6(scratched registers on the stack) + assert(m2n_get_size() % 8 == 0); + // 15 = 1(alignment) + 8(fp) + 6(gp) registers were preserved on the stack + uint64 * const inputs_addr = m2n_base_addr - (m2n_get_size() / 8) - 15; + // 1(return ip); + uint64 * extra_inputs_addr = m2n_base_addr + 1; + + assert(!hythread_is_suspend_enabled()); + Method_Signature_Handle msh = method_get_signature(method); + + unsigned num_gp_used = 0; + unsigned num_fp_used = 0; + for(unsigned i = 0; i < method_args_get_number(msh); i++) { + Type_Info_Handle tih = method_args_get_type_info(msh, i); + switch (type_info_get_type(tih)) { + case VM_DATA_TYPE_INT64: + case VM_DATA_TYPE_UINT64: + case VM_DATA_TYPE_INT8: + case VM_DATA_TYPE_UINT8: + case VM_DATA_TYPE_INT16: + case VM_DATA_TYPE_UINT16: + case VM_DATA_TYPE_INT32: + case VM_DATA_TYPE_UINT32: + case VM_DATA_TYPE_INTPTR: + case VM_DATA_TYPE_UINTPTR: + case VM_DATA_TYPE_BOOLEAN: + case VM_DATA_TYPE_CHAR: + case VM_DATA_TYPE_UP: + if (num_gp_used < MAX_GP) { + ++num_gp_used; + } else { + ++extra_inputs_addr; + } + break; + case VM_DATA_TYPE_CLASS: + case VM_DATA_TYPE_ARRAY: { + uint64 * ref_addr; + if (num_gp_used < MAX_GP) { + ref_addr = inputs_addr + num_gp_used; + ++num_gp_used; + } else { + ref_addr = extra_inputs_addr; + ++extra_inputs_addr; + } + gc->add_object((ManagedObject**)ref_addr); + break; + } + case VM_DATA_TYPE_MP: { + uint64 * ref_addr; + if (num_gp_used < MAX_GP) { + ref_addr = inputs_addr + num_gp_used; + ++num_gp_used; + } else { + ref_addr = extra_inputs_addr; + ++extra_inputs_addr; + } + gc->add_managed_pointer((ManagedPointer*)ref_addr); + break; + } + case VM_DATA_TYPE_F4: + case VM_DATA_TYPE_F8: + if (num_fp_used < MAX_FP) { + ++num_fp_used; + } else { + ++extra_inputs_addr; + } + break; + case VM_DATA_TYPE_VALUE: + DIE("This functionality is not currently supported"); + default: + ASSERT(0, "Unexpected data type: " << type_info_get_type(tih)); + } + } +} + +/* BEGIN COMPILE-ME STUBS */ + +// compile_me stack frame +// m2n frame +// 8 byte alignment +// 6 xmm registers +// 6 gp registers +// method handle +const int32 stack_size = m2n_get_size() + 8 + 120; + +NativeCodePtr compile_jit_a_method(Method * method); + +static NativeCodePtr compile_get_compile_me_generic() { + static NativeCodePtr addr = NULL; + if (addr) { + return addr; + } + + const int STUB_SIZE = 350; + char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE, + DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); + addr = stub; +#ifndef NDEBUG + memset(stub, 0xcc /*int 3*/, STUB_SIZE); +#endif + assert(stack_size % 8 == 0); + assert(stack_size % 16 != 0); + // set up stack frame + stub = alu(stub, sub_opc, rsp_opnd, Imm_Opnd(stack_size)); + // TODO: think over saving xmm registers conditionally + stub = movq(stub, M_Base_Opnd(rsp_reg, 112), xmm7_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 104), xmm6_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 96), xmm5_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 88), xmm4_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 80), xmm3_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 72), xmm2_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 64), xmm1_opnd); + stub = movq(stub, M_Base_Opnd(rsp_reg, 56), xmm0_opnd); + // we need to preserve all general purpose registers here + // to protect managed objects from GC during compilation + stub = mov(stub, M_Base_Opnd(rsp_reg, 48), r9_opnd); + stub = mov(stub, M_Base_Opnd(rsp_reg, 40), r8_opnd); + stub = mov(stub, M_Base_Opnd(rsp_reg, 32), rcx_opnd); + stub = mov(stub, M_Base_Opnd(rsp_reg, 24), rdx_opnd); + stub = mov(stub, M_Base_Opnd(rsp_reg, 16), rsi_opnd); + stub = mov(stub, M_Base_Opnd(rsp_reg, 8), rdi_opnd); + // push m2n to the stack + // skip m2n frame, 6 xmm registers, 6 gp registers and method handle + + stub = m2n_gen_push_m2n(stub, NULL, + FRAME_COMPILATION, false, 0, 0, stack_size); + // restore Method_Handle + stub = mov(stub, rdi_opnd, M_Base_Opnd(rsp_reg, 0)); + // compile the method + stub = call(stub, (char *)&compile_jit_a_method); + // restore gp inputs from the stack + // NOTE: m2n_gen_pop_m2n must not destroy inputs + stub = pop(stub, rdi_opnd); + stub = pop(stub, rdi_opnd); + stub = pop(stub, rsi_opnd); + stub = pop(stub, rdx_opnd); + stub = pop(stub, rcx_opnd); + stub = pop(stub, r8_opnd); + stub = pop(stub, r9_opnd); + // restore fp inputs from the stack + stub = movq(stub, xmm0_opnd, M_Base_Opnd(rsp_reg, 0)); + stub = movq(stub, xmm1_opnd, M_Base_Opnd(rsp_reg, 8)); + stub = movq(stub, xmm2_opnd, M_Base_Opnd(rsp_reg, 16)); + stub = movq(stub, xmm3_opnd, M_Base_Opnd(rsp_reg, 24)); + stub = movq(stub, xmm4_opnd, M_Base_Opnd(rsp_reg, 32)); + stub = movq(stub, xmm5_opnd, M_Base_Opnd(rsp_reg, 40)); + stub = movq(stub, xmm6_opnd, M_Base_Opnd(rsp_reg, 48)); + stub = movq(stub, xmm7_opnd, M_Base_Opnd(rsp_reg, 56)); + // pop m2n from the stack + const int32 bytes_to_m2n_bottom = 72; + stub = m2n_gen_pop_m2n(stub, false, 0, bytes_to_m2n_bottom, 1); + // adjust stack pointer + stub = alu(stub, add_opc, rsp_opnd, Imm_Opnd(bytes_to_m2n_bottom + m2n_get_size())); + // transfer control to the compiled code + stub = jump(stub, rax_opnd); + + assert(stub - (char *)addr <= STUB_SIZE); + +#if 0 + if (VM_Global_State::loader_env->TI->isEnabled()) + { + jvmti_add_dynamic_generated_code_chunk("compile_me_generic", stub, STUB_SIZE); + jvmti_send_dynamic_code_generated_event("compile_me_generic", stub, STUB_SIZE); + } +#endif + + DUMP_STUB(addr, "compileme_generic", stub - (char *)addr); + + return addr; +} + +NativeCodePtr compile_gen_compile_me(Method_Handle method) { + int STUB_SIZE = 32; +#ifdef VM_STATS + ++VM_Statistics::get_vm_stats().num_compileme_generated; +#endif + char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE, + DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); + NativeCodePtr addr = stub; +#ifndef NDEBUG + memset(stub, 0xcc /*int 3*/, STUB_SIZE); +#endif + +#ifdef VM_STATS + // FIXME: vm_stats_total is not yet initialized :-( + //stub = mov(stub, r9_opnd, (int64)&VM_Statistics::get_vm_stats().num_compileme_used); + //stub = inc(stub, M_Base_Opnd(r9_reg, 0)); +#endif + // preserve method handle + stub = mov(stub, r10_opnd, Imm_Opnd(size_64, (int64)method)); + stub = mov(stub, M_Base_Opnd(rsp_reg, -stack_size), r10_opnd); + // transfer control to generic part + stub = jump(stub, (char *)compile_get_compile_me_generic()); + assert(stub - (char *)addr <= STUB_SIZE); + + +#if 0 + if (VM_Global_State::loader_env->TI->isEnabled()) + { + char * name; + const char * c = class_get_name(method_get_class(method)); + const char * m = method_get_name(method); + const char * d = method_get_descriptor(method); + size_t sz = strlen(c)+strlen(m)+strlen(d)+12; + name = (char *)STD_MALLOC(sz); + sprintf(name, "compileme.%s.%s%s", c, m, d); + jvmti_add_dynamic_generated_code_chunk(name, stub, STUB_SIZE); + jvmti_send_dynamic_code_generated_event(name, stub, STUB_SIZE); + } +#endif + + +#ifndef NDEBUG + static unsigned done = 0; + // dump first 10 compileme stubs + if (dump_stubs && ++done <= 10) { + char * buf; + const char * c = class_get_name(method_get_class(method)); + const char * m = method_get_name(method); + const char * d = method_get_descriptor(method); + size_t sz = strlen(c)+strlen(m)+strlen(d)+12; + buf = (char *)STD_MALLOC(sz); + sprintf(buf, "compileme.%s.%s%s", c, m, d); + assert(strlen(buf) < sz); + DUMP_STUB(addr, buf, stub - (char *)addr); + STD_FREE(buf); + } +#endif + return addr; +} + +/* END COMPILE-ME STUBS */ + + +/* BEGIN SUPPORT FOR STUB OVERRIDE CODE SEQUENCES */ + +static Stub_Override_Entry _stub_override_entries_base[] = {}; + +Stub_Override_Entry * stub_override_entries = &(_stub_override_entries_base[0]); + +int sizeof_stub_override_entries = sizeof(_stub_override_entries_base) / sizeof(_stub_override_entries_base[0]); + +/* END SUPPORT FOR STUB OVERRIDE CODE SEQUENCES */ diff --git vm/vmcore/src/util/em64t/base/ini_em64t.cpp vm/vmcore/src/util/em64t/base/ini_em64t.cpp index 012e989..171bedf 100644 --- vm/vmcore/src/util/em64t/base/ini_em64t.cpp +++ vm/vmcore/src/util/em64t/base/ini_em64t.cpp @@ -25,41 +25,39 @@ #include <assert.h> #include "jni_types.h" #include "jit_intf.h" #include "open/types.h" -#include "open/thread.h" #include "open/em.h" +#include "environment.h" #include "Class.h" #include "object_handles.h" #include "nogc.h" -#define LOG_DOMAIN "vm.helpers" #include "port_malloc.h" -#include "cxxlog.h" #include "tl/memory_pool.h" #include "encoder.h" #include "lil_code_generator_utils.h" -#ifndef NDEBUG +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" + #include "dump.h" -extern bool dump_stubs; -#endif -typedef int64 ( * invoke_native_func_int_t) ( +typedef int64 ( * invoke_managed_func_int_t) ( // six fake parameters should be passed over GR void *, void *, void *, void *, void *, void *, const void * const method_entry_point, - int gr_nargs, int fr_nargs, int stack_nargs, + int64 gr_nargs, int64 fr_nargs, int64 stack_nargs, uint64 gr_args[], double fr_args[], uint64 stack_args[]); -typedef double ( * invoke_native_func_double_t)( +typedef double ( * invoke_managed_func_double_t)( // six fake parameters should be passed over GR void *, void *, void *, void *, void *, void *, const void * const method_entry_point, - int gr_nargs, int fr_nargs, int stack_nargs, + int64 gr_nargs, int64 fr_nargs, int64 stack_nargs, uint64 gr_args[], double fr_args[], uint64 stack_args[]); -static invoke_native_func_int_t gen_invoke_native_func() { - static invoke_native_func_int_t func = NULL; +static invoke_managed_func_int_t gen_invoke_managed_func() { + static invoke_managed_func_int_t func = NULL; if (func) { return func; } @@ -67,6 +65,7 @@ static invoke_native_func_int_t gen_invo const char * MOVE_STACK_ARGS_BEGIN = "move_stack_args_begin"; const char * MOVE_STACK_ARGS_END = "move_stack_args_end"; const char * MOVE_FR_ARGS_END = "move_fr_args_end"; + const char * COMPUTE_ADDRESS = "compute_address"; // [rbp + 16] - method_entry_point // [rbp + 24] - gr_nargs @@ -83,8 +82,7 @@ static invoke_native_func_int_t gen_invo const int32 FR_ARGS_OFFSET = 56; const int32 STACK_ARGS_OFFSET = 64; - // FIXME: why 124 - const int STUB_SIZE = 124; + const int STUB_SIZE = 200; char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); #ifdef _DEBUG @@ -94,52 +92,57 @@ #endif tl::MemoryPool pool; LilCguLabelAddresses labels(&pool, stub); - func = (invoke_native_func_int_t) stub; + func = (invoke_managed_func_int_t) stub; stub = push(stub, rbp_opnd); stub = mov(stub, rbp_opnd, rsp_opnd); - // 1) preserve callee-saves registers - stub = push(stub, r15_opnd); - stub = push(stub, r14_opnd); - stub = push(stub, r13_opnd); - stub = push(stub, r12_opnd); - stub = push(stub, rbx_opnd); - - // 2) push stacked arguments in reverse (right-to-left) order + // 1) move stacked arguments in reverse (right-to-left) order stub = mov(stub, rcx_opnd, M_Base_Opnd(rbp_reg, STACK_NARGS_OFFSET)); stub = alu(stub, or_opc, rcx_opnd, rcx_opnd); stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(MOVE_STACK_ARGS_END, stub - 1, LPT_Rel8); + + // align stack if required (rsp % 16 == 0) + stub = alu(stub, and_opc, rcx_opnd, Imm_Opnd(size_64, 1)); + stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0)); + labels.add_patch_to_label(COMPUTE_ADDRESS, stub - 1, LPT_Rel8); + stub = push(stub, rax_opnd); + // compute effective address of the last stacked argument + labels.define_label(COMPUTE_ADDRESS, stub, false); + stub = mov(stub, r10_opnd, M_Base_Opnd(rbp_reg, STACK_ARGS_OFFSET)); stub = lea(stub, r10_opnd, M_Index_Opnd(r10_reg, rcx_reg, -8, 8)); stub = alu(stub, sub_opc, r10_opnd, rsp_opnd); + // iterate through the arguments labels.define_label(MOVE_STACK_ARGS_BEGIN, stub, false); - stub = push(stub, M_Index_Opnd(r10_reg, rsp_reg, 0, 1)); + + stub = push(stub, M_Index_Opnd(rsp_reg, r10_reg, 0, 1)); stub = loop(stub, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(MOVE_STACK_ARGS_BEGIN, stub - 1, LPT_Rel8); + labels.define_label(MOVE_STACK_ARGS_END, stub, false); - // 3) move from fr_args to registers + // 2) move from fr_args to registers stub = mov(stub, rcx_opnd, M_Base_Opnd(rbp_reg, FR_NARGS_OFFSET)); stub = alu(stub, or_opc, rcx_opnd, rcx_opnd); stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(MOVE_FR_ARGS_END, stub - 1, LPT_Rel8); stub = mov(stub, r10_opnd, M_Base_Opnd(rbp_reg, FR_ARGS_OFFSET)); - stub = sse_mov(stub, xmm0_opnd, M_Base_Opnd(r10_reg, 0 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm1_opnd, M_Base_Opnd(r10_reg, 1 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm2_opnd, M_Base_Opnd(r10_reg, 2 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm3_opnd, M_Base_Opnd(r10_reg, 3 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm4_opnd, M_Base_Opnd(r10_reg, 4 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm5_opnd, M_Base_Opnd(r10_reg, 5 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm6_opnd, M_Base_Opnd(r10_reg, 6 * FR_STACK_SIZE), true); - stub = sse_mov(stub, xmm7_opnd, M_Base_Opnd(r10_reg, 7 * FR_STACK_SIZE), true); + stub = movq(stub, xmm0_opnd, M_Base_Opnd(r10_reg, 0 * FR_STACK_SIZE)); + stub = movq(stub, xmm1_opnd, M_Base_Opnd(r10_reg, 1 * FR_STACK_SIZE)); + stub = movq(stub, xmm2_opnd, M_Base_Opnd(r10_reg, 2 * FR_STACK_SIZE)); + stub = movq(stub, xmm3_opnd, M_Base_Opnd(r10_reg, 3 * FR_STACK_SIZE)); + stub = movq(stub, xmm4_opnd, M_Base_Opnd(r10_reg, 4 * FR_STACK_SIZE)); + stub = movq(stub, xmm5_opnd, M_Base_Opnd(r10_reg, 5 * FR_STACK_SIZE)); + stub = movq(stub, xmm6_opnd, M_Base_Opnd(r10_reg, 6 * FR_STACK_SIZE)); + stub = movq(stub, xmm7_opnd, M_Base_Opnd(r10_reg, 7 * FR_STACK_SIZE)); labels.define_label(MOVE_FR_ARGS_END, stub, false); - // 4) unconditionally move from gr_args to registers + // 3) unconditionally move from gr_args to registers stub = mov(stub, r10_opnd, M_Base_Opnd(rbp_reg, GR_ARGS_OFFSET)); stub = mov(stub, rdi_opnd, M_Base_Opnd(r10_reg, 0 * GR_STACK_SIZE)); stub = mov(stub, rsi_opnd, M_Base_Opnd(r10_reg, 1 * GR_STACK_SIZE)); @@ -148,28 +151,18 @@ #endif stub = mov(stub, r8_opnd, M_Base_Opnd(r10_reg, 4 * GR_STACK_SIZE)); stub = mov(stub, r9_opnd, M_Base_Opnd(r10_reg, 5 * GR_STACK_SIZE)); - // 5) transfer control + // 4) transfer control stub = mov(stub, r10_opnd, M_Base_Opnd(rbp_reg, METHOD_ENTRY_POINT_OFFSET)); stub = call(stub, r10_opnd); - // 6) restore calles-saves registers - stub = lea(stub, rsp_opnd, M_Base_Opnd(rbp_reg, -5 * GR_STACK_SIZE)); - stub = pop(stub, rbx_opnd); - stub = pop(stub, r12_opnd); - stub = pop(stub, r13_opnd); - stub = pop(stub, r14_opnd); - stub = pop(stub, r15_opnd); - - // 7) leave current frame + // 5) leave current frame + stub = mov(stub, rsp_opnd, rbp_opnd); stub = pop(stub, rbp_opnd); stub = ret(stub); assert(stub - (char *)func <= STUB_SIZE); -#ifndef NDEBUG - if (dump_stubs) { - dump((char *)func, "gen_invoke_native_func", stub - (char *)func); - } -#endif + + DUMP_STUB(func, "invoke_managed_func", stub - (char *)func); return func; } @@ -177,10 +170,10 @@ #endif void JIT_execute_method_default(JIT_Handle jh, jmethodID methodID, jvalue * result, jvalue * args) { - assert(!tmn_is_suspend_enabled()); + assert(!hythread_is_suspend_enabled()); - static const invoke_native_func_int_t invoke_managed_func = - (invoke_native_func_int_t) gen_invoke_native_func(); + static const invoke_managed_func_int_t invoke_managed_func = + (invoke_managed_func_int_t) gen_invoke_managed_func(); // maximum number of GP registers for inputs const int MAX_GR = 6; // maximum number of FP registers for inputs @@ -189,7 +182,7 @@ void JIT_execute_method_default(JIT_Hand uint64 gr_args[MAX_GR]; // holds arguments that should be placed in FR's double fr_args[MAX_FR]; - // gen_invoke_native_func assumes such size + // gen_invoke_managed_func assumes such size assert(sizeof(double) == 8); Method * const method = (Method *)methodID; @@ -199,10 +192,10 @@ void JIT_execute_method_default(JIT_Hand // hold arguments that should be placed on the memory stack uint64 * const stack_args = (uint64 *) STD_MALLOC(sizeof(uint64) * method->get_num_args()); - int gr_nargs = 0; - int fr_nargs = 0; - int stack_nargs = 0; - int arg_num = 0; + int64 gr_nargs = 0; + int64 fr_nargs = 0; + int64 stack_nargs = 0; + int64 arg_num = 0; TRACE2("invoke", "enter method " << method->get_class()->name->bytes << " " @@ -213,7 +206,9 @@ void JIT_execute_method_default(JIT_Hand if(!method->is_static()) { ObjectHandle handle = (ObjectHandle) args[arg_num++].l; assert(handle); - // TODO: check if there is no need to convert from native to managed null + // only compressed references are supported yet + assert(VM_Global_State::loader_env->compress_references); + // convert from native to managed NULL gr_args[gr_nargs++] = handle->object != NULL ? (uint64) handle->object : (uint64) Class::managed_null; } @@ -227,7 +222,9 @@ void JIT_execute_method_default(JIT_Hand case JAVA_TYPE_ARRAY: { ObjectHandle handle = (ObjectHandle) args[arg_num++].l; uint64 ref = handle ? (uint64) handle->object : 0; - // TODO: check if there is no need to convert from native to managed null + // only compressed references are supported yet + assert(VM_Global_State::loader_env->compress_references); + // convert from native to managed NULL ref = ref ? ref : (uint64) Class::managed_null; if (gr_nargs < MAX_GR) { gr_args[gr_nargs++] = ref; @@ -306,7 +303,6 @@ void JIT_execute_method_default(JIT_Hand iter = advance_arg_iterator(iter); } - // Save the result type = method->get_return_java_type(); switch(type) { @@ -323,11 +319,10 @@ void JIT_execute_method_default(JIT_Hand method_entry_point, gr_nargs, fr_nargs, stack_nargs, gr_args, fr_args, stack_args); - // TODO: check if there is no need to convert from native to managed null - // Convert a null reference in managed code to the - // representation of null in unmanaged code - ref = is_compressed_reference(ref) && is_null_compressed_reference(ref) - ? (uint64) NULL : ref; + // only compressed references are supported yet + assert(VM_Global_State::loader_env->compress_references); + // convert from managed to native NULL + ref = ref != (uint64) Class::managed_null ? ref : (uint64) NULL; if (ref) { handle = oh_allocate_local_handle(); handle->object = (ManagedObject*) ref; @@ -348,7 +343,7 @@ void JIT_execute_method_default(JIT_Hand break; case JAVA_TYPE_DOUBLE: case JAVA_TYPE_FLOAT: - result->d = (invoke_native_func_double_t(invoke_managed_func))( + result->d = (invoke_managed_func_double_t(invoke_managed_func))( NULL, NULL, NULL, NULL, NULL, NULL, method_entry_point, gr_nargs, fr_nargs, stack_nargs, @@ -358,6 +353,8 @@ void JIT_execute_method_default(JIT_Hand DIE("INTERNAL ERROR: Unexpected return type: " << type); } + STD_FREE(stack_args); + TRACE2("invoke", "exit method " << method->get_class()->name->bytes << " " << method->get_name()->bytes << " " diff --git vm/vmcore/src/util/em64t/base/jit_generic_rt_support_ia32.cpp vm/vmcore/src/util/em64t/base/jit_generic_rt_support_ia32.cpp deleted file mode 100644 index f691a21..0000000 --- vm/vmcore/src/util/em64t/base/jit_generic_rt_support_ia32.cpp +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ - */ - -// -// This file contains IA32-specific code that does not depend on any VM internals. -// For the most part, this means math helpers. -// - -#include <assert.h> -#include <float.h> -#include <math.h> - -#define LOG_DOMAIN "vm.helpers" -#include "cxxlog.h" - -#include "jit_runtime_support.h" - -#include "nogc.h" // for malloc_fixed_code_for_jit() -#include "encoder.h" -#include "vm_stats.h" -#include "vm_arrays.h" - -#ifdef PLATFORM_POSIX - -#ifndef _isnan -#define _isnan isnan -#endif - -#endif // PLATFORM_POSIX - -extern bool dump_stubs; - -//static uint64 vm_lshl(unsigned count, uint64 n) -//{ -// assert(!hythread_is_suspend_enabled()); -// return n << (count & 0x3f); -//} //vm_lshl - - -// The arguments are: -// edx:eax - the value to be shifted -// ecx - how many bits to shift by -// The result is returned in edx:eax. - - -void * getaddress__vm_lshl_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_lshl_naked - - -//static int64 vm_lshr(unsigned count, int64 n) -//{ -// assert(!hythread_is_suspend_enabled()); -// return n >> (count & 0x3f); -//} //vm_lshr - - -// The arguments are: -// edx:eax - the value to be shifted -// ecx - how many bits to shift by -// The result is returned in edx:eax. - - -void * getaddress__vm_lshr_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_lshr_naked - - -//static uint64 vm_lushr(unsigned count, uint64 n) -//{ -// assert(!hythread_is_suspend_enabled()); -// return n >> (count & 0x3f); -//} //vm_lushr - - -// The arguments are: -// edx:eax - the value to be shifted -// ecx - how many bits to shift by -// The result is returned in edx:eax. - - -void * getaddress__vm_lushr_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_lushr_naked - - -static int64 __stdcall vm_lmul(int64 m, int64 n) stdcall__; - -static int64 __stdcall vm_lmul(int64 m, int64 n) -{ - assert(!hythread_is_suspend_enabled()); - - return m * n; -} //vm_lmul - -#ifdef VM_LONG_OPT -static int64 __stdcall vm_lmul_const_multiplier(int64 m, int64 n) stdcall__; - -static int64 __stdcall vm_lmul_const_multiplier(int64 m, int64 n) -{ - assert(!hythread_is_suspend_enabled()); - __asm{ - mov eax,dword ptr [ebp+0ch] - mov ecx,dword ptr [ebp+10h] - mul ecx - mov ebx,eax - mov eax,dword ptr [ebp+08h] - mul ecx - add edx,ebx - } -} //vm_lmul_const_multiplier -#endif - - -//static int64 __stdcall do_lrem(int64 m, int64 n) stdcall__; - -//static int64 __stdcall do_lrem(int64 m, int64 n) -//{ -// assert(!hythread_is_suspend_enabled()); -// -// return m % n; -//} //do_lrem - - -void * getaddress__vm_const_lrem_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_const_lrem_naked - -static void *getaddress__vm_const_ldiv_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_ldiv_naked - - -static double vm_rt_ddiv(double a, double b) -{ - double result = a / b; - return result; -} //vm_rt_ddiv - -/* -static int32 d2i_infinite(double d) -{ -#ifdef __INTEL_COMPILER -#pragma warning(disable: 4146) -#endif - if(_isnan(d)) { - return 0; - } else if(d > (double)2147483647) { - return 2147483647; // maxint - } else if(d < (double)-2147483648) { - return -2147483648; // minint - } else { - // The above should exhaust all possibilities - return 0; - } -#ifdef __INTEL_COMPILER -#pragma warning(default: 4146) -#endif -} -*/ -//static short fpstatus = 0x0e7f; -void *getaddress__vm_d2i() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_d2i - -void *getaddress__vm_d2l() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_d2l - - -static int64 __stdcall vm_d2l(double d) stdcall__; - -static int64 __stdcall vm_d2l(double d) -{ - assert(!hythread_is_suspend_enabled()); - -#ifdef VM_STATS - vm_stats_total.num_d2l++; -#endif - - int64 result; - - int64 (*gad2l)(int, int, int, double); - gad2l = (int64 ( *)(int, int, int, double) )getaddress__vm_d2l(); - - result = gad2l(0, 0, 0, d); - -#ifdef __INTEL_COMPILER -#pragma warning(disable: 4146) -#endif - // 0x80000000 is the integer indefinite value - if(0x80000000 == *(uint32*)((char*)&result+4)) { - -#ifdef PLATFORM_POSIX - if (isnan(d)) - return 0; -#else - if (_isnan(d)) - return 0; -#endif - - if(d >= (double)(__INT64_C(0x7fffffffffffffff))) { - return __INT64_C(0x7fffffffffffffff); // maxint - } else if(d < (double)-__INT64_C(0x8000000000000000)) { - return -__INT64_C(0x8000000000000000); // minint - } else { - // The above should exhaust all possibilities - ASSERT(0, "All the possible cases are expected to be already covered"); - return result; - } - - } else { - return result; - } - -#ifdef __INTEL_COMPILER -#pragma warning(default: 4146) -#endif -} //vm_d2l - -/* -static int32 f2i_infinite(float f) -{ -#ifdef __INTEL_COMPILER -#pragma warning(disable: 4146) -#endif - if(_isnan(f)) { - return 0; - } else if(f > (double)2147483647) { - return 2147483647; // maxint - } else if(f < (double)-2147483648) { - return -2147483648; // minint - } else { - // The above should exhaust all possibilities - return 0; - } -#ifdef __INTEL_COMPILER -#pragma warning(default: 4146) -#endif -} -*/ - -void *getaddress__vm_f2i() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_f2i - -static void *getaddress__vm_f2l() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_f2l - - -static int64 __stdcall vm_f2l(float f) stdcall__; - -static int64 __stdcall vm_f2l(float f) -{ - assert(!hythread_is_suspend_enabled()); - -#ifdef VM_STATS - vm_stats_total.num_f2l++; -#endif - - int64 result; - - int64 (*gaf2l)(int, int, int, float); - gaf2l = (int64 ( *)(int, int, int, float) )getaddress__vm_f2l(); - - result = gaf2l(0, 0, 0, f); - -#ifdef __INTEL_COMPILER -#pragma warning(disable: 4146) -#endif - // 0x80000000 is the integer indefinite value - if(0x80000000 == *(uint32*)((char*)&result+4)) { - if(_isnan(f)) { - return 0; - } else if(f >= __INT64_C(0x7fffffffffffffff) ) { - return __INT64_C(0x7fffffffffffffff); // maxint - } else if(f < (double)__INT64_C(-0x8000000000000000) ) { - return __INT64_C(-0x8000000000000000); // minint - } else { - // The above should exhaust all possibilities - ASSERT(0, "All the possible cases are expected to be already covered"); - return result; - } - } else { - return result; - } -#ifdef __INTEL_COMPILER -#pragma warning(default: 4146) -#endif -} //vm_f2l - - -// -// If fprem succeeds in producing a remainder that is less than the -// modulus, the function is complete and the C2 flag is cleared. -// Otherwise, C2 is set, and the result on the top of the fp stack -// is the partial remainder. We need to re-execute the fprem instruction -// (using the partial remainder) until C2 is cleared. -// - - -void *getaddress__vm_frem() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_frem - - - -void *getaddress__vm_drem() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_drem - - -#ifdef VM_STATS // exclude remark in release mode (defined but not used) -// Return the log base 2 of the integer operand. If the argument is less than or equal to zero, return zero. -static int get_log2(int value) -{ - register int n = value; - register int result = 0; - - while (n > 1) { - n = n >> 1; - result++; - } - return result; -} //get_log2 -#endif - -static void vm_rt_char_arraycopy_no_exc(ManagedObject *src, - int32 srcOffset, - ManagedObject *dst, - int32 dstOffset, - int32 length) -{ - // 20030303 Use a C loop to (hopefully) speed up short array copies. - - // Check that the array references are non-null. - assert(src && dst); - // Check that the arrays are arrays of 16 bit characters. - Class * UNUSED src_class = src->vt()->clss; - assert(src_class); - Class * UNUSED dst_class = dst->vt()->clss; - assert(dst_class); - assert((src_class->is_array) && (dst_class->is_array)); - assert((src_class->is_array_of_primitives) && (dst_class->is_array_of_primitives)); - assert(strcmp(src_class->name->bytes, "[C") == 0); - assert(strcmp(dst_class->name->bytes, "[C") == 0); - // Check the offsets - assert(srcOffset >= 0); - assert(dstOffset >= 0); - assert(length >= 0); - assert((srcOffset + length) <= get_vector_length((Vector_Handle)src)); - assert((dstOffset + length) <= get_vector_length((Vector_Handle)dst)); - - tmn_suspend_disable(); // vvvvvvvvvvvvvvvvvvv - - register uint16 *dst_addr = get_vector_element_address_uint16(dst, dstOffset); - register uint16 *src_addr = get_vector_element_address_uint16(src, srcOffset); - -#ifdef VM_STATS - vm_stats_total.num_char_arraycopies++; - if (dst_addr == src_addr) { - vm_stats_total.num_same_array_char_arraycopies++; - } - if (srcOffset == 0) { - vm_stats_total.num_zero_src_offset_char_arraycopies++; - } - if (dstOffset == 0) { - vm_stats_total.num_zero_dst_offset_char_arraycopies++; - } - if ((((POINTER_SIZE_INT)dst_addr & 0x7) == 0) && (((POINTER_SIZE_INT)src_addr & 0x7) == 0)) { - vm_stats_total.num_aligned_char_arraycopies++; - } - vm_stats_total.total_char_arraycopy_length += length; - vm_stats_total.char_arraycopy_count[get_log2(length)]++; -#endif //VM_STATS - - // 20030219 The length threshold 32 here works well for SPECjbb and should be reasonable for other applications. - if (length < 32) { - register int i; - if (src_addr > dst_addr) { - for (i = length; i > 0; i--) { - *dst_addr++ = *src_addr++; - } - } else { - // copy down, from higher address to lower - src_addr += length-1; - dst_addr += length-1; - for (i = length; i > 0; i--) { - *dst_addr-- = *src_addr--; - } - } - } else { - memmove(dst_addr, src_addr, (length * sizeof(uint16))); - } - - tmn_suspend_enable(); // ^^^^^^^^^^^^^^^^^^^ -} //vm_rt_char_arraycopy_no_exc - - -static int32 vm_rt_imul_common(int32 v1, int32 v2) -{ - return v1 * v2; -} //vm_rt_imul_common - - - -static int32 vm_rt_idiv_common(int32 v1, int32 v2) -{ - assert(v2); - return v1 / v2; -} //vm_rt_idiv_common - - - -static int32 vm_rt_irem_common(int32 v1, int32 v2) -{ - assert(v2); - return v1 % v2; -} //vm_rt_irem_common - - -void *get_generic_rt_support_addr_ia32(VM_RT_SUPPORT f) -{ - switch(f) { - case VM_RT_F2I: - return getaddress__vm_f2i(); - case VM_RT_F2L: - return (void *)vm_f2l; - case VM_RT_D2I: - return getaddress__vm_d2i(); - case VM_RT_D2L: - return (void *)vm_d2l; - case VM_RT_LSHL: - return getaddress__vm_lshl_naked(); - case VM_RT_LSHR: - return getaddress__vm_lshr_naked(); - case VM_RT_LUSHR: - return getaddress__vm_lushr_naked(); - case VM_RT_FREM: - return getaddress__vm_frem(); - case VM_RT_DREM: - return getaddress__vm_drem(); - case VM_RT_LMUL: - return (void *)vm_lmul; -#ifdef VM_LONG_OPT - case VM_RT_LMUL_CONST_MULTIPLIER: - return (void *)vm_lmul_const_multiplier; -#endif - case VM_RT_CONST_LDIV: - return getaddress__vm_const_ldiv_naked() ; - case VM_RT_CONST_LREM: - return getaddress__vm_const_lrem_naked() ; - case VM_RT_DDIV: - return (void *)vm_rt_ddiv; - - case VM_RT_IMUL: - return (void *)vm_rt_imul_common; - case VM_RT_IDIV: - return (void *)vm_rt_idiv_common; - case VM_RT_IREM: - return (void *)vm_rt_irem_common; - case VM_RT_CHAR_ARRAYCOPY_NO_EXC: - return (void *)vm_rt_char_arraycopy_no_exc; - - default: - ASSERT(0, "Unexpected helper id"); - return 0; - } -} diff --git vm/vmcore/src/util/em64t/base/jit_lock_rt_support_em64t.cpp vm/vmcore/src/util/em64t/base/jit_lock_rt_support_em64t.cpp new file mode 100644 index 0000000..5050945 --- /dev/null +++ vm/vmcore/src/util/em64t/base/jit_lock_rt_support_em64t.cpp @@ -0,0 +1,306 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision$ + */ + +/* MONITOR ENTER RUNTIME SUPPORT */ + +#include <assert.h> + +#include "open/hythread_ext.h" +#include "lil.h" +#include "lil_code_generator.h" +#include "jit_runtime_support.h" +#include "Class.h" +#include "mon_enter_exit.h" +#include "exceptions.h" +#include "exceptions_jit.h" + +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" + +#include "vm_stats.h" +#include "dump.h" + +static LilCodeStub * rth_get_lil_monitor_enter_generic(LilCodeStub * cs) { + + return lil_parse_onto_end(cs, + "out platform:ref:g4;" + "o0 = l0;" + "call %0i;" + "jc r!=%1i,slow_path;" + "ret;" + ":slow_path;" + "push_m2n 0, 0;" + "out platform:ref:void;" + "o0 = l0;" + "call %2i;" + "pop_m2n;" + "ret;", + vm_monitor_try_enter, + TM_ERROR_NONE, + vm_monitor_enter); +} + +NativeCodePtr rth_get_lil_monitor_enter_static() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub("entry 0:managed:pint:void;"); +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER_STATIC, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // convert struct Class into java_lang_Class + cs = lil_parse_onto_end(cs, + "in2out platform:ref;" + "call %0i;" + "locals 1;" + "l0 = r;", + struct_Class_to_java_lang_Class + ); + assert(cs); + + // append generic monitor enter code + cs = rth_get_lil_monitor_enter_generic(cs); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "monitor_enter_static", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + +NativeCodePtr rth_get_lil_monitor_enter() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub("entry 0:managed:ref:void;"); + +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // check if object is null + cs = lil_parse_onto_end(cs, + "jc i0 = %0i:ref, throw_null_pointer;" + "locals 1;" + "l0 = i0;", + (ManagedObject *) Class::managed_null + ); + assert(cs); + + // append generic monitor enter code + cs = rth_get_lil_monitor_enter_generic(cs); + assert(cs); + + // throw NullPointerException + cs = lil_parse_onto_end(cs, + ":throw_null_pointer;" + "out managed::void;" + "call.noret %0i;", + lil_npc_to_fp(exn_get_rth_throw_null_pointer()) + ); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB((char *)addr, "monitor_enter", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + +// this function doesn't throw NullPointerException in case of null object +NativeCodePtr rth_get_lil_monitor_enter_non_null() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub( + "entry 0:managed:ref:void;" + "locals 1;" + "l0 = i0;" + ); + assert(cs); + +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER_NON_NULL, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // append generic monitor enter code + cs = rth_get_lil_monitor_enter_generic(cs); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "monitor_enter_non_null", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + + +/* MONITOR EXIT RUNTIME SUPPORT */ + +static LilCodeStub * rth_get_lil_monitor_exit_generic(LilCodeStub * cs) { + return lil_parse_onto_end(cs, + "call %0i;" + "jc r!=%1i, illegal_monitor;" + "ret;" + ":illegal_monitor;" + "out managed::void;" + "call.noret %2i;", + vm_monitor_try_exit, + TM_ERROR_NONE, + lil_npc_to_fp(exn_get_rth_throw_illegal_monitor_state())); +} + +NativeCodePtr rth_get_lil_monitor_exit_static() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub("entry 0:managed:pint:void;"); +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT_STATIC, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // convert struct Class into java_lang_Class + cs = lil_parse_onto_end(cs, + "in2out platform:ref;" + "call %0i;" + "out platform:ref:g4;" + "o0 = r;", + struct_Class_to_java_lang_Class + ); + assert(cs); + + // append generic monitor enter code + cs = rth_get_lil_monitor_exit_generic(cs); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "monitor_exit_static", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + + +NativeCodePtr rth_get_lil_monitor_exit() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub("entry 0:managed:ref:void;"); + +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // check if object is null + cs = lil_parse_onto_end(cs, + "jc i0 = %0i:ref, throw_null_pointer;" + "in2out platform:g4;", + (ManagedObject *) Class::managed_null + ); + + assert(cs); + + // append generic monitor enter code + cs = rth_get_lil_monitor_exit_generic(cs); + assert(cs); + + // throw NullPointerException + cs = lil_parse_onto_end(cs, + ":throw_null_pointer;" + "out managed::void;" + "call.noret %0i;", + lil_npc_to_fp(exn_get_rth_throw_null_pointer()) + ); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "monitor_exit", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + +// this function doesn't throw NullPointerException in case of null object +NativeCodePtr rth_get_lil_monitor_exit_non_null() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub * cs = lil_parse_code_stub( + "entry 0:managed:ref:void;" + "in2out platform:g4;" + ); + assert(cs); + +#ifdef VM_STATS +// int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT_NON_NULL, 0, NULL); +// cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); +// assert(cs); +#endif + // append generic monitor enter code + cs = rth_get_lil_monitor_exit_generic(cs); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "monitor_exit_non_null", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + + +Boolean jit_may_inline_object_synchronization(unsigned * UNREF thread_id_register, + unsigned * UNREF sync_header_offset, + unsigned * UNREF sync_header_width, + unsigned * UNREF lock_owner_offset, + unsigned * UNREF lock_owner_width, + Boolean * UNREF jit_clears_ccv) { + return FALSE; +} diff --git vm/vmcore/src/util/em64t/base/jit_lock_rt_support_ia32.cpp vm/vmcore/src/util/em64t/base/jit_lock_rt_support_ia32.cpp deleted file mode 100644 index 74067ea..0000000 --- vm/vmcore/src/util/em64t/base/jit_lock_rt_support_ia32.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ - */ - - -#include "platform_lowlevel.h" - -//MVM -#include <iostream> - -using namespace std; - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#include "vm_synch.h" -#include "open/vm_util.h" -#include "encoder.h" -#include "vm_stats.h" -#include "nogc.h" -#include "compile.h" - -#include "exceptions.h" -#include "lil.h" -#include "lil_code_generator.h" -#include "../m2n_em64t_internal.h" -#include "object_handles.h" - - -extern bool dump_stubs; - -char *gen_setup_j2n_frame(char *s); -char *gen_pop_j2n_frame(char *s); - - - -// patch_addr_null_arg_ptr is the address of a variable holding the -// address of a branch instruction byte to patch with the destination -// to be taken if the struct Class* argument is NULL. -/* -static char * gen_convert_struct_class_to_object(char *ss, char **patch_addr_null_arg_ptr) -{ - return ss; -} //gen_convert_struct_class_to_object - - -static char * gen_restore_monitor_enter(char *ss, char *patch_addr_null_arg) -{ - return ss; -} //gen_restore_monitor_enter -*/ - -void * restore__vm_monitor_enter_naked(void * code_addr) -{ - return code_addr; -} //restore__vm_monitor_enter_naked - - -void * restore__vm_monitor_enter_static_naked(void * code_addr) -{ - return code_addr; -} //restore__vm_monitor_enter_static_naked - -/* -static char * gen_restore_monitor_exit(char *ss, char *patch_addr_null_arg) -{ - return ss; -} //gen_restore_monitor_exit -*/ - -void * restore__vm_monitor_exit_naked(void * code_addr) -{ - return code_addr; -} //restore__vm_monitor_exit_naked - - -void * restore__vm_monitor_exit_static_naked(void * code_addr) -{ - return code_addr; -} //restore__vm_monitor_exit_static_naked - - -void * getaddress__vm_monitor_enter_naked() -{ - static void *addr = NULL; - return addr; -} - - -void * getaddress__vm_monitor_enter_static_naked() -{ - static void *addr = NULL; - return addr; -} //getaddress__vm_monitor_enter_static_naked - - -void * getaddress__vm_monitor_exit_naked() -{ - static void *addr = NULL; - return addr; -} //getaddress__vm_monitor_exit_naked - - -void * getaddress__vm_monitor_exit_static_naked() -{ - static void *addr = NULL; - return addr; -} //getaddress__vm_monitor_exit_static_naked - -Boolean jit_may_inline_object_synchronization(unsigned *thread_id_register, - unsigned *sync_header_offset, - unsigned *sync_header_width, - unsigned *lock_owner_offset, - unsigned *lock_owner_width, - Boolean *jit_clears_ccv) -{ - return FALSE; -} diff --git vm/vmcore/src/util/em64t/base/jit_runtime_support_em64t.cpp vm/vmcore/src/util/em64t/base/jit_runtime_support_em64t.cpp new file mode 100644 index 0000000..c2a08a3 --- /dev/null +++ vm/vmcore/src/util/em64t/base/jit_runtime_support_em64t.cpp @@ -0,0 +1,222 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision$ + */ + +#include <assert.h> + +#include "open/types.h" +#include "open/gc.h" + +#include "port_general.h" +#include "heap.h" +#include "vm_threads.h" + +#include "lil.h" +#include "lil_code_generator.h" +#include "jit_runtime_support.h" +#include "m2n.h" +#include "../m2n_em64t_internal.h" + +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" + +#include "vm_stats.h" +#include "dump.h" +#include "exceptions.h" +#include "jit_runtime_support_common.h" + +/** + * Generic allocation routine. + */ +static LilCodeStub * rth_get_lil_new_generic(LilCodeStub * cs, void * fast_alloc, void * slow_alloc) { + + POINTER_SIZE_INT ts_gc_offset = APR_OFFSETOF(VM_thread, _gc_private_information); + + return lil_parse_onto_end(cs, + "locals 1;" + "l0 = ts;" + "out platform:g4,pint,pint:ref;" + "o0 = i0;" + "o1 = i1;" + "o2 = l0+%0i:pint;" + "call %1i;" + "jc r = 0, alloc_slow;" + "ret;" + ":alloc_slow;" + "push_m2n 0, 0;" + "out platform:g4,pint,pint:ref;" + "o0 = i0;" + "o1 = i1;" + "o2 = l0+%2i:pint;" + "call %3i;" + "pop_m2n;" + "ret;", + ts_gc_offset, fast_alloc, ts_gc_offset, slow_alloc); +} + +/** + * Object allocation helper. + */ +NativeCodePtr rth_get_lil_new_resolved_using_vtable_and_size() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:g4,pint:ref;"); + assert(cs); + +#ifdef VM_STATS + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add( + (void*)VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE, 0, NULL); + cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); + assert(cs); +#endif + + cs = rth_get_lil_new_generic(cs, (void *)gc_alloc_fast, (void *)vm_malloc_with_thread_pointer); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "new_resolved_using_vtable_and_size", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; +} + +/** + * Vector allocation routine. + */ +NativeCodePtr rth_get_lil_new_vector_using_vtable() { + static NativeCodePtr addr = NULL; + + if (addr != NULL) { + return addr; + } + + LilCodeStub* cs = lil_parse_code_stub("entry 0:managed:g4,pint:ref;"); + assert(cs); + +#ifdef VM_STATS + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add( + (void*)VM_RT_NEW_VECTOR_USING_VTABLE, 0, NULL); + cs = lil_parse_onto_end(cs, "inc [%0i:pint];", value); + assert(cs); +#endif + + cs = rth_get_lil_new_generic(cs, + (void *)vm_new_vector_or_null_using_vtable_and_thread_pointer, + (void *)vm_rt_new_vector_using_vtable_and_thread_pointer); + assert(cs && lil_is_valid(cs)); + + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "new_vector_using_vtable", lil_cs_get_code_size(cs)); + + lil_free_code_stub(cs); + return addr; + +} + +/** + * Creates multidimensional array. Arguments are expected to lie right above last m2n frame. + * Doesn't return if exception occurs. + * + * Note: this is a helper routine for rth_get_lil_multianewarray (see jit_runtime_support.cpp). + */ +Vector_Handle +vm_rt_multianewarray_recursive(Class *c, + int *dims_array, + unsigned dims); + +Vector_Handle rth_multianewarrayhelper() +{ + ASSERT_THROW_AREA; + M2nFrame* m2nf = m2n_get_last_frame(); + const unsigned max_dim = 255; + int lens[max_dim]; + +#ifdef VM_STATS + VM_Statistics::get_vm_stats().num_multianewarray++; +#endif + // +1(skip rip) + uint64 * args = (uint64 *)m2n_get_frame_base(m2nf) + 1; + Class * c = (Class *)args[0]; + unsigned dims = (unsigned)(args[1] & 0xFFFFffff); + assert(dims <= max_dim); + // compute the base address of an array + uint64* lens_base = (uint64*)(args+2); + for(unsigned i = 0; i < dims; i++) { + lens[i] = lens_base[dims-i-1]; + } + return vm_rt_multianewarray_recursive(c, lens, dims); +} + + +// see jit_lock_rt_support.cpp for the implementation +NativeCodePtr rth_get_lil_monitor_enter_static(); +NativeCodePtr rth_get_lil_monitor_enter(); +NativeCodePtr rth_get_lil_monitor_enter_non_null(); + +NativeCodePtr rth_get_lil_monitor_exit_static(); +NativeCodePtr rth_get_lil_monitor_exit(); +NativeCodePtr rth_get_lil_monitor_exit_non_null(); + +void * vm_get_rt_support_addr(VM_RT_SUPPORT f) { + +#ifdef VM_STATS + VM_Statistics::get_vm_stats().rt_function_requests.add((void *)f, 1, NULL); +#endif // VM_STATS + + NativeCodePtr res = rth_get_lil_helper(f); + if (res) return res; + + switch(f) { + // Monitor enter runtime helpers + case VM_RT_MONITOR_ENTER_STATIC: + return rth_get_lil_monitor_enter_static(); + case VM_RT_MONITOR_ENTER: + return rth_get_lil_monitor_enter(); + case VM_RT_MONITOR_ENTER_NON_NULL: + return rth_get_lil_monitor_enter_non_null(); + + // Monitor exit runtime helpers + case VM_RT_MONITOR_EXIT_STATIC: + return rth_get_lil_monitor_exit_static(); + case VM_RT_MONITOR_EXIT: + return rth_get_lil_monitor_exit(); + case VM_RT_MONITOR_EXIT_NON_NULL: + return rth_get_lil_monitor_exit_non_null(); + + // Object creation helper + case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: + return rth_get_lil_new_resolved_using_vtable_and_size(); + // Array creation helper + case VM_RT_NEW_VECTOR_USING_VTABLE: + return rth_get_lil_new_vector_using_vtable(); + default: + ASSERT(false, "Unexpected helper id" << f); + return NULL; + } +} + +void * vm_get_rt_support_addr_optimized(VM_RT_SUPPORT f, Class_Handle UNREF c) { + return vm_get_rt_support_addr(f); +} diff --git vm/vmcore/src/util/em64t/base/jit_runtime_support_ia32.cpp vm/vmcore/src/util/em64t/base/jit_runtime_support_ia32.cpp deleted file mode 100644 index 3bb3b19..0000000 --- vm/vmcore/src/util/em64t/base/jit_runtime_support_ia32.cpp +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.5 $ - */ - - - -//MVM -#include <iostream> - -using namespace std; - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <float.h> -#include <math.h> - -#define LOG_DOMAIN "vm.helpers" -#include "cxxlog.h" - -#include "object_layout.h" -#include "open/types.h" -#include "Class.h" -#include "environment.h" -#include "lil.h" -#include "lil_code_generator.h" -#include "method_lookup.h" -#include "exceptions.h" -#include "vm_synch.h" -#include "open/gc.h" -#include "ini.h" -#include "nogc.h" -#include "encoder.h" -#include "open/vm_util.h" - -#include "vm_threads.h" -#include "mon_enter_exit.h" -#include "vm_arrays.h" -#include "vm_strings.h" -#include "compile.h" - -#include "mon_enter_exit.h" - -#include "sync_bits.h" - -#include "vm_stats.h" -#include "internal_jit_intf.h" -#include "jit_runtime_support_common.h" -#include "jit_runtime_support.h" - -#include "../m2n_em64t_internal.h" - -#include "open/vm_util.h" - -// gets the offset of a certain field within a struct or class type -#define OFFSET(Struct, Field) \ - ((int) (&(((Struct *) NULL)->Field) - NULL)) - -// gets the size of a field within a struct or class -#define SIZE(Struct, Field) \ - (sizeof(((Struct *) NULL)->Field)) - -extern bool dump_stubs; - -void * getaddress__vm_monitor_enter_naked(); -void * getaddress__vm_monitor_enter_static_naked(); -void * getaddress__vm_monitor_exit_naked(); -void * getaddress__vm_monitor_exit_static_naked(); -void * get_generic_rt_support_addr_ia32(VM_RT_SUPPORT f); - - -///////////////////////////////////////////////////////////////// -// begin VM_Runtime_Support -///////////////////////////////////////////////////////////////// -/* -static void vm_throw_java_lang_ClassCastException() -{ - assert(!hythread_is_suspend_enabled()); - throw_java_exception("java/lang/ClassCastException"); -} //vm_throw_java_lang_ClassCastException - -#ifdef VM_STATS // exclude remark in release mode (defined but not used) -static void update_checkcast_stats(ManagedObject *obj, Class *c) -{ - vm_stats_total.num_checkcast ++; - if (obj == NULL) - vm_stats_total.num_checkcast_null ++; - if (obj != NULL && obj->vt()->clss == c) - vm_stats_total.num_checkcast_equal_type ++; - if (obj != NULL && c->is_suitable_for_fast_instanceof) - vm_stats_total.num_checkcast_fast_decision ++; -} //update_checkcast_stats -#endif -*/ - -// 20030321 This JIT support routine expects to be called directly from managed code. -// NOTE: We do not translate null references since vm_instanceof() also expects to be -// called directly by managed code. -static void *getaddress__vm_checkcast_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_checkcast_naked - - - - -// This function is added so that we can have a LIL version of -// instanceof. If LIL is turned off, the address of vm_instanceof is -// returned, just like before. -static void *getaddress__vm_instanceof() -{ - static void *addr = 0; - if (addr) { - return addr; - } - - if (VM_Global_State::loader_env->use_lil_stubs) - { - LilCodeStub *cs = gen_lil_typecheck_stub(false); - assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_instanceof", dump_stubs); - lil_free_code_stub(cs); - return addr; - } - - // just use vm_instanceof - addr = (void *) vm_instanceof; - return addr; -} - -/* -static Boolean is_class_initialized(Class *clss) -{ -#ifdef VM_STATS - vm_stats_total.num_is_class_initialized++; - clss->num_class_init_checks++; -#endif // VM_STATS - assert(!hythread_is_suspend_enabled()); - return clss->state == ST_Initialized; -} //is_class_initialized -*/ - - -static void *getaddress__vm_initialize_class_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_initialize_class_naked - - - -////////////////////////////////////////////////////////////////////// -// Object allocation -////////////////////////////////////////////////////////////////////// - -static void *getaddress__vm_alloc_java_object_resolved_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_alloc_java_object_resolved_naked - - -static void *generate_object_allocation_stub_with_thread_pointer(char *fast_obj_alloc_proc, - char *slow_obj_alloc_proc, - char *stub_name) -{ - return (void *)NULL; -} //generate_object_allocation_stub_with_thread_pointer - - -static void *getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked() -{ - static void *addr = 0; - if (addr) { - return addr; - } - - addr = generate_object_allocation_stub_with_thread_pointer((char *) gc_alloc_fast, - (char *) vm_malloc_with_thread_pointer, - "getaddress__vm_alloc_java_object_resolved_using_thread_pointer_naked"); - - return addr; -} //getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked - - -static void* vm_aastore_nullpointer() -{ - static NativeCodePtr addr = NULL; - return addr; -} //vm_aastore_nullpointer - - -static void* vm_aastore_array_index_out_of_bounds() -{ - static NativeCodePtr addr = NULL; - return addr; -} //vm_aastore_array_index_out_of_bounds - - -static void* vm_aastore_arraystore() -{ - static NativeCodePtr addr = NULL; - return addr; -} //vm_aastore_arraystore - - - -static void *__stdcall -aastore_ia32(volatile ManagedObject *elem, - int idx, - Vector_Handle array) stdcall__; - - -// 20030321 This JIT support routine expects to be called directly from managed code. -static void *__stdcall -aastore_ia32(volatile ManagedObject *elem, - int idx, - Vector_Handle array) -{ - if (VM_Global_State::loader_env->compress_references) { - // 20030321 Convert a null reference from a managed (heap_base) to an unmanaged null (NULL/0). - if (elem == (volatile ManagedObject *)Class::heap_base) { - elem = NULL; - } - if (array == (ManagedObject *)Class::heap_base) { - array = NULL; - } - } - - assert ((elem == NULL) || (((ManagedObject *)elem)->vt() != NULL)); -#ifdef VM_STATS - vm_stats_total.num_aastore++; -#endif // VM_STATS - void *new_eip = 0; - if (array == NULL) { - new_eip = vm_aastore_nullpointer(); - } else if ((unsigned)get_vector_length(array) <= (unsigned)idx) { - new_eip = vm_aastore_array_index_out_of_bounds(); - } else { - assert(idx >= 0); - if (elem != NULL) { - VTable *vt = get_vector_vtable(array); -#ifdef VM_STATS - if (vt == cached_object_array_vtable_ptr) - vm_stats_total.num_aastore_object_array ++; - if (vt->clss->array_element_class->vtable == ((ManagedObject *)elem)->vt()) - vm_stats_total.num_aastore_equal_type ++; - if (vt->clss->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_fast_decision ++; -#endif // VM_STATS - if(vt == cached_object_array_vtable_ptr || - class_is_subtype_fast(((ManagedObject *)elem)->vt(), vt->clss->array_element_class)) { - STORE_REFERENCE((ManagedObject *)array, get_vector_element_address_ref(array, idx), (ManagedObject *)elem); - return 0; - } - new_eip = vm_aastore_arraystore(); - } else { - // A null reference. No need to check types for a null reference. - assert(elem == NULL); -#ifdef VM_STATS - vm_stats_total.num_aastore_null ++; -#endif // VM_STATS - // 20030502 Someone earlier commented out a call to the GC interface function gc_heap_slot_write_ref() and replaced it - // by code to directly store a NULL in the element without notifying the GC. I've retained that change here but I wonder if - // there could be a problem later with, say, concurrent GCs. - if (VM_Global_State::loader_env->compress_references) { - COMPRESSED_REFERENCE *elem_ptr = (COMPRESSED_REFERENCE *)get_vector_element_address_ref(array, idx); - *elem_ptr = (COMPRESSED_REFERENCE)NULL; - } else { - ManagedObject **elem_ptr = get_vector_element_address_ref(array, idx); - *elem_ptr = (ManagedObject *)NULL; - } - return 0; - } - } - - // This may possibly break if the C compiler applies very aggresive optimizations. - void **saved_eip = ((void **)&elem) - 1; - void *old_eip = *saved_eip; - *saved_eip = new_eip; - return old_eip; -} //aastore_ia32 - - -static void *getaddress__vm_aastore() -{ - assert(VM_Global_State::loader_env->use_lil_stubs); - static void *addr = NULL; - if (addr != NULL) { - return addr; - } - - LilCodeStub* cs = lil_parse_code_stub( - "entry 0:managed:ref,pint,ref:void; // The args are the element ref to store, the index, and the array to store into\n" - "in2out managed:pint; " - "call %0i; // vm_rt_aastore either returns NULL or the ClassHandle of an exception to throw \n" - "jc r!=0,aastore_failed; \ - ret; \ - :aastore_failed; \ - std_places 1; \ - sp0=r; \ - tailcall %1i;", - (void *)vm_rt_aastore, - exn_get_rth_throw_lazy_trampoline()); - assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_aastore", dump_stubs); - lil_free_code_stub(cs); - return addr; -} //getaddress__vm_aastore - - - -static void * gen_new_vector_stub(char *stub_name, char *fast_new_vector_proc, char *slow_new_vector_proc) -{ - return NULL; -} //gen_new_vector_stub - - -static void *getaddress__vm_new_vector_naked() -{ - static void *addr = 0; - if (addr) { - return addr; - } - - addr = gen_new_vector_stub("getaddress__vm_new_vector_naked", - (char *)vm_new_vector_or_null, (char *)vm_new_vector); - return addr; -} //getaddress__vm_new_vector_naked - - -static void *getaddress__vm_new_vector_using_vtable_naked() { - static void *addr = 0; - if (addr) { - return addr; - } - - addr = generate_object_allocation_stub_with_thread_pointer((char *)vm_new_vector_or_null_using_vtable_and_thread_pointer, - (char *)vm_new_vector_using_vtable_and_thread_pointer, - "getaddress__vm_new_vector_using_vtable_naked"); - return addr; -} //getaddress__vm_new_vector_using_vtable_naked - - -// This is a __cdecl function and the caller must pop the arguments. -static void *getaddress__vm_multianewarray_resolved_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_multianewarray_resolved_naked - - - -static void *getaddress__vm_instantiate_cp_string_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_instantiate_cp_string_naked - - -/* -static void vm_throw_java_lang_IncompatibleClassChangeError() -{ - throw_java_exception("java/lang/IncompatibleClassChangeError"); -} //vm_throw_java_lang_IncompatibleClassChangeError -*/ - - -// 20030321 This JIT support routine expects to be called directly from managed code. -void * getaddress__vm_get_interface_vtable_old_naked() //wjw verify that this works -{ - static void *addr = 0; - return addr; -} //getaddress__vm_get_interface_vtable_old_naked - -/* -static void vm_throw_java_lang_ArithmeticException() -{ - assert(!hythread_is_suspend_enabled()); - throw_java_exception("java/lang/ArithmeticException"); -} //vm_throw_java_lang_ArithmeticException - -static void* getaddress__setup_java_to_native_frame() -{ - static void *addr = 0; - return addr; -} //getaddress__setup_java_to_native_frame -*/ - - -VMEXPORT char *gen_setup_j2n_frame(char *s) -{ - return s; -} //setup_j2n_frame - -/* -static void* getaddress__pop_java_to_native_frame() -{ - static void *addr = 0; - return addr; -} //getaddress__pop_java_to_native_frame -*/ - -VMEXPORT char *gen_pop_j2n_frame(char *s) -{ - return s; -} //setup_j2n_frame - - -///////////////////////////////////////////////////////////////// -// end VM_Runtime_Support -///////////////////////////////////////////////////////////////// - -/* -static void -vm_throw_linking_exception(Class *clss, - unsigned cp_index, - unsigned opcode) -{ - printf("vm_throw_linking_exception, idx=%d\n", cp_index); - class_throw_linking_error(clss, cp_index, opcode); -} //vm_throw_linking_exception -*/ - -void * getaddress__vm_throw_linking_exception_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_throw_linking_exception_naked - - - -// 20030321 This JIT support routine expects to be called directly from managed code. -void * getaddress__gc_write_barrier_fastcall() -{ - static void *addr = 0; - return addr; -} //getaddress__gc_write_barrier_fastcall - -/* -static int64 __stdcall vm_lrem(int64 m, int64 n) stdcall__; - -static int64 __stdcall vm_lrem(int64 m, int64 n) -{ - assert(!hythread_is_suspend_enabled()); - return m % n; -} //vm_lrem -*/ - -void * getaddress__vm_lrem_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_lrem_naked - -/* -static int64 __stdcall vm_ldiv(int64 m, int64 n) stdcall__; - -static int64 __stdcall vm_ldiv(int64 m, int64 n) -{ - assert(!hythread_is_suspend_enabled()); - assert(n); - return m / n; -} //vm_ldiv -*/ - -static void *getaddress__vm_ldiv_naked() -{ - static void *addr = 0; - return addr; -} //getaddress__vm_ldiv_naked - - - - - - -#ifdef VM_STATS - -static void register_request_for_rt_function(VM_RT_SUPPORT f) { - // Increment the number of times that f was requested by a JIT. This is not the number of calls to that function, - // but this does tell us how often a call to that function is compiled into JITted code. - vm_stats_total.rt_function_requests.add((void *)f, /*value*/ 1, /*value1*/ NULL); -} //register_request_for_rt_function - -#endif //VM_STATS - - -void *vm_get_rt_support_addr(VM_RT_SUPPORT f) -{ -#ifdef VM_STATS - register_request_for_rt_function(f); -#endif // VM_STATS - - NativeCodePtr res = rth_get_lil_helper(f); - if (res) return res; - - - switch(f) { - case VM_RT_NULL_PTR_EXCEPTION: - return exn_get_rth_throw_null_pointer(); - case VM_RT_IDX_OUT_OF_BOUNDS: - return exn_get_rth_throw_array_index_out_of_bounds(); - case VM_RT_ARRAY_STORE_EXCEPTION: - return exn_get_rth_throw_array_store(); - case VM_RT_DIVIDE_BY_ZERO_EXCEPTION: - return exn_get_rth_throw_arithmetic(); - case VM_RT_THROW: - case VM_RT_THROW_SET_STACK_TRACE: - return exn_get_rth_throw(); - case VM_RT_THROW_LAZY: - return exn_get_rth_throw_lazy(); - case VM_RT_LDC_STRING: - return getaddress__vm_instantiate_cp_string_naked(); - case VM_RT_NEW_RESOLVED: - return getaddress__vm_alloc_java_object_resolved_naked(); - case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: - return getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked(); - case VM_RT_MULTIANEWARRAY_RESOLVED: - return getaddress__vm_multianewarray_resolved_naked(); - case VM_RT_NEW_VECTOR: - return getaddress__vm_new_vector_naked(); - case VM_RT_NEW_VECTOR_USING_VTABLE: - return getaddress__vm_new_vector_using_vtable_naked(); - case VM_RT_AASTORE: - if (VM_Global_State::loader_env->use_lil_stubs) { - return getaddress__vm_aastore(); - } else { - return (void *)aastore_ia32; - } - case VM_RT_AASTORE_TEST: - return (void *)vm_aastore_test; - case VM_RT_WRITE_BARRIER_FASTCALL: - return getaddress__gc_write_barrier_fastcall(); - - case VM_RT_CHECKCAST: - return getaddress__vm_checkcast_naked(); - - case VM_RT_INSTANCEOF: - return getaddress__vm_instanceof(); - - case VM_RT_MONITOR_ENTER: - case VM_RT_MONITOR_ENTER_NO_EXC: - return getaddress__vm_monitor_enter_naked(); - - case VM_RT_MONITOR_ENTER_STATIC: - return getaddress__vm_monitor_enter_static_naked(); - - case VM_RT_MONITOR_EXIT: - case VM_RT_MONITOR_EXIT_NON_NULL: - return getaddress__vm_monitor_exit_naked(); - - case VM_RT_MONITOR_EXIT_STATIC: - return getaddress__vm_monitor_exit_static_naked(); - - case VM_RT_GET_INTERFACE_VTABLE_VER0: - return getaddress__vm_get_interface_vtable_old_naked(); //tryitx - case VM_RT_INITIALIZE_CLASS: - return getaddress__vm_initialize_class_naked(); - case VM_RT_THROW_LINKING_EXCEPTION: - return getaddress__vm_throw_linking_exception_naked(); - - case VM_RT_LREM: - return getaddress__vm_lrem_naked(); - case VM_RT_LDIV: - return getaddress__vm_ldiv_naked(); - - case VM_RT_F2I: - case VM_RT_F2L: - case VM_RT_D2I: - case VM_RT_D2L: - case VM_RT_LSHL: - case VM_RT_LSHR: - case VM_RT_LUSHR: - case VM_RT_FREM: - case VM_RT_DREM: - case VM_RT_LMUL: -#ifdef VM_LONG_OPT - case VM_RT_LMUL_CONST_MULTIPLIER: -#endif - case VM_RT_CONST_LDIV: - case VM_RT_CONST_LREM: - case VM_RT_DDIV: - case VM_RT_IMUL: - case VM_RT_IDIV: - case VM_RT_IREM: - case VM_RT_CHAR_ARRAYCOPY_NO_EXC: - return get_generic_rt_support_addr_ia32(f); - - default: - ABORT("Unexpected helper id"); - return 0; - } -} //vm_get_rt_support_addr - - - -/************************************************** - * The following code has to do with the LIL stub inlining project. - * Modifying it should not affect anything. - */ - - -// a structure used in memoizing already created stubs -struct TypecheckStubMemoizer { - Class *clss; // the class for which this stub is for - void *fast_checkcast_stub, *fast_instanceof_stub; - TypecheckStubMemoizer *next; - - static TypecheckStubMemoizer* head; // head of the list - static tl::MemoryPool mem; // we'll alocate structures from here - - static void* find_stub(Class *c, bool is_checkcast) { - // search for an existing struct for this class - for (TypecheckStubMemoizer *t = head; t != NULL; t = t->next) { - if (t->clss == c) { - return (is_checkcast) ? - t->fast_checkcast_stub : t->fast_instanceof_stub; - } - } - - return NULL; - } - - static void add_stub(Class *c, void *stub, bool is_checkcast) { - // search for an existing struct for this class - - TypecheckStubMemoizer *t; - for (t = head; t != NULL; t = t->next) { - if (t->clss == c) - break; - } - - if (t == NULL) { - // create new structure - t = (TypecheckStubMemoizer*) mem.alloc(sizeof(TypecheckStubMemoizer)); - t->clss = c; - t->fast_checkcast_stub = NULL; - t->fast_instanceof_stub = NULL; - t->next = head; - head = t; - } - - if (is_checkcast) { - assert(t->fast_checkcast_stub == NULL); - t->fast_checkcast_stub = stub; - } - else { - assert(t->fast_instanceof_stub == NULL); - t->fast_instanceof_stub = stub; - } - } -}; - -static StaticInitializer jit_runtime_initializer; -TypecheckStubMemoizer* TypecheckStubMemoizer::head = NULL; -tl::MemoryPool TypecheckStubMemoizer::mem; // we'll alocate structures from here - -/* 03/07/30: temporary interface change!!! */ -void *vm_get_rt_support_addr_optimized(VM_RT_SUPPORT f, Class_Handle c) { - Class *clss = (Class*) c; - if (clss == NULL) - { - return vm_get_rt_support_addr(f); - } - - switch (f) { - case VM_RT_CHECKCAST: - return vm_get_rt_support_addr(f); - break; - case VM_RT_INSTANCEOF: - return vm_get_rt_support_addr(f); - break; - case VM_RT_NEW_RESOLVED: - if (class_is_finalizable(c)) - return getaddress__vm_alloc_java_object_resolved_naked(); - else - return vm_get_rt_support_addr(f); - break; - case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: - if (class_is_finalizable(c)) - return getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked(); - else - return vm_get_rt_support_addr(f); - break; - default: - return vm_get_rt_support_addr(f); - break; - } -} - - -// instead of returning a stub address, this support function returns -// parsed LIL code. -// May return NULL if the stub requested should not be inlined -VMEXPORT LilCodeStub *vm_get_rt_support_stub(VM_RT_SUPPORT f, Class_Handle c) { - Class *clss = (Class *) c; - - switch (f) { - case VM_RT_CHECKCAST: - { - if (!clss->is_suitable_for_fast_instanceof) - return NULL; - - return gen_lil_typecheck_stub_specialized(true, true, clss); - } - case VM_RT_INSTANCEOF: - { - if (!clss->is_suitable_for_fast_instanceof) - return NULL; - - return gen_lil_typecheck_stub_specialized(false, true, clss); - } - default: - ABORT("Unexpected hepler id"); - return NULL; - } -} - - -/* - * LIL inlining code - end - **************************************************/ diff --git vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp new file mode 100755 index 0000000..bafcd38 --- /dev/null +++ vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "method_lookup.h" +#include "native_stack.h" + +void native_get_frame_info(Registers* regs, void** ip, /* void** ret, */ void** bp, void** sp) +{ + *ip = (void*)regs->rip; + // + // FIXME: number of parameters should be fixed in public interface + // + //*ret = ((void**)regs->rbp)[1]; + *bp = (void*)regs->rbp; + *sp = (void*)regs->rsp; +} + +bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +{ + return false; // Not implemented +} + +void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) +{ // Not implemented +} + +void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) +{ // Not implemented +} + +bool native_is_out_of_stack(void* value) +{ + return true; // Not implemented +} + +bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +{ + return false; // Not implemented +} + +int native_test_unwind_special(native_module_t* modules, void* sp) +{ + return false; // Not implemented +} + +bool native_unwind_special(native_module_t* modules, + void* stack, void** ip, void** sp, void** bp, bool is_last) +{ + return false; // Not implemented +} diff --git vm/vmcore/src/util/em64t/base/optimize_ia32.cpp vm/vmcore/src/util/em64t/base/optimize_ia32.cpp deleted file mode 100644 index 7eb3c88..0000000 --- vm/vmcore/src/util/em64t/base/optimize_ia32.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.5 $ - */ - - -//MVM -#include <iostream> - -using namespace std; - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#include "open/types.h" -#include "environment.h" -#include "encoder.h" -#include "open/vm_util.h" -#include "compile.h" - -// *** This is for readInternal override -#include "jni_utils.h" -#include "vm_arrays.h" -#include "open/vm_util.h" - -extern int readinternal_override_lil(JNIEnv *jenv, Java_java_io_FileInputStream *pThis, int fd, Vector_Handle pArrayOfByte, int offset, int len); - -// *** This is for currenttimemillis override -#include "platform_core_natives.h" -/* -static unsigned java_array_of_char_body_offset() -{ - return vector_first_element_offset(VM_DATA_TYPE_CHAR); -} - -static unsigned java_array_of_char_length_offset() -{ - return vector_length_offset(); -} -*/ -static bool enable_fast_char_arraycopy() -{ - Global_Env *env = VM_Global_State::loader_env; - if (env->compress_references) - return false; - return true; -} - -/* -static ManagedObject * -get_class_ptr(ManagedObject *obj) -{ - return *(obj->vt()->clss->class_handle); -} -*/ -// ****** Begin overrides -// ****** identityHashCode -#include "object_generic.h" -unsigned native_hashcode_fastpath_size(Method *m) -{ - return 20; -} -void gen_native_hashcode(Emitter_Handle h, Method *m) -{ -} - -// ****** newInstance -// *** This is for the newInstance override -unsigned native_newinstance_fastpath_size(Method *m) -{ - return 100; -} - -void gen_native_newinstance(Emitter_Handle h, Method *m) -{ -} - -// ****** readInternal -unsigned native_readinternal_fastpath_size(Method *m) -{ - return 100; -} -void gen_native_readinternal(Emitter_Handle h, Method *m) -{ -} - -// ****** get current time millis -unsigned native_getccurrenttime_fastpath_size(Method *m) -{ - return 20; -} -void gen_native_system_currenttimemillis(Emitter_Handle h, Method *m) -{ -} - -// above are additions to bring original on par with LIL - -unsigned native_getclass_fastpath_size(Method *m) -{ - return 20; -} - - -void gen_native_getclass_fastpath(Emitter_Handle h, Method *m) -{ -} - - - -// Return an upper bound on the size of the custom arraycopy routine. -unsigned native_arraycopy_fastpath_size(Method *m) -{ - if (enable_fast_char_arraycopy()) - return 350; - return 0; -} - -//MOV_PAIR must be less than 32 -#define MOV_PAIR 8 -void gen_native_arraycopy_fastpath(Emitter_Handle h, Method *method) -{ -} //jit_inline_native_array_copy_general - - - -int find_inline_native_method(const char* clss_name, const char* method_name,JIT_Result (*&func)(Method& method, JIT_Flags flags)) -{ - return -1 ; -} //find_inline_native_method diff --git vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.cpp vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.cpp new file mode 100644 index 0000000..4002fc9 --- /dev/null +++ vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision$ + */ + +void setup_floating_point_state(int * p_old_floating_point_state) { +} + +void cleanup_floating_point_state(int old_floating_point_state) { +} diff --git vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.h vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.h new file mode 100644 index 0000000..ddd7831 --- /dev/null +++ vm/vmcore/src/util/em64t/base_natives/java_lang_thread_em64t.h @@ -0,0 +1,56 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision: 1.1.2.1.4.3 $ + */ + + +#include "log_macro.h" + +#ifdef PLATFORM_POSIX + + +#define OS_HW_REGS_TO_VM_THREAD_REGS() ABORT("Not supported"); +#define OS_VM_THREAD_REGS_TO_HW_REGS() ABORT("Not supported"); + +#else + +#define OS_HW_REGS_TO_VM_THREAD_REGS() \ + p_thr->regs.eax = nt_registers.Eax; \ + p_thr->regs.ebx = nt_registers.Ebx; \ + p_thr->regs.ecx = nt_registers.Ecx; \ + p_thr->regs.edx = nt_registers.Edx; \ + p_thr->regs.edi = nt_registers.Edi; \ + p_thr->regs.esi = nt_registers.Esi; \ + p_thr->regs.ebp = nt_registers.Ebp; \ + p_thr->regs.esp = nt_registers.Esp; \ + p_thr->regs.eip = nt_registers.Eip; + + + +#define OS_VM_THREAD_REGS_TO_HW_REGS() \ + nt_registers.Eax = p_thr->regs.eax; \ + nt_registers.Ebx = p_thr->regs.ebx; \ + nt_registers.Ecx = p_thr->regs.ecx; \ + nt_registers.Edx = p_thr->regs.edx; \ + nt_registers.Edi = p_thr->regs.edi; \ + nt_registers.Esi = p_thr->regs.esi; \ + nt_registers.Ebp = p_thr->regs.ebp; + + + +#endif diff --git vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.cpp vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.cpp deleted file mode 100644 index 6e8e7c5..0000000 --- vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ - */ - - - -#include "platform.h" -#include <assert.h> - -//MVM -#include <iostream> - -using namespace std; - - -#ifndef PLATFORM_POSIX -#include "vm_process.h" -#endif - -#include "environment.h" -#include "open/types.h" -#include "open/vm_util.h" -#include "object_layout.h" -#include "Class.h" -#include "vm_threads.h" - -#include "thread_generic.h" - -void setup_floating_point_state(int *p_old_floating_point_state) -{ - int old_floating_point_state = 0; -#ifdef PLATFORM_NT - int floating_point_temp = 0; - __asm { - // the below set the significand to 53 bits for doubles - // this is "non-strict" mode - // you should call cleanup_floating_point_state (see below) - // before entering Java Code - fnstcw WORD PTR [old_floating_point_state] - fnstcw WORD PTR [floating_point_temp] - and DWORD PTR[floating_point_temp], 0feffH - or DWORD PTR [floating_point_temp], 0200H - fldcw WORD PTR [floating_point_temp] - } -#endif - *p_old_floating_point_state = old_floating_point_state; -} - - -void cleanup_floating_point_state(int old_floating_point_state) -{ -#ifdef PLATFORM_NT - // the below restores floating point state to "strict" mode - __asm { - fldcw WORD PTR [old_floating_point_state] - } -#endif -} diff --git vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.h vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.h deleted file mode 100644 index ec8e5c7..0000000 --- vm/vmcore/src/util/em64t/base_natives/java_lang_thread_ia32.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.4 $ - */ - - -#include "log_macro.h" - -#ifdef PLATFORM_POSIX - - -#define OS_HW_REGS_TO_VM_THREAD_REGS() ABORT("Not supported"); -#define OS_VM_THREAD_REGS_TO_HW_REGS() ABORT("Not supported"); - -#else - -#define OS_HW_REGS_TO_VM_THREAD_REGS() \ - p_thr->regs.eax = nt_registers.Eax; \ - p_thr->regs.ebx = nt_registers.Ebx; \ - p_thr->regs.ecx = nt_registers.Ecx; \ - p_thr->regs.edx = nt_registers.Edx; \ - p_thr->regs.edi = nt_registers.Edi; \ - p_thr->regs.esi = nt_registers.Esi; \ - p_thr->regs.ebp = nt_registers.Ebp; \ - p_thr->regs.esp = nt_registers.Esp; \ - p_thr->regs.eip = nt_registers.Eip; - - - -#define OS_VM_THREAD_REGS_TO_HW_REGS() \ - nt_registers.Eax = p_thr->regs.eax; \ - nt_registers.Ebx = p_thr->regs.ebx; \ - nt_registers.Ecx = p_thr->regs.ecx; \ - nt_registers.Edx = p_thr->regs.edx; \ - nt_registers.Edi = p_thr->regs.edi; \ - nt_registers.Esi = p_thr->regs.esi; \ - nt_registers.Ebp = p_thr->regs.ebp; - - - -#endif diff --git vm/vmcore/src/util/ia32/base/compile_IA32.cpp vm/vmcore/src/util/ia32/base/compile_IA32.cpp old mode 100644 new mode 100755 index 03c7cd1..c47b3dd --- vm/vmcore/src/util/ia32/base/compile_IA32.cpp +++ vm/vmcore/src/util/ia32/base/compile_IA32.cpp @@ -18,11 +18,9 @@ * @version $Revision: 1.1.2.2.4.4 $ */ - -#define LOG_DOMAIN "port.old" +#define LOG_DOMAIN "vm.helpers" #include "cxxlog.h" - #include "platform.h" //MVM @@ -44,6 +42,7 @@ #include "stack_iterator.h" #include "m2n.h" #include "../m2n_ia32_internal.h" #include "exceptions.h" +#include "exceptions_jit.h" #include "jit_intf.h" #include "jit_intf_cpp.h" #include "jit_runtime_support.h" @@ -59,44 +58,27 @@ #include "open/vm_util.h" #include "vm_synch.h" #include "vm_threads.h" #include "ini.h" -#include "vm_stats.h" #include "compile.h" #include "lil.h" #include "lil_code_generator.h" -#ifndef NDEBUG +#include "vm_stats.h" #include "dump.h" -extern bool dump_stubs; -#endif - -// Used by prepare_native_method() to compute the offsets of fields in structures -#define offset_of(type,member) ((size_t)(&((type *)0)->member)) - -#define REWRITE_INVALID_TYPE 0 -#define REWRITE_PATCH_COMPILE_ME_STUB 1 -#define REWRITE_PATCH_CALLER 2 -#define REWRITE_PATCH_OLD_CODE_TO_REWRITER 3 -void compile_flush_generated_code_block(Byte*, size_t) -{ +void compile_flush_generated_code_block(Byte*, size_t) { // Nothing to do on IA32 } - -void compile_flush_generated_code() -{ +void compile_flush_generated_code() { // Nothing to do on IA32 } - -static uint32* get_arg_word(unsigned num_arg_words, unsigned word) -{ +static uint32* get_arg_word(unsigned num_arg_words, unsigned word) { return m2n_get_args(m2n_get_last_frame())+num_arg_words-word-1; } -void compile_protect_arguments(Method_Handle method, GcFrame* gc) -{ +void compile_protect_arguments(Method_Handle method, GcFrame* gc) { assert(!hythread_is_suspend_enabled()); Method_Signature_Handle msh = method_get_signature(method); unsigned num_args = method_args_get_number(msh); @@ -147,176 +129,14 @@ void compile_protect_arguments(Method_Ha } } - -// create_call_native_proc_stub() creates a customized stub that can be used to call a native procedure from managed code. -// Arguments used to customize the generated stub: -// - "proc_addr" - address of the native procedure (e.g., address of jit_a_method or delegate_invocation_work) -// - "stub_name" - name of the new stub. -// - "final_action" - action to take after calling "proc_addr". For example: -// - CNP_ReturnFinalAction - return after calling the native procedure (e.g. delegate Invoke) -// - CNP_JmpToRetAddrFinalAction - call the procedure whose address is returned by the native procedure (e.g. JIT compile method) -// - "return_type" - If CNP_ReturnFinalAction, the type returned by the called "proc_addr". NB: "proc_addr" MUST return any result -// in eax/edx as a long (int64) value; "return_type" determines what registers to set.from this value. -// -// On entry to the generated stub: -// - the stack contains arguments already pushed by a caller -// - eax contains a first argument to be passed to "proc_addr": e.g., a method handle. -// - ecx contains a stack adjustment value used to pop the arguments when "final_action" is CNP_ReturnFinalAction. -// This is also passed to "proc_addr" as a second argument. -// -void *create_call_native_proc_stub(char *proc_addr, char *stub_name, CNP_FinalAction final_action, CNP_ReturnType return_type) -{ - const int stub_size = 100; - char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); -#ifdef _DEBUG - memset(stub, 0xcc /*int 3*/, stub_size); -#endif - char *ss = stub; - - ss = push(ss, ebp_opnd); - ss = push(ss, ebx_opnd); - ss = push(ss, esi_opnd); - ss = push(ss, edi_opnd); - ss = mov(ss, esi_opnd, eax_opnd); - ss = mov(ss, edi_opnd, ecx_opnd); - ss = m2n_gen_push_m2n(ss, NULL, FRAME_UNKNOWN, false, 4); - - // Call the procedure passing the 2 arguments: the values originally in eax and ecx - ss = push(ss, edi_opnd); // 2nd arg: value from ecx originally - ss = push(ss, esi_opnd); // 1st arg: value from eax, typically a method handle - ss = call(ss, proc_addr); - ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(8)); - // Any return value is left in eax/edx - - - // Exception rethrow code. - - // Save eax and edx's values in callee-saved registers - ss = mov(ss, esi_opnd, eax_opnd); - ss = mov(ss, ebp_opnd, edx_opnd); - - ///////////////////////////////////////////////////////////// - // begin exceptions - - ss = call(ss, (char *)get_current_thread_exception); - ss = alu(ss, or_opc, eax_opnd, eax_opnd); - ss = branch8(ss, Condition_E, Imm_Opnd(size_8, 5)); - ss = call(ss, (char *)rethrow_current_thread_exception); - - // end exceptions - ///////////////////////////////////////////////////////////// - - // Restore eax and edx's values from callee-saved registers - ss = mov(ss, eax_opnd, esi_opnd); - ss = mov(ss, edx_opnd, ebp_opnd); - - ss = mov(ss, ecx_opnd, edi_opnd); - ss = m2n_gen_pop_m2n(ss, false, 0, 0, 2); - - // Perform end-of-stub action after calling the procedure. For example, just return - // or jump to the address the called procedure returned. - switch (final_action) { - case CNP_ReturnFinalAction: { - // Return. First set the appropriate result registers. - switch (return_type) { - case CNP_VoidReturnType: - case CNP_IntReturnType: - break; - case CNP_FloatReturnType: - // move the float32 value in eax to ST(0), the top of the FP stack - // It appears the JNI interpreter wrapper fixes up the FP stack for you, - // meaning these instructions merely stomp on previous values. - ss = push(ss, eax_opnd); - ss = fld(ss, M_Base_Opnd(esp_reg, 0), /*is_double*/ 0); - ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); - break; - case CNP_DoubleReturnType: - // move the float64 value in eax/edx to ST(0), the top of the FP stack - // It appears the JNI interpreter wrapper fixes up the FP stack for you, - // meaning these instructions merely stomp on previous values. - ss = push(ss, edx_opnd); - ss = push(ss, eax_opnd); - ss = fld(ss, M_Base_Opnd(esp_reg, 0), /*is_double*/ 1); - ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(8)); - break; - default: - ABORT("Wrong return type"); - } - // Adjust the stack pointer to pop the incoming arguments. - // We'd like to do a "ret [%ecx]", but that's not a legal instruction. - // The stack holds %ecx bytes of arguments followed by the return address. - // Note that all registers are in use except ecx. - ss = push(ss, edi_opnd); - // temporarily save edi on the stack - // Copy the return address to where we want it for the ret instruction: - // at the stack location of the first pushed arg - - // displacement "4" because of the push we just did - M_Index_Opnd first_arg(esp_reg, ecx_reg, /*disp*/ 4, /*shift*/ 0); - // edi := return address - ss = mov(ss, edi_opnd, M_Base_Opnd(esp_reg, 4)); - // store return address where we want it for the ret instruction - ss = mov(ss, first_arg, edi_opnd); - // restore edi - ss = pop(ss, edi_opnd); - // pop args, leaving stack pointer pointing at return address - ss = alu(ss, add_opc, esp_opnd, ecx_opnd); - ss = ret(ss); - } - break; - case CNP_JmpToRetAddrFinalAction: { - // Continue execution in, e.g., the newly compiled method. - ss = jump(ss, eax_opnd); - } - break; - default: - ABORT("Wrong final action"); - } - - assert((ss - stub) <= stub_size); - - if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk(stub_name, stub, stub_size); - jvmti_send_dynamic_code_generated_event(stub_name, stub, stub_size); - } - -#ifndef NDEBUG - if (dump_stubs) - dump(stub, stub_name, ss - stub); -#endif - return stub; -} //create_call_native_proc_stub - - -void patch_code_with_threads_suspended(Byte * UNREF code_block, Byte * UNREF new_code, size_t UNREF size) -{ +void patch_code_with_threads_suspended(Byte * UNREF code_block, Byte * UNREF new_code, size_t UNREF size) { ABORT("Not supported on IA32 currently"); -} //patch_code_with_threads_suspended - - -Emitter_Handle gen_throw_if_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char* ss = (char*)emitter; - ss = mov(ss, eax_opnd, M_Base_Opnd(esp_reg, stack_pointer_offset)); - if (VM_Global_State::loader_env->compress_references) { - ss = alu(ss, cmp_opc, eax_opnd, Imm_Opnd((int32)Class::heap_base) ); - } else { - ss = test(ss, eax_opnd, eax_opnd); - } - ss = branch8(ss, Condition_NE, Imm_Opnd(size_8, 0)); // not null, branch around the throw - char *backpatch_address__not_managed_null = ((char *)ss) - 1; - ss = jump(ss, (char*)exn_get_rth_throw_null_pointer()); - signed offset = (signed)ss - (signed)backpatch_address__not_managed_null - 1; - *backpatch_address__not_managed_null = (char)offset; - return (Emitter_Handle)ss; } - -// Convert a reference on the stack, if null, from a managed null (represented by heap_base) to an unmanaged one (NULL/0). Uses %eax. -Emitter_Handle gen_convert_managed_to_unmanaged_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char *ss = (char *)emitter; +// Convert a reference on the stack, if null, from a managed null +// (represented by heap_base) to an unmanaged one (NULL/0). Uses %eax. +char * gen_convert_managed_to_unmanaged_null_ia32(char * ss, + unsigned stack_pointer_offset) { if (VM_Global_State::loader_env->compress_references) { ss = mov(ss, eax_opnd, M_Base_Opnd(esp_reg, stack_pointer_offset)); ss = alu(ss, cmp_opc, eax_opnd, Imm_Opnd((int32)Class::heap_base) ); @@ -326,38 +146,13 @@ Emitter_Handle gen_convert_managed_to_un signed offset = (signed)ss - (signed)backpatch_address__not_managed_null - 1; *backpatch_address__not_managed_null = (char)offset; } - return (Emitter_Handle)ss; -} //gen_convert_managed_to_unmanaged_null_ia32 - - -// Convert a reference on the stack, if null, from an unmanaged null (NULL/0) to an managed one (heap_base). Uses %eax. -Emitter_Handle gen_convert_unmanaged_to_managed_null_ia32(Emitter_Handle emitter, unsigned stack_pointer_offset) -{ - char *ss = (char *)emitter; - if (VM_Global_State::loader_env->compress_references) { - ss = mov(ss, eax_opnd, M_Base_Opnd(esp_reg, stack_pointer_offset)); - ss = test(ss, eax_opnd, eax_opnd); - ss = branch8(ss, Condition_NE, Imm_Opnd(size_8, 0)); // not null, branch around the mov 0 - char *backpatch_address__not_unmanaged_null = ((char *)ss) - 1; - ss = mov(ss, M_Base_Opnd(esp_reg, stack_pointer_offset), Imm_Opnd((int32)Class::heap_base)); - signed offset = (signed)ss - (signed)backpatch_address__not_unmanaged_null - 1; - *backpatch_address__not_unmanaged_null = (char)offset; - } - return (Emitter_Handle)ss; -} //gen_convert_unmanaged_to_managed_null_ia32 - - + return ss; +} -char *create_unboxer(Method * UNREF method) -{ - ABORT("Not implemented"); - return 0; -} //create_unboxer -////////////////////////////////////////////////////////////////////////// -// Compile-Me Stubs +/* BEGIN COMPILE-ME STUBS */ -NativeCodePtr compile_jit_a_method(Method* method); +NativeCodePtr compile_jit_a_method(Method * method); static NativeCodePtr compile_get_compile_me_generic() { static NativeCodePtr addr = NULL; @@ -365,7 +160,8 @@ static NativeCodePtr compile_get_compile return addr; } - const int STUB_SIZE = 8 + m2n_push_m2n_size(false, 0) + m2n_pop_m2n_size(false, 0, 0, 1); + const int STUB_SIZE = 15 + m2n_push_m2n_size(false, 0) + + m2n_pop_m2n_size(false, 0, 0, 1); char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); addr = stub; @@ -382,30 +178,30 @@ #endif stub = pop(stub, ecx_opnd); // pop m2n from the stack stub = m2n_gen_pop_m2n(stub, false, 0, 0, 1); + stub = push(stub, eax_opnd); + // rethrow exception if + stub = call(stub, (char *)&exn_rethrow_if_pending); + stub = pop(stub, eax_opnd); // transfer control to the compiled code stub = jump(stub, eax_opnd); assert(stub - (char *)addr <= STUB_SIZE); + compile_add_dynamic_generated_code_chunk("compile_me_generic", addr, STUB_SIZE); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("compile_me_generic", addr, STUB_SIZE); jvmti_send_dynamic_code_generated_event("compile_me_generic", addr, STUB_SIZE); - } -#ifndef NDEBUG - if (dump_stubs) - dump((char *)addr, "compileme_generic", stub - (char *)addr); -#endif + DUMP_STUB(addr, "compileme_generic", stub - (char *)addr); + return addr; -} //compile_get_compile_me_generic +} NativeCodePtr compile_gen_compile_me(Method_Handle method) { - int STUB_SIZE = 8; + const int STUB_SIZE = 16; #ifdef VM_STATS - STUB_SIZE = 16; - ++vm_stats_total.num_compileme_generated; + ++VM_Statistics::get_vm_stats().num_compileme_generated; #endif char * stub = (char *) malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_DEFAULT, CAA_Allocate); @@ -415,25 +211,23 @@ #ifndef NDEBUG #endif #ifdef VM_STATS - stub = inc(stub, M_Base_Opnd(n_reg, (int32)&vm_stats_total.num_compileme_used)); + stub = inc(stub, M_Base_Opnd(n_reg, (int32)&VM_Statistics::get_vm_stats().num_compileme_used)); #endif stub = mov(stub, ecx_opnd, Imm_Opnd((int32)method)); stub = jump(stub, (char *)compile_get_compile_me_generic()); assert(stub - (char *)addr <= STUB_SIZE); + char * name; + const char * c = class_get_name(method_get_class(method)); + const char * m = method_get_name(method); + const char * d = method_get_descriptor(method); + size_t sz = strlen(c)+strlen(m)+strlen(d)+12; + name = (char *)STD_MALLOC(sz); + sprintf(name, "compileme.%s.%s%s", c, m, d); + compile_add_dynamic_generated_code_chunk(name, addr, STUB_SIZE); if (VM_Global_State::loader_env->TI->isEnabled()) - { - char * name; - const char * c = class_get_name(method_get_class(method)); - const char * m = method_get_name(method); - const char * d = method_get_descriptor(method); - size_t sz = strlen(c)+strlen(m)+strlen(d)+12; - name = (char *)STD_MALLOC(sz); - sprintf(name, "compileme.%s.%s%s", c, m, d); - jvmti_add_dynamic_generated_code_chunk(name, addr, STUB_SIZE); jvmti_send_dynamic_code_generated_event(name, addr, STUB_SIZE); - } #ifndef NDEBUG @@ -448,7 +242,7 @@ #ifndef NDEBUG buf = (char *)STD_MALLOC(sz); sprintf(buf, "compileme.%s.%s%s", c, m, d); assert(strlen(buf) < sz); - dump((char *)addr, buf, stub - (char *)addr); + DUMP_STUB(addr, buf, stub - (char *)addr); STD_FREE(buf); } #endif @@ -484,6 +278,8 @@ #endif // // return addr; //} // compile_gen_compile_me_exc_throw + +/* END COMPILE-ME STUBS */ void gen_native_hashcode(Emitter_Handle h, Method *m); unsigned native_hashcode_fastpath_size(Method *m); diff --git vm/vmcore/src/util/ia32/base/jit_generic_rt_support_ia32.cpp vm/vmcore/src/util/ia32/base/jit_generic_rt_support_ia32.cpp index 8c91626..f9f19c0 100644 --- vm/vmcore/src/util/ia32/base/jit_generic_rt_support_ia32.cpp +++ vm/vmcore/src/util/ia32/base/jit_generic_rt_support_ia32.cpp @@ -34,8 +34,8 @@ #include "jit_runtime_support.h" #include "nogc.h" // for malloc_fixed_code_for_jit() #include "encoder.h" -#include "vm_stats.h" #include "vm_arrays.h" +#include "compile.h" #ifdef PLATFORM_POSIX @@ -45,10 +45,8 @@ #endif #endif // PLATFORM_POSIX -#ifndef NDEBUG #include "dump.h" -extern bool dump_stubs; -#endif +#include "vm_stats.h" static uint64 vm_lshl(unsigned count, uint64 n) { @@ -91,17 +89,14 @@ #endif assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_lshl_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_lshl_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_lshl_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_lshl_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_lshl_naked", ss - stub); + return addr; } //getaddress__vm_lshl_naked @@ -146,16 +141,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_lshr_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_lshr_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_lshr_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_lshr_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_lshr_naked", ss - stub); + return addr; } //getaddress__vm_lshr_naked @@ -200,16 +192,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_lushr_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_lushr_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_lushr_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_lushr_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_lushr_naked", ss - stub); + return addr; } //getaddress__vm_lushr_naked @@ -336,16 +325,13 @@ void * getaddress__vm_const_lrem_naked() assert((ss - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("vm_const_lrem_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_const_lrem_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_const_lrem_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump( stub, "getaddress__vm_const_lrem_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_const_lrem_naked", ss - stub); + return addr; } //getaddress__vm_const_lrem_naked @@ -545,16 +531,13 @@ static void *getaddress__vm_const_ldiv_n assert((ss - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("vm_const_ldiv_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_const_ldiv_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_const_ldiv_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_const_ldiv_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_const_ldiv_naked", ss - stub); + return addr; } //getaddress__vm_ldiv_naked @@ -625,16 +608,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_d2i", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_d2i", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_d2i", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_d2i", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_d2i", ss - stub); + return addr; } //getaddress__vm_d2i @@ -683,16 +663,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_d2l", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_d2l", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_d2l", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_d2l", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_d2l", ss - stub); + return addr; } //getaddress__vm_d2l @@ -704,7 +681,7 @@ static int64 __stdcall vm_d2l(double d) assert(!hythread_is_suspend_enabled()); #ifdef VM_STATS - vm_stats_total.num_d2l++; + VM_Statistics::get_vm_stats().num_d2l++; #endif int64 result; @@ -808,16 +785,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_f2i", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_f2i", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_f2i", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_f2i", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_f2i", ss - stub); + return addr; } //getaddress__vm_f2i @@ -865,16 +839,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_f2l", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_f2l", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_f2l", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_f2l", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_f2l", ss - stub); + return addr; } //getaddress__vm_f2l @@ -886,7 +857,7 @@ static int64 __stdcall vm_f2l(float f) assert(!hythread_is_suspend_enabled()); #ifdef VM_STATS - vm_stats_total.num_f2l++; + VM_Statistics::get_vm_stats().num_f2l++; #endif int64 result; @@ -964,16 +935,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_frem", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_frem", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_frem", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_frem", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_frem", ss - stub); + return addr; } //getaddress__vm_frem @@ -1016,16 +984,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_drem", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_drem", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_drem", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_drem", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_drem", ss - stub); + return addr; } //getaddress__vm_drem @@ -1076,21 +1041,21 @@ static void vm_rt_char_arraycopy_no_exc( register uint16 *src_addr = get_vector_element_address_uint16(src, srcOffset); #ifdef VM_STATS - vm_stats_total.num_char_arraycopies++; + VM_Statistics::get_vm_stats().num_char_arraycopies++; if (dst_addr == src_addr) { - vm_stats_total.num_same_array_char_arraycopies++; + VM_Statistics::get_vm_stats().num_same_array_char_arraycopies++; } if (srcOffset == 0) { - vm_stats_total.num_zero_src_offset_char_arraycopies++; + VM_Statistics::get_vm_stats().num_zero_src_offset_char_arraycopies++; } if (dstOffset == 0) { - vm_stats_total.num_zero_dst_offset_char_arraycopies++; + VM_Statistics::get_vm_stats().num_zero_dst_offset_char_arraycopies++; } if ((((POINTER_SIZE_INT)dst_addr & 0x7) == 0) && (((POINTER_SIZE_INT)src_addr & 0x7) == 0)) { - vm_stats_total.num_aligned_char_arraycopies++; + VM_Statistics::get_vm_stats().num_aligned_char_arraycopies++; } - vm_stats_total.total_char_arraycopy_length += length; - vm_stats_total.char_arraycopy_count[get_log2(length)]++; + VM_Statistics::get_vm_stats().total_char_arraycopy_length += length; + VM_Statistics::get_vm_stats().char_arraycopy_count[get_log2(length)]++; #endif //VM_STATS // 20030219 The length threshold 32 here works well for SPECjbb and should be reasonable for other applications. diff --git vm/vmcore/src/util/ia32/base/jit_lock_rt_support_ia32.cpp vm/vmcore/src/util/ia32/base/jit_lock_rt_support_ia32.cpp index cbe689b..f146440 100644 --- vm/vmcore/src/util/ia32/base/jit_lock_rt_support_ia32.cpp +++ vm/vmcore/src/util/ia32/base/jit_lock_rt_support_ia32.cpp @@ -33,28 +33,27 @@ #include <assert.h> #include "vm_synch.h" #include "open/vm_util.h" #include "encoder.h" -#include "vm_stats.h" #include "nogc.h" #include "compile.h" -#include "exceptions.h" +#include "exceptions_jit.h" #include "lil.h" #include "lil_code_generator.h" #include "../m2n_ia32_internal.h" #include "object_handles.h" #include "Class.h" - -#ifdef VM_STATS #include "jit_runtime_support.h" -#endif -#ifndef NDEBUG #include "dump.h" -extern bool dump_stubs; -#endif +#include "vm_stats.h" + + +char * gen_convert_managed_to_unmanaged_null_ia32(char * ss, + unsigned stack_pointer_offset); + #define INPUT_ARG_OFFSET 4 -char *gen_setup_j2n_frame(char *s); -char *gen_pop_j2n_frame(char *s); +char * gen_setup_j2n_frame(char * s); +char * gen_pop_j2n_frame(char * s); @@ -89,7 +88,7 @@ static char * gen_restore_monitor_enter( signed offset; assert(header_offset); #ifdef VM_STATS - ss = inc(ss, M_Opnd((unsigned)&(vm_stats_total.num_monitor_enter))); + ss = inc(ss, M_Opnd((unsigned)&(VM_Statistics::get_vm_stats().num_monitor_enter))); #endif ss = mov(ss, ecx_opnd, M_Base_Opnd(esp_reg, INPUT_ARG_OFFSET)); @@ -146,10 +145,9 @@ #endif ss = gen_restore_monitor_enter(ss, /*patch_addr_null_arg*/ NULL); assert((ss - stub) < stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_enter_naked_mt", ss - stub); -#endif + + DUMP_STUB(stub, "getaddress__vm_monitor_enter_naked_mt", ss - stub); + return code_addr; } //restore__vm_monitor_enter_naked @@ -169,10 +167,9 @@ #endif ss = gen_restore_monitor_enter(ss, patch_addr_null_arg); assert((ss - stub) < stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_enter_static_naked_mt", ss - stub); -#endif + + DUMP_STUB(stub, "getaddress__vm_monitor_enter_static_naked_mt", ss - stub); + return code_addr; } //restore__vm_monitor_enter_static_naked @@ -182,7 +179,7 @@ static char * gen_restore_monitor_exit(c const unsigned header_offset = ManagedObject::header_offset(); #ifdef VM_STATS - ss = inc(ss, M_Opnd((unsigned)&(vm_stats_total.num_monitor_enter))); + ss = inc(ss, M_Opnd((unsigned)&(VM_Statistics::get_vm_stats().num_monitor_enter))); #endif ss = mov(ss, ecx_opnd, M_Base_Opnd(esp_reg, INPUT_ARG_OFFSET)); @@ -229,10 +226,9 @@ #endif ss = gen_restore_monitor_exit(ss, /*patch_addr_null_arg*/ NULL); assert((ss - stub) < stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_exit_naked_mt", ss - stub); -#endif + + DUMP_STUB(stub, "getaddress__vm_monitor_exit_naked_mt", ss - stub); + return code_addr; } //restore__vm_monitor_exit_naked @@ -252,10 +248,9 @@ #endif ss = gen_restore_monitor_exit(ss, patch_addr_null_arg); assert((ss - stub) < stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_exit_static_naked_mt", ss - stub); -#endif + + DUMP_STUB(stub, "getaddress__vm_monitor_exit_static_naked_mt", ss - stub); + return code_addr; } //restore__vm_monitor_exit_static_naked @@ -275,7 +270,7 @@ #endif char *ss = stub; #ifdef VM_STATS - int * value = vm_stats_total.rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER, 0, NULL); + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER, 0, NULL); ss = inc(ss, M_Opnd((unsigned)value)); #endif @@ -284,17 +279,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_monitor_enter_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_monitor_enter_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_monitor_enter_naked", stub, stub_size); - } + DUMP_STUB(stub, "getaddress__vm_monitor_enter_naked", ss - stub); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_enter_naked", ss - stub); -#endif return addr; } @@ -314,7 +305,7 @@ #endif char *ss = stub; #ifdef VM_STATS - int * value = vm_stats_total.rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER_STATIC, 0, NULL); + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_ENTER_STATIC, 0, NULL); ss = inc(ss, M_Opnd((unsigned)value)); #endif @@ -325,21 +316,19 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_monitor_enter_static_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_monitor_enter_static_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_monitor_enter_static_naked", stub, stub_size); - } - -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_enter_static_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_monitor_enter_static_naked", ss - stub); + return addr; } //getaddress__vm_monitor_enter_static_naked + + void * getaddress__vm_monitor_exit_naked() { static void *addr = NULL; @@ -352,26 +341,23 @@ void * getaddress__vm_monitor_exit_naked char *ss = stub; #ifdef VM_STATS - int * value = vm_stats_total.rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT, 0, NULL); + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT, 0, NULL); ss = inc(ss, M_Opnd((unsigned)value)); #endif - ss = (char *)gen_convert_managed_to_unmanaged_null_ia32((Emitter_Handle)ss, /*stack_pointer_offset*/ INPUT_ARG_OFFSET); + ss = gen_convert_managed_to_unmanaged_null_ia32((Emitter_Handle)ss, /*stack_pointer_offset*/ INPUT_ARG_OFFSET); ss = gen_restore_monitor_exit(ss, /*patch_addr_null_arg*/ NULL); addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_monitor_enter_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_monitor_enter_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_monitor_enter_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_exit_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_monitor_exit_naked", ss - stub); + return addr; } //getaddress__vm_monitor_exit_naked @@ -388,7 +374,7 @@ void * getaddress__vm_monitor_exit_stati char *ss = stub; #ifdef VM_STATS - int * value = vm_stats_total.rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT_STATIC, 0, NULL); + int * value = VM_Statistics::get_vm_stats().rt_function_calls.lookup_or_add((void*)VM_RT_MONITOR_EXIT_STATIC, 0, NULL); ss = inc(ss, M_Opnd((unsigned)value)); #endif @@ -399,16 +385,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_monitor_exit_static_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_monitor_exit_static_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_monitor_exit_static_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_monitor_exit_static_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_monitor_exit_static_naked", ss - stub); + return addr; } //getaddress__vm_monitor_exit_static_naked diff --git vm/vmcore/src/util/ia32/base/jit_runtime_support_ia32.cpp vm/vmcore/src/util/ia32/base/jit_runtime_support_ia32.cpp old mode 100644 new mode 100755 index 0a39fe1..243c72f --- vm/vmcore/src/util/ia32/base/jit_runtime_support_ia32.cpp +++ vm/vmcore/src/util/ia32/base/jit_runtime_support_ia32.cpp @@ -26,58 +26,46 @@ using namespace std; #include <assert.h> -#define LOG_DOMAIN "vm.helpers" -#include "cxxlog.h" - -#include "object_layout.h" #include "open/types.h" -#include "Class.h" -#include "environment.h" -#include "lil.h" -#include "lil_code_generator.h" -#include "method_lookup.h" -#include "exceptions.h" -#include "vm_synch.h" #include "open/gc.h" -#include "ini.h" -#include "nogc.h" -#include "encoder.h" #include "open/vm_util.h" +#include "environment.h" +#include "Class.h" +#include "object_layout.h" +#include "mon_enter_exit.h" +#include "vm_threads.h" + #include "open/thread_helpers.h" -#include "vm_threads.h" -#include "mon_enter_exit.h" #include "vm_arrays.h" +#include "vm_synch.h" #include "vm_strings.h" +#include "ini.h" +#include "nogc.h" #include "compile.h" - -#include "mon_enter_exit.h" - +#include "method_lookup.h" +#include "exceptions.h" +#include "exceptions_jit.h" #include "sync_bits.h" -#include "vm_stats.h" -#include "internal_jit_intf.h" +#include "encoder.h" +#include "lil.h" +#include "lil_code_generator.h" #include "jit_runtime_support_common.h" #include "jit_runtime_support.h" - +#include "internal_jit_intf.h" +#include "m2n.h" #include "../m2n_ia32_internal.h" -#include "open/vm_util.h" +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" -#ifndef NDEBUG #include "dump.h" -#endif -// TODO: remove from global name space -extern bool dump_stubs; - -// gets the offset of a certain field within a struct or class type -#define OFFSET(Struct, Field) \ - ((int) (&(((Struct *) NULL)->Field) - NULL)) +#include "vm_stats.h" -// gets the size of a field within a struct or class -#define SIZE(Struct, Field) \ - (sizeof(((Struct *) NULL)->Field)) +char * gen_convert_managed_to_unmanaged_null_ia32(char * ss, + unsigned stack_pointer_offset); void * get_generic_rt_support_addr_ia32(VM_RT_SUPPORT f); @@ -88,21 +76,22 @@ void * get_generic_rt_support_addr_ia32( static void vm_throw_java_lang_ClassCastException() { + ASSERT_THROW_AREA; assert(!hythread_is_suspend_enabled()); - throw_java_exception("java/lang/ClassCastException"); + exn_throw_by_name("java/lang/ClassCastException"); ABORT("The last called function should not return"); } //vm_throw_java_lang_ClassCastException #ifdef VM_STATS // exclude remark in release mode (defined but not used) static void update_checkcast_stats(ManagedObject *obj, Class *c) { - vm_stats_total.num_checkcast ++; + VM_Statistics::get_vm_stats().num_checkcast ++; if (obj == NULL) - vm_stats_total.num_checkcast_null ++; + VM_Statistics::get_vm_stats().num_checkcast_null ++; if (obj != NULL && obj->vt()->clss == c) - vm_stats_total.num_checkcast_equal_type ++; + VM_Statistics::get_vm_stats().num_checkcast_equal_type ++; if (obj != NULL && c->is_suitable_for_fast_instanceof) - vm_stats_total.num_checkcast_fast_decision ++; + VM_Statistics::get_vm_stats().num_checkcast_fast_decision ++; } //update_checkcast_stats #endif @@ -117,7 +106,10 @@ static void *getaddress__vm_checkcast_na } if (VM_Global_State::loader_env->use_lil_stubs) { LilCodeStub *cs = gen_lil_typecheck_stub(true); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_rt_checkcast", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "vm_rt_checkcast", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -174,16 +166,13 @@ #endif // VM_STATS addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_rt_checkcast", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_rt_checkcast", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_rt_checkcast", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_checkcast_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_checkcast_naked", ss - stub); + return addr; } //getaddress__vm_checkcast_naked @@ -204,7 +193,10 @@ static void *getaddress__vm_instanceof() { LilCodeStub *cs = gen_lil_typecheck_stub(false); assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_instanceof", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "vm_instanceof", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -218,7 +210,7 @@ static void *getaddress__vm_instanceof() static Boolean is_class_initialized(Class *clss) { #ifdef VM_STATS - vm_stats_total.num_is_class_initialized++; + VM_Statistics::get_vm_stats().num_is_class_initialized++; clss->num_class_init_checks++; #endif // VM_STATS assert(!hythread_is_suspend_enabled()); @@ -237,7 +229,8 @@ static void *getaddress__vm_initialize_c if (VM_Global_State::loader_env->use_lil_stubs) { LilCodeStub* cs = lil_parse_code_stub( "entry 0:managed:pint:void; // The single argument is a Class_Handle \n" - "in2out platform:pint; \ + "locals 3;\ + in2out platform:pint; \ call %0i; \ jc r=0,not_initialized; \ ret; \ @@ -246,19 +239,26 @@ static void *getaddress__vm_initialize_c in2out platform:void; \ call %2i; \ l1 = ts; \ - ld l1, [l1 + %3i:ref]; \ - jc l1 != 0,_exn_raised; \ + ld l2, [l1 + %3i:ref]; \ + jc l2 != 0,_exn_raised; \ + ld l2, [l1 + %4i:ref]; \ + jc l2 != 0,_exn_raised; \ pop_m2n; \ ret; \ :_exn_raised; \ out platform::void; \ - call.noret %4i;", + call.noret %5i;", (void *)is_class_initialized, FRAME_JNI, (void *)class_initialize, - OFFSET(VM_thread, p_exception_object), (void*)rethrow_current_thread_exception); + APR_OFFSETOF(VM_thread, thread_exception.exc_object), + APR_OFFSETOF(VM_thread, thread_exception.exc_class), + (void*)exn_rethrow); assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_initialize_class_naked", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "vm_initialize_class_naked", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -283,7 +283,7 @@ #endif *backpatch_address__class_not_initialized = (char)offset; ss = gen_setup_j2n_frame(ss); ss = push(ss, M_Base_Opnd(esp_reg, m2n_sizeof_m2n_frame)); - ss = call(ss, (char *)class_initialize); + ss = call(ss, (char *)vm_rt_class_initialize); ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); ss = gen_pop_j2n_frame(ss); ss = ret(ss, Imm_Opnd(4)); @@ -291,16 +291,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_initialize_class_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_initialize_class_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_initialize_class_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_initialize_class_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_initialize_class_naked", ss - stub); + return addr; } //getaddress__vm_initialize_class_naked @@ -310,75 +307,6 @@ #endif // Object allocation ////////////////////////////////////////////////////////////////////// -static void *getaddress__vm_alloc_java_object_resolved_naked() -{ - static void *addr = 0; - if (addr) { - return addr; - } - - if (VM_Global_State::loader_env->use_lil_stubs) { - LilCodeStub* cs = lil_parse_code_stub( - "entry 0:managed:pint:ref; // The one arg is a ClassHandle for the class of the object we want to create \n" - "in2out platform:ref; \ - call %0i; \ - jc r=0,fast_alloc_failed; \ - ret; \ - :fast_alloc_failed; \ - push_m2n 0, 0; \ - in2out platform:ref; \ - call %1i; \ - pop_m2n; \ - ret;", - (void *)class_alloc_new_object_or_null, - (void *)class_alloc_new_object); - assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_alloc_java_object_resolved_naked", dump_stubs); - lil_free_code_stub(cs); - return addr; - } - - const int stub_size = 44; - char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_MAX/2, CAA_Allocate); -#ifdef _DEBUG - memset(stub, 0xcc /*int 3*/, stub_size); -#endif - char *ss = stub; - ss = push(ss, M_Base_Opnd(esp_reg, 4)); - ss = call(ss, (char *)class_alloc_new_object_or_null); - ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); - ss = alu(ss, or_opc, eax_opnd, eax_opnd); - ss = branch8(ss, Condition_Z, Imm_Opnd(size_8, 0)); - char *backpatch_address__fast_alloc_failed = ((char *)ss) - 1; - ss = ret(ss, Imm_Opnd(4)); - - signed offset = (signed)ss - (signed)backpatch_address__fast_alloc_failed - 1; - *backpatch_address__fast_alloc_failed = (char)offset; - ss = gen_setup_j2n_frame(ss); - ss = push(ss, M_Base_Opnd(esp_reg, m2n_sizeof_m2n_frame)); - ss = call(ss, (char *)class_alloc_new_object); - ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); - ss = gen_pop_j2n_frame(ss); - ss = ret(ss, Imm_Opnd(4)); - - addr = stub; - assert((ss - stub) <= stub_size); - - if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_alloc_java_object_resolved_naked", stub, stub_size); - jvmti_send_dynamic_code_generated_event("vm_alloc_java_object_resolved_naked", stub, stub_size); - } - -#ifndef NDEBUG - if (dump_stubs) { - dump(stub, "getaddress__vm_alloc_java_object_resolved_naked", ss - stub); - } -#endif - return addr; -} //getaddress__vm_alloc_java_object_resolved_naked - - static void *generate_object_allocation_stub_with_thread_pointer(char *fast_obj_alloc_proc, char *slow_obj_alloc_proc, char *stub_name) @@ -445,16 +373,13 @@ #endif // !PLATFORM_POSIX assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("object_allocation_stub_with_thread_pointer", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("object_allocation_stub_with_thread_pointer", stub, stub_size); jvmti_send_dynamic_code_generated_event("object_allocation_stub_with_thread_pointer", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, stub_name, ss - stub); -#endif + DUMP_STUB(stub, stub_name, ss - stub); + return (void *)stub; } //generate_object_allocation_stub_with_thread_pointer @@ -493,10 +418,9 @@ #endif addr = stub; assert((ss - stub) <= stub_size); -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "vm_aastore_nullpointer", ss - stub); -#endif + + DUMP_STUB(stub, "vm_aastore_nullpointer", ss - stub); + return addr; } //vm_aastore_nullpointer @@ -521,16 +445,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_aastore_nullpointer", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_aastore_nullpointer", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_aastore_nullpointer", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub,"vm_aastore_array_index_out_of_bounds", ss - stub); -#endif + DUMP_STUB(stub, "vm_aastore_array_index_out_of_bounds", ss - stub); + return addr; } //vm_aastore_array_index_out_of_bounds @@ -557,16 +478,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_aastore_arraystore", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_aastore_arraystore", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_aastore_arraystore", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "vm_aastore_arraystore", ss - stub); -#endif + DUMP_STUB(stub, "vm_aastore_arraystore", ss - stub); + return addr; } //vm_aastore_arraystore @@ -596,7 +514,7 @@ aastore_ia32(volatile ManagedObject *ele assert ((elem == NULL) || (((ManagedObject *)elem)->vt() != NULL)); #ifdef VM_STATS - vm_stats_total.num_aastore++; + VM_Statistics::get_vm_stats().num_aastore++; #endif // VM_STATS void *new_eip = 0; if (array == NULL) { @@ -609,11 +527,11 @@ #endif // VM_STATS VTable *vt = get_vector_vtable(array); #ifdef VM_STATS if (vt == cached_object_array_vtable_ptr) - vm_stats_total.num_aastore_object_array ++; + VM_Statistics::get_vm_stats().num_aastore_object_array ++; if (vt->clss->array_element_class->vtable == ((ManagedObject *)elem)->vt()) - vm_stats_total.num_aastore_equal_type ++; + VM_Statistics::get_vm_stats().num_aastore_equal_type ++; if (vt->clss->array_element_class->is_suitable_for_fast_instanceof) - vm_stats_total.num_aastore_fast_decision ++; + VM_Statistics::get_vm_stats().num_aastore_fast_decision ++; #endif // VM_STATS if(vt == cached_object_array_vtable_ptr || class_is_subtype_fast(((ManagedObject *)elem)->vt(), vt->clss->array_element_class)) { @@ -625,7 +543,7 @@ #endif // VM_STATS // A null reference. No need to check types for a null reference. assert(elem == NULL); #ifdef VM_STATS - vm_stats_total.num_aastore_null ++; + VM_Statistics::get_vm_stats().num_aastore_null ++; #endif // VM_STATS // 20030502 Someone earlier commented out a call to the GC interface function gc_heap_slot_write_ref() and replaced it // by code to directly store a NULL in the element without notifying the GC. I've retained that change here but I wonder if @@ -670,7 +588,10 @@ static void *getaddress__vm_aastore() (void *)vm_rt_aastore, exn_get_rth_throw_lazy_trampoline()); assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_aastore", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "vm_aastore", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } //getaddress__vm_aastore @@ -712,45 +633,56 @@ #endif assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_new_vector_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_new_vector_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_new_vector_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, stub_name, ss - stub); -#endif + DUMP_STUB(stub, stub_name, ss - stub); + return stub; } //gen_new_vector_stub - -static void *getaddress__vm_new_vector_naked() -{ - static void *addr = 0; - if (addr) { - return addr; - } - - addr = gen_new_vector_stub("getaddress__vm_new_vector_naked", - (char *)vm_new_vector_or_null, (char *)vm_new_vector); - return addr; -} //getaddress__vm_new_vector_naked - - static void *getaddress__vm_new_vector_using_vtable_naked() { static void *addr = 0; if (addr) { return addr; } - addr = generate_object_allocation_stub_with_thread_pointer((char *)vm_new_vector_or_null_using_vtable_and_thread_pointer, - (char *)vm_new_vector_using_vtable_and_thread_pointer, + addr = generate_object_allocation_stub_with_thread_pointer( + (char *)vm_new_vector_or_null_using_vtable_and_thread_pointer, + (char *)vm_rt_new_vector_using_vtable_and_thread_pointer, "getaddress__vm_new_vector_using_vtable_naked"); return addr; } //getaddress__vm_new_vector_using_vtable_naked +// this is a helper routine for rth_get_lil_multianewarray(see jit_runtime_support.cpp). +Vector_Handle +vm_rt_multianewarray_recursive(Class *c, + int *dims_array, + unsigned dims); + +Vector_Handle rth_multianewarrayhelper() +{ + ASSERT_THROW_AREA; + M2nFrame* m2nf = m2n_get_last_frame(); + const unsigned max_dim = 255; + int lens[max_dim]; + +#ifdef VM_STATS + VM_Statistics::get_vm_stats().num_multianewarray++; +#endif + + POINTER_SIZE_INT* p_args = m2n_get_args(m2nf); + Class* c = (Class*)p_args[0]; + unsigned dims = p_args[1]; + assert(dims<=max_dim); + uint32* lens_base = (uint32*)(p_args+2); + for(unsigned i = 0; i < dims; i++) { + lens[i] = lens_base[dims-i-1]; + } + return vm_rt_multianewarray_recursive(c, lens, dims); +} // This is a __cdecl function and the caller must pop the arguments. static void *getaddress__vm_multianewarray_resolved_naked() @@ -796,16 +728,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_multinewarray_resolved_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_multinewarray_resolved_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_multinewarray_resolved_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_multianewarray_resolved_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_multianewarray_resolved_naked", ss - stub); + return addr; } //getaddress__vm_multianewarray_resolved_naked @@ -834,16 +763,13 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_instantiate_cp_string_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_instantiate_cp_string_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_instantiate_cp_string_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_instantiate_cp_string_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_instantiate_cp_string_naked", ss - stub); + return addr; } //getaddress__vm_instantiate_cp_string_naked @@ -851,7 +777,8 @@ #endif static void vm_throw_java_lang_IncompatibleClassChangeError() { - throw_java_exception("java/lang/IncompatibleClassChangeError"); + ASSERT_THROW_AREA; + exn_throw_by_name("java/lang/IncompatibleClassChangeError"); ABORT("The last called function should not return"); } //vm_throw_java_lang_IncompatibleClassChangeError @@ -909,24 +836,22 @@ #endif addr = stub; assert((ss - stub) <= stub_size); + compile_add_dynamic_generated_code_chunk("vm_get_interface_vtable_old_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_get_interface_vtable_old_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_get_interface_vtable_old_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_get_interface_vtable_old_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_get_interface_vtable_old_naked", ss - stub); + return addr; } //getaddress__vm_get_interface_vtable_old_naked static void vm_throw_java_lang_ArithmeticException() { + ASSERT_THROW_AREA; assert(!hythread_is_suspend_enabled()); - throw_java_exception("java/lang/ArithmeticException"); + exn_throw_by_name("java/lang/ArithmeticException"); ABORT("The last called function should not return"); } //vm_throw_java_lang_ArithmeticException @@ -953,16 +878,13 @@ #endif assert((ss - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("setup_java_to_native_frame", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("setup_java_to_native_frame", stub, stub_size); jvmti_send_dynamic_code_generated_event("setup_java_to_native_frame", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__setup_java_to_native_frame", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__setup_java_to_native_frame", ss - stub); + return addr; } //getaddress__setup_java_to_native_frame @@ -996,16 +918,13 @@ #endif assert((ss - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("pop_java_to_native_frame", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("pop_java_to_native_frame", stub, stub_size); jvmti_send_dynamic_code_generated_event("pop_java_to_native_frame", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__pop_java_to_native_frame", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__pop_java_to_native_frame", ss - stub); + return addr; } //getaddress__pop_java_to_native_frame @@ -1028,7 +947,7 @@ vm_throw_linking_exception(Class *clss, unsigned opcode) { TRACE("vm_throw_linking_exception, idx=" << cp_index << "\n"); - class_throw_linking_error(clss, cp_index, opcode); + vm_rt_class_throw_linking_error(clss, cp_index, opcode); ABORT("The last called function should not return"); } //vm_throw_linking_exception @@ -1056,16 +975,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("vm_throw_linking_exception_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_throw_linking_exception_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_throw_linking_exception_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_throw_linking_exception_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_throw_linking_exception_naked", ss - stub); + return addr; } //getaddress__vm_throw_linking_exception_naked @@ -1106,16 +1022,13 @@ #endif addr = stub; assert((ss - stub) < stub_size); + compile_add_dynamic_generated_code_chunk("gc_write_barrier_fastcall", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("gc_write_barrier_fastcall", stub, stub_size); jvmti_send_dynamic_code_generated_event("gc_write_barrier_fastcall", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__gc_write_barrier_fastcall", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__gc_write_barrier_fastcall", ss - stub); + return addr; } //getaddress__gc_write_barrier_fastcall @@ -1157,16 +1070,13 @@ #endif assert((ss - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("vm_lrem_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_lrem_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_lrem_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_lrem_naked", ss - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_lrem_naked", ss - stub); + return addr; } //getaddress__vm_lrem_naked @@ -1207,16 +1117,13 @@ #endif assert((s - stub) <= stub_size); addr = stub; + compile_add_dynamic_generated_code_chunk("vm_ldiv_naked", stub, stub_size); + if (VM_Global_State::loader_env->TI->isEnabled()) - { - jvmti_add_dynamic_generated_code_chunk("vm_ldiv_naked", stub, stub_size); jvmti_send_dynamic_code_generated_event("vm_ldiv_naked", stub, stub_size); - } -#ifndef NDEBUG - if (dump_stubs) - dump(stub, "getaddress__vm_ldiv_naked", s - stub); -#endif + DUMP_STUB(stub, "getaddress__vm_ldiv_naked", s - stub); + return addr; } //getaddress__vm_ldiv_naked @@ -1230,7 +1137,7 @@ #ifdef VM_STATS static void register_request_for_rt_function(VM_RT_SUPPORT f) { // Increment the number of times that f was requested by a JIT. This is not the number of calls to that function, // but this does tell us how often a call to that function is compiled into JITted code. - vm_stats_total.rt_function_requests.add((void *)f, /*value*/ 1, /*value1*/ NULL); + VM_Statistics::get_vm_stats().rt_function_requests.add((void *)f, /*value*/ 1, /*value1*/ NULL); } //register_request_for_rt_function #endif //VM_STATS @@ -1268,14 +1175,10 @@ #endif // VM_STATS return exn_get_rth_throw_lazy(); case VM_RT_LDC_STRING: return getaddress__vm_instantiate_cp_string_naked(); - case VM_RT_NEW_RESOLVED: - return getaddress__vm_alloc_java_object_resolved_naked(); case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: return getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked(); case VM_RT_MULTIANEWARRAY_RESOLVED: return getaddress__vm_multianewarray_resolved_naked(); - case VM_RT_NEW_VECTOR: - return getaddress__vm_new_vector_naked(); case VM_RT_NEW_VECTOR_USING_VTABLE: return getaddress__vm_new_vector_using_vtable_naked(); case VM_RT_AASTORE: @@ -1296,7 +1199,7 @@ #endif // VM_STATS return getaddress__vm_instanceof(); case VM_RT_MONITOR_ENTER: - case VM_RT_MONITOR_ENTER_NO_EXC: + case VM_RT_MONITOR_ENTER_NON_NULL: return getaddress__vm_monitor_enter_naked(); case VM_RT_MONITOR_ENTER_STATIC: @@ -1427,12 +1330,6 @@ void *vm_get_rt_support_addr_optimized(V case VM_RT_INSTANCEOF: return vm_get_rt_support_addr(f); // break;// remark #111: statement is unreachable - case VM_RT_NEW_RESOLVED: - if (class_is_finalizable(c)) - return getaddress__vm_alloc_java_object_resolved_naked(); - else - return vm_get_rt_support_addr(f); - // break;// remark #111: statement is unreachable case VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE: if (class_is_finalizable(c)) return getaddress__vm_alloc_java_object_resolved_using_vtable_and_size_naked(); diff --git vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp new file mode 100755 index 0000000..97a8260 --- /dev/null +++ vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "method_lookup.h" +#include "native_stack.h" + +void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp) +{ + *ip = (void*)regs->eip; + *bp = (void*)regs->ebp; + *sp = (void*)regs->esp; +} + +bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +{ + void** frame_ptr = (void**)frame; + + *ip = frame_ptr[1]; + *bp = frame_ptr[0]; + // FIXME - wrong value, we cannot get sp anyhow + *sp = (void*)((POINTER_SIZE_INT)frame + 2*sizeof(void*)); + + return (*bp != NULL && *ip != NULL); +} + +void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) +{ + JitFrameContext* jfc = si_get_jit_context(si); + *ip = (void*)*jfc->p_eip; + *bp = (void*)*jfc->p_ebp; +} + +void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) +{ + *sp = (void*)si_get_jit_context(si)->esp; +} + +bool native_is_out_of_stack(void* value) +{ + // FIXME: Invalid criterion + return (value < (void*)0x10000) || (value > (void*)0x80000000); +} + +bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +{ + // Check for frame layout and stack values + if ((bp < sp) || native_is_out_of_stack(bp)) + return false; // Invalid frame + + void** dw_ptr = (void**)bp; + void* ret_ip = *(dw_ptr + 1); // Return address for frame + + // Check return address for meaning + if (!native_is_ip_in_modules(modules, ret_ip) && !native_is_ip_stub(ret_ip)) + return false; + + return true; +} + +// Searches for correct return address in the stack +// Returns stack address pointing to return address +static void** native_search_special_frame(native_module_t* modules, void* sp) +{ +// Max search depth for return address +#define MAX_SPECIAL_DEPTH 0x40 + + POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)sp; + for (POINTER_SIZE_INT sp_int = sp_begin; + sp_int < sp_begin + MAX_SPECIAL_DEPTH; + sp_int +=2) // 2 is minimum stack item for ia32 + { + void** sp_pointer = (void**)sp_int; + + if (native_is_ip_in_modules(modules, *sp_pointer)) + return sp_pointer; + } + + return NULL; +} + +// Tests if stack contains non-BP-based frames on top +int native_test_unwind_special(native_module_t* modules, void* sp) +{ +#define MAX_SPECIAL_COUNT 16 + +#if (!defined PLATFORM_POSIX) + return -1; // Because we cannot identify executable code on Windows +#endif + + if (modules == NULL) + return false; + + int count = 0; + void** sp_pointer = (void**)sp; + + do + { + if (native_is_ip_stub(sp_pointer[-1])) + break; // We've found JNI stub + + // We've reached Java without native stub + if (vm_identify_eip(sp_pointer[-1]) == VM_TYPE_JAVA) + break; + + void** next_sp = native_search_special_frame(modules, sp_pointer); + + if (next_sp == NULL) + break; // We cannot unwind anymore + + if (count > 0 && // Check BP-frame for upper frames + sp_pointer[-2] >= sp_pointer && // Correct frame layout + sp_pointer[-2] == next_sp - 1 && // is BP saved correctly + next_sp[-1] >= next_sp + 1) // Correct next frame layout + { + break; + } + + sp_pointer = next_sp + 1; + + } while (++count <= MAX_SPECIAL_COUNT); + + return count; +} + +// Tries to unwind non-BP-based frame +bool native_unwind_special(native_module_t* modules, + void* stack, void** ip, void** sp, void** bp, bool is_last) +{ + if (modules == NULL) + { + *ip = NULL; + return false; + } + + void** found = NULL; + + POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)stack; + for (POINTER_SIZE_INT sp_int = sp_begin; + sp_int < sp_begin + MAX_SPECIAL_DEPTH; + sp_int +=2) // 2 is minimum stack item for ia32 + { + void** sp_pointer = (void**)sp_int; + + if (native_is_ip_in_modules(modules, *sp_pointer)) + { + found = sp_pointer; + break; + } + } + + if (!found) + { + *ip = NULL; + return false; + } + + *ip = *found; + *sp = found + 1; + + if (is_last && !native_is_ip_stub(*ip)) + *bp = found[-1]; + else + *bp = *sp; + + return true; +} diff --git vm/vmcore/src/util/ipf/base/compile_ipf.cpp vm/vmcore/src/util/ipf/base/compile_ipf.cpp index fc06ee0..385432b 100644 --- vm/vmcore/src/util/ipf/base/compile_ipf.cpp +++ vm/vmcore/src/util/ipf/base/compile_ipf.cpp @@ -73,15 +73,8 @@ #include "lil.h" #include "lil_code_generator.h" #include "stub_code_utils.h" -#ifndef NDEBUG #include "dump.h" -#endif - -extern bool dump_stubs; - -#ifdef VM_STATS #include "vm_stats.h" -#endif void emit_hashcode_override(Emitter_Handle eh, Method *method); void emit_arraycopy_override(Emitter_Handle eh, Method *method); @@ -95,26 +88,22 @@ void flush_hw_cache(Byte *addr, size_t l } } //flush_hw_cache -////////////////////////////////////////////////////////// -// begin utilities to convert between managed and unmanaged nulls +/* BEGIN UTILITIES TO CONVERT BETWEEN MANAGED AND UNMANAGED NULLS */ // Convert a reference in register "reg", if null, from a managed null (heap_base) to an unmanaged one (NULL/0). Uses SCRATCH_GENERAL_REG. -void gen_convert_managed_to_unmanaged_null_ipf(Emitter_Handle emitter, unsigned reg) -{ +void gen_convert_managed_to_unmanaged_null_ipf(Emitter_Handle emitter, unsigned reg) { assert(reg != SCRATCH_GENERAL_REG); assert(reg != SCRATCH_GENERAL_REG2); // because of the call to increment_stats_counter() if (VM_Global_State::loader_env->compress_references) { Merced_Code_Emitter *mce = (Merced_Code_Emitter *)emitter; #ifdef VM_STATS - increment_stats_counter(*mce, &vm_stats_total.num_convert_null_m2u); + increment_stats_counter(*mce, &VM_Statistics::get_vm_stats().num_convert_null_m2u); #endif gen_compare_to_managed_null(*mce, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, reg, SCRATCH_GENERAL_REG); mce->ipf_mov(reg, 0, SCRATCH_PRED_REG); } -} //gen_convert_managed_to_unmanaged_null_ipf - - +} // Convert a reference in "reg", if null, from an unmanaged null (NULL/0) to an managed one (heap_base). // If a null must be translated, will rewrite rewrite "reg". @@ -125,24 +114,20 @@ void gen_convert_unmanaged_to_managed_nu if (VM_Global_State::loader_env->compress_references) { Merced_Code_Emitter *mce = (Merced_Code_Emitter *)emitter; #ifdef VM_STATS - increment_stats_counter(*mce, &vm_stats_total.num_convert_null_u2m); + increment_stats_counter(*mce, &VM_Statistics::get_vm_stats().num_convert_null_u2m); #endif mce->ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, reg, 0); emit_mov_imm_compactor(*mce, reg, (uint64)Class::heap_base, SCRATCH_PRED_REG); } } //gen_convert_unmanaged_to_managed_null_ipf +/* END UTILITIES TO CONVERT BETWEEN MANAGED AND UNMANAGED NULLS */ -// end utilities to convert between managed and unmanaged nulls -////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////// -// begin Support for stub override code sequences +/* BEGIN SUPPORT FOR STUB OVERRIDE CODE SEQUENCES */ // Override for the RNI method java_lang_Class.newInstance(Java_java_lang_Class *clss). -static void emit_newinstance_override(Emitter_Handle eh, Method *method) -{ +static void emit_newinstance_override(Emitter_Handle eh, Method *method) { Merced_Code_Emitter *mce = (Merced_Code_Emitter *)eh; Merced_Code_Emitter &emitter = *mce; // Emit code to examine the argument class (a java_lang_Class instance) and allocate an instance using fast inline code @@ -223,10 +208,9 @@ static void emit_newinstance_override(Em emitter.ipf_st(int_mem_size_8, mem_st_none, mem_none, SCRATCH_GENERAL_REG, SCRATCH_GENERAL_REG4, SCRATCH_PRED_REG3); emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG3); } -} //emit_newinstance_override +} -static void emit_convertToByteArray_override(Emitter_Handle eh, Method *method) -{ +static void emit_convertToByteArray_override(Emitter_Handle eh, Method *method) { Merced_Code_Emitter *mce = (Merced_Code_Emitter *)eh; Merced_Code_Emitter &emitter = *mce; const int v0 = RETURN_VALUE_REG; @@ -315,8 +299,7 @@ static void emit_convertToByteArray_over emitter.set_target(target_fail); emitter.ipf_mov(v0, 0); emitter.ipf_br(br_cond, br_few, br_sptk, br_none, target_end); -} // emit_convertToByteArray_override - +} static unsigned default_override_size(Method *m) { @@ -337,31 +320,26 @@ Stub_Override_Entry *stub_override_entri int sizeof_stub_override_entries = sizeof(_stub_override_entries_base) / sizeof(_stub_override_entries_base[0]); +/* END SUPPORT FOR STUB OVERRIDE CODE SEQUENCES */ -// end Support for stub override code sequences -///////////////////////////////////////////////////////////////// -void compile_flush_generated_code_block(Byte* b, size_t sz) -{ +void compile_flush_generated_code_block(Byte* b, size_t sz) { flush_hw_cache(b, sz); } extern "C" void do_mf_asm(); -extern "C" void do_mf() -{ +extern "C" void do_mf() { do_mf_asm(); -} //do_mf +} -void compile_flush_generated_code() -{ +void compile_flush_generated_code() { sync_i_cache(); do_mf(); } // 20030711: This function might not be compressed references safe -static void protect_value_type(Class_Handle c, uint64* start, GcFrame* gc) -{ +static void protect_value_type(Class_Handle c, uint64* start, GcFrame* gc) { ABORT("It is supposed that the function is never called"); assert(!hythread_is_suspend_enabled()); unsigned num_fields = class_num_instance_fields_recursive(c); @@ -396,8 +374,7 @@ static void protect_value_type(Class_Han } } -void compile_protect_arguments(Method_Handle method, GcFrame* gc) -{ +void compile_protect_arguments(Method_Handle method, GcFrame* gc) { assert(!hythread_is_suspend_enabled()); Method_Signature_Handle msh = method_get_signature(method); unsigned num_args = method_args_get_number(msh); @@ -446,16 +423,9 @@ void compile_protect_arguments(Method_Ha ABORT("Unexpected data type"); } } - } -// end compile-me stubs -////////////////////////////////////////////////////////// - - - -void patch_code_with_threads_suspended(Byte *code_block, Byte *new_code, size_t size) -{ +void patch_code_with_threads_suspended(Byte *code_block, Byte *new_code, size_t size) { // Check that the code being modified is one or more complete bundles on IPF. assert((((size_t)code_block) % 16) == 0); // else did not start at a possible bundle address @@ -478,26 +448,18 @@ void patch_code_with_threads_suspended(B assert(original_inst0 == new_inst0); memcpy(code_block, new_code, size); -} //patch_code_with_threads_suspended +} -char *create_unboxer(Method *method) -{ - assert(0); - return 0; -} //create_unboxer +/* BEGIN COMPILE-ME STUBS */ -////////////////////////////////////////////////////////////////////////// -// Compile-Me Stubs +NativeCodePtr compile_jit_a_method(Method * method); -NativeCodePtr compile_jit_a_method(Method* method); - -static NativeCodePtr compile_get_compile_me_generic() -{ +static NativeCodePtr compile_get_compile_me_generic() { static NativeCodePtr addr = NULL; if (!addr) { - unsigned eoo = (unsigned)(POINTER_SIZE_INT)&((VM_thread*)NULL)->p_exception_object; NativeCodePtr (*p_jitter)(Method*) = compile_jit_a_method; + NativeCodePtr (*p_rethrow)(Method*) = exn_rethrow_if_pending; LilCodeStub* cs = lil_parse_code_stub( "entry 1:managed:arbitrary;" "push_m2n 0, %0i;" @@ -506,18 +468,22 @@ static NativeCodePtr compile_get_compile "o0=sp0;" "call %1i;" "pop_m2n;" - "tailcall r;", - FRAME_COMPILATION, p_jitter, eoo, rethrow_current_thread_exception); + "locals 1;" + "l0 = r;" + "call %2i;" + "tailcall l0;", + FRAME_COMPILATION, p_jitter, p_rethrow); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "compile_me_generic", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB(addr, "compile_me_generic", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } return addr; -} //compile_get_compile_me_generic - +} -NativeCodePtr compile_gen_compile_me(Method_Handle method) -{ +NativeCodePtr compile_gen_compile_me(Method_Handle method) { LilCodeStub * cs = lil_parse_code_stub( "entry 0:managed:arbitrary;" "std_places 1;" @@ -527,7 +493,7 @@ NativeCodePtr compile_gen_compile_me(Met assert(cs && lil_is_valid(cs)); - NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs, "", false); + NativeCodePtr addr = LilCodeGenerator::get_platform()->compile(cs); #ifndef NDEBUG static unsigned done = 0; // dump first 10 compileme stubs @@ -540,12 +506,12 @@ #ifndef NDEBUG buf = (char *)STD_MALLOC(sz); sprintf(buf, "compileme.%s.%s%s", c, m, d); assert(strlen(buf) < sz); - dump((char *)addr, buf, lil_cs_get_code_size(cs)); + DUMP_STUB(addr, buf, lil_cs_get_code_size(cs)); STD_FREE(buf); } #endif lil_free_code_stub(cs); return addr; -} //compile_gen_compile_me - +} +/* END COMPILE-ME STUBS */ diff --git vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp index 8529074..60a99f2 100644 --- vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp +++ vm/vmcore/src/util/ipf/base/exceptions_ipf.cpp @@ -53,6 +53,8 @@ #include "nogc.h" #include "exceptions.h" +void gen_convert_managed_to_unmanaged_null_ipf(Emitter_Handle emitter, + unsigned reg); extern "C" void vm_rt_athrow(volatile ManagedObject *exc_obj, uint64 *bsp_arg, diff --git vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp index f62fbcd..0537e73 100644 --- vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp +++ vm/vmcore/src/util/ipf/base/jit_runtime_support_ipf.cpp @@ -20,11 +20,14 @@ // -#include "platform.h" //MVM #include <iostream> +#ifdef PLATFORM_POSIX +#include <unistd.h> +#endif + using namespace std; #include <stdlib.h> @@ -33,66 +36,49 @@ #include <assert.h> #include <float.h> #include <math.h> -#define LOG_DOMAIN "vm.helpers" -#include "cxxlog.h" - -#include "object_layout.h" #include "open/types.h" -#include "Class.h" +#include "open/gc.h" +#include "open/vm_util.h" + +#include "platform.h" #include "environment.h" +#include "Class.h" +#include "object_generic.h" +#include "object_layout.h" +#include "mon_enter_exit.h" +#include "ini.h" +#include "nogc.h" +#include "compile.h" #include "method_lookup.h" -#include "m2n.h" -#include "../m2n_ipf_internal.h" #include "exceptions.h" -#include "vm_synch.h" -#include "open/gc.h" -#include "ini.h" -#include "open/vm_util.h" #include "vm_strings.h" +#include "vm_arrays.h" #include "vm_threads.h" +#include "vm_synch.h" +#include "port_malloc.h" +#include "jni_utils.h" // This is for readInternal override -#include "vm_stats.h" -#include "merced.h" -#include "Code_Emitter.h" -#include "stub_code_utils.h" -#include "vm_ipf.h" -#include "nogc.h" -#include "vm_arrays.h" #include "lil.h" #include "lil_code_generator.h" - #include "jit_runtime_support_common.h" #include "jit_runtime_support.h" -#include "mon_enter_exit.h" -#include "compile.h" -#include "object_generic.h" - - -#include "jni_utils.h" // This is for readInternal override - - -#ifdef DUMP_JIT -#include "dump_jit.h" -#include "disasm.h" -#endif // DUMP_JIT - -#ifdef PLATFORM_POSIX -#include <unistd.h> -#endif -#include "port_malloc.h" - - -// gets the offset of a certain field within a struct or class type -#define OFFSET(Struct, Field) \ - ((POINTER_SIZE_SINT) (&(((Struct *) NULL)->Field) - NULL)) - -// gets the size of a field within a struct or class -#define SIZE(Struct, Field) \ - (sizeof(((Struct *) NULL)->Field)) +#include "m2n.h" +#include "../m2n_ipf_internal.h" +#include "merced.h" +#include "Code_Emitter.h" +#include "stub_code_utils.h" +#include "vm_ipf.h" +#define LOG_DOMAIN "vm.helpers" +#include "cxxlog.h" +#include "dump.h" +#include "vm_stats.h" -extern bool dump_stubs; +void gen_convert_managed_to_unmanaged_null_ipf(Emitter_Handle emitter, + unsigned reg); +void gen_convert_unmanaged_to_managed_null_ipf(Emitter_Handle emitter, + unsigned reg); ///////// begin arithmetic helpers @@ -170,14 +156,38 @@ extern "C" ManagedObject *vm_rt_new_reso assert(!hythread_is_suspend_enabled()); assert(strcmp(c->name->bytes, "java/lang/Class")); #ifdef VM_STATS - vm_stats_total.num_class_alloc_new_object++; + VM_Statistics::get_vm_stats().num_class_alloc_new_object++; c->num_allocations++; c->num_bytes_allocated += get_instance_data_size(c); #endif //VM_STATS return (ManagedObject *)vm_malloc_with_thread_pointer(c->instance_data_size, c->allocation_handle, vm_get_gc_thread_local()); } //vm_rt_new_resolved +// this is a helper routine for rth_get_lil_multianewarray(see jit_runtime_support.cpp). +Vector_Handle +vm_rt_multianewarray_recursive(Class *c, + int *dims_array, + unsigned dims); +Vector_Handle rth_multianewarrayhelper() +{ + ASSERT_THROW_AREA; + M2nFrame* m2nf = m2n_get_last_frame(); + const unsigned max_dim = 255; + int lens[max_dim]; + +#ifdef VM_STATS + VM_Statistics::get_vm_stats().num_multianewarray++; +#endif + + Class* c = (Class*)*m2n_get_arg_word(m2nf, 0); + unsigned dims = (unsigned)(*m2n_get_arg_word(m2nf, 1) & 0xFFFFffff); + assert(dims <= max_dim); + for(unsigned i = 0; i < dims; i++) { + lens[dims-i-1] = (int)(*m2n_get_arg_word(m2nf, i+2) & 0xFFFFffff); + } + return vm_rt_multianewarray_recursive(c, lens, dims); +} static void *vm_rt_multianewarray_resolved(Class *arr_clss, int dims, @@ -398,7 +408,7 @@ #ifdef VM_STATS { int out0, save_pfs, save_b0, save_gp; const int num_in_args = 2, num_out_args = 3; - void (*p_vm_new_vector_update_stats)(Allocation_Handle vector_handle, POINTER_SIZE_INT length, void *tp); + void (*p_vm_new_vector_update_stats)(int length, Allocation_Handle vector_handle, void *tp); p_vm_new_vector_update_stats = vm_new_vector_update_stats; emit_alloc_for_single_call(emitter, num_in_args, num_out_args, (void **)p_vm_new_vector_update_stats, @@ -477,19 +487,7 @@ static void *generate_object_allocation_ sync_i_cache(); -#ifdef DUMP_JIT - if (dump_stubs) { - FILE *out = acquire_dump_jit_file(NULL); - fprintf(out, "Stub: %s (non-LIL)\n", stub_name); - if (!disasm_to_file((Byte *) addr, (unsigned) stub_size, out)) { - fprintf(out, "Error in disassembling stub\n"); - release_dump_jit_file(); - ASSERT(0, "Error in disassembling stub"); - } - fprintf(out, "End stub %s\n", stub_name); - release_dump_jit_file(); - } -#endif // DUMP_JIT + DUMP_STUB(addr, stub_name, stub_size); return addr; } //generate_object_allocation_with_thread_pointer_stub_compactor @@ -543,10 +541,13 @@ static void *get_vm_rt_new_resolved_usin } //get_vm_rt_new_resolved_using_vtable_address_and_size +// newarray/anewarray helper + // Create a new array (of either primitive or ref type) // Returns -1 if there is a negative size static Vector_Handle rth_newarrayhelper() { + ASSERT_THROW_AREA; M2nFrame* m2nf = m2n_get_last_frame(); int len = (int)(*m2n_get_arg_word(m2nf, 1) & 0xFFFFffff); if (len < 0) return (Vector_Handle)-1; @@ -554,11 +555,9 @@ static Vector_Handle rth_newarrayhelper( VTable *vector_vtable = ManagedObject::allocation_handle_to_vtable(vh); Class* c = vector_vtable->clss; - return vm_new_vector(c, len); + return vm_rt_new_vector(c, len); } - -// newarray/anewarray helper static void *get_vm_rt_new_vector__using_vtable_address() { static void *addr = 0; @@ -581,19 +580,22 @@ static void *get_vm_rt_new_vector__using rth_newarrayhelper, (POINTER_SIZE_INT)-1, lil_npc_to_fp(exn_get_rth_throw_negative_array_size())); assert(cs && lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "rth_newarrayhelper", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB( addr, "rth_newarrayhelper", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); } else { - Vector_Handle (*p_vm_new_vector_or_null_using_vtable_and_thread_pointer)(Allocation_Handle vector_handle, int length, void *tp); - Vector_Handle (*p_vm_new_vector_using_vtable_and_thread_pointer)(Allocation_Handle vector_handle, int length, void *tp); + Vector_Handle (*p_vm_new_vector_or_null_using_vtable_and_thread_pointer)(int length, Allocation_Handle vector_handle, void *tp); + Vector_Handle (*p_vm_rt_new_vector_using_vtable_and_thread_pointer)(int length, Allocation_Handle vector_handle, void *tp); p_vm_new_vector_or_null_using_vtable_and_thread_pointer = vm_new_vector_or_null_using_vtable_and_thread_pointer; - p_vm_new_vector_using_vtable_and_thread_pointer = vm_new_vector_using_vtable_and_thread_pointer; + p_vm_rt_new_vector_using_vtable_and_thread_pointer = vm_rt_new_vector_using_vtable_and_thread_pointer; addr = generate_object_allocation_with_thread_pointer_stub_compactor( (void **) p_vm_new_vector_or_null_using_vtable_and_thread_pointer, - (void **) p_vm_new_vector_using_vtable_and_thread_pointer, + (void **) p_vm_rt_new_vector_using_vtable_and_thread_pointer, "rt_new_vector_using_vtable", true, true); @@ -865,7 +867,10 @@ static void *get_vm_rt_checkcast_address if (VM_Global_State::loader_env->use_lil_stubs) { LilCodeStub *cs = gen_lil_typecheck_stub(true); assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_rt_checkcast", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB( addr, "vm_rt_checkcast", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -903,23 +908,11 @@ static void *get_vm_rt_checkcast_address addr = (void *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_MAX/2, CAA_Allocate); emitter.copy((char *)addr); -#ifdef DUMP_JIT - if (dump_stubs) { - FILE *out = acquire_dump_jit_file(NULL); - fprintf(out, "Stub: vm_rt_checkcast (non-LIL)\n"); - if (!disasm_to_file((Byte *) addr, (unsigned) stub_size, out)) { - fprintf(out, "Error in disassembling stub\n"); - release_dump_jit_file(); - ASSERT(0, "Error in disassembling stub"); - } - fprintf(out, "End stub vm_rt_checkcast\n"); - release_dump_jit_file(); - } -#endif // DUMP_JIT flush_hw_cache((Byte *)addr, stub_size); sync_i_cache(); + DUMP_STUB(addr, "vm_rt_checkcast", stub_size); return addr; } //get_vm_rt_checkcast_address_compactor @@ -935,7 +928,10 @@ static void *get_vm_rt_instanceof_addres if (VM_Global_State::loader_env->use_lil_stubs) { LilCodeStub *cs = gen_lil_typecheck_stub(false); assert(lil_is_valid(cs)); - addr = LilCodeGenerator::get_platform()->compile(cs, "vm_rt_instanceof", dump_stubs); + addr = LilCodeGenerator::get_platform()->compile(cs); + + DUMP_STUB( addr, "vm_rt_instanceof", lil_cs_get_code_size(cs)); + lil_free_code_stub(cs); return addr; } @@ -968,23 +964,11 @@ static void *get_vm_rt_instanceof_addres addr = (void *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_MAX/2, CAA_Allocate); emitter.copy((char *)addr); -#ifdef DUMP_JIT - if (dump_stubs) { - FILE *out = acquire_dump_jit_file(NULL); - fprintf(out, "Stub: vm_rt_instanceof (non-LIL)\n"); - if (!disasm_to_file((Byte *) addr, (unsigned) stub_size, out)) { - fprintf(out, "Error in disassembling stub\n"); - release_dump_jit_file(); - ASSERT(0, Error in disassembling stub); - } - fprintf(out, "End stub vm_rt_instanceof\n"); - release_dump_jit_file(); - } -#endif // DUMP_JIT flush_hw_cache((Byte *)addr, stub_size); sync_i_cache(); + DUMP_STUB(addr, "vm_rt_instanceof", stub_size); return addr; } //get_vm_rt_instanceof_address_compactor @@ -1102,7 +1086,7 @@ static void *get_vm_rt_initialize_class_ Class *dummy = NULL; #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_is_class_initialized); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_is_class_initialized); // Update the per-class counter. // reg0 = in0 + offset(num_class_init_checks) // reg1 = [reg0] @@ -1126,7 +1110,7 @@ #endif // VM_STATS unsigned out_arg0 = m2n_gen_push_m2n(&emitter, NULL, FRAME_JNI, false, 0, 0, 1); emitter.ipf_mov(out_arg0+0, IN_REG0); void (*p_class_initialize)(Class *clss); - p_class_initialize = class_initialize; + p_class_initialize = vm_rt_class_initialize; emit_call_with_gp(emitter, (void **)p_class_initialize); // pop m2n frame and return m2n_gen_pop_m2n(&emitter, false, MPR_None); @@ -1187,7 +1171,7 @@ static void gen_vm_rt_monitorenter_fast_ // We do not implement the IA32 lazy lock scheme that speeds up single-threaded applications since we want to optimize // IPF performance for the multithreaded applications that we expect to be typical of servers. #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_enter); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_enter); #endif // Set object_stack_key_addr_reg to the address of the object's stack key field. @@ -1196,11 +1180,11 @@ #endif if (check_null) { // Set SCRATCH_PRED_REG2 to 1 if the object reference is non-null. #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_enter_null_check); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_enter_null_check); #endif emitter.ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, IN_REG0, 0); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_enter_is_null, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_enter_is_null, SCRATCH_PRED_REG); #endif // ==== Instructions below are only executed if the object reference is non-null ==== @@ -1235,7 +1219,7 @@ #endif } #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_enter_fastcall, SCRATCH_PRED_REG3); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_enter_fastcall, SCRATCH_PRED_REG3); #endif enforce_calling_conventions(&emitter, SCRATCH_PRED_REG3); emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG3); @@ -1264,18 +1248,18 @@ static void gen_vm_rt_monitorexit_fast_p const int header_offset = ManagedObject::header_offset(); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit); #endif unsigned end_of_monitorexit_fast_path_target = 1; if (check_null) { // Branch around the rest of the code emitted by this procedure if the object reference is null. #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_null_check); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_null_check); #endif emitter.ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, IN_REG0, 0); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_is_null, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_is_null, SCRATCH_PRED_REG); #endif emitter.ipf_br(br_cond, br_few, br_sptk, br_none, end_of_monitorexit_fast_path_target, SCRATCH_PRED_REG); } @@ -1290,7 +1274,7 @@ #endif emitter.ipf_cmp(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, object_lock_info_reg, SCRATCH_GENERAL_REG2); emitter.ipf_st(int_mem_size_4, mem_st_rel, mem_none, SCRATCH_GENERAL_REG, 0, SCRATCH_PRED_REG); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_fastestcall, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_fastestcall, SCRATCH_PRED_REG); #endif emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG); @@ -1302,7 +1286,7 @@ #endif emitter.ipf_ld(int_mem_size_2, mem_ld_none, mem_none, SCRATCH_GENERAL_REG, object_stack_key_addr_reg); emitter.ipf_cmp(icmp_ne, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, thread_stack_key_reg, SCRATCH_GENERAL_REG); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_unowned_object, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_unowned_object, SCRATCH_PRED_REG); #endif emitter.ipf_br(br_cond, br_few, br_sptk, br_none, end_of_monitorexit_fast_path_target, SCRATCH_PRED_REG); @@ -1314,7 +1298,7 @@ #endif emitter.ipf_cmpi(icmp_eq, cmp_none, SCRATCH_PRED_REG, SCRATCH_PRED_REG2, 0, object_lock_info_reg); emitter.ipf_st(int_mem_size_2, mem_st_rel, mem_none, object_stack_key_addr_reg, 0, SCRATCH_PRED_REG); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_fastcall, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_fastcall, SCRATCH_PRED_REG); #endif emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG); @@ -1327,13 +1311,13 @@ #endif emitter.ipf_adds(object_recur_count_addr_reg, (header_offset + RECURSION_OFFSET), IN_REG0, SCRATCH_PRED_REG); emitter.ipf_st(int_mem_size_1, mem_st_rel, mem_none, object_recur_count_addr_reg, SCRATCH_GENERAL_REG, SCRATCH_PRED_REG); #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_decr_rec_count, SCRATCH_PRED_REG); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_decr_rec_count, SCRATCH_PRED_REG); #endif emitter.ipf_brret(br_many, br_sptk, br_none, BRANCH_RETURN_LINK_REG, SCRATCH_PRED_REG); // Slowest path. The contention bit is nonzero. Fall through to call vm_monitor_exit() to release the lock... #ifdef VM_STATS - increment_stats_counter(emitter, &vm_stats_total.num_monitor_exit_very_slow_path); + increment_stats_counter(emitter, &VM_Statistics::get_vm_stats().num_monitor_exit_very_slow_path); #endif // If the object reference is null or the current thread doesn't own the object, we branch to here. @@ -2272,28 +2256,28 @@ #define COUNT_MAX 128 uint16 *dst_addr = get_vector_element_address_uint16(dst, (int32)dstOffset); uint16 *src_addr = get_vector_element_address_uint16(src, (int32)srcOffset); - vm_stats_total.num_char_arraycopies++; + VM_Statistics::get_vm_stats().num_char_arraycopies++; if (dst_addr == src_addr) { - vm_stats_total.num_same_array_char_arraycopies++; + VM_Statistics::get_vm_stats().num_same_array_char_arraycopies++; } if (srcOffset == 0) { - vm_stats_total.num_zero_src_offset_char_arraycopies++; + VM_Statistics::get_vm_stats().num_zero_src_offset_char_arraycopies++; } if (dstOffset == 0) { - vm_stats_total.num_zero_dst_offset_char_arraycopies++; + VM_Statistics::get_vm_stats().num_zero_dst_offset_char_arraycopies++; } if ((((POINTER_SIZE_INT)dst_addr & 0x7) == 0) && (((POINTER_SIZE_INT)src_addr & 0x7) == 0)) { - vm_stats_total.num_aligned_char_arraycopies++; + VM_Statistics::get_vm_stats().num_aligned_char_arraycopies++; } - vm_stats_total.total_char_arraycopy_length += length; - vm_stats_total.char_arraycopy_count[get_log2((int)length)]++; + VM_Statistics::get_vm_stats().total_char_arraycopy_length += length; + VM_Statistics::get_vm_stats().char_arraycopy_count[get_log2((int)length)]++; bool both_aligned = (((POINTER_SIZE_INT)dst_addr & 0x7) == 0) && (((POINTER_SIZE_INT)src_addr & 0x7) == 0); if (both_aligned && (src != dst) && (length < 32)) { uint64 num_bytes_to_copy = 2*length; uint64 num_uint64_to_copy = num_bytes_to_copy/sizeof(uint64); - vm_stats_total.num_fast_char_arraycopies++; - vm_stats_total.total_fast_char_arraycopy_uint64_copies += num_uint64_to_copy; - vm_stats_total.char_arraycopy_uint64_copies[get_log2((int)num_uint64_to_copy)]++; + VM_Statistics::get_vm_stats().num_fast_char_arraycopies++; + VM_Statistics::get_vm_stats().total_fast_char_arraycopy_uint64_copies += num_uint64_to_copy; + VM_Statistics::get_vm_stats().char_arraycopy_uint64_copies[get_log2((int)num_uint64_to_copy)]++; } #endif // VM_STATS } @@ -2467,13 +2451,13 @@ #if _DEBUG if (print_helper_info) { int num_args; char *fn_name; - vm_stats_total.rt_function_map.lookup((void *)f, &num_args, (void **)&fn_name); + VM_Statistics::get_vm_stats().rt_function_map.lookup((void *)f, &num_args, (void **)&fn_name); printf("Calling helper %s, %d args\n", fn_name, num_args); } #endif // _DEBUG // Increment the number of times that f was called by a JIT. - vm_stats_total.rt_function_calls.add((void *)f, /*value*/ 1, /*value1*/ NULL); + VM_Statistics::get_vm_stats().rt_function_calls.add((void *)f, /*value*/ 1, /*value1*/ NULL); } //increment_helper_count @@ -2558,7 +2542,7 @@ void *emit_counting_wrapper_for_jit_help static void register_rt_support_addr_request(VM_RT_SUPPORT f) { // Increment the number of times that f was requested by a JIT. This is not the number of calls to that function, // but this does tell us how often a call to that function is compiled into JITted code. - vm_stats_total.rt_function_requests.add((void *)f, /*value*/ 1, /*value1*/ NULL); + VM_Statistics::get_vm_stats().rt_function_requests.add((void *)f, /*value*/ 1, /*value1*/ NULL); } //register_rt_support_addr_request #endif //VM_STATS @@ -2735,7 +2719,7 @@ #ifdef VM_STATS if (true) { int num_args = 0; char *helper_name = NULL; - bool found = vm_stats_total.rt_function_map.lookup((void *)f, &num_args, (void **)&helper_name); + bool found = VM_Statistics::get_vm_stats().rt_function_map.lookup((void *)f, &num_args, (void **)&helper_name); assert(found); // else changes were made to the enum VM_RT_SUPPORT in jit_runtime_support.h. void *wrapper = emit_counting_wrapper_for_jit_helper(f, helper, num_args, helper_name); diff --git vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp new file mode 100755 index 0000000..e05a954 --- /dev/null +++ vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "native_stack.h" + +void native_get_frame_info(Registers* regs, void** ip, void** ret, void** bp, void** sp) +{ + // TODO: implement copying +} + +bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +{ + return false; // Not implemented +} + +void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) +{ // Not implemented +} + +void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) +{ // Not implemented +} + +bool native_is_out_of_stack(void* value) +{ + return true; // Not implemented +} + +bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +{ + return false; // Not implemented +} + +int native_test_unwind_special(native_module_t* modules, void* sp) +{ + return false; // Not implemented +} + +bool native_unwind_special(native_module_t* modules, + void* stack, void** ip, void** sp, void** bp, bool is_last) +{ + return false; // Not implemented +} diff --git vm/vmcore/src/util/jarfile_support.cpp vm/vmcore/src/util/jarfile_support.cpp index 0c23572..7cd02e8 100644 --- vm/vmcore/src/util/jarfile_support.cpp +++ vm/vmcore/src/util/jarfile_support.cpp @@ -173,7 +173,7 @@ #endif lseek(fp, offsetCD, SEEK_SET); - buf = (unsigned char *)STD_ALLOCA(fsize - offsetCD); + buf = (unsigned char *)STD_MALLOC(fsize - offsetCD); fsize = read(fp, buf, fsize - offsetCD); off = 0; @@ -189,6 +189,7 @@ #endif m_entries.insert(make_pair(GetHashValue(je.m_fileName), je)); off += JAR_DIRECTORYENTRY_LEN + je.m_nameLength + je.m_extraLength; } + STD_FREE(buf); // read and parse manifest from archive m_manifest = new Manifest( this ); diff --git vm/vmcore/src/util/linux/include/platform.h vm/vmcore/src/util/linux/include/platform.h index 5ab5a50..7d12468 100644 --- vm/vmcore/src/util/linux/include/platform.h +++ vm/vmcore/src/util/linux/include/platform.h @@ -220,308 +220,8 @@ typedef struct event_wrapper { } event_wrapper; -typedef struct _FLOATING_SAVE_AREA { - DWORD ControlWord; - DWORD StatusWord; - DWORD TagWord; - DWORD ErrorOffset; - DWORD ErrorSelector; - DWORD DataOffset; - DWORD DataSelector; - BYTE RegisterArea[80]; - DWORD Cr0NpxState; -} FLOATING_SAVE_AREA; - -typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; - -#ifdef _IPF_ -typedef struct _CONTEXT { - - DWORD ContextFlags; - DWORD Fill1[3]; - - ULONGLONG DbI0; - ULONGLONG DbI1; - ULONGLONG DbI2; - ULONGLONG DbI3; - ULONGLONG DbI4; - ULONGLONG DbI5; - ULONGLONG DbI6; - ULONGLONG DbI7; - - ULONGLONG DbD0; - ULONGLONG DbD1; - ULONGLONG DbD2; - ULONGLONG DbD3; - ULONGLONG DbD4; - ULONGLONG DbD5; - ULONGLONG DbD6; - ULONGLONG DbD7; - - FLOAT128 FltS0; - FLOAT128 FltS1; - FLOAT128 FltS2; - FLOAT128 FltS3; - FLOAT128 FltT0; - FLOAT128 FltT1; - FLOAT128 FltT2; - FLOAT128 FltT3; - FLOAT128 FltT4; - FLOAT128 FltT5; - FLOAT128 FltT6; - FLOAT128 FltT7; - FLOAT128 FltT8; - FLOAT128 FltT9; - - FLOAT128 FltS4; - FLOAT128 FltS5; - FLOAT128 FltS6; - FLOAT128 FltS7; - FLOAT128 FltS8; - FLOAT128 FltS9; - FLOAT128 FltS10; - FLOAT128 FltS11; - FLOAT128 FltS12; - FLOAT128 FltS13; - FLOAT128 FltS14; - FLOAT128 FltS15; - FLOAT128 FltS16; - FLOAT128 FltS17; - FLOAT128 FltS18; - FLOAT128 FltS19; - - FLOAT128 FltF32; - FLOAT128 FltF33; - FLOAT128 FltF34; - FLOAT128 FltF35; - FLOAT128 FltF36; - FLOAT128 FltF37; - FLOAT128 FltF38; - FLOAT128 FltF39; - - FLOAT128 FltF40; - FLOAT128 FltF41; - FLOAT128 FltF42; - FLOAT128 FltF43; - FLOAT128 FltF44; - FLOAT128 FltF45; - FLOAT128 FltF46; - FLOAT128 FltF47; - FLOAT128 FltF48; - FLOAT128 FltF49; - - FLOAT128 FltF50; - FLOAT128 FltF51; - FLOAT128 FltF52; - FLOAT128 FltF53; - FLOAT128 FltF54; - FLOAT128 FltF55; - FLOAT128 FltF56; - FLOAT128 FltF57; - FLOAT128 FltF58; - FLOAT128 FltF59; - - FLOAT128 FltF60; - FLOAT128 FltF61; - FLOAT128 FltF62; - FLOAT128 FltF63; - FLOAT128 FltF64; - FLOAT128 FltF65; - FLOAT128 FltF66; - FLOAT128 FltF67; - FLOAT128 FltF68; - FLOAT128 FltF69; - - FLOAT128 FltF70; - FLOAT128 FltF71; - FLOAT128 FltF72; - FLOAT128 FltF73; - FLOAT128 FltF74; - FLOAT128 FltF75; - FLOAT128 FltF76; - FLOAT128 FltF77; - FLOAT128 FltF78; - FLOAT128 FltF79; - - FLOAT128 FltF80; - FLOAT128 FltF81; - FLOAT128 FltF82; - FLOAT128 FltF83; - FLOAT128 FltF84; - FLOAT128 FltF85; - FLOAT128 FltF86; - FLOAT128 FltF87; - FLOAT128 FltF88; - FLOAT128 FltF89; - - FLOAT128 FltF90; - FLOAT128 FltF91; - FLOAT128 FltF92; - FLOAT128 FltF93; - FLOAT128 FltF94; - FLOAT128 FltF95; - FLOAT128 FltF96; - FLOAT128 FltF97; - FLOAT128 FltF98; - FLOAT128 FltF99; - - FLOAT128 FltF100; - FLOAT128 FltF101; - FLOAT128 FltF102; - FLOAT128 FltF103; - FLOAT128 FltF104; - FLOAT128 FltF105; - FLOAT128 FltF106; - FLOAT128 FltF107; - FLOAT128 FltF108; - FLOAT128 FltF109; - - FLOAT128 FltF110; - FLOAT128 FltF111; - FLOAT128 FltF112; - FLOAT128 FltF113; - FLOAT128 FltF114; - FLOAT128 FltF115; - FLOAT128 FltF116; - FLOAT128 FltF117; - FLOAT128 FltF118; - FLOAT128 FltF119; - - FLOAT128 FltF120; - FLOAT128 FltF121; - FLOAT128 FltF122; - FLOAT128 FltF123; - FLOAT128 FltF124; - FLOAT128 FltF125; - FLOAT128 FltF126; - FLOAT128 FltF127; - - ULONGLONG StFPSR; - - ULONGLONG IntGp; - ULONGLONG IntT0; - ULONGLONG IntT1; - ULONGLONG IntS0; - ULONGLONG IntS1; - ULONGLONG IntS2; - ULONGLONG IntS3; - ULONGLONG IntV0; - ULONGLONG IntT2; - ULONGLONG IntT3; - ULONGLONG IntT4; - ULONGLONG IntSp; - ULONGLONG IntTeb; - ULONGLONG IntT5; - ULONGLONG IntT6; - ULONGLONG IntT7; - ULONGLONG IntT8; - ULONGLONG IntT9; - ULONGLONG IntT10; - ULONGLONG IntT11; - ULONGLONG IntT12; - ULONGLONG IntT13; - ULONGLONG IntT14; - ULONGLONG IntT15; - ULONGLONG IntT16; - ULONGLONG IntT17; - ULONGLONG IntT18; - ULONGLONG IntT19; - ULONGLONG IntT20; - ULONGLONG IntT21; - ULONGLONG IntT22; - - ULONGLONG IntNats; - - ULONGLONG Preds; - - ULONGLONG BrRp; - ULONGLONG BrS0; - ULONGLONG BrS1; - ULONGLONG BrS2; - ULONGLONG BrS3; - ULONGLONG BrS4; - ULONGLONG BrT0; - ULONGLONG BrT1; - - ULONGLONG ApUNAT; - ULONGLONG ApLC; - ULONGLONG ApEC; - ULONGLONG ApCCV; - ULONGLONG ApDCR; - - - ULONGLONG RsPFS; - ULONGLONG RsBSP; - ULONGLONG RsBSPSTORE; - ULONGLONG RsRSC; - ULONGLONG RsRNAT; - - ULONGLONG StIPSR; - ULONGLONG StIIP; - ULONGLONG StIFS; - - ULONGLONG StFCR; - ULONGLONG Eflag; - ULONGLONG SegCSD; - ULONGLONG SegSSD; - ULONGLONG Cflag; - ULONGLONG StFSR; - ULONGLONG StFIR; - ULONGLONG StFDR; - - ULONGLONG UNUSEDPACK; - -} CONTEXT; -#else -typedef struct _CONTEXT { - - DWORD ContextFlags; - - DWORD Dr0; - DWORD Dr1; - DWORD Dr2; - DWORD Dr3; - DWORD Dr6; - DWORD Dr7; - - FLOATING_SAVE_AREA FloatSave; - - DWORD SegGs; - DWORD SegFs; - DWORD SegEs; - DWORD SegDs; - - DWORD Edi; - DWORD Esi; - DWORD Ebx; - DWORD Edx; - DWORD Ecx; - DWORD Eax; - - DWORD Ebp; - DWORD Eip; - DWORD SegCs; - DWORD EFlags; - DWORD Esp; - DWORD SegSs; - -} CONTEXT; -#endif // _IPF_ - - -typedef CONTEXT *PCONTEXT; - -#define CONTEXT_CONTROL 1 -#define CONTEXT_FLOATING_POINT 2 -#define CONTEXT_INTEGER 3 #define THREAD_PRIORITY_NORMAL 4 -/* - -BOOL GetThreadContext(VmThreadHandle hthread, const CONTEXT *lpcontext); -BOOL SetThreadContext(VmThreadHandle hh, const CONTEXT *cc); -BOOL SetThreadPriority(VmThreadHandle hh, int pp); -*/ #define _MAX_PATH PATH_MAX struct _finddata_t { @@ -543,8 +243,6 @@ __int64 _lseeki64(int, int64, int); void * _alloca(int); -__uint64 GetTickCount(); - typedef void * FARPROC; /*inline void vm_terminate_thread(VmThreadHandle thrdaddr) { diff --git vm/vmcore/src/util/linux/native_modules.cpp vm/vmcore/src/util/linux/native_modules.cpp new file mode 100755 index 0000000..8f9aa09 --- /dev/null +++ vm/vmcore/src/util/linux/native_modules.cpp @@ -0,0 +1,115 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Petr Ivanov, Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "open/types.h" +#include "port_malloc.h" +#include "native_modules.h" + + +void clear_native_modules(native_module_t** list_ptr) +{ + native_module_t* cur = *list_ptr; + + while (cur) + { + native_module_t* next = cur->next; + + if (cur->filename) + STD_FREE(cur->filename); + + STD_FREE(cur); + cur = next; + } + + *list_ptr = NULL; +} + +void native_clear_raw_list(raw_module* list) +{ + if (list->name) + STD_FREE(list->name); + + raw_module* cur = list->next; + + while (cur) + { + raw_module* next = cur->next; + STD_FREE(cur); + cur = next; + } +} + +raw_module* native_add_raw_segment(raw_module* last, + void* start, void* end, + char acc_r, char acc_x) +{ + if (last->next == NULL) + { + last->next = (raw_module*)STD_MALLOC(sizeof(raw_module)); + if (last->next == NULL) + return NULL; + + last->next->name = NULL; + last->next->next = NULL; + } + + last = last->next; + + last->start = start; + last->end = end; + last->acc_r = (acc_r == 'r'); + last->acc_x = (acc_x == 'x'); + + return last; +} + +native_module_t* native_fill_module(raw_module* rawModule, size_t count) +{ + native_module_t* module = + (native_module_t*)STD_MALLOC(sizeof(native_module_t) + sizeof(native_segment_t)*(count - 1)); + + if (module == NULL) + return NULL; + + module->seg_count = count; + module->filename = rawModule->name; + rawModule->name = NULL; + module->next = NULL; + + for (size_t i = 0; i < count; i++) + { + if (rawModule->acc_x) + module->segments[i].type = SEGMENT_TYPE_CODE; + else if (rawModule->acc_r) + module->segments[i].type = SEGMENT_TYPE_DATA; + else + module->segments[i].type = SEGMENT_TYPE_UNKNOWN; + + module->segments[i].base = rawModule->start; + module->segments[i].size = + (size_t)((POINTER_SIZE_INT)rawModule->end - + (POINTER_SIZE_INT)rawModule->start); + + rawModule = rawModule->next; + } + + return module; +} + diff --git vm/vmcore/src/util/linux/native_modules_em64t.cpp vm/vmcore/src/util/linux/native_modules_em64t.cpp new file mode 100755 index 0000000..9ed269b --- /dev/null +++ vm/vmcore/src/util/linux/native_modules_em64t.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Petr Ivanov, Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include <stdio.h> +#include <memory.h> +#include <sys/types.h> +#include <unistd.h> +#include "platform.h" +#include "open/types.h" +#include "port_malloc.h" +#include "native_modules.h" + +bool get_all_native_modules(native_module_t** list_ptr, int* count_ptr) +{ + char buf[_MAX_PATH]; + + if (list_ptr == NULL || count_ptr == NULL) + return false; + + pid_t pid = getpid(); + sprintf(buf, "/proc/%d/maps", pid); + + FILE* file = fopen(buf, "rt"); + if (!file) + return false; + + POINTER_SIZE_INT start, end; + char acc_r, acc_x; + char filename[_MAX_PATH]; + raw_module module; // First raw module + raw_module* lastseg = &module; // Address of last filled segment + size_t segment_count = 0; + int module_count = 0; + native_module_t** cur_next_ptr = list_ptr; + module.name = NULL; + module.next = NULL; + *list_ptr = NULL; + + while (!feof(file) && (fgets(buf, sizeof(buf), file))) + { + int res = sscanf(buf, "%" PI_FMT "x-%" PI_FMT "x %c%*c%c%*c %*" PI_FMT "x %*02x:%*02x %*u %s", + &start, &end, &acc_r, &acc_x, filename); + + if (res < 5) + continue; + + if (module.name == NULL || // First module, first record + strcmp(module.name, filename) != 0) // Next module + { + if (segment_count) // Add previous module + { + native_module_t* filled = + native_fill_module(&module, segment_count); + + if (!filled) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + *cur_next_ptr = filled; + cur_next_ptr = &filled->next; + } + + module.name = (char*)STD_MALLOC(strlen(filename) + 1); + if (module.name == NULL) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + strcpy(module.name, filename); + + // Store new module information + module.start = (void*)start; + module.end = (void*)end; + module.acc_r = (acc_r == 'r'); + module.acc_x = (acc_x == 'x'); + module.next = NULL; + ++module_count; + + lastseg = &module; + segment_count = 1; + } + else + { + lastseg = native_add_raw_segment(lastseg, + (void*)start, (void*)end, acc_r, acc_x); + + if (lastseg == NULL) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + ++segment_count; + } + } + + if (segment_count) // To process the last module + { + native_module_t* filled = native_fill_module(&module, segment_count); + + if (!filled) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + *cur_next_ptr = filled; + } + + native_clear_raw_list(&module); + fclose(file); + + *count_ptr = module_count; + return true; +} diff --git vm/vmcore/src/util/linux/native_modules_ia32.cpp vm/vmcore/src/util/linux/native_modules_ia32.cpp new file mode 100755 index 0000000..da5ee57 --- /dev/null +++ vm/vmcore/src/util/linux/native_modules_ia32.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Petr Ivanov, Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include <stdio.h> +#include <memory.h> +#include <sys/types.h> +#include <unistd.h> +#include "platform.h" +#include "open/types.h" +#include "port_malloc.h" +#include "native_modules.h" + +bool get_all_native_modules(native_module_t** list_ptr, int* count_ptr) +{ + char buf[_MAX_PATH]; + + if (list_ptr == NULL || count_ptr == NULL) + return false; + + pid_t pid = getpid(); + sprintf(buf, "/proc/%d/maps", pid); + + FILE* file = fopen(buf, "rt"); + if (!file) + return false; + + POINTER_SIZE_INT start, end; + char acc_r, acc_x; + char filename[_MAX_PATH]; + raw_module module; // First raw module + raw_module* lastseg = &module; // Address of last filled segment + size_t segment_count = 0; + int module_count = 0; + native_module_t** cur_next_ptr = list_ptr; + module.name = NULL; + module.next = NULL; + *list_ptr = NULL; + + while (!feof(file) && (fgets(buf, sizeof(buf), file))) + { + int res = sscanf(buf, "%08x-%08x %c%*c%c%*c %*08x %*02x:%*02x %*u %s", + &start, &end, &acc_r, &acc_x, filename); + + if (res < 5) + continue; + + if (module.name == NULL || // First module, first record + strcmp(module.name, filename) != 0) // Next module + { + if (segment_count) // Add previous module + { + native_module_t* filled = + native_fill_module(&module, segment_count); + + if (!filled) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + *cur_next_ptr = filled; + cur_next_ptr = &filled->next; + } + + module.name = (char*)STD_MALLOC(strlen(filename) + 1); + if (module.name == NULL) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + strcpy(module.name, filename); + + // Store new module information + module.start = (void*)start; + module.end = (void*)end; + module.acc_r = (acc_r == 'r'); + module.acc_x = (acc_x == 'x'); + module.next = NULL; + ++module_count; + + lastseg = &module; + segment_count = 1; + } + else + { + lastseg = native_add_raw_segment(lastseg, + (void*)start, (void*)end, acc_r, acc_x); + + if (lastseg == NULL) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + ++segment_count; + } + } + + if (segment_count) // To process the last module + { + native_module_t* filled = native_fill_module(&module, segment_count); + + if (!filled) + { + native_clear_raw_list(&module); + clear_native_modules(list_ptr); + fclose(file); + return false; + } + + *cur_next_ptr = filled; + } + + native_clear_raw_list(&module); + fclose(file); + + *count_ptr = module_count; + return true; +} diff --git vm/vmcore/src/util/linux/native_modules_ipf.cpp vm/vmcore/src/util/linux/native_modules_ipf.cpp new file mode 100755 index 0000000..5facd58 --- /dev/null +++ vm/vmcore/src/util/linux/native_modules_ipf.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Petr Ivanov, Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "native_modules.h" + +bool get_all_native_modules(native_module_t** list_ptr, int* count_ptr) +{ + return false; // Not implemented +} diff --git vm/vmcore/src/util/linux/signals_em64t.cpp vm/vmcore/src/util/linux/signals_em64t.cpp old mode 100644 new mode 100755 index 5818edf..2f26eed --- vm/vmcore/src/util/linux/signals_em64t.cpp +++ vm/vmcore/src/util/linux/signals_em64t.cpp @@ -39,7 +39,7 @@ #include <errno.h> #include <sys/ucontext.h> #include <sys/wait.h> - +#include <sys/mman.h> #undef __USE_XOPEN #include <signal.h> @@ -54,6 +54,7 @@ #include "environment.h" #include "open/gc.h" #include "exceptions.h" +#include "exceptions_jit.h" #include "vm_synch.h" #include "vm_threads.h" #include "open/vm_util.h" @@ -76,7 +77,7 @@ static uint64 exam_point; bool SuspendThread(unsigned xx){ return 0; } bool ResumeThread(unsigned xx){ return 1; } -static void linux_sigcontext_to_regs(Registers* regs, ucontext_t *uc) +void linux_ucontext_to_regs(Registers* regs, ucontext_t *uc) { regs->rax = uc->uc_mcontext.gregs[REG_RAX]; regs->rcx = uc->uc_mcontext.gregs[REG_RCX]; @@ -89,7 +90,7 @@ static void linux_sigcontext_to_regs(Reg regs->rsp = uc->uc_mcontext.gregs[REG_RSP]; } -static void linux_regs_to_sigcontext(ucontext_t *uc, Registers* regs) +void linux_regs_to_ucontext(ucontext_t *uc, Registers* regs) { uc->uc_mcontext.gregs[REG_RAX] = regs->rax; uc->uc_mcontext.gregs[REG_RCX] = regs->rcx; @@ -102,6 +103,30 @@ static void linux_regs_to_sigcontext(uco uc->uc_mcontext.gregs[REG_RSP] = regs->rsp; } +static void throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) +{ + Registers regs; + linux_ucontext_to_regs(®s, uc); + + DebugUtilsTI* ti = VM_Global_State::loader_env->TI; + + exn_athrow_regs(®s, exc_clss); + linux_regs_to_ucontext(uc, ®s); +} + +static bool java_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) +{ + ASSERT_NO_INTERPRETER; + unsigned *rip = (unsigned *) uc->uc_mcontext.gregs[REG_RIP]; + VM_Code_Type vmct = vm_identify_eip((void *)rip); + if(vmct != VM_TYPE_JAVA) { + return false; + } + + throw_from_sigcontext(uc, exc_clss); + return true; +} + static bool linux_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) { ASSERT_NO_INTERPRETER; @@ -112,11 +137,11 @@ static bool linux_throw_from_sigcontext( } Registers regs; - linux_sigcontext_to_regs(®s, uc); + linux_ucontext_to_regs(®s, uc); exn_athrow_regs(®s, exc_clss); - linux_regs_to_sigcontext(uc, ®s); + linux_regs_to_ucontext(uc, ®s); return true; } @@ -185,6 +210,146 @@ void print_native_stack (unsigned *rbp) addr2line(buf); } +/* + * Information about stack + */ +inline void* find_stack_addr() { + int err; + void* stack_addr; + pthread_attr_t pthread_attr; + + pthread_t thread = pthread_self(); + err = pthread_getattr_np(thread, &pthread_attr); + err = pthread_attr_getstackaddr(&pthread_attr, &stack_addr); + pthread_attr_destroy(&pthread_attr); + return stack_addr; +} + +inline size_t find_stack_size() { + int err; + size_t stack_size; + pthread_attr_t pthread_attr; + + pthread_attr_init(&pthread_attr); + err = pthread_attr_getstacksize(&pthread_attr, &stack_size); + pthread_attr_destroy(&pthread_attr); + return stack_size; +} + +inline size_t find_guard_stack_size() { + return 64*1024; +} + +inline size_t find_guard_page_size() { + int err; + size_t guard_size; + pthread_attr_t pthread_attr; + + pthread_attr_init(&pthread_attr); + err = pthread_attr_getguardsize(&pthread_attr, &guard_size); + pthread_attr_destroy(&pthread_attr); + return guard_size; +} + +static size_t common_stack_size; +static size_t common_guard_stack_size; +static size_t common_guard_page_size; + +inline void* get_stack_addr() { + return p_TLS_vmthread->stack_addr; +} + +inline size_t get_stack_size() { + return common_stack_size; +} + +inline size_t get_guard_stack_size() { + return common_guard_stack_size; +} + +inline size_t get_guard_page_size() { + return common_guard_page_size; +} + +void set_guard_stack(); + +void init_stack_info() { + p_TLS_vmthread->stack_addr = find_stack_addr(); + common_stack_size = find_stack_size(); + common_guard_stack_size = find_guard_stack_size(); + common_guard_page_size =find_guard_page_size(); + + set_guard_stack(); +} + +void set_guard_stack() { + int err; + char* stack_addr = (char*) get_stack_addr(); + size_t stack_size = get_stack_size(); + size_t guard_stack_size = get_guard_stack_size(); + size_t guard_page_size = get_guard_page_size(); + + err = mprotect(stack_addr - stack_size + guard_page_size + guard_stack_size, + guard_page_size, PROT_NONE); + + stack_t sigalt; + sigalt.ss_sp = stack_addr - stack_size + guard_page_size; + sigalt.ss_flags = SS_ONSTACK; + sigalt.ss_size = guard_stack_size; + + err = sigaltstack (&sigalt, NULL); +} + +size_t get_available_stack_size() { + char* stack_adrr = (char*) get_stack_addr(); + size_t used_stack_size = stack_adrr - ((char*)&stack_adrr); + size_t available_stack_size = + get_stack_size() - used_stack_size + - get_guard_page_size() - get_guard_stack_size(); + return available_stack_size; +} + +bool check_available_stack_size(size_t required_size) { + if (get_available_stack_size() < required_size) { + exn_raise_by_name("java/lang/StackOverflowError"); + return false; + } else { + return true; + } +} + +void remove_guard_stack() { + int err; + char* stack_addr = (char*) get_stack_addr(); + size_t stack_size = get_stack_size(); + size_t guard_stack_size = get_guard_stack_size(); + size_t guard_page_size = get_guard_page_size(); + + err = mprotect(stack_addr - stack_size + guard_page_size + guard_stack_size, + guard_page_size, PROT_READ | PROT_WRITE); + + stack_t sigalt; + sigalt.ss_sp = stack_addr - stack_size + guard_page_size; + sigalt.ss_flags = SS_DISABLE; + sigalt.ss_size = guard_stack_size; + + err = sigaltstack (&sigalt, NULL); +} + +bool check_stack_overflow(siginfo_t *info, ucontext_t *uc) { + char* stack_addr = (char*) get_stack_addr(); + size_t stack_size = get_stack_size(); + size_t guard_stack_size = get_guard_stack_size(); + size_t guard_page_size = get_guard_page_size(); + + char* guard_page_begin = stack_addr - stack_size + guard_page_size + guard_stack_size; + char* guard_page_end = guard_page_begin + guard_page_size; + char* fault_addr = (char*)(info->si_addr); + //char* esp_value = (char*)(uc->uc_mcontext.gregs[REG_ESP]); + + return((guard_page_begin <= fault_addr) && (fault_addr < guard_page_end)); +} + /* * We find the true signal stack frame set-up by kernel,which is located @@ -192,12 +357,40 @@ void print_native_stack (unsigned *rbp) * exception handling semantics, so that when the signal handler is * returned, application can continue its execution in Java exception handler. */ +void stack_overflow_handler(int signum, siginfo_t* UNREF info, void* context) +{ + ucontext_t *uc = (ucontext_t *)context; + Global_Env *env = VM_Global_State::loader_env; + + if (java_throw_from_sigcontext( + uc, env->java_lang_StackOverflowError_Class)) { + return; + } else { + if (is_unwindable()) { + if (hythread_is_suspend_enabled()) { + tmn_suspend_disable(); + } + throw_from_sigcontext( + uc, env->java_lang_StackOverflowError_Class); + } else { + remove_guard_stack(); + exn_raise_by_name("java/lang/StackOverflowError"); + p_TLS_vmthread->restore_guard_page = true; + } + } +} + void null_java_reference_handler(int signum, siginfo_t* info, void* context) { ucontext_t *uc = (ucontext_t *)context; Global_Env *env = VM_Global_State::loader_env; + if (check_stack_overflow(info, uc)) { + stack_overflow_handler(signum, info, context); + return; + } + if (env->shutting_down != 0) { fprintf(stderr, "null_java_reference_handler(): called in shutdown stage\n"); } else if (!interpreter_enabled()) { @@ -295,7 +488,7 @@ not be used when gcc compiles it; and as in our experiments. */ -volatile void locate_sigcontext(int signum) +void locate_sigcontext(int signum) { sigcontext *sc, *found_sc; uint64 *rbp; @@ -383,7 +576,7 @@ void initialize_signals() sigaction(SIGUSR2, &sa, NULL); */ sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK;; sa.sa_sigaction = &null_java_reference_handler; sigaction(SIGSEGV, &sa, NULL); diff --git vm/vmcore/src/util/linux/signals_ia32.cpp vm/vmcore/src/util/linux/signals_ia32.cpp index b098a33..37d40cd 100644 --- vm/vmcore/src/util/linux/signals_ia32.cpp +++ vm/vmcore/src/util/linux/signals_ia32.cpp @@ -55,6 +55,7 @@ #include "environment.h" #include "open/gc.h" #include "exceptions.h" +#include "exceptions_jit.h" #include "vm_synch.h" #include "vm_threads.h" #include "open/vm_util.h" @@ -69,12 +70,13 @@ #include "thread_manager.h" #include "exception_filter.h" #include "interpreter.h" #include "crash_handler.h" +#include "stack_dump.h" // Variables used to locate the context from the signal handler static int sc_nest = -1; static uint32 exam_point; -static void linux_sigcontext_to_regs(Registers* regs, ucontext_t *uc) +void linux_ucontext_to_regs(Registers* regs, ucontext_t *uc) { regs->eax = uc->uc_mcontext.gregs[REG_EAX]; regs->ecx = uc->uc_mcontext.gregs[REG_ECX]; @@ -87,7 +89,7 @@ static void linux_sigcontext_to_regs(Reg regs->esp = uc->uc_mcontext.gregs[REG_ESP]; } -static void linux_regs_to_sigcontext(ucontext_t *uc, Registers* regs) +void linux_regs_to_ucontext(ucontext_t *uc, Registers* regs) { uc->uc_mcontext.gregs[REG_EAX] = regs->eax; uc->uc_mcontext.gregs[REG_ECX] = regs->ecx; @@ -100,14 +102,62 @@ static void linux_regs_to_sigcontext(uco uc->uc_mcontext.gregs[REG_ESP] = regs->esp; } +// exception catch support for JVMTI +extern "C" { + static void __attribute__ ((used, cdecl)) jvmti_exception_catch_callback_wrapper(Registers regs){ + jvmti_exception_catch_callback(®s); + } +} + +static void __attribute__ ((cdecl)) asm_jvmti_exception_catch_callback() { + //naked_jvmti_exception_catch_callback: + asm ( + "addl $-36, %%esp;\n" + "movl %%eax, -36(%%ebp);\n" + "movl %%ebx, -32(%%ebp);\n" + "movl %%ecx, -28(%%ebp);\n" + "movl %%edx, -24(%%ebp);\n" + "movl %%esp, %%eax;\n" + "movl (%%ebp), %%ebx;\n" + "movl 4(%%ebp), %%ecx;\n" + "addl $44, %%eax;\n" + "movl %%edi, -20(%%ebp);\n" + "movl %%esi, -16(%%ebp);\n" + "movl %%ebx, -12(%%ebp);\n" + "movl %%eax, -8(%%ebp);\n" + "movl %%ecx, -4(%%ebp);\n" + "call jvmti_exception_catch_callback_wrapper;\n" + "movl -36(%%ebp), %%eax;\n" + "movl -32(%%ebp), %%ebx;\n" + "movl -28(%%ebp), %%ecx;\n" + "movl -24(%%ebp), %%edx;\n" + "addl $36, %%esp;\n" + "leave;\n" + "ret;\n" + : /* no output operands */ + : /* no input operands */ + ); +} + static void throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) { Registers regs; - linux_sigcontext_to_regs(®s, uc); + linux_ucontext_to_regs(®s, uc); + + uint32 exception_esp = regs.esp; + DebugUtilsTI* ti = VM_Global_State::loader_env->TI; exn_athrow_regs(®s, exc_clss); - linux_regs_to_sigcontext(uc, ®s); + assert(exception_esp <= regs.esp); + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { + regs.esp = regs.esp - 4; + *((uint32*) regs.esp) = regs.eip; + regs.eip = ((uint32)asm_jvmti_exception_catch_callback); + //regs.eip = ((uint32)naked_jvmti_exception_catch_callback); + } + + linux_regs_to_ucontext(uc, ®s); } static bool java_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) @@ -258,6 +308,8 @@ void init_stack_info() { common_stack_size = find_stack_size(); common_guard_stack_size = find_guard_stack_size(); common_guard_page_size =find_guard_page_size(); + + set_guard_stack(); } void set_guard_stack() { @@ -328,7 +380,7 @@ bool check_stack_overflow(siginfo_t *inf char* fault_addr = (char*)(info->si_addr); //char* esp_value = (char*)(uc->uc_mcontext.gregs[REG_ESP]); - return((guard_page_begin <= fault_addr) && (fault_addr <= guard_page_end)); + return((guard_page_begin <= fault_addr) && (fault_addr < guard_page_end)); } /* @@ -349,7 +401,7 @@ void stack_overflow_handler(int signum, } else { if (is_unwindable()) { if (hythread_is_suspend_enabled()) { - hythread_suspend_disable(); + tmn_suspend_disable(); } throw_from_sigcontext( uc, env->java_lang_StackOverflowError_Class); @@ -366,6 +418,9 @@ void null_java_reference_handler(int sig ucontext_t *uc = (ucontext_t *)context; Global_Env *env = VM_Global_State::loader_env; + TRACE2("signals", "NPE or SOE detected at " << + (void *)uc->uc_mcontext.gregs[REG_EIP]); + if (check_stack_overflow(info, uc)) { stack_overflow_handler(signum, info, context); return; @@ -377,13 +432,14 @@ void null_java_reference_handler(int sig if (java_throw_from_sigcontext( uc, env->java_lang_NullPointerException_Class)) { return; - } else { - fprintf(stderr, "SIGSEGV in VM code.\n"); - return; } } - // crash with default handler + fprintf(stderr, "SIGSEGV in VM code.\n"); + Registers regs; + linux_ucontext_to_regs(®s, uc); + st_print_stack(®s); + signal(signum, 0); } @@ -393,6 +449,9 @@ void null_java_divide_by_zero_handler(in ucontext_t *uc = (ucontext_t *)context; Global_Env *env = VM_Global_State::loader_env; + TRACE2("signals", "ArithmeticException detected at " << + (void *)uc->uc_mcontext.gregs[REG_EIP]); + if (env->shutting_down != 0) { fprintf(stderr, "null_java_divide_by_zero_handler(): called in shutdown stage\n"); } else if (!interpreter_enabled()) { @@ -402,10 +461,35 @@ void null_java_divide_by_zero_handler(in } } + fprintf(stderr, "SIGFPE in VM code.\n"); + Registers regs; + linux_ucontext_to_regs(®s, uc); + st_print_stack(®s); + // crash with default handler signal(signum, 0); } +void jvmti_jit_breakpoint_handler(int signum, siginfo_t* UNREF info, void* context) +{ + ucontext_t *uc = (ucontext_t *)context; + Registers regs; + + linux_ucontext_to_regs(®s, uc); + TRACE2("signals", "JVMTI breakpoint detected at " << + (void *)regs.eip); + assert(!interpreter_enabled()); + + bool handled = jvmti_send_jit_breakpoint_event(®s); + if (handled) + linux_regs_to_ucontext(uc, ®s); + + fprintf(stderr, "SIGINT in VM code.\n"); + linux_ucontext_to_regs(®s, uc); + st_print_stack(®s); + signal(signum, 0); +} + /* See function initialize_signals() below first please. @@ -494,9 +578,13 @@ #define SC_SEARCH_WIDTH 3 * @note call stacks may be used for debugging */ void abort_handler (int signum, siginfo_t* UNREF info, void* context) { - // crash with default handle. + fprintf(stderr, "SIGABRT in VM code.\n"); + Registers regs; + ucontext_t *uc = (ucontext_t *)context; + linux_ucontext_to_regs(®s, uc); + st_print_stack(®s); + signal(signum, 0); - fprintf(stderr, "abort_handler()\n"); } /* @@ -558,7 +646,12 @@ void initialize_signals() sigaction(SIGUSR2, &sa, NULL); */ sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = &jvmti_jit_breakpoint_handler; + sigaction(SIGTRAP, &sa, NULL); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK;; sa.sa_sigaction = &null_java_reference_handler; sigaction(SIGSEGV, &sa, NULL); @@ -566,7 +659,7 @@ void initialize_signals() sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = &null_java_divide_by_zero_handler; sigaction(SIGFPE, &sa, NULL); - + extern void interrupt_handler(int); signal(SIGINT, (void (*)(int)) interrupt_handler); extern void quit_handler(int); diff --git vm/vmcore/src/util/linux/signals_ipf.cpp vm/vmcore/src/util/linux/signals_ipf.cpp index 92b4a08..3174cd1 100644 --- vm/vmcore/src/util/linux/signals_ipf.cpp +++ vm/vmcore/src/util/linux/signals_ipf.cpp @@ -158,6 +158,16 @@ static uint32 exam_point; bool SuspendThread(unsigned xx){ return 0; } bool ResumeThread(unsigned xx){ return 1; } +void linux_ucontext_to_regs(Registers* regs, ucontext_t* uc) +{ +//TODO: ADD Copying of IPF registers here like it was done on ia32!! +} + +void linux_regs_to_ucontext(ucontext_t* uc, Registers* regs) +{ +//TODO: ADD Copying of IPF registers here like it was done on ia32!! +} + static void linux_sigcontext_to_regs(Registers* regs, sigcontext* sc) { //TODO: ADD Copying of IPF registers here like it was done on ia32!! @@ -189,10 +199,10 @@ static void linux_throw_from_sigcontext( assert(vm_identify_eip((void *)sc->sc_ip) == VM_TYPE_JAVA); Registers regs; - linux_sigcontext_to_regs(®s, sc); +// linux_sigcontext_to_regs(®s, sc); // FIXME: transfer to linux_ucontext_to_regs exn_athrow_regs(®s, exc_clss); - linux_regs_to_sigcontext(sc, ®s); - linux_regs_to_sigcontext(top_sc, ®s); +// linux_regs_to_sigcontext(sc, ®s); // FIXME: transfer to linux_regs_to_ucontext +// linux_regs_to_sigcontext(top_sc, ®s); // FIXME: transfer to linux_regs_to_ucontext } /* diff --git vm/vmcore/src/util/linux/stubs.cpp vm/vmcore/src/util/linux/stubs.cpp index 7185c50..e3319ab 100644 --- vm/vmcore/src/util/linux/stubs.cpp +++ vm/vmcore/src/util/linux/stubs.cpp @@ -44,162 +44,3 @@ DWORD IJGetLastError(VOID) { return errno; } - -//wgs: I wonder if we could give it a errno -DWORD WSAGetLastError(VOID) -{ - ABORT("Not implemented"); - return errno; -} - -void _fpreset(void) -{ - ABORT("Not implemented"); -} - - - -#include <sys/time.h> -__uint64 GetTickCount(void) -{ - static bool not_initialized = true; - static timeval basetime; - __uint64 now; - struct timezone UNUSED tz; - assert(!gettimeofday(&basetime, &tz)); - now = (*(__uint64 *)&basetime.tv_sec)*1000000+*(__uint64 *)&basetime; - if (not_initialized) { - basetime = *(timeval *)&now; - not_initialized = false; - return (__uint64)0; - } else { - return (now - *(__uint64*)&basetime); - } -} - -/* TODO reimplement this code while implementing IPF support. - -VmRegisterContext::VmRegisterContext() -{ - CONTEXT *ctx = new CONTEXT; - ctx->ContextFlags = 0; - _pcontext = (void *) ctx; -} - -VmRegisterContext::~VmRegisterContext() -{ - delete (CONTEXT *) _pcontext; -} - -void VmRegisterContext::setFlag(VmRegisterContext::ContextFlag flag) -{ - unsigned old = ((CONTEXT *)_pcontext)->ContextFlags; - switch (flag) - { - case VmRegisterContext::CF_FloatingPoint: - old |= CONTEXT_FLOATING_POINT; - break; - case VmRegisterContext::CF_Integer: - old |= CONTEXT_INTEGER; - break; - case VmRegisterContext::CF_Control: - old |= CONTEXT_CONTROL; - break; - default: - ASSERT(0, "Unexpected context flag"); - break; - } - ((CONTEXT *)_pcontext)->ContextFlags = old; -} - - -void VmRegisterContext::getContext(VM_thread *thread) -{ - CONTEXT *ctx = (CONTEXT *) _pcontext; - BOOL UNUSED stat = GetThreadContext(thread->thread_handle, ctx); - assert(stat); -#ifdef _IPF_ - thread->regs.gr[4] = ctx->IntS0; - thread->regs.gr[5] = ctx->IntS1; - thread->regs.gr[6] = ctx->IntS2; - thread->regs.gr[7] = ctx->IntS3; - thread->regs.gr[12] = ctx->IntSp; - thread->regs.preds = ctx->Preds; - thread->regs.pfs = ctx->RsPFS; - thread->regs.bsp = (uint64 *)ctx->RsBSP; - thread->regs.ip = ctx->StIIP; -#else // !_IPF_ -#ifdef _EM64T_ - thread->regs.rax = ctx->Eax; - thread->regs.rbx = ctx->Ebx; - thread->regs.rcx = ctx->Ecx; - thread->regs.rdx = ctx->Edx; - thread->regs.rdi = ctx->Edi; - thread->regs.rsi = ctx->Esi; - thread->regs.rbp = ctx->Ebp; - thread->regs.rsp = ctx->Esp; - thread->regs.rip = ctx->Eip; -#else - thread->regs.eax = ctx->Eax; - thread->regs.ebx = ctx->Ebx; - thread->regs.ecx = ctx->Ecx; - thread->regs.edx = ctx->Edx; - thread->regs.edi = ctx->Edi; - thread->regs.esi = ctx->Esi; - thread->regs.ebp = ctx->Ebp; - thread->regs.esp = ctx->Esp; - thread->regs.eip = ctx->Eip; -#endif //_EM64T_ -#endif // !_IPF_ -} - -void VmRegisterContext::setContext(VM_thread *thread) -{ - CONTEXT *ctx = (CONTEXT *) _pcontext; - BOOL stat = GetThreadContext(thread->thread_handle, ctx); - assert(stat); -#ifdef _IPF_ - ctx->IntS0 = thread->regs.gr[4]; - ctx->IntS1 = thread->regs.gr[5]; - ctx->IntS2 = thread->regs.gr[6]; - ctx->IntS3 = thread->regs.gr[7]; -#else // !_IPF_ -#ifdef _EM64T_ - ctx->Eax = thread->regs.rax; - ctx->Ebx = thread->regs.rbx; - ctx->Ecx = thread->regs.rcx; - ctx->Edx = thread->regs.rdx; - ctx->Edi = thread->regs.rdi; - ctx->Esi = thread->regs.rsi; - ctx->Ebp = thread->regs.rbp; -#else - ctx->Eax = thread->regs.eax; - ctx->Ebx = thread->regs.ebx; - ctx->Ecx = thread->regs.ecx; - ctx->Edx = thread->regs.edx; - ctx->Edi = thread->regs.edi; - ctx->Esi = thread->regs.esi; - ctx->Ebp = thread->regs.ebp; -#endif //_EM64T_ -#endif // !_IPF_ - stat = SetThreadContext(thread->thread_handle, ctx); - assert(stat); -} - -void VmRegisterContext::getBspAndRnat(VM_thread * UNREF thread, uint64 ** UNREF bspstore, uint64 * UNREF rnat) -{ -#ifdef _IPF_ - CONTEXT *ctx = (CONTEXT *) _pcontext; - BOOL stat; - while ((stat = GetThreadContext(thread->thread_handle, ctx)) == 0) { - DWORD error_number = IJGetLastError(); - DIE("Unexpected error from GetThreadContext : " << error_number); - // GetThreadContext should never return zero on NT - } - *bspstore = (uint64*)ctx->RsBSPSTORE; - *rnat = ctx->RsRNAT; -#else // !_IPF_ - ABORT("Not supported"); // shouldn't be called under IA-32 -#endif // !_IPF_ -} -*/ diff --git vm/vmcore/src/util/mem_alloc.cpp vm/vmcore/src/util/mem_alloc.cpp index 361bd01..4e2340b 100644 --- vm/vmcore/src/util/mem_alloc.cpp +++ vm/vmcore/src/util/mem_alloc.cpp @@ -94,9 +94,9 @@ #ifdef VM_STATS p_pool->num_pool_allocations++; p_pool->total_pool_size += size; if (is_code) { - vm_stats_total.codemgr_total_code_pool_size += size; + VM_Statistics::get_vm_stats().codemgr_total_code_pool_size += size; } else { - vm_stats_total.codemgr_total_data_pool_size += size; + VM_Statistics::get_vm_stats().codemgr_total_data_pool_size += size; } #endif //VM_STATS @@ -182,9 +182,9 @@ #ifdef VM_STATS p_pool->num_allocations++; p_pool->total_size_allocated += size; if (p_pool->is_code) { - vm_stats_total.codemgr_total_code_allocated += size; + VM_Statistics::get_vm_stats().codemgr_total_code_allocated += size; } else { - vm_stats_total.codemgr_total_data_allocated += size; + VM_Statistics::get_vm_stats().codemgr_total_data_allocated += size; } #endif //VM_STATS return p; @@ -270,10 +270,10 @@ void vm_init_mem_alloc() assert(initial_code_pool_size); #ifdef VM_STATS - vm_stats_total.codemgr_total_code_pool_size = 0; - vm_stats_total.codemgr_total_code_allocated = 0; - vm_stats_total.codemgr_total_data_pool_size = 0; - vm_stats_total.codemgr_total_data_allocated = 0; + VM_Statistics::get_vm_stats().codemgr_total_code_pool_size = 0; + VM_Statistics::get_vm_stats().codemgr_total_code_allocated = 0; + VM_Statistics::get_vm_stats().codemgr_total_data_pool_size = 0; + VM_Statistics::get_vm_stats().codemgr_total_data_allocated = 0; #endif //VM_STATS init_pools(page_size_for_allocation); diff --git vm/vmcore/src/util/native_stack.cpp vm/vmcore/src/util/native_stack.cpp new file mode 100755 index 0000000..685fc91 --- /dev/null +++ vm/vmcore/src/util/native_stack.cpp @@ -0,0 +1,419 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "lock_manager.h" +#include "method_lookup.h" +#include "m2n.h" +#include "stack_trace.h" +#include "interpreter.h" +#include "interpreter_exports.h" +#include "compile.h" +#include "native_modules.h" +#include "native_stack.h" + + + +// Global lock used for locking module list access +static Lock_Manager g_list_lock; + + +////////////////////////////////////////////////////////////////////////////// +/// Helper functions + +static bool get_modules(native_module_t** pmodules) +{ + assert(pmodules); + + if (*pmodules != NULL) + return true; + + int mod_count; + native_module_t* mod_list = NULL; + + LMAutoUnlock aulock(&g_list_lock); + + bool result = get_all_native_modules(&mod_list, &mod_count); + + if (!result) + return false; + + *pmodules = mod_list; + return true; +} + +bool native_is_ip_in_modules(native_module_t* modules, void* ip) +{ + for (native_module_t* module = modules; module; module = module->next) + { + for (size_t i = 0; i < module->seg_count; i++) + { + char* base = (char*)module->segments[i].base; + + if (ip >= base && + ip < (base + module->segments[i].size)) + return true; + } + } + + return false; +} + +bool native_is_ip_stub(void* ip) +{ + for (DynamicCode *dcList = compile_get_dynamic_code_list(); + NULL != dcList; dcList = dcList->next) + { + if (ip >= dcList->address && + ip < (void*)((POINTER_SIZE_INT)dcList->address + dcList->length)) + return true; + } + + return false; +} +/// Helper functions +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +// + +static int walk_native_stack_jit(Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array); +static int walk_native_stack_pure(Registers* pregs, + int max_depth, native_frame_t* frame_array); +static int walk_native_stack_interpreter(Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array); + +int walk_native_stack_registers(Registers* pregs, + VM_thread* pthread, int max_depth, native_frame_t* frame_array) +{ + if (pthread == NULL) // Pure native thread + return walk_native_stack_pure(pregs, max_depth, frame_array); + + if (interpreter_enabled()) + return walk_native_stack_interpreter(pregs, pthread, max_depth, frame_array); + + return walk_native_stack_jit(pregs, pthread, max_depth, frame_array); +} + + +static int walk_native_stack_jit(Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array) +{ + // These vars store current frame context for each iteration + void *ip, *bp, *sp; + // To translate platform-dependant info; we will use ip from here + native_get_frame_info(pregs, &ip, &bp, &sp); + + int frame_count = 0; + + // Search for method containing corresponding address + VM_Code_Type code_type = vm_identify_eip(ip); + bool flag_dummy_frame = false; + jint java_depth = 0; + StackIterator* si = NULL; + bool is_java = false; + native_module_t* modules = NULL; + + if (code_type == VM_TYPE_JAVA) + { // We must add dummy M2N frame to start SI iteration + assert(pthread); + m2n_push_suspended_frame(pthread, pregs); + flag_dummy_frame = true; + is_java = true; + } + + si = si_create_from_native(pthread); + + if (is_java) + si_goto_previous(si); + + jint inline_index = -1; + jint inline_count; + CodeChunkInfo* cci = NULL; + bool is_stub = false; + int special_count = 0; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + frame_array[frame_count].java_depth = + is_java ? java_depth : -1; + + frame_array[frame_count].ip = ip; + frame_array[frame_count].frame = bp; + frame_array[frame_count].stack = sp; + } + + ++frame_count; + +///////////////////////// +// vv Java vv + if (is_java) //code_type == VM_TYPE_JAVA + { // Go to previous frame using StackIterator + cci = si_get_code_chunk_info(si); + assert(cci); // Java method should contain cci + + // if (inline_index < 0) we have new si + // (inline_index < inline_count) we must process inline + // (inline_index == inline_count) we must process si itself + if (inline_index < 0) + { + inline_count = si_get_inline_depth(si); + inline_index = 0; + } + + ++java_depth; + + if (inline_index < inline_count) + { // Process inlined method + // We don't need to update context, + // because context is equal for + // all inlined methods + ++inline_index; + } + else + { + inline_index = -1; + // Ge to previous stack frame from StackIterator + si_goto_previous(si); + native_get_ip_bp_from_si_jit_context(si, &ip, &bp);//??? + native_get_sp_from_si_jit_context(si, &sp); + } + + code_type = vm_identify_eip(ip); + is_java = (code_type == VM_TYPE_JAVA); + continue; + } +// ^^ Java ^^ +///////////////////////// +// vv Native vv + is_stub = native_is_ip_stub(ip); + + if (is_stub) + { // Native stub, previous frame is Java frame + assert(si_is_native(si)); + + // Mark first frame (JNI stub) as Java frame + if (frame_array && frame_count == 1) + frame_array[frame_count - 1].java_depth = java_depth; + + if (frame_array && frame_count > 1) + frame_array[frame_count - 2].java_depth = java_depth; + + ++java_depth; + + // Ge to previous stack frame from StackIterator + si_goto_previous(si); + // Let's get context from si + native_get_ip_bp_from_si_jit_context(si, &ip, &bp); + native_get_sp_from_si_jit_context(si, &sp); + } + else + { + if (!modules && !get_modules(&modules)) + break; + + if (native_is_frame_valid(modules, bp, sp)) + { // Simply bp-based frame, let's unwind it + native_unwind_bp_based_frame(bp, &ip, &bp, &sp); + } + else + { // Is not bp-based frame + if (frame_count == 1) + { // For first frame, test special unwinding possibility + special_count = native_test_unwind_special(modules, sp); + if (special_count <= 0) + ip = NULL; + } + + if (frame_count <= special_count) + { // Specially unwind first native frames + bool res = native_unwind_special(modules, + sp, &ip, &sp, &bp, + frame_count == special_count); + + if (!res) + break; // Unwinding failed + } + else + break; // There is another invalid frame in the stack + } + } + + code_type = vm_identify_eip(ip); + is_java = (code_type == VM_TYPE_JAVA); + + // If we've reached Java without native stub + if (is_java && !is_stub) + break; // then stop processing +// ^^ Native ^^ +///////////////////////// + } + + if (flag_dummy_frame) + { // Delete previously added dummy frame + M2nFrame* plm2n = m2n_get_last_frame(pthread); + m2n_set_last_frame(pthread, m2n_get_previous_frame(plm2n)); + STD_FREE(plm2n); + } + + return frame_count; +} + + +static int walk_native_stack_pure(Registers* pregs, + int max_depth, native_frame_t* frame_array) +{ + // These vars store current frame context for each iteration + void *ip, *bp, *sp; + // To translate platform-dependant info; we will use ip from here + native_get_frame_info(pregs, &ip, &bp, &sp); + assert(vm_identify_eip(ip) != VM_TYPE_JAVA); + + int frame_count = 0; + int special_count = 0; + native_module_t* modules = NULL; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + frame_array[frame_count].java_depth = -1; + frame_array[frame_count].ip = ip; + frame_array[frame_count].frame = bp; + frame_array[frame_count].stack = sp; + } + + ++frame_count; + + if (!modules && !get_modules(&modules)) + break; + + // Simply bp-based frame, let's unwind it + if (native_is_frame_valid(modules, bp, sp)) + { + native_unwind_bp_based_frame(bp, &ip, &bp, &sp); + } + else + { // Wrong frame + if (frame_count == 1) + { // For first frame, test special unwinding possibility + special_count = native_test_unwind_special(modules, sp); + if (special_count <= 0) + break; + } + + if (frame_count <= special_count) + { // Specially unwind first native frames + native_unwind_special(modules, sp, &ip, &sp, &bp, + frame_count == special_count); + } + else // There is another invalid frame in the stack + break; + } + } + + return frame_count; +} + + +static int walk_native_stack_interpreter(Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array) +{ + // These vars store current frame context for each iteration + void *ip, *bp, *sp; + // To translate platform-dependant info; we will use ip from here + native_get_frame_info(pregs, &ip, &bp, &sp); + + assert(pthread); + FrameHandle* last_frame = interpreter.interpreter_get_last_frame(pthread); + FrameHandle* frame = last_frame; + + int frame_count = 0; + jint java_depth = 0; + int special_count = 0; + native_module_t* modules = NULL; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + frame_array[frame_count].java_depth = -1; + frame_array[frame_count].ip = ip; + frame_array[frame_count].frame = bp; + frame_array[frame_count].stack = sp; + } + + ++frame_count; + + // Store previous value to identify frame range later + void* prev_sp = sp; + + if (!modules && !get_modules(&modules)) + break; + + if (native_is_frame_valid(modules, bp, sp)) + { // Simply bp-based frame, let's unwind it + native_unwind_bp_based_frame(bp, &ip, &bp, &sp); + } + else + { // Is not bp-based frame + if (frame_count == 1) + { // For first frame, test special unwinding possibility + special_count = native_test_unwind_special(modules, sp); + if (special_count <= 0) + break; + } + + if (frame_count <= special_count) + { // Specially unwind first native frames + native_unwind_special(modules, sp, &ip, &sp, &bp, + frame_count == special_count); + } + else + break; // There is another invalid frame in the stack + } + + bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, sp); + + if (is_java) + { + // Set Java frame number + if (frame_array && frame_count > 1) + frame_array[frame_count - 2].java_depth = java_depth++; + + // Go to previous frame + frame = interpreter.interpreter_get_prev_frame(frame); + } + } + + return frame_count; +} diff --git vm/vmcore/src/util/natives_support.cpp vm/vmcore/src/util/natives_support.cpp index 91ee6b1..8703bf7 100644 --- vm/vmcore/src/util/natives_support.cpp +++ vm/vmcore/src/util/natives_support.cpp @@ -157,6 +157,18 @@ #endif } +static inline bool is_name_lowercase(const char* name) +{ + for(; *name; name++) + { + if (isalpha(*name) && !islower(*name)) + return false; + } + + return true; +} + + // Function loads native library with a given name. NativeLibraryHandle natives_load_library(const char* library_name, bool* just_loaded, @@ -164,6 +176,9 @@ natives_load_library(const char* library { assert(NULL != library_name); assert(NULL != pstatus); +#ifdef PLATFORM_NT + assert(is_name_lowercase(library_name)); +#endif jni_libs.lock._lock(); diff --git vm/vmcore/src/util/vm_stats.cpp vm/vmcore/src/util/vm_stats.cpp index 48cd72b..61427da 100644 --- vm/vmcore/src/util/vm_stats.cpp +++ vm/vmcore/src/util/vm_stats.cpp @@ -19,7 +19,8 @@ */ #ifdef VM_STATS -#define LOG_DOMAIN "stats" + +#define LOG_DOMAIN "vm.stats" #include "cxxlog.h" #include "platform.h" @@ -34,13 +35,9 @@ #include "classloader.h" #include "vm_stats.h" #include "GlobalClassLoaderIterator.h" -VM_Statistics vm_stats_total; - bool vm_print_total_stats = false; int vm_print_total_stats_level = 0; - - // 20030425 The list of JIT support functions below must be kept in synch with the enum VM_RT_SUPPORT in jit_runtime_support.h. typedef struct JIT_RT_Function_Entry { VM_RT_SUPPORT function; @@ -64,7 +61,7 @@ static JIT_RT_Function_Entry _jit_rt_fun {VM_RT_THROW_SET_STACK_TRACE, "VM_RT_THROW_SET_STACK_TRACE", 1}, {VM_RT_MONITOR_ENTER, "VM_RT_MONITOR_ENTER", 1}, - {VM_RT_MONITOR_ENTER_NO_EXC, "VM_RT_MONITOR_ENTER_NO_EXC", 1}, + {VM_RT_MONITOR_ENTER_NON_NULL, "VM_RT_MONITOR_ENTER_NON_NULL", 1}, {VM_RT_MONITOR_EXIT, "VM_RT_MONITOR_EXIT", 1}, {VM_RT_MONITOR_EXIT_NON_NULL, "VM_RT_MONITOR_EXIT_NON_NULL", 1}, {VM_RT_MONITOR_ENTER_STATIC, "VM_RT_MONITOR_ENTER_STATIC", 1}, @@ -84,6 +81,8 @@ static JIT_RT_Function_Entry _jit_rt_fun {VM_RT_JVMTI_METHOD_ENTER_CALLBACK, "VM_RT_JVMTI_METHOD_ENTER_CALLBACK", 1}, {VM_RT_JVMTI_METHOD_EXIT_CALLBACK, "VM_RT_JVMTI_METHOD_EXIT_CALLBACK", 2}, + {VM_RT_JVMTI_FIELD_ACCESS_CALLBACK, "VM_RT_JVMTI_FIELD_ACCESS__CALLBACK", 4}, + {VM_RT_JVMTI_FIELD_MODIFICATION_CALLBACK, "VM_RT_JVMTI_FIELD_MODIFICATION_CALLBACK", 5}, {VM_RT_RESOLVE, "VM_RT_RESOLVE", 3}, @@ -113,8 +112,6 @@ #endif // VM_LONG_OPT {VM_RT_CHAR_ARRAYCOPY_NO_EXC, "VM_RT_CHAR_ARRAYCOPY_NO_EXC", 5}, - {VM_RT_NEW_RESOLVED, "VM_RT_NEW_RESOLVED", 1}, - {VM_RT_NEW_VECTOR, "VM_RT_NEW_VECTOR", 2}, {VM_RT_WRITE_BARRIER_FASTCALL, "VM_RT_WRITE_BARRIER_FASTCALL", 2}, }; @@ -313,9 +310,19 @@ #endif num_args = jit_rt_function_entries[i].number_of_args; rt_function_map.add((void *)fn_number, num_args, fn_name); } + + apr_pool_create(&vm_stats_pool, 0); } //VM_Statistics::VM_Statistics +VM_Statistics::~VM_Statistics() { + apr_pool_destroy(vm_stats_pool); +} +VM_Statistics & VM_Statistics::get_vm_stats() { + static StaticInitializer initializer = StaticInitializer(); + static VM_Statistics vm_stats = VM_Statistics(); + return vm_stats; +} static void print_classes() { @@ -557,23 +564,23 @@ static void print_array_distribution(cha -static void print_rt_function_stats(VM_Statistics *stats) +void VM_Statistics::print_rt_function_stats() { int num_entries, i; printf("\nJIT runtime support functions requested:\n"); - num_entries = stats->rt_function_requests.size(); + num_entries = rt_function_requests.size(); if (num_entries > 0) { PairEntry **pair_array = (PairEntry **)STD_MALLOC(num_entries * sizeof(PairEntry *)); - dump(stats->rt_function_requests, pair_array, num_entries, /*threshold*/ 1); + dump(rt_function_requests, pair_array, num_entries, /*threshold*/ 1); // Sort by increasing number of requests. quick_sort(pair_array, 0, num_entries-1); for (i = 0; i < num_entries; i++) { VM_RT_SUPPORT fn_number = (VM_RT_SUPPORT)((POINTER_SIZE_INT)(pair_array[i]->key)); int num_args = 0; char *fn_name = NULL; - bool UNUSED found = stats->rt_function_map.lookup((void *)fn_number, &num_args, (void **)&fn_name); + bool UNUSED found = rt_function_map.lookup((void *)fn_number, &num_args, (void **)&fn_name); assert(found); // else changes were made to the enum VM_RT_SUPPORT in jit_runtime_support.h. printf("%11d :::: %s\n", pair_array[i]->value, fn_name); } @@ -581,27 +588,71 @@ static void print_rt_function_stats(VM_S printf("\n"); } -#ifdef VM_STATS - num_entries = stats->rt_function_calls.size(); + num_entries = rt_function_calls.size(); if (num_entries > 0) { printf("\nJIT runtime support functions called:\n"); PairEntry **pair_array = (PairEntry **)STD_MALLOC(num_entries * sizeof(PairEntry *)); - dump(stats->rt_function_calls, pair_array, num_entries, /*threshold*/ 1); + dump(rt_function_calls, pair_array, num_entries, /*threshold*/ 1); // Sort by increasing number of calls. quick_sort(pair_array, 0, num_entries-1); for (i = 0; i < num_entries; i++) { VM_RT_SUPPORT fn_number = (VM_RT_SUPPORT)((POINTER_SIZE_INT)(pair_array[i]->key)); int num_args = 0; char *fn_name = NULL; - bool found = stats->rt_function_map.lookup((void *)fn_number, &num_args, (void **)&fn_name); + bool found = rt_function_map.lookup((void *)fn_number, &num_args, (void **)&fn_name); assert(found); // else changes were made to the enum VM_RT_SUPPORT in jit_runtime_support.h. printf("%11d :::: %s\n", pair_array[i]->value, fn_name); } printf("\n"); } -#endif //VM_STATS } //print_rt_function_stats +void VM_Statistics::print_string_pool_stats() { + printf("\nBegin: Virtual Machine String Pool Statistics\n"); + //printf("\tname\ttotal lookups\ttotal collisions\n"); + unsigned long num_lookup_total = 0; + unsigned long num_lookup_collision_total = 0; + String_Pool & string_pool = VM_Global_State::loader_env->string_pool; + for (apr_hash_index_t * index = + apr_hash_first(vm_stats_pool, string_pool.string_stat); + index != NULL; index = apr_hash_next(index)) { + char * key; + apr_ssize_t key_len; + String_Stat * key_stats; + + apr_hash_this(index, (const void **)&key, &key_len, (void **)&key_stats); + + num_lookup_total += key_stats->num_lookup; + num_lookup_collision_total += key_stats->num_lookup_collision; + + bool is_interned = false; + String * string = string_pool.lookup(key, key_len); + if (VM_Global_State::loader_env->compress_references) { + if (string->intern.compressed_ref) { + is_interned = true; + } + } else { + if (string->intern.raw_ref) { + is_interned = true; + } + } + + char * str = key; + // replace '\n' literal with space + while(str = strchr(str, '\n')) { + *str = ' '; + ++str; + } + printf("%s#%i#%i#%s\n", key, key_stats->num_lookup, + key_stats->num_lookup_collision, is_interned == 0 ? "uninterned" : "interned"); + } + int num_elements = apr_hash_count(string_pool.string_stat); + float hash_quality = ((float)(num_elements) - string_pool.num_ambiguity ) / num_elements; + + printf("Total lookups/lookup collisions/conflicting elements/hash quality:#%i#%i#%i#%f\n", + num_lookup_total, num_lookup_collision_total, string_pool.num_ambiguity, hash_quality); + printf("\n End: Virtual Machine String Pool Statistics\n"); +} void VM_Statistics::print() { @@ -865,11 +916,13 @@ #ifdef VM_STATS printf("%11" FMT64 "u :::: num_resizes\n", vtable_data_pool->num_resizes); printf("%11" FMT64 "u :::: current_alloc_size\n", uint64(vtable_data_pool->current_alloc_size)); } -#endif // VM_STATS fflush(stdout); - print_rt_function_stats(this); + print_rt_function_stats(); + + print_string_pool_stats(); +#endif // VM_STATS printf("==== end VM statistics\n"); } //VM_Statistics::print diff --git vm/vmcore/src/util/vm_strings.cpp vm/vmcore/src/util/vm_strings.cpp index 613b3cc..b0dc667 100644 --- vm/vmcore/src/util/vm_strings.cpp +++ vm/vmcore/src/util/vm_strings.cpp @@ -232,6 +232,7 @@ static void string_set_fields_separate(M // Return: str gets the string object, buf points to buffer static void string_create(unsigned unicode_length, bool eight_bit, ManagedObject** str, StringBuffer* buf) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); Global_Env *global_env = VM_Global_State::loader_env; @@ -245,7 +246,7 @@ static void string_create(unsigned unico Vector_Handle array = gc_alloc(sz, clss->allocation_handle, vm_get_gc_thread_local()); if (!array) { // OutOfMemory should be thrown *str = NULL; - exn_throw(VM_Global_State::loader_env->java_lang_OutOfMemoryError); + exn_raise_object(VM_Global_State::loader_env->java_lang_OutOfMemoryError); return; } #ifdef VM_STATS @@ -282,6 +283,7 @@ #endif //VM_STATS // GC must be disabled, but at a GC safe point ManagedObject* string_create_from_utf8(const char* buf, unsigned length) { + ASSERT_RAISE_AREA; assert(buf && buf[length]=='\0'); int unicode_length = get_unicode_length_of_utf8(buf); if (unicode_length < 0) // data error @@ -311,6 +313,7 @@ static bool is_compressible_jchar_array( // GC must be disabled, but at a GC safe point ManagedObject* string_create_from_unicode(const uint16* buf, unsigned length) { + ASSERT_RAISE_AREA; Global_Env *global_env = VM_Global_State::loader_env; bool compress = global_env->strings_are_compressed && is_compressible_jchar_array(buf, length); ManagedObject* str; @@ -330,6 +333,7 @@ ManagedObject* string_create_from_unicod ObjectHandle string_create_from_utf8_h(const char* buf, unsigned length) { + ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); ObjectHandle res = oh_allocate_local_handle(); @@ -340,6 +344,7 @@ ObjectHandle string_create_from_utf8_h(c ObjectHandle string_create_from_unicode_h(const uint16* buf, unsigned length) { + ASSERT_RAISE_AREA; assert(hythread_is_suspend_enabled()); tmn_suspend_disable(); ObjectHandle res = oh_allocate_local_handle(); @@ -534,6 +539,7 @@ void string_get_utf8_region_h(ObjectHand VMEXPORT // temporary solution for interpreter unplug Java_java_lang_String *vm_instantiate_cp_string_resolved(String *str) { + ASSERT_RAISE_AREA; assert(!hythread_is_suspend_enabled()); Global_Env *env = VM_Global_State::loader_env; if (env->compress_references) { @@ -545,50 +551,14 @@ Java_java_lang_String *vm_instantiate_cp return str->intern.raw_ref; } } - - volatile Java_java_lang_String* lang_string = string_create_from_utf8(str->bytes, str->len); - if (!lang_string) { // if OutOfMemory - return NULL; - } - assert(!hythread_is_suspend_enabled()); - - // Atomically update the string structure since some other thread might be trying to make the same update. - // The GC won't be able to enumerate here since GC is disabled, so there are no race conditions with GC. - if (env->compress_references) { - COMPRESSED_REFERENCE compressed_lang_string = (COMPRESSED_REFERENCE)((POINTER_SIZE_INT)lang_string - (POINTER_SIZE_INT)Class::heap_base); - assert(is_compressed_reference(compressed_lang_string)); - assert(sizeof(LONG) == sizeof(uint32)); - uint32 result = apr_atomic_cas32( - /*destination*/ (volatile uint32 *)&str->intern.compressed_ref, - /*exchange*/ compressed_lang_string, - /*comparand*/ 0); - if (result == 0) { - // Note the successful write of the object. - gc_heap_write_global_slot_compressed((COMPRESSED_REFERENCE *)&str->intern.compressed_ref, (Managed_Object_Handle)lang_string); - } - // Some other thread may have beaten us to the slot. - lang_string = (volatile Java_java_lang_String *)uncompress_compressed_reference(str->intern.compressed_ref); - } else { - volatile void *result = - (volatile void *)apr_atomic_casptr( - /*destination*/ (volatile void **)&str->intern.raw_ref, - /*exchange*/ (void *)lang_string, - /*comparand*/ (void *)NULL); - if (result == NULL) { - // Note the successful write of the object. - gc_heap_write_global_slot((Managed_Object_Handle *)&str->intern.raw_ref, (Managed_Object_Handle)lang_string); - } - // Some other thread may have beaten us to the slot. - lang_string = str->intern.raw_ref; - } - - return (Java_java_lang_String *)lang_string; + return env->string_pool.intern(str); } //vm_instantiate_cp_string_resolved // Interning of strings VMEXPORT jstring string_intern(JNIEnv *jenv, jobject jstr_obj) { + ASSERT_RAISE_AREA; jboolean is_copy; const char* val = jenv->GetStringUTFChars(jstr_obj, &is_copy); String* str = VM_Global_State::loader_env->string_pool.lookup(val); @@ -601,8 +571,10 @@ VMEXPORT jstring string_intern(JNIEnv *j jstring String_to_interned_jstring(String* str) { + ASSERT_RAISE_AREA; tmn_suspend_disable(); Java_java_lang_String *jstr = vm_instantiate_cp_string_resolved(str); + if (jstr == NULL) { tmn_suspend_enable(); assert(exn_raised()); @@ -619,8 +591,9 @@ jstring String_to_interned_jstring(Strin Java_java_lang_String * vm_instantiate_cp_string_slow(Class *c, unsigned cp_index) { + ASSERT_THROW_AREA; #ifdef VM_STATS - vm_stats_total.num_instantiate_cp_string_slow++; + VM_Statistics::get_vm_stats().num_instantiate_cp_string_slow++; #endif Java_java_lang_String *result; @@ -629,7 +602,11 @@ #endif String *str = cp[cp_index].CONSTANT_String.string; assert(cp_is_constant(cp, cp_index)); + + BEGIN_RAISE_AREA; result = vm_instantiate_cp_string_resolved(str); + END_RAISE_AREA; + exn_rethrow_if_pending(); return result; } //vm_instantiate_cp_string_slow diff --git vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp index 62bdc08..164c3f0 100644 --- vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp +++ vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp @@ -42,6 +42,32 @@ #include "thread_generic.h" // Afremov Pavel 20050117 #include "../m2n_em64t_internal.h" +void nt_to_vm_context(PCONTEXT pcontext, Registers* regs) +{ + regs->rax = pcontext->Eax; + regs->rcx = pcontext->Ecx; + regs->rdx = pcontext->Edx; + regs->rdi = pcontext->Edi; + regs->rsi = pcontext->Esi; + regs->rbx = pcontext->Ebx; + regs->rbp = pcontext->Ebp; + regs->rip = pcontext->Eip; + regs->rsp = pcontext->Esp; +} + +void vm_to_nt_context(Registers* regs, PCONTEXT pcontext) +{ + pcontext->Esp = regs->rsp; + pcontext->Eip = regs->rip; + pcontext->Ebp = regs->rbp; + pcontext->Ebx = regs->rbx; + pcontext->Esi = regs->rsi; + pcontext->Edi = regs->rdi; + pcontext->Eax = regs->rax; + pcontext->Ecx = regs->rcx; + pcontext->Edx = regs->rdx; +} + int NT_exception_filter(LPEXCEPTION_POINTERS p_NT_exception) { @@ -97,27 +123,12 @@ int NT_exception_filter(LPEXCEPTION_POIN } Registers regs; - regs.rax = p_NT_exception->ContextRecord->Eax; - regs.rcx = p_NT_exception->ContextRecord->Ecx; - regs.rdx = p_NT_exception->ContextRecord->Edx; - regs.rdi = p_NT_exception->ContextRecord->Edi; - regs.rsi = p_NT_exception->ContextRecord->Esi; - regs.rbx = p_NT_exception->ContextRecord->Ebx; - regs.rbp = p_NT_exception->ContextRecord->Ebp; - regs.rip = p_NT_exception->ContextRecord->Eip; - regs.rsp = p_NT_exception->ContextRecord->Esp; + + nt_to_vm_context(p_NT_exception->ContextRecord, ®s); exn_athrow_regs(®s, exc_clss); - p_NT_exception->ContextRecord->Esp = regs.rsp; - p_NT_exception->ContextRecord->Eip = regs.rip; - p_NT_exception->ContextRecord->Ebp = regs.rbp; - p_NT_exception->ContextRecord->Ebx = regs.rbx; - p_NT_exception->ContextRecord->Esi = regs.rsi; - p_NT_exception->ContextRecord->Edi = regs.rdi; - p_NT_exception->ContextRecord->Eax = regs.rax; - p_NT_exception->ContextRecord->Ecx = regs.rcx; - p_NT_exception->ContextRecord->Edx = regs.rdx; + vm_to_nt_context(®s, p_NT_exception->ContextRecord); return EXCEPTION_CONTINUE_EXECUTION; } //NT_exception_filter diff --git vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp old mode 100644 new mode 100755 index dc4f95b..e0e5353 --- vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp +++ vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp @@ -22,19 +22,15 @@ #include "cxxlog.h" #include "method_lookup.h" #include "Environment.h" #include "exceptions.h" +#include "exceptions_jit.h" +#include "interpreter_exports.h" +#include "stack_dump.h" // Windows specific #include <string> #include <excpt.h> -// TODO - fix temporarily comment to solve win2k's lack of dbghelp.lib problem -// search for $$WIN2k for other related mods for this to undo -// -// #include <dbghelp.h> -// #include <windows.h> -// #pragma comment(linker, "/defaultlib:dbghelp.lib") - -static inline void nt_to_vm_context(PCONTEXT context, Registers* regs) +void nt_to_vm_context(PCONTEXT context, Registers* regs) { regs->eax = context->Eax; regs->ecx = context->Ecx; @@ -47,7 +43,7 @@ static inline void nt_to_vm_context(PCON regs->esp = context->Esp; } -static inline void vm_to_nt_context(Registers* regs, PCONTEXT context) +void vm_to_nt_context(Registers* regs, PCONTEXT context) { context->Esp = regs->esp; context->Eip = regs->eip; @@ -86,74 +82,15 @@ static void print_state(LPEXCEPTION_POIN fprintf(stderr, " EIP: 0x%08x\n", nt_exception->ContextRecord->Eip); } -/* todo - resolve problem for win2k $$WIN2k - -// CallStack print -#define CALLSTACK_DEPTH_LIMIT 100 // max stack length is 100 to prevent getting into loop -static void print_callstack(LPEXCEPTION_POINTERS nt_exception) -{ +static void print_callstack(LPEXCEPTION_POINTERS nt_exception) { PCONTEXT context = nt_exception->ContextRecord; - STACKFRAME StackFrm; - // initialize STACKFRAME - memset(&StackFrm, 0, sizeof(STACKFRAME)); - StackFrm.AddrPC.Offset = context->Eip; - StackFrm.AddrPC.Mode = AddrModeFlat; - StackFrm.AddrStack.Offset = context->Esp; - StackFrm.AddrStack.Mode = AddrModeFlat; - StackFrm.AddrFrame.Offset = context->Ebp; - StackFrm.AddrFrame.Mode = AddrModeFlat; - - // init sym handler for GetCurrentProcess() process - if (!SymInitialize(GetCurrentProcess(), NULL, true)) - { - fprintf(stderr, "CallStack is inaccessible due to dbghelp library initialization failed.\n"); - return; - } - fprintf(stderr, "CallStack:\n"); - - // try to go throuh the stack - for (int counter = 0; counter < CALLSTACK_DEPTH_LIMIT; counter++) - { - if (!StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &StackFrm, - context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) { - // no STACKFRAME found any more - break; - } - - // try to get function name - BYTE smBuf[sizeof(SYMBOL_INFO) + 2048]; - PSYMBOL_INFO pSymb = (PSYMBOL_INFO)smBuf; - pSymb->SizeOfStruct = sizeof(smBuf); - pSymb->MaxNameLen = 2048; - - DWORD64 funcDispl; - if (SymFromAddr(GetCurrentProcess(), StackFrm.AddrPC.Offset, &funcDispl, pSymb)) { - fprintf(stderr, " %s ", pSymb->Name); - } - else { - fprintf(stderr, " No name "); - } - - // try to get file name and line number - DWORD lineOffset; - IMAGEHLP_LINE lineInfo; - if (SymGetLineFromAddr(GetCurrentProcess(), StackFrm.AddrPC.Offset, &lineOffset, &lineInfo)) - { - fprintf(stderr, " (File: %s Line: %d )\n", lineInfo.FileName, lineInfo.LineNumber); - } - else - { - // skip functions w/o file name and line number - fprintf(stderr, " (File: ?? Line: ?? )"); - } - } - + Registers regs; + nt_to_vm_context(context, ®s); + st_print_stack(®s); fflush(stderr); } -*/ - /* * Information about stack */ @@ -274,6 +211,11 @@ static void __cdecl exception_catch_call exception_catch_callback(); } +// exception catch support for JVMTI +static void __cdecl jvmti_exception_catch_callback_wrapper(Registers regs){ + jvmti_exception_catch_callback(®s); +} + static void __declspec(naked) __stdcall naked_exception_catch_callback() { __asm { push ebp @@ -292,6 +234,35 @@ static void __declspec(naked) __stdcall } } +static void __declspec(naked) __stdcall naked_jvmti_exception_catch_callback() { + __asm { + push ebp + mov ebp, esp + add esp, -36 + mov [ebp-36], eax + mov [ebp-32], ebx + mov [ebp-28], ecx + mov [ebp-24], edx + mov eax, esp + mov ebx, [ebp] + mov ecx, [ebp+4] + add eax, 44 + mov [ebp-20], edi + mov [ebp-16], esi + mov [ebp-12], ebx + mov [ebp-8], eax + mov [ebp-4], ecx + call jvmti_exception_catch_callback_wrapper + mov eax, [ebp-36] + mov ebx, [ebp-32] + mov ecx, [ebp-28] + mov edx, [ebp-24] + add esp, 36 + leave + ret + } +} + LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) { DWORD code = nt_exception->ExceptionRecord->ExceptionCode; @@ -310,15 +281,17 @@ LONG NTAPI vectored_exception_handler(LP // exception, we first make sure the exception was thrown inside a Java // method else crash handler or default handler is executed, this means that // it was thrown by VM C/C++ code. - if ((code == STATUS_ACCESS_VIOLATION - || code == STATUS_INTEGER_DIVIDE_BY_ZERO - || code == STATUS_STACK_OVERFLOW) - && vm_identify_eip((void *)context->Eip) == VM_TYPE_JAVA) { + if (((code == STATUS_ACCESS_VIOLATION || + code == STATUS_INTEGER_DIVIDE_BY_ZERO || + code == STATUS_STACK_OVERFLOW) && + vm_identify_eip((void *)context->Eip) == VM_TYPE_JAVA) || + code == STATUS_BREAKPOINT) + { run_default_handler = false; } else if (code == STATUS_STACK_OVERFLOW) { if (is_unwindable()) { if (hythread_is_suspend_enabled()) { - hythread_suspend_disable(); + tmn_suspend_disable(); } run_default_handler = false; } else { @@ -376,8 +349,7 @@ LONG NTAPI vectored_exception_handler(LP if (!vm_get_boolean_property_value_with_default("vm.assert_dialog")) { print_state(nt_exception, msg); - // TODO fix for win2k runtime problem $$WIN2k - // print_callstack(nt_exception); + print_callstack(nt_exception); LOGGER_EXIT(-1); } @@ -385,7 +357,13 @@ LONG NTAPI vectored_exception_handler(LP } // since we are now sure HWE occured in java code, gc should also have been disabled - assert(!hythread_is_suspend_enabled()); + + // gregory - this is not true since for debugging we may use int3 + // in VM code which produces BREAKPOINT exception. JVMTI has + // assertions for breakpoints which it has set in Java inside of + // breakpoint handling function. Otherwise this assert should not + // fail in case _CrtDbgBreak() was added somewhere in VM. + assert(!hythread_is_suspend_enabled() || code == STATUS_BREAKPOINT); Global_Env *env = VM_Global_State::loader_env; Class *exc_clss = 0; @@ -422,6 +400,22 @@ LONG NTAPI vectored_exception_handler(LP exc_clss = env->java_lang_ArithmeticException_Class; } break; + case STATUS_BREAKPOINT: + // JVMTI breakpoint in JITted code + { + Registers regs; + nt_to_vm_context(context, ®s); + TRACE2("signals", "JVMTI breakpoint detected at " << + (void *)regs.eip); + bool handled = jvmti_send_jit_breakpoint_event(®s); + if (handled) + { + vm_to_nt_context(®s, context); + return EXCEPTION_CONTINUE_EXECUTION; + } + else + return EXCEPTION_CONTINUE_SEARCH; + } default: assert(false); } @@ -434,16 +428,15 @@ LONG NTAPI vectored_exception_handler(LP exn_athrow_regs(®s, exc_clss); - if (exception_esp < regs.esp) { - if (p_TLS_vmthread->restore_guard_page) { - regs.esp = regs.esp - 4; - *((uint32*) regs.esp) = regs.eip; - regs.eip = ((uint32)naked_exception_catch_callback); - } - } else { - // should be unreachable code - //jvmti_exception_catch_callback(®s); - assert(0); + assert(exception_esp <= regs.esp); + if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { + regs.esp = regs.esp - 4; + *((uint32*) regs.esp) = regs.eip; + regs.eip = ((uint32)naked_jvmti_exception_catch_callback); + } else if (p_TLS_vmthread->restore_guard_page) { + regs.esp = regs.esp - 4; + *((uint32*) regs.esp) = regs.eip; + regs.eip = ((uint32)naked_exception_catch_callback); } vm_to_nt_context(®s, context); diff --git vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp index d7e66ed..bb3f138 100644 --- vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp +++ vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp @@ -36,45 +36,45 @@ #include "exception_filter.h" // Afremov Pavel 20050117 #include "../m2n_ipf_internal.h" -static void nt_to_vm_context(LPEXCEPTION_POINTERS p_NT_exception, Registers* regs) +void nt_to_vm_context(PCONTEXT pcontext, Registers* regs) { ABORT("The function is never called"); // 20030402: This code is broken - regs->pfs = (uint64)(p_NT_exception->ContextRecord->RsPFS); - regs->ip = (uint64)(p_NT_exception->ContextRecord->StIIP); - regs->bsp = (uint64*) (p_NT_exception->ContextRecord->RsBSP); - - regs->gr[ 1] = (uint64)(p_NT_exception->ContextRecord->IntGp); - regs->gr[ 2] = (uint64)(p_NT_exception->ContextRecord->IntT0); - regs->gr[ 3] = (uint64)(p_NT_exception->ContextRecord->IntT1); - regs->gr[ 4] = (uint64)(p_NT_exception->ContextRecord->IntS0); - regs->gr[ 5] = (uint64)(p_NT_exception->ContextRecord->IntS1); - regs->gr[ 6] = (uint64)(p_NT_exception->ContextRecord->IntS2); - regs->gr[ 7] = (uint64)(p_NT_exception->ContextRecord->IntS3); - regs->gr[ 8] = (uint64)(p_NT_exception->ContextRecord->IntV0); - regs->gr[ 9] = (uint64)(p_NT_exception->ContextRecord->IntT2); - regs->gr[ 10] = (uint64)(p_NT_exception->ContextRecord->IntT3); - regs->gr[ 11] = (uint64)(p_NT_exception->ContextRecord->IntT4); - regs->gr[ 12] = (uint64)(p_NT_exception->ContextRecord->IntSp); - regs->gr[ 13] = (uint64)(p_NT_exception->ContextRecord->IntTeb); - regs->gr[ 14] = (uint64)(p_NT_exception->ContextRecord->IntT5); - regs->gr[ 15] = (uint64)(p_NT_exception->ContextRecord->IntT6); - regs->gr[ 16] = (uint64)(p_NT_exception->ContextRecord->IntT7); - regs->gr[ 17] = (uint64)(p_NT_exception->ContextRecord->IntT8); - regs->gr[ 18] = (uint64)(p_NT_exception->ContextRecord->IntT9); - regs->gr[ 19] = (uint64)(p_NT_exception->ContextRecord->IntT10); - regs->gr[ 20] = (uint64)(p_NT_exception->ContextRecord->IntT11); - regs->gr[ 21] = (uint64)(p_NT_exception->ContextRecord->IntT12); - regs->gr[ 22] = (uint64)(p_NT_exception->ContextRecord->IntT13); - regs->gr[ 23] = (uint64)(p_NT_exception->ContextRecord->IntT14); - regs->gr[ 24] = (uint64)(p_NT_exception->ContextRecord->IntT15); - regs->gr[ 25] = (uint64)(p_NT_exception->ContextRecord->IntT16); - regs->gr[ 26] = (uint64)(p_NT_exception->ContextRecord->IntT17); - regs->gr[ 27] = (uint64)(p_NT_exception->ContextRecord->IntT18); - regs->gr[ 28] = (uint64)(p_NT_exception->ContextRecord->IntT19); - regs->gr[ 29] = (uint64)(p_NT_exception->ContextRecord->IntT20); - regs->gr[ 30] = (uint64)(p_NT_exception->ContextRecord->IntT21); - regs->gr[ 31] = (uint64)(p_NT_exception->ContextRecord->IntT22); + regs->pfs = (uint64)(pcontext->RsPFS); + regs->ip = (uint64)(pcontext->StIIP); + regs->bsp = (uint64*) (pcontext->RsBSP); + + regs->gr[ 1] = (uint64)(pcontext->IntGp); + regs->gr[ 2] = (uint64)(pcontext->IntT0); + regs->gr[ 3] = (uint64)(pcontext->IntT1); + regs->gr[ 4] = (uint64)(pcontext->IntS0); + regs->gr[ 5] = (uint64)(pcontext->IntS1); + regs->gr[ 6] = (uint64)(pcontext->IntS2); + regs->gr[ 7] = (uint64)(pcontext->IntS3); + regs->gr[ 8] = (uint64)(pcontext->IntV0); + regs->gr[ 9] = (uint64)(pcontext->IntT2); + regs->gr[ 10] = (uint64)(pcontext->IntT3); + regs->gr[ 11] = (uint64)(pcontext->IntT4); + regs->gr[ 12] = (uint64)(pcontext->IntSp); + regs->gr[ 13] = (uint64)(pcontext->IntTeb); + regs->gr[ 14] = (uint64)(pcontext->IntT5); + regs->gr[ 15] = (uint64)(pcontext->IntT6); + regs->gr[ 16] = (uint64)(pcontext->IntT7); + regs->gr[ 17] = (uint64)(pcontext->IntT8); + regs->gr[ 18] = (uint64)(pcontext->IntT9); + regs->gr[ 19] = (uint64)(pcontext->IntT10); + regs->gr[ 20] = (uint64)(pcontext->IntT11); + regs->gr[ 21] = (uint64)(pcontext->IntT12); + regs->gr[ 22] = (uint64)(pcontext->IntT13); + regs->gr[ 23] = (uint64)(pcontext->IntT14); + regs->gr[ 24] = (uint64)(pcontext->IntT15); + regs->gr[ 25] = (uint64)(pcontext->IntT16); + regs->gr[ 26] = (uint64)(pcontext->IntT17); + regs->gr[ 27] = (uint64)(pcontext->IntT18); + regs->gr[ 28] = (uint64)(pcontext->IntT19); + regs->gr[ 29] = (uint64)(pcontext->IntT20); + regs->gr[ 30] = (uint64)(pcontext->IntT21); + regs->gr[ 31] = (uint64)(pcontext->IntT22); uint32 gr_cursor = 32; uint64 *bsp_cursor = regs->bsp; @@ -93,21 +93,21 @@ static void nt_to_vm_context(LPEXCEPTION } -static void vm_to_nt_context(LPEXCEPTION_POINTERS p_NT_exception, Registers* regs) +void vm_to_nt_context(Registers* regs, PCONTEXT pcontext) { ABORT("The function is never called"); // 20030402: This code is broken - p_NT_exception->ContextRecord->RsPFS = regs->pfs; - p_NT_exception->ContextRecord->StIIP = regs->ip; - p_NT_exception->ContextRecord->RsBSP = (uint64)regs->bsp; - p_NT_exception->ContextRecord->IntGp = regs->gr[ 1]; - p_NT_exception->ContextRecord->IntS0 = regs->gr[ 4]; - p_NT_exception->ContextRecord->IntS1 = regs->gr[ 5]; - p_NT_exception->ContextRecord->IntS2 = regs->gr[ 6]; - p_NT_exception->ContextRecord->IntS3 = regs->gr[ 7]; - p_NT_exception->ContextRecord->IntV0 = regs->gr[ 8]; - p_NT_exception->ContextRecord->IntSp = regs->gr[ 12]; - p_NT_exception->ContextRecord->IntTeb = regs->gr[ 13]; + pcontext->RsPFS = regs->pfs; + pcontext->StIIP = regs->ip; + pcontextRsBSP = (uint64)regs->bsp; + pcontextIntGp = regs->gr[ 1]; + pcontextIntS0 = regs->gr[ 4]; + pcontext->IntS1 = regs->gr[ 5]; + pcontext->IntS2 = regs->gr[ 6]; + pcontext->IntS3 = regs->gr[ 7]; + pcontext->IntV0 = regs->gr[ 8]; + pcontext->IntSp = regs->gr[ 12]; + pcontext->IntTeb = regs->gr[ 13]; } @@ -181,13 +181,13 @@ int NT_exception_filter(LPEXCEPTION_POIN } Registers regs; - nt_to_vm_context(p_NT_exception, ®s); + nt_to_vm_context(p_NT_exception->ContextRecord, ®s); // The exception object of class exc_clss will be created by vm_null_ptr_throw. assert(exc_clss); exn_athrow_regs(®s, exc_clss); - vm_to_nt_context(p_NT_exception, ®s); + vm_to_nt_context(®s, p_NT_exception->ContextRecord); return EXCEPTION_CONTINUE_EXECUTION; } //NT_exception_filter diff --git vm/vmcore/src/util/win/native_modules.cpp vm/vmcore/src/util/win/native_modules.cpp new file mode 100755 index 0000000..631e435 --- /dev/null +++ vm/vmcore/src/util/win/native_modules.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Petr Ivanov, Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include <memory.h> +#include <Windows.h> +#include <Tlhelp32.h> +#include "port_malloc.h" +#include "native_modules.h" + +static native_module_t* fill_module(MODULEENTRY32 src); + +bool get_all_native_modules(native_module_t** list_ptr, int* count_ptr) +{ + HANDLE hModuleSnap = INVALID_HANDLE_VALUE; + MODULEENTRY32 module; + native_module_t** cur_next_ptr = list_ptr; + int count = 0; + + hModuleSnap = + CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); + + if (hModuleSnap == INVALID_HANDLE_VALUE) + return false; + + *list_ptr = NULL; + + //It is required to set the size of the structure. + module.dwSize = sizeof(MODULEENTRY32); + if ( !Module32First(hModuleSnap, &module) ) + { + CloseHandle(hModuleSnap); + return false; + } + + do + { + native_module_t* filled = fill_module(module); + + if (!filled) + { + CloseHandle(hModuleSnap); + clear_native_modules(list_ptr); + return false; + } + + *cur_next_ptr = filled; + cur_next_ptr = &filled->next; + count++; + + } while (Module32Next(hModuleSnap, &module)); + + CloseHandle(hModuleSnap); + *count_ptr = count; + + return true; +} + +void clear_native_modules(native_module_t** list_ptr) +{ + native_module_t* cur = *list_ptr; + + while (cur) + { + native_module_t* next = cur->next; + + if (cur->filename) + STD_FREE(cur->filename); + + STD_FREE(cur); + cur = next; + } + + *list_ptr = NULL; +} + +native_module_t* fill_module(MODULEENTRY32 src) +{ + native_module_t* module = + (native_module_t*)STD_MALLOC(sizeof(native_module_t)); + + if (module == NULL) + return NULL; + + size_t path_size = strlen(src.szExePath) + 1; + module->filename = (char*)STD_MALLOC(path_size); + if (module->filename == NULL) + { + STD_FREE(module); + return NULL; + } + + memcpy(module->filename, src.szExePath, path_size); + strlwr(module->filename); + + module->seg_count = 1; + module->segments[0].type = SEGMENT_TYPE_UNKNOWN; + module->segments[0].base = src.modBaseAddr; + module->segments[0].size = (size_t)src.modBaseSize; + module->next = NULL; + + return module; +} diff --git vm/vmcore/src/util/win/nt_platform_utils.cpp vm/vmcore/src/util/win/nt_platform_utils.cpp index 16f75cc..4373896 100644 --- vm/vmcore/src/util/win/nt_platform_utils.cpp +++ vm/vmcore/src/util/win/nt_platform_utils.cpp @@ -197,135 +197,3 @@ const char *socket_strerror(int errcode) return sock_errstr1[errcode - 11001]; return NULL; } - - -VmRegisterContext::VmRegisterContext() -{ - CONTEXT *ctx = new CONTEXT; - ctx->ContextFlags = 0; - _pcontext = (void *) ctx; -} - -VmRegisterContext::~VmRegisterContext() -{ - delete (CONTEXT *) _pcontext; -} - -void VmRegisterContext::setFlag(VmRegisterContext::ContextFlag flag) -{ - unsigned old = ((CONTEXT *)_pcontext)->ContextFlags; - switch (flag) - { - case VmRegisterContext::CF_FloatingPoint: - old |= CONTEXT_FLOATING_POINT; - break; - case VmRegisterContext::CF_Integer: - old |= CONTEXT_INTEGER; - break; - case VmRegisterContext::CF_Control: - old |= CONTEXT_CONTROL; - break; - default: - ABORT("Unexpected flag"); - break; - } - ((CONTEXT *)_pcontext)->ContextFlags = old; -} - -/* FIXME integration uncomment and fix -void VmRegisterContext::getContext(VM_thread *thread) -{ - CONTEXT *ctx = (CONTEXT *) _pcontext; - BOOL stat = GetThreadContext(thread->thread_handle, ctx); - assert(stat); -#ifdef _IPF_ - thread->regs.gr[4] = ctx->IntS0; - thread->regs.gr[5] = ctx->IntS1; - thread->regs.gr[6] = ctx->IntS2; - thread->regs.gr[7] = ctx->IntS3; - thread->regs.gr[12] = ctx->IntSp; - thread->regs.preds = ctx->Preds; - thread->regs.pfs = ctx->RsPFS; - thread->regs.bsp = (uint64 *)ctx->RsBSP; - thread->regs.ip = ctx->StIIP; -#else // !_IPF_ -#ifdef _EM64T_ - thread->regs.rax = ctx->Eax; - thread->regs.rbx = ctx->Ebx; - thread->regs.rcx = ctx->Ecx; - thread->regs.rdx = ctx->Edx; - thread->regs.rdi = ctx->Edi; - thread->regs.rsi = ctx->Esi; - thread->regs.rbp = ctx->Ebp; - thread->regs.rsp = ctx->Esp; - thread->regs.rip = ctx->Eip; -#else - thread->regs.eax = ctx->Eax; - thread->regs.ebx = ctx->Ebx; - thread->regs.ecx = ctx->Ecx; - thread->regs.edx = ctx->Edx; - thread->regs.edi = ctx->Edi; - thread->regs.esi = ctx->Esi; - thread->regs.ebp = ctx->Ebp; - thread->regs.esp = ctx->Esp; - thread->regs.eip = ctx->Eip; -#endif // _EM64T_ -#endif // !_IPF_ -} - -void VmRegisterContext::setContext(VM_thread *thread) -{ - CONTEXT *ctx = (CONTEXT *) _pcontext; - BOOL stat = GetThreadContext(thread->thread_handle, ctx); - assert(stat); -#ifdef _IPF_ - ctx->IntS0 = thread->regs.gr[4]; - ctx->IntS1 = thread->regs.gr[5]; - ctx->IntS2 = thread->regs.gr[6]; - ctx->IntS3 = thread->regs.gr[7]; -#else // !_IPF_ -#ifdef _EM64T_ - ctx->Eax = thread->regs.rax; - ctx->Ebx = thread->regs.rbx; - ctx->Ecx = thread->regs.rcx; - ctx->Edx = thread->regs.rdx; - ctx->Edi = thread->regs.rdi; - ctx->Esi = thread->regs.rsi; - ctx->Ebp = thread->regs.rbp; -#else - ctx->Eax = thread->regs.eax; - ctx->Ebx = thread->regs.ebx; - ctx->Ecx = thread->regs.ecx; - ctx->Edx = thread->regs.edx; - ctx->Edi = thread->regs.edi; - ctx->Esi = thread->regs.esi; - ctx->Ebp = thread->regs.ebp; -#endif // _EM64T_ -#endif // !_IPF_ - stat = SetThreadContext(thread->thread_handle, ctx); - assert(stat); -} - -void VmRegisterContext::getBspAndRnat(VM_thread *thread, uint64 **bspstore, uint64 *rnat) -{ - CONTEXT *ctx = (CONTEXT *) _pcontext; -#ifdef _IPF_ - BOOL stat; - while ((stat = GetThreadContext(thread->thread_handle, ctx)) == 0) { - DWORD error_number = GetLastError(); - printf("Unexpected error from GetThreadContext %d\n", error_number); - // GetThreadContext should never return zero on NT - DIE("Unexpected error from GetThreadContext " << error_number); - } - *bspstore = (uint64*)ctx->RsBSPSTORE; - *rnat = ctx->RsRNAT; -#else // !_IPF_ - DIE("VmRegisterContext::getBspAndRnat shouldn't be called under IA-32"); -#endif // !_IPF_ -} - -int VM_thread::setPriority(int priority) -{ - return SetThreadPriority(thread_handle, priority); -} -*/ diff --git vm/vmcore/src/verifier/Graph.cpp vm/vmcore/src/verifier/Graph.cpp index fcd703f..8c02ccc 100644 --- vm/vmcore/src/verifier/Graph.cpp +++ vm/vmcore/src/verifier/Graph.cpp @@ -575,6 +575,7 @@ #if _VERIFY_DEBUG VERIFY_DEBUG( "Method: " << class_get_name( ctex->m_class ) << "::" << method_get_name( ctex->m_method ) << method_get_descriptor( ctex->m_method ) << endl ); + VERIFY_DEBUG( "-- start --" ); for( unsigned index = 0; index < GetNodeNumber(); index++ ) { DumpNode( index, ctex ); } @@ -609,13 +610,14 @@ #if _VERIFY_DEBUG } else if( vf_is_instruction_has_flags( &ctex->m_code[m_node[num].m_start], VF_FLAG_END_ENTRY ) ) { // end node - VERIFY_DEBUG( "node[" << num << "]: " << m_node[num].m_start << "[-] end\n" ); + VERIFY_DEBUG( "node[" << num << "]: " << m_node[num].m_start << "[-] end" ); + VERIFY_DEBUG( "-- end --" ); } else if( vf_is_instruction_has_flags( &ctex->m_code[m_node[num].m_start], VF_FLAG_HANDLER ) ) { // handler node VERIFY_DEBUG( "node[" << num << "]: " << num << "handler entry" ); } else { // another nodes - DumpNodeInternal( num, "\n", "\n", cerr, ctex ); + DumpNodeInternal( num, ctex ); } // print node outcoming edges @@ -635,15 +637,12 @@ #endif // _VERIFY_DEBUG */ void vf_Graph::DumpNodeInternal( unsigned num, // graph node number - char *next_node, // separator between nodes in stream - char *next_instr, // separator between intructions in stream - ostream &out, // output stream vf_Context_t *ctex) // verifier context { #if _VERIFY_DEBUG // print node header - out << "Node #" << num << next_node - << "Stack mod: " << m_node[num].m_stack << next_node; + VERIFY_DEBUG( "Node #" << num ); + VERIFY_DEBUG( "Stack mod: " << m_node[num].m_stack ); // get code instructions unsigned count = m_node[num].m_end - m_node[num].m_start + 1; @@ -651,9 +650,9 @@ #if _VERIFY_DEBUG // print node instructions for( unsigned index = 0; index < count; index++, instr++ ) { - out << index << ": " << ((instr->m_stack < 0) ? "[" : "[ ") + VERIFY_DEBUG( index << ": " << ((instr->m_stack < 0) ? "[" : "[ ") << instr->m_stack << "| " << instr->m_minstack << "] " - << vf_opcode_names[*(instr->m_addr)] << next_instr; + << vf_opcode_names[*(instr->m_addr)] ); } #endif // _VERIFY_DEBUG return; @@ -861,7 +860,6 @@ vf_create_graph( vf_Context_t *ctex ) nodeCount, handlcount, *code2node; - unsigned char *last_instr; vf_Code_t *code, *codeInstr; vf_Graph_t *vGraph; @@ -870,8 +868,8 @@ vf_create_graph( vf_Context_t *ctex ) /** * Get context */ - last_instr = method_get_bytecode( ctex->m_method ) - + method_get_code_length( ctex->m_method ) - 1; + unsigned char* code_end = method_get_bytecode( ctex->m_method ) + + method_get_code_length( ctex->m_method ); handlcount = method_get_exc_handler_number( ctex->m_method ); code = ctex->m_code; codeNum = ctex->m_codeNum; @@ -916,7 +914,7 @@ vf_create_graph( vf_Context_t *ctex ) } } // set last node with code segment - len = last_instr - code[last].m_addr; + len = code_end - code[last].m_addr; vGraph->SetNode( nodeCount, last, index - 1, len ); vGraph->SetNodeStackModifier( nodeCount, vf_get_node_stack_deep( &code[last], &code[index - 1] ) ); diff --git vm/vmcore/src/verifier/Verifier.cpp vm/vmcore/src/verifier/Verifier.cpp index b6a3b2f..e76064d 100644 --- vm/vmcore/src/verifier/Verifier.cpp +++ vm/vmcore/src/verifier/Verifier.cpp @@ -18,8 +18,10 @@ * @version $Revision: 1.1.2.3.4.4 $ */ +#include <limits.h> #include "ver_real.h" + /** * Debug flag macros */ @@ -322,88 +324,89 @@ vf_get_instruction_branch( vf_Instr_t *c } // vf_get_instruction_branch /** - * Function receives 2 bytes instruction branch offset value from bytecode array. + * Function receives half word (2 bytes) instruction branch offset + * value from bytecode array. */ static inline int -vf_get_word_offset( unsigned instr_num, // instruction offset in bytecode array - unsigned char *bytecode, // bytecode array - unsigned *index_p) // offset index in bytecode array +vf_get_hword_offset( unsigned code_pc, // instruction offset in bytecode array + unsigned char *bytecode, // bytecode array + unsigned *index_p) // offset index in bytecode array { // get first branch offset - int offset = (int)instr_num + int offset = (int)code_pc + (short)( (bytecode[(*index_p)] << 8)|(bytecode[(*index_p) + 1]) ); // skip parameter (s2) (*index_p) += 2; return offset; -} // vf_get_2word_offset +} // vf_get_hword_offset /** - * Function receives 4 bytes instruction branch offset value from bytecode array. + * Function receives word (4 bytes) instruction branch offset value from bytecode array. */ static inline int -vf_get_2word_offset( unsigned instr_num, // instruction offset in bytecode array - unsigned char *bytecode, // bytecode array - unsigned *index_p) // offset index in bytecode array +vf_get_word_offset( unsigned code_pc, // instruction offset in bytecode array + unsigned char *bytecode, // bytecode array + unsigned *index_p) // offset index in bytecode array { // get switch branch offset - int offset = (int)instr_num + int offset = (int)code_pc + (int)( (bytecode[(*index_p)] << 24)|(bytecode[(*index_p) + 1] << 16) |(bytecode[(*index_p) + 2] << 8)|(bytecode[(*index_p) + 3] ) ); // skip parameter (s4) (*index_p) += 4; return offset; -} // vf_get_2word_offset +} // vf_get_word_offset /** - * Function receives 2 bytes branch offset from bytecode array, + * Function receives half word (2 bytes) branch offset from bytecode array, * sets into instruction and returns it. */ static inline int -vf_get_single_branch_offset( vf_Instr_t *code, // instruction - unsigned instr_num, // instruction offset in bytecode array - unsigned char *bytecode, // bytecode array - unsigned *index_p, // offset index in bytecode array - vf_VerifyPool_t * pool) // memory pool +vf_get_single_hword_branch_offset( vf_Instr_t *code, // instruction + unsigned code_pc, // offset in bytecode array + unsigned char *bytecode, // bytecode array + unsigned *index_p, // offset index in bytecode array + vf_VerifyPool_t * pool) // memory pool { // get first branch offset - int offset = vf_get_word_offset( instr_num, bytecode, index_p ); + int offset = vf_get_hword_offset( code_pc, bytecode, index_p ); // create and set edge branch for instruction vf_set_single_instruction_offset( code, offset, pool ); return offset; -} // vf_get_single_branch_offset +} // vf_get_single_hword_branch_offset /** - * Function receives 4 bytes branch offset from bytecode array, + * Function receives word (4 bytes) branch offset from bytecode array, * sets into instruction and returns it. */ static inline int -vf_get_single_2word_branch_offset( vf_Instr_t *code, // instruction - unsigned instr_num, // offset in bytecode array - unsigned char *bytecode, // bytecode array - unsigned *index_p, // offset index in bytecode array - vf_VerifyPool_t * pool) // memory pool +vf_get_single_word_branch_offset( vf_Instr_t *code, // instruction + unsigned code_pc, // offset in bytecode array + unsigned char *bytecode, // bytecode array + unsigned *index_p, // offset index in bytecode array + vf_VerifyPool_t * pool) // memory pool { // get first branch offset - int offset = vf_get_2word_offset( instr_num, bytecode, index_p ); + int offset = vf_get_word_offset( code_pc, bytecode, index_p ); // create and set edge branch for instruction vf_set_single_instruction_offset( code, offset, pool ); return offset; -} // vf_get_single_2word_branch_offset +} // vf_get_single_word_branch_offset /** - * Function receives 2 bytes branch offset from bytecode array and + * Function receives half word (2 bytes) branch offset from bytecode array and * sets reseived offset and next instruction offset into instruction. * Function returns recieved offset. */ static inline int vf_get_double_branch_offset( vf_Instr_t *code, // instruction - unsigned instr_num, // instruction offset in bytcode array + unsigned code_pc, // instruction offset in bytcode array unsigned char *bytecode, // bytecode array unsigned *index_p, // offset index in bytecode array vf_VerifyPool_t *pool) // memory pool { // get first branch offset - int offset = vf_get_word_offset( instr_num, bytecode, index_p ); + int offset = vf_get_hword_offset( code_pc, bytecode, index_p ); // create and set edge branchs for instruction vf_create_instruction_offset( code, 2, pool ); // set first edge branch for instruction @@ -420,13 +423,13 @@ vf_get_double_branch_offset( vf_Instr_t */ static inline int vf_get_tableswitch_alternative( vf_Instr_t *code, // instruction - unsigned instr_num, // offset in bytcode array + unsigned code_pc, // offset in bytcode array unsigned alternative, // number of tableswitch branch unsigned char *bytecode, // bytecode array unsigned *index_p) // offset index in bytecode array { // get first branch offset - int offset = vf_get_2word_offset( instr_num, bytecode, index_p ); + int offset = vf_get_word_offset( code_pc, bytecode, index_p ); // set first edge branch for instruction vf_set_instruction_offset( code, alternative, offset ); return offset; @@ -439,10 +442,10 @@ vf_get_tableswitch_alternative( vf_Instr */ static inline int vf_set_tableswitch_offsets( vf_Instr_t *code, // instruction - unsigned instr_num, // instruction offset in bytcode array - unsigned char *bytecode, // bytecode array + unsigned code_pc, // instruction offset in bytecode array unsigned *index_p, // offset index in bytecode array - vf_VerifyPool_t * pool) // memory pool + unsigned char *bytecode, // bytecode array + vf_VerifyPool_t *pool) // memory pool { // skip padding unsigned default_off = ((*index_p) + 0x3)&(~0x3U); @@ -450,16 +453,16 @@ vf_set_tableswitch_offsets( vf_Instr_t * // skip default offset index += 4; // get low and high tableswitch values - int low = vf_get_2word_offset( instr_num, bytecode, &index ); - int high = vf_get_2word_offset( instr_num, bytecode, &index ); + int low = vf_get_word_offset( code_pc, bytecode, &index ); + int high = vf_get_word_offset( code_pc, bytecode, &index ); int number = high - low + 2; // create tableswitch branches vf_create_instruction_offset( code, number, pool ); // set default offset - vf_get_tableswitch_alternative( code, instr_num, 0, bytecode, &default_off ); + vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off ); // set another instruction offsets for( int count = 1; count < number; count++ ) { - vf_get_tableswitch_alternative( code, instr_num, count, bytecode, + vf_get_tableswitch_alternative( code, code_pc, count, bytecode, &index ); } // set index next instruction @@ -472,12 +475,13 @@ vf_set_tableswitch_offsets( vf_Instr_t * * sets them into instruction. * Function returns number of alternatives. */ -static inline int -vf_set_lookupswitch_offsets( vf_Instr_t *code, - unsigned instr_num, - unsigned char *bytecode, - unsigned *index_p, - vf_VerifyPool_t * pool) +static inline Verifier_Result +vf_set_lookupswitch_offsets( vf_Instr_t *code, // inctruction + unsigned code_pc, // instruction offset in bytecode + unsigned *index_p, // offset index in bytecode array + unsigned char *bytecode, // array of bytecode + unsigned *branch_p, // number of alternatives + vf_Context_t *ctex) // verifier context { // skip padding unsigned default_off = ((*index_p) + 0x3)&(~0x3U); @@ -485,21 +489,33 @@ vf_set_lookupswitch_offsets( vf_Instr_t // skip default offset index += 4; // get alternative number of lookupswitch (add default alternative) - int number = vf_get_2word_offset( 0, bytecode, &index ) + 1; + int number = vf_get_word_offset( 0, bytecode, &index ) + 1; + *branch_p = number; // create and tableswitch branches - vf_create_instruction_offset( code, number, pool ); + vf_create_instruction_offset( code, number, ctex->m_pool ); // set default offset - vf_get_tableswitch_alternative( code, instr_num, 0, bytecode, &default_off ); + vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off ); // set another instruction offsets + int old_key = INT_MIN; for( int count = 1; count < number; count++ ) { - // skip branch key value - index += 4; - vf_get_tableswitch_alternative( code, instr_num, count, bytecode, + // get and check branch key value + int key = vf_get_word_offset( 0, bytecode, &index ); + if( old_key < key ) { + old_key = key; + } else if( key != INT_MIN ) { + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( ctex->m_method ) + << method_get_descriptor( ctex->m_method ) + << ") Instruction lookupswitch has unsorted key values" ); + return VER_ErrorInstruction; + } + // get lookupswitch alternative and set offset to instruction + vf_get_tableswitch_alternative( code, code_pc, count, bytecode, &index ); } // set index next instruction (*index_p) = index; - return number; + return VER_OK; } // vf_set_lookupswitch_offsets /************************************************************ @@ -560,17 +576,6 @@ vf_set_vector_type( vf_MapEntry_t *vecto } // vf_set_vector_type /** - * Function sets a given data type to stack map vector entry. - */ -static inline void -vf_set_vector_init_flag( vf_MapEntry_t *vector, // stack map vector - unsigned num, // vector entry number - unsigned short init_flag) // reference initialization flag -{ - vector[num].m_need_init = init_flag; -} // vf_set_vector_type - -/** * Function sets null data type for given stack map vector entry. */ static inline void @@ -1361,7 +1366,6 @@ vf_set_description_vector( const char *d do { index++; } while( descr[index] != ';' ); - vf_set_vector_init_flag( *vector, vector_index, 1 ); if( !array ) { // set vector reference entry valid = ctex->m_type->NewType( type, index - count ); @@ -1661,7 +1665,6 @@ vf_check_cp_method( unsigned short index cp_parse->method.m_inlen += 1; vf_ValidType_t *type = vf_create_class_valid_type( class_name, ctex ); vf_set_vector_stack_entry_ref( cp_parse->method.m_invector, 0, type ); - vf_set_vector_init_flag( cp_parse->method.m_invector, 0, 1 ); } else { vf_set_description_vector( descr, cp_parse->method.m_inlen, 0 /* only vector */, cp_parse->method.m_outlen, &cp_parse->method.m_invector, @@ -1706,8 +1709,6 @@ vf_check_cp_field( unsigned short index, cp_parse->field.f_vlen += 1; vf_ValidType_t *type = vf_create_class_valid_type( class_name, ctex ); vf_set_vector_stack_entry_ref( cp_parse->field.f_vector, 0, type ); - // uninitialized this could be used for putfield/getfield - vf_set_vector_init_flag( cp_parse->field.f_vector, 0, 2 ); } else { vf_set_description_vector( descr, cp_parse->field.f_vlen, 0 /* only vector */, 0, &cp_parse->field.f_vector, NULL, ctex); @@ -2071,6 +2072,7 @@ vf_opcode_aloadx( vf_Code_t *code, // create in vector vf_new_in_vector( code, 1, pool ); vf_set_in_vector_local_var_ref( code, 0, NULL, local ); + vf_set_vector_check( code->m_invector, 0, VF_CHECK_UNINITIALIZED_THIS ); // create out vector vf_new_out_vector( code, 1, pool ); vf_set_out_vector_type( code, 0, SM_COPY_0 ); @@ -2370,6 +2372,7 @@ vf_opcode_astorex( vf_Code_t *code, // create in vector vf_new_in_vector( code, 1, pool ); vf_set_in_vector_stack_entry_ref( code, 0, NULL ); + vf_set_vector_check( code->m_invector, 0, VF_CHECK_UNINITIALIZED_THIS ); // create out vector vf_new_out_vector( code, 1, pool ); vf_set_out_vector_local_var_type( code, 0, SM_COPY_0, local ); @@ -4242,9 +4245,7 @@ vf_parse_bytecode( vf_Context_t *ctex ) constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_ldcx( code, - (bytecode[instr] == OPCODE_LDC_W ? 1 : 2), - constIndex, ctex ); + result = vf_opcode_ldcx( code, bytecode[instr] - OPCODE_LDC, constIndex, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } @@ -4700,7 +4701,7 @@ vf_parse_bytecode( vf_Context_t *ctex ) &codeInstr[index], pool ); break; case OPCODE_GOTO: /* 0xa7 + s2 */ - offset = vf_get_single_branch_offset( &codeInstr[instr], + offset = vf_get_single_hword_branch_offset( &codeInstr[instr], instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -4724,7 +4725,7 @@ vf_parse_bytecode( vf_Context_t *ctex ) case OPCODE_TABLESWITCH: /* 0xaa + pad + s4 * (3 + N) */ vf_opcode_switch( code, pool ); branches = vf_set_tableswitch_offsets( &codeInstr[instr], - instr, bytecode, &index, pool); + instr, &index, bytecode, pool); // check tableswitch branches and set begin of basic blocks for( count = 0; count < branches; count++ ) { @@ -4741,8 +4742,11 @@ vf_parse_bytecode( vf_Context_t *ctex ) break; case OPCODE_LOOKUPSWITCH: /* 0xab + pad + s4 * 2 * (N + 1) */ vf_opcode_switch( code, pool ); - branches = vf_set_lookupswitch_offsets( &codeInstr[instr], - instr, bytecode, &index, pool); + result = vf_set_lookupswitch_offsets( &codeInstr[instr], + instr, &index, bytecode, &branches, ctex); + if( result != VER_OK ) { + goto labelEnd_vf_parse_bytecode; + } // check tableswitch branches and set begin of basic blocks for( count = 0; count < branches; count++ ) { @@ -4994,7 +4998,7 @@ vf_parse_bytecode( vf_Context_t *ctex ) &codeInstr[index], pool ); break; case OPCODE_GOTO_W: /* 0xc8 + s4 */ - offset = vf_get_single_2word_branch_offset( &codeInstr[instr], + offset = vf_get_single_word_branch_offset( &codeInstr[instr], instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -5119,6 +5123,20 @@ vf_parse_bytecode( vf_Context_t *ctex ) } } + // set constraints for class exceptions a method can throw + count = method_get_number_exc_method_can_throw( ctex->m_method ); + for( index = 0; index < count; index++ ) { + // create valid type for exception class + const char* name = method_get_exc_method_can_throw( ctex->m_method, index ); + vf_ValidType_t *type = vf_create_class_valid_type( name, ctex ); + + // set restriction for handler class + if( ctex->m_vtype.m_throwable->string[0] != type->string[0] ) { + ctex->m_type->SetRestriction( ctex->m_vtype.m_throwable->string[0], + type->string[0], 0, VF_CHECK_SUPER ); + } + } + /** * Initialize basic block count * Include start-entry basic block, handler basic blocks, @@ -5300,6 +5318,8 @@ #endif // VERIFY_CLASS context.m_vtype.m_throwable = context.m_type->NewType( "Ljava/lang/Throwable", 20 ); context.m_vtype.m_object = context.m_type->NewType( "Ljava/lang/Object", 17 ); context.m_vtype.m_array = context.m_type->NewType( "[Ljava/lang/Object", 18 ); + context.m_vtype.m_clone = context.m_type->NewType( "Ljava/lang/Cloneable", 20 ); + context.m_vtype.m_serialize = context.m_type->NewType( "Ljava/io/Serializable", 21 ); /** * Set verification level flag diff --git vm/vmcore/src/verifier/ver_dataflow.cpp vm/vmcore/src/verifier/ver_dataflow.cpp index 2b078bf..ce7eb97 100644 --- vm/vmcore/src/verifier/ver_dataflow.cpp +++ vm/vmcore/src/verifier/ver_dataflow.cpp @@ -436,7 +436,6 @@ vf_check_access(vf_MapEntry_t *source, static inline Verifier_Result vf_check_entry_refs( vf_MapEntry_t *source, // stack map entry vf_MapEntry_t *target, // required map entry - unsigned short init_flag, // source initialization flag vf_Context_t *ctex) // verifier context { // check entries type @@ -457,10 +456,14 @@ vf_check_entry_refs( vf_MapEntry_t *sour return VER_OK; } // check initialization - if( source->m_type == SM_UNINITIALIZED ) { - if( init_flag == 2 && !source->m_new ) { + if( source->m_type == SM_UNINITIALIZED && target->m_type != SM_UNINITIALIZED) { + if( source->m_new == 0 // SM_UNINITIALIZED_THIS + && (target->m_ctype == VF_CHECK_UNINITIALIZED_THIS // astore/aload + || target->m_ctype == VF_CHECK_ACCESS_FIELD ) ) // putfield/getfield + { // uninitialized this could be used in getfield/putfield - } else if( init_flag ) { + // and aload/astore instructions + } else { VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) << ", method: " << method_get_name( ctex->m_method ) << method_get_descriptor( ctex->m_method ) @@ -474,7 +477,8 @@ vf_check_entry_refs( vf_MapEntry_t *sour switch( target->m_ctype ) { case VF_CHECK_NONE: - case VF_CHECK_PARAM: // check method invocation convertion + case VF_CHECK_UNINITIALIZED_THIS: + case VF_CHECK_PARAM: // check method invocation convertion if( target->m_vtype != NULL ) { is_error = ctex->m_type->CheckTypes( target->m_vtype, source->m_vtype, 0, VF_CHECK_PARAM ); @@ -538,8 +542,7 @@ vf_check_entry_types( vf_MapEntry_t *ent case SM_REF: // check reference entries { - Verifier_Result result = vf_check_entry_refs( entry1, entry2, - entry2->m_need_init, ctex ); + Verifier_Result result = vf_check_entry_refs( entry1, entry2, ctex ); *need_copy = true; return result; } @@ -783,18 +786,15 @@ vf_check_instruction_in_vector( vf_MapEn // check reference array element assert( index > 0 ); newvector = &buf[index]; - if( ctex->m_dump.m_verify ) { - // check is in progress if full verification flag is set - // check assignment conversion - vf_set_array_element_type( newvector, vector, &buf[0], ctex ); + // check assignment conversion + vf_set_array_element_type( newvector, vector, &buf[0], ctex ); + if( newvector->m_vtype ) { newvector->m_ctype = VF_CHECK_ASSIGN_WEAK; } else { - // check if stored element is reference - newvector->m_type = SM_REF; - newvector->m_vtype = NULL; + newvector->m_ctype = VF_CHECK_NONE; } // check entry types - result = vf_check_entry_refs( entry, newvector, 1, ctex ); + result = vf_check_entry_refs( entry, newvector, ctex ); if( result != VER_OK ) { VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) << ", method: " << method_get_name( ctex->m_method ) @@ -805,19 +805,21 @@ vf_check_instruction_in_vector( vf_MapEn break; case SM_REF: // check entry references - result = vf_check_entry_refs( entry, vector, vector->m_need_init, ctex ); + result = vf_check_entry_refs( entry, vector, ctex ); if( result != VER_OK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Data flow analysis error (uninitialized)" ); + if( !ctex->m_error ) { + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( ctex->m_method ) + << method_get_descriptor( ctex->m_method ) + << ") Data flow analysis error" ); + } return result; } copy = true; break; case SM_UNINITIALIZED: // check entry references - if( entry->m_type != SM_UNINITIALIZED ) { + if( entry->m_type == SM_REF ) { // double initialization VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) << ", method: " << method_get_name( ctex->m_method ) @@ -825,7 +827,7 @@ vf_check_instruction_in_vector( vf_MapEn << ") Double initialization of object reference" ); return VER_ErrorDataFlow; } - result = vf_check_entry_refs( entry, vector, 0, ctex ); + result = vf_check_entry_refs( entry, vector, ctex ); if( result != VER_OK ) { VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) << ", method: " << method_get_name( ctex->m_method ) @@ -834,7 +836,7 @@ vf_check_instruction_in_vector( vf_MapEn return result; } // check initialization class in constructor - if( entry->m_new == 0 ) { + if( entry->m_type == SM_UNINITIALIZED && entry->m_new == 0 ) { // initialization of this reference in class construction assert( entry->m_vtype->number == 1 ); if( vector->m_vtype->string[0] != entry->m_vtype->string[0] ) { diff --git vm/vmcore/src/verifier/ver_real.h vm/vmcore/src/verifier/ver_real.h index 605a5cd..fdf2a40 100644 --- vm/vmcore/src/verifier/ver_real.h +++ vm/vmcore/src/verifier/ver_real.h @@ -234,6 +234,7 @@ typedef enum { VF_CHECK_ACCESS_METHOD, VF_CHECK_DIRECT_SUPER, VF_CHECK_INVOKESPECIAL, + VF_CHECK_UNINITIALIZED_THIS, VF_CHECK_NUM } vf_CheckConstraint_t; @@ -271,7 +272,7 @@ typedef enum { * Code instruction flags enum. */ typedef enum { - VF_FLAG_NONE, + VF_FLAG_NONE = 0, VF_FLAG_BEGIN_BASIC_BLOCK = 1, VF_FLAG_START_ENTRY = 2, VF_FLAG_END_ENTRY = 4, @@ -342,10 +343,6 @@ typedef struct { }; unsigned short m_type : 5; ///< stack map type @see vf_MapType_t unsigned short m_ctype : 4; ///< constraint type @see vf_CheckConstraint_t - unsigned short m_need_init : 2; ///< initialization flag - ///< 0 - reference can be uninitialized - ///< 1 - reference must be init - ///< 2 - reference can be uninitialized this unsigned short m_is_local : 1; ///< local variable modify flag ///< true - modify local, false - modify stack } vf_MapEntry_t; @@ -754,18 +751,12 @@ public: /** * Function prints graph node instruction in stream. * @param node_num - number of graph node - * @param next_node - separator between nodes in stream - * @param next_instr - separator between intructions in stream - * @param out - output stream * @param context - current verifier context * @note Function is valid in debug mode. * @note Assertion is raised if <i>node_num</i> is out of range. * @see vf_Context_t */ void DumpNodeInternal( unsigned node_num, - char *next_node, - char *next_instr, - ostream &out, vf_Context_t *context); /** @@ -1121,6 +1112,8 @@ public: vf_ValidType_t *m_throwable; ///< context java/lang/Throwable valid type vf_ValidType_t *m_object; ///< context java/lang/Object valid type vf_ValidType_t *m_array; ///< context [Ljava/lang/Object; valid type + vf_ValidType_t *m_clone; ///< context java/lang/Cloneable valid type + vf_ValidType_t *m_serialize; ///< context java/io/Serializable valid type } m_vtype; /** diff --git vm/vmcore/src/verifier/ver_utils.cpp vm/vmcore/src/verifier/ver_utils.cpp index 90263b0..04b512f 100644 --- vm/vmcore/src/verifier/ver_utils.cpp +++ vm/vmcore/src/verifier/ver_utils.cpp @@ -755,11 +755,7 @@ vf_is_param_valid( class_handler source, class_handler target) // required class { // check if target class is array - if( class_is_array( target ) ) { - if( !class_is_array( source ) ) { - // source class must be array too - return false; - } + if( class_is_array( target ) && class_is_array( source ) ) { // get array element classes return vf_is_param_valid( class_get_array_element_class( source ), class_get_array_element_class( target )); @@ -937,15 +933,15 @@ vf_is_assign_valid( class_handler source // source class is array if( class_is_interface_( target ) ) { // target class is interface - if( !strcmp( class_get_name( target ), "java/lang/Cloneable" ) - || !strcmp( class_get_name( target ), "java/io/Serializable" ) ) + if( !memcmp( class_get_name( target ), "java/lang/Cloneable", 20 ) + || !memcmp( class_get_name( target ), "java/io/Serializable", 21 ) ) { // target class is Cloneable or Serializable return true; } } else { // target class is class - if( !strcmp( class_get_name( target ), "java/lang/Object" ) ) { + if( !memcmp( class_get_name( target ), "java/lang/Object", 17 ) ) { // target class is object return true; } else if ( class_is_array( target ) ) { @@ -962,7 +958,7 @@ vf_is_assign_valid( class_handler source return vf_is_super_interface( source, target ); } else { // target class is class - if( !strcmp( class_get_name( target ), "java/lang/Object" ) ) { + if( !memcmp( class_get_name( target ), "java/lang/Object", 17 ) ) { // target class is object return true; } @@ -1011,19 +1007,10 @@ vf_is_valid( class_handler source, return class_is_same_class( class_get_super_class( source ), target ); case VF_CHECK_ACCESS_FIELD: // protected field access case VF_CHECK_ACCESS_METHOD: // protected method acceess - if( class_is_same_package( source, current ) - || vf_is_super_class( source, current ) ) - { - return true; - } - return false; - case VF_CHECK_INVOKESPECIAL: - if( vf_is_super_class( source, current ) - && vf_is_super_class( current, target ) ) - { - return true; - } - return false; + return vf_is_super_class( source, current ); + case VF_CHECK_INVOKESPECIAL: // check object for invokespecial instruction + return vf_is_super_class( source, current ) + && vf_is_super_class( current, target ); default: DIE( "Verifier: vf_is_valid: invalid check type" ); return false; @@ -1033,6 +1020,71 @@ vf_is_valid( class_handler source, } // vf_is_valid /** + * Sets verifier error. + */ +static inline void +vf_set_error( method_handler method, // failed method + unsigned check, // failed check + vf_Context_t *ctex) // verifier context +{ + switch( check ) + { + case VF_CHECK_PARAM: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Incompatible argument for function" ); + break; + case VF_CHECK_ASSIGN: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Incompatible types for field assignment" ); + break; + case VF_CHECK_ASSIGN_WEAK: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Incompatible types for array assignment" ); + break; + case VF_CHECK_SUPER: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Exception class not a subclass of Throwable" ); + break; + case VF_CHECK_ACCESS_FIELD: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Bad access to protected field" ); + break; + case VF_CHECK_ACCESS_METHOD: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Bad access to protected method" ); + break; + case VF_CHECK_DIRECT_SUPER: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Call to wrong initialization method" ); + break; + case VF_CHECK_INVOKESPECIAL: + VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) + << ", method: " << method_get_name( method ) + << method_get_descriptor( method ) + << ") Incompatible object argument for invokespecial" ); + break; + default: + DIE( "Verifier: vf_set_error: unknown check type" ); + break; + } + return; +} // vf_set_error + +/** * Checks some constraints without loading of needed classes. */ static inline Verifier_Result @@ -1074,8 +1126,39 @@ vf_check_without_loading( vf_TypeConstra // no need to check return VER_OK; } + + /** + * Extension for java/lang/Cloneable and java/io/Serializable + * interfaces doesn't check because it's expected all arrays extend it. + * Just check is source array. + */ + if( (restriction->target == ctex->m_vtype.m_clone->string[0] + || restriction->target == ctex->m_vtype.m_serialize->string[0]) + && restriction->source[0] == '[' ) + { + // no need to check + return VER_OK; + } + + /** + * If method invocation conversion takes place between array and + * non-array reference, return error. + */ + if( (restriction->target[0] != '[' && restriction->source[0] == '[') + || (restriction->target[0] != '[' && restriction->source[0] == '[') ) + { + vf_set_error( ctex->m_method, VF_CHECK_PARAM, ctex ); + return VER_ErrorIncompatibleArgument; + } break; + case VF_CHECK_ASSIGN_WEAK: + // check assignment weak reference conversions + if( restriction->source[0] == 'L' ) { + return VER_OK; + } + assert(restriction->source[0] == '['); + // go to the next check... case VF_CHECK_ASSIGN: // check assignment reference conversions if( restriction->source[0] == '[' ) { @@ -1091,10 +1174,7 @@ vf_check_without_loading( vf_TypeConstra return VER_OK; } else if ( restriction->target[0] != '[' ) { // target class isn't array class - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible types for field assignment" ); + vf_set_error( ctex->m_method, restriction->check_type, ctex ); return VER_ErrorIncompatibleArgument; } } @@ -1140,57 +1220,7 @@ vf_check_constraint( vf_TypeConstraint_t // check restriction if( !vf_is_valid( source, target, ctex->m_class, restriction->check_type ) ) { // return error - switch( restriction->check_type ) - { - case VF_CHECK_PARAM: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible argument for function" ); - break; - case VF_CHECK_ASSIGN: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible types for field assignment" ); - break; - case VF_CHECK_ASSIGN_WEAK: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible types for array assignment" ); - break; - case VF_CHECK_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Exception class not a subclass of Throwable" ); - break; - case VF_CHECK_ACCESS_FIELD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Bad access to protected field" ); - break; - case VF_CHECK_ACCESS_METHOD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Bad access to protected method" ); - break; - case VF_CHECK_DIRECT_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Call to wrong initialization method" ); - break; - default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible argument" ); - break; - } + vf_set_error( ctex->m_method, restriction->check_type, ctex ); return VER_ErrorIncompatibleArgument; } return VER_OK; @@ -1216,6 +1246,13 @@ vf_check_access_constraint( const char * return VER_OK; } + // check if a class and a parent class is in the same package + if( class_is_same_package( ctex->m_class, super_class ) ) { + // class and parent class is in the same package, + // no need check access to protect members + return VER_OK; + } + // check is a member protected bool need_check = false; if( check_type == VF_CHECK_ACCESS_FIELD ) { @@ -1262,26 +1299,9 @@ vf_check_access_constraint( const char * } // check access constraint - if( !vf_is_valid( instance, NULL, ctex->m_class, check_type ) ) - { + if( !vf_is_valid( instance, NULL, ctex->m_class, check_type ) ) { // return error - switch( check_type ) - { - case VF_CHECK_ACCESS_FIELD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Bad access to protected field" ); - break; - case VF_CHECK_ACCESS_METHOD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Bad access to protected method" ); - break; - default: - vf_error(); - } + vf_set_error( ctex->m_method, check_type, ctex ); return VER_ErrorIncompatibleArgument; } return VER_OK; @@ -1367,6 +1387,16 @@ vf_force_check_constraint( vf_TypeConstr return VER_ErrorLoadClass; } + // check if constraint is already verified + if( constraint->check_type == VF_CHECK_NONE ) { + // already verified + VERIFY_TRACE( "constraint.checked", "verify constraint: have \"" + << constraint->source << "\" need \"" << constraint->target + << "\" already done (check #2) for class " + << class_get_name( ctex->m_class ) ); + return VER_OK; + } + /** * Verifier which is built on Java VM Specification 2nd Edition (4.9.2) * recommendation of verification proccess doesn't check interfaces usage. @@ -1375,7 +1405,9 @@ vf_force_check_constraint( vf_TypeConstr * checks only if -Xverify option is present in command line. */ if( !ctex->m_dump.m_verify && class_is_interface_( target ) ) { - // no need to check + // skip constraint check + // reset constraint to successful + constraint->check_type = VF_CHECK_NONE; return VER_OK; } @@ -1384,7 +1416,7 @@ vf_force_check_constraint( vf_TypeConstr // already verified VERIFY_TRACE( "constraint.checked", "verify constraint: have \"" << constraint->source << "\" need \"" << constraint->target - << "\" already done (check #2) for class " + << "\" already done (check #3) for class " << class_get_name( ctex->m_class ) ); return VER_OK; } @@ -1407,7 +1439,7 @@ vf_force_check_constraint( vf_TypeConstr return VER_ErrorLoadClass; } - // store constraint check type (it could be changed during loading classes) + // store constraint check type (it could be changed during validation check) vf_CheckConstraint_t check = (vf_CheckConstraint_t)constraint->check_type; // check if constraint is already verified @@ -1415,69 +1447,18 @@ vf_force_check_constraint( vf_TypeConstr // already verified VERIFY_TRACE( "constraint.checked", "verify constraint: have \"" << constraint->source << "\" need \"" << constraint->target - << "\" already done (check #3) for class " + << "\" already done (check #4) for class " << class_get_name( ctex->m_class ) ); return VER_OK; } // check restriction - if( !vf_is_valid( source, target, ctex->m_class, check ) ) - { - switch( check ) - { - case VF_CHECK_PARAM: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Incompatible argument for function" ); - break; - case VF_CHECK_ASSIGN: - VERIFY_DEBUG( "has " << constraint->source << " need " << constraint->target ); - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Incompatible types for field assignment" ); - break; - case VF_CHECK_ASSIGN_WEAK: - VERIFY_DEBUG( "has " << constraint->source << " need " << constraint->target ); - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Incompatible types for array assignment" ); - break; - case VF_CHECK_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Exception class not a subclass of Throwable" ); - break; - case VF_CHECK_ACCESS_FIELD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Bad access to protected field" ); - break; - case VF_CHECK_ACCESS_METHOD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Bad access to protected method" ); - break; - case VF_CHECK_DIRECT_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Call to wrong initialization method" ); - break; - default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( constraint->method ) - << method_get_descriptor( constraint->method ) - << ") Incompatible argument" ); - break; - } + if( !vf_is_valid( source, target, ctex->m_class, check ) ) { + // return error + vf_set_error( constraint->method, check, ctex ); return VER_ErrorIncompatibleArgument; } + // reset constraint to successful constraint->check_type = VF_CHECK_NONE; return VER_OK; } // vf_force_check_constraint diff --git vm/vmstart/src/compmgr/component_manager_impl.cpp vm/vmstart/src/compmgr/component_manager_impl.cpp index 6db50c4..9daf8a9 100644 --- vm/vmstart/src/compmgr/component_manager_impl.cpp +++ vm/vmstart/src/compmgr/component_manager_impl.cpp @@ -702,6 +702,7 @@ CmLoadComponent(const char* path, int ret = LoadLib(&lib, path); if (APR_SUCCESS != ret) { PORT_VERIFY_SUCCESS(apr_thread_rwlock_unlock(global_lock)); + printf("failed to load: %d %s\n", ret, path); return ret; } @@ -711,6 +712,7 @@ CmLoadComponent(const char* path, /* Ignore error */ ReleaseLib(lib); PORT_VERIFY_SUCCESS(apr_thread_rwlock_unlock(global_lock)); + printf("failed to init: %d\n", ret); return ret; }