Skip to content

Commit

Permalink
Ensure boolean JNI methods produce a result of zero or one
Browse files Browse the repository at this point in the history
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 <zongaro@ca.ibm.com>
  • Loading branch information
hzongaro committed Dec 20, 2018
1 parent e45ac33 commit e714ff7
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 2 deletions.
17 changes: 17 additions & 0 deletions runtime/compiler/compile/J9SymbolReferenceTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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();
Expand Down
1 change: 1 addition & 0 deletions runtime/compiler/compile/J9SymbolReferenceTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 12 additions & 1 deletion runtime/compiler/x/amd64/codegen/AMD64JNILinkage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
12 changes: 11 additions & 1 deletion runtime/compiler/x/i386/codegen/IA32JNILinkage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit e714ff7

Please sign in to comment.