private CachingResult LoadStandardDictionaryFast(ILGenerator ilGenerator, IDictionary<string, object> dictionary) { Assumes.NotNull(ilGenerator); Assumes.NotNull(dictionary); Assumes.IsTrue(dictionary.Count < GenerationServices.StandardDictionaryGeneratorsCount); CachingResult result = CachingResult.SucceededResult; MethodInfo standardDictionaryGenerator = this._standardDictionaryGenerators[dictionary.Count]; // all we need to do is load all keys and values on stack and then invoke the standard generator foreach (KeyValuePair<string, object> dictionaryItem in dictionary) { // load key - boxing is never required for strings result = result.MergeResult(this.LoadValue(ilGenerator, dictionaryItem.Key)); // load value result = result.MergeResult(this.LoadValue(ilGenerator, dictionaryItem.Value)); if (GenerationServices.IsBoxingRequiredForValue(dictionaryItem.Value)) { ilGenerator.Emit(OpCodes.Box, dictionaryItem.Value.GetType()); } } // call the standard dictionary generator - this would load the value on stack ilGenerator.EmitCall(OpCodes.Call, standardDictionaryGenerator, null); return result; }
private CachingResult LoadEnumerable(ILGenerator ilGenerator, IEnumerable enumerable) { Assumes.NotNull(ilGenerator); Assumes.NotNull(enumerable); CachingResult result = CachingResult.SucceededResult; // We load enumerable as an array - this is the most compact and efficient way of representing it Type elementType = null; Type closedType = null; if (GenerationServices.TryGetGenericInterfaceType(enumerable.GetType(), GenerationServices.IEnumerableTypeofT, out closedType)) { elementType = closedType.GetGenericArguments()[0]; } else { elementType = typeof(object); } elementType = GenerationServices.NormalizeCollectionElementType(elementType); // // elem[] array = new elem[<enumerable.Count()>] // GenerationServices.LoadInt(ilGenerator, enumerable.Cast<object>().Count()); ilGenerator.Emit(OpCodes.Newarr, elementType); // at this point we have the array on the stack int index = 0; foreach (object value in enumerable) { // //array[<index>] = value; // // load the array on teh stack again ilGenerator.Emit(OpCodes.Dup); GenerationServices.LoadInt(ilGenerator, index); result = result.MergeResult(this.LoadValue(ilGenerator, value)); if (GenerationServices.IsBoxingRequiredForValue(value) && !elementType.IsValueType) { ilGenerator.Emit(OpCodes.Box, value.GetType()); } ilGenerator.Emit(OpCodes.Stelem, elementType); index++; // at this point we have the array on teh stack again } // the array is already on the stack - just exit return result; }
private CachingResult LoadGenericDictionary<TKey, TValue>(ILGenerator ilGenerator, IDictionary<TKey, TValue> dictionary, bool isStandardDictionary) { Assumes.NotNull(ilGenerator); Assumes.NotNull(dictionary); CachingResult result = CachingResult.SucceededResult; Type keyType = GenerationServices.NormalizeCollectionElementType(typeof(TKey)); Type valueType = GenerationServices.NormalizeCollectionElementType(typeof(TValue)); Type dictionaryType = null; MethodInfo dictionaryAddMethod = null; ConstructorInfo dictionaryConstructor = null; if (isStandardDictionary) { dictionaryType = GenerationServices.standardDictionaryType; dictionaryAddMethod = GenerationServices.standardDictionaryAddMethod; dictionaryConstructor = dictionaryType.GetConstructor(new Type[] { Int32Type }); } else { dictionaryType = GenerationServices.GenericDictionaryType.MakeGenericType(keyType, valueType); dictionaryAddMethod = dictionaryType.GetMethod("Add", new Type[] { keyType, valueType }); dictionaryConstructor = dictionaryType.GetConstructor(new Type[] { Int32Type }); } // // Dictionary<TKey, TValue> metadata = new Dictionary<TKey, TValue>(capacity) // // create and load the dictionary GenerationServices.LoadInt(ilGenerator, dictionary.Count); ilGenerator.Emit(OpCodes.Newobj, dictionaryConstructor); // // Generate a sequence of "Add" statements // foreach (KeyValuePair<TKey, TValue> dictionaryItem in dictionary) { // // metadata.Add(key, value) // // the dictionary is on top of the stack - load it again ilGenerator.Emit(OpCodes.Dup); // load the key, boxing if necessary result = result.MergeResult(this.LoadValue(ilGenerator, dictionaryItem.Key)); // key = string for standard dictionaries, so no boxing is ever required if (!isStandardDictionary && GenerationServices.IsBoxingRequiredForValue(dictionaryItem.Key) && !keyType.IsValueType) { ilGenerator.Emit(OpCodes.Box, dictionaryItem.Key.GetType()); } // load the value, boxing if necessary result = result.MergeResult(this.LoadValue(ilGenerator, dictionaryItem.Value)); // key = object for standard dictionaries, so value type is never a struct if (GenerationServices.IsBoxingRequiredForValue(dictionaryItem.Value) && (isStandardDictionary || !valueType.IsValueType) ) { ilGenerator.Emit(OpCodes.Box, dictionaryItem.Value.GetType()); } // Caal the "Add" ilGenerator.EmitCall(OpCodes.Call, dictionaryAddMethod, null); // At this point the dictionary, key and value have been popped off the stack, and we ended up with the origical state of the dictionary on top of the stack } // // the dicationary is already loaded on the stack - exit // return result; }