示例#1
0
        protected void ComputeInputFilesHash(BinarySerializationWriter writer, IPrepareContext prepareContext)
        {
            var inputFiles = GetInputFiles();

            if (inputFiles is null)
            {
                return;
            }

            foreach (var inputFile in inputFiles)
            {
                var hash = prepareContext.ComputeInputHash(inputFile.Type, inputFile.Path);
                if (hash == ObjectId.Empty)
                {
                    writer.NativeStream.WriteByte(0);
                }
                else
                {
                    writer.NativeStream.Write((byte[])hash, 0, ObjectId.HashSize);
                }
            }
        }
示例#2
0
        internal static PreparedInformations Prepare(
            TranslateContext translateContext,
            Func <ITypeInformation, bool> predictType,
            Func <IMethodInformation, bool> predictMethod)
        {
            IPrepareContext prepareContext = translateContext;

            var allTypes = translateContext.Assembly.Modules.
                           SelectMany(module => module.Types).
                           Where(predictType).
                           Distinct().
                           ToArray();

            // Lookup type references.
            foreach (var type in allTypes)
            {
                prepareContext.RegisterType(type);
            }

            // Lookup fields.
            foreach (var field in allTypes.SelectMany(type => type.Fields))
            {
                prepareContext.RegisterType(field.FieldType);
            }

            // Construct result.
            return(new PreparedInformations(
                       allTypes,
                       (from type in allTypes
                        from method in type.DeclaredMethods
                        where predictMethod(method)
                        let preparedMethod = PrepareMethod(prepareContext, method)
                                             where preparedMethod != null
                                             select preparedMethod).
                       ToDictionary(
                           preparedMethod => preparedMethod.Method,
                           preparedMethod => preparedMethod)));
        }
示例#3
0
 /// <summary>
 /// Computes the command hash. If an error occurecd, the hash is <see cref="ObjectId.Empty"/>
 /// </summary>
 /// <param name="prepareContext">The prepare context.</param>
 /// <returns>Hash of the command.</returns>
 internal ObjectId ComputeCommandHash(IPrepareContext prepareContext)
 {
     var stream = new DigestStream(Stream.Null);
     try
     {
         ComputeCommandHash(stream, prepareContext);
         return stream.CurrentHash;
     }
     catch (Exception ex)
     {
         prepareContext.Logger.Error("Unexpected error while computing the command hash for [{0}]. Reason: {1}", ex, this.GetType().Name, ex.Message);
     }
     return ObjectId.Empty;
 }
示例#4
0
        public void ComputeCommandHash(Stream stream, IPrepareContext prepareContext)
        {
            var writer = new BinarySerializationWriter(stream);
            writer.Context.SerializerSelector = SerializerSelector.AssetWithReuse;

            writer.Write(CommandCacheVersion);

            // Compute assembly hash
            ComputeAssemblyHash(writer);

            // Compute parameters hash
            ComputeParameterHash(writer);

            // Compute static input files hash (parameter dependent)
            ComputeInputFilesHash(writer, prepareContext);
        }
示例#5
0
        protected void ComputeInputFilesHash(BinarySerializationWriter writer, IPrepareContext prepareContext)
        {
            var inputFiles = GetInputFiles();
            if (inputFiles == null)
                return;

            foreach (var inputFile in inputFiles)
            {
                var hash = prepareContext.ComputeInputHash(inputFile.Type, inputFile.Path);
                if (hash == ObjectId.Empty)
                {
                    writer.NativeStream.WriteByte(0);
                }
                else
                {
                    writer.NativeStream.Write((byte[])hash, 0, ObjectId.HashSize);
                }
            }
        }
