Skip to content

Commit 834db0c

Browse files
authored
Add runtime helper IsReferenceOrContainsReferences (#3214)
***NO_CI***
1 parent eb1578c commit 834db0c

File tree

5 files changed

+172
-6
lines changed

5 files changed

+172
-6
lines changed

src/CLR/CorLib/corlib_native.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ static const CLR_RT_MethodHandler method_lookup[] =
744744
Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::GetObjectValue___STATIC__OBJECT__OBJECT,
745745
Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::RunClassConstructor___STATIC__VOID__SystemRuntimeTypeHandle,
746746
Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::get_OffsetToStringData___STATIC__I4,
747+
Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::IsReferenceOrContainsReferences___STATIC__BOOLEAN,
747748
nullptr,
748749
Library_corlib_native_System_Runtime_Remoting_RemotingServices::IsTransparentProxy___STATIC__BOOLEAN__OBJECT,
749750
nullptr,
@@ -1572,7 +1573,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib =
15721573

15731574
#if (NANOCLR_REFLECTION == TRUE)
15741575

1575-
0xF9C8A1EA,
1576+
0xCF059C3B,
15761577

15771578
#elif (NANOCLR_REFLECTION == FALSE)
15781579

src/CLR/CorLib/corlib_native.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,17 @@ struct Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers
876876
NANOCLR_NATIVE_DECLARE(RunClassConstructor___STATIC__VOID__SystemRuntimeTypeHandle);
877877
NANOCLR_NATIVE_DECLARE(get_OffsetToStringData___STATIC__I4);
878878

879+
#if (NANOCLR_REFLECTION == TRUE)
880+
NANOCLR_NATIVE_DECLARE(IsReferenceOrContainsReferences___STATIC__BOOLEAN);
881+
#endif
882+
879883
//--//
884+
885+
static HRESULT CheckReferenceOrContainsReferences(
886+
const CLR_RT_TypeDef_Index &cls,
887+
NanoCLRDataType dt,
888+
CLR_RT_SignatureParser *parserCaller,
889+
bool &isRefContainsRefs);
880890
};
881891

882892
struct Library_corlib_native_System_Runtime_Remoting_RemotingServices

src/CLR/CorLib/corlib_native_System_Runtime_CompilerServices_RuntimeHelpers.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,157 @@ HRESULT Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::ge
220220

221221
NANOCLR_NOCLEANUP();
222222
}
223+
224+
#if (NANOCLR_REFLECTION == TRUE)
225+
226+
HRESULT Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::
227+
IsReferenceOrContainsReferences___STATIC__BOOLEAN(CLR_RT_StackFrame &stack)
228+
{
229+
NANOCLR_HEADER();
230+
231+
bool isRefContainsRefs = false;
232+
233+
// exceptionally need to push the return value
234+
CLR_RT_HeapBlock &top = stack.PushValueAndClear();
235+
236+
// grab caller
237+
CLR_RT_MethodDef_Instance &caller = stack.MethodCall();
238+
239+
// parse the method signature to grab the generic argument
240+
CLR_RT_MethodSpec_Instance thisMethodSpecInst;
241+
thisMethodSpecInst.InitializeFromIndex(caller.methodSpec);
242+
243+
CLR_RT_SignatureParser parserCaller;
244+
parserCaller.Initialize_MethodSignature(&thisMethodSpecInst);
245+
246+
CLR_RT_SignatureParser::Element element;
247+
248+
// advance to the 1st (and only parameter)
249+
parserCaller.Advance(element);
250+
251+
if (element.DataType == DATATYPE_GENERICINST)
252+
{
253+
parserCaller.Advance(element);
254+
}
255+
256+
NANOCLR_CHECK_HRESULT(
257+
CheckReferenceOrContainsReferences(element.Class, element.DataType, &parserCaller, isRefContainsRefs));
258+
259+
top.SetBoolean(isRefContainsRefs);
260+
261+
NANOCLR_NOCLEANUP();
262+
}
263+
264+
HRESULT Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::CheckReferenceOrContainsReferences(
265+
const CLR_RT_TypeDef_Index &cls,
266+
NanoCLRDataType dt,
267+
CLR_RT_SignatureParser *parserCaller,
268+
bool &isRefContainsRefs)
269+
{
270+
NANOCLR_HEADER();
271+
272+
if (dt <= DATATYPE_LAST_NONPOINTER)
273+
{
274+
// primitive types aren't and don't contain references
275+
isRefContainsRefs |= false;
276+
}
277+
else if (dt == DATATYPE_CLASS || dt == DATATYPE_VALUETYPE)
278+
{
279+
// for class and value types need to check the instance fields
280+
281+
// get the type definition
282+
CLR_RT_TypeDef_Instance inst{};
283+
inst.InitializeFromIndex(cls);
284+
285+
const CLR_RECORD_FIELDDEF *targetField = nullptr;
286+
CLR_RT_Assembly *assm = nullptr;
287+
CLR_RT_TypeDef_Instance instSub = inst;
288+
289+
int clsFields = instSub.target->instanceFieldsCount;
290+
int totFields = inst.CrossReference().totalFields;
291+
292+
if (totFields == 0)
293+
{
294+
// this class has no fields, therefore doesn't contain references
295+
isRefContainsRefs |= false;
296+
}
297+
298+
// Crawl all instance fields from last to first
299+
while (--totFields >= 0)
300+
{
301+
while (clsFields == 0)
302+
{
303+
if (instSub.SwitchToParent() == false)
304+
{
305+
NANOCLR_SET_AND_LEAVE(CLR_E_FAIL);
306+
}
307+
308+
clsFields = instSub.target->instanceFieldsCount;
309+
targetField = nullptr;
310+
}
311+
312+
if (targetField == nullptr)
313+
{
314+
assm = instSub.assembly;
315+
targetField = assm->GetFieldDef(instSub.target->firstInstanceField + clsFields);
316+
}
317+
318+
// move to the previous field (GetFieldDef returns a pointer one past the last when indexed this way)
319+
targetField--;
320+
clsFields--;
321+
322+
#if defined(NANOCLR_INSTANCE_NAMES)
323+
const char *typeName = assm->GetString(targetField->type);
324+
const char *fieldName = assm->GetString(targetField->name);
325+
#endif
326+
// parse the field signature to discover its element type/levels
327+
CLR_RT_SignatureParser parser{};
328+
parser.Initialize_FieldDef(assm, targetField);
329+
330+
CLR_RT_SignatureParser::Element element;
331+
NANOCLR_CHECK_HRESULT(parser.Advance(element));
332+
333+
if (element.DataType == DATATYPE_MVAR)
334+
{
335+
NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
336+
}
337+
else if (element.DataType == DATATYPE_VAR)
338+
{
339+
CLR_RT_SignatureParser::Element typeElement;
340+
341+
// get the type from the caller's generic type
342+
for (int paramIndex = 0; paramIndex <= element.GenericParamPosition; paramIndex++)
343+
{
344+
parserCaller->Advance(typeElement);
345+
}
346+
347+
NANOCLR_CHECK_HRESULT(CheckReferenceOrContainsReferences(
348+
typeElement.Class,
349+
typeElement.DataType,
350+
parserCaller,
351+
isRefContainsRefs));
352+
353+
// has levels, therefore it's an array
354+
isRefContainsRefs |= true;
355+
}
356+
else
357+
{
358+
// recurse using the element information
359+
NANOCLR_CHECK_HRESULT(CheckReferenceOrContainsReferences(
360+
element.Class,
361+
element.DataType,
362+
parserCaller,
363+
isRefContainsRefs));
364+
}
365+
}
366+
}
367+
else
368+
{
369+
// everything else are or contain references
370+
isRefContainsRefs |= true;
371+
}
372+
373+
NANOCLR_NOCLEANUP();
374+
}
375+
376+
#endif

src/CLR/Core/TypeSystem.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,7 @@ void CLR_RT_MethodDef_Instance::ClearInstance()
16041604
{
16051605
NATIVE_PROFILE_CLR_CORE();
16061606
CLR_RT_MethodDef_Index::Clear();
1607+
methodSpec.Clear();
16071608

16081609
assembly = nullptr;
16091610
target = nullptr;
@@ -1758,8 +1759,7 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(
17581759

17591760
const CLR_RECORD_METHODSPEC *ms = assembly->GetMethodSpec(index);
17601761

1761-
CLR_RT_MethodSpec_Index msIndex;
1762-
msIndex.Set(assembly->assemblyIndex, index);
1762+
methodSpec.Set(assembly->assemblyIndex, index);
17631763

17641764
switch (ms->MethodKind())
17651765
{
@@ -1791,10 +1791,10 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(
17911791
}
17921792
case TBL_TypeSpec:
17931793
{
1794-
CLR_RT_MethodSpec_Index methodSpec;
1795-
assm->FindMethodSpecFromTypeSpec(index, methodSpec);
1794+
CLR_RT_MethodSpec_Index newMethodSpec;
1795+
assm->FindMethodSpecFromTypeSpec(index, newMethodSpec);
17961796

1797-
const CLR_RECORD_METHODSPEC *ms = assm->GetMethodSpec(index);
1797+
const CLR_RECORD_METHODSPEC *ms = assm->GetMethodSpec(newMethodSpec.Method());
17981798

17991799
switch (ms->MethodKind())
18001800
{

src/CLR/Include/nanoCLR_Runtime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,7 @@ struct CLR_RT_MethodDef_Instance : public CLR_RT_MethodDef_Index
21752175
const CLR_RECORD_METHODDEF *target;
21762176

21772177
const CLR_RT_TypeSpec_Index *genericType;
2178+
CLR_RT_MethodSpec_Index methodSpec;
21782179

21792180
#if defined(NANOCLR_INSTANCE_NAMES)
21802181
const char *name;

0 commit comments

Comments
 (0)