@@ -6232,6 +6232,11 @@ TR_J9ByteCodeIlGenerator::genWithField(TR::SymbolReference * symRef, TR_OpaqueCl
6232
6232
TR::Node *newFieldValue = pop ();
6233
6233
TR::Node *originalObject = pop ();
6234
6234
6235
+ if (symRef->getSymbol ()->getType ().isIntegral ())
6236
+ {
6237
+ newFieldValue = narrowIntStoreIfRequired (newFieldValue, symRef);
6238
+ }
6239
+
6235
6240
/*
6236
6241
* Insert nullchk for the original object as requested by the JVM spec.
6237
6242
* Especially in case of value type class with a single field, the nullchk is still
@@ -6998,6 +7003,48 @@ TR_J9ByteCodeIlGenerator::storeInstance(int32_t cpIndex)
6998
7003
storeInstance (symRef);
6999
7004
}
7000
7005
7006
+ TR::Node*
7007
+ TR_J9ByteCodeIlGenerator::narrowIntStoreIfRequired (TR::Node *value, TR::SymbolReference *symRef)
7008
+ {
7009
+ TR::DataType type = symRef->getSymbol ()->getDataType ();
7010
+
7011
+ // Per the JVM spec, putstatic/putfield/withfield opcodes must adhere to field type compatibility.
7012
+ // Integer values on the stack must be narrowed when stored into smaller types like bool, byte,
7013
+ // char, and short fields. For byte and short fields, narrowing involves conversion from integer
7014
+ // to byte/short, then back to integer. For bool and char types, which are unsigned, narrowing
7015
+ // entails ANDing the value with a mask matching the type width.
7016
+
7017
+ switch (type)
7018
+ {
7019
+ case TR::Int8:
7020
+ if (symRefTab ()->isStaticTypeBool (symRef))
7021
+ {
7022
+ value = TR::Node::create (TR::iand, 2 , value, TR::Node::create (TR::iconst, 0 , 1 ));
7023
+ }
7024
+ else
7025
+ {
7026
+ value = TR::Node::create (TR::i2b, 1 , value);
7027
+ value = TR::Node::create (TR::b2i, 1 , value);
7028
+ }
7029
+ break ;
7030
+ case TR::Int16:
7031
+ if (symRefTab ()->isStaticTypeChar (symRef))
7032
+ {
7033
+ value = TR::Node::create (TR::iand, 2 , value, TR::Node::create (TR::iconst, 0 , 0xffff ));
7034
+ }
7035
+ else
7036
+ {
7037
+ value = TR::Node::create (TR::i2s, 1 , value);
7038
+ value = TR::Node::create (TR::s2i, 1 , value);
7039
+ }
7040
+ break ;
7041
+ default :
7042
+ break ;
7043
+ }
7044
+
7045
+ return value;
7046
+ }
7047
+
7001
7048
void
7002
7049
TR_J9ByteCodeIlGenerator::storeInstance (TR::SymbolReference * symRef)
7003
7050
{
@@ -7019,8 +7066,8 @@ TR_J9ByteCodeIlGenerator::storeInstance(TR::SymbolReference * symRef)
7019
7066
}
7020
7067
else
7021
7068
{
7022
- if (type == TR::Int8 && symRefTab ()-> isFieldTypeBool (symRef ))
7023
- value = TR::Node::create (TR::iand, 2 , value, TR::Node::create (TR::iconst, 0 , 1 ) );
7069
+ if (type. isIntegral ( ))
7070
+ value = narrowIntStoreIfRequired ( value, symRef );
7024
7071
node = TR::Node::createWithSymRef (comp ()->il .opCodeForIndirectStore (type), 2 , 2 , addressNode, value, symRef);
7025
7072
}
7026
7073
@@ -7303,8 +7350,9 @@ TR_J9ByteCodeIlGenerator::storeStatic(int32_t cpIndex)
7303
7350
TR::Node * node;
7304
7351
7305
7352
TR_J9VMBase *fej9 = (TR_J9VMBase *)fe ();
7306
- if (type == TR::Int8 && symRefTab ()->isStaticTypeBool (symRef))
7307
- value = TR::Node::create (TR::iand, 2 , value, TR::Node::create (TR::iconst, 0 , 1 ));
7353
+
7354
+ if (type.isIntegral ())
7355
+ value = narrowIntStoreIfRequired (value, symRef);
7308
7356
7309
7357
if ((type == TR::Address && _generateWriteBarriersForGC) || _generateWriteBarriersForFieldWatch)
7310
7358
{
0 commit comments