Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recognize StringLatin1.inflate([BI[BII)V #20867

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion runtime/compiler/aarch64/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6960,7 +6960,7 @@ J9::ARM64::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result
resultReg = inlineFPTrg1Src3(node, TR::InstOpCode::fmadds, cg);
return true;

case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
if (cg->getSupportsInlineStringLatin1Inflate())
{
resultReg = inlineStringLatin1Inflate(node, cg);
Expand Down
3 changes: 2 additions & 1 deletion runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@
java_lang_String_decompressedArrayCopy_BICII,
java_lang_String_decompressedArrayCopy_CIBII,
java_lang_String_decompressedArrayCopy_CICII,
java_lang_StringLatin1_inflate,
java_lang_String_concat,
java_lang_String_length,
java_lang_String_lengthInternal,
Expand Down Expand Up @@ -232,6 +231,8 @@

java_lang_StringLatin1_indexOf,
java_lang_StringLatin1_indexOfChar,
java_lang_StringLatin1_inflate_BICII,
java_lang_StringLatin1_inflate_BIBII,

java_lang_StringUTF16_charAt,
java_lang_StringUTF16_checkIndex,
Expand Down
6 changes: 4 additions & 2 deletions runtime/compiler/env/j9method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3234,7 +3234,8 @@ void TR_ResolvedJ9Method::construct()
{
{ x(TR::java_lang_StringLatin1_indexOf, "indexOf", "([BI[BII)I")},
{ x(TR::java_lang_StringLatin1_indexOfChar, "indexOfChar", "([BIII)I")},
{ x(TR::java_lang_StringLatin1_inflate, "inflate", "([BI[CII)V")},
{ x(TR::java_lang_StringLatin1_inflate_BICII, "inflate", "([BI[CII)V")},
{ x(TR::java_lang_StringLatin1_inflate_BIBII, "inflate", "([BI[BII)V")},
{ TR::unknownMethod }
};

Expand Down Expand Up @@ -5121,7 +5122,8 @@ TR_ResolvedJ9Method::setRecognizedMethodInfo(TR::RecognizedMethod rm)
case TR::java_lang_System_nanoTime:
case TR::java_lang_String_hashCodeImplCompressed:
case TR::java_lang_String_hashCodeImplDecompressed:
case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
case TR::java_lang_StringLatin1_inflate_BIBII:
case TR::java_lang_StringCoding_hasNegatives:
case TR::java_lang_StringCoding_countPositives:
case TR::sun_nio_ch_NativeThread_current:
Expand Down
7 changes: 6 additions & 1 deletion runtime/compiler/optimizer/InlinerTempForJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5603,11 +5603,16 @@ TR_J9InlinerPolicy::supressInliningRecognizedInitialCallee(TR_CallSite* callsite
}
break;
}
case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
if (comp->cg()->getSupportsInlineStringLatin1Inflate())
{
return true;
}
case TR::java_lang_StringLatin1_inflate_BIBII:
if (comp->cg()->getSupportsArrayTranslateTROTNoBreak() && !comp->target().cpu.isPower())
{
return true;
}
break;
case TR::java_lang_StringCoding_hasNegatives:
if (comp->cg()->getSupportsInlineStringCodingHasNegatives())
Expand Down
176 changes: 176 additions & 0 deletions runtime/compiler/optimizer/J9RecognizedCallTransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "optimizer/CallInfo.hpp"
#include "optimizer/IdiomRecognitionUtils.hpp"
#include "optimizer/Structure.hpp"
#include "optimizer/ValuePropagation.hpp"
#include "codegen/CodeGenerator.hpp"
#include "optimizer/TransformUtil.hpp"
#include "env/j9method.h"
Expand Down Expand Up @@ -271,6 +272,176 @@ void J9::RecognizedCallTransformer::process_java_lang_StringCoding_encodeASCII(T
cfg->removeEdge(fallthroughBlock, fallbackPathBlock);
}

void J9::RecognizedCallTransformer::process_java_lang_StringLatin1_inflate_BIBII(TR::TreeTop *treetop, TR::Node *node)
{
/*
* Replace the call with the following tree (+ boundary checks)
*
* treetop
* arraytranslate (TROTNoBreak)
* aladd
* srcObj
* ladd
* srcOff
* hdrSize
* aladd
* dstObj
* ladd
* lmul
* dstOff
* lconst 2
* hdrSize
* iconst 0 (dummy: table node)
* iconst 0xffff (term char node)
* length
* iconst -1 (dummy: stop index node)
*/
static bool verboseLatin1inflate = (feGetEnv("TR_verboseLatin1inflate") != NULL);
if (verboseLatin1inflate)
{
fprintf(stderr, "Recognize StringLatin1.inflate([BI[BII)V: %s @ %s\n",
comp()->signature(),
comp()->getHotnessName(comp()->getMethodHotness()));
}

TR_ASSERT_FATAL(comp()->cg()->getSupportsArrayTranslateTROTNoBreak(), "Support for arraytranslateTROTNoBreak is required");

bool is64BitTarget = comp()->target().is64Bit();

TR::Node *srcObj = node->getChild(0);
TR::Node *srcOff = node->getChild(1);
TR::Node *dstObj = node->getChild(2);
TR::Node *dstOff = node->getChild(3);
TR::Node *length = node->getChild(4);

TR::Node *hdrSize = createHdrSizeNode(comp(), node);

TR::Node *strideNode;
if (is64BitTarget)
{
strideNode = TR::Node::create(node, TR::lconst);
strideNode->setLongInt(2);
}
else
{
strideNode = TR::Node::create(node, TR::iconst, 0, 2);
}

TR::Node *arrayTranslateNode = TR::Node::create(node, TR::arraytranslate, 6);
arrayTranslateNode->setSourceIsByteArrayTranslate(true);
arrayTranslateNode->setTargetIsByteArrayTranslate(false);
arrayTranslateNode->setTermCharNodeIsHint(false);
arrayTranslateNode->setSourceCellIsTermChar(false);
arrayTranslateNode->setTableBackedByRawStorage(true);
arrayTranslateNode->setSymbolReference(comp()->getSymRefTab()->findOrCreateArrayTranslateSymbol());

TR::Node *srcAddr, *dstAddr;

#if defined(OMR_GC_SPARSE_HEAP_ALLOCATION)
if (TR::Compiler->om.isOffHeapAllocationEnabled())
{
dstOff = TR::TransformUtil::generateConvertArrayElementIndexToOffsetTrees(comp(), dstOff, strideNode, 0, false);
srcAddr = TR::TransformUtil::generateArrayElementAddressTrees(comp(), srcObj, srcOff);
dstAddr = TR::TransformUtil::generateArrayElementAddressTrees(comp(), dstObj, dstOff);
}
else
#endif /* OMR_GC_SPARSE_HEAP_ALLOCATION */
{
TR::Node *tmpNode;
if (is64BitTarget)
{
tmpNode = TR::Node::create(node, TR::i2l, 1, srcOff);
tmpNode = TR::Node::create(node, TR::ladd, 2, tmpNode, hdrSize);
}
else
{
tmpNode = TR::Node::create(node, TR::iadd, 2, srcOff, hdrSize);
}
srcAddr = TR::Node::create(node, is64BitTarget ? TR::aladd : TR::aiadd, 2, srcObj, tmpNode);

if (is64BitTarget)
{
tmpNode = TR::Node::create(node, TR::i2l, 1, dstOff);
tmpNode = TR::Node::create(node, TR::lmul, 2, tmpNode, strideNode);
}
else
{
tmpNode = TR::Node::create(node, TR::imul, 2, dstOff, strideNode);
}
tmpNode = TR::Node::create(node, is64BitTarget ? TR::ladd : TR::iadd, 2, tmpNode, hdrSize);
dstAddr = TR::Node::create(node, is64BitTarget ? TR::aladd : TR::aiadd, 2, dstObj, tmpNode);
}
TR::Node *termCharNode = TR::Node::create(node, TR::iconst, 0, 0xffff); // mask for ISO 8859-1 decoder
TR::Node *tableNode = TR::Node::create(node, TR::iconst, 0, 0); // dummy table node
TR::Node *stoppingNode = TR::Node::create(node, TR::iconst, 0, -1); // dummy stop index node

arrayTranslateNode->setAndIncChild(0, srcAddr);
arrayTranslateNode->setAndIncChild(1, dstAddr);
arrayTranslateNode->setAndIncChild(2, tableNode);
arrayTranslateNode->setAndIncChild(3, termCharNode);
arrayTranslateNode->setAndIncChild(4, length);
arrayTranslateNode->setAndIncChild(5, stoppingNode);

TR::CFG *cfg = comp()->getFlowGraph();

// if (length < 0) { call the original method }
TR::Node *constZeroNode1 = TR::Node::create(node, TR::iconst, 0, 0);
TR::Node *ifCmpNode1 = TR::Node::createif(TR::ificmplt, length, constZeroNode1);
TR::TreeTop *ifCmpTreeTop1 = TR::TreeTop::create(comp(), treetop->getPrevTreeTop(), ifCmpNode1);
// if (srcOff < 0) { call the original method }
TR::Node *constZeroNode2 = TR::Node::create(node, TR::iconst, 0, 0);
TR::Node *ifCmpNode2 = TR::Node::createif(TR::ificmplt, srcOff, constZeroNode2);
TR::TreeTop *ifCmpTreeTop2 = TR::TreeTop::create(comp(), ifCmpTreeTop1, ifCmpNode2);
// if (srcObj.length < srcOff + length) { call the original method }
TR::Node *arrayLenNode1 = TR::Node::create(node, TR::arraylength, 1, srcObj);
TR::Node *iaddNode1 = TR::Node::create(node, TR::iadd, 2, srcOff, length);
TR::Node *ifCmpNode3 = TR::Node::createif(TR::ificmplt, arrayLenNode1, iaddNode1);
TR::TreeTop *ifCmpTreeTop3 = TR::TreeTop::create(comp(), ifCmpTreeTop2, ifCmpNode3);
// if (dstOff < 0) { call the original method }
TR::Node *constZeroNode3 = TR::Node::create(node, TR::iconst, 0, 0);
TR::Node *ifCmpNode4 = TR::Node::createif(TR::ificmplt, dstOff, constZeroNode3);
TR::TreeTop *ifCmpTreeTop4 = TR::TreeTop::create(comp(), ifCmpTreeTop3, ifCmpNode4);
// if ((dstObj.length >> 1) < dstOff + length) { call the original method }
TR::Node *arrayLenNode2 = TR::Node::create(node, TR::arraylength, 1, dstObj);
TR::Node *constOneNode = TR::Node::create(node, TR::iconst, 0, 1);
TR::Node *ishrNode = TR::Node::create(node, TR::ishr, 2, arrayLenNode2, constOneNode);
TR::Node *iaddNode2 = TR::Node::create(node, TR::iadd, 2, dstOff, length);
TR::Node *ifCmpNode5 = TR::Node::createif(TR::ificmplt, ishrNode, iaddNode2);
TR::TreeTop *ifCmpTreeTop5 = TR::TreeTop::create(comp(), ifCmpTreeTop4, ifCmpNode5);

TR::TreeTop *arrayTranslateTreeTop = TR::TreeTop::create(comp(), ifCmpTreeTop5, arrayTranslateNode);

TR::Block *ifCmpBlock1 = ifCmpTreeTop1->getEnclosingBlock();
TR::Block *ifCmpBlock2 = ifCmpBlock1->split(ifCmpTreeTop2, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
TR::Block *ifCmpBlock3 = ifCmpBlock2->split(ifCmpTreeTop3, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
TR::Block *ifCmpBlock4 = ifCmpBlock3->split(ifCmpTreeTop4, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
TR::Block *ifCmpBlock5 = ifCmpBlock4->split(ifCmpTreeTop5, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
TR::Block *fallThroughPathBlock = ifCmpBlock5->split(arrayTranslateTreeTop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
// This block contains the original call node
TR::Block *fallbackPathBlock = fallThroughPathBlock->split(treetop, cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);
TR::Block *tailBlock = fallbackPathBlock->split(treetop->getNextTreeTop(), cfg, true /* fixUpCommoning */, true /* copyExceptionSuccessors */);

// Go to the tail block from the fall-through block
TR::Node *gotoNode = TR::Node::create(node, TR::Goto);
TR::TreeTop *gotoTree = TR::TreeTop::create(comp(), gotoNode, NULL, NULL);
gotoNode->setBranchDestination(tailBlock->getEntry());
fallThroughPathBlock->getExit()->insertBefore(gotoTree);

// Set the ificmp blocks' destinations to the fallback block and update the CFG
ifCmpNode1->setBranchDestination(fallbackPathBlock->getEntry());
cfg->addEdge(ifCmpBlock1, fallbackPathBlock);
ifCmpNode2->setBranchDestination(fallbackPathBlock->getEntry());
cfg->addEdge(ifCmpBlock2, fallbackPathBlock);
ifCmpNode3->setBranchDestination(fallbackPathBlock->getEntry());
cfg->addEdge(ifCmpBlock3, fallbackPathBlock);
ifCmpNode4->setBranchDestination(fallbackPathBlock->getEntry());
cfg->addEdge(ifCmpBlock4, fallbackPathBlock);
ifCmpNode5->setBranchDestination(fallbackPathBlock->getEntry());
cfg->addEdge(ifCmpBlock5, fallbackPathBlock);
cfg->addEdge(fallThroughPathBlock, tailBlock);
cfg->removeEdge(fallThroughPathBlock, fallbackPathBlock);
}

void J9::RecognizedCallTransformer::process_java_lang_StringUTF16_toBytes(TR::TreeTop* treetop, TR::Node* node)
{
TR_J9VMBase* fej9 = static_cast<TR_J9VMBase*>(comp()->fe());
Expand Down Expand Up @@ -1591,6 +1762,8 @@ bool J9::RecognizedCallTransformer::isInlineable(TR::TreeTop* treetop)
case TR::java_lang_StringCoding_encodeASCII:
case TR::java_lang_String_encodeASCII:
return comp()->cg()->getSupportsInlineEncodeASCII();
case TR::java_lang_StringLatin1_inflate_BIBII:
return (comp()->cg()->getSupportsArrayTranslateTROTNoBreak() && !comp()->target().cpu.isPower());
case TR::jdk_internal_util_ArraysSupport_vectorizedMismatch:
return comp()->cg()->getSupportsInlineVectorizedMismatch();
default:
Expand Down Expand Up @@ -1727,6 +1900,9 @@ void J9::RecognizedCallTransformer::transform(TR::TreeTop* treetop)
case TR::java_lang_String_encodeASCII:
process_java_lang_StringCoding_encodeASCII(treetop, node);
break;
case TR::java_lang_StringLatin1_inflate_BIBII:
process_java_lang_StringLatin1_inflate_BIBII(treetop, node);
break;
case TR::java_lang_StrictMath_sqrt:
case TR::java_lang_Math_sqrt:
process_java_lang_StrictMath_and_Math_sqrt(treetop, node);
Expand Down
19 changes: 19 additions & 0 deletions runtime/compiler/optimizer/J9RecognizedCallTransformer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ class RecognizedCallTransformer : public OMR::RecognizedCallTransformer
* \endcode
*/
void process_java_lang_StringCoding_encodeASCII(TR::TreeTop* treetop, TR::Node* node);
/** \brief
* Transforms java/lang/StringLatin1.inflate([BI[BII)V using arraytranslate
*
* \param treetop
* The treetop which anchors the call node.
*
* \param node
* The call node representing a call to java/lang/StringLatin1.inflate([BI[BII)V which has the following shape:
*
* \code
* acall <java/lang/StringLatin1.inflate([BI[BII)V>
* <src byte array>
* <src offset>
* <dst byte array>
* <dst offset>
* <length>
* \endcode
*/
void process_java_lang_StringLatin1_inflate_BIBII(TR::TreeTop* treetop, TR::Node* node);
/** \brief
* Transforms java/lang/StringUTF16.toBytes([CII)[B into a fast allocate and arraycopy sequence with equivalent
* semantics.
Expand Down
2 changes: 1 addition & 1 deletion runtime/compiler/p/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12230,7 +12230,7 @@ J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result
}
break;

case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
if (cg->getSupportsInlineStringLatin1Inflate())
{
bool result = inlineIntrinsicInflate(node, cg);
Expand Down
2 changes: 1 addition & 1 deletion runtime/compiler/x/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12127,7 +12127,7 @@ J9::X86::TreeEvaluator::directCallEvaluator(TR::Node *node, TR::CodeGenerator *c
}

break;
case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
if (cg->getSupportsInlineStringLatin1Inflate())
{
return TR::TreeEvaluator::inlineStringLatin1Inflate(node, cg);
Expand Down
2 changes: 1 addition & 1 deletion runtime/compiler/z/codegen/J9CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4069,7 +4069,7 @@ J9::Z::CodeGenerator::inlineDirectCall(
break;
}

case TR::java_lang_StringLatin1_inflate:
case TR::java_lang_StringLatin1_inflate_BICII:
if (cg->getSupportsInlineStringLatin1Inflate())
{
resultReg = TR::TreeEvaluator::inlineStringLatin1Inflate(node, cg);
Expand Down