/// <summary> /// Fill in the GC-relevant stack frame locations. /// </summary> private void FakeGcScanRoots(MethodDesc method, ArgIterator argit, CORCOMPILE_GCREFMAP_TOKENS[] frame) { // Encode generic instantiation arg if (argit.HasParamType) { if (method.RequiresInstMethodDescArg()) { frame[argit.GetParamTypeArgOffset()] = CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_METHOD_PARAM; } else if (method.RequiresInstMethodTableArg()) { frame[argit.GetParamTypeArgOffset()] = CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_TYPE_PARAM; } } // If the function has a this pointer, add it to the mask if (argit.HasThis) { bool isUnboxingStub = false; // TODO: is this correct? bool interior = method.OwningType.IsValueType && !isUnboxingStub; frame[_transitionBlock.ThisOffset] = (interior ? CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_INTERIOR : CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_REF); } if (argit.IsVarArg) { frame[argit.GetVASigCookieOffset()] = CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_VASIG_COOKIE; // We are done for varargs - the remaining arguments are reported via vasig cookie return; } // Also if the method has a return buffer, then it is the first argument, and could be an interior ref, // so always promote it. if (argit.HasRetBuffArg()) { frame[_transitionBlock.GetRetBuffArgOffset(argit.HasThis)] = CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_INTERIOR; } // // Now iterate the arguments // // Cycle through the arguments, and call GcScanRoots for each int argIndex = 0; int argOffset; while ((argOffset = argit.GetNextOffset()) != TransitionBlock.InvalidOffset) { ArgLocDesc? argLocDescForStructInRegs = argit.GetArgLoc(argOffset); ArgDestination argDest = new ArgDestination(_transitionBlock, argOffset, argLocDescForStructInRegs); GcScanRoots(method.Signature[argIndex], in argDest, delta: 0, frame); argIndex++; } }