Path: blob/master/runtime/compiler/il/J9MethodSymbol.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "compile/Compilation.hpp"23#include "env/TRMemory.hpp"24#include "il/DataTypes.hpp"25#include "il/MethodSymbol.hpp"26#include "infra/Assert.hpp"27#include "runtime/J9Runtime.hpp"2829/**30* Return true if this method is pure ie no side-effects.31*32* Currently only runtime helpers and recognized methods can be true.33*/34bool35J9::MethodSymbol::isPureFunction()36{37switch(self()->getRecognizedMethod())38{39case TR::java_lang_Math_abs_I:40case TR::java_lang_Math_abs_L:41case TR::java_lang_Math_abs_F:42case TR::java_lang_Math_abs_D:43case TR::java_lang_Math_acos:44case TR::java_lang_Math_asin:45case TR::java_lang_Math_atan:46case TR::java_lang_Math_atan2:47case TR::java_lang_Math_cbrt:48case TR::java_lang_Math_ceil:49case TR::java_lang_Math_copySign_F:50case TR::java_lang_Math_copySign_D:51case TR::java_lang_Math_cos:52case TR::java_lang_Math_cosh:53case TR::java_lang_Math_exp:54case TR::java_lang_Math_expm1:55case TR::java_lang_Math_floor:56case TR::java_lang_Math_hypot:57case TR::java_lang_Math_IEEEremainder:58case TR::java_lang_Math_log:59case TR::java_lang_Math_log10:60case TR::java_lang_Math_log1p:61case TR::java_lang_Math_max_I:62case TR::java_lang_Math_max_L:63case TR::java_lang_Math_max_F:64case TR::java_lang_Math_max_D:65case TR::java_lang_Math_min_I:66case TR::java_lang_Math_min_L:67case TR::java_lang_Math_min_F:68case TR::java_lang_Math_min_D:69case TR::java_lang_Math_nextAfter_F:70case TR::java_lang_Math_nextAfter_D:71case TR::java_lang_Math_pow:72case TR::java_lang_Math_rint:73case TR::java_lang_Math_round_F:74case TR::java_lang_Math_round_D:75case TR::java_lang_Math_scalb_F:76case TR::java_lang_Math_scalb_D:77case TR::java_lang_Math_sin:78case TR::java_lang_Math_sinh:79case TR::java_lang_Math_sqrt:80case TR::java_lang_Math_tan:81case TR::java_lang_Math_tanh:82case TR::java_lang_ref_Reference_reachabilityFence:83case TR::java_lang_StrictMath_acos:84case TR::java_lang_StrictMath_asin:85case TR::java_lang_StrictMath_atan:86case TR::java_lang_StrictMath_atan2:87case TR::java_lang_StrictMath_cbrt:88case TR::java_lang_StrictMath_ceil:89case TR::java_lang_StrictMath_copySign_F:90case TR::java_lang_StrictMath_copySign_D:91case TR::java_lang_StrictMath_cos:92case TR::java_lang_StrictMath_cosh:93case TR::java_lang_StrictMath_exp:94case TR::java_lang_StrictMath_expm1:95case TR::java_lang_StrictMath_floor:96case TR::java_lang_StrictMath_hypot:97case TR::java_lang_StrictMath_IEEEremainder:98case TR::java_lang_StrictMath_log:99case TR::java_lang_StrictMath_log10:100case TR::java_lang_StrictMath_log1p:101case TR::java_lang_StrictMath_nextAfter_F:102case TR::java_lang_StrictMath_nextAfter_D:103case TR::java_lang_StrictMath_pow:104case TR::java_lang_StrictMath_random:105case TR::java_lang_StrictMath_round_F:106case TR::java_lang_StrictMath_round_D:107case TR::java_lang_StrictMath_scalb_F:108case TR::java_lang_StrictMath_scalb_D:109case TR::java_lang_StrictMath_rint:110case TR::java_lang_StrictMath_sin:111case TR::java_lang_StrictMath_sinh:112case TR::java_lang_StrictMath_sqrt:113case TR::java_lang_StrictMath_tan:114case TR::java_lang_StrictMath_tanh:115case TR::java_nio_Bits_keepAlive:116/*117case TR::java_math_BigDecimal_valueOf:118case TR::java_math_BigDecimal_add:119case TR::java_math_BigDecimal_subtract:120case TR::java_math_BigDecimal_multiply:121case TR::java_math_BigInteger_add:122case TR::java_math_BigInteger_subtract:123case TR::java_math_BigInteger_multiply:124*/125return true;126default:127return false;128}129return false;130}131132/**133* Returns true if the function call will not yield to OSR point.134*135* An example of kind of function which can go in the list would be recognized calls with136* NOP calls or the one that are guaranteed to be inlined by codegenerator.137*/138bool139J9::MethodSymbol::functionCallDoesNotYieldOSR()140{141switch(self()->getRecognizedMethod())142{143case TR::java_lang_ref_Reference_reachabilityFence:144case TR::java_nio_Bits_keepAlive:145return true;146default:147return OMR::MethodSymbolConnector::functionCallDoesNotYieldOSR();148}149return false;150}151152// Which recognized methods are known to have no valid null checks153//154static TR::RecognizedMethod canSkipNullChecks[] =155{156// NOTE!! add methods whose checks can be skipped by sov library to the beginning of the list (see stopMethod below)157TR::java_lang_invoke_FilterArgumentsHandle_invokeExact,158TR::java_lang_invoke_MethodHandle_undoCustomizationLogic,159TR::java_lang_invoke_CollectHandle_invokeExact,160TR::java_util_ArrayList_add,161TR::java_util_ArrayList_ensureCapacity,162TR::java_util_ArrayList_get,163#if JAVA_SPEC_VERSION < 17164TR::java_lang_String_trim,165TR::java_lang_String_replace,166TR::java_lang_String_charAt,167TR::java_lang_String_charAtInternal_I,168TR::java_lang_String_charAtInternal_IB,169TR::java_lang_String_hashCodeImplCompressed,170TR::java_lang_String_hashCodeImplDecompressed,171TR::java_lang_String_length,172TR::java_lang_String_lengthInternal,173//TR::java_lang_String_toLowerCase,174//TR::java_lang_String_toUpperCase,175//TR::java_lang_String_toLowerCaseCore,176//TR::java_lang_String_toUpperCaseCore,177TR::java_lang_String_equalsIgnoreCase,178TR::java_lang_String_indexOf_fast,179TR::java_lang_String_isCompressed,180TR::java_lang_String_coder,181TR::java_lang_String_isLatin1,182TR::java_lang_String_init_int_String_int_String_String,183TR::java_lang_String_init_int_int_char_boolean,184TR::java_lang_String_split_str_int,185#endif186TR::java_lang_StringBuffer_capacityInternal,187TR::java_lang_StringBuffer_lengthInternalUnsynchronized,188TR::java_lang_StringBuilder_capacityInternal,189TR::java_lang_StringBuilder_lengthInternal,190TR::java_lang_StringUTF16_charAt,191TR::java_lang_StringUTF16_checkIndex,192TR::java_lang_StringUTF16_length,193TR::java_util_Hashtable_clone,194TR::java_util_Hashtable_contains,195TR::java_util_HashtableHashEnumerator_hasMoreElements,196TR::java_util_HashtableHashEnumerator_nextElement,197TR::java_util_HashMap_resize,198TR::java_util_HashMapHashIterator_nextNode,199//TR::java_util_Vector_addElement,200TR::java_math_BigDecimal_longString1C,201TR::java_math_BigDecimal_longString2,202TR::java_util_EnumMap__nec_,203TR::java_util_TreeMapUnboundedValueIterator_next,204TR::java_util_TreeMapSubMap_setFirstKey,205TR::java_util_TreeMapSubMap_setLastKey,206TR::java_nio_Bits_getCharB,207TR::java_nio_Bits_getCharL,208TR::java_nio_Bits_getShortB,209TR::java_nio_Bits_getShortL,210TR::java_nio_Bits_getIntB,211TR::java_nio_Bits_getIntL,212TR::java_nio_Bits_getLongB,213TR::java_nio_Bits_getLongL,214TR::java_nio_HeapByteBuffer__get,215TR::java_nio_HeapByteBuffer_put,216TR::unknownMethod217};218219bool220J9::MethodSymbol::safeToSkipNullChecks()221{222TR::RecognizedMethod methodId = self()->getRecognizedMethod();223if (methodId == TR::unknownMethod)224return false;225226for (int i = 0; canSkipNullChecks[i] != TR::unknownMethod; ++i)227if (canSkipNullChecks[i] == methodId)228return true;229230return false;231}232233234// Which recognized methods are known to have no valid bound checks235//236static TR::RecognizedMethod canSkipBoundChecks[] =237{238// NOTE!! add methods whose checks can be skipped by sov library to the beginning of the list (see stopMethod below)239//TR::java_util_ArrayList_add,240//TR::java_util_ArrayList_remove,241//TR::java_util_ArrayList_ensureCapacity,242//TR::java_util_ArrayList_get,243TR::java_lang_Character_toLowerCase,244TR::java_lang_invoke_FilterArgumentsHandle_invokeExact,245TR::java_lang_invoke_CollectHandle_invokeExact,246TR::java_lang_String_trim,247TR::java_lang_String_charAt,248TR::java_lang_String_charAtInternal_I,249TR::java_lang_String_charAtInternal_IB,250TR::java_lang_String_indexOf_String,251TR::java_lang_String_indexOf_String_int,252TR::java_lang_String_indexOf_native,253TR::java_lang_String_indexOf_fast,254TR::java_lang_String_replace,255TR::java_lang_String_compareTo,256TR::java_lang_String_lastIndexOf,257TR::java_lang_String_toLowerCase,258TR::java_lang_String_toUpperCase,259TR::java_lang_String_toLowerCaseCore,260TR::java_lang_String_toUpperCaseCore,261TR::java_lang_String_regionMatches,262TR::java_lang_String_regionMatches_bool,263TR::java_lang_String_regionMatchesInternal,264TR::java_lang_String_equalsIgnoreCase,265TR::java_lang_String_compareToIgnoreCase,266TR::java_lang_String_hashCodeImplCompressed,267TR::java_lang_String_hashCodeImplDecompressed,268TR::java_lang_String_unsafeCharAt,269TR::java_lang_String_split_str_int,270TR::java_lang_String_startsWith,271TR::java_lang_StringUTF16_compareCodePointCI,272TR::java_lang_StringUTF16_compareToCIImpl,273TR::java_lang_StringUTF16_compareValues,274TR::java_util_Hashtable_get,275TR::java_util_Hashtable_put,276TR::java_util_Hashtable_clone,277TR::java_util_Hashtable_rehash,278TR::java_util_Hashtable_remove,279TR::java_util_Hashtable_contains,280TR::java_util_Hashtable_getEntry,281TR::java_util_HashtableHashEnumerator_hasMoreElements,282TR::java_util_HashtableHashEnumerator_nextElement,283TR::java_util_HashMap_getNode,284TR::java_util_HashMap_resize,285//TR::java_util_HashMapHashIterator_nextNode, /* Unsafe if the Iterator is being incorrectly used (concurrent execution) */286TR::java_util_HashMapHashIterator_init, /* Safe because the object is only visible by one thread when init() is executing */287TR::java_util_EnumMap_put,288TR::java_util_EnumMap_typeCheck,289TR::java_util_EnumMap__init_,290TR::java_util_EnumMap__nec_,291TR::java_util_TreeMap_all,292TR::java_util_TreeMap_rbInsert,293TR::java_math_BigDecimal_longString1C,294TR::java_math_BigDecimal_longString2,295TR::java_util_TreeMapUnboundedValueIterator_next,296TR::java_util_TreeMapSubMap_setFirstKey,297TR::java_util_TreeMapSubMap_setLastKey,298TR::java_util_HashMap_get,299TR::java_util_HashMap_findNonNullKeyEntry,300TR::java_util_HashMap_putImpl,301TR::java_lang_String_init_int_String_int_String_String,302TR::java_lang_String_init_int_int_char_boolean,303TR::java_nio_Bits_getCharB,304TR::java_nio_Bits_getCharL,305TR::java_nio_Bits_getShortB,306TR::java_nio_Bits_getShortL,307TR::java_nio_Bits_getIntB,308TR::java_nio_Bits_getIntL,309TR::java_nio_Bits_getLongB,310TR::java_nio_Bits_getLongL,311TR::java_nio_HeapByteBuffer__get,312TR::java_nio_HeapByteBuffer_put,313TR::unknownMethod314};315316bool317J9::MethodSymbol::safeToSkipBoundChecks()318{319TR::RecognizedMethod methodId = self()->getRecognizedMethod();320if (methodId == TR::unknownMethod)321return false;322323for (int i = 0; canSkipBoundChecks[i] != TR::unknownMethod; ++i)324if (canSkipBoundChecks[i] == methodId)325return true;326327return false;328}329330// Which recognized methods are known to have no valid div checks331//332static TR::RecognizedMethod canSkipDivChecks[] =333{334TR::java_util_Hashtable_get,335TR::java_util_Hashtable_put,336TR::java_util_Hashtable_rehash,337TR::java_util_Hashtable_remove,338TR::java_util_Hashtable_getEntry,339TR::unknownMethod340};341342bool343J9::MethodSymbol::safeToSkipDivChecks()344{345TR::RecognizedMethod methodId = self()->getRecognizedMethod();346if (methodId == TR::unknownMethod)347return false;348349for (int i = 0; canSkipDivChecks[i] != TR::unknownMethod; ++i)350if (canSkipDivChecks[i] == methodId)351return true;352353return false;354}355356357// Which recognized methods are known to have no valid checkcasts358//359static TR::RecognizedMethod canSkipCheckCasts[] =360{361TR::java_util_ArrayList_ensureCapacity,362TR::java_util_HashMap_resize,363TR::java_util_HashMapHashIterator_nextNode,364TR::java_util_Hashtable_clone,365TR::java_util_Hashtable_putAll,366TR::unknownMethod367};368369bool370J9::MethodSymbol::safeToSkipCheckCasts()371{372TR::RecognizedMethod methodId = self()->getRecognizedMethod();373if (methodId == TR::unknownMethod)374return false;375376for (int i = 0; canSkipCheckCasts[i] != TR::unknownMethod; ++i)377if (canSkipCheckCasts[i] == methodId)378return true;379380return false;381}382383384// Which recognized methods are known to have no valid array store checks385//386static TR::RecognizedMethod canSkipArrayStoreChecks[] =387{388TR::java_lang_invoke_CollectHandle_invokeExact,389TR::java_util_ArrayList_add,390TR::java_util_ArrayList_ensureCapacity,391TR::java_util_ArrayList_get,392TR::java_util_ArrayList_remove,393TR::java_util_ArrayList_set,394TR::java_util_Hashtable_get,395TR::java_util_Hashtable_put,396TR::java_util_Hashtable_clone,397TR::java_util_Hashtable_putAll,398TR::java_util_Hashtable_rehash,399TR::java_util_Hashtable_remove,400TR::java_util_Hashtable_contains,401TR::java_util_Hashtable_getEntry,402TR::java_util_Hashtable_getEnumeration,403TR::java_util_Hashtable_elements,404TR::java_util_HashtableHashEnumerator_hasMoreElements,405TR::java_util_HashtableHashEnumerator_nextElement,406TR::java_util_HashMap_rehash,407TR::java_util_HashMap_analyzeMap,408TR::java_util_HashMap_calculateCapacity,409TR::java_util_HashMap_findNullKeyEntry,410TR::java_util_HashMap_get,411TR::java_util_HashMap_findNonNullKeyEntry,412TR::java_util_HashMap_putImpl,413TR::java_util_HashMap_resize,414TR::java_util_HashMapHashIterator_nextNode,415TR::java_util_Vector_addElement,416TR::java_util_Vector_contains,417TR::java_util_Vector_subList,418TR::java_util_TreeMap_rbInsert,419TR::java_util_TreeMapUnboundedValueIterator_next,420TR::java_util_TreeMapSubMap_setLastKey,421TR::java_util_TreeMapSubMap_setFirstKey,422TR::java_util_concurrent_ConcurrentHashMap_addCount,423TR::java_util_concurrent_ConcurrentHashMap_tryPresize,424TR::java_util_concurrent_ConcurrentHashMap_transfer,425TR::java_util_concurrent_ConcurrentHashMap_fullAddCount,426TR::java_util_concurrent_ConcurrentHashMap_helpTransfer,427TR::java_util_concurrent_ConcurrentHashMap_initTable,428TR::java_util_concurrent_ConcurrentHashMap_tabAt,429TR::java_util_concurrent_ConcurrentHashMap_casTabAt,430TR::java_util_concurrent_ConcurrentHashMap_setTabAt,431TR::java_util_concurrent_ConcurrentHashMap_TreeBin_lockRoot,432TR::java_util_concurrent_ConcurrentHashMap_TreeBin_contendedLock,433TR::java_util_concurrent_ConcurrentHashMap_TreeBin_find,434TR::java_util_TreeMap_all,435TR::java_util_EnumMap_put,436TR::java_util_EnumMap_typeCheck,437TR::java_util_EnumMap__init_,438TR::java_util_EnumMap__nec_,439TR::java_util_HashMap_all,440TR::java_util_ArrayList_all,441TR::java_util_Hashtable_all,442TR::java_util_concurrent_ConcurrentHashMap_all,443TR::java_util_Vector_all,444TR::unknownMethod445};446447bool448J9::MethodSymbol::safeToSkipArrayStoreChecks()449{450TR::RecognizedMethod methodId = self()->getRecognizedMethod();451if (methodId == TR::unknownMethod)452return false;453454for (int i = 0; canSkipArrayStoreChecks[i] != TR::unknownMethod; ++i)455if (canSkipArrayStoreChecks[i] == methodId)456return true;457458return false;459}460461462// Which recognized methods are known to require no checking when lowering to TR::arraycopy463//464static TR::RecognizedMethod canSkipChecksOnArrayCopies[] =465{466// NOTE!! add methods whose checks can be skipped by sov library to the beginning of the list (see stopMethod below)467//TR::java_util_ArrayList_ensureCapacity,468//TR::java_util_ArrayList_remove, /* ArrayList is NOT synchronized and therefore it's unsafe to remove checks! */469TR::java_lang_Character_toLowerCase,470TR::java_lang_String_concat,471TR::java_lang_String_replace,472TR::java_lang_String_toLowerCase,473TR::java_lang_String_toUpperCase,474TR::java_lang_String_toLowerCaseCore,475TR::java_lang_String_toUpperCaseCore,476TR::java_lang_String_toCharArray,477TR::java_lang_StringBuffer_append,478TR::java_lang_StringBuffer_ensureCapacityImpl,479TR::java_lang_String_init_int_String_int_String_String,480TR::java_lang_String_init_int_int_char_boolean,481TR::java_util_HashMap_resize,482TR::java_util_HashMapHashIterator_nextNode,483TR::unknownMethod484};485486// These are logically the same as the above (canSkipChecksOnArrayCopies).487// I've broken them out so that we can selectively disable this group488// with the TR_DisableExtraCopyOfOpts env var. If/when these prove to be safe489// they can be migrated into the main group.490static TR::RecognizedMethod extraCanSkipChecksOnArrayCopies[] =491{492TR::java_util_Arrays_copyOf_byte,493TR::java_util_Arrays_copyOf_short,494TR::java_util_Arrays_copyOf_char,495TR::java_util_Arrays_copyOf_boolean,496TR::java_util_Arrays_copyOf_int,497TR::java_util_Arrays_copyOf_long,498TR::java_util_Arrays_copyOf_float,499TR::java_util_Arrays_copyOf_double,500TR::java_util_Arrays_copyOf_Object1,501TR::unknownMethod502};503504bool505J9::MethodSymbol::safeToSkipChecksOnArrayCopies()506{507TR::RecognizedMethod methodId = self()->getRecognizedMethod();508if (methodId == TR::unknownMethod)509return false;510511for (int i = 0; canSkipChecksOnArrayCopies[i] != TR::unknownMethod; ++i)512if (canSkipChecksOnArrayCopies[i] == methodId)513return true;514515static char *disableExtraCopyOfOpts=feGetEnv("TR_DisableExtraCopyOfOpts");516if (!disableExtraCopyOfOpts)517for (int i = 0; extraCanSkipChecksOnArrayCopies[i] != TR::unknownMethod; ++i)518if (extraCanSkipChecksOnArrayCopies[i] == methodId)519return true;520521return false;522}523524// Which recognized methods are known to not require zero initialization of arrays525//526static TR::RecognizedMethod canSkipZeroInitializationOnNewarrays[] =527{528TR::java_lang_Character_toLowerCase,529TR::java_lang_String_init,530TR::java_lang_String_init_int_int_char_boolean,531TR::java_lang_String_concat,532TR::java_lang_String_replace,533TR::java_lang_String_toCharArray,534TR::java_lang_String_toLowerCase,535//TR::java_lang_String_toUpperCase,536TR::java_lang_String_toLowerCaseCore,537//TR::java_lang_String_toUpperCaseCore,538TR::java_lang_String_split_str_int,539TR::java_math_BigDecimal_toString,540TR::java_lang_StringCoding_encode,541TR::java_lang_StringCoding_decode,542TR::java_lang_StringCoding_StringEncoder_encode,543TR::java_lang_StringCoding_StringDecoder_decode,544//TR::java_lang_StringBuilder_ensureCapacityImpl,545//TR::java_lang_StringBuffer_ensureCapacityImpl,546//TR::java_util_Arrays_copyOf,547TR::java_io_Writer_write_lStringII,548TR::java_io_Writer_write_I,549TR::java_util_regex_Matcher_init,550TR::java_util_regex_Matcher_usePattern,551TR::unknownMethod552};553554555bool556J9::MethodSymbol::safeToSkipZeroInitializationOnNewarrays()557{558TR::RecognizedMethod methodId = self()->getRecognizedMethod();559if (methodId == TR::unknownMethod)560return false;561562for (int i = 0; canSkipZeroInitializationOnNewarrays[i] != TR::unknownMethod; ++i)563if (canSkipZeroInitializationOnNewarrays[i] == methodId)564return true;565566return false;567}568569570