Skip to content

Change return type of getStringUTF8Length #21005

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

Merged
merged 2 commits into from
Feb 18, 2025
Merged
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
13 changes: 2 additions & 11 deletions runtime/compiler/control/JITClientCompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,15 +630,6 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
client->write(response, fe->stackWalkerMaySkipFrames(method, clazz));
}
break;
case MessageType::VM_getStringUTF8Length:
{
uintptr_t string = std::get<0>(client->getRecvData<uintptr_t>());
{
TR::VMAccessCriticalSection getStringUTF8Length(fe);
client->write(response, fe->getStringUTF8Length(string));
}
}
break;
case MessageType::VM_classInitIsFinished:
{
TR_OpaqueClassBlock *clazz = std::get<0>(client->getRecvData<TR_OpaqueClassBlock *>());
Expand Down Expand Up @@ -2351,7 +2342,7 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
"next", "Ljava/lang/invoke/MethodHandle;"),
"type", "Ljava/lang/invoke/MethodType;"),
"methodDescriptor", "Ljava/lang/String;");
size_t methodDescriptorLength = fe->getStringUTF8Length(methodDescriptorRef);
intptr_t methodDescriptorLength = fe->getStringUTF8Length(methodDescriptorRef);
char *methodDescriptor = (char*)alloca(methodDescriptorLength+1);
fe->getStringUTF8(methodDescriptorRef, methodDescriptor, methodDescriptorLength+1);
client->write(response, std::string(methodDescriptor, methodDescriptorLength));
Expand Down Expand Up @@ -2504,7 +2495,7 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes
int32_t numArgsPassToFinallyTarget = (int32_t)fe->getArrayLengthInElements(arguments);

uintptr_t methodDescriptorRef = fe->getReferenceField(finallyType, "methodDescriptor", "Ljava/lang/String;");
int methodDescriptorLength = fe->getStringUTF8Length(methodDescriptorRef);
intptr_t methodDescriptorLength = fe->getStringUTF8Length(methodDescriptorRef);
char *methodDescriptor = (char*)alloca(methodDescriptorLength+1);
fe->getStringUTF8(methodDescriptorRef, methodDescriptor, methodDescriptorLength+1);
client->write(response, numArgsPassToFinallyTarget, std::string(methodDescriptor, methodDescriptorLength));
Expand Down
23 changes: 19 additions & 4 deletions runtime/compiler/env/VMJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5537,18 +5537,33 @@ TR_J9VMBase::getStringCharacter(uintptr_t objectPointer, int32_t index)
}
}

intptr_t
int32_t
TR_J9VMBase::getStringUTF8Length(uintptr_t objectPointer)
{
TR_ASSERT(haveAccess(), "Must have VM access to call getStringUTF8Length");
TR_ASSERT(objectPointer, "assertion failure");
return vmThread()->javaVM->internalVMFunctions->getStringUTF8Length(vmThread(), (j9object_t)objectPointer);
uint64_t actualLength = vmThread()->javaVM->internalVMFunctions->getStringUTF8LengthTruncated(vmThread(), (j9object_t)objectPointer, INT64_MAX);

// Fail if length+1 cannot be represented as an int32_t value. The extra byte accounts for
// any NUL terminator that might be needed in copying the UTF-8 encoded string into a buffer
TR_ASSERT_FATAL(actualLength+1 <= std::numeric_limits<int32_t>::max(), "UTF8-encoded String length of " UINT64_PRINTF_FORMAT " must be in the range permitted for type int32_t, also allowing for a NUL terminator.\n", actualLength);

return (int32_t) actualLength;
}


uint64_t
TR_J9VMBase::getStringUTF8UnabbreviatedLength(uintptr_t objectPointer)
{
TR_ASSERT(haveAccess(), "Must have VM access to call getStringUTF8Length");
TR_ASSERT(objectPointer, "assertion failure");
return vmThread()->javaVM->internalVMFunctions->getStringUTF8LengthTruncated(vmThread(), (j9object_t)objectPointer, INT64_MAX);
}

