4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
+ using System . Runtime . InteropServices ;
7
8
8
9
using ILCompiler . DependencyAnalysis ;
9
10
@@ -402,6 +403,7 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
402
403
break ;
403
404
404
405
case ILOpcode . call :
406
+ case ILOpcode . callvirt :
405
407
{
406
408
MethodDesc method = ( MethodDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
407
409
MethodSignature methodSig = method . Signature ;
@@ -427,6 +429,13 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
427
429
methodParams [ i ] = stack . PopIntoLocation ( GetArgType ( method , i ) ) ;
428
430
}
429
431
432
+ if ( opcode == ILOpcode . callvirt )
433
+ {
434
+ // Only support non-virtual methods for now + we don't emulate NRE on null this
435
+ if ( method . IsVirtual || methodParams [ 0 ] == null )
436
+ return Status . Fail ( methodIL . OwningMethod , opcode ) ;
437
+ }
438
+
430
439
Value retVal ;
431
440
if ( ! method . IsIntrinsic || ! TryHandleIntrinsicCall ( method , methodParams , out retVal ) )
432
441
{
@@ -598,6 +607,11 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
598
607
return Status . Fail ( methodIL . OwningMethod , opcode , "Reference field" ) ;
599
608
}
600
609
610
+ if ( field . FieldType . IsByRef )
611
+ {
612
+ return Status . Fail ( methodIL . OwningMethod , opcode , "Byref field" ) ;
613
+ }
614
+
601
615
var settableInstance = instance . Value as IHasInstanceFields ;
602
616
if ( settableInstance == null )
603
617
{
@@ -2259,28 +2273,65 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
2259
2273
public override ReferenceTypeValue ToForeignInstance ( int baseInstructionCounter ) => this ;
2260
2274
}
2261
2275
2262
- private sealed class StringInstance : ReferenceTypeValue
2276
+ private sealed class StringInstance : ReferenceTypeValue , IHasInstanceFields
2263
2277
{
2264
- private readonly string _value ;
2278
+ private readonly byte [ ] _value ;
2265
2279
2280
+ private string ValueAsString
2281
+ {
2282
+ get
2283
+ {
2284
+ FieldDesc firstCharField = Type . GetField ( "_firstChar" ) ;
2285
+ int startOffset = firstCharField . Offset . AsInt ;
2286
+ int length = _value . Length - startOffset - sizeof ( char ) /* terminating null */ ;
2287
+ return new string ( MemoryMarshal . Cast < byte , char > (
2288
+ ( ( ReadOnlySpan < byte > ) _value ) . Slice ( startOffset , length ) ) ) ;
2289
+ }
2290
+ }
2266
2291
public StringInstance ( TypeDesc stringType , string value )
2267
2292
: base ( stringType )
2268
2293
{
2269
- _value = value ;
2294
+ _value = ConstructStringInstance ( stringType , value ) ;
2295
+ }
2296
+
2297
+ private static byte [ ] ConstructStringInstance ( TypeDesc stringType , ReadOnlySpan < char > value )
2298
+ {
2299
+ int pointerSize = stringType . Context . Target . PointerSize ;
2300
+ var bytes = new byte [
2301
+ pointerSize /* MethodTable */
2302
+ + sizeof ( int ) /* length */
2303
+ + ( value . Length * sizeof ( char ) ) /* bytes */
2304
+ + sizeof ( char ) /* null terminator */ ] ;
2305
+
2306
+ FieldDesc lengthField = stringType . GetField ( "_stringLength" ) ;
2307
+ Debug . Assert ( lengthField . FieldType . IsWellKnownType ( WellKnownType . Int32 )
2308
+ && lengthField . Offset . AsInt == pointerSize ) ;
2309
+ new FieldAccessor ( bytes ) . SetField ( lengthField , ValueTypeValue . FromInt32 ( value . Length ) ) ;
2310
+
2311
+ FieldDesc firstCharField = stringType . GetField ( "_firstChar" ) ;
2312
+ Debug . Assert ( firstCharField . FieldType . IsWellKnownType ( WellKnownType . Char )
2313
+ && firstCharField . Offset . AsInt == pointerSize + sizeof ( int ) /* length */ ) ;
2314
+
2315
+ value . CopyTo ( MemoryMarshal . Cast < byte , char > ( ( ( Span < byte > ) bytes ) . Slice ( firstCharField . Offset . AsInt ) ) ) ;
2316
+
2317
+ return bytes ;
2270
2318
}
2271
2319
2272
2320
public override void WriteFieldData ( ref ObjectDataBuilder builder , NodeFactory factory )
2273
2321
{
2274
- builder . EmitPointerReloc ( factory . SerializedStringObject ( _value ) ) ;
2322
+ builder . EmitPointerReloc ( factory . SerializedStringObject ( ValueAsString ) ) ;
2275
2323
}
2276
2324
2277
2325
public override bool GetRawData ( NodeFactory factory , out object data )
2278
2326
{
2279
- data = factory . SerializedStringObject ( _value ) ;
2327
+ data = factory . SerializedStringObject ( ValueAsString ) ;
2280
2328
return true ;
2281
2329
}
2282
2330
2283
2331
public override ReferenceTypeValue ToForeignInstance ( int baseInstructionCounter ) => this ;
2332
+ Value IHasInstanceFields . GetField ( FieldDesc field ) => new FieldAccessor ( _value ) . GetField ( field ) ;
2333
+ void IHasInstanceFields . SetField ( FieldDesc field , Value value ) => ThrowHelper . ThrowInvalidProgramException ( ) ;
2334
+ ByRefValue IHasInstanceFields . GetFieldAddress ( FieldDesc field ) => new FieldAccessor ( _value ) . GetFieldAddress ( field ) ;
2284
2335
}
2285
2336
2286
2337
#pragma warning disable CA1852
0 commit comments