示例#6
0
        private static PreparedMethodInformation PrepareMethodBody(
            IPrepareContext prepareContext,
            IMethodInformation method)
        {
            // TODO: move into MethodInformation
            var localVariables = method.LocalVariables.
                                 // If found non named local variable, force named "local[n]__"
                                 GroupBy(variable => variable).
                                 // If contains both named symbol each different scope (in the method by C#'s block), try to named with index number.
                                 SelectMany(g =>
            {
                var list = g.ToArray();
                return((list.Length >= 2) ?
                       list.Select((variable, index) => new LocalVariableInformation(
                                       method,
                                       variable.Index,
                                       string.Format("{0}{1}", g.Key.UnsafeCLanguageSymbolName, index),
                                       variable.TargetType)) :
                       new[] { new LocalVariableInformation(
                                   method,
                                   list[0].Index,
                                   string.Format("{0}", g.Key.UnsafeCLanguageSymbolName),
                                   list[0].TargetType) });
            }).
                                 OrderBy(e => e.Index).
#if DEBUG
                                 Select((e, index) =>
            {
                Debug.Assert(e.Index == index);
                return(e);
            }).
#endif
                                 ToArray();

            foreach (var local in localVariables)
            {
                prepareContext.RegisterType(local.TargetType, method);
            }

            //////////////////////////////////////////////////////////////////////////////
            // Construct decode context

            var decodeContext = new DecodeContext(
                method,
                prepareContext);

            //////////////////////////////////////////////////////////////////////////////
            // Important:
            //   It's core decoding sequence.
            //   The flow analysis can't predict by sequential path.
            //   So, it reorders by IL offset.

            var generators = decodeContext.
                             Traverse(dc => dc.TryDequeueNextPath() ? dc : null, true).
                             SelectMany(dc =>
                                        from ilBody in DecodeAndEnumerateILBodies(dc)
                                        let generator = ilBody.ILConverter.Apply(ilBody.Code.Operand, dc)
                                                        select new PreparedILBody(
                                            ilBody.Label,
                                            generator,
                                            dc.UniqueCodeBlockIndex,
                                            ilBody.Code,
                                            dc.DecodingPathNumber)).
                             OrderBy(ilb => ilb.UniqueCodeBlockIndex).
                             ThenBy(ilb => ilb.Label.Offset).
                             ToDictionary(ilb => ilb.Label.Offset, ilb => ilb.Generator);

            //////////////////////////////////////////////////////////////////////////////

            var stacks = decodeContext.
                         ExtractStacks().
                         ToArray();

            var labelNames = decodeContext.
                             ExtractLabelNames();

            var catchVariables = decodeContext.
                                 ExtractCatchVariables();

            var leaveContinuations = decodeContext.
                                     ExtractLeaveContinuations();

            return(new PreparedMethodInformation(
                       method,
                       stacks,
                       labelNames,
                       catchVariables,
                       leaveContinuations,
                       generators));
        }
示例#7
0
        private static PreparedMethodInformation PrepareMethod(
            IPrepareContext prepareContext,
            IMethodInformation method)
        {
            var returnType = method.ReturnType;
            var parameters = method.Parameters;

            prepareContext.RegisterType(returnType, method.CLanguageMemberScope);
            foreach (var parameter in parameters)
            {
                prepareContext.RegisterType(parameter.TargetType, method.CLanguageMemberScope);
            }

            // Pure abstract method (ignored.)
            if (method.IsVirtual && method.IsAbstract)
            {
                Debug.Assert(!method.HasBody);
                return(null);
            }

            // Delegate constructor (ignored, it will be handled by the AssemblyWriter.)
            if (method.IsConstructor && method.DeclaringType.IsDelegate &&
                (method.Parameters.Length == 3) &&
                method.Parameters[1].TargetType.IsObjectType &&
                method.Parameters[2].TargetType.IsIntPtrType)
            {
                // Debug.Assert(!method.HasBody);  // Depended for the compiler (it has no body for Roslyn)
                return(null);
            }

            // internalcall or DllImport
            if (method.IsExtern)
            {
                Debug.Assert(!method.HasBody);

                if (method.NativeMethod != null)
                {
                    if (string.IsNullOrWhiteSpace(method.NativeMethod.IncludeFileName))
                    {
                        throw new InvalidProgramSequenceException(
                                  "Not given FunctionImport attribute argument. Name={0}",
                                  method.FriendlyName);
                    }

                    // TODO: register library name.
                    prepareContext.RegisterImportIncludeFile(method.NativeMethod.IncludeFileName);
                    if (method.ReturnType.NativeType != null)
                    {
                        prepareContext.RegisterImportIncludeFile(method.ReturnType.NativeType.IncludeFileName);
                    }
                    foreach (var parameter in method.Parameters)
                    {
                        if (parameter.TargetType.NativeType != null)
                        {
                            prepareContext.RegisterImportIncludeFile(parameter.TargetType.NativeType.IncludeFileName);
                        }
                    }
                }
                else if (method.PInvokeInformation != null)
                {
                    if (string.IsNullOrWhiteSpace(method.PInvokeInformation.Module.Name))
                    {
                        throw new InvalidProgramSequenceException(
                                  "Not given DllImport attribute argument. Name={0}",
                                  method.FriendlyName);
                    }

                    // TODO: register library name.
                    //prepareContext.RegisterPrivateIncludeFile(method.PInvokeInformation.Module.Name);
                }

                // Construct dummy information.
                return(new PreparedMethodInformation(
                           method,
                           null,
                           null,
                           null,
                           null,
                           null));
            }

            Debug.Assert(method.HasBody);

            return(PrepareMethodBody(
                       prepareContext,
                       method));
        }
示例#8
0
        internal CommandResultEntry FindMatchingResult(IPrepareContext prepareContext, CommandResultEntry[] commandResultCollection)
        {
            if (commandResultCollection == null)
                return null;

            // Then check input dependencies and output versions
            //builderContext.AssetIndexMap.LoadNewValues();

            foreach (CommandResultEntry entry in commandResultCollection)
            {
                bool entryMatch = true;

                foreach (var inputDepVersion in entry.InputDependencyVersions)
                {
                    var hash = prepareContext.ComputeInputHash(inputDepVersion.Key.Type, inputDepVersion.Key.Path);
                    if (hash != inputDepVersion.Value)
                    {
                        entryMatch = false;
                        break;
                    }
                }

                if (!entryMatch)
                    continue;

                if (entry.OutputObjects.Any(outputObject => !VirtualFileSystem.FileExists(FileOdbBackend.BuildUrl(VirtualFileSystem.ApplicationDatabasePath, outputObject.Value))))
                {
                    entryMatch = false;
                }

                if (!entryMatch)
                    continue;

                // TODO/Benlitz: check matching spawned commands if needed

                return entry;
            }

            return null;
        }
示例#9
0
        internal ObjectId ComputeCommandHash(IPrepareContext prepareContext)
        {
            var stream = new DigestStream(Stream.Null);

            ComputeCommandHash(stream, prepareContext);

            return stream.CurrentHash;
        }
示例#10
0
        private static PreparedFunction PrepareMethod(
            IPrepareContext prepareContext,
            string methodName,
            string rawMethodName,
            TypeReference returnType,
            Parameter[] parameters,
            MethodBody body)
        {
            var localVariables = body.Variables
                                 // If found non named local variable, force named "local[n]__"
                                 .GroupBy(v => body.Method.DebugInformation.TryGetName(v, out var name) ? name : "local")
                                 // If contains both named symbol each different scope (in the method by C#'s block), try to named with index number.
                                 .SelectMany(g =>
            {
                var list = g.ToArray();
                return((list.Length >= 2)
                        ? list.Select((v, index) => new {
                    Name = string.Format("{0}{1}", g.Key, index),
                    Type = v.VariableType,
                    Index = v.Index
                })
                        : new[] { new {
                                      Name = string.Format("{0}", g.Key),
                                      Type = list[0].VariableType,
                                      Index = list[0].Index
                                  } });
            })
                                 .OrderBy(e => e.Index)
                                 .Select((e, index) =>
            {
                Debug.Assert(e.Index == index);
                return(new SymbolInformation(e.Name, e.Type));
            })
                                 .ToArray();

            foreach (var local in localVariables)
            {
                prepareContext.RegisterType(local.TargetType);
            }

            var decodeContext = new DecodeContext(
                body.Method.Module,
                methodName,
                returnType,
                parameters,
                localVariables,
                body.Instructions.ToArray(),
                prepareContext);

            // It gathers sequence point informations.
            // It will use writing the line preprocessor directive.
            var sequencePoints =
                (from sp in body.Method.DebugInformation.SequencePoints
                 where !sp.IsHidden
                 group sp by sp.Offset into g
                 let sps = g.OrderBy(sp => sp.Offset).ToArray()
                           where sps.Length >= 1
                           select new { g.Key, sps })
                .ToDictionary(g => g.Key, g => g.sps);

            // Important:
            //   It's core decoding sequence.
            //   The flow analysis can't predict by sequential path.
            //   So, it reorders by IL offset.
            var preparedILBodies = decodeContext
                                   .Traverse(dc => dc.TryDequeueNextPath() ? dc : null, true)
                                   .SelectMany(dc =>
                                               from ilBody in DecodeAndEnumerateILBodies(dc)
                                               let sps = sequencePoints.UnsafeGetValue(ilBody.Label.Offset, empty)
                                                         let generator = ilBody.ILConverter.Apply(ilBody.Operand, dc)
                                                                         select new PreparedILBody(
                                                   ilBody.Label,
                                                   generator,
                                                   dc.UniqueCodeBlockIndex,
                                                   sps,
                                                   ilBody.ILConverter.OpCode,
                                                   ilBody.Operand,
                                                   dc.DecodingPathNumber))
                                   .OrderBy(ilb => ilb.UniqueCodeBlockIndex)
                                   .ThenBy(ilb => ilb.Label.Offset)
                                   .ToArray();

            var stacks = decodeContext
                         .ExtractStacks()
                         .ToArray();

            var labelNames = decodeContext
                             .ExtractLabelNames();

            return(new PreparedFunction(
                       methodName,
                       rawMethodName,
                       returnType,
                       parameters,
                       preparedILBodies,
                       localVariables,
                       stacks,
                       labelNames,
                       body.Method.IsVirtual ? (int?)body.Method.GetMethodOverloadIndex() : null));
        }