private bool GetArrayValue(ClrType type, ulong addr, int index, out object result) { var componentType = type.ComponentType; // componentType being null is a dac bug which should only happen when we have an array of // value types, where we have never *actually* constructed one of the types. If there are // other dac bugs which cause this, we unfortunately cannot work around it. if (addr == 0 || componentType == null) { result = new ClrNullValue(m_heap); return(true); } if (index < 0 || index >= m_len) { throw new IndexOutOfRangeException(); } // Now construct the value based on the element type. if (componentType.ElementType == ClrElementType.Struct) { addr = type.GetArrayElementAddress(addr, index); result = new ClrObject(m_heap, componentType, addr, true); return(true); } else if (componentType.IsObjectReference) { addr = type.GetArrayElementAddress(addr, index); if (!m_heap.Runtime.ReadPointer(addr, out addr) || addr == 0) { result = new ClrNullValue(m_heap); return(true); } else { result = new ClrObject(m_heap, componentType, addr); return(true); } } else if (componentType.IsPrimitive) { result = new ClrPrimitiveValue(type.GetArrayElementValue(addr, index), componentType.ElementType); return(true); } result = null; return(false); }
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (IsNull()) { result = new ClrNullValue(m_heap); return(true); } if (m_type.IsArray) { // Populate length for bounds check. if (m_len == -1) { m_len = m_type.GetArrayLength(m_addr); } int index = GetIndexFromObjects(indexes); return(GetArrayValue(m_type, m_addr, index, out result)); } // Dictionary if (IsDictionary()) { if (indexes.Length != 1) { throw new ArgumentException("Only one index is allowed for Dictionary indexing."); } dynamic dict = ((dynamic)this); dynamic entries = dict.entries; ClrInstanceField key = ((ClrType)entries).ComponentType.GetFieldByName("key"); // Two cases: The key is an object or string, denoted by "System.__Canon", or it's a primitive. // otherwise we don't support it. var keyType = key.Type; if (keyType.IsObjectReference) { Debug.Assert(keyType.Name == "System.__Canon"); if (indexes[0].GetType() == typeof(string)) { string index = (string)indexes[0]; int len = dict.count; for (int i = 0; i < len; ++i) { if ((string)entries[i].key == index) { result = entries[i].value; return(true); } } throw new KeyNotFoundException(); } else { ulong addr; if (indexes[0].GetType() == typeof(long)) { addr = (ulong)(long)indexes[0]; } else if (indexes[0].GetType() == typeof(ulong)) { addr = (ulong)indexes[0]; } else { addr = (ulong)(dynamic)indexes[0]; } int len = dict.count; for (int i = 0; i < len; ++i) { if ((ulong)entries[i].key == addr) { result = entries[i].value; return(true); } } } } else if (keyType.IsPrimitive) { object index = indexes[0]; if (index is ClrPrimitiveValue) { index = ((ClrPrimitiveValue)index).GetValue(); } Type type = index.GetType(); int len = dict.count; for (int i = 0; i < len; ++i) { ClrPrimitiveValue value = entries[i].key; if (value.GetValue().Equals(index)) { result = entries[i].value; return(true); } } throw new KeyNotFoundException(); } } if (IsList()) { int index = GetIndexFromObjects(indexes); var itemsField = m_type.GetFieldByName("_items"); ulong addr = (ulong)itemsField.GetValue(m_addr); // Populate length for bounds check. if (m_len == -1) { var sizeField = m_type.GetFieldByName("_size"); m_len = (int)sizeField.GetValue(m_addr); } // If type is null, then we've hit a dac bug. Attempt to work around it, // but we'll have to give up if getting the object type directly doesn't work. ClrType type = itemsField.Type; if (type == null || type.ComponentType == null) { type = m_heap.GetObjectType(addr); if (type == null || type.ComponentType == null) { result = new ClrNullValue(m_heap); return(true); } } return(GetArrayValue(type, addr, index, out result)); } throw new InvalidOperationException(string.Format("Object of type '{0}' is not indexable.", m_type.Name)); }
public override bool TryGetMember(GetMemberBinder binder, out object result) { if (IsNull()) { result = new ClrNullValue(m_heap); return(true); } ClrInstanceField field = null; if (binder.IgnoreCase) { foreach (var inst in m_type.Fields) { if (inst.Name.Equals(binder.Name, StringComparison.CurrentCultureIgnoreCase)) { field = inst; break; } } } else { field = m_type.GetFieldByName(binder.Name); } if (field == null) { if (ClrDynamicClass.GetStaticField(m_heap, m_type, binder, out result)) { return(true); } throw new InvalidOperationException(string.Format("Type '{0}' does not contain a '{1}' field.", m_type.Name, binder.Name)); } if (field.IsPrimitive) { object value = field.GetValue(m_addr, m_inner); if (value == null) { result = new ClrNullValue(m_heap); } else { result = new ClrPrimitiveValue(value, field.ElementType); } return(true); } else if (field.IsValueClass) { ulong addr = field.GetAddress(m_addr, m_inner); result = new ClrObject(m_heap, field.Type, addr, true); return(true); } else if (field.ElementType == ClrElementType.String) { ulong addr = field.GetAddress(m_addr, m_inner); if (!m_heap.Runtime.ReadPointer(addr, out addr)) { result = new ClrNullValue(m_heap); return(true); } result = new ClrObject(m_heap, field.Type, addr); return(true); } else { object value = field.GetValue(m_addr, m_inner); if (value == null) { result = new ClrNullValue(m_heap); } else { result = new ClrObject(m_heap, field.Type, (ulong)value); } return(true); } }