/// <summary> /// Returns true if this is a type that doesn't require marshalling. /// </summary> private static bool IsBlittableType(TypeDesc type) { type = type.UnderlyingType; if (type.IsValueType) { if (type.IsPrimitive) { // All primitive types except char and bool are blittable TypeFlags category = type.Category; if (category == TypeFlags.Boolean || category == TypeFlags.Char) return false; return true; } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) continue; TypeDesc fieldType = field.FieldType; // TODO: we should also reject fields that specify custom marshalling if (!IsBlittableType(fieldType)) return false; } return true; } if (type.IsPointer) return true; return false; }
private int GatherClassGCLayout(TypeDesc type, byte* gcPtrs) { int result = 0; foreach (var field in type.GetFields()) { if (field.IsStatic) continue; CorInfoGCType gcType = CorInfoGCType.TYPE_GC_NONE; var fieldType = field.FieldType; if (fieldType.IsValueType) { if (!((MetadataType)fieldType).ContainsPointers) continue; gcType = CorInfoGCType.TYPE_GC_OTHER; } else if ((fieldType is DefType) || (fieldType is ArrayType)) { gcType = CorInfoGCType.TYPE_GC_REF; } else if (fieldType.IsByRef) { gcType = CorInfoGCType.TYPE_GC_BYREF; } else { continue; } Debug.Assert(field.Offset % PointerSize == 0); byte* fieldGcPtrs = gcPtrs + field.Offset / PointerSize; if (gcType == CorInfoGCType.TYPE_GC_OTHER) { result += GatherClassGCLayout(fieldType, fieldGcPtrs); } else { // Ensure that if we have multiple fields with the same offset, // that we don't double count the data in the gc layout. if (*fieldGcPtrs == (byte)CorInfoGCType.TYPE_GC_NONE) { *fieldGcPtrs = (byte)gcType; result++; } else { Debug.Assert(*fieldGcPtrs == (byte)gcType); } } } return result; }
private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t) { bool explicitLayout = false; ClassLayoutMetadata classLayoutMetadata = default(ClassLayoutMetadata); if (t.IsValueType) { MetadataType metadataType = (MetadataType)t; if (metadataType.IsExplicitLayout) { explicitLayout = true; classLayoutMetadata = metadataType.GetClassLayout(); } } int instanceFieldIndex = 0; if (explicitLayout) { sb.AppendLine(); sb.Append("union {"); sb.Indent(); } foreach (var field in t.GetFields()) { if (field.IsStatic) { if (field.IsLiteral) continue; TypeDesc fieldType = GetFieldTypeOrPlaceholder(field); CppGenerationBuffer builder; if (!fieldType.IsValueType) { builder = _gcStatics; } else { // TODO: Valuetype statics with GC references builder = _statics; } builder.AppendLine(); builder.Append(GetCppSignatureTypeName(fieldType)); builder.Append(" "); builder.Append(GetCppStaticFieldName(field) + ";"); } else { if (explicitLayout) { sb.AppendLine(); sb.Append("struct {"); sb.Indent(); int offset = classLayoutMetadata.Offsets[instanceFieldIndex].Offset; if (offset > 0) { sb.AppendLine(); sb.Append("char __pad" + instanceFieldIndex + "[" + offset + "];"); } } sb.AppendLine(); sb.Append(GetCppSignatureTypeName(GetFieldTypeOrPlaceholder(field)) + " " + GetCppFieldName(field) + ";"); if (explicitLayout) { sb.Exdent(); sb.AppendLine(); sb.Append("};"); } instanceFieldIndex++; } } if (explicitLayout) { sb.Exdent(); sb.AppendLine(); sb.Append("};"); } }
private void AddTypeReference(TypeDesc type, bool constructed) { AddTypeDependency(type, constructed); foreach (var field in type.GetFields()) { AddTypeDependency(field.FieldType, false); } }
private void OutputType(TypeDesc t, bool full) { _emittedTypes.Add(t); if (full) { if (!t.IsValueType) { var baseType = t.BaseType; if (baseType != null) { if (!_emittedTypes.Contains(baseType)) { OutputType(baseType, full); } } } foreach (var field in t.GetFields()) { var fieldType = GetFieldTypeOrPlaceholder(field); if (fieldType.IsValueType && !fieldType.IsPrimitive && !field.IsStatic) { if (!_emittedTypes.Contains(fieldType)) { OutputType(fieldType, full); } } } } string mangledName = GetCppTypeName(t); int nesting = 0; int current = 0; for (;;) { int sep = mangledName.IndexOf("::", current); if (sep < 0) break; Out.Write("namespace " + mangledName.Substring(current, sep - current) + " { "); current = sep + 2; nesting++; } if (full) { Out.Write("class " + mangledName.Substring(current)); if (!t.IsValueType) { var baseType = t.BaseType; if (baseType != null) { Out.Write(" : public " + GetCppTypeName(baseType)); } } Out.WriteLine(" { public:"); // TODO: Enable once the dependencies are tracked for arrays // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) if (!t.IsPointer && !t.IsByRef) { Out.WriteLine("static MethodTable * __getMethodTable();"); } List<MethodDesc> virtualSlots; _compilation.NodeFactory.VirtualSlots.TryGetValue(t, out virtualSlots); if (virtualSlots != null) { int baseSlots = 0; var baseType = t.BaseType; while (baseType != null) { List<MethodDesc> baseVirtualSlots; _compilation.NodeFactory.VirtualSlots.TryGetValue(baseType, out baseVirtualSlots); if (baseVirtualSlots != null) baseSlots += baseVirtualSlots.Count; baseType = baseType.BaseType; } for (int slot = 0; slot < virtualSlots.Count; slot++) { MethodDesc virtualMethod = virtualSlots[slot]; Out.WriteLine(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); } } if (t.IsDelegate) { Out.WriteLine(GetCodeForDelegate(t)); } OutputTypeFields(t); if (t.HasStaticConstructor) { _statics.AppendLine("bool __cctor_" + GetCppTypeName(t).Replace("::", "__") + ";"); } List<MethodDesc> methodList; if (_methodLists.TryGetValue(t, out methodList)) { foreach (var m in methodList) { OutputMethod(m); } } Out.Write("};"); } else { Out.Write("class " + mangledName.Substring(current) + ";"); } while (nesting > 0) { Out.Write(" };"); nesting--; } Out.WriteLine(); }
private void ExpandType(TypeDesc type) { if (_emittedTypes.Contains(type)) return; _emittedTypes.Add(type); GetCppSignatureTypeName(type); var baseType = type.BaseType; if (baseType != null) { ExpandType(baseType); } foreach (var field in type.GetFields()) { ExpandType(GetFieldTypeOrPlaceholder(field)); } if (type.IsDelegate) { MethodDesc method = type.GetMethod("Invoke", null); var sig = method.Signature; ExpandType(sig.ReturnType); for (int i = 0; i < sig.Length; i++) ExpandType(sig[i]); } if (type.IsArray) { ExpandType(((ArrayType)type).ElementType); } }
private void OutputType(CppGenerationBuffer sb, TypeDesc t, bool full) { _emittedTypes.Add(t); if (full) { if (!t.IsValueType) { var baseType = t.BaseType; if (baseType != null) { if (!_emittedTypes.Contains(baseType)) { OutputType(sb, baseType, full); } } } foreach (var field in t.GetFields()) { var fieldType = GetFieldTypeOrPlaceholder(field); if (fieldType.IsValueType && !fieldType.IsPrimitive && !field.IsStatic) { if (!_emittedTypes.Contains(fieldType)) { OutputType(sb, fieldType, full); } } } } string mangledName = GetCppTypeName(t); int nesting = 0; int current = 0; // Create Namespaces. If a mangledName starts with just :: we will simply ignore it. sb.AppendLine(); for (;;) { int sep = mangledName.IndexOf("::", current); if (sep < 0) break; if (sep != 0) { // Case of a name not starting with :: sb.Append("namespace " + mangledName.Substring(current, sep - current) + " { "); nesting++; } current = sep + 2; } if (full) { sb.Append("class " + mangledName.Substring(current)); if (!t.IsValueType) { if (t.BaseType != null) { sb.Append(" : public " + GetCppTypeName(t.BaseType)); } } sb.Append(" {"); sb.AppendLine(); sb.Append("public:"); sb.Indent(); // TODO: Enable once the dependencies are tracked for arrays // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) if (!t.IsPointer && !t.IsByRef) { sb.AppendLine(); sb.Append("static MethodTable * __getMethodTable();"); } IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(t).Slots; int baseSlots = 0; var baseType = t.BaseType; while (baseType != null) { IReadOnlyList<MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots; if (baseVirtualSlots != null) baseSlots += baseVirtualSlots.Count; baseType = baseType.BaseType; } for (int slot = 0; slot < virtualSlots.Count; slot++) { MethodDesc virtualMethod = virtualSlots[slot]; sb.AppendLine(); sb.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); } if (t.IsDelegate) { sb.AppendLine(); sb.Append(GetCodeForDelegate(t)); } OutputTypeFields(sb, t); if (t.HasStaticConstructor) { _statics.AppendLine(); _statics.Append("bool __cctor_" + GetCppTypeName(t).Replace("::", "__") + ";"); } List<MethodDesc> methodList; if (_methodLists.TryGetValue(t, out methodList)) { foreach (var m in methodList) { OutputMethod(sb, m); } } sb.Exdent(); sb.AppendLine(); sb.Append("};"); } else { sb.Append("class " + mangledName.Substring(current) + ";"); } while (nesting > 0) { sb.Append("};"); nesting--; } // Make some rooms between two type definitions if (full) sb.AppendEmptyLine(); }
private void AddInstanceFields(TypeDesc type) { foreach (var field in type.GetFields()) { if (!field.IsStatic) { _compilation.AddField(field); var fieldType = field.FieldType; if (fieldType.IsValueType && !fieldType.IsPrimitive) AddInstanceFields(fieldType); } } }
/// <summary> /// Returns true if struct doesn't have fields that require marshalling. /// </summary> private static bool IsBlittableStruct(TypeDesc type) { if (type.IsValueType) { foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) continue; TypeDesc fieldType = field.FieldType; // TODO: we should also reject fields that specify custom marshalling if (!IsSimpleType(fieldType) && !IsBlittableStruct(fieldType)) return false; } return true; } return false; }
/// <summary> /// Returns true if this is a type that doesn't require marshalling. /// </summary> private static bool IsBlittableType(TypeDesc type) { type = type.UnderlyingType; if (type.IsValueType) { if (type.IsPrimitive) { // All primitive types except char and bool are blittable TypeFlags category = type.Category; if (category == TypeFlags.Boolean || category == TypeFlags.Char) return false; return true; } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) continue; TypeDesc fieldType = field.FieldType; // TODO: we should also reject fields that specify custom marshalling if (!IsBlittableType(fieldType)) { // This field can still be blittable if it's a Char and marshals as Unicode var owningType = field.OwningType as MetadataType; if (owningType == null) return false; if (fieldType.Category != TypeFlags.Char || owningType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass) return false; } } return true; } if (type.IsPointer) return true; return false; }
private void AddTypeReference(TypeDesc type, bool constructed) { // CppImporter will rather arbitrarily try to generate types as constructed. // Stomp over the choice and only allow this if it remotely makes sense. constructed = constructed & ConstructedEETypeNode.CreationAllowed(type); AddTypeDependency(type, constructed); foreach (var field in type.GetFields()) { AddTypeDependency(field.FieldType, false); } }