Пример #1
0
        protected void ComputeMetadata <TPolicy>(
            TPolicy policy,
            NodeFactory factory,
            out byte[] metadataBlob,
            out List <MetadataMapping <MetadataType> > typeMappings,
            out List <MetadataMapping <MethodDesc> > methodMappings,
            out List <MetadataMapping <FieldDesc> > fieldMappings,
            out List <MetadataMapping <MethodDesc> > stackTraceMapping) where TPolicy : struct, IMetadataPolicy
        {
            var transformed             = MetadataTransform.Run(policy, GetCompilationModulesWithMetadata());
            MetadataTransform transform = transformed.Transform;

            // TODO: DeveloperExperienceMode: Use transformed.Transform.HandleType() to generate
            //       TypeReference records for _typeDefinitionsGenerated that don't have metadata.
            //       (To be used in MissingMetadataException messages)

            // Generate metadata blob
            var writer = new MetadataWriter();

            writer.ScopeDefinitions.AddRange(transformed.Scopes);

            // Generate entries in the blob for methods that will be necessary for stack trace purposes.
            var stackTraceRecords = new List <KeyValuePair <MethodDesc, MetadataRecord> >();

            foreach (var methodBody in GetCompiledMethodBodies())
            {
                MethodDesc method = methodBody.Method;

                MethodDesc typicalMethod = method.GetTypicalMethodDefinition();

                // Methods that will end up in the reflection invoke table should not have an entry in stack trace table
                // We'll try looking them up in reflection data at runtime.
                if (transformed.GetTransformedMethodDefinition(typicalMethod) != null &&
                    ShouldMethodBeInInvokeMap(method) &&
                    (GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) != 0)
                {
                    continue;
                }

                if (!_stackTraceEmissionPolicy.ShouldIncludeMethod(method))
                {
                    continue;
                }

                MetadataRecord record = transform.HandleQualifiedMethod(typicalMethod);

                // As a twist, instantiated generic methods appear as if instantiated over their formals.
                if (typicalMethod.HasInstantiation)
                {
                    var methodInst = new MethodInstantiation
                    {
                        Method = record,
                    };
                    methodInst.GenericTypeArguments.Capacity = typicalMethod.Instantiation.Length;
                    foreach (EcmaGenericParameter typeArgument in typicalMethod.Instantiation)
                    {
                        var genericParam = new TypeReference
                        {
                            TypeName = (ConstantStringValue)typeArgument.Name,
                        };
                        methodInst.GenericTypeArguments.Add(genericParam);
                    }
                    record = methodInst;
                }

                stackTraceRecords.Add(new KeyValuePair <MethodDesc, MetadataRecord>(
                                          method,
                                          record));

                writer.AdditionalRootRecords.Add(record);
            }

            var ms = new MemoryStream();

            // .NET metadata is UTF-16 and UTF-16 contains code points that don't translate to UTF-8.
            var noThrowUtf8Encoding = new UTF8Encoding(false, false);

            using (var logWriter = _metadataLogFile != null ? new StreamWriter(File.Open(_metadataLogFile, FileMode.Create, FileAccess.Write, FileShare.Read), noThrowUtf8Encoding) : null)
            {
                writer.LogWriter = logWriter;
                writer.Write(ms);
            }

            metadataBlob = ms.ToArray();

            typeMappings      = new List <MetadataMapping <MetadataType> >();
            methodMappings    = new List <MetadataMapping <MethodDesc> >();
            fieldMappings     = new List <MetadataMapping <FieldDesc> >();
            stackTraceMapping = new List <MetadataMapping <MethodDesc> >();

            // Generate type definition mappings
            foreach (var type in factory.MetadataManager.GetTypesWithEETypes())
            {
                MetadataType definition = type.IsTypeDefinition ? type as MetadataType : null;
                if (definition == null)
                {
                    continue;
                }

                MetadataRecord record = transformed.GetTransformedTypeDefinition(definition);

                // Reflection requires that we maintain type identity. Even if we only generated a TypeReference record,
                // if there is an EEType for it, we also need a mapping table entry for it.
                if (record == null)
                {
                    record = transformed.GetTransformedTypeReference(definition);
                }

                if (record != null)
                {
                    typeMappings.Add(new MetadataMapping <MetadataType>(definition, writer.GetRecordHandle(record)));
                }
            }

            foreach (var method in GetCompiledMethods())
            {
                if (method.IsCanonicalMethod(CanonicalFormKind.Specific))
                {
                    // Canonical methods are not interesting.
                    continue;
                }

                if (IsReflectionBlocked(method.Instantiation) || IsReflectionBlocked(method.OwningType.Instantiation))
                {
                    continue;
                }

                if ((GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) == 0)
                {
                    continue;
                }

                MetadataRecord record = transformed.GetTransformedMethodDefinition(method.GetTypicalMethodDefinition());

                if (record != null)
                {
                    methodMappings.Add(new MetadataMapping <MethodDesc>(method, writer.GetRecordHandle(record)));
                }
            }

            foreach (var eetypeGenerated in GetTypesWithEETypes())
            {
                if (eetypeGenerated.IsGenericDefinition)
                {
                    continue;
                }

                if (eetypeGenerated.HasInstantiation)
                {
                    // Collapsing of field map entries based on canonicalization, to avoid redundant equivalent entries

                    TypeDesc canonicalType = eetypeGenerated.ConvertToCanonForm(CanonicalFormKind.Specific);
                    if (canonicalType != eetypeGenerated && TypeGeneratesEEType(canonicalType))
                    {
                        continue;
                    }
                }

                foreach (FieldDesc field in eetypeGenerated.GetFields())
                {
                    if (IsReflectionBlocked(field.OwningType.Instantiation))
                    {
                        continue;
                    }

                    Field record = transformed.GetTransformedFieldDefinition(field.GetTypicalFieldDefinition());
                    if (record != null)
                    {
                        fieldMappings.Add(new MetadataMapping <FieldDesc>(field, writer.GetRecordHandle(record)));
                    }
                }
            }

            // Generate stack trace metadata mapping
            foreach (var stackTraceRecord in stackTraceRecords)
            {
                stackTraceMapping.Add(new MetadataMapping <MethodDesc>(stackTraceRecord.Key, writer.GetRecordHandle(stackTraceRecord.Value)));
            }
        }
