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); }