@@ -895,11 +895,11 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
895
895
}
896
896
897
897
TypeDesc token = ( TypeDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
898
- if ( token . IsGCPointer )
898
+ if ( token . IsGCPointer || popped . Value is not ByRefValue byrefVal )
899
899
{
900
900
return Status . Fail ( methodIL . OwningMethod , opcode ) ;
901
901
}
902
- ( ( ByRefValue ) popped . Value ) . Initialize ( token . GetElementSize ( ) . AsInt ) ;
902
+ byrefVal . Initialize ( token . GetElementSize ( ) . AsInt ) ;
903
903
}
904
904
break ;
905
905
@@ -1415,6 +1415,53 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
1415
1415
}
1416
1416
break ;
1417
1417
1418
+ case ILOpcode . ldind_i1 :
1419
+ case ILOpcode . ldind_u1 :
1420
+ case ILOpcode . ldind_i2 :
1421
+ case ILOpcode . ldind_u2 :
1422
+ case ILOpcode . ldind_i4 :
1423
+ case ILOpcode . ldind_u4 :
1424
+ case ILOpcode . ldind_i8 :
1425
+ {
1426
+ StackEntry entry = stack . Pop ( ) ;
1427
+ if ( entry . Value is ByRefValue byRefVal )
1428
+ {
1429
+ switch ( opcode )
1430
+ {
1431
+ case ILOpcode . ldind_i1 :
1432
+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( byRefVal . DereferenceAsSByte ( ) ) ) ;
1433
+ break ;
1434
+ case ILOpcode . ldind_u1 :
1435
+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( byte ) byRefVal . DereferenceAsSByte ( ) ) ) ;
1436
+ break ;
1437
+ case ILOpcode . ldind_i2 :
1438
+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( byRefVal . DereferenceAsInt16 ( ) ) ) ;
1439
+ break ;
1440
+ case ILOpcode . ldind_u2 :
1441
+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( ushort ) byRefVal . DereferenceAsInt16 ( ) ) ) ;
1442
+ break ;
1443
+ case ILOpcode . ldind_i4 :
1444
+ case ILOpcode . ldind_u4 :
1445
+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( byRefVal . DereferenceAsInt32 ( ) ) ) ;
1446
+ break ;
1447
+ case ILOpcode . ldind_i8 :
1448
+ stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( byRefVal . DereferenceAsInt64 ( ) ) ) ;
1449
+ break ;
1450
+ case ILOpcode . ldind_r4 :
1451
+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( byRefVal . DereferenceAsSingle ( ) ) ) ;
1452
+ break ;
1453
+ case ILOpcode . ldind_r8 :
1454
+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( byRefVal . DereferenceAsDouble ( ) ) ) ;
1455
+ break ;
1456
+ }
1457
+ }
1458
+ else
1459
+ {
1460
+ ThrowHelper . ThrowInvalidProgramException ( ) ;
1461
+ }
1462
+ }
1463
+ break ;
1464
+
1418
1465
case ILOpcode . constrained :
1419
1466
// Fallthrough. If this is ever implemented, make sure delegates to static virtual methods
1420
1467
// are also handled. We currently assume the frozen delegate will not be to a static
@@ -1428,12 +1475,20 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
1428
1475
return Status . Fail ( methodIL . OwningMethod , "Control fell through" ) ;
1429
1476
}
1430
1477
1431
- private static ValueTypeValue NewUninitializedLocationValue ( TypeDesc locationType )
1478
+ private static BaseValueTypeValue NewUninitializedLocationValue ( TypeDesc locationType )
1432
1479
{
1433
1480
if ( locationType . IsGCPointer || locationType . IsByRef )
1434
1481
{
1435
1482
return null ;
1436
1483
}
1484
+ else if ( locationType . IsByRefLike && locationType is MetadataType maybeReadOnlySpan
1485
+ && maybeReadOnlySpan . Module == locationType . Context . SystemModule
1486
+ && maybeReadOnlySpan . Name == "ReadOnlySpan`1"
1487
+ && maybeReadOnlySpan . Namespace == "System"
1488
+ && maybeReadOnlySpan . Instantiation [ 0 ] is MetadataType readOnlySpanElementType )
1489
+ {
1490
+ return new ReadOnlySpanValue ( readOnlySpanElementType , Array . Empty < byte > ( ) ) ;
1491
+ }
1437
1492
else
1438
1493
{
1439
1494
Debug . Assert ( locationType . IsValueType || locationType . IsPointer || locationType . IsFunctionPointer ) ;
@@ -1460,6 +1515,33 @@ private static bool TryHandleIntrinsicCall(MethodDesc method, Value[] parameters
1460
1515
return array . TryInitialize ( rvaData ) ;
1461
1516
}
1462
1517
return false ;
1518
+ case "CreateSpan" :
1519
+ if ( method . OwningType is MetadataType createSpanType
1520
+ && createSpanType . Name == "RuntimeHelpers" && createSpanType . Namespace == "System.Runtime.CompilerServices"
1521
+ && createSpanType . Module == createSpanType . Context . SystemModule
1522
+ && parameters [ 0 ] is RuntimeFieldHandleValue createSpanFieldHandle
1523
+ && createSpanFieldHandle . Field . IsStatic && createSpanFieldHandle . Field . HasRva
1524
+ && createSpanFieldHandle . Field is Internal . TypeSystem . Ecma . EcmaField createSpanEcmaField
1525
+ && method . Instantiation [ 0 ] . IsValueType )
1526
+ {
1527
+ var elementType = ( MetadataType ) method . Instantiation [ 0 ] ;
1528
+ int elementSize = elementType . InstanceFieldSize . AsInt ;
1529
+ byte [ ] rvaData = Internal . TypeSystem . Ecma . EcmaFieldExtensions . GetFieldRvaData ( createSpanEcmaField ) ;
1530
+ if ( rvaData . Length % elementSize != 0 )
1531
+ return false ;
1532
+ retVal = new ReadOnlySpanValue ( elementType , rvaData ) ;
1533
+ return true ;
1534
+ }
1535
+ return false ;
1536
+ case "get_Item" :
1537
+ if ( method . OwningType is MetadataType readonlySpanType
1538
+ && readonlySpanType . Name == "ReadOnlySpan`1" && readonlySpanType . Namespace == "System"
1539
+ && parameters [ 0 ] is ReadOnlySpanReferenceValue spanRef
1540
+ && parameters [ 1 ] is ValueTypeValue spanIndex )
1541
+ {
1542
+ return spanRef . TryAccessElement ( spanIndex . AsInt32 ( ) , out retVal ) ;
1543
+ }
1544
+ return false ;
1463
1545
}
1464
1546
1465
1547
return false ;
@@ -1938,6 +2020,93 @@ public override bool GetRawData(NodeFactory factory, out object data)
1938
2020
}
1939
2021
}
1940
2022
2023
+ private sealed class ReadOnlySpanValue : BaseValueTypeValue , IInternalModelingOnlyValue
2024
+ {
2025
+ private readonly MetadataType _elementType ;
2026
+ private readonly byte [ ] _bytes ;
2027
+
2028
+ public ReadOnlySpanValue ( MetadataType elementType , byte [ ] bytes )
2029
+ {
2030
+ _elementType = elementType ;
2031
+ _bytes = bytes ;
2032
+ }
2033
+
2034
+ public override int Size => 2 * _elementType . Context . Target . PointerSize ;
2035
+
2036
+ public override bool Equals ( Value value )
2037
+ {
2038
+ // ceq instruction on ReadOnlySpans is hard to support.
2039
+ // We should not see it in the first place.
2040
+ ThrowHelper . ThrowInvalidProgramException ( ) ;
2041
+ return false ;
2042
+ }
2043
+
2044
+ public override void WriteFieldData ( ref ObjectDataBuilder builder , NodeFactory factory )
2045
+ {
2046
+ throw new NotSupportedException ( ) ;
2047
+ }
2048
+
2049
+ public override bool GetRawData ( NodeFactory factory , out object data )
2050
+ {
2051
+ data = null ;
2052
+ return false ;
2053
+ }
2054
+
2055
+ public override Value Clone ( )
2056
+ {
2057
+ // ReadOnlySpan is immutable and there's no way for the data to escape
2058
+ return this ;
2059
+ }
2060
+
2061
+ public override bool TryCreateByRef ( out Value value )
2062
+ {
2063
+ value = new ReadOnlySpanReferenceValue ( _elementType , _bytes ) ;
2064
+ return true ;
2065
+ }
2066
+ }
2067
+
2068
+ private sealed class ReadOnlySpanReferenceValue : Value
2069
+ {
2070
+ private readonly MetadataType _elementType ;
2071
+ private readonly byte [ ] _bytes ;
2072
+
2073
+ public ReadOnlySpanReferenceValue ( MetadataType elementType , byte [ ] bytes )
2074
+ {
2075
+ _elementType = elementType ;
2076
+ _bytes = bytes ;
2077
+ }
2078
+
2079
+ public override bool Equals ( Value value )
2080
+ {
2081
+ // ceq instruction on refs to ReadOnlySpans is hard to support.
2082
+ // We should not see it in the first place.
2083
+ ThrowHelper . ThrowInvalidProgramException ( ) ;
2084
+ return false ;
2085
+ }
2086
+
2087
+ public override void WriteFieldData ( ref ObjectDataBuilder builder , NodeFactory factory )
2088
+ {
2089
+ throw new NotSupportedException ( ) ;
2090
+ }
2091
+
2092
+ public override bool GetRawData ( NodeFactory factory , out object data )
2093
+ {
2094
+ data = null ;
2095
+ return false ;
2096
+ }
2097
+
2098
+ public bool TryAccessElement ( int index , out Value value )
2099
+ {
2100
+ value = default ;
2101
+ int limit = _bytes . Length / _elementType . InstanceFieldSize . AsInt ;
2102
+ if ( index >= limit )
2103
+ return false ;
2104
+
2105
+ value = new ByRefValue ( _bytes , index * _elementType . InstanceFieldSize . AsInt ) ;
2106
+ return true ;
2107
+ }
2108
+ }
2109
+
1941
2110
private sealed class MethodPointerValue : BaseValueTypeValue , IInternalModelingOnlyValue
1942
2111
{
1943
2112
public MethodDesc PointedToMethod { get ; }
@@ -2021,6 +2190,20 @@ public override bool GetRawData(NodeFactory factory, out object data)
2021
2190
data = null ;
2022
2191
return false ;
2023
2192
}
2193
+
2194
+ private ReadOnlySpan < byte > AsExactByteCount ( int count )
2195
+ {
2196
+ if ( PointedToOffset + count > PointedToBytes . Length )
2197
+ ThrowHelper . ThrowInvalidProgramException ( ) ;
2198
+ return new ReadOnlySpan < byte > ( PointedToBytes , PointedToOffset , count ) ;
2199
+ }
2200
+
2201
+ public sbyte DereferenceAsSByte ( ) => ( sbyte ) AsExactByteCount ( 1 ) [ 0 ] ;
2202
+ public short DereferenceAsInt16 ( ) => BitConverter . ToInt16 ( AsExactByteCount ( 2 ) ) ;
2203
+ public int DereferenceAsInt32 ( ) => BitConverter . ToInt32 ( AsExactByteCount ( 4 ) ) ;
2204
+ public long DereferenceAsInt64 ( ) => BitConverter . ToInt64 ( AsExactByteCount ( 8 ) ) ;
2205
+ public float DereferenceAsSingle ( ) => BitConverter . ToSingle ( AsExactByteCount ( 4 ) ) ;
2206
+ public double DereferenceAsDouble ( ) => BitConverter . ToDouble ( AsExactByteCount ( 8 ) ) ;
2024
2207
}
2025
2208
2026
2209
private abstract class ReferenceTypeValue : Value
0 commit comments