diff --git a/jcl/src/java.base/share/classes/java/lang/String.java b/jcl/src/java.base/share/classes/java/lang/String.java index 50b4ff328cc..0da202b65a0 100644 --- a/jcl/src/java.base/share/classes/java/lang/String.java +++ b/jcl/src/java.base/share/classes/java/lang/String.java @@ -2423,14 +2423,19 @@ public byte[] getBytes() { int currentLength = lengthInternal(); /*[IF Sidecar19-SE]*/ + byte[] buffer = value; // Check if the String is compressed if (enableCompression && count >= 0) { - byte[] buffer = new byte[currentLength]; - compressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength) { + buffer = new byte[currentLength]; + compressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(String.LATIN1, buffer); } else { - byte[] buffer = new byte[currentLength * 2]; - decompressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength << 1) { + buffer = new byte[currentLength << 1]; + decompressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(String.UTF16, buffer); } /*[ELSE]*/ @@ -2521,16 +2526,20 @@ public byte[] getBytes(String encoding) throws UnsupportedEncodingException { } int currentLength = lengthInternal(); - /*[IF Sidecar19-SE]*/ + byte[] buffer = value; // Check if the String is compressed if (enableCompression && count >= 0) { - byte[] buffer = new byte[currentLength]; - compressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength) { + buffer = new byte[currentLength]; + compressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(encoding, String.LATIN1, buffer); } else { - byte[] buffer = new byte[currentLength * 2]; - decompressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength << 1) { + buffer = new byte[currentLength << 1]; + decompressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(encoding, String.UTF16, buffer); } /*[ELSE]*/ @@ -5102,14 +5111,19 @@ public byte[] getBytes(Charset charset) { int currentLength = lengthInternal(); /*[IF Sidecar19-SE]*/ + byte[] buffer = value; // Check if the String is compressed if (enableCompression && count >= 0) { - byte[] buffer = new byte[currentLength]; - compressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength) { + buffer = new byte[currentLength]; + compressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(charset, String.LATIN1, buffer); } else { - byte[] buffer = new byte[currentLength * 2]; - decompressedArrayCopy(value, 0, buffer, 0, currentLength); + if (buffer.length != currentLength << 1) { + buffer = new byte[currentLength << 1]; + decompressedArrayCopy(value, 0, buffer, 0, currentLength); + } return StringCoding.encode(charset, String.UTF16, buffer); } /*[ELSE]*/ diff --git a/runtime/tr.source/trj9/codegen/J9RecognizedMethodsEnum.hpp b/runtime/tr.source/trj9/codegen/J9RecognizedMethodsEnum.hpp index f7cfe894119..867256ecbbc 100644 --- a/runtime/tr.source/trj9/codegen/J9RecognizedMethodsEnum.hpp +++ b/runtime/tr.source/trj9/codegen/J9RecognizedMethodsEnum.hpp @@ -196,6 +196,8 @@ java_lang_String_unsafeCharAt, java_lang_String_split_str_int, + java_lang_StringUTF16_getChar, + java_lang_StringBuffer_append, java_lang_StringBuffer_capacityInternal, java_lang_StringBuffer_ensureCapacityImpl, @@ -1086,6 +1088,10 @@ java_lang_StringCoding_encode, java_lang_StringCoding_StringDecoder_decode, java_lang_StringCoding_StringEncoder_encode, + java_lang_StringCoding_implEncodeISOArray, + java_lang_StringCoding_encode8859_1, + java_lang_StringCoding_encodeASCII, + java_lang_StringCoding_encodeUTF8, java_util_Arrays_copyOf_byte, java_util_Arrays_copyOf_short, diff --git a/runtime/tr.source/trj9/compile/J9Compilation.cpp b/runtime/tr.source/trj9/compile/J9Compilation.cpp index fc3ae1a598f..f6c6f5fad2e 100644 --- a/runtime/tr.source/trj9/compile/J9Compilation.cpp +++ b/runtime/tr.source/trj9/compile/J9Compilation.cpp @@ -368,6 +368,7 @@ J9::Compilation::isConverterMethod(TR::RecognizedMethod rm) switch (rm) { case TR::sun_nio_cs_ISO_8859_1_Encoder_encodeISOArray: + case TR::java_lang_StringCoding_implEncodeISOArray: case TR::sun_nio_cs_ISO_8859_1_Decoder_decodeISO8859_1: case TR::sun_nio_cs_US_ASCII_Encoder_encodeASCII: case TR::sun_nio_cs_US_ASCII_Decoder_decodeASCII: @@ -402,6 +403,7 @@ J9::Compilation::canTransformConverterMethod(TR::RecognizedMethod rm) switch (rm) { case TR::sun_nio_cs_ISO_8859_1_Encoder_encodeISOArray: + case TR::java_lang_StringCoding_implEncodeISOArray: return genTRxx || self()->cg()->getSupportsArrayTranslateTRTO255() || self()->cg()->getSupportsArrayTranslateTRTO() || genSIMD; case TR::sun_nio_cs_ISO_8859_1_Decoder_decodeISO8859_1: diff --git a/runtime/tr.source/trj9/env/VMJ9.cpp b/runtime/tr.source/trj9/env/VMJ9.cpp index f598fc509c1..b3750c474d0 100644 --- a/runtime/tr.source/trj9/env/VMJ9.cpp +++ b/runtime/tr.source/trj9/env/VMJ9.cpp @@ -3305,6 +3305,7 @@ int TR_J9VMBase::checkInlineableTarget (TR_CallTarget* target, TR_CallSite* call case TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject32: case TR::com_ibm_jit_JITHelpers_getJ9ClassFromObject64: case TR::com_ibm_jit_JITHelpers_getClassInitializeStatus: + case TR::java_lang_StringUTF16_getChar: return DontInline_Callee; default: break; diff --git a/runtime/tr.source/trj9/env/j9method.cpp b/runtime/tr.source/trj9/env/j9method.cpp index f2266ab1df5..3848cf79fe5 100644 --- a/runtime/tr.source/trj9/env/j9method.cpp +++ b/runtime/tr.source/trj9/env/j9method.cpp @@ -2987,6 +2987,10 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron { {x(TR::java_lang_StringCoding_decode, "decode", "(Ljava/nio/charset/Charset;[BII)[C")}, {x(TR::java_lang_StringCoding_encode, "encode", "(Ljava/nio/charset/Charset;[CII)[B")}, + {x(TR::java_lang_StringCoding_implEncodeISOArray, "implEncodeISOArray", "([BI[BII)I")}, + {x(TR::java_lang_StringCoding_encode8859_1, "encode8859_1", "(B[B)[B")}, + {x(TR::java_lang_StringCoding_encodeASCII, "encodeASCII", "(B[B)[B")}, + {x(TR::java_lang_StringCoding_encodeUTF8, "encodeUTF8", "(B[B)[B")}, { TR::unknownMethod} }; @@ -3302,6 +3306,12 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron { TR::unknownMethod} }; + static X StringUTF16Methods[] = + { + { x(TR::java_lang_StringUTF16_getChar, "getChar", "([BI)C")}, + { TR::unknownMethod } + }; + static X DecimalFormatHelperMethods[] = { {x(TR::com_ibm_jit_DecimalFormatHelper_formatAsDouble, "formatAsDouble", "(Ljava/text/DecimalFormat;Ljava/math/BigDecimal;)Ljava/lang/String;")}, @@ -4158,6 +4168,7 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron static Y class21[] = { { "java/lang/ClassLoader", ClassLoaderMethods }, + { "java/lang/StringUTF16", StringUTF16Methods }, { 0 } }; diff --git a/runtime/tr.source/trj9/il/symbol/J9MethodSymbol.cpp b/runtime/tr.source/trj9/il/symbol/J9MethodSymbol.cpp index c67e8a6041c..60548e55d61 100644 --- a/runtime/tr.source/trj9/il/symbol/J9MethodSymbol.cpp +++ b/runtime/tr.source/trj9/il/symbol/J9MethodSymbol.cpp @@ -538,6 +538,9 @@ static TR::RecognizedMethod canSkipZeroInitializationOnNewarrays[] = //TR::java_util_Arrays_copyOf, TR::java_io_Writer_write_lStringII, TR::java_io_Writer_write_I, + TR::java_lang_StringCoding_encode8859_1, + TR::java_lang_StringCoding_encodeASCII, + TR::java_lang_StringCoding_encodeUTF8, TR::unknownMethod }; diff --git a/runtime/tr.source/trj9/ilgen/Walker.cpp b/runtime/tr.source/trj9/ilgen/Walker.cpp index da075c5c3af..b54d1db66af 100644 --- a/runtime/tr.source/trj9/ilgen/Walker.cpp +++ b/runtime/tr.source/trj9/ilgen/Walker.cpp @@ -6899,6 +6899,22 @@ TR_J9ByteCodeIlGenerator::genNewArray(int32_t typeIndex) if (_methodSymbol->skipZeroInitializationOnNewarrays()) node->setCanSkipZeroInitialization(true); + // special case for handling Arrays.copyOf in the StringEncoder fast paths for Java 9+ + if (!comp()->isOutermostMethod() + && _methodSymbol->getRecognizedMethod() == TR::java_util_Arrays_copyOf_byte) + { + int32_t callerIndex = comp()->getCurrentInlinedCallSite()->_byteCodeInfo.getCallerIndex(); + TR::ResolvedMethodSymbol *caller = callerIndex > -1 ? comp()->getInlinedResolvedMethodSymbol(callerIndex) : comp()->getMethodSymbol(); + switch (caller->getRecognizedMethod()) + { + case TR::java_lang_StringCoding_encode8859_1: + case TR::java_lang_StringCoding_encodeASCII: + case TR::java_lang_StringCoding_encodeUTF8: + node->setCanSkipZeroInitialization(true); + break; + } + } + bool separateInitializationFromAllocation; switch (_methodSymbol->getRecognizedMethod()) { diff --git a/runtime/tr.source/trj9/optimizer/UnsafeFastPath.cpp b/runtime/tr.source/trj9/optimizer/UnsafeFastPath.cpp index 8f05647fdbf..9a96e9dc085 100644 --- a/runtime/tr.source/trj9/optimizer/UnsafeFastPath.cpp +++ b/runtime/tr.source/trj9/optimizer/UnsafeFastPath.cpp @@ -149,6 +149,16 @@ int32_t TR_UnsafeFastPath::perform() bool isVolatile = false; bool isArrayOperation = false; bool isByIndex = false; + int32_t objectChild = 1; + int32_t offsetChild = 2; + + switch (symbol->getRecognizedMethod()) + { + case TR::java_lang_StringUTF16_getChar: + objectChild = 0; + offsetChild = 1; + break; + } // Check for array operation switch (symbol->getRecognizedMethod()) @@ -190,6 +200,7 @@ int32_t TR_UnsafeFastPath::perform() case TR::com_ibm_jit_JITHelpers_putLongInArray: case TR::com_ibm_jit_JITHelpers_putObjectInArrayVolatile: case TR::com_ibm_jit_JITHelpers_putObjectInArray: + case TR::java_lang_StringUTF16_getChar: isArrayOperation = true; break; default: @@ -223,6 +234,7 @@ int32_t TR_UnsafeFastPath::perform() case TR::com_ibm_jit_JITHelpers_getByteFromArray: type = TR::Int8; break; + case TR::java_lang_StringUTF16_getChar: case TR::com_ibm_jit_JITHelpers_getCharFromArrayByIndex: isByIndex = true; type = TR::Int16; @@ -392,27 +404,35 @@ int32_t TR_UnsafeFastPath::perform() if (type != TR::NoType && performTransformation(comp(), "%s Found unsafe/JITHelpers calls, turning node [" POINTER_PRINTF_FORMAT "] into a load/store\n", optDetailString(), node)) { - TR::SymbolReference * unsafeSymRef = comp()->getSymRefTab()->findOrCreateUnsafeSymbolRef(type, true, false, isVolatile); + // some helpers are special - we know they are accessing an array and we know the kind of that array + // so use the more helpful symref if we can + switch (calleeMethod) + { + case TR::java_lang_StringUTF16_getChar: + unsafeSymRef = comp()->getSymRefTab()->findOrCreateArrayShadowSymbolRef(TR::Int8); + break; + } + // Change the object child to the starting address of static fields in J9Class if (isStatic) { - TR::Node *jlClass = node->getChild(1); + TR::Node *jlClass = node->getChild(objectChild); TR::Node *j9Class = TR::Node::createWithSymRef(TR::aloadi, 1, 1, jlClass, comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()); TR::Node *ramStatics = TR::Node::createWithSymRef(TR::aloadi, 1, 1, j9Class, comp()->getSymRefTab()->findOrCreateRamStaticsFromClassSymbolRef()); - node->setAndIncChild(1, ramStatics); + node->setAndIncChild(objectChild, ramStatics); jlClass->recursivelyDecReferenceCount(); - offset = node->getChild(2); + offset = node->getChild(offsetChild); // The offset for a static field is low taged, mask out the last bit to get the real offset TR::Node *newOffset = TR::Node::create(offset, TR::land, 2, offset, TR::Node::lconst(offset, ~1)); - node->setAndIncChild(2, newOffset); + node->setAndIncChild(offsetChild, newOffset); offset->recursivelyDecReferenceCount(); } @@ -420,20 +440,20 @@ int32_t TR_UnsafeFastPath::perform() anchorAllChildren(node, tt); // When accessing a static field, object is the starting address of static fields - object = node->getChild(1); + object = node->getChild(objectChild); if (!isStatic) object->setIsNonNull(true); if (isByIndex) { - index = node->getChild(2); + index = node->getChild(offsetChild); index->setIsNonNegative(true); offset = J9::TransformUtil::calculateOffsetFromIndexInContiguousArray(comp(), index, type); } else { - offset = node->getChild(2); + offset = node->getChild(offsetChild); offset->setIsNonNegative(true); // Index is not used in the non-arraylet case so no need to compute it