@@ -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
0 commit comments