80
80
import jdk .graal .compiler .nodes .ValueNode ;
81
81
import jdk .graal .compiler .nodes .ValuePhiNode ;
82
82
import jdk .graal .compiler .nodes .calc .AddNode ;
83
+ import jdk .graal .compiler .nodes .calc .AndNode ;
83
84
import jdk .graal .compiler .nodes .calc .ConditionalNode ;
84
85
import jdk .graal .compiler .nodes .calc .FloatingIntegerDivRemNode ;
85
86
import jdk .graal .compiler .nodes .calc .IntegerBelowNode ;
89
90
import jdk .graal .compiler .nodes .calc .IsNullNode ;
90
91
import jdk .graal .compiler .nodes .calc .LeftShiftNode ;
91
92
import jdk .graal .compiler .nodes .calc .NarrowNode ;
93
+ import jdk .graal .compiler .nodes .calc .OrNode ;
92
94
import jdk .graal .compiler .nodes .calc .ReinterpretNode ;
93
95
import jdk .graal .compiler .nodes .calc .RightShiftNode ;
94
96
import jdk .graal .compiler .nodes .calc .SignExtendNode ;
@@ -834,7 +836,7 @@ protected ReadNode createUnsafeRead(StructuredGraph graph, RawLoadNode load, Gua
834
836
} else {
835
837
memoryRead .setGuard (guard );
836
838
}
837
- ValueNode readValue = performBooleanCoercionIfNecessary ( implicitLoadConvert ( graph , readKind , memoryRead , compressible ), readKind );
839
+ ValueNode readValue = implicitUnsafeLoadConvert ( graph , readKind , memoryRead , compressible );
838
840
load .replaceAtUsages (readValue );
839
841
return memoryRead ;
840
842
}
@@ -849,18 +851,18 @@ protected void lowerUnsafeMemoryLoadNode(UnsafeMemoryLoadNode load) {
849
851
// An unsafe read must not float otherwise it may float above
850
852
// a test guaranteeing the read is safe.
851
853
memoryRead .setForceFixed (true );
852
- ValueNode readValue = performBooleanCoercionIfNecessary ( implicitLoadConvert ( graph , readKind , memoryRead , false ), readKind );
854
+ ValueNode readValue = implicitUnsafeLoadConvert ( graph , readKind , memoryRead , false );
853
855
load .replaceAtUsages (readValue );
854
856
graph .replaceFixedWithFixed (load , memoryRead );
855
857
}
856
858
857
- private static ValueNode performBooleanCoercionIfNecessary ( ValueNode readValue , JavaKind readKind ) {
858
- if ( readKind == JavaKind . Boolean ) {
859
- StructuredGraph graph = readValue . graph ();
860
- IntegerEqualsNode eq = graph . addOrUnique ( new IntegerEqualsNode ( readValue , ConstantNode . forInt ( 0 , graph )));
861
- return graph . addOrUnique ( new ConditionalNode ( eq , ConstantNode . forBoolean ( false , graph ), ConstantNode . forBoolean ( true , graph )));
862
- }
863
- return readValue ;
859
+ /**
860
+ * Coerce integer values into a boolean 0 or 1 to match Java semantics. The returned nodes have
861
+ * not been added to the graph.
862
+ */
863
+ private static ValueNode performBooleanCoercion ( ValueNode readValue ) {
864
+ IntegerEqualsNode eq = new IntegerEqualsNode ( readValue , ConstantNode . forInt ( 0 ));
865
+ return new ConditionalNode ( eq , ConstantNode . forBoolean ( false ), ConstantNode . forBoolean ( true )) ;
864
866
}
865
867
866
868
protected void lowerUnsafeStoreNode (RawStoreNode store ) {
@@ -1273,45 +1275,66 @@ protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
1273
1275
return stamp ;
1274
1276
}
1275
1277
1276
- public final ValueNode implicitLoadConvertWithBooleanCoercionIfNecessary (StructuredGraph graph , JavaKind kind , ValueNode value ) {
1277
- return performBooleanCoercionIfNecessary (implicitLoadConvert (graph , kind , value ), kind );
1278
+ protected abstract ValueNode newCompressionNode (CompressionOp op , ValueNode value );
1279
+
1280
+ /**
1281
+ * Perform sign or zero extensions for subword types, and convert potentially unsafe 8 bit
1282
+ * boolean values into 0 or 1. The nodes have already been added to the graph.
1283
+ */
1284
+ public final ValueNode implicitUnsafeLoadConvert (StructuredGraph graph , JavaKind kind , ValueNode value , boolean compressible ) {
1285
+ if (compressible && kind .isObject ()) {
1286
+ return implicitLoadConvert (graph , kind , value , compressible );
1287
+ } else {
1288
+ ValueNode ret = implicitUnsafePrimitiveLoadConvert (kind , value );
1289
+ if (!ret .isAlive ()) {
1290
+ ret = graph .addOrUniqueWithInputs (ret );
1291
+ }
1292
+ return ret ;
1293
+ }
1278
1294
}
1279
1295
1280
1296
public final ValueNode implicitLoadConvert (StructuredGraph graph , JavaKind kind , ValueNode value ) {
1281
1297
return implicitLoadConvert (graph , kind , value , true );
1282
1298
}
1283
1299
1284
- public ValueNode implicitLoadConvert (JavaKind kind , ValueNode value ) {
1285
- return implicitLoadConvert (kind , value , true );
1286
- }
1287
-
1300
+ /**
1301
+ * Perform sign or zero extensions for subword types and add the nodes to the graph.
1302
+ */
1288
1303
protected final ValueNode implicitLoadConvert (StructuredGraph graph , JavaKind kind , ValueNode value , boolean compressible ) {
1289
- ValueNode ret = implicitLoadConvert (kind , value , compressible );
1304
+ ValueNode ret ;
1305
+ if (useCompressedOops (kind , compressible )) {
1306
+ ret = newCompressionNode (CompressionOp .Uncompress , value );
1307
+ } else {
1308
+ ret = implicitPrimitiveLoadConvert (kind , value );
1309
+ }
1310
+
1290
1311
if (!ret .isAlive ()) {
1291
- ret = graph .addOrUnique (ret );
1312
+ ret = graph .addOrUniqueWithInputs (ret );
1292
1313
}
1293
1314
return ret ;
1294
1315
}
1295
1316
1296
- protected abstract ValueNode newCompressionNode (CompressionOp op , ValueNode value );
1297
-
1298
1317
/**
1299
- * @param compressible whether the convert should be compressible
1318
+ * Perform sign or zero extensions for subword types. The caller is expected to add an resulting
1319
+ * nodes to the graph.
1300
1320
*/
1301
- protected ValueNode implicitLoadConvert (JavaKind kind , ValueNode value , boolean compressible ) {
1302
- if (useCompressedOops (kind , compressible )) {
1303
- return newCompressionNode (CompressionOp .Uncompress , value );
1304
- }
1321
+ public static ValueNode implicitPrimitiveLoadConvert (JavaKind kind , ValueNode value ) {
1322
+ return switch (kind ) {
1323
+ case Byte , Short -> new SignExtendNode (value , 32 );
1324
+ case Boolean , Char -> new ZeroExtendNode (value , 32 );
1325
+ default -> value ;
1326
+ };
1327
+ }
1305
1328
1306
- switch ( kind ) {
1307
- case Byte :
1308
- case Short :
1309
- return new SignExtendNode ( value , 32 );
1310
- case Boolean :
1311
- case Char :
1312
- return new ZeroExtendNode (value , 32 );
1329
+ /**
1330
+ * Perform sign or zero extensions for subword types, and convert potentially unsafe 8 bit
1331
+ * boolean values into 0 or 1. The caller is expected to add an resulting * nodes to the graph.
1332
+ */
1333
+ public static ValueNode implicitUnsafePrimitiveLoadConvert ( JavaKind kind , ValueNode value ) {
1334
+ if ( kind == JavaKind . Boolean ) {
1335
+ return performBooleanCoercion ( new ZeroExtendNode (value , 32 ) );
1313
1336
}
1314
- return value ;
1337
+ return implicitPrimitiveLoadConvert ( kind , value ) ;
1315
1338
}
1316
1339
1317
1340
public ValueNode arrayImplicitStoreConvert (StructuredGraph graph ,
@@ -1368,15 +1391,60 @@ protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean
1368
1391
return newCompressionNode (CompressionOp .Compress , value );
1369
1392
}
1370
1393
1371
- switch (kind ) {
1372
- case Boolean :
1373
- case Byte :
1374
- return new NarrowNode (value , 8 );
1375
- case Char :
1376
- case Short :
1377
- return new NarrowNode (value , 16 );
1378
- }
1379
- return value ;
1394
+ return implicitPrimitiveStoreConvert (kind , value );
1395
+ }
1396
+
1397
+ public static ValueNode implicitPrimitiveStoreConvert (JavaKind kind , ValueNode value ) {
1398
+ return switch (kind ) {
1399
+ case Boolean , Byte -> new NarrowNode (value , 8 );
1400
+ case Char , Short -> new NarrowNode (value , 16 );
1401
+ default -> value ;
1402
+ };
1403
+ }
1404
+
1405
+ /**
1406
+ * Simulate a primitive store.
1407
+ *
1408
+ * So for code like:
1409
+ *
1410
+ * <pre>
1411
+ * static class Data {
1412
+ * int value = 0xF0F0F0F0;
1413
+ * }
1414
+ *
1415
+ * Data data = new Data();
1416
+ * UNSAFE.putByte(data, FIELD_OFFSET, 0x0F);
1417
+ * </pre>
1418
+ *
1419
+ * The field value of the data object is 0xF0F0F0F0 before the unsafe write operation and
1420
+ * 0xF0F0F00F after the unsafe write operation. We are not allowed to touch the upper 3 bytes.
1421
+ * To simulate the write operation we extract the appropriate bytes and combine them.
1422
+ * <p>
1423
+ * Example for a byte operation, currently stored value 0xF0F0F0F0 and value to store
1424
+ * 0x0000000F:
1425
+ *
1426
+ * <pre>
1427
+ * lowerBytesMask = 00000000 00000000 00000000 11111111
1428
+ * upperBytesMask = 11111111 11111111 11111111 00000000
1429
+ * currentStored = 11110000 11110000 11110000 11110000
1430
+ * valueToStore = 00000000 00000000 00000000 00001111
1431
+ * newValue = (currentStored & upperBytesMask) | (valueToStore & lowerBytesMask)
1432
+ * = 11110000 11110000 11110000 00001111
1433
+ * </pre>
1434
+ *
1435
+ */
1436
+ public static ValueNode simulatePrimitiveStore (JavaKind kind , ValueNode currentValue , ValueNode valueToStore ) {
1437
+ // compute the masks
1438
+ int bitCount = kind .getByteCount () * 8 ;
1439
+ int lowerBytesMask = (int ) CodeUtil .mask (bitCount );
1440
+ int upperBytesMask = ~lowerBytesMask ;
1441
+
1442
+ // extract the upper bytes from the current entry
1443
+ ValueNode upperBytes = AndNode .create (ConstantNode .forInt (upperBytesMask ), currentValue , NodeView .DEFAULT );
1444
+ // extract the lower bytes from the value
1445
+ ValueNode lowerBytes = AndNode .create (ConstantNode .forInt (lowerBytesMask ), valueToStore , NodeView .DEFAULT );
1446
+ // combine both
1447
+ return OrNode .create (upperBytes , lowerBytes , NodeView .DEFAULT );
1380
1448
}
1381
1449
1382
1450
protected abstract ValueNode createReadHub (StructuredGraph graph , ValueNode object , LoweringTool tool );
0 commit comments