private static MethodSpec GetVirtualMethod(TypeSpec impl_ts, MethodSpec decl_ms, target.Target t, bool allow_non_virtual = false) { /* Iterate through methods looking for virtual ones */ var first_mdef = impl_ts.m.GetIntEntry(MetadataStream.tid_TypeDef, impl_ts.tdrow, 5); var last_mdef = impl_ts.m.GetLastMethodDef(impl_ts.tdrow); for (uint mdef_row = first_mdef; mdef_row < last_mdef; mdef_row++) { var flags = impl_ts.m.GetIntEntry(MetadataStream.tid_MethodDef, (int)mdef_row, 2); if (allow_non_virtual || (flags & 0x40) == 0x40) { MethodSpec impl_ms; impl_ts.m.GetMethodDefRow(MetadataStream.tid_MethodDef, (int)mdef_row, out impl_ms, impl_ts.gtparams, null); impl_ms.type = impl_ts; if ((flags & 0x400) != 0x400) { // Not marked abstract if (MetadataStream.CompareString(impl_ms.m, impl_ms.m.GetIntEntry(MetadataStream.tid_MethodDef, (int)mdef_row, 3), decl_ms.m, decl_ms.m.GetIntEntry(MetadataStream.tid_MethodDef, (int)decl_ms.mdrow, 3))) { if (MetadataStream.CompareSignature(impl_ms.m, impl_ms.msig, impl_ts.gtparams, null, decl_ms.m, decl_ms.msig, impl_ts.gtparams, null)) { // this is the correct one return(impl_ms); } if (MetadataStream.CompareSignature(impl_ms.m, impl_ms.msig, impl_ts.gtparams, null, decl_ms.m, decl_ms.msig, decl_ms.gtparams, null)) { // this is the correct one return(impl_ms); } } } } } // if not found, look to base classes var bc = impl_ts.GetExtends(); if (bc != null) { return(GetVirtualMethod(bc, decl_ms, t, allow_non_virtual)); } else { return(null); } }
private static int GetVTableIndex(MethodSpec ms, List <VTableItem> list) { for (int idx = 0; idx < list.Count; idx++) { var i = list[idx]; if (MetadataStream.CompareString(ms.m, ms.m.GetIntEntry(MetadataStream.tid_MethodDef, ms.mdrow, 3), i.unimpl_meth.m, i.unimpl_meth.m.GetIntEntry(MetadataStream.tid_MethodDef, i.unimpl_meth.mdrow, 3))) { if (MetadataStream.CompareSignature(ms, i.unimpl_meth)) { return(idx); } } } return(-1); }
public static int GetVTableOffset(metadata.TypeSpec ts, metadata.MethodSpec ms, Target t) { var vtbl = GetVirtualMethodDeclarations(ts); var search_meth_name = ms.m.GetIntEntry(MetadataStream.tid_MethodDef, ms.mdrow, 3); // find the requested method, match on name, signature and declaring type for (int i = 0; i < vtbl.Count; i++) { var test = vtbl[i]; var mdecl = test.unimpl_meth; if (mdecl.type.Equals(ts)) { // Check on name var mname = mdecl.m.GetIntEntry(MetadataStream.tid_MethodDef, mdecl.mdrow, 3); if (MetadataStream.CompareString(mdecl.m, mname, ms.m, search_meth_name)) { // Check on signature if (MetadataStream.CompareSignature(mdecl.m, mdecl.msig, mdecl.gtparams, mdecl.gmparams, ms.m, ms.msig, ms.gtparams, ms.gmparams)) { if (ts.IsInterface == false) { i += (6 + t.ExtraVTableFieldsPointerLength); } return(i); } } } } throw new Exception("Requested virtual method slot not found"); }
public static void ImplementVirtualMethods(TypeSpec ts, List <VTableItem> list) { // We implement those methods in the most derived class first and work back foreach (var i in list) { // skip if already done if (i.impl_meth != null) { continue; } // if we've gone back far enough to the max_implementor class // we can start looking for implementations from here if (i.max_implementor != null && i.max_implementor.Equals(ts)) { i.max_implementor = null; } // if we haven't, skip this method for this class (it will be // implemented in a base class) if (i.max_implementor != null) { continue; } // Now, search for a matching method in this particular class /* Iterate through methods looking for virtual ones */ var first_mdef = ts.m.GetIntEntry(MetadataStream.tid_TypeDef, ts.tdrow, 5); var last_mdef = ts.m.GetLastMethodDef(ts.tdrow); var search_meth_name = i.unimpl_meth.m.GetIntEntry(MetadataStream.tid_MethodDef, i.unimpl_meth.mdrow, 3); for (uint mdef_row = first_mdef; mdef_row < last_mdef; mdef_row++) { var flags = ts.m.GetIntEntry(MetadataStream.tid_MethodDef, (int)mdef_row, 2); if ((flags & 0x40) == 0x40) { // its a virtual method MethodSpec impl_ms; ts.m.GetMethodDefRow(MetadataStream.tid_MethodDef, (int)mdef_row, out impl_ms, ts.gtparams, null); impl_ms.type = ts; // compare on name if (MetadataStream.CompareString(i.unimpl_meth.m, search_meth_name, ts.m, ts.m.GetIntEntry(MetadataStream.tid_MethodDef, (int)mdef_row, 3))) { // and on signature if (MetadataStream.CompareSignature(i.unimpl_meth, impl_ms)) { // If its marked abstract, we dont implement it if ((flags & 0x400) == 0x400) { i.impl_meth = null; } else { // we have found a valid implementing method i.impl_meth = impl_ms; } } } } } } // now implement on base classes var extends = ts.GetExtends(); if (extends != null) { ImplementVirtualMethods(extends, list); } }
public static int GetFieldOffset(metadata.TypeSpec ts, string fname, target.Target t, out bool is_tls, bool is_static = false, List <TypeSpec> field_types = null, List <string> field_names = null, List <int> field_offsets = null) { int align = 1; is_tls = false; if (ts.SimpleType == 0) // class { align = GetTypeAlignment(ts, t, is_static); } if (ts.SimpleType == 0xe && !is_static) // string { align = t.GetPointerSize(); } if (ts.Equals(ts.m.SystemString) && !is_static) { /* System.String has a special layout in dotnet clr because the fields * length and firstchar are reversed */ if (field_names != null) { field_names.Add("__vtbl"); field_names.Add("__mutex_lock"); field_names.Add("m_stringLength"); field_names.Add("m_firstChar"); } if (field_types != null) { field_types.Add(ts.m.SystemIntPtr); field_types.Add(ts.m.SystemInt64); field_types.Add(ts.m.SystemInt32); field_types.Add(ts.m.SystemChar); } if (field_offsets != null) { field_offsets.Add(0); field_offsets.Add(GetArrayFieldOffset(ArrayField.MutexLock, t)); field_offsets.Add(GetTypeSize(ts.m.SystemObject, t)); field_offsets.Add(GetTypeSize(ts.m.SystemObject, t) + t.GetPointerSize()); } if (fname == null) { // size = sizeof(Object) + sizeof(int length), aligned to pointer size return(GetTypeSize(ts.m.SystemObject, t) + t.GetPointerSize()); } else { if (fname == "length" || fname == "m_stringLength") { return(GetTypeSize(ts.m.SystemObject, t)); } else if (fname == "start_char" || fname == "m_firstChar") { return(GetTypeSize(ts.m.SystemObject, t) + t.GetPointerSize()); } else { throw new NotSupportedException(); } } } /* Iterate through methods looking for requested * one */ var first_fdef = ts.m.GetIntEntry(MetadataStream.tid_TypeDef, ts.tdrow, 4); var last_fdef = ts.m.GetLastFieldDef(ts.tdrow); int cur_offset = 0; int cur_tl_offset = 0; if (is_static == false && !ts.IsValueType) { if (ts.GetExtends() == null) { // Add a vtable entry if (field_offsets != null) { field_offsets.Add(cur_offset); } cur_offset += t.GetCTSize(ir.Opcode.ct_object); cur_offset = util.util.align(cur_offset, align); if (field_types != null) { field_types.Add(ts.m.SystemIntPtr); } if (field_names != null) { field_names.Add("__vtbl"); } // Add a mutex lock entry if (field_offsets != null) { field_offsets.Add(cur_offset); } cur_offset += t.GetCTSize(ir.Opcode.ct_int64); cur_offset = util.util.align(cur_offset, align); if (field_types != null) { field_types.Add(ts.m.SystemInt64); } if (field_names != null) { field_names.Add("__mutex_lock"); } } else { cur_offset = GetFieldOffset(ts.GetExtends(), (string)null, t, out is_tls, is_static, field_types, field_names, field_offsets); cur_offset = util.util.align(cur_offset, align); } } else if (is_static) { // Add an is_initalized field cur_offset += t.GetCTSize(ir.Opcode.ct_intptr); cur_offset = util.util.align(cur_offset, align); } for (uint fdef_row = first_fdef; fdef_row < last_fdef; fdef_row++) { // Ensure field is static if requested var flags = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 0); if (((flags & 0x10) == 0x10 && is_static == true) || ((flags & 0x10) == 0 && is_static == false)) { // Check on name if we are looking for a particular field bool f_is_tls = ts.m.thread_local_fields[fdef_row]; if (fname != null) { var ffname = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 1); if (MetadataStream.CompareString(ts.m, ffname, fname)) { if (f_is_tls) { is_tls = true; return(cur_tl_offset); } else { is_tls = false; return(cur_offset); } } } // Increment by type size var fsig = (int)ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 2); var ft = ts.m.GetFieldType(ref fsig, ts.gtparams, null); var ft_size = t.GetSize(ft); if (field_types != null) { field_types.Add(ft); } if (field_names != null) { var cur_fname = ts.m.GetStringEntry(MetadataStream.tid_Field, (int)fdef_row, 1); field_names.Add(cur_fname); } if (field_offsets != null) { if (f_is_tls) { field_offsets.Add(cur_tl_offset); } else { field_offsets.Add(cur_offset); } } if (f_is_tls) { cur_tl_offset += ft_size; cur_tl_offset = util.util.align(cur_tl_offset, align); } else { cur_offset += ft_size; cur_offset = util.util.align(cur_offset, align); } } } // Shouldn't get here if looking for a specific field if (fname != null) { throw new MissingFieldException(); } // Else return size of complete type return(cur_offset); }
public static int GetFieldOffset(metadata.TypeSpec ts, metadata.MethodSpec fs, target.Target t, out bool is_tls, bool is_static = false) { int align = 1; is_tls = false; if (ts.SimpleType == 0 || ts.SimpleType == 0xe) // class or string { align = GetTypeAlignment(ts, t, is_static); } /* Iterate through methods looking for requested * one */ var first_fdef = ts.m.GetIntEntry(MetadataStream.tid_TypeDef, ts.tdrow, 4); var last_fdef = ts.m.GetLastFieldDef(ts.tdrow); uint search_field_name = 0; if (fs != null) { search_field_name = fs.m.GetIntEntry(MetadataStream.tid_Field, fs.mdrow, 1); } int cur_offset = 0; int cur_tl_offset = 0; if (is_static == false && !ts.IsValueType) { if (ts.GetExtends() == null) { // Add a vtable entry cur_offset += t.GetCTSize(ir.Opcode.ct_object); cur_offset = util.util.align(cur_offset, align); // Add a mutex lock entry cur_offset += t.GetCTSize(ir.Opcode.ct_int64); cur_offset = util.util.align(cur_offset, align); } else { cur_offset = GetFieldOffset(ts.GetExtends(), (string)null, t, out is_tls); cur_offset = util.util.align(cur_offset, align); } } else if (is_static) { // Add an is_initalized field cur_offset += t.GetCTSize(ir.Opcode.ct_intptr); cur_offset = util.util.align(cur_offset, align); } for (uint fdef_row = first_fdef; fdef_row < last_fdef; fdef_row++) { // Ensure field is static if requested var flags = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 0); if (((flags & 0x10) == 0x10 && is_static == true) || ((flags & 0x10) == 0 && is_static == false)) { // Check on name if we are looking for a particular field bool f_is_tls = ts.m.thread_local_fields[fdef_row]; if (search_field_name != 0) { var fname = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 1); if (MetadataStream.CompareString(ts.m, fname, fs.m, search_field_name)) { if (f_is_tls) { is_tls = true; return(cur_tl_offset); } else { is_tls = false; return(cur_offset); } } } // Increment by type size var fsig = (int)ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 2); var ft = ts.m.GetFieldType(ref fsig, ts.gtparams, null); var ft_size = t.GetSize(ft); if (f_is_tls) { cur_tl_offset += ft_size; cur_tl_offset = util.util.align(cur_tl_offset, align); } else { cur_offset += ft_size; cur_offset = util.util.align(cur_offset, align); } } } // Shouldn't get here if looking for a specific field if (search_field_name != 0) { throw new MissingFieldException(); } // Else return size of complete type return(cur_offset); }