Skip to content

Commit 5b23ee9

Browse files
authored
Add SZArrayHelper and Unsafe.As<T> (#257)
1 parent 7c0182d commit 5b23ee9

File tree

3 files changed

+177
-1
lines changed

3 files changed

+177
-1
lines changed

nanoFramework.CoreLibrary/CoreLibrary.nfproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
<Compile Include="System\Collections\Generic\IEnumerator.cs" />
7575
<Compile Include="System\Diagnostics\StackTraceHiddenAttribute.cs" />
7676
<Compile Include="System\Nullable.cs" />
77+
<Compile Include="System\Runtime\CompilerServices\Unsafe.cs" />
7778
<Compile Include="System\Runtime\InteropServices\InAttribute .cs" />
7879
<Compile Include="System\Diagnostics\NativeProfiledAttribute.cs" />
7980
<Compile Include="System\PlatformNotSupportedException.cs" />
@@ -262,4 +263,4 @@
262263
<Import Project="..\packages\Microsoft.SourceLink.Common.1.1.1\build\Microsoft.SourceLink.Common.targets" Condition="Exists('..\packages\Microsoft.SourceLink.Common.1.1.1\build\Microsoft.SourceLink.Common.targets')" />
263264
<Import Project="..\packages\Microsoft.SourceLink.GitHub.1.1.1\build\Microsoft.SourceLink.GitHub.targets" Condition="Exists('..\packages\Microsoft.SourceLink.GitHub.1.1.1\build\Microsoft.SourceLink.GitHub.targets')" />
264265
<Import Project="..\packages\Nerdbank.GitVersioning.3.7.115\build\Nerdbank.GitVersioning.targets" Condition="Exists('..\packages\Nerdbank.GitVersioning.3.7.115\build\Nerdbank.GitVersioning.targets')" />
265-
</Project>
266+
</Project>

nanoFramework.CoreLibrary/System/Array.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
using System.Collections;
55
using System.Runtime.CompilerServices;
6+
#if NANOCLR_REFLECTION
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
#endif // NANOCLR_REFLECTION
610

711
namespace System
812
{
@@ -429,5 +433,153 @@ public void Reset()
429433
_index = _startIndex - 1;
430434
}
431435
}
436+
437+
#if NANOCLR_REFLECTION
438+
#pragma warning disable CA1822 // Mark members as static
439+
//----------------------------------------------------------------------------------------
440+
// ! READ THIS BEFORE YOU WORK ON THIS CLASS.
441+
//
442+
// The methods on this class must be written VERY carefully to avoid introducing security holes.
443+
// That's because they are invoked with special "this"! The "this" object
444+
// for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
445+
// where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
446+
// see a lot of expressions that cast "this" "T[]".
447+
//
448+
// This class is needed to allow an SZ array of type T[] to expose IList<T>,
449+
// IList<T.BaseType>, etc., etc. all the way up to IList<Object>. When the following call is
450+
// made:
451+
//
452+
// ((IList<T>) (new U[n])).SomeIListMethod()
453+
//
454+
// the interface stub dispatcher treats this as a special case, loads up SZArrayHelper,
455+
// finds the corresponding generic method (matched simply by method name), instantiates
456+
// it for type <T> and executes it.
457+
//
458+
// The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be
459+
// array that is castable to "T[]" (i.e. for primitives and valuetypes, it will be exactly
460+
// "T[]" - for orefs, it may be a "U[]" where U derives from T.)
461+
//----------------------------------------------------------------------------------------
462+
internal sealed class SZArrayHelper
463+
{
464+
// It is never legal to instantiate this class.
465+
private SZArrayHelper()
466+
{
467+
Debug.Assert(false, "Hey! How'd I get here?");
468+
}
469+
470+
internal IEnumerator<T> GetEnumerator<T>()
471+
{
472+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
473+
// ! or you may introduce a security hole!
474+
T[] @this = Unsafe.As<T[]>(this);
475+
int length = @this.Length;
476+
return length == 0 ? SZGenericArrayEnumerator<T>.Empty : new SZGenericArrayEnumerator<T>(@this, length);
477+
}
478+
479+
private void CopyTo<T>(T[] array, int index)
480+
{
481+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
482+
// ! or you may introduce a security hole!
483+
484+
T[] @this = Unsafe.As<T[]>(this);
485+
Array.Copy(@this, 0, array, index, @this.Length);
486+
}
487+
488+
internal int get_Count<T>()
489+
{
490+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
491+
// ! or you may introduce a security hole!
492+
T[] @this = Unsafe.As<T[]>(this);
493+
return @this.Length;
494+
}
495+
496+
internal T get_Item<T>(int index)
497+
{
498+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
499+
// ! or you may introduce a security hole!
500+
501+
T[] @this = Unsafe.As<T[]>(this);
502+
if ((uint)index >= (uint)@this.Length)
503+
{
504+
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
505+
throw new ArgumentOutOfRangeException();
506+
#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
507+
}
508+
509+
return @this[index];
510+
}
511+
512+
internal void set_Item<T>(int index, T value)
513+
{
514+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
515+
// ! or you may introduce a security hole!
516+
T[] @this = Unsafe.As<T[]>(this);
517+
if ((uint)index >= (uint)@this.Length)
518+
{
519+
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
520+
throw new ArgumentOutOfRangeException();
521+
#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
522+
}
523+
524+
@this[index] = value;
525+
}
526+
527+
private void Add<T>(T _)
528+
{
529+
// Not meaningful for arrays.
530+
throw new NotSupportedException();
531+
}
532+
533+
private bool Contains<T>(T value)
534+
{
535+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
536+
// ! or you may introduce a security hole!
537+
T[] @this = Unsafe.As<T[]>(this);
538+
return Array.IndexOf(@this, value, 0, @this.Length) >= 0;
539+
}
540+
541+
private bool get_IsReadOnly<T>()
542+
{
543+
return true;
544+
}
545+
546+
private void Clear<T>()
547+
{
548+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
549+
// ! or you may introduce a security hole!
550+
551+
throw new NotSupportedException();
552+
}
553+
554+
private int IndexOf<T>(T value)
555+
{
556+
// ! Warning: "this" is an array, not an SZArrayHelper. See comments above
557+
// ! or you may introduce a security hole!
558+
T[] @this = Unsafe.As<T[]>(this);
559+
return Array.IndexOf(@this, value, 0, @this.Length);
560+
}
561+
562+
private void Insert<T>(int _, T _1)
563+
{
564+
// Not meaningful for arrays
565+
throw new NotSupportedException();
566+
}
567+
568+
private bool Remove<T>(T _)
569+
{
570+
// Not meaningful for arrays
571+
throw new NotSupportedException();
572+
return default;
573+
}
574+
575+
private void RemoveAt<T>(int _)
576+
{
577+
// Not meaningful for arrays
578+
throw new NotSupportedException();
579+
}
580+
}
581+
#pragma warning restore CA1822
582+
583+
#endif
432584
}
433585
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#if NANOCLR_REFLECTION
5+
#nullable enable
6+
7+
namespace System.Runtime.CompilerServices
8+
{
9+
/// <summary>
10+
/// Contains generic, low-level functionality for manipulating pointers.
11+
/// </summary>
12+
public static unsafe partial class Unsafe
13+
{
14+
/// <summary>
15+
/// Casts the given object to the specified type, performs no dynamic type checking.
16+
/// </summary>
17+
/// <typeparam name="T">The target reference type. The return value will be of this type.</typeparam>
18+
[MethodImpl(MethodImplOptions.InternalCall)]
19+
public static extern T? As<T>(object? o) where T : class?;
20+
}
21+
}
22+
23+
#endif

0 commit comments

Comments
 (0)