/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Text;
using dnlib.DotNet;
using dnSpy.Contracts.Decompiler;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
namespace dnSpy.Decompiler.ILSpy.Core.CSharp {
///
/// State for one decompiler thread. There should be at most one of these per CPU. This class
/// is not thread safe and must only be accessed by the owner thread.
///
sealed class AstBuilderState {
public readonly AstBuilder AstBuilder;
///
/// instance used by XML doc code. This is always in a random
/// state (random text) and caller must Clear() it before use.
///
public readonly StringBuilder XmlDoc_StringBuilder;
readonly Dictionary hasXmlDocFile;
ModuleDef? lastModule;
bool lastModuleResult;
public AstBuilderState(int settingsVersion) {
AstBuilder = new AstBuilder(new DecompilerContext(settingsVersion, null, null, true));
XmlDoc_StringBuilder = new StringBuilder();
hasXmlDocFile = new Dictionary();
}
public bool? HasXmlDocFile(ModuleDef module) {
if (lastModule == module)
return lastModuleResult;
if (hasXmlDocFile.TryGetValue(module, out var res)) {
lastModule = module;
lastModuleResult = res;
return res;
}
return null;
}
public void SetHasXmlDocFile(ModuleDef module, bool value) {
lastModule = module;
lastModuleResult = value;
hasXmlDocFile.Add(module, value);
}
///
/// Called to re-use this instance for another decompilation. Only the fields that need
/// resetting will be reset.
///
public void Reset() => AstBuilder.Reset();
}
///
/// One instance is created and stored in . It's used by the
/// decompiler threads to get an instance.
///
sealed class BuilderCache {
readonly ThreadSafeObjectPool astBuilderStatePool;
public BuilderCache(int settingsVersion) => astBuilderStatePool = new ThreadSafeObjectPool(Environment.ProcessorCount, () => new AstBuilderState(settingsVersion), resetAstBuilderState);
static readonly Action resetAstBuilderState = abs => abs.Reset();
public AstBuilderState AllocateAstBuilderState() => astBuilderStatePool.Allocate();
public void Free(AstBuilderState state) => astBuilderStatePool.Free(state);
}
}