char *
TR_J9VMBase::getStringUTF8(uintptr_t objectPointer, char *buffer, intptr_t bufferSize)
TR_J9VMBase::getStringUTF8(uintptr_t objectPointer, char *buffer, uintptr_t bufferSize)
{
TR_ASSERT(haveAccess(), "Must have VM access to call getStringAscii");
TR_ASSERT(haveAccess(), "Must have VM access to call getStringUTF8");

vmThread()->javaVM->internalVMFunctions->copyStringToUTF8Helper(vmThread(), (j9object_t)objectPointer, J9_STR_NULL_TERMINATE_RESULT, 0, J9VMJAVALANGSTRING_LENGTH(vmThread(), objectPointer), (U_8*)buffer, (UDATA)bufferSize);

Expand Down
27 changes: 24 additions & 3 deletions runtime/compiler/env/VMJ9.h
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ class TR_J9VMBase : public TR_FrontEnd
*/
virtual bool isChangesCurrentThread(TR_ResolvedMethod *method);

/*
/**
* \brief
* tell whether it's possible to dereference a field given the field symbol at compile time
*
Expand All @@ -1138,8 +1138,29 @@ class TR_J9VMBase : public TR_FrontEnd
virtual bool isJavaLangObject(TR_OpaqueClassBlock *clazz);
virtual int32_t getStringLength(uintptr_t objectPointer);
virtual uint16_t getStringCharacter(uintptr_t objectPointer, int32_t index);
virtual intptr_t getStringUTF8Length(uintptr_t objectPointer);
virtual char *getStringUTF8 (uintptr_t objectPointer, char *buffer, intptr_t bufferSize);

/**
* \brief Returns the number of UTF-8 encoded bytes needed to represent a Java String object.
* The number of bytes needed to UTF-8 encode the String is representable as
* a \c uint64_t, in general, but this method returns a length of type \c int32_t.
* If the length might exceed the range of \c int32_t, use
* \ref getStringUTF8UnabbreviatedLength instead.
*
* \param[in] objectPointer A pointer to a Java String object
*
* \return The number of UTF-8 encoded bytes needed to represent the String
*/
virtual int32_t getStringUTF8Length(uintptr_t objectPointer);

/**
* \brief Returns the number of UTF-8 encoded bytes needed to represent a Java String object.
*
* \param[in] objectPointer A pointer to a Java String object
*
* \return The number of UTF-8 encoded bytes needed to represent the String
*/
virtual uint64_t getStringUTF8UnabbreviatedLength(uintptr_t objectPointer);
virtual char *getStringUTF8(uintptr_t objectPointer, char *buffer, uintptr_t bufferSize);

virtual uint32_t getVarHandleHandleTableOffset(TR::Compilation *);

Expand Down
12 changes: 8 additions & 4 deletions runtime/compiler/env/VMJ9Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1073,12 +1073,16 @@ TR_J9ServerVM::getHostClass(TR_OpaqueClassBlock *clazz)
return hostClass;
}

intptr_t
int32_t
TR_J9ServerVM::getStringUTF8Length(uintptr_t objectPointer)
{
JITServer::ServerStream *stream = _compInfoPT->getMethodBeingCompiled()->_stream;
stream->write(JITServer::MessageType::VM_getStringUTF8Length, objectPointer);
return std::get<0>(stream->read<intptr_t>());
TR_ASSERT_FATAL(false, "getStringUTF8Length(uintptr_t) should not be called by JITServer");
}

uint64_t
TR_J9ServerVM::getStringUTF8UnabbreviatedLength(uintptr_t objectPointer)
{
TR_ASSERT_FATAL(false, "getStringUTF8UnabbreviatedLength(uintptr_t) should not be called by JITServer");
}

bool
Expand Down
3 changes: 2 additions & 1 deletion runtime/compiler/env/VMJ9Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ class TR_J9ServerVM: public TR_J9VM
virtual bool hasFinalFieldsInClass(TR_OpaqueClassBlock *clazz) override;
virtual const char *sampleSignature(TR_OpaqueMethodBlock * aMethod, char *buf, int32_t bufLen, TR_Memory *memory) override;
virtual TR_OpaqueClassBlock * getHostClass(TR_OpaqueClassBlock *clazzOffset) override;
virtual intptr_t getStringUTF8Length(uintptr_t objectPointer) override;
virtual int32_t getStringUTF8Length(uintptr_t objectPointer) override;
virtual uint64_t getStringUTF8UnabbreviatedLength(uintptr_t objectPointer) override;
virtual bool classInitIsFinished(TR_OpaqueClassBlock *) override;
virtual int32_t getNewArrayTypeFromClass(TR_OpaqueClassBlock *clazz) override;
virtual TR_OpaqueClassBlock *getClassFromNewArrayType(int32_t arrayType) override;
Expand Down
4 changes: 2 additions & 2 deletions runtime/compiler/env/j9method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8413,7 +8413,7 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef)

uintptr_t methodHandle;
uintptr_t methodDescriptorRef;
intptr_t methodDescriptorLength;
uintptr_t methodDescriptorLength;

#if defined(J9VM_OPT_JITSERVER)
if (comp()->isOutOfProcessCompilation())
Expand Down Expand Up @@ -9262,7 +9262,7 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef)
numArgsPassToFinallyTarget = (int32_t)fej9->getArrayLengthInElements(arguments);

