Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
0
        private CachingResult GenerateGetCatalogMetadata()
        {
            Assumes.NotNull(this._getCatalogMetadata);
            Assumes.NotNull(this._catalogMetadata);

            ILGenerator   ilGenerator = this._getCatalogMetadata.GetILGenerator();
            CachingResult result      = this._generationServices.LoadValue(ilGenerator, this._catalogMetadata);

            ilGenerator.Emit(OpCodes.Ret);

            return(result);
        }
Ejemplo n.º 3
0
        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;
        }
Ejemplo n.º 4
0
        public CachingResult <Type> EndGeneration()
        {
            Assumes.IsTrue(this._isGenerationStarted);
            Assumes.IsFalse(this._isGenerationCompleted);
            CachingResult result = CachingResult.SucceededResult;

            result = result.MergeResult(this.GenerateGetCatalogMetadata());
            result = result.MergeResult(this.GenerateGetCatalogIndex());
            Type stubType = this._stubBuilder.CreateType();

            this._partsDefinitionBuilder.CreateType();
            this._exportsDefinitionBuilder.CreateType();
            this._importsDefinitionBuilder.CreateType();

            this._isGenerationCompleted = true;
            return(result.ToResult <Type>(stubType));
        }
        protected override object WriteCacheCore(IEnumerable <ComposablePartDefinition> partDefinitions, IDictionary <string, object> catalogMetadata, ICachedComposablePartCatalogSite catalogSite)
        {
            this.ThrowIfDisposed();
            catalogSite = catalogSite ?? new EmptyCachedComposablePartCatalogSite();

            CachingResult          result = CachingResult.SucceededResult;
            int                    currentCatalogIdentifierCounter = this._currentCatalogIdentifierCouner++;
            string                 currentCatalogIdentifier        = string.Format(CultureInfo.InvariantCulture, "{0}", currentCatalogIdentifierCounter);
            AssemblyCacheGenerator generator = new AssemblyCacheGenerator(this._moduleBuilder, this._generationServices, catalogSite, currentCatalogIdentifier);

            generator.BeginGeneration();
            foreach (ComposablePartDefinition partDefinition in partDefinitions)
            {
                result = result.MergeErrors(generator.CachePartDefinition(partDefinition).Errors);
            }
            generator.CacheCatalogMetadata(catalogMetadata);
            CachingResult <Type> stubGenerationResult = generator.EndGeneration();

            result = result.MergeErrors(stubGenerationResult.Errors);
            result.ThrowOnErrors();

            return(currentCatalogIdentifier);
        }
Ejemplo n.º 6
0
        private CachingResult <MethodInfo> CachePartImportsOrExports <T>(IEnumerable <T> items, TypeBuilder definitionsTable, MethodBuilder stubFactoryMethod, Func <T, IDictionary <string, object> > cacheGenerator, string methodName)
        // in reality this is only ExportDefinition or ImportDefinition
        {
            Assumes.NotNull(items);
            Assumes.NotNull(definitionsTable);
            Assumes.NotNull(stubFactoryMethod);
            Assumes.NotNull(cacheGenerator);
            Assumes.NotNull(methodName);
            CachingResult result = CachingResult.SucceededResult;

            if (!items.Any())
            {
                return(result.ToResult <MethodInfo>(null));
            }

            Type itemType = null;

            if (typeof(T) == AssemblyCacheGenerator._importDefinitionType)
            {
                itemType = AssemblyCacheGenerator._importDefinitionType;
            }
            else
            {
                itemType = AssemblyCacheGenerator._exportDefinitionType;
            }

            //
            // internal static IEnumerable<T> CreateTs(ComposablePartDefinition owner)
            // {
            //    T[] items = new ImportDefinition[<count>];
            //
            //    IDictionary<string, object> dictionary0 = new Dictionary<string, object>();
            //    <populate the dictionary with the cache values>
            //    items[0] = CachingStubX.CreateTDefinition(dictinary0);
            //    ...
            //    IDictionary<string, object> dictionary<count-1> = new Dictionary<string, object>();
            //    <populate the dictionary with the cache values>
            //    items[<count-1>] = CachingStubX.CreateTDefinition(dictinary<count-1>);
            //    ...
            //    return items;
            // }

            // Generate the signature
            MethodBuilder itemsFactoryBuilder = definitionsTable.DefineMethod(
                methodName,
                MethodAttributes.Static | MethodAttributes.Assembly,
                typeof(IEnumerable <T>),
                new Type[] { AssemblyCacheGenerator._composablePartDefinitionType });
            ILGenerator ilGenerator = itemsFactoryBuilder.GetILGenerator();

            //
            // Generate array creation
            //
            this._generationServices.LoadValue(ilGenerator, items.Count());
            ilGenerator.Emit(OpCodes.Newarr, itemType);
            // At this point the array is on the stack

            int index = 0;

            foreach (T item in items)
            {
                // get the cache
                IDictionary <string, object> cache = cacheGenerator(item);

                //
                //items[<index>] = stub.CreateTDefinition(<dictionary>)
                //
                ilGenerator.Emit(OpCodes.Dup); // this will load the array on the stack
                result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, index));

                ilGenerator.Emit(OpCodes.Ldarg_0);                                                   // load the part definition
                result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, cache)); // load the dictionary
                ilGenerator.EmitCall(OpCodes.Call, stubFactoryMethod, null);

                ilGenerator.Emit(OpCodes.Stelem, itemType);
                index++;
                // at this point the duplicate array has been popped from the stack
            }

            // just return - the stack already contains the array
            ilGenerator.Emit(OpCodes.Ret);

            return(result.ToResult <MethodInfo>(itemsFactoryBuilder));
        }