Пример #2
0
        private List <MetadataMapping <MethodDesc> > GenerateStackTraceMetadata(NodeFactory factory)
        {
            var transformed             = MetadataTransform.Run(new NoDefinitionMetadataPolicy(), Array.Empty <ModuleDesc>());
            MetadataTransform transform = transformed.Transform;

            // Generate metadata blob
            var writer = new MetadataWriter();

            // Only emit stack trace metadata for those methods which don't have reflection metadata
            HashSet <MethodDesc> methodInvokeMap = new HashSet <MethodDesc>();

            foreach (var mappingEntry in GetMethodMapping(factory))
            {
                var method = mappingEntry.Entity;
                if (ShouldMethodBeInInvokeMap(method))
                {
                    methodInvokeMap.Add(method);
                }
            }

            // Generate entries in the blob for methods that will be necessary for stack trace purposes.
            var stackTraceRecords = new List <KeyValuePair <MethodDesc, MetadataRecord> >();

            foreach (var methodBody in GetCompiledMethodBodies())
            {
                NonExternMethodSymbolNode methodNode = methodBody as NonExternMethodSymbolNode;
                if (methodNode != null && !methodNode.HasCompiledBody)
                {
                    continue;
                }

                MethodDesc method = methodBody.Method;

                if (methodInvokeMap.Contains(method))
                {
                    continue;
                }

                if (!_stackTraceEmissionPolicy.ShouldIncludeMethod(method))
                {
                    continue;
                }

                // In the metadata, we only represent the generic definition
                MethodDesc     methodToGenerateMetadataFor = method.GetTypicalMethodDefinition();
                MetadataRecord record = transform.HandleQualifiedMethod(methodToGenerateMetadataFor);

                // As a twist, instantiated generic methods appear as if instantiated over their formals.
                if (methodToGenerateMetadataFor.HasInstantiation)
                {
                    var methodInst = new MethodInstantiation
                    {
                        Method = record,
                    };
                    methodInst.GenericTypeArguments.Capacity = methodToGenerateMetadataFor.Instantiation.Length;
                    foreach (EcmaGenericParameter typeArgument in methodToGenerateMetadataFor.Instantiation)
                    {
                        var genericParam = new TypeReference
                        {
                            TypeName = (ConstantStringValue)typeArgument.Name,
                        };
                        methodInst.GenericTypeArguments.Add(genericParam);
                    }
                    record = methodInst;
                }

                stackTraceRecords.Add(new KeyValuePair <MethodDesc, MetadataRecord>(
                                          method,
                                          record));

                writer.AdditionalRootRecords.Add(record);
            }

            var ms = new MemoryStream();

            writer.Write(ms);

            _stackTraceBlob = ms.ToArray();

            var result = new List <MetadataMapping <MethodDesc> >();

            // Generate stack trace metadata mapping
            foreach (var stackTraceRecord in stackTraceRecords)
            {
                result.Add(new MetadataMapping <MethodDesc>(stackTraceRecord.Key, writer.GetRecordHandle(stackTraceRecord.Value)));
            }

            return(result);
        }