uintptr_t methodDescriptorRef = fej9->getReferenceField(finallyType, "methodDescriptor", "Ljava/lang/String;");
int methodDescriptorLength = fej9->getStringUTF8Length(methodDescriptorRef);
intptr_t methodDescriptorLength = fej9->getStringUTF8Length(methodDescriptorRef);
methodDescriptor = (char*)alloca(methodDescriptorLength+1);
fej9->getStringUTF8(methodDescriptorRef, methodDescriptor, methodDescriptorLength+1);
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/compiler/net/CommunicationStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class CommunicationStream
// likely to lose an increment when merging/rebasing/etc.
//
static const uint8_t MAJOR_NUMBER = 1;
static const uint16_t MINOR_NUMBER = 78; // ID: DGwBSxx9FLiSwWTdQCIn
static const uint16_t MINOR_NUMBER = 79; // ID: Su+UK1Q5oJlgUkWIBA6f
static const uint8_t PATCH_NUMBER = 0;
static uint32_t CONFIGURATION_FLAGS;

Expand Down
1 change: 0 additions & 1 deletion runtime/compiler/net/MessageTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ const char *messageNames[] =
"VM_getObjectClassFromKnownObjectIndexJLClass",
"VM_getObjectClassInfoFromObjectReferenceLocation",
"VM_stackWalkerMaySkipFrames",
"VM_getStringUTF8Length",
"VM_classInitIsFinished",
"VM_getClassFromNewArrayType",
"VM_getArrayClassFromComponentClass",
Expand Down
1 change: 0 additions & 1 deletion runtime/compiler/net/MessageTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ enum MessageType : uint16_t
VM_getObjectClassFromKnownObjectIndexJLClass,
VM_getObjectClassInfoFromObjectReferenceLocation,
VM_stackWalkerMaySkipFrames,
VM_getStringUTF8Length,
VM_classInitIsFinished,
VM_getClassFromNewArrayType,
VM_getArrayClassFromComponentClass,
Expand Down
29 changes: 25 additions & 4 deletions runtime/compiler/optimizer/StringBuilderTransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ int32_t TR_StringBuilderTransformer::performOnBlock(TR::Block* block)
{
int32_t capacity = computeHeuristicStringBuilderInitCapacity(appendArguments);

// Guard against the possibility that the computed capacity has overflowed,
// as StringBuilder.<init>(I) will throw a NegativeArraySizeException if the
// capacity argument is negative. It is extremely unlikely that the capacity
// calculation will overflow, but possible.
if (capacity < 0)
{
return 1;
}

if (performTransformation(comp(), "%sTransforming java/lang/StringBuilder.<init>()V call at node [0x%p] to java/lang/StringBuilder.<init>(I)V with capacity = %d\n", OPT_DETAILS, initNode, capacity))
{
static const bool collectAppendStatistics = feGetEnv("TR_StringBuilderTransformerCollectAppendStatistics") != NULL;
Expand Down Expand Up @@ -465,14 +474,23 @@ TR::Node* TR_StringBuilderTransformer::findStringBuilderChainedAppendArguments(T
* The heuristic used in the non-constant case is hard coded per object type and was determined using the
* statistics collection mechanisms implemented by this optimization. See TR_StringBuilderTransformer Environment
* Variables section for more details.
*
* \returns A non-negative computed capacity or a negative value if the capacity estimate resulted in an integer overflow
*/
int32_t TR_StringBuilderTransformer::computeHeuristicStringBuilderInitCapacity(List<TR_Pair<TR::Node*, TR::RecognizedMethod> >& appendArguments)
{
int32_t capacity = 0;
uint32_t capacity = 0;

ListIterator<TR_Pair<TR::Node*, TR::RecognizedMethod> > iter(&appendArguments);

for (TR_Pair<TR::Node*, TR::RecognizedMethod>* pair = iter.getFirst(); pair != NULL; pair = iter.getNext())
// Iterate over pairs of recognized methods and arguments that can be used
// to estimate the size of the StringBuilder buffer that will be needed.
// If the estimated capacity ever exceeds the maximum int32_t value, the
// calculation has overflowed, so halt early.
//
for (TR_Pair<TR::Node*, TR::RecognizedMethod>* pair = iter.getFirst();
(pair != NULL) && (capacity <= std::numeric_limits<int32_t>::max());
pair = iter.getNext())
{
TR::Node* argument = pair->getKey();

Expand Down Expand Up @@ -595,7 +613,7 @@ int32_t TR_StringBuilderTransformer::computeHeuristicStringBuilderInitCapacity(L
{
uintptr_t stringObjectLocation = (uintptr_t)symbol->castToStaticSymbol()->getStaticAddress();
uintptr_t stringObject = comp()->fej9()->getStaticReferenceFieldAtAddress(stringObjectLocation);
capacity += comp()->fe()->getStringUTF8Length(stringObject);
capacity += comp()->fej9()->getStringLength(stringObject);

break;
}
Expand Down Expand Up @@ -625,5 +643,8 @@ int32_t TR_StringBuilderTransformer::computeHeuristicStringBuilderInitCapacity(L
}
}

return capacity;
// If the loop has halted early because the value of capacity is greater than the
// int32_t value, casting the capacity to int32_t will yield a negative result,
// signalling that the capacity calculation has failed.
return (int32_t) capacity;
}