Ejemplo n.º 7
0
        public CachingResult <MethodInfo> CachePartDefinition(ComposablePartDefinition partDefinition)
        {
            Assumes.NotNull(partDefinition);
            CachingResult result     = CachingResult.SucceededResult;
            string        methodName = string.Format(CultureInfo.InvariantCulture, "{0}", this._partsCounter);


            //Ftypeof
            // public static ComposablePartDefinition<>()
            // {
            //    // load dictionary
            //    return CachingStubX.CreatePartDefinition(<dictinary>, <importsFactory>, <exportsFactory>);
            // }

            // Generate the signature
            MethodBuilder partFactoryBuilder = this._partsDefinitionBuilder.DefineMethod(
                methodName,
                MethodAttributes.Static | MethodAttributes.Public,
                AssemblyCacheGenerator._composablePartDefinitionType,
                Type.EmptyTypes);
            ILGenerator ilGenerator = partFactoryBuilder.GetILGenerator();

            // Generate imports caching
            CachingResult <MethodInfo> importsFactoryResult = this.CachePartImportsOrExports <ImportDefinition>(
                partDefinition.ImportDefinitions,
                this._importsDefinitionBuilder,
                this._createImportDefinitionMethod,
                (import) => this._cachedCatalogSite.CacheImportDefinition(partDefinition, import),
                methodName);

            result = result.MergeErrors(importsFactoryResult.Errors);

            // Generate exports caching
            CachingResult <MethodInfo> exportsFactoryResult = this.CachePartImportsOrExports <ExportDefinition>(
                partDefinition.ExportDefinitions,
                this._exportsDefinitionBuilder,
                this._createExportDefinitionMethod,
                (export) => this._cachedCatalogSite.CacheExportDefinition(partDefinition, export),
                methodName);

            result = result.MergeErrors(exportsFactoryResult.Errors);


            // get the actual cache for the part definition
            IDictionary <string, object> cache = this._cachedCatalogSite.CachePartDefinition(partDefinition);

            //
            // now write the method
            //

            // load the cache dictionary on stack
            result = result.MergeResult(this._generationServices.LoadValue(ilGenerator, cache));

            // load the imports function pointer on stack
            MethodInfo importsFactory = importsFactoryResult.Value;

            if (importsFactory != null)
            {
                ilGenerator.Emit(OpCodes.Ldftn, importsFactory);
            }
            else
            {
                // load IntPtr.Zero
                ilGenerator.Emit(OpCodes.Ldsfld, AssemblyCacheGenerator._IntPtr_Zero);
            }

            // load the exports function pointer on stack
            MethodInfo exportsFactory = exportsFactoryResult.Value;

            if (exportsFactory != null)
            {
                ilGenerator.Emit(OpCodes.Ldftn, exportsFactory);
            }
            else
            {
                // load IntPtr.Zero
                ilGenerator.Emit(OpCodes.Ldsfld, AssemblyCacheGenerator._IntPtr_Zero);
            }

            // and then call into stub.CreatePartDefinition and return
            ilGenerator.EmitCall(OpCodes.Call, this._createPartDefinitionMethod, null);
            ilGenerator.Emit(OpCodes.Ret);
            this._partsCounter++;

            this.UpdateCatalogIndex(partDefinition, partFactoryBuilder);

            return(result.ToResult <MethodInfo>(partFactoryBuilder));
        }
