From e714ff7c618a6056269b10be2d26430b6f70a56f Mon Sep 17 00:00:00 2001 From: Henry Zongaro Date: Mon, 17 Dec 2018 11:21:31 -0500 Subject: [PATCH] Ensure boolean JNI methods produce a result of zero or one In calling a JNI boolean method, if the native implementation returns zero, the result is false; if it returns a non-zero value, the result is true. This behaviour is consistent with the reference implementation. Progresses issue #2049 Signed-off-by: Henry Zongaro --- .../compiler/compile/J9SymbolReferenceTable.cpp | 17 +++++++++++++++++ .../compiler/compile/J9SymbolReferenceTable.hpp | 1 + .../x/amd64/codegen/AMD64JNILinkage.cpp | 13 ++++++++++++- .../compiler/x/i386/codegen/IA32JNILinkage.cpp | 12 +++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/runtime/compiler/compile/J9SymbolReferenceTable.cpp b/runtime/compiler/compile/J9SymbolReferenceTable.cpp index 4f645a0ccbe..89d625fc7cc 100644 --- a/runtime/compiler/compile/J9SymbolReferenceTable.cpp +++ b/runtime/compiler/compile/J9SymbolReferenceTable.cpp @@ -1269,6 +1269,13 @@ static bool isSignatureTypeBool(const char *fieldSignature, int32_t len) return len == 1 && fieldSignature[0] == 'Z'; } +static bool isSignatureReturnTypeBool(const char *methodSignature, int32_t len) + { + TR_ASSERT(len > 1, "Method signature is unexpectedly short %d", len); + // Method signature must end with ")Z" to have a boolean result type + return len > 1 && (')' == methodSignature[len-2]) && ('Z' == methodSignature[len-1]); + } + bool J9::SymbolReferenceTable::isFieldTypeBool(TR::SymbolReference *symRef) { @@ -1287,6 +1294,16 @@ J9::SymbolReferenceTable::isStaticTypeBool(TR::SymbolReference *symRef) return isSignatureTypeBool(fieldSignature, len); } +bool +J9::SymbolReferenceTable::isReturnTypeBool(TR::SymbolReference *symRef) + { + TR_Method *method = symRef->getSymbol()->castToResolvedMethodSymbol()->getMethod(); + char *methodSignature = method->signatureChars(); + const int32_t len = method->signatureLength(); + dumpOptDetails(comp(), "got method signature as %.*s\n", len, methodSignature); + return isSignatureReturnTypeBool(methodSignature, len); + } + static bool parmSlotCameFromExpandingAnArchetypeArgPlaceholder(int32_t slot, TR::ResolvedMethodSymbol *sym, TR_Memory *mem) { TR_ResolvedMethod *meth = sym->getResolvedMethod(); diff --git a/runtime/compiler/compile/J9SymbolReferenceTable.hpp b/runtime/compiler/compile/J9SymbolReferenceTable.hpp index 18e481c3a77..2b8088d7ac8 100644 --- a/runtime/compiler/compile/J9SymbolReferenceTable.hpp +++ b/runtime/compiler/compile/J9SymbolReferenceTable.hpp @@ -263,6 +263,7 @@ class SymbolReferenceTable : public OMR::SymbolReferenceTableConnector bool isFieldClassObject(TR::SymbolReference *symRef); bool isFieldTypeBool(TR::SymbolReference *symRef); bool isStaticTypeBool(TR::SymbolReference *symRef); + bool isReturnTypeBool(TR::SymbolReference *symRef); void addParameters(TR::ResolvedMethodSymbol * owningMethodSymbol); // NO LONGER NEEDED? Disabled since inception (2009) diff --git a/runtime/compiler/x/amd64/codegen/AMD64JNILinkage.cpp b/runtime/compiler/x/amd64/codegen/AMD64JNILinkage.cpp index 2b785da6555..c532657e396 100644 --- a/runtime/compiler/x/amd64/codegen/AMD64JNILinkage.cpp +++ b/runtime/compiler/x/amd64/codegen/AMD64JNILinkage.cpp @@ -1181,14 +1181,25 @@ void TR::AMD64JNILinkage::cleanupReturnValue( // type so that we sign and zero extend the narrower integer return types properly. // TR_X86OpCodes op; + TR::SymbolReference *callSymRef = callNode->getSymbolReference(); TR::ResolvedMethodSymbol *callSymbol = callNode->getSymbol()->castToResolvedMethodSymbol(); TR_ResolvedMethod *resolvedMethod = callSymbol->getResolvedMethod(); bool isUnsigned = resolvedMethod->returnTypeIsUnsigned(); + switch (resolvedMethod->returnType()) { case TR::Int8: - if (isUnsigned) + if (comp()->getSymRefTab()->isReturnTypeBool(callSymRef)) + { + // For bool return type, must check whether value returned by + // JNI is zero (false) or non-zero (true) to yield Java result + generateRegRegInstruction(TEST1RegReg, callNode, + linkageReturnReg, linkageReturnReg, cg()); + generateRegInstruction(SETNE1Reg, callNode, linkageReturnReg, cg()); + op = TR::Compiler->target.is64Bit() ? MOVZXReg8Reg1 : MOVZXReg4Reg1; + } + else if (isUnsigned) { op = TR::Compiler->target.is64Bit() ? MOVZXReg8Reg1 : MOVZXReg4Reg1; } diff --git a/runtime/compiler/x/i386/codegen/IA32JNILinkage.cpp b/runtime/compiler/x/i386/codegen/IA32JNILinkage.cpp index 9280f95b1c6..17249f91c74 100644 --- a/runtime/compiler/x/i386/codegen/IA32JNILinkage.cpp +++ b/runtime/compiler/x/i386/codegen/IA32JNILinkage.cpp @@ -335,10 +335,20 @@ TR::Register *TR::IA32JNILinkage::buildJNIDispatch(TR::Node *callNode) // type so that we sign and zero extend the narrower integer return types properly. // bool isUnsigned = resolvedMethod->returnTypeIsUnsigned(); + bool isBoolean; switch (resolvedMethod->returnType()) { case TR::Int8: - generateRegRegInstruction(isUnsigned ? MOVZXReg4Reg1 : MOVSXReg4Reg1, + isBoolean = comp()->getSymRefTab()->isReturnTypeBool(callSymRef); + if (isBoolean) + { + // For bool return type, must check whether value returned by + // JNI is zero (false) or non-zero (true) to yield Java result + generateRegRegInstruction(TEST1RegReg, callNode, eaxReal, eaxReal, cg()); + generateRegInstruction(SETNE1Reg, callNode, eaxReal, cg()); + } + generateRegRegInstruction((isUnsigned || isBoolean) + ? MOVZXReg4Reg1 : MOVSXReg4Reg1, callNode, ecxReal, eaxReal, cg()); break; case TR::Int16: