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); } } }
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))); }
/// <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; }
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); }
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); } } }
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)); }
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)); }
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; }
internal ObjectId ComputeCommandHash(IPrepareContext prepareContext) { var stream = new DigestStream(Stream.Null); ComputeCommandHash(stream, prepareContext); return stream.CurrentHash; }
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)); }