Ejemplo n.º 8
0
        /// Generates the code that loads the supplied value on the stack
        /// This is not as simple as it seems, as different instructions need to be generated depending
        /// on its type.
        /// We support:
        /// 1. All primitive types and IntPtrs
        /// 2. Strings
        /// 3. Enums
        /// 4. typeofs
        /// 5. nulls
        /// 6. Dictionaries of (string, object) recursively containing all of the above
        /// 7. Enumerables
        /// Everything else cannot be represented as literals
        /// <param name="ilGenerator"></param>
        /// <param name="item"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal CachingResult LoadValue(ILGenerator ilGenerator, object value)
        {
            Assumes.NotNull(ilGenerator);
            CachingResult result = CachingResult.SucceededResult;

            //
            // Get nulls out of the way - they are basically typeless, so we just load null
            //
            if (value == null)
            {
                return GenerationServices.LoadNull(ilGenerator);
            }

            //
            // Prepare for literal loading - decide whether we should box, and handle enums properly
            //
            Type valueType = value.GetType();
            object rawValue = value;
            if (valueType.IsEnum)
            {
                // enums are special - we need to load the underlying constant on the stack
                rawValue = Convert.ChangeType(value, Enum.GetUnderlyingType(valueType), null);
                valueType = rawValue.GetType();
            }

            //
            // Generate IL depending on the valueType - this is messier than it should ever be, but sadly necessary
            //
            Type dictionaryKeyType;
            Type dictionaryValueType;
            IDictionary<string, object> standardDictionary = value as IDictionary<string, object>;
            if (standardDictionary != null)
            {
                if (standardDictionary.Count < GenerationServices.StandardDictionaryGeneratorsCount)
                {
                    return this.LoadStandardDictionaryFast(ilGenerator, standardDictionary);
                }
                else
                {
                    return this.LoadGenericDictionary(ilGenerator, standardDictionary, true);
                }
            }
            else if (GenerationServices.TryGetDictionaryElementType(valueType, out dictionaryKeyType, out dictionaryValueType))
            {
                result = result.MergeResult(this.LoadDictionary(ilGenerator, rawValue, dictionaryKeyType, dictionaryValueType));
            }
            else if (valueType == GenerationServices.StringType)
            {
                // we need to check for strings before enumerables, because strings are IEnumerable<char>
                result = result.MergeResult(GenerationServices.LoadString(ilGenerator,(string)rawValue));
            }
            else if (GenerationServices.TypeType.IsAssignableFrom(valueType))
            {
                result = result.MergeResult(GenerationServices.LoadTypeOf(ilGenerator, (Type)rawValue));
            }
            else if (GenerationServices.IEnumerableType.IsAssignableFrom(valueType))
            {
                // NOTE : strings and dictionaries are also enumerables, but we have already handled those
                result = result.MergeResult(this.LoadEnumerable(ilGenerator, (IEnumerable) rawValue));
            }
            else if (
                (valueType == GenerationServices.CharType) ||
                (valueType == GenerationServices.BooleanType) ||
                (valueType == GenerationServices.ByteType) ||
                (valueType == GenerationServices.SByteType) ||
                (valueType == GenerationServices.Int16Type) ||
                (valueType == GenerationServices.UInt16Type) ||
                (valueType == GenerationServices.Int32Type)
                )
            {
                // NOTE : Everything that is 32 bit or less uses ldc.i4. We need to pass int32, even if the actual types is shorter - this is IL memory model
                // direct casting to (int) won't work, because the value is boxed, thus we need to use Convert.
                // Sadly, this will not work for all cases - namely large uint32 - because they can't semantically fit into 32 signed bits
                // We have a special case for that next
                result = result.MergeResult(GenerationServices.LoadInt(ilGenerator, (int)Convert.ChangeType(rawValue, typeof(int), CultureInfo.InvariantCulture)));
            }
            else if (valueType == GenerationServices.UInt32Type)
            {
                // NOTE : This one is a bit tricky. Ldc.I4 takes an Int32 as an argument, although it really treats it as a 32bit number
                // That said, some UInt32 values are larger that Int32.MaxValue, so the Convert call above will fail, which is why 
                // we need to treat this case individually and cast to uint, and then - unchecked - to int.
                result = result.MergeResult(GenerationServices.LoadInt(ilGenerator, unchecked((int)((uint)rawValue))));
            }
            else if (valueType == GenerationServices.Int64Type)
            {
                result = result.MergeResult(GenerationServices.LoadLong(ilGenerator, (long)rawValue));
            }
            else if (valueType == GenerationServices.UInt64Type)
            {
                // NOTE : This one is a bit tricky. Ldc.I8 takes an Int64 as an argument, although it really treats it as a 64bit number
                // That said, some UInt64 values are larger that Int64.MaxValue, so the direct case we use above (or Convert, for that matter)will fail, which is why
                // we need to treat this case individually and cast to ulong, and then - unchecked - to long.
                result = result.MergeResult(GenerationServices.LoadLong(ilGenerator, unchecked((long)((ulong)rawValue))));
            }
            else if (valueType == GenerationServices.SingleType)
            {
                result = result.MergeResult(GenerationServices.LoadFloat(ilGenerator, (float)rawValue));
            }
            else if (valueType == GenerationServices.DoubleType)
            {
                result = result.MergeResult(GenerationServices.LoadDouble(ilGenerator, (double)rawValue));
            }
            else
            {
                result = result.MergeError(Strings.UnsupportedCacheValue, value.GetType().FullName);

                // Make sure the IL is balanced - generate the ldnull instead
                GenerationServices.LoadNull(ilGenerator);
            }

            return result;
        }
Ejemplo n.º 9
0
        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;

        }
Ejemplo n.º 10
0
 public CachingResult MergeResult(CachingResult result)
 {
     return(MergeErrors(result._errors));
 }