This is a subset of:
 https://cciast.codeplex.com/ @ 0699625623
 https://ccimetadata.codeplex.com/ @ c1d8a9f6b9

Tests and samples are excluded for now to prevent large binaries from being
rooted by the master branch.

The larger codeplex history is disjoint from the GitHub master branch but can
still be seen on GitHub in the codeplex/cci{ast,metadata,samples} branches.
This commit is contained in:
Microsoft GitHub User 2016-04-21 19:17:27 -07:00 коммит произвёл Nick Guerrera
Коммит 3a1793da2a
283 изменённых файлов: 290083 добавлений и 0 удалений

67
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,67 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
# Force bash scripts to always use lf line endings so that if a repo is accessed
# in Unix via a file share from Windows, the scripts will work.
*.sh text eol=lf

260
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,260 @@
syntax: glob
### VisualStudio ###
# Tool Runtime Dir
/[Tt]ools/
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
msbuild.log
# Cross building rootfs
cross/rootfs/
# Visual Studio 2015
.vs/
# Visual Studio 2015 Pre-CTP6
*.sln.ide
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
*.pubxml
*.publishproj
# NuGet Packages
*.nuget.props
*.nuget.targets
*.nupkg
**/packages/*
# NuGet package restore lockfiles
project.lock.json
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
*.metaproj
*.metaproj.tmp
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
### MonoDevelop ###
*.pidb
*.userprefs
### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Linux ###
*~
# KDE directory preferences
.directory
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# vim temporary files
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~

1
.gitmirrorall Normal file
Просмотреть файл

@ -0,0 +1 @@
This folder will be mirrored by the Git-TFS Mirror recursively.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E8B89C56-383A-4A1D-9EEE-E5FE9FC9DE03}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.Analysis</RootNamespace>
<AssemblyName>Microsoft.Cci.Analysis.AnalysisUtilities</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
<CodeContractsInferRequires>True</CodeContractsInferRequires>
<CodeContractsInferEnsures>True</CodeContractsInferEnsures>
<CodeContractsInferObjectInvariants>True</CodeContractsInferObjectInvariants>
<CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
<CodeContractsSuggestRequires>False</CodeContractsSuggestRequires>
<CodeContractsSuggestEnsures>False</CodeContractsSuggestEnsures>
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
<CodeContractsDisjunctiveRequires>True</CodeContractsDisjunctiveRequires>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions>-show unreached</CodeContractsExtraAnalysisOptions>
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>2</CodeContractsAnalysisWarningLevel>
<DocumentationFile>bin\Debug\Microsoft.Cci.Analysis.AnalysisUtilities.XML</DocumentationFile>
<CodeContractsSQLServerOption />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Microsoft.Cci.Analysis.AnalysisUtilities.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Common\Include\Version.cs">
<Link>Build\Version.cs</Link>
</Compile>
<Compile Include="AbstractDomains\Intervals.cs" />
<Compile Include="AbstractInterpretation.cs" />
<Compile Include="Evaluator.cs" />
<Compile Include="ExpressionCanonicalizer.cs" />
<Compile Include="Purger.cs" />
<Compile Include="SatSolver.cs" />
<Compile Include="Simplifier.cs" />
<Compile Include="SingleAssignment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ValueMappings.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataHelper\MetadataHelper.csproj">
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
<Name>MetadataHelper</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\MutableMetadataModel\MutableMetadataModel.csproj">
<Project>{319E151C-8F33-49E7-81C9-30F02F9BA90A}</Project>
<Name>MutableMetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\SourceModel\SourceModel.csproj">
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
<Name>SourceModel</Name>
</ProjectReference>
<ProjectReference Include="..\ControlAndDataFlowGraph\ControlAndDataFlowGraph.csproj">
<Project>{2596EFB0-87AE-42CE-89EB-84F35D6350D2}</Project>
<Name>ControlAndDataFlowGraph</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,300 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
using Microsoft.Cci.MutableCodeModel;
using System;
namespace Microsoft.Cci.Analysis {
internal class ExpressionCanonicalizer<Instruction>
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
internal ExpressionCanonicalizer(ValueMappings<Instruction> mappings) {
Contract.Requires(mappings != null);
this.mappings = mappings;
}
ValueMappings<Instruction> mappings;
Dictionary<Instruction, Instruction> cache = new Dictionary<Instruction, Instruction>(new ExpressionComparer());
Instruction dummyInstruction = new Instruction();
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.mappings != null);
Contract.Invariant(this.cache != null);
Contract.Invariant(this.dummyInstruction != null);
}
internal class ExpressionComparer : IEqualityComparer<Instruction> {
[ContractVerification(false)]
public bool Equals(Instruction x, Instruction y) {
if (x == null) return y == null;
if (y == null) return false;
if (object.ReferenceEquals(x, y)) return true;
if (x.Operation.OperationCode != y.Operation.OperationCode) return false;
if (x.Operation.Value == null) {
if (y.Operation.Value != null) return false;
} else {
if (!x.Operation.Value.Equals(y.Operation.Value)) return false;
}
if (x.Operand1 == null) return y.Operand1 == null;
bool result = this.Equals((Instruction)x.Operand1, (Instruction)y.Operand1);
if (x.Operand2 == null) return result && y.Operand2 == null;
var operand2x = x.Operand2 as Instruction;
var operand2y = y.Operand2 as Instruction;
if (operand2x != null) {
if (operand2y == null) return false;
if (this.Equals(operand2x, operand2y)) return result;
if (result) return false;
if (OperationIsCummutative(x.Operation.OperationCode)) {
return (this.Equals((Instruction)x.Operand1, operand2y) && this.Equals((Instruction)y.Operand1, operand2x));
}
return false;
}
if (!result) return false;
var operandsx = x.Operand2 as Instruction[];
var operandsy = y.Operand2 as Instruction[];
Contract.Assume(operandsx != null);
var n = operandsx.Length;
if (operandsy == null || operandsy.Length != n) return false;
for (int i = 0; i < n; i++) {
var opx = operandsx[i];
var opy = operandsy[i];
if (!this.Equals(opx, opy)) return false;
}
return true;
}
private static bool OperationIsCummutative(OperationCode operationCode) {
switch (operationCode) {
case OperationCode.Add:
case OperationCode.Add_Ovf:
case OperationCode.Add_Ovf_Un:
case OperationCode.And:
case OperationCode.Beq:
case OperationCode.Beq_S:
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
case OperationCode.Ceq:
case OperationCode.Mul:
case OperationCode.Mul_Ovf:
case OperationCode.Mul_Ovf_Un:
case OperationCode.Or:
case OperationCode.Xor:
return true;
}
return false;
}
[ContractVerification(false)]
public int GetHashCode(Instruction instruction) {
if (instruction == null) return 0;
int result = (int)instruction.Operation.OperationCode;
if (instruction.Operation.Value != null)
result = (result << 2) ^ instruction.Operation.Value.GetHashCode();
if (instruction.Operand1 == null) return result;
var hash1 = this.GetHashCode((Instruction)instruction.Operand1);
if (instruction.Operand2 == null) return (result << 2) ^ hash1;
var operand2 = instruction.Operand2 as Instruction;
if (operand2 != null) {
var hash2 = this.GetHashCode(operand2);
return (result << 3) ^ (hash1 ^ hash2);
}
var operands = instruction.Operand2 as Instruction[];
Contract.Assume(operands != null);
for (int i = 0, n = operands.Length; i < n; i++) {
result = (result << 2) ^ this.GetHashCode(operands[i]);
}
return result;
}
}
/// <summary>
/// Returns the canonical form of an expression that results in the given constant at runtime.
/// </summary>
/// <param name="compileTimeConstant">The compile time constant that should be equal to the value the resulting expression will evaluate to at runtime.</param>
/// <param name="originalInstruction">An instruction that will result in the given constant at runtime. The result of this method is a canonical form of this instruction.</param>
internal Instruction GetAsCanonicalizedLoadConstant(IMetadataConstant compileTimeConstant, Instruction originalInstruction) {
Contract.Requires(compileTimeConstant != null);
Contract.Requires(originalInstruction != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var ic = compileTimeConstant.Value as IConvertible;
if (ic != null)
return this.GetAsLoadConstant(ic, originalInstruction);
else if (compileTimeConstant.Value == null)
return new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldnull, Location = originalInstruction.Operation.Location }, Type = compileTimeConstant.Type };
else
return originalInstruction;
}
/// <summary>
/// Returns the canonical form of an expression that results in the given constant at runtime.
/// </summary>
/// <param name="convertible">The value that the resulting expression must evaluate to at runtime.</param>
/// <param name="originalInstruction">An instruction that will result in the given constant at runtime. The result of this method is a canonical form of this instruction.</param>
private Instruction GetAsLoadConstant(IConvertible convertible, Instruction originalInstruction) {
Contract.Requires(convertible != null);
Contract.Requires(originalInstruction != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
Instruction result = originalInstruction;
var operation = originalInstruction.Operation;
var location = originalInstruction.Operation.Location;
TypeCode tc = convertible.GetTypeCode();
switch (tc) {
case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Char:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
long n = convertible.ToInt64(null);
if (int.MinValue <= n && n <= int.MaxValue)
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldc_I4, Value = (int)n, Location = location } };
else
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldc_I8, Value = n, Location = location } };
break;
case TypeCode.UInt64:
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldc_I8, Value = (long)convertible.ToUInt64(null), Location = location } };
break;
case TypeCode.Single:
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldc_R4, Value = convertible.ToSingle(null), Location = location } };
break;
case TypeCode.Double:
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldc_R8, Value = convertible.ToDouble(null), Location = location } };
break;
case TypeCode.String:
result = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldstr, Value = convertible.ToString(null), Location = location } };
break;
}
result.Type = originalInstruction.Type;
return this.GetCanonicalExpression(result);
}
/// <summary>
/// If an expression equivalent to the given expression can be found in the cache, the result is that expression.
/// Otherwise the result is the given expression and it is added to the cache as well.
/// </summary>
/// <param name="expression">An instruction that computes a value.</param>
internal Instruction GetCanonicalExpression(Instruction expression) {
Contract.Requires(expression != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
Instruction result;
if (!this.cache.TryGetValue(expression, out result)) {
this.cache[expression] = result = expression;
}
Contract.Assume(result != null);
return result;
}
/// <summary>
/// If the cache contains an expression with an Operation structurally equivalent to unaryInstruction.Operation and Operand1 structurally equivalent to
/// operand1, then return that expression. Otherwise construct such an expression, add it to the cache and return it.
/// </summary>
/// <param name="unaryInstruction">An instruction with a single operand.</param>
/// <param name="operand1">The already canonicalized version of unaryInstruction.Operand1, if available, otherwise unaryInstruction.Operand1.</param>
internal Instruction GetCanonicalExpression(Instruction unaryInstruction, Instruction operand1) {
Contract.Requires(unaryInstruction != null);
Contract.Requires(operand1 != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var expression = this.dummyInstruction;
expression.Operation = unaryInstruction.Operation;
expression.Operand1 = operand1;
expression.Operand2 = null;
expression.Type = unaryInstruction.Type;
Instruction result;
if (!this.cache.TryGetValue(expression, out result)) {
result = this.GetCanonicalExpression(Simplifier.SimplifyUnary(expression, this.mappings, this));
this.cache[expression] = result;
this.dummyInstruction = new Instruction();
}
Contract.Assume(result != null);
return result;
}
/// <summary>
/// If the cache contains an expression with an Operation structurally equivalent to binaryInstruction.Operation, Operand1 structurally equivalent to
/// operand1 and Operand2 structurally equivalent to the operand2, then return that expression.
/// Otherwise construct such an expression, simplify it and then add it to the cache and return it.
/// </summary>
/// <param name="binaryInstruction">An instruction with a two operands.</param>
/// <param name="operand1">The already canonicalized version of binaryInstruction.Operand1, if available, otherwise binaryInstruction.Operand1.</param>
/// <param name="operand2">The already canonicalized version of binaryInstruction.Operand2, if available, otherwise binaryInstruction.Operand2.</param>
internal Instruction GetCanonicalExpression(Instruction binaryInstruction, Instruction operand1, Instruction operand2) {
Contract.Requires(binaryInstruction != null);
Contract.Requires(operand1 != null);
Contract.Requires(operand2 != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var expression = this.dummyInstruction;
expression.Operation = binaryInstruction.Operation;
expression.Operand1 = operand1;
expression.Operand2 = operand2;
expression.Type = binaryInstruction.Type;
Instruction result;
if (!this.cache.TryGetValue(expression, out result)) {
result = this.GetCanonicalExpression(Simplifier.SimplifyBinary(expression, this.mappings, this));
this.cache[expression] = result;
this.dummyInstruction = new Instruction();
}
Contract.Assume(result != null);
return result;
}
internal Instruction GetCanonicalExpression(Instruction naryInstruction, Instruction operand1, Instruction/*?*/ operand2, Instruction[]/*?*/ operands2andBeyond) {
Contract.Requires(naryInstruction != null);
Contract.Requires(operand1 != null);
var expression = this.dummyInstruction;
expression.Operation = naryInstruction.Operation;
expression.Operand1 = this.GetCanonicalExpression(Simplifier.Simplify(operand1, this.mappings, this));
if (operand2 != null)
expression.Operand2 = this.GetCanonicalExpression(Simplifier.Simplify(operand2, this.mappings, this));
else if (operands2andBeyond != null) {
var n = operands2andBeyond.Length;
var canonOps = new Instruction[n];
for (int i = 0; i < n; i++) {
Contract.Assume(operands2andBeyond[i] != null);
canonOps[i] = this.GetCanonicalExpression(Simplifier.Simplify(operands2andBeyond[i], this.mappings, this));
}
expression.Operand2 = canonOps;
}
expression.Type = naryInstruction.Type;
Instruction result;
if (!this.cache.TryGetValue(expression, out result)) {
this.cache[expression] = result = expression;
this.dummyInstruction = new Instruction();
}
Contract.Assume(result != null);
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsoft.Cci.Analysis.AnalysisUtilities")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c7078b32-c394-49a1-9946-c0306c238aa8")]

Просмотреть файл

@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
using Microsoft.Cci.MutableCodeModel;
using System;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Rewrites Boolean expressions to exclude references to variables that have been updated.
/// </summary>
public static class Purger {
/// <summary>
/// Rewrites Boolean expressions to exclude references to variables that have been updated.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="variable"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction/*?*/ Purge<Instruction>(Instruction instruction, INamedEntity variable, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(variable != null);
Contract.Requires(canonicalizer != null);
var operand1 = instruction.Operand1 as Instruction;
if (operand1 == null)
return PurgeNullary(instruction, variable);
var operand2 = instruction.Operand2 as Instruction;
if (operand2 != null)
return PurgeBinary(instruction, variable, canonicalizer);
else if (instruction.Operand2 == null)
return PurgeUnary(instruction, variable, canonicalizer);
else
return PurgeNary(instruction, variable, canonicalizer);
}
private static Instruction/*?*/ PurgeNary<Instruction>(Instruction instruction, INamedEntity variable, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(variable != null);
Contract.Requires(canonicalizer != null);
Contract.Assume(instruction.Operand1 is Instruction);
var operand1 = Purge((Instruction)instruction.Operand1, variable, canonicalizer);
if (operand1 == null) return null;
var operand2andBeyond = instruction.Operand2 as Instruction[];
Contract.Assume(operand2andBeyond != null);
var n = operand2andBeyond.Length;
Instruction[] copy = null;
for (int i = 0; i < n; i++) {
Contract.Assume(operand2andBeyond[i] != null);
var opi = Purge(operand2andBeyond[i], variable, canonicalizer);
if (opi == null) return null;
if (opi != operand2andBeyond[i]) {
if (copy == null) {
copy = new Instruction[n];
for (int j = 0; j < i; j++) copy[j] = operand2andBeyond[j];
}
Contract.Assume(copy.Length == n);
copy[i] = opi;
}
}
if (operand1 != instruction.Operand1 || copy != null)
return canonicalizer.GetCanonicalExpression(instruction, operand1, null, copy);
return instruction;
}
private static Instruction/*?*/ PurgeNullary<Instruction>(Instruction instruction, INamedEntity variable)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(variable != null);
if (instruction.Operation.Value == variable) return null;
return instruction;
}
/// <summary>
/// Uses Arithmetic and Boolean laws to simplify expressions.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="variable"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction/*?*/ PurgeBinary<Instruction>(Instruction instruction, INamedEntity variable, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(variable != null);
Contract.Requires(canonicalizer != null);
var operation = instruction.Operation;
Contract.Assume(instruction.Operand1 is Instruction);
var operand1 = (Instruction)instruction.Operand1;
Contract.Assume(instruction.Operand2 is Instruction);
var operand2 = (Instruction)instruction.Operand2;
operand1 = Purge(operand1, variable, canonicalizer);
operand2 = Purge(operand2, variable, canonicalizer);
switch (operation.OperationCode) {
case OperationCode.And:
case OperationCode.Or:
if (operand1 == null) return operand2;
if (operand2 == null) return operand1;
if (operand1 != instruction.Operand1 || operand2 != instruction.Operand2)
return canonicalizer.GetCanonicalExpression(instruction, operand1, operand2);
break;
}
if (operand1 != instruction.Operand1 || operand2 != instruction.Operand2) return null;
return instruction;
}
/// <summary>
///
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="variable"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction/*?*/ PurgeUnary<Instruction>(Instruction instruction, INamedEntity variable, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(variable != null);
Contract.Requires(canonicalizer != null);
var operation = instruction.Operation;
Contract.Assume(instruction.Operand1 is Instruction);
var operand1 = (Instruction)instruction.Operand1;
var operand = Purge(operand1, variable, canonicalizer);
if (operand != operand1) return null;
return instruction;
}
}
}

Просмотреть файл

@ -0,0 +1,318 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
using System.Collections.Generic;
using Microsoft.Cci.MutableCodeModel;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Implemented by an object that implements a Boolean Satisfibility Solver.
/// </summary>
public interface ISatSolver {
/// <summary>
/// An expression for which ISatSolverContext.Check always returns null.
/// </summary>
ISatExpressionWrapper Dummy { get; }
/// <summary>
/// An expression for which ISatSolverContext.Check always returns false.
/// </summary>
ISatExpressionWrapper False { get; }
/// <summary>
/// Provides a context that can hold a number of boolean expressions.
/// The solver is used to see if there exists an assignment of values to variables that will make all of the Boolean expressions true.
/// </summary>
ISatSolverContext GetNewContext();
/// <summary>
/// Returns an ISatExpressionWrapper instance that corresponds to the given operation. The operation takes no arguments, so it is expected
/// to be a constant value or a variable reference. May return null if operation cannot be mapped to an expression.
/// </summary>
ISatExpressionWrapper/*?*/ MakeExpression(IOperation operation, ITypeReference expressionType);
/// <summary>
/// Returns an ISatExpressionWrapper instance that corresponds to the given operation. The operation takes a single argument, so it is expected
/// to involve a unary operator, such as - or ! or ~. May return null if operation cannot be mapped to an expression.
/// </summary>
ISatExpressionWrapper/*?*/ MakeExpression(IOperation operation, ITypeReference expressionType, ISatExpressionWrapper operand1);
/// <summary>
/// Returns an ISatExpressionWrapper instance that corresponds to the given operation. The operation takes two arguments, so it is expected
/// to involve a binary operator, such as * or / or ^. May return null if operation cannot be mapped to an expression.
/// </summary>
ISatExpressionWrapper/*?*/ MakeExpression(IOperation operation, ITypeReference expressionType, ISatExpressionWrapper operand1, ISatExpressionWrapper operand2);
/// <summary>
/// Returns an ISatExpressionWrapper instance that corresponds to operand1 => operand2.
/// </summary>
ISatExpressionWrapper MakeImplication(ISatExpressionWrapper operand1, ISatExpressionWrapper operand2);
/// <summary>
/// An expression for which ISatSolverContext.Check always returns true.
/// </summary>
ISatExpressionWrapper True { get; }
//TODO: add a way to make predicates that check for overflow. I.e. like MakeExpression, but the result is a boolean expression that indicates overflow can happen if it is satisfiable.
}
/// <summary>
/// A context that can hold a number of boolean expressions.
/// The solver is used to see if there exists an assignment of values to variables that will make all of the Boolean expressions true.
/// </summary>
public interface ISatSolverContext {
/// <summary>
/// Adds a boolean expression to the context.
/// </summary>
void Add(ISatExpressionWrapper expression);
/// <summary>
/// Adds the inverse of the given boolean expression to the context.
/// </summary>
void AddInverse(ISatExpressionWrapper expression);
/// <summary>
/// Checks if there exists an assigment of values to variables that will make all of the Boolean expressions in the context true.
/// Since this problem is not decidable, the solver may not be able to return an answer, in which case the return result is null
/// rather than false or true.
/// </summary>
bool? Check();
/// <summary>
/// Creates a check point from the expressions currently in the context. Any expressions added to the context after this call will be
/// discarded when a corresponding call is made to RestoreCheckPoint.
/// </summary>
void MakeCheckPoint();
/// <summary>
/// The number of check points that have been created.
/// </summary>
uint NumberOfCheckPoints { get; }
/// <summary>
/// Discards any expressions added to the context since the last call to MakeCheckPoint. At least one check point must exist.
/// </summary>
void RestoreCheckPoint();
}
/// <summary>
/// A wrapper for an expression encoded in a format understood by the SAT solver.
/// </summary>
public interface ISatExpressionWrapper {
/// <summary>
/// The type of value this expression results in.
/// </summary>
ITypeReference Type { get; }
/// <summary>
/// Unwraps the wrapped expression, returning a value of the type expected by the SAT solver.
/// </summary>
T Unwrap<T>();
}
internal class SatSolverHelper<Instruction> where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
internal SatSolverHelper(ISatSolver satSolver, ValueMappings<Instruction> mappings) {
Contract.Requires(satSolver != null);
Contract.Requires(mappings != null);
this.satSolver = satSolver;
this.mappings = mappings;
this.expressionMap = new Hashtable<Instruction, object>();
this.andOp = new Operation() { OperationCode = OperationCode.And };
this.orOp = new Operation() { OperationCode = OperationCode.Or };
}
IOperation andOp;
IOperation orOp;
ISatSolver satSolver;
Hashtable<Instruction, object> expressionMap;
ValueMappings<Instruction> mappings;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.satSolver != null);
Contract.Invariant(this.expressionMap != null);
Contract.Invariant(this.mappings != null);
}
internal void AddPhiNodeConstraints(Instruction expression, ISatSolverContext context) {
Contract.Requires(expression != null);
Contract.Requires(context != null);
if (expression.Operation.OperationCode == OperationCode.Nop) {
var phiVar = expression.Operation.Value as INamedEntity;
if (phiVar != null) {
var operand1 = expression.Operand1 as Instruction;
if (operand1 == null) return;
var loadPhiVar = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ldloc, Value = phiVar }, Type = operand1.Type };
var constraint = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ceq }, Operand1 = loadPhiVar, Operand2 = operand1, Type = operand1.Type.PlatformType.SystemBoolean };
var operand2 = expression.Operand2 as Instruction;
if (operand2 != null) {
var eq2 = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ceq }, Operand1 = loadPhiVar, Operand2 = operand2, Type = constraint.Type };
constraint = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Or }, Operand1 = constraint, Operand2 = eq2, Type = constraint.Type };
} else {
var operands2toN = expression.Operand2 as Instruction[];
if (operands2toN != null) {
for (int i = 0; i < operands2toN.Length; i++) {
var operandi = operands2toN[i];
Contract.Assume(operandi != null);
var eqi = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Ceq }, Operand1 = loadPhiVar, Operand2 = operandi, Type = constraint.Type };
constraint = new Instruction() { Operation = new Operation() { OperationCode = OperationCode.Or }, Operand1 = constraint, Operand2 = eqi, Type = constraint.Type };
}
}
}
context.Add(this.GetSolverExpressionFor(constraint));
}
} else {
var operand1 = expression.Operand1 as Instruction;
if (operand1 != null) {
this.AddPhiNodeConstraints(operand1, context);
var operand2 = expression.Operand2 as Instruction;
if (operand2 != null) {
this.AddPhiNodeConstraints(operand2, context);
} else {
var operands2toN = expression.Operand2 as Instruction[];
if (operands2toN != null) {
for (int i = 0; i < operands2toN.Length; i++) {
var operandi = operands2toN[i];
Contract.Assume(operandi != null);
this.AddPhiNodeConstraints(operandi, context);
}
}
}
}
}
}
internal ISatExpressionWrapper GetSolverExpressionFor(Instruction expression, List<List<Instruction>> listOfConjunctions = null) {
Contract.Requires(expression != null);
Contract.Ensures(Contract.Result<ISatExpressionWrapper>() != null);
var wrapper = this.expressionMap[expression] as ISatExpressionWrapper;
if (wrapper == null) {
if (!this.mappings.IsRecursive(expression))
expression = Simplifier.HoistPhiNodes(expression);
if (listOfConjunctions != null && expression.Type.TypeCode == PrimitiveTypeCode.Boolean && expression.Operation.OperationCode == OperationCode.Nop && expression.Operation.Value is INamedEntity) {
wrapper = this.GetSolverExpressionForBooleanPhiNode(expression, listOfConjunctions);
} else {
var operand1 = expression.Operand1 as Instruction;
if (operand1 == null) {
wrapper = this.satSolver.MakeExpression(expression.Operation, expression.Type);
} else {
var operand1wrapper = this.GetSolverExpressionFor(operand1, listOfConjunctions);
var operand2 = expression.Operand2 as Instruction;
if (operand2 == null) {
wrapper = this.satSolver.MakeExpression(expression.Operation, expression.Type, operand1wrapper);
} else {
var operand2wrapper = this.GetSolverExpressionFor(operand2, listOfConjunctions);
wrapper = this.satSolver.MakeExpression(expression.Operation, expression.Type, operand1wrapper, operand2wrapper);
}
}
}
if (wrapper == null) wrapper = this.satSolver.Dummy;
Contract.Assume(wrapper != null);
this.expressionMap[expression] = wrapper;
}
return wrapper;
}
private ISatExpressionWrapper/*?*/ GetSolverExpressionForBooleanPhiNode(Instruction expression, List<List<Instruction>> listOfConjunctions) {
Contract.Requires(expression != null);
Contract.Requires(listOfConjunctions != null);
var operand1 = expression.Operand1 as Instruction;
if (operand1 == null) return null;
var result = this.GetSolverExpressionFor(operand1);
Contract.Assume(listOfConjunctions.Count > 0);
if (listOfConjunctions[0] == null) return null;
var entryConstraint1 = this.GetSolverExpressionFor(listOfConjunctions[0]);
if (entryConstraint1 != null)
result = this.satSolver.MakeImplication(entryConstraint1, result);
var operand2 = expression.Operand2 as Instruction;
if (operand2 != null) {
var wrappedOperand2 = this.GetSolverExpressionFor(operand2);
Contract.Assume(listOfConjunctions.Count > 1);
if (listOfConjunctions[1] == null) return null;
var entryConstraint2 = this.GetSolverExpressionFor(listOfConjunctions[1]);
if (entryConstraint2 != null)
result = this.satSolver.MakeImplication(entryConstraint2, wrappedOperand2);
result = this.satSolver.MakeExpression(this.andOp, expression.Type, result, wrappedOperand2);
} else {
var operand2toN = expression.Operand2 as Instruction[];
if (operand2toN != null) {
for (int i = 0; i < operand2toN.Length; i++) {
Contract.Assume(operand2toN[i] != null);
var wrappedOperandi = this.GetSolverExpressionFor(operand2toN[i]);
Contract.Assume(listOfConjunctions.Count > i+1);
if (listOfConjunctions[i+1] == null) return null;
var entryConstrainti = this.GetSolverExpressionFor(listOfConjunctions[i+1]);
if (entryConstrainti != null)
result = this.satSolver.MakeImplication(entryConstrainti, wrappedOperandi);
result = this.satSolver.MakeExpression(this.andOp, expression.Type, result, wrappedOperandi);
}
}
}
return result;
}
internal ISatExpressionWrapper/*?*/ GetSolverExpressionFor(List<List<Instruction>> listOfConjunctions) {
Contract.Requires(listOfConjunctions != null);
var n = listOfConjunctions.Count;
if (n == 0) return null;
ISatExpressionWrapper/*?*/ disjunct = null;
for (int i = 0; i < n; i++) {
if (listOfConjunctions[i] == null) return null;
var conjunct = this.GetSolverExpressionFor(listOfConjunctions[i]);
if (conjunct == null) return null;
if (disjunct == null)
disjunct = conjunct;
else
disjunct = this.satSolver.MakeExpression(this.orOp, disjunct.Type, disjunct, conjunct);
}
return disjunct;
}
private ISatExpressionWrapper/*?*/ GetSolverExpressionFor(List<Instruction> listOfExpressions) {
Contract.Requires(listOfExpressions != null);
var n = listOfExpressions.Count;
if (n == 0) return null;
ISatExpressionWrapper/*?*/ conjunct = null;
for (int i = 0; i < n; i++) {
if (listOfExpressions[i] == null) return null;
var expression = this.GetSolverExpressionFor(listOfExpressions[i]);
if (conjunct == null)
conjunct = expression;
else
conjunct = this.satSolver.MakeExpression(this.andOp, conjunct.Type, conjunct, expression);
}
return conjunct;
}
internal ISatSolver SatSolver {
get {
Contract.Ensures(Contract.Result<ISatSolver>() != null);
return this.satSolver;
}
}
}
}

Просмотреть файл

@ -0,0 +1,617 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci;
using Microsoft.Cci.UtilityDataStructures;
using Microsoft.Cci.MutableCodeModel;
using System;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Uses Arithmetic and Boolean laws to simplify expressions.
/// </summary>
public static class Simplifier {
/// <summary>
/// Uses Arithmetic and Boolean laws to simplify expressions.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="mappings"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction Simplify<Instruction>(Instruction instruction, ValueMappings<Instruction> mappings, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(mappings != null);
Contract.Requires(canonicalizer != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var operand1 = instruction.Operand1 as Instruction;
if (operand1 == null)
return SimplifyNullary(instruction, mappings);
var operand2 = instruction.Operand2 as Instruction;
if (operand2 != null)
return SimplifyBinary(instruction, mappings, canonicalizer);
else if (instruction.Operand2 == null)
return SimplifyUnary(instruction, mappings, canonicalizer);
else
return SimplifyNary(instruction, mappings, canonicalizer);
}
private static Instruction SimplifyNary<Instruction>(Instruction instruction, ValueMappings<Instruction> mappings, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(mappings != null);
Contract.Requires(canonicalizer != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
Contract.Assume(instruction.Operand1 is Instruction);
instruction.Operand1 = Simplify((Instruction)instruction.Operand1, mappings, canonicalizer);
var operand2 = instruction.Operand2 as Instruction;
if (operand2 != null) {
instruction.Operand2 = Simplify(operand2, mappings, canonicalizer);
} else {
var operand2andBeyond = instruction.Operand2 as Instruction[];
Contract.Assume(operand2andBeyond != null);
for (int i = 0, n = operand2andBeyond.Length; i < n; i++) {
Contract.Assume(operand2andBeyond[i] != null);
operand2andBeyond[i] = Simplify(operand2andBeyond[i], mappings, canonicalizer);
}
}
return instruction;
}
private static Instruction SimplifyNullary<Instruction>(Instruction instruction, ValueMappings<Instruction> mappings)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(mappings != null);
var oldOp = instruction.Operation;
OperationCode newCode = OperationCode.Invalid;
switch (oldOp.OperationCode) {
case OperationCode.Ldarga_S: newCode = OperationCode.Ldarga; break;
case OperationCode.Ldloca_S: newCode = OperationCode.Ldloca; break;
case OperationCode.Br_S: newCode = OperationCode.Br; break;
case OperationCode.Leave_S: newCode = OperationCode.Leave; break;
case OperationCode.Ldc_I4_0: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_1: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_2: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_3: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_4: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_5: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_6: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_7: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_8: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_M1: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldc_I4_S: newCode = OperationCode.Ldc_I4; break;
case OperationCode.Ldarg_0: newCode = OperationCode.Ldarg; break;
case OperationCode.Ldarg_1: newCode = OperationCode.Ldarg; break;
case OperationCode.Ldarg_2: newCode = OperationCode.Ldarg; break;
case OperationCode.Ldarg_3: newCode = OperationCode.Ldarg; break;
case OperationCode.Ldarg_S: newCode = OperationCode.Ldarg; break;
case OperationCode.Ldloc_0: newCode = OperationCode.Ldloc; break;
case OperationCode.Ldloc_1: newCode = OperationCode.Ldloc; break;
case OperationCode.Ldloc_2: newCode = OperationCode.Ldloc; break;
case OperationCode.Ldloc_3: newCode = OperationCode.Ldloc; break;
case OperationCode.Ldloc_S: newCode = OperationCode.Ldloc; break;
}
switch (newCode) {
case OperationCode.Ldarg:
case OperationCode.Ldloc:
var localOrParameter = oldOp.Value as INamedEntity;
if (localOrParameter == null) break;
var definingExpression = mappings.GetDefiningExpressionFor(localOrParameter);
if (definingExpression != null) return definingExpression;
break;
}
if (newCode == OperationCode.Invalid) return instruction;
var newOp = new Operation() { OperationCode = newCode, Location = oldOp.Location, Offset = oldOp.Offset, Value = oldOp.Value };
return new Instruction() { Operation = newOp, Operand1 = instruction.Operand1, Operand2 = instruction.Operand2, Type = instruction.Type };
}
/// <summary>
/// Uses Arithmetic and Boolean laws to simplify expressions.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="mappings"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction SimplifyBinary<Instruction>(Instruction instruction, ValueMappings<Instruction> mappings, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(mappings != null);
Contract.Requires(canonicalizer != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var operation = instruction.Operation;
Contract.Assume(instruction.Operand1 is Instruction);
var operand1 = (Instruction)instruction.Operand1;
Contract.Assume(instruction.Operand2 is Instruction);
var operand2 = (Instruction)instruction.Operand2;
IMetadataConstant constantResult = null;
var compileTimeConstant1 = mappings.GetCompileTimeConstantValueFor(operand1);
var compileTimeConstant2 = mappings.GetCompileTimeConstantValueFor(operand2);
if (compileTimeConstant1 != null) {
if (compileTimeConstant2 != null)
constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant1, compileTimeConstant2);
else
constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant1, operand2, mappings);
} else if (compileTimeConstant2 != null) {
constantResult = Evaluator.Evaluate(instruction.Operation, operand1, compileTimeConstant2, mappings);
} else {
constantResult = Evaluator.Evaluate(instruction.Operation, operand1, operand2, mappings);
}
if (constantResult != null) return canonicalizer.GetAsCanonicalizedLoadConstant(constantResult, instruction);
//If we get here, the instruction does not simplify to a constant, but it could still simplify to a simpler expression.
bool operand1IsZero = compileTimeConstant1 != null && MetadataExpressionHelper.IsIntegralZero(compileTimeConstant1);
bool operand1IsOne = compileTimeConstant1 != null && (operand1IsZero ? false : MetadataExpressionHelper.IsIntegralOne(compileTimeConstant1));
bool operand1IsMinusOne = compileTimeConstant1 != null && ((operand1IsZero || operand1IsOne) ? false : MetadataExpressionHelper.IsIntegralMinusOne(compileTimeConstant1));
bool operand2IsZero = compileTimeConstant2 != null && MetadataExpressionHelper.IsIntegralZero(compileTimeConstant2);
bool operand2IsOne = compileTimeConstant2 != null && (operand1IsZero ? false : MetadataExpressionHelper.IsIntegralOne(compileTimeConstant2));
bool operand2IsMinusOne = compileTimeConstant2 != null && ((operand2IsZero || operand2IsOne) ? false : MetadataExpressionHelper.IsIntegralMinusOne(compileTimeConstant2));
operand1 = Simplify(operand1, mappings, canonicalizer);
operand2 = Simplify(operand2, mappings, canonicalizer);
switch (operation.OperationCode) {
case OperationCode.Add:
case OperationCode.Add_Ovf:
case OperationCode.Add_Ovf_Un:
if (operand1IsZero) return operand2;
if (operand2IsZero) return operand1;
//TODO: factor out common mults/divs/etc (subject to overflow checks).
break;
case OperationCode.And:
if (operand1IsZero) return operand1;
if (operand2IsZero) return operand2;
if (operand1IsMinusOne) return operand2;
if (operand2IsMinusOne) return operand1;
if (operand1.Operation.OperationCode == OperationCode.Not && operand2.Operation.OperationCode == OperationCode.Not) {
var opnd11 = operand1.Operand1 as Instruction;
var opnd21 = operand2.Operand1 as Instruction;
Contract.Assume(opnd11 != null && opnd21 != null);
var or = new Operation() { OperationCode = OperationCode.Or, Location = operation.Location, Offset = operation.Offset };
var orInst = new Instruction() { Operation = or, Operand1 = opnd11, Operand2 = opnd21, Type = instruction.Type };
var not = new Operation { OperationCode = OperationCode.Not, Location = operation.Location, Offset = operation.Offset };
return new Instruction() { Operation = not, Operand1 = orInst, Type = instruction.Type };
}
break;
case OperationCode.Ceq:
//If one of the operands is const 0 and the other is a boolean expression, invert the boolean expression
if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean) {
var not = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Not };
instruction = new Instruction() { Operation = not, Operand1 = operand1, Type = instruction.Type };
return SimplifyUnary(instruction, mappings, canonicalizer);
} else if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean) {
var not = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Not };
instruction = new Instruction() { Operation = not, Operand1 = operand2, Type = instruction.Type };
return SimplifyUnary(instruction, mappings, canonicalizer);
} else {
operation = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Beq };
}
break;
case OperationCode.Cgt:
operation = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Bgt };
break;
case OperationCode.Cgt_Un:
operation = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Bgt_Un };
break;
case OperationCode.Clt:
operation = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Blt };
break;
case OperationCode.Clt_Un:
operation = new Operation() { Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Blt_Un };
break;
case OperationCode.Div:
case OperationCode.Div_Un:
if (operand2IsOne) return operand1;
break;
case OperationCode.Mul:
case OperationCode.Mul_Ovf:
case OperationCode.Mul_Ovf_Un:
if (operand1IsOne) return operand2;
if (operand2IsOne) return operand1;
break;
case OperationCode.Or:
if (operand1IsZero) return operand2;
if (operand2IsZero) return operand1;
if (operand1.Operation.OperationCode == OperationCode.Not && operand2.Operation.OperationCode == OperationCode.Not) {
var opnd11 = operand1.Operand1 as Instruction;
var opnd21 = operand2.Operand1 as Instruction;
Contract.Assume(opnd11 != null && opnd21 != null);
var and = new Operation() { OperationCode = OperationCode.And, Location = operation.Location, Offset = operation.Offset };
var andInst = new Instruction() { Operation = and, Operand1 = opnd11, Operand2 = opnd21, Type = instruction.Type };
var not = new Operation { OperationCode = OperationCode.Not, Location = operation.Location, Offset = operation.Offset };
return new Instruction() { Operation = not, Operand1 = andInst, Type = instruction.Type };
}
if (operand1.Operand1 == operand2.Operand1 && operand1.Operand2 == operand2.Operand2 &&
operand1.Operation.OperationCode != operand2.Operation.OperationCode && operand2.Operand1 != null &&
operand1.Operation.OperationCode == GetInverse(operand2.Operation.OperationCode,
operand2.Operand1.Type.TypeCode == PrimitiveTypeCode.Float32 || operand2.Operand1.Type.TypeCode == PrimitiveTypeCode.Float64)) {
return canonicalizer.GetAsCanonicalizedLoadConstant(new MetadataConstant() { Value = true, Type = instruction.Type }, instruction);
}
break;
case OperationCode.Rem:
case OperationCode.Rem_Un:
break;
case OperationCode.Shl:
case OperationCode.Shr:
case OperationCode.Shr_Un:
if (operand2IsZero) return operand1;
break;
case OperationCode.Sub:
case OperationCode.Sub_Ovf:
case OperationCode.Sub_Ovf_Un:
if (operand2IsZero) return operand1;
break;
case OperationCode.Xor:
break;
case OperationCode.Beq:
case OperationCode.Beq_S:
if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean) {
var operand2inv = TryToGetSimplerLogicalInverse(operand2);
if (operand2inv != null) return operand2inv;
} else if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean) {
var operand1inv = TryToGetSimplerLogicalInverse(operand1);
if (operand1inv != null) return operand1inv;
}
goto case OperationCode.Bge_S;
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean) return operand2;
if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean) return operand1;
goto case OperationCode.Bge_S;
case OperationCode.Bge_S:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble_S:
case OperationCode.Ble_Un_S:
case OperationCode.Blt_S:
case OperationCode.Blt_Un_S:
operation = new Operation() {
Location = operation.Location, Offset = operation.Offset,
OperationCode = LongVersionOf(operation.OperationCode), Value = operation.Value
};
break;
}
if (operation != instruction.Operation || operand1 != instruction.Operand1 || operand2 != instruction.Operand2)
return new Instruction() { Operation = operation, Operand1 = operand1, Operand2 = operand2, Type = instruction.Type };
return instruction;
}
/// <summary>
///
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <returns></returns>
public static Instruction HoistPhiNodes<Instruction>(Instruction instruction)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
var operand1 = instruction.Operand1 as Instruction;
if (operand1 == null) return instruction;
var operand2 = instruction.Operand2 as Instruction;
if (operand2 == null) return instruction; //TODO: unary ops
bool operand1IsPhiNode = operand1.Operation.OperationCode == OperationCode.Nop && operand1.Operation.Value is INamedEntity;
bool operand2IsPhiNode = operand2.Operation.OperationCode == OperationCode.Nop && operand2.Operation.Value is INamedEntity;
if (operand1IsPhiNode) {
if (operand2IsPhiNode)
return HoistPhiPhi(instruction, operand1, operand2);
else
return HoistPhiOp(instruction, operand1, operand2);
} else {
if (operand2IsPhiNode)
return HoistOpPhi(instruction, operand1, operand2);
}
return instruction;
}
private static Instruction HoistPhiPhi<Instruction>(Instruction instruction, Instruction operand1, Instruction operand2)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(operand1 != null);
Contract.Requires(operand2 != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var result = new Instruction() { Operation = new Operation() { Value = Dummy.LocalVariable }, Type = instruction.Type };
var operand11 = operand1.Operand1 as Instruction;
var operand21 = operand2.Operand1 as Instruction;
if (operand11 == null) {
Contract.Assume(operand21 == null);
return result;
}
result.Operand1 = new Instruction() { Operation = instruction.Operation, Operand1 = operand11, Operand2 = operand21, Type = instruction.Type };
var operand12 = operand1.Operand2 as Instruction;
var operand22 = operand2.Operand2 as Instruction;
if (operand12 != null && operand22 != null) {
result.Operand2 = new Instruction() { Operation = instruction.Operation, Operand1 = operand12, Operand2 = operand22, Type = instruction.Type };
} else {
var operand12toN = operand1.Operand2 as Instruction[];
var operand22toN = operand2.Operand2 as Instruction[];
if (operand12toN != null && operand22toN != null) {
var n = operand12toN.Length;
Contract.Assume(n == operand22toN.Length);
var resultOperands2ToN = new Instruction[n];
result.Operand2 = resultOperands2ToN;
for (int i = 0; i < n; i++) {
var operand1i = operand12toN[i];
var operand2i = operand22toN[i];
resultOperands2ToN[i] = new Instruction() { Operation = instruction.Operation, Operand1 = operand1i, Operand2 = operand2i, Type = instruction.Type };
}
}
}
return result;
}
private static Instruction HoistPhiOp<Instruction>(Instruction instruction, Instruction operand1, Instruction operand2)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(operand1 != null);
Contract.Requires(operand2 != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var result = new Instruction() { Operation = new Operation() { Value = Dummy.LocalVariable }, Type = instruction.Type };
var operand11 = operand1.Operand1 as Instruction;
if (operand11 == null) {
Contract.Assume(false);
return result;
}
result.Operand1 = new Instruction() { Operation = instruction.Operation, Operand1 = operand11, Operand2 = operand2, Type = instruction.Type };
var operand12 = operand1.Operand2 as Instruction;
if (operand12 != null) {
result.Operand2 = new Instruction() { Operation = instruction.Operation, Operand1 = operand12, Operand2 = operand2, Type = instruction.Type };
} else {
var operand12toN = operand1.Operand2 as Instruction[];
if (operand12toN != null) {
var n = operand12toN.Length;
var resultOperands2ToN = new Instruction[n];
result.Operand2 = resultOperands2ToN;
for (int i = 0; i < n; i++) {
var operand1i = operand12toN[i];
resultOperands2ToN[i] = new Instruction() { Operation = instruction.Operation, Operand1 = operand1i, Operand2 = operand2, Type = instruction.Type };
}
}
}
return result;
}
private static Instruction HoistOpPhi<Instruction>(Instruction instruction, Instruction operand1, Instruction operand2)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(operand1 != null);
Contract.Requires(operand2 != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var result = new Instruction() { Operation = new Operation() { Value = Dummy.LocalVariable }, Type = instruction.Type };
var operand21 = operand2.Operand1 as Instruction;
if (operand21 == null) {
Contract.Assume(false);
return result;
}
result.Operand1 = new Instruction() { Operation = instruction.Operation, Operand1 = operand1, Operand2 = operand21, Type = instruction.Type };
var operand22 = operand2.Operand2 as Instruction;
if (operand22 != null) {
result.Operand2 = new Instruction() { Operation = instruction.Operation, Operand1 = operand1, Operand2 = operand22, Type = instruction.Type };
} else {
var operand22toN = operand2.Operand2 as Instruction[];
if (operand22toN != null) {
var n = operand22toN.Length;
var resultOperands2ToN = new Instruction[n];
result.Operand2 = resultOperands2ToN;
for (int i = 0; i < n; i++) {
var operand2i = operand22toN[i];
resultOperands2ToN[i] = new Instruction() { Operation = instruction.Operation, Operand1 = operand1, Operand2 = operand2i, Type = instruction.Type };
}
}
}
return result;
}
/// <summary>
/// If the given operation code is a short branch, return the corresponding long branch. Otherwise return the given operation code.
/// </summary>
/// <param name="operationCode">An operation code.</param>
public static OperationCode LongVersionOf(OperationCode operationCode) {
switch (operationCode) {
case OperationCode.Beq_S: return OperationCode.Beq;
case OperationCode.Bge_S: return OperationCode.Bge;
case OperationCode.Bge_Un_S: return OperationCode.Bge_Un;
case OperationCode.Bgt_S: return OperationCode.Bgt;
case OperationCode.Bgt_Un_S: return OperationCode.Bgt_Un;
case OperationCode.Ble_S: return OperationCode.Ble;
case OperationCode.Ble_Un_S: return OperationCode.Ble_Un;
case OperationCode.Blt_S: return OperationCode.Blt;
case OperationCode.Blt_Un_S: return OperationCode.Blt_Un;
case OperationCode.Bne_Un_S: return OperationCode.Bne_Un;
case OperationCode.Br_S: return OperationCode.Br;
case OperationCode.Brfalse_S: return OperationCode.Brfalse;
case OperationCode.Brtrue_S: return OperationCode.Brtrue;
case OperationCode.Leave_S: return OperationCode.Leave;
default: return operationCode;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="Instruction"></typeparam>
/// <param name="instruction"></param>
/// <param name="mappings"></param>
/// <param name="canonicalizer"></param>
/// <returns></returns>
internal static Instruction SimplifyUnary<Instruction>(Instruction instruction, ValueMappings<Instruction> mappings, ExpressionCanonicalizer<Instruction> canonicalizer)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
Contract.Requires(mappings != null);
Contract.Requires(canonicalizer != null);
Contract.Ensures(Contract.Result<Instruction>() != null);
var operation = instruction.Operation;
Contract.Assume(instruction.Operand1 is Instruction);
var operand1 = (Instruction)instruction.Operand1;
var operand = Simplify(operand1, mappings, canonicalizer);
var compileTimeConstant = mappings.GetCompileTimeConstantValueFor(operand);
if (compileTimeConstant != null) {
var constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant);
if (constantResult != null) return canonicalizer.GetAsCanonicalizedLoadConstant(constantResult, instruction);
}
switch (operation.OperationCode) {
case OperationCode.Neg:
if (operand.Operation.OperationCode == OperationCode.Neg) {
Contract.Assume(operand.Operand1 is Instruction);
return (Instruction)operand.Operand1;
}
//TODO: if the operand is a binary operation with arithmetic operands where one of them is a Neg
//distribute the neg over the binary operation, if doing so is safe w.r.t. overflow.
break;
case OperationCode.Not:
var simplerInverse = TryToGetSimplerLogicalInverse(operand);
if (simplerInverse != null) return simplerInverse;
if (operand != operand1) {
var operation1 = operand1.Operation;
switch (operation1.OperationCode) {
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
case OperationCode.Beq:
case OperationCode.Beq_S:
OperationCode newOpcode = GetInverse(operation1.OperationCode, operand1.Type.TypeCode == PrimitiveTypeCode.Float32 || operand1.Type.TypeCode == PrimitiveTypeCode.Float64);
return new Instruction() {
Operation = new Operation() { OperationCode = newOpcode, Offset = operation.Offset, Location = operation.Location },
Operand1 = operand1.Operand1,
Operand2 = operand1.Operand2,
Type = instruction.Type
};
}
}
return new Instruction() { Operation = operation, Operand1 = operand, Type = instruction.Type };
}
return instruction;
}
private static Instruction/*?*/ TryToGetSimplerLogicalInverse<Instruction>(Instruction instruction)
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
Contract.Requires(instruction != null);
switch (instruction.Operation.OperationCode) {
case OperationCode.Not:
Contract.Assume(instruction.Operand1 is Instruction);
return (Instruction)instruction.Operand1;
case OperationCode.And: {
var opnd1 = instruction.Operand1 as Instruction;
var opnd2 = instruction.Operand2 as Instruction;
Contract.Assume(opnd1 != null && opnd2 != null);
var opnd1inv = TryToGetSimplerLogicalInverse(opnd1);
var opnd2inv = TryToGetSimplerLogicalInverse(opnd2);
if (opnd1inv == null) {
if (opnd2inv == null) return null;
var not = new Operation() { OperationCode = OperationCode.Not, Location = opnd1.Operation.Location, Offset = opnd1.Operation.Offset };
opnd1inv = new Instruction() { Operation = not, Operand1 = opnd1, Type = instruction.Type };
} else if (opnd2inv == null) {
var not = new Operation() { OperationCode = OperationCode.Not, Location = opnd2.Operation.Location, Offset = opnd2.Operation.Offset };
opnd2inv = new Instruction() { Operation = not, Operand1 = opnd2, Type = instruction.Type };
}
var or = new Operation() { OperationCode = OperationCode.Or, Location = instruction.Operation.Location, Offset = instruction.Operation.Offset };
return new Instruction() { Operation = or, Operand1 = opnd1inv, Operand2 = opnd2inv, Type = instruction.Type };
}
case OperationCode.Or: {
var opnd1 = instruction.Operand1 as Instruction;
var opnd2 = instruction.Operand2 as Instruction;
Contract.Assume(opnd1 != null && opnd2 != null);
var opnd1inv = TryToGetSimplerLogicalInverse(opnd1);
var opnd2inv = TryToGetSimplerLogicalInverse(opnd2);
if (opnd1inv == null) {
if (opnd2inv == null) return null;
var not = new Operation() { OperationCode = OperationCode.Not, Location = opnd1.Operation.Location, Offset = opnd1.Operation.Offset };
opnd1inv = new Instruction() { Operation = not, Operand1 = opnd1, Type = instruction.Type };
} else if (opnd2inv == null) {
var not = new Operation() { OperationCode = OperationCode.Not, Location = opnd2.Operation.Location, Offset = opnd2.Operation.Offset };
opnd2inv = new Instruction() { Operation = not, Operand1 = opnd2, Type = instruction.Type };
}
var and = new Operation() { OperationCode = OperationCode.And, Location = instruction.Operation.Location, Offset = instruction.Operation.Offset };
return new Instruction() { Operation = and, Operand1 = opnd1inv, Operand2 = opnd2inv, Type = instruction.Type };
}
case OperationCode.Beq:
case OperationCode.Bge:
case OperationCode.Bge_Un:
case OperationCode.Bgt:
case OperationCode.Bgt_Un:
case OperationCode.Ble:
case OperationCode.Ble_Un:
case OperationCode.Blt:
case OperationCode.Blt_Un:
case OperationCode.Bne_Un:
case OperationCode.Ceq:
case OperationCode.Cgt:
case OperationCode.Cgt_Un:
case OperationCode.Clt:
case OperationCode.Clt_Un: {
var opnd1 = instruction.Operand1 as Instruction;
var opnd2 = instruction.Operand2 as Instruction;
Contract.Assume(opnd1 != null && opnd2 != null);
OperationCode newOpcode = GetInverse(instruction.Operation.OperationCode, opnd1.Type.TypeCode == PrimitiveTypeCode.Float32 || opnd1.Type.TypeCode == PrimitiveTypeCode.Float64);
if (newOpcode != instruction.Operation.OperationCode) {
var cmp = new Operation() { OperationCode = newOpcode, Location = instruction.Operation.Location, Offset = instruction.Operation.Offset };
return new Instruction() { Operation = cmp, Operand1 = opnd1, Operand2 = opnd2, Type = instruction.Type };
}
break;
}
}
return null;
}
private static OperationCode GetInverse(OperationCode operationCode, bool isFloatingPointOperation) {
if (isFloatingPointOperation) {
switch (operationCode) {
case OperationCode.Beq: return OperationCode.Bne_Un;
case OperationCode.Bge: return OperationCode.Blt_Un;
case OperationCode.Bge_Un: return OperationCode.Blt;
case OperationCode.Bgt: return OperationCode.Ble_Un;
case OperationCode.Bgt_Un: return OperationCode.Ble;
case OperationCode.Ble: return OperationCode.Bgt_Un;
case OperationCode.Ble_Un: return OperationCode.Bgt;
case OperationCode.Blt: return OperationCode.Bge_Un;
case OperationCode.Blt_Un: return OperationCode.Bge;
case OperationCode.Bne_Un: return OperationCode.Beq;
case OperationCode.Ceq: return OperationCode.Bne_Un;
case OperationCode.Cgt: return OperationCode.Ble_Un;
case OperationCode.Cgt_Un: return OperationCode.Ble;
case OperationCode.Clt: return OperationCode.Bge_Un;
case OperationCode.Clt_Un: return OperationCode.Bge;
}
} else {
switch (operationCode) {
case OperationCode.Beq: return OperationCode.Bne_Un;
case OperationCode.Bge: return OperationCode.Blt;
case OperationCode.Bge_Un: return OperationCode.Blt_Un;
case OperationCode.Bgt: return OperationCode.Ble;
case OperationCode.Bgt_Un: return OperationCode.Ble_Un;
case OperationCode.Ble: return OperationCode.Bgt;
case OperationCode.Ble_Un: return OperationCode.Bgt_Un;
case OperationCode.Blt: return OperationCode.Bge;
case OperationCode.Blt_Un: return OperationCode.Bge_Un;
case OperationCode.Bne_Un: return OperationCode.Beq;
case OperationCode.Ceq: return OperationCode.Bne_Un;
case OperationCode.Cgt: return OperationCode.Ble;
case OperationCode.Cgt_Un: return OperationCode.Ble;
case OperationCode.Clt: return OperationCode.Bge;
case OperationCode.Clt_Un: return OperationCode.Bge_Un;
}
}
return operationCode;
}
}
}

Просмотреть файл

@ -0,0 +1,967 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Provides a static method that modifies a suitable control and data flow graph into a form where every local is assigned to in a single location.
/// That is, the graph is put into Static Single Assignment (SSA) form. (The "Static" is an attempt to make it clear that a local can be assigned
/// to many times dynamically (during execution) even though there is a single assignment instruction for it in the graph.)
/// </summary>
/// <typeparam name="BasicBlock">A type that is a subtype of Microsoft.Cci.Analysis.SSABasicBlock.</typeparam>
/// <typeparam name="Instruction">A type that is a subtype of Microsoft.Cci.Analysis.Instruction and that has a default constructor.</typeparam>
public class SingleAssigner<BasicBlock, Instruction>
where BasicBlock : SSABasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
/// Initializes an instance of SingleAssigner.
/// </summary>
/// <param name="cdfg">
/// A set of basic blocks, each of which has a list of successor blocks and some other information.
/// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes.
/// </param>
/// <param name="nameTable">
/// An extensible collection of IName instances that represent names that are commonly used during compilation.
/// </param>
/// <param name="cfgQueries"></param>
/// <param name="sourceLocationProvider">An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.</param>
private SingleAssigner(INameTable nameTable, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg,
ControlGraphQueries<BasicBlock, Instruction> cfgQueries, ISourceLocationProvider sourceLocationProvider) {
Contract.Requires(nameTable != null);
Contract.Requires(cdfg != null);
Contract.Requires(cfgQueries != null);
this.nameTable = nameTable;
this.cdfg = cdfg;
this.cfgQueries = cfgQueries;
this.sourceLocationProvider = sourceLocationProvider;
}
/// <summary>
/// An extensible collection of IName instances that represent names that are commonly used during compilation.
/// </summary>
INameTable nameTable;
/// <summary>
/// An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.
/// </summary>
ISourceLocationProvider sourceLocationProvider;
/// <summary>
/// Used to make up unique names for the new locals introduced to make all assignments unique.
/// </summary>
uint localCounter;
/// <summary>
/// A set of basic blocks, each of which has a list of successor blocks and some other information.
/// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes.
/// </summary>
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
/// <summary>
/// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers.
/// </summary>
ControlGraphQueries<BasicBlock, Instruction> cfgQueries;
/// <summary>
/// A list of all of the reads (join points or phi nodes) in this.cdfg. Used to avoid allocating new List objects for every block.
/// </summary>
List<Join> allReads = new List<Join>();
/// <summary>
/// Keeps track of all of the blocks that have already been visited. Used to break cycles during visitation.
/// </summary>
SetOfObjects blocksAlreadyVisited = new SetOfObjects();
/// <summary>
/// A map from the local (or parameter) used in the original IL to the new local written by the most recent assignment to the original local.
/// </summary>
Hashtable<object, object> ssaVariableFor = new Hashtable<object, object>();
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.nameTable != null);
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.cfgQueries != null);
Contract.Invariant(this.allReads != null);
Contract.Invariant(this.blocksAlreadyVisited != null);
Contract.Invariant(this.ssaVariableFor != null);
}
/// <summary>
/// Rewrites the blocks in the given cdfg so that every assignment to a local or parameter is to a new local (and thus each local is just
/// assigned to in exactly one place in the graph). The new names introduced by the writes are connected to the reads in successor blocks
/// by means of join points (a.k.a. Phi nodes) that are found in the Reads property of an SSABasicBlock.
/// </summary>
/// <param name="cdfg">
/// A set of basic blocks, each of which has a list of successor blocks and some other information.
/// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes.
/// </param>
/// <param name="cfgQueries">
/// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers.
/// </param>
/// <param name="nameTable">
/// An extensible collection of IName instances that represent names that are commonly used during compilation.
/// </param>
/// <param name="sourceLocationProvider"></param>
public static void GetInSingleAssignmentForm(INameTable nameTable, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg,
ControlGraphQueries<BasicBlock, Instruction> cfgQueries, ISourceLocationProvider sourceLocationProvider) {
Contract.Requires(nameTable != null);
Contract.Requires(cdfg != null);
Contract.Requires(cfgQueries != null);
var singleAssigner = new SingleAssigner<BasicBlock, Instruction>(nameTable, cdfg, cfgQueries, sourceLocationProvider);
singleAssigner.GetInSingleAssignmentForm();
}
/// <summary>
/// Rewrites the blocks in the given cdfg so that every assignment to a local or parameter is to a new local (and thus each local is just
/// assigned to in exactly one place in the graph). The new names introduced by the writes are connected to the reads in successor blocks
/// by means of join points (a.k.a. Phi nodes) that are found in the Reads property of an SSABasicBlock.
/// </summary>
private void GetInSingleAssignmentForm() {
foreach (var block in this.cdfg.AllBlocks) {
Contract.Assume(block != null);
this.CreateSSAVariablesAndJoinInformation(block);
}
foreach (var block in this.cdfg.RootBlocks) {
Contract.Assume(block != null);
this.ssaVariableFor.Clear();
this.ReplaceLocalsWithSSALocals(block, this.ssaVariableFor);
}
}
private void ReplaceLocalsWithSSALocals(BasicBlock block, Hashtable<object, object> ssaVariableFor) {
Contract.Requires(block != null);
Contract.Requires(ssaVariableFor != null);
if (block.Joins != null) {
foreach (var join in block.Joins) {
Contract.Assume(join.OriginalLocal != null);
ssaVariableFor[join.OriginalLocal] = join.NewLocal;
}
}
foreach (var instruction in block.Instructions) {
Contract.Assume(instruction != null);
var operation = instruction.Operation;
switch (operation.OperationCode) {
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
case OperationCode.Starg:
case OperationCode.Starg_S:
Contract.Assume(operation.Value is SSAParameterDefinition);
var ssaParam = (SSAParameterDefinition)operation.Value;
ssaVariableFor[ssaParam.OriginalParameter] = ssaParam;
break;
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
Contract.Assume(operation.Value is SSALocalDefinition);
var ssaLocal = (SSALocalDefinition)operation.Value;
ssaVariableFor[ssaLocal.OriginalLocal] = ssaLocal;
break;
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
var ssaVar = ssaVariableFor[operation.Value??Dummy.ParameterDefinition];
if (ssaVar != null)
instruction.Operation = new SSAOperation(operation, ssaVar);
break;
}
}
var successors = this.cdfg.SuccessorsFor(block);
var n = successors.Count;
if (n == 0) return;
for (var i = 0; i < n; i++) {
var succ = successors[i];
if (this.cfgQueries.ImmediateDominator(succ) == block) {
//Add join information, if necessary
foreach (var pair in this.ssaVariableFor) {
if (succ.Joins != null) {
foreach (var join in succ.Joins) {
if (join.OriginalLocal == pair.key) {
if (join.Join2 == null) {
join.Join2 = (INamedEntity)pair.value;
join.Block2 = block;
} else {
var otherJoins = join.OtherJoins;
if (otherJoins == null) join.OtherJoins = otherJoins = new List<INamedEntity>();
otherJoins.Add((INamedEntity)pair.value);
var otherBlocks = join.OtherBlocks;
if (otherBlocks == null) join.OtherBlocks = otherBlocks = new List<object>();
otherBlocks.Add(block);
}
break;
}
}
}
}
}
}
for (var i = 0; i < n-1; i++) {
var succ = successors[i];
if (!this.blocksAlreadyVisited.Add(succ)) continue;
var copyOfssaVariableFor = new Hashtable<object, object>(ssaVariableFor);
this.ReplaceLocalsWithSSALocals(succ, copyOfssaVariableFor);
}
var lastSuccessor = successors[n-1];
//Contract.Assume(lastSuccessor != null);
if (this.blocksAlreadyVisited.Add(lastSuccessor))
this.ReplaceLocalsWithSSALocals(lastSuccessor, ssaVariableFor);
}
/// <summary>
/// Runs through the instructions of the given block and updates any instruction that references a local or parameter
/// to instead reference a SSA local or parameter.
/// </summary>
private void CreateSSAVariablesAndJoinInformation(BasicBlock block) {
Contract.Requires(block != null);
this.ssaVariableFor.Clear();
foreach (var instruction in block.Instructions) {
Contract.Assume(instruction != null);
var operation = instruction.Operation;
switch (operation.OperationCode) {
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
var ssaVariable = this.ssaVariableFor[operation.Value??Dummy.ParameterDefinition];
if (ssaVariable != null)
//The variable has already been defined in this block, use its new identity.
instruction.Operation = new SSAOperation(operation, ssaVariable);
else
//Create a new identity for this variable.
this.ReplaceWithNewSSAValue(instruction);
//Now replace the value one more time because this instruction represents both a read (the above replacement) and a write (the replacement below).
this.ReplaceWithNewSSAValue(instruction);
break;
case OperationCode.Starg:
case OperationCode.Starg_S:
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
//Assign to new variable
this.ReplaceWithNewSSAValue(instruction);
break;
//case OperationCode.Stind_I:
//case OperationCode.Stind_I1:
//case OperationCode.Stind_I2:
//case OperationCode.Stind_I4:
//case OperationCode.Stind_I8:
//case OperationCode.Stind_R4:
//case OperationCode.Stind_R8:
//case OperationCode.Stind_Ref:
//These could potentially write to locals. In that case the SSA constructed by this algorithm is inaccurate.
//Such coding patterns are very rare and fixing the inaccuracy at this level is very expensive.
//Consequently we leave it to the client to either fix the inaccuracy itself, or to detect situations where
//a stind could write to a local and to report them as errors.
}
}
foreach (var successor in this.cfgQueries.DominanceFrontierFor(block)) {
Contract.Assume(successor != null);
foreach (var pair in this.ssaVariableFor) {
bool joinedWriteWithRead = false;
if (successor.Joins != null) {
foreach (var join in successor.Joins) {
if (join.OriginalLocal == pair.key) {
if (join.Join2 == null) {
join.Join2 = (INamedEntity)pair.value;
join.Block2 = block;
} else {
var otherJoins = join.OtherJoins;
if (otherJoins == null) join.OtherJoins = otherJoins = new List<INamedEntity>();
otherJoins.Add((INamedEntity)pair.value);
var otherBlocks = join.OtherBlocks;
if (otherBlocks == null) join.OtherBlocks = otherBlocks = new List<object>();
otherBlocks.Add(block);
}
joinedWriteWithRead = true;
break;
}
}
}
if (!joinedWriteWithRead) {
successor.Joins = new Join() {
OriginalLocal = pair.key, NewLocal = this.GetNewLocal(pair.key),
Join1 = (INamedEntity)pair.value, Block1 = block, Next = successor.Joins
};
}
}
}
}
/// <summary>
/// Makes up a new LocalDefinition or ParameterDefinition corresponding to the one in instruction.Operation.Value and
/// then updates instruction.Operation.Value with the new definition. The new definition will be an instance of
/// SSALocalDefinition or SSAParameterDefinition, both of which retain a reference to the original definition
/// so that the original IL can be recovered from the control flow graph even after it has been put into SSA form.
/// </summary>
/// <param name="instruction">The instruction to update.</param>
private void ReplaceWithNewSSAValue(Instruction instruction) {
Contract.Requires(instruction != null);
var operation = instruction.Operation;
var local = operation.Value as ILocalDefinition;
if (local != null) {
var newLocal = this.GetNewLocal(local);
this.ssaVariableFor[local] = newLocal;
instruction.Operation = new SSAOperation(operation, newLocal);
} else {
var par = operation.Value as IParameterDefinition;
var newPar = this.GetNewLocal(par);
if (par == null) par = Dummy.ParameterDefinition;
this.ssaVariableFor[par] = newPar;
instruction.Operation = new SSAOperation(operation, newPar);
}
}
/// <summary>
/// Returns a new SSALocalDefinition if the argument is a local or a new SSAParameterDefinition if the argument is a parameter.
/// </summary>
private object GetNewLocal(object localOrParameter) {
Contract.Ensures(Contract.Result<object>() != null);
var local = localOrParameter as ILocalDefinition;
if (local != null) {
var localName = this.GetLocalName(local);
IName newName = this.GetNewName(localName);
return new SSALocalDefinition(local, newName);
} else {
var par = (localOrParameter as IParameterDefinition)??Dummy.ParameterDefinition;
IName newName = this.GetNewName(par.Name.Value);
return new SSAParameterDefinition(par, newName, this.cdfg.MethodBody.MethodDefinition.ContainingTypeDefinition);
}
}
/// <summary>
/// Looks up a source provided name for the local using this.sourceLocationProvider, if there is one.
/// </summary>
/// <param name="local"></param>
/// <returns></returns>
private string GetLocalName(ILocalDefinition local) {
Contract.Requires(local != null);
Contract.Ensures(Contract.Result<string>() != null);
if (this.sourceLocationProvider != null) {
bool isCompilerGenerated;
var result = this.sourceLocationProvider.GetSourceNameFor(local, out isCompilerGenerated);
if (!string.IsNullOrEmpty(result)) return result;
}
return local.Name.Value;
}
/// <summary>
/// Makes up a new name that is derived from the given name, but distinct from all other local names in this graph.
/// </summary>
/// <remarks>Since all local names are going to get rewritten like this, they should remain unique if they started out that way.</remarks>
private IName GetNewName(string name) {
Contract.Requires(name != null);
Contract.Ensures(Contract.Result<IName>() != null);
if (name.Length == 0) name = "this";
return this.nameTable.GetNameFor(name+"_"+this.localCounter++);
}
}
/// <summary>
/// A basic block in a control flow graph, enhanced with information to help create and represent a Static Single Assignment (SSA) form
/// of the control flow graph.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
public class SSABasicBlock<Instruction> : EnhancedBasicBlock<Instruction> where Instruction : Microsoft.Cci.Analysis.Instruction {
/// <summary>
/// A potentially null (empty) list of locals
/// </summary>
public Join/*?*/ Joins;
}
/// <summary>
/// Records information about a local (or parameter) whose value can come from more than one SSA variable defined in ancestor blocks.
/// Corresponds to a "Phi node" in SSA literature.
/// </summary>
public class Join {
/// <summary>
/// The block from which control flowed to create Join1.
/// </summary>
public object Block1;
/// <summary>
/// The block from which control flowed to create Join2.
/// </summary>
public object Block2;
/// <summary>
/// A potentially null (empty) list of blocks from which control flowed to create OtherJoins. The order is the same, so OtherBlocks[i] will be the block that provided OtherJoins[i].
/// </summary>
public List<object>/*?*/ OtherBlocks;
/// <summary>
/// The local (or parameter) that appears in the original IL.
/// </summary>
public object OriginalLocal;
/// <summary>
/// The "SSA" local (or parameter) that is "written" by this join point (a.k.a. "Phi node")
/// </summary>
public object NewLocal;
/// <summary>
/// A local written by an ancestor block that flows into this join point without an intervening write to OriginalLocal.
/// </summary>
public INamedEntity Join1;
/// <summary>
/// A local written by another ancestor block that flows into this join point without an intervening write to OriginalLocal.
/// </summary>
public INamedEntity/*?*/ Join2;
/// <summary>
/// A potentially null (empty) set of locals written by other ancestor blocks that flows into this join point without an intervening write to OriginalLocal.
/// </summary>
public List<INamedEntity>/*?*/ OtherJoins;
/// <summary>
/// The type of the local (or parameter).
/// </summary>
public ITypeReference Type {
get {
Contract.Ensures(Contract.Result<ITypeReference>() != null);
var local = this.NewLocal as ILocalDefinition;
if (local != null) return local.Type;
var par = this.NewLocal as IParameterDefinition;
Contract.Assume(par != null);
return par.Type;
}
}
/// <summary>
/// The next local.
/// </summary>
internal Join/*?*/ Next;
/// <summary>
///
/// </summary>
/// <returns></returns>
public ReadLocalEnumerator GetEnumerator() {
return new ReadLocalEnumerator(this);
}
/// <summary>
///
/// </summary>
public struct ReadLocalEnumerator {
internal ReadLocalEnumerator(Join head) {
Contract.Requires(head != null);
this.current = head;
this.next = head;
}
/// <summary>
///
/// </summary>
public Join Current {
get {
Contract.Ensures(Contract.Result<Join>() != null);
Contract.Assume(this.current != null);
return this.current;
}
}
Join/*?*/ current;
Join/*?*/ next;
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool MoveNext() {
if (this.next == null) return false;
this.current = this.next;
this.next = this.current.Next;
return true;
}
}
}
/// <summary>
/// A local definition that is just a new name (and object identity) for an existing local. The existing local
/// can be recovered via the OriginalLocal property.
/// </summary>
public class SSALocalDefinition : ILocalDefinition {
/// <summary>
/// A local definition that is just a new name (and object identity) for an existing local. The existing local
/// can be recovered via the OriginalLocal property.
/// </summary>
/// <param name="originalLocal">The local for which the new local provides a new name and new object identity.</param>
/// <param name="name">The name of the new local.</param>
public SSALocalDefinition(ILocalDefinition originalLocal, IName name) {
Contract.Requires(originalLocal != null);
Contract.Requires(name != null);
this.originalLocal = originalLocal;
this.name = name;
}
/// <summary>
/// The name of this local.
/// </summary>
IName name;
/// <summary>
/// The local for which this local provides a new name and new object identity.
/// </summary>
ILocalDefinition originalLocal;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.originalLocal != null);
Contract.Invariant(this.name != null);
}
/// <summary>
/// The local for which this local provides a new name and new object identity.
/// </summary>
public ILocalDefinition OriginalLocal {
get {
Contract.Ensures(Contract.Result<ILocalDefinition>() != null);
return this.originalLocal;
}
}
/// <summary>
/// Return the name of the local.
/// </summary>
public override string ToString() {
return this.name.Value;
}
#region ILocalDefinition Members
/// <summary>
/// The compile time value of the definition, if it is a local constant.
/// </summary>
public IMetadataConstant CompileTimeValue {
get {
Contract.Assume(this.originalLocal.IsConstant);
return this.originalLocal.CompileTimeValue;
}
}
/// <summary>
/// Custom modifiers associated with local variable definition.
/// </summary>
public IEnumerable<ICustomModifier> CustomModifiers {
get {
Contract.Assume(this.originalLocal.IsModified);
return this.originalLocal.CustomModifiers;
}
}
/// <summary>
/// True if this local definition is readonly and initialized with a compile time constant value.
/// </summary>
public bool IsConstant {
get { return this.originalLocal.IsConstant; }
}
/// <summary>
/// The local variable has custom modifiers.
/// </summary>
public bool IsModified {
get { return this.originalLocal.IsModified; }
}
/// <summary>
/// True if the value referenced by the local must not be moved by the actions of the garbage collector.
/// </summary>
public bool IsPinned {
get { return this.originalLocal.IsPinned; }
}
/// <summary>
/// True if the local contains a managed pointer (for example a reference to a local variable or a reference to a field of an object).
/// </summary>
public bool IsReference {
get { return this.originalLocal.IsReference; }
}
/// <summary>
/// The definition of the method in which this local is defined.
/// </summary>
public IMethodDefinition MethodDefinition {
get { return this.originalLocal.MethodDefinition; }
}
/// <summary>
/// The type of the local.
/// </summary>
public ITypeReference Type {
get { return this.originalLocal.Type; }
}
#endregion
#region INamedEntity Members
/// <summary>
/// The name of the entity.
/// </summary>
public IName Name {
get { return this.name; }
}
#endregion
#region IObjectWithLocations Members
/// <summary>
/// A potentially empty collection of locations that correspond to this instance.
/// </summary>
public IEnumerable<ILocation> Locations {
get { return this.originalLocal.Locations; }
}
#endregion
}
/// <summary>
/// A parameter definition that is just a new name (and object identity) for an existing parameter. The existing parameter
/// can be recovered via the OriginalParameter property.
/// </summary>
public class SSAParameterDefinition : IParameterDefinition {
/// <summary>
/// A parameter definition that is just a new name (and object identity) for an existing parameter. The existing parameter
/// can be recovered via the OriginalParameter property.
/// </summary>
/// <param name="originalParameter">The parameter for which the new parameter provides a new name and new object identity.</param>
/// <param name="name"></param>
/// <param name="containingType"></param>
public SSAParameterDefinition(IParameterDefinition originalParameter, IName name, ITypeDefinition containingType) {
Contract.Requires(originalParameter != null);
Contract.Requires(name != null);
Contract.Requires(containingType != null);
this.originalParameter = originalParameter;
this.name = name;
if (originalParameter.Type is Dummy)
this.type = containingType; //should only happen if the parameter is the this parameter.
else
this.type = originalParameter.Type;
}
/// <summary>
/// The name of this parameter.
/// </summary>
IName name;
/// <summary>
/// The parameter for which this object provides a new name and new object identity.
/// </summary>
IParameterDefinition originalParameter;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.originalParameter != null);
Contract.Invariant(this.name != null);
Contract.Invariant(this.type != null);
}
/// <summary>
/// The parameter for which this object provides a new name and new object identity.
/// </summary>
public IParameterDefinition OriginalParameter {
get {
Contract.Ensures(Contract.Result<IParameterDefinition>() != null);
return this.originalParameter;
}
}
/// <summary>
/// Returns the name of the parameter.
/// </summary>
public override string ToString() {
return this.name.Value;
}
#region IParameterDefinition Members
/// <summary>
/// A compile time constant value that should be supplied as the corresponding argument value by callers that do not explicitly specify an argument value for this parameter.
/// </summary>
public IMetadataConstant DefaultValue {
get { return this.originalParameter.DefaultValue; }
}
/// <summary>
/// True if the parameter has a default value that should be supplied as the argument value by a caller for which the argument value has not been explicitly specified.
/// </summary>
public bool HasDefaultValue {
get { return this.originalParameter.HasDefaultValue; }
}
/// <summary>
/// True if the argument value must be included in the marshalled arguments passed to a remote callee.
/// </summary>
public bool IsIn {
get { return this.originalParameter.IsIn; }
}
/// <summary>
/// This parameter has associated marshalling information.
/// </summary>
public bool IsMarshalledExplicitly {
get { return this.originalParameter.IsMarshalledExplicitly; }
}
/// <summary>
/// True if the argument value must be included in the marshalled arguments passed to a remote callee only if it is different from the default value (if there is one).
/// </summary>
public bool IsOptional {
get { return this.originalParameter.IsOptional; }
}
/// <summary>
/// True if the final value assigned to the parameter will be marshalled with the return values passed back from a remote callee.
/// </summary>
public bool IsOut {
get { return this.originalParameter.IsOut; }
}
/// <summary>
/// True if the parameter has the ParamArrayAttribute custom attribute.
/// </summary>
public bool IsParameterArray {
get { return this.originalParameter.IsParameterArray; }
}
/// <summary>
/// Specifies how this parameter is marshalled when it is accessed from unmanaged code.
/// </summary>
public IMarshallingInformation MarshallingInformation {
get { return this.originalParameter.MarshallingInformation; }
}
/// <summary>
/// The element type of the parameter array.
/// </summary>
public ITypeReference ParamArrayElementType {
get { return this.originalParameter.ParamArrayElementType; }
}
#endregion
#region IReference Members
/// <summary>
/// A collection of metadata custom attributes that are associated with this definition.
/// </summary>
public IEnumerable<ICustomAttribute> Attributes {
get { return this.originalParameter.Attributes; }
}
/// <summary>
/// Calls visitor.Visit(IParameterDefinition).
/// </summary>
public void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Calls visitor.VisitReference(IParameterDefinition).
/// </summary>
public void DispatchAsReference(IMetadataVisitor visitor) {
visitor.VisitReference(this);
}
#endregion
#region IObjectWithLocations Members
/// <summary>
/// A potentially empty collection of locations that correspond to this instance.
/// </summary>
public IEnumerable<ILocation> Locations {
get { return this.originalParameter.Locations; }
}
#endregion
#region INamedEntity Members
/// <summary>
/// The name of the entity.
/// </summary>
public IName Name {
get { return this.name; }
}
#endregion
#region IParameterTypeInformation Members
/// <summary>
/// The method or property that defines this parameter.
/// </summary>
public ISignature ContainingSignature {
get { return this.originalParameter.ContainingSignature; }
}
/// <summary>
/// The list of custom modifiers, if any, associated with the parameter. Evaluate this property only if IsModified is true.
/// </summary>
public IEnumerable<ICustomModifier> CustomModifiers {
get {
Contract.Assume(this.originalParameter.IsModified);
return this.originalParameter.CustomModifiers;
}
}
/// <summary>
/// True if the parameter is passed by reference (using a managed pointer).
/// </summary>
public bool IsByReference {
get { return this.originalParameter.IsByReference; }
}
/// <summary>
/// This parameter has one or more custom modifiers associated with it.
/// </summary>
public bool IsModified {
get { return this.originalParameter.IsModified; }
}
/// <summary>
/// The type of argument value that corresponds to this parameter.
/// </summary>
public ITypeReference Type {
get { return this.type; }
}
ITypeReference type;
#endregion
#region IParameterListEntry Members
/// <summary>
/// The position in the parameter list where this instance can be found.
/// </summary>
public ushort Index {
get { return this.originalParameter.Index; }
}
#endregion
#region IMetadataConstantContainer Members
/// <summary>
/// The constant value associated with this metadata object. For example, the default value of a parameter.
/// </summary>
public IMetadataConstant Constant {
get { return this.originalParameter.Constant; }
}
#endregion
}
/// <summary>
/// A copy of an existing operation, whose Value property has been updated to reference a SSALocalDefinition or SSAParameterDefinition.
/// The original operation can be recovered via the OriginalOperation property.
/// </summary>
internal class SSAOperation : IOperation {
/// <summary>
/// A copy of an existing operation, whose Value property has been updated to reference a SSALocalDefinition or SSAParameterDefinition.
/// The original operation can be recovered via the OriginalOperation property.
/// </summary>
/// <param name="originalOperation">The operation to copy into the new operation.</param>
/// <param name="value">The object to use as the Value property of the new operation.</param>
internal SSAOperation(IOperation originalOperation, object value) {
Contract.Requires(originalOperation != null);
this.originalOperation = originalOperation;
this.value = value;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.originalOperation != null);
}
/// <summary>
/// The operation that was replaced by this object. It is the same as this object except for this.Value.
/// </summary>
IOperation originalOperation;
/// <summary>
/// The object to use as the Value property of this object. Usually an SSALocalDefinition or an SSAParameterDefinition
/// but could be a Dummy.ParameterDefinition of the operation references the this value of an instance method.
/// </summary>
object value;
/// <summary>
/// The operation that was replaced by this object. It is the same as this object except for this.Value.
/// </summary>
public IOperation OriginalOperation {
get {
return this.originalOperation;
}
}
#region IOperation Members
/// <summary>
/// The actual value of the operation code
/// </summary>
public OperationCode OperationCode {
get { return this.originalOperation.OperationCode; }
}
/// <summary>
/// The offset from the start of the operation stream of a method
/// </summary>
public uint Offset {
get { return this.originalOperation.Offset; }
}
/// <summary>
/// The location that corresponds to this instruction.
/// </summary>
public ILocation Location {
get { return this.originalOperation.Location; }
}
/// <summary>
/// Immediate data such as a string, the address of a branch target, or a metadata reference, such as a Field
/// </summary>
public object Value {
get { return this.value; }
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,340 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
using Microsoft.Cci.MutableCodeModel;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Provides several maps from expressions to concrete and abstract values.
/// </summary>
/// <typeparam name="Instruction">An instruction that results in value.</typeparam>
public class ValueMappings<Instruction>
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
/// Provides several maps from expressions to concrete and abstract values.
/// </summary>
public ValueMappings(IPlatformType platformType, ISatSolver/*?*/ satSolver = null) {
Contract.Requires(platformType != null);
if (satSolver != null)
this.satSolverHelper = new SatSolverHelper<Instruction>(satSolver, this);
this.Int8Interval = new Interval(new MetadataConstant() { Value = sbyte.MinValue, Type = platformType.SystemInt8 },
new MetadataConstant() { Value = sbyte.MaxValue, Type = platformType.SystemInt8 });
this.Int16Interval = new Interval(new MetadataConstant() { Value = short.MinValue, Type = platformType.SystemInt16 },
new MetadataConstant() { Value = short.MaxValue, Type = platformType.SystemInt16 });
this.Int32Interval = new Interval(new MetadataConstant() { Value = int.MinValue, Type = platformType.SystemInt32 },
new MetadataConstant() { Value = int.MaxValue, Type = platformType.SystemInt32 });
this.Int64Interval = new Interval(new MetadataConstant() { Value = long.MinValue, Type = platformType.SystemInt64 },
new MetadataConstant() { Value = long.MaxValue, Type = platformType.SystemInt64 });
this.UInt8Interval = new Interval(new MetadataConstant() { Value = byte.MinValue, Type = platformType.SystemUInt8 },
new MetadataConstant() { Value = byte.MaxValue, Type = platformType.SystemUInt8 });
this.UInt16Interval = new Interval(new MetadataConstant() { Value = ushort.MinValue, Type = platformType.SystemUInt16 },
new MetadataConstant() { Value = ushort.MaxValue, Type = platformType.SystemUInt16 });
this.UInt32Interval = new Interval(new MetadataConstant() { Value = uint.MinValue, Type = platformType.SystemUInt32 },
new MetadataConstant() { Value = uint.MaxValue, Type = platformType.SystemUInt32 });
this.UInt64Interval = new Interval(new MetadataConstant() { Value = ulong.MinValue, Type = platformType.SystemUInt64 },
new MetadataConstant() { Value = ulong.MaxValue, Type = platformType.SystemUInt64 });
}
Hashtable<Instruction, object> compileTimeConstantValueForExpression = new Hashtable<Instruction, object>();
Hashtable<IMetadataConstant> compileTimeConstantForSSAVariable = new Hashtable<IMetadataConstant>();
Hashtable<Instruction, AiBasicBlock<Instruction>> definingBlockForExpression = new Hashtable<Instruction, AiBasicBlock<Instruction>>();
Hashtable<Instruction> definingExpressionForSSAVariable = new Hashtable<Instruction>();
Hashtable<Join> definingJoinForSSAVariable = new Hashtable<Join>();
Hashtable<Instruction, Instruction> expressionForExpression = new Hashtable<Instruction, Instruction>();
Interval dummyInterval = new Interval();
SatSolverHelper<Instruction>/*?*/ satSolverHelper;
HashtableForUintValues<Instruction> recursiveExpressions = new HashtableForUintValues<Instruction>();
internal Interval Int8Interval;
internal Interval Int16Interval;
internal Interval Int32Interval;
internal Interval Int64Interval;
internal Interval UInt8Interval;
internal Interval UInt16Interval;
internal Interval UInt32Interval;
internal Interval UInt64Interval;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.compileTimeConstantValueForExpression != null);
Contract.Invariant(this.compileTimeConstantForSSAVariable != null);
Contract.Invariant(this.definingBlockForExpression != null);
Contract.Invariant(this.definingExpressionForSSAVariable != null);
Contract.Invariant(this.definingJoinForSSAVariable != null);
Contract.Invariant(this.expressionForExpression != null);
Contract.Invariant(this.recursiveExpressions != null);
}
/// <summary>
/// Returns a compile time constant value that is known to be the value of the given expression in all possible executions of the analyzed method.
/// If the value is Dummy.Constant, the expression is known to fail at runtime in all possible executions of the analyzed method.
/// </summary>
/// <param name="expression">The expression for which a compile time constant value is desired.</param>
/// <param name="block">A block providing the context for the interval. The entry contraints of the block are used to narrow the interval if possible. May be null.</param>
[Pure]
public IMetadataConstant/*?*/ GetCompileTimeConstantValueFor(Instruction expression, AiBasicBlock<Instruction>/*?*/ block = null) {
Contract.Requires(expression != null);
var result = this.compileTimeConstantValueForExpression[expression] as IMetadataConstant;
if (result != null) return result;
var ce = this.GetCanonicalExpressionFor(expression);
if (ce == null) return null;
result = this.compileTimeConstantValueForExpression[ce] as IMetadataConstant;
if (result != null || block == null) return result;
result = block.ConstantForExpression[expression] as IMetadataConstant;
if (result != null) {
if (result == Dummy.Constant) return null;
return result;
}
var operand1 = ce.Operand1 as Instruction;
if (operand1 == null) return null;
var operand2 = ce.Operand2 as Instruction;
if (operand2 != null) {
result = Evaluator.Evaluate(ce.Operation, operand1, operand2, this, block);
block.ConstantForExpression[expression] = result??Dummy.Constant;
if (result != null && result != Dummy.Constant) {
return result;
}
} else {
var operands2toN = ce.Operand2 as Instruction[];
if (operands2toN != null) {
result = Evaluator.Evaluate(ce.Operation, operand1, operands2toN, this, block);
block.ConstantForExpression[expression] = result??Dummy.Constant;
if (result != null && result != Dummy.Constant) {
return result;
}
}
}
return null;
}
/// <summary>
/// Returns a compile time constant that is known to be the value that is assigned to the given variable in all possible executions of the analyzed method.
/// </summary>
public IMetadataConstant/*?*/ GetCompileTimeConstantValueFor(INamedEntity variable) {
Contract.Requires(variable != null);
return this.compileTimeConstantForSSAVariable[(uint)variable.Name.UniqueKey];
}
/// <summary>
/// Returns an expression that results in the same value as the given expression in all possible executions of the analyzed method.
/// May be null if no such expression can be found.
/// </summary>
public Instruction/*?*/ GetCanonicalExpressionFor(Instruction expression) {
Contract.Requires(expression != null);
return this.expressionForExpression[expression];
}
/// <summary>
/// Returns the expression which computes the value of the sole assignment to the given variable.
/// This can be a NOP instruction, which is a "phi" node in the SSA. Can be null.
/// </summary>
public Instruction/*?*/ GetDefiningExpressionFor(INamedEntity variable) {
Contract.Requires(variable != null);
return this.definingExpressionForSSAVariable[(uint)variable.Name.UniqueKey];
}
/// <summary>
/// Returns the block that defined the given "phi" node expression. This is useful because the entry contraints of this block might provide
/// additional information about the expression. If the block has not been defined earlier via SetDefiningBlockFor, the result will be null.
/// </summary>
internal AiBasicBlock<Instruction>/*?*/ GetDefiningBlockFor(Instruction expression) {
Contract.Requires(expression != null);
return this.definingBlockForExpression[expression];
}
/// <summary>
/// Return the Join information of the "phi" node that is the right hand side of the sole assignment to the given variable. Returns null if the variable is not
/// defined by a "phi" node.
/// </summary>
/// <param name="variable"></param>
/// <returns></returns>
public Join/*?*/ GetDefiningJoinFor(INamedEntity variable) {
Contract.Requires(variable != null);
return this.definingJoinForSSAVariable[(uint)variable.Name.UniqueKey];
}
/// <summary>
/// Computes an inclusive numerical interval that contains the runtime value of the given expression. If no such interval can be found, the result is null.
/// </summary>
/// <param name="expression">The expression for which a containing interval is desired.</param>
/// <param name="block">A block providing the context for the interval. The entry contraints of the block are used to narrow the interval if possible.</param>
public Interval/*?*/ GetIntervalFor(Instruction expression, AiBasicBlock<Instruction> block) {
Contract.Requires(expression != null);
Contract.Requires(block != null);
var interval = block.IntervalForExpression[expression];
if (interval == this.dummyInterval) return null;
if (interval == null) {
block.IntervalForExpression[expression] = this.dummyInterval;
interval = Interval.TryToGetAsInterval(expression, block, null, null, this);
block.IntervalForExpression[expression] = interval??this.dummyInterval;
}
return interval;
}
/// <summary>
/// Returns true if the given expression is the value of a variable that is updated (inside of a loop) with a value that depends on the value of the variable in a an earlier iteration of the loop.
/// </summary>
internal bool IsRecursive(Instruction expression) {
Contract.Requires(expression != null);
var tag = this.recursiveExpressions[expression];
if (tag == 0) {
tag = 1;
var operand1 = expression.Operand1 as Instruction;
if (operand1 != null) {
if (this.IsRecursive(operand1))
tag = 2;
else {
var operand2 = expression.Operand2 as Instruction;
if (operand2 != null) {
if (this.IsRecursive(operand2)) tag = 2;
} else {
var operand2toN = expression.Operand2 as Instruction[];
if (operand2toN != null) {
for (int i = 0, n = operand2toN.Length; i < n; i++) {
var operandi = operand2toN[i];
Contract.Assume(operandi != null);
if (this.IsRecursive(operandi)) {
tag = 2;
break;
}
}
}
}
}
}
this.recursiveExpressions[expression] = tag;
}
return tag == 2;
}
/// <summary>
/// Uses the SAT solver, if supplied, to check if the given Boolean expression is true in the context of the given block.
/// Since this problem is not decidable, the solver may not be able to return an answer, in which case the return result is null
/// rather than false or true. Likewise, if no solver is available, the result is null.
/// </summary>
public bool? CheckIfExpressionIsTrue(Instruction expression, AiBasicBlock<Instruction> block) {
Contract.Requires(expression != null);
Contract.Requires(block != null);
var satSolverHelper = this.satSolverHelper;
if (satSolverHelper == null) return null;
var context = block.SatSolverContext;
if (context == null) {
block.SatSolverContext = context = satSolverHelper.SatSolver.GetNewContext();
Contract.Assume(context != null);
var constraintsAtEntry = satSolverHelper.GetSolverExpressionFor(block.ConstraintsAtEntry);
if (constraintsAtEntry != null) context.Add(constraintsAtEntry);
}
var solverExpression = this.satSolverHelper.GetSolverExpressionFor(expression, block.ConstraintsAtEntry);
context.MakeCheckPoint();
if (!this.IsRecursive(expression))
satSolverHelper.AddPhiNodeConstraints(expression, context);
//context.MakeCheckPoint();
context.Add(solverExpression);
var result = context.Check();
context.RestoreCheckPoint();
if (result != null && !result.Value) {
//context.RestoreCheckPoint();
return false; //The expression is never satisfied, so it is known to be false.
}
context.MakeCheckPoint();
if (!this.IsRecursive(expression))
satSolverHelper.AddPhiNodeConstraints(expression, context);
context.AddInverse(solverExpression);
result = context.Check();
context.RestoreCheckPoint();
//context.RestoreCheckPoint();
if (result != null && !result.Value) return true; //The inverse expression is never satisfied, so the expression is known to be true.
return null;
}
/// <summary>
/// Associates the given expression with a canonical version that will always evaluate to the same value as the given expression.
/// </summary>
/// <param name="expression"></param>
/// <param name="canonicalExpression"></param>
internal void SetCanonicalExpressionFor(Instruction expression, Instruction canonicalExpression) {
Contract.Requires(expression != null);
Contract.Requires(canonicalExpression != null);
this.expressionForExpression[expression] = canonicalExpression;
}
/// <summary>
/// Associates the given SSA variable with the compile time constant that is always the value of the right side of the single assignment to this variable.
/// </summary>
public void SetCompileTimeConstantValueFor(INamedEntity variable, IMetadataConstant compileTimeConstant) {
Contract.Requires(variable != null);
Contract.Requires(compileTimeConstant != null);
this.compileTimeConstantForSSAVariable[(uint)variable.Name.UniqueKey] = compileTimeConstant;
}
/// <summary>
/// Associates the given expression with a compile time constant value that is always its result when evaluated at runtime.
/// </summary>
internal void SetCompileTimeConstantValueFor(Instruction expression, IMetadataConstant compileTimeConstant) {
Contract.Requires(expression != null);
Contract.Requires(compileTimeConstant != null);
this.compileTimeConstantValueForExpression[expression] = compileTimeConstant;
}
/// <summary>
/// Keeps track of the block in which a "phi" node expression is defined. This is useful because the entry contraints of this block might provide
/// additional information about the expression.
/// </summary>
internal void SetDefininingBlockFor(Instruction expression, AiBasicBlock<Instruction> block) {
Contract.Requires(expression != null);
Contract.Requires(block != null);
this.definingBlockForExpression[expression] = block;
}
/// <summary>
/// Associates the given SSA variable with the expression (expected to be canonicalized) that is the right hand side of the single assignment to this variable.
/// </summary>
internal void SetDefininingExpressionFor(INamedEntity variable, Instruction expression) {
Contract.Requires(variable != null);
Contract.Requires(expression != null);
this.definingExpressionForSSAVariable[(uint)variable.Name.UniqueKey] = expression;
}
/// <summary>
/// Associates the given SSA variable with the Join information of the "phi" node that that is the right hand side of the single assignment to this variable.
/// </summary>
internal void SetDefininingJoinFor(INamedEntity variable, Join join) {
Contract.Requires(variable != null);
Contract.Requires(join != null);
this.definingJoinForSSAVariable[(uint)variable.Name.UniqueKey] = join;
}
/// <summary>
/// Records that the given expression is the value of a variable that is updated (inside of a loop) with a value that depends on the value of the variable in a an earlier iteration of the loop.
/// </summary>
internal void SetIsRecursive(Instruction expression) {
Contract.Requires(expression != null);
this.recursiveExpressions[expression] = 2;
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All Rights Reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
// ==--==
// Warning: Automatically generated file. DO NOT EDIT
// Generated at
using System.Reflection;
[assembly: AssemblyVersion("1.0.13.0")]
[assembly: AssemblyFileVersion("1.0.13.0")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyTrademark("Microsoft")]
[assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyProduct("CCI")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif

Двоичные данные
Metadata/Sources/Common/InterimKey.snk Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2596EFB0-87AE-42CE-89EB-84F35D6350D2}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.Analysis</RootNamespace>
<AssemblyName>Microsoft.Cci.Analysis.ControlAndDataFlowGraph</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions>
</CodeContractsExtraAnalysisOptions>
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>2</CodeContractsAnalysisWarningLevel>
<DocumentationFile>bin\Debug\Microsoft.Cci.Analysis.ControlAndDataFlowGraph.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Microsoft.Cci.Analysis.ControlAndDataFlowGraph.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\Version.cs">
<Link>Build\Version.cs</Link>
</Compile>
<Compile Include="ControlFlowInferencer.cs" />
<Compile Include="ControlFlowQueries.cs" />
<Compile Include="DataFlowInferencer.cs" />
<Compile Include="Graph.cs" />
<Compile Include="HandlerInferencer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeInferencer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataHelper\MetadataHelper.csproj">
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
<Name>MetadataHelper</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\SourceModel\SourceModel.csproj">
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
<Name>SourceModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,323 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Analysis {
internal class ControlFlowInferencer<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.BasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
private ControlFlowInferencer(IMetadataHost host, IMethodBody methodBody, ILocalScopeProvider/*?*/ localScopeProvider = null) {
Contract.Requires(host != null);
Contract.Requires(methodBody != null);
this.platformType = host.PlatformType;
this.internFactory = host.InternFactory;
this.methodBody = methodBody;
this.localScopeProvider = localScopeProvider;
int size = 1024;
var ops = methodBody.Operations as ICollection<IOperation>;
if (ops != null) size = ops.Count;
Hashtable<BasicBlock> blockFor = new Hashtable<BasicBlock>((uint)size);
List<BasicBlock> allBlocks = new List<BasicBlock>(size);
List<BasicBlock> rootBlocks = new List<BasicBlock>(1+(int)IteratorHelper.EnumerableCount(methodBody.OperationExceptionInformation));
this.successorEdges = new List<BasicBlock>(size);
this.cdfg = new ControlAndDataFlowGraph<BasicBlock, Instruction>(methodBody, this.successorEdges, allBlocks, rootBlocks, blockFor);
this.instructions = new List<Instruction>(size);
this.blocksThatTarget = new MultiHashtable<BasicBlock>((uint)size);
}
IPlatformType platformType;
IInternFactory internFactory;
IMethodBody methodBody;
ILocalScopeProvider/*?*/ localScopeProvider;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
List<BasicBlock> successorEdges;
List<Instruction> instructions;
MultiHashtable<BasicBlock> blocksThatTarget;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.platformType != null);
Contract.Invariant(this.internFactory != null);
Contract.Invariant(this.methodBody != null);
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.successorEdges != null);
Contract.Invariant(this.instructions != null);
Contract.Invariant(this.blocksThatTarget != null);
}
/// <summary>
///
/// </summary>
internal static ControlAndDataFlowGraph<BasicBlock, Instruction> SetupControlFlow(IMetadataHost host, IMethodBody methodBody, ILocalScopeProvider/*?*/ localScopeProvider = null) {
Contract.Requires(host != null);
Contract.Requires(methodBody != null);
Contract.Ensures(Contract.Result<ControlAndDataFlowGraph<BasicBlock, Instruction>>() != null);
var inferencer = new ControlFlowInferencer<BasicBlock, Instruction>(host, methodBody, localScopeProvider);
return inferencer.CreateBlocksAndEdges();
}
private ControlAndDataFlowGraph<BasicBlock, Instruction> CreateBlocksAndEdges() {
Contract.Ensures(Contract.Result<ControlAndDataFlowGraph<BasicBlock, Instruction>>() != null);
var firstBlock = new BasicBlock();
this.cdfg.BlockFor[0] = firstBlock;
this.cdfg.RootBlocks.Add(firstBlock);
this.CreateBlocksForLocalScopes();
this.CreateBlocksForBranchTargetsAndFallthroughs();
this.CreateBlocksForExceptionHandlers();
this.CreateSuccessorEdges(firstBlock);
this.successorEdges.TrimExcess();
this.instructions.TrimExcess();
this.cdfg.AllBlocks.TrimExcess();
this.cdfg.RootBlocks.TrimExcess();
return this.cdfg;
}
private void CreateBlocksForLocalScopes() {
if (this.localScopeProvider == null) return;
foreach (var scope in this.localScopeProvider.GetLocalScopes(this.methodBody)) {
Contract.Assume(scope != null);
this.CreateBlock(scope.Offset);
this.CreateBlock(scope.Offset+scope.Length);
}
}
private void CreateBlocksForBranchTargetsAndFallthroughs() {
bool lastInstructionWasBranch = false;
foreach (var ilOperation in this.methodBody.Operations) {
if (lastInstructionWasBranch) {
this.CreateBlock(ilOperation.Offset);
lastInstructionWasBranch = false;
}
switch (ilOperation.OperationCode) {
case OperationCode.Beq:
case OperationCode.Beq_S:
case OperationCode.Bge:
case OperationCode.Bge_S:
case OperationCode.Bge_Un:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble:
case OperationCode.Ble_S:
case OperationCode.Ble_Un:
case OperationCode.Ble_Un_S:
case OperationCode.Blt:
case OperationCode.Blt_S:
case OperationCode.Blt_Un:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
case OperationCode.Br:
case OperationCode.Br_S:
case OperationCode.Brfalse:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue:
case OperationCode.Brtrue_S:
case OperationCode.Leave:
case OperationCode.Leave_S:
Contract.Assume(ilOperation.Value is uint); //This is an informally specified property of the Metadata model.
this.CreateBlock((uint)ilOperation.Value);
lastInstructionWasBranch = true;
break;
case OperationCode.Ret:
case OperationCode.Throw:
case OperationCode.Jmp:
//The code following these instructions will be dead unless its a branch target, but we may as well end the basic block with the transfer.
lastInstructionWasBranch = true;
break;
case OperationCode.Switch: {
Contract.Assume(ilOperation.Value is uint[]); //This is an informally specified property of the Metadata model.
uint[] branches = (uint[])ilOperation.Value;
foreach (uint targetAddress in branches)
this.CreateBlock(targetAddress);
}
lastInstructionWasBranch = true;
break;
default:
break;
}
}
}
private void CreateBlocksForExceptionHandlers() {
foreach (IOperationExceptionInformation exinfo in this.methodBody.OperationExceptionInformation) {
this.CreateBlock(exinfo.TryStartOffset);
var block = CreateBlock(exinfo.HandlerStartOffset);
this.cdfg.RootBlocks.Add(block);
if (exinfo.HandlerKind == HandlerKind.Filter) {
block = this.CreateBlock(exinfo.FilterDecisionStartOffset);
this.cdfg.RootBlocks.Add(block);
}
this.CreateBlock(exinfo.HandlerEndOffset);
}
}
private BasicBlock CreateBlock(uint targetAddress) {
var result = this.cdfg.BlockFor[targetAddress];
if (result == null) {
result = new BasicBlock() { Offset = targetAddress };
this.cdfg.BlockFor[targetAddress] = result;
}
return result;
}
private void CreateSuccessorEdges(BasicBlock currentBlock) {
Contract.Requires(currentBlock != null);
this.cdfg.AllBlocks.Add(currentBlock);
int startingEdge = 0;
int startingInstruction = 0;
bool lastInstructionWasUnconditionalTransfer = false;
foreach (var ilOperation in this.methodBody.Operations) {
Contract.Assert(ilOperation != null); //This is formally specified in the Metadata model, but the checker does not yet understand it well enough to prove this.
Contract.Assume(startingInstruction <= instructions.Count); //due to the limitations of the contract language and checker
Contract.Assume(startingEdge <= successorEdges.Count); //due to the limitations of the contract language and checker
var newBlock = this.cdfg.BlockFor.Find(ilOperation.Offset);
if (newBlock != null && currentBlock != newBlock) {
this.cdfg.AllBlocks.Add(newBlock);
currentBlock.Instructions = new Sublist<Instruction>(instructions, startingInstruction, instructions.Count-startingInstruction);
if (!lastInstructionWasUnconditionalTransfer)
this.AddToSuccessorListIfNotAlreadyInIt(successorEdges, startingEdge, newBlock, currentBlock);
currentBlock.firstSuccessorEdge = startingEdge;
currentBlock.successorCount = successorEdges.Count-startingEdge;
startingEdge = successorEdges.Count;
startingInstruction = instructions.Count;
currentBlock = newBlock;
}
instructions.Add(this.GetInstruction(ilOperation, currentBlock, successorEdges, out lastInstructionWasUnconditionalTransfer));
}
if (instructions.Count > startingInstruction)
currentBlock.Instructions = new Sublist<Instruction>(instructions, startingInstruction, instructions.Count-startingInstruction);
if (successorEdges.Count > startingEdge) {
currentBlock.firstSuccessorEdge = startingEdge;
currentBlock.successorCount = successorEdges.Count-startingEdge;
}
}
private void AddToSuccessorListIfNotAlreadyInIt(List<BasicBlock> edges, int startingEdge, BasicBlock target, BasicBlock current) {
Contract.Requires(edges != null);
Contract.Requires(startingEdge >= 0);
Contract.Requires(target != null);
Contract.Requires(current != null);
Contract.Ensures(Contract.OldValue(edges.Count) <= edges.Count);
for (int i = startingEdge, n = edges.Count; i < n; i++) {
if (edges[i] == target) return;
}
edges.Add(target);
this.blocksThatTarget.Add(target.Offset, current);
}
private Instruction GetInstruction(IOperation ilOperation, BasicBlock currentBlock, List<BasicBlock> edges, out bool isUnconditionalTransfer) {
Contract.Requires(ilOperation != null);
Contract.Requires(currentBlock != null);
Contract.Requires(edges != null);
isUnconditionalTransfer = false;
var instruction = new Instruction() { Operation = ilOperation };
switch (ilOperation.OperationCode) {
case OperationCode.Beq:
case OperationCode.Beq_S:
case OperationCode.Bge:
case OperationCode.Bge_S:
case OperationCode.Bge_Un:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble:
case OperationCode.Ble_S:
case OperationCode.Ble_Un:
case OperationCode.Ble_Un_S:
case OperationCode.Blt:
case OperationCode.Blt_S:
case OperationCode.Blt_Un:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
Contract.Assume(ilOperation.Value is uint); //This is an informally specified property of the Metadata model.
var targetOffset = (uint)ilOperation.Value;
this.blocksThatTarget.Add(targetOffset, currentBlock);
edges.Add(this.cdfg.BlockFor[targetOffset]);
break;
case OperationCode.Br:
case OperationCode.Br_S:
case OperationCode.Leave:
case OperationCode.Leave_S:
Contract.Assume(ilOperation.Value is uint); //This is an informally specified property of the Metadata model.
targetOffset = (uint)ilOperation.Value;
this.blocksThatTarget.Add(targetOffset, currentBlock);
edges.Add(this.cdfg.BlockFor[targetOffset]);
isUnconditionalTransfer = true;
break;
case OperationCode.Brfalse:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue:
case OperationCode.Brtrue_S:
Contract.Assume(ilOperation.Value is uint); //This is an informally specified property of the Metadata model.
targetOffset = (uint)ilOperation.Value;
this.blocksThatTarget.Add(targetOffset, currentBlock);
edges.Add(this.cdfg.BlockFor[targetOffset]);
break;
case OperationCode.Endfilter:
case OperationCode.Endfinally:
case OperationCode.Jmp:
case OperationCode.Ret:
case OperationCode.Rethrow:
case OperationCode.Throw:
isUnconditionalTransfer = true;
break;
case OperationCode.Switch:
this.AddEdgesForSwitch(ilOperation, currentBlock, edges, instruction);
break;
}
return instruction;
}
private void AddEdgesForSwitch(IOperation ilOperation, BasicBlock currentBlock, List<BasicBlock> edges, Instruction instruction) {
Contract.Requires(ilOperation != null);
Contract.Requires(currentBlock != null);
Contract.Requires(ilOperation.OperationCode == OperationCode.Switch);
Contract.Requires(edges != null);
Contract.Requires(instruction != null);
Contract.Assume(ilOperation.Value is uint[]); //This is an informally specified property of the Metadata model.
uint[] branches = (uint[])ilOperation.Value;
SetOfObjects currentSuccesors = new SetOfObjects((uint)branches.Length);
foreach (uint targetAddress in branches) {
this.blocksThatTarget.Add(targetAddress, currentBlock);
var target = this.cdfg.BlockFor[targetAddress];
Contract.Assume(target != null); //All branch targets must have blocks, but we can't put that in a contract that satisfies the checker.
if (currentSuccesors.Contains(target)) continue;
currentSuccesors.Add(target);
edges.Add(target);
}
}
}
}

Просмотреть файл

@ -0,0 +1,368 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers.
/// </summary>
public class ControlGraphQueries<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.EnhancedBasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
/// Presents information derived from a simple control flow graph. For example, traversal orders, predecessors, dominators and dominance frontiers.
/// </summary>
/// <param name="controlFlowGraph">The simple control flow graph from which to derive the information.</param>
public ControlGraphQueries(ControlAndDataFlowGraph<BasicBlock, Instruction> controlFlowGraph) {
Contract.Requires(controlFlowGraph != null);
this.cfg = controlFlowGraph;
}
ControlAndDataFlowGraph<BasicBlock, Instruction> cfg;
BasicBlock[] preOrder;
BasicBlock[] postOrder;
List<BasicBlock> predecessorEdges;
List<BasicBlock> dominanceFrontier;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.cfg != null);
}
/// <summary>
/// Contains the same nodes as the AllBlocks property of the control flow graph, but in the order they will be visited by a depth first, post order traversal of successor nodes.
/// </summary>
public BasicBlock[] BlocksInPostorder {
get {
Contract.Ensures(Contract.Result<BasicBlock[]>() != null);
if (this.postOrder == null)
this.SetupTraversalOrders();
return this.postOrder;
}
}
/// <summary>
/// Contains the same nodes as the AllBlocks property of the control flow graph, but in the order they will be visited by a depth first, pre order traversal of successor nodes.
/// </summary>
public BasicBlock[] BlocksInPreorder {
get {
Contract.Ensures(Contract.Result<BasicBlock[]>() != null);
if (this.preOrder == null)
this.SetupTraversalOrders();
return this.preOrder;
}
}
/// <summary>
/// Returns zero or more nodes that are reachable from the given basic block, but are not dominated by the given basic block.
/// </summary>
public Sublist<BasicBlock> DominanceFrontierFor(BasicBlock basicBlock) {
Contract.Requires(basicBlock != null);
if (this.dominanceFrontier == null)
this.SetupDominanceFrontier();
if (basicBlock.firstDominanceFrontierNode+basicBlock.dominanceFrontierCount > this.dominanceFrontier.Count)
throw new InvalidOperationException(); //can only happen if the basic block does not belong to this graph.
Contract.Assume(basicBlock.firstDominanceFrontierNode >= 0);
Contract.Assume(basicBlock.dominanceFrontierCount >= 0);
return new Sublist<BasicBlock>(this.dominanceFrontier, basicBlock.firstDominanceFrontierNode, basicBlock.dominanceFrontierCount);
}
/// <summary>
/// Returns true if the first block dominates the second block. That is, if all control paths from the applicable root node
/// lead to the second block only via the first block.
/// </summary>
public bool Dominates(BasicBlock block1, BasicBlock block2) {
Contract.Requires(block1 != null);
Contract.Requires(block2 != null);
if (block1 == block2) return true;
var block2dominator = ImmediateDominator(block2);
while (true) {
if (block1 == block2dominator) return true;
if (block2 == block2dominator) return false;
block2 = block2dominator;
block2dominator = ImmediateDominator(block2);
}
}
/// <summary>
/// Returns the last block through which all control flows from a root must pass in order to reach the given block.
/// This block can be a root, however, it will not be the given block, except when the given block is a root.
/// </summary>
public BasicBlock ImmediateDominator(BasicBlock basicBlock) {
Contract.Requires(basicBlock != null);
Contract.Ensures(Contract.Result<BasicBlock>() != null);
if (!this.immediateDominatorsAreInitialized)
this.SetupImmediateDominators();
Contract.Assume(basicBlock.immediateDominator is BasicBlock);
return (BasicBlock)basicBlock.immediateDominator;
}
bool immediateDominatorsAreInitialized;
/// <summary>
/// All basic blocks from which control can flow to the given basic block.
/// </summary>
public Sublist<BasicBlock> PredeccessorsFor(BasicBlock basicBlock) {
Contract.Requires(basicBlock != null);
if (this.predecessorEdges == null)
this.SetupPredecessorEdges();
if (basicBlock.firstPredecessorEdge+basicBlock.predeccessorCount > this.predecessorEdges.Count)
throw new InvalidOperationException(); //can only happen if the basic block does not belong to this graph.
Contract.Assume(basicBlock.firstPredecessorEdge >= 0);
Contract.Assume(basicBlock.predeccessorCount >= 0);
return new Sublist<BasicBlock>(this.predecessorEdges, basicBlock.firstPredecessorEdge, basicBlock.predeccessorCount);
}
private void SetupDominanceFrontier() {
Contract.Ensures(this.dominanceFrontier != null);
MultiHashtable<BasicBlock> frontierFor = new MultiHashtable<BasicBlock>();
if (!this.immediateDominatorsAreInitialized)
this.SetupImmediateDominators();
var predecessorEdges = this.predecessorEdges;
Contract.Assume(predecessorEdges != null);
var dominanceFrontier = this.dominanceFrontier = new List<BasicBlock>(this.cfg.AllBlocks.Count*2);
foreach (var block in this.cfg.AllBlocks) {
Contract.Assume(block != null);
var n = block.predeccessorCount;
if (n < 2) continue;
for (int i = 0; i < n; i++) {
Contract.Assume(block.firstPredecessorEdge+i >= 0);
Contract.Assume(block.firstPredecessorEdge+i < predecessorEdges.Count);
var pred = predecessorEdges[block.firstPredecessorEdge+i];
Contract.Assume(pred != null);
var a = pred;
while (true) {
if (a == block.immediateDominator) break; //Any node that dominates node a will also dominate node block and hence block will not be in its dominance frontier.
frontierFor.Add(a.Offset, block);
if (a == a.immediateDominator) break; //Since there are multiple roots, block can be its own immediate dominator while still having predecessors.
a = (BasicBlock)a.immediateDominator;
Contract.Assume(a != null);
}
}
}
foreach (var block in this.cfg.AllBlocks) {
Contract.Assume(block != null);
block.firstDominanceFrontierNode = dominanceFrontier.Count;
foreach (var frontierNode in frontierFor.GetValuesFor(block.Offset)) {
dominanceFrontier.Add(frontierNode);
}
block.dominanceFrontierCount = dominanceFrontier.Count-block.firstDominanceFrontierNode;
}
dominanceFrontier.TrimExcess();
}
private void SetupImmediateDominators() {
Contract.Ensures(this.immediateDominatorsAreInitialized);
//Note this is an adaptation of the algorithm in Cooper, Keith D.; Harvey, Timothy J.; and Kennedy, Ken (2001). A Simple, Fast Dominance Algorithm
//The big difference is that we deal with multiple roots at the same time.
if (this.postOrder == null)
this.SetupTraversalOrders();
var postOrder = this.postOrder;
if (this.predecessorEdges == null)
this.SetupPredecessorEdges();
foreach (var rootBlock in this.cfg.RootBlocks) {
Contract.Assume(rootBlock != null);
rootBlock.immediateDominator = rootBlock;
}
var predecessorEdges = this.predecessorEdges;
var n = postOrder.Length;
var changed = true;
while (changed) {
changed = false;
for (int i = n-1; i >= 0; i--) { //We iterate in reverse post order so that a block always has its immediateDominator field filled in before we get to any of its successors.
var b = postOrder[i];
Contract.Assume(b != null);
if (b.immediateDominator == b) continue;
if (b.predeccessorCount == 0) {
b.immediateDominator = b;
continue;
}
Contract.Assume(b.firstPredecessorEdge >= 0);
Contract.Assume(b.firstPredecessorEdge < predecessorEdges.Count);
var predecessors = new HashSet<BasicBlock>();
for (int j = 0, m = b.predeccessorCount; j < m; j++) {
predecessors.Add(predecessorEdges[b.firstPredecessorEdge + j]);
}
// newIDom <- first (processed) predecessor of b
BasicBlock newIDom = null;
foreach (var p in predecessors) {
if (p.immediateDominator != null) {
newIDom = p;
break;
}
}
Contract.Assume(newIDom != null);
predecessors.Remove(newIDom);
foreach (var predecessor in predecessors) {
Contract.Assume(predecessor != null);
if (predecessor.immediateDominator != null) {
var intersection = Intersect(predecessor, newIDom);
if (intersection != null) {
newIDom = intersection;
} else {
//This can happen when predecessor and newIDom are only reachable via distinct roots.
//We now have two distinct paths from a root to b. This means b is its own dominator.
b.immediateDominator = newIDom = b;
break;
}
}
}
if (b.immediateDominator != newIDom) {
b.immediateDominator = newIDom;
changed = true;
}
}
}
this.immediateDominatorsAreInitialized = true;
}
private BasicBlock/*?*/ Intersect(BasicBlock block1, BasicBlock block2) {
Contract.Requires(block1 != null);
Contract.Requires(block2 != null);
while (block1 != block2) {
while (block1.postOrderNumber < block2.postOrderNumber) {
var block1dominator = block1.immediateDominator;
if (block1dominator == block1) return null; //block2 is its own dominator, which means it has no predecessors
block1 = (BasicBlock)block1dominator; //The block with the smaller post order number cannot be a predecessor of the other block.
if (block1 == null) return null;
}
while (block2.postOrderNumber < block1.postOrderNumber) {
var block2dominator = block2.immediateDominator;
if (block2dominator == block2) return null; //block2 is its own dominator, which means it has no predecessors
block2 = (BasicBlock)block2dominator; //The block with the smaller post order number cannot be a predecessor of the other block.
if (block2 == null) return null;
}
}
return block1;
}
private void SetupPredecessorEdges() {
Contract.Ensures(this.predecessorEdges != null);
var predecessorEdges = this.predecessorEdges = new List<BasicBlock>(this.cfg.SuccessorEdges.Count);
MultiHashtable<BasicBlock> blocksThatTarget = new MultiHashtable<BasicBlock>();
foreach (var block in this.cfg.AllBlocks) {
Contract.Assume(block != null);
foreach (var successor in this.cfg.SuccessorsFor(block)) {
blocksThatTarget.Add(successor.Offset, block);
}
}
foreach (var block in this.cfg.AllBlocks) {
Contract.Assume(block != null);
block.firstPredecessorEdge = predecessorEdges.Count;
foreach (var predecessor in blocksThatTarget.GetValuesFor(block.Offset)) {
predecessorEdges.Add(predecessor);
}
block.predeccessorCount = predecessorEdges.Count-block.firstPredecessorEdge;
}
}
private void SetupTraversalOrders() {
Contract.Ensures(this.postOrder != null);
Contract.Ensures(this.preOrder != null);
var n = cfg.AllBlocks.Count;
this.postOrder = new BasicBlock[n];
this.preOrder = new BasicBlock[n];
uint preorderCounter = 0;
uint postorderCounter = 0;
var alreadyTraversed = new SetOfObjects((uint)n);
foreach (var rootBlock in cfg.RootBlocks) {
Contract.Assume(rootBlock != null);
this.SetupTraversalOrders(rootBlock, alreadyTraversed, ref preorderCounter, ref postorderCounter);
}
Contract.Assume(preorderCounter == postorderCounter);
if (preorderCounter != n) {
//Add unreachable blocks to traversal order, treating them as if they were roots.
foreach (var block in cfg.AllBlocks) {
Contract.Assume(block != null);
if (alreadyTraversed.Contains(block)) continue;
this.SetupTraversalOrders(block, alreadyTraversed, ref preorderCounter, ref postorderCounter);
}
}
Contract.Assume(this.postOrder != null);
Contract.Assume(this.preOrder != null);
}
private void SetupTraversalOrders(BasicBlock root, SetOfObjects alreadyTraversed, ref uint preOrderIndex, ref uint postOrderIndex) {
Contract.Requires(root != null);
Contract.Requires(alreadyTraversed != null);
if (!alreadyTraversed.Add(root)) return;
Contract.Assume(this.preOrder != null);
Contract.Assume(this.postOrder != null);
Contract.Assume(preOrderIndex < this.preOrder.Length);
this.preOrder[preOrderIndex++] = root;
foreach (var successor in this.cfg.SuccessorsFor(root)) {
Contract.Assume(successor != null);
this.SetupTraversalOrders(successor, alreadyTraversed, ref preOrderIndex, ref postOrderIndex);
}
Contract.Assume(this.postOrder != null);
Contract.Assume(postOrderIndex < this.postOrder.Length);
root.postOrderNumber = postOrderIndex;
this.postOrder[postOrderIndex++] = root;
}
}
/// <summary>
/// A basic block with additional fields to help compute things such as predecessor edges, dominance and dominance frontiers.
/// </summary>
/// <typeparam name="Instruction"></typeparam>
public class EnhancedBasicBlock<Instruction> : BasicBlock<Instruction> where Instruction : Microsoft.Cci.Analysis.Instruction {
/// <summary>
/// The first block in a list of blocks that are reachable from, but not dominated by this block.
/// </summary>
internal int firstDominanceFrontierNode;
/// <summary>
/// The number of blocks that are reachable from, but not dominated by this block.
/// </summary>
internal int dominanceFrontierCount;
/// <summary>
/// The first edge that enters this block. The edges are a contiguous sublist of the the PredeccessorEdges list of the ControlAndDataFlowGraph that contains this block.
/// </summary>
internal int firstPredecessorEdge;
/// <summary>
/// The number of edges that enter this block. The edges are a contiguous sublist of the the PredeccessorEdges list of the ControlAndDataFlowGraph that contains this block.
/// </summary>
internal int predeccessorCount;
/// <summary>
/// The block through which all control flows from a root must pass in order to reach this block. Can be a root. Will not be the block itself, except when the block is a root.
/// </summary>
internal EnhancedBasicBlock<Instruction> immediateDominator;
/// <summary>
/// The position of the node in a depth first, post order traversal of successor edges.
/// </summary>
internal uint postOrderNumber;
}
}

Просмотреть файл

@ -0,0 +1,565 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Analysis {
internal class DataFlowInferencer<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.BasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
private DataFlowInferencer(IMetadataHost host, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg) {
Contract.Requires(host != null);
Contract.Requires(cdfg != null);
var numberOfBlocks = cdfg.BlockFor.Count;
this.platformType = host.PlatformType;
this.cdfg = cdfg;
this.operandStackSetupInstructions = new List<Instruction>(cdfg.MethodBody.MaxStack);
this.stack = new Stack<Instruction>(cdfg.MethodBody.MaxStack);
this.blocksToVisit = new Queue<BasicBlock>((int)numberOfBlocks);
this.blocksAlreadyVisited = new SetOfObjects(numberOfBlocks); ;
this.internFactory = host.InternFactory;
}
IPlatformType platformType;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
Stack<Instruction> stack;
List<Instruction> operandStackSetupInstructions;
Queue<BasicBlock> blocksToVisit;
SetOfObjects blocksAlreadyVisited;
IInternFactory internFactory;
bool codeIsUnreachable;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.platformType != null);
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.stack != null);
Contract.Invariant(this.operandStackSetupInstructions != null);
Contract.Invariant(this.blocksToVisit != null);
Contract.Invariant(this.blocksAlreadyVisited != null);
Contract.Invariant(this.internFactory != null);
}
/// <summary>
///
/// </summary>
internal static void SetupDataFlow(IMetadataHost host, IMethodBody methodBody, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg) {
Contract.Requires(host != null);
Contract.Requires(methodBody != null);
Contract.Requires(cdfg != null);
var dataFlowInferencer = new DataFlowInferencer<BasicBlock, Instruction>(host, cdfg);
dataFlowInferencer.SetupDataFlowFor(methodBody);
}
private void SetupDataFlowFor(IMethodBody methodBody) {
Contract.Requires(methodBody != null);
//If this is a dummy body, do nothing.
if (this.cdfg.AllBlocks.Count == 1 && this.cdfg.AllBlocks[0] != null && this.cdfg.AllBlocks[0].Instructions.Count <= 1) return;
this.AddStackSetupForExceptionHandlers(methodBody);
foreach (var root in this.cdfg.RootBlocks) {
this.blocksToVisit.Enqueue(root);
while (this.blocksToVisit.Count != 0)
this.DequeueBlockAndSetupDataFlow();
}
//At this point, all reachable code blocks have had their data flow inferred. Now look for unreachable blocks.
this.codeIsUnreachable = true; //unreachable code might not satisfy invariants.
foreach (var block in this.cdfg.AllBlocks) {
if (this.blocksAlreadyVisited.Contains(block)) continue;
blocksToVisit.Enqueue(block);
while (blocksToVisit.Count != 0)
this.DequeueBlockAndSetupDataFlow();
}
this.operandStackSetupInstructions.TrimExcess();
}
private void AddStackSetupForExceptionHandlers(IMethodBody methodBody) {
Contract.Requires(methodBody != null);
foreach (var exinfo in methodBody.OperationExceptionInformation) {
Contract.Assert(exinfo != null); //The checker can't work out that all collection elements are non null, even though there is a contract to that effect
if (exinfo.HandlerKind == HandlerKind.Filter) {
var block = this.cdfg.BlockFor[exinfo.FilterDecisionStartOffset];
Contract.Assume(block != null); //All branch targets must have blocks, but we can't put that in a contract that satisfies the checker.
this.AddStackSetup(block, exinfo.ExceptionType);
block = this.cdfg.BlockFor[exinfo.HandlerStartOffset];
Contract.Assume(block != null); //All branch targets must have blocks, but we can't put that in a contract that satisfies the checker.
this.AddStackSetup(block, exinfo.ExceptionType);
} else if (exinfo.HandlerKind == HandlerKind.Catch) {
var block = this.cdfg.BlockFor[exinfo.HandlerStartOffset];
Contract.Assume(block != null); //All branch targets must have blocks, but we can't put that in a contract that satisfies the checker.
this.AddStackSetup(block, exinfo.ExceptionType);
}
}
}
private void AddStackSetup(BasicBlock block, ITypeReference operandType) {
Contract.Requires(block != null);
Contract.Requires(operandType != null);
this.operandStackSetupInstructions.Add(new Instruction() { Type = operandType });
block.OperandStack = new Sublist<Instruction>(this.operandStackSetupInstructions, this.operandStackSetupInstructions.Count-1, 1);
}
private void DequeueBlockAndSetupDataFlow() {
var block = this.blocksToVisit.Dequeue();
Contract.Assume(block != null); //this.blocksToVisit only has non null elements, but we can't put that in a contract that satisfies the checker
if (!this.blocksAlreadyVisited.Add(block)) return; //The same block can be added multiple times to the queue.
foreach (var instruction in block.OperandStack) {
Contract.Assume(instruction != null); //block.OperandStack only has non null elements, but we can't put that in a contract that satisfies the checker
this.stack.Push(instruction);
}
foreach (var instruction in block.Instructions) {
Contract.Assume(instruction != null); //block.Instructions only has non null elements, but we can't put that in a contract that satisfies the checker
this.SetupDataFlowFor(instruction);
}
foreach (var successor in this.cdfg.SuccessorsFor(block)) {
Contract.Assume(successor != null); //block.Successors only has non null elements, but we can't put that in a contract that satisfies the checker
this.SetupStackFor(successor);
if (blocksAlreadyVisited.Contains(successor)) continue;
blocksToVisit.Enqueue(successor); //The block might already be in the queue, but we can deal with this more efficiently by checking blocksAlreadyVisited when dequeueing.
}
this.stack.Clear();
}
private void SetupStackFor(BasicBlock successor) {
Contract.Requires(successor != null);
if (successor.OperandStack.Count == 0) {
int n = this.stack.Top;
if (n < 0) return;
int startingCount = this.operandStackSetupInstructions.Count;
for (int i = 0; i <= n; i++) {
var pushInstruction = this.stack.Peek(i);
this.operandStackSetupInstructions.Add(new Instruction() { Operand1 = pushInstruction });
}
successor.OperandStack = new Sublist<Instruction>(this.operandStackSetupInstructions, startingCount, operandStackSetupInstructions.Count-startingCount);
} else {
int n = this.stack.Top;
Contract.Assume(n == successor.OperandStack.Count-1); //This is an optimistic assumption. It should be true for any well formed PE file. We are content to crash given bad input.
for (int i = 0; i <= n; i++) {
var pushInstruction = this.stack.Peek(i);
var setupInstruction = successor.OperandStack[i];
if (setupInstruction.Operand2 == null)
setupInstruction.Operand2 = pushInstruction;
else {
var list = setupInstruction.Operand2 as List<Instruction>;
if (list == null) {
Contract.Assume(setupInstruction.Operand2 is Instruction);
list = new List<Instruction>(4);
list.Add((Instruction)setupInstruction.Operand2);
}
list.Add(pushInstruction);
}
}
}
}
private void SetupDataFlowFor(Instruction instruction) {
Contract.Requires(instruction != null);
switch (instruction.Operation.OperationCode) {
case OperationCode.Add:
case OperationCode.Add_Ovf:
case OperationCode.Add_Ovf_Un:
case OperationCode.And:
case OperationCode.Ceq:
case OperationCode.Cgt:
case OperationCode.Cgt_Un:
case OperationCode.Clt:
case OperationCode.Clt_Un:
case OperationCode.Div:
case OperationCode.Div_Un:
case OperationCode.Ldelema:
case OperationCode.Ldelem:
case OperationCode.Ldelem_I:
case OperationCode.Ldelem_I1:
case OperationCode.Ldelem_I2:
case OperationCode.Ldelem_I4:
case OperationCode.Ldelem_I8:
case OperationCode.Ldelem_R4:
case OperationCode.Ldelem_R8:
case OperationCode.Ldelem_Ref:
case OperationCode.Ldelem_U1:
case OperationCode.Ldelem_U2:
case OperationCode.Ldelem_U4:
case OperationCode.Mul:
case OperationCode.Mul_Ovf:
case OperationCode.Mul_Ovf_Un:
case OperationCode.Or:
case OperationCode.Rem:
case OperationCode.Rem_Un:
case OperationCode.Shl:
case OperationCode.Shr:
case OperationCode.Shr_Un:
case OperationCode.Sub:
case OperationCode.Sub_Ovf:
case OperationCode.Sub_Ovf_Un:
case OperationCode.Xor:
instruction.Operand2 = this.stack.Pop();
instruction.Operand1 = this.stack.Pop();
this.stack.Push(instruction);
break;
case OperationCode.Arglist:
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
case OperationCode.Ldsfld:
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
case OperationCode.Ldsflda:
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
case OperationCode.Ldftn:
case OperationCode.Ldc_I4:
case OperationCode.Ldc_I4_0:
case OperationCode.Ldc_I4_1:
case OperationCode.Ldc_I4_2:
case OperationCode.Ldc_I4_3:
case OperationCode.Ldc_I4_4:
case OperationCode.Ldc_I4_5:
case OperationCode.Ldc_I4_6:
case OperationCode.Ldc_I4_7:
case OperationCode.Ldc_I4_8:
case OperationCode.Ldc_I4_M1:
case OperationCode.Ldc_I4_S:
case OperationCode.Ldc_I8:
case OperationCode.Ldc_R4:
case OperationCode.Ldc_R8:
case OperationCode.Ldnull:
case OperationCode.Ldstr:
case OperationCode.Ldtoken:
case OperationCode.Sizeof:
this.stack.Push(instruction);
break;
case OperationCode.Array_Addr:
case OperationCode.Array_Get:
Contract.Assume(instruction.Operation.Value is IArrayTypeReference); //This is an informally specified property of the Metadata model.
InitializeArrayIndexerInstruction(instruction, this.stack, (IArrayTypeReference)instruction.Operation.Value);
break;
case OperationCode.Array_Create:
case OperationCode.Array_Create_WithLowerBound:
case OperationCode.Newarr:
InitializeArrayCreateInstruction(instruction, this.stack, instruction.Operation);
break;
case OperationCode.Array_Set:
Contract.Assume(instruction.Operation.Value is IArrayTypeReference); //This is an informally specified property of the Metadata model.
InitializeArraySetInstruction(instruction, this.stack, (IArrayTypeReference)instruction.Operation.Value);
break;
case OperationCode.Beq:
case OperationCode.Beq_S:
case OperationCode.Bge:
case OperationCode.Bge_S:
case OperationCode.Bge_Un:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble:
case OperationCode.Ble_S:
case OperationCode.Ble_Un:
case OperationCode.Ble_Un_S:
case OperationCode.Blt:
case OperationCode.Blt_S:
case OperationCode.Blt_Un:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
instruction.Operand2 = this.stack.Pop();
instruction.Operand1 = this.stack.Pop();
break;
case OperationCode.Box:
case OperationCode.Castclass:
case OperationCode.Ckfinite:
case OperationCode.Conv_I:
case OperationCode.Conv_I1:
case OperationCode.Conv_I2:
case OperationCode.Conv_I4:
case OperationCode.Conv_I8:
case OperationCode.Conv_Ovf_I:
case OperationCode.Conv_Ovf_I_Un:
case OperationCode.Conv_Ovf_I1:
case OperationCode.Conv_Ovf_I1_Un:
case OperationCode.Conv_Ovf_I2:
case OperationCode.Conv_Ovf_I2_Un:
case OperationCode.Conv_Ovf_I4:
case OperationCode.Conv_Ovf_I4_Un:
case OperationCode.Conv_Ovf_I8:
case OperationCode.Conv_Ovf_I8_Un:
case OperationCode.Conv_Ovf_U:
case OperationCode.Conv_Ovf_U_Un:
case OperationCode.Conv_Ovf_U1:
case OperationCode.Conv_Ovf_U1_Un:
case OperationCode.Conv_Ovf_U2:
case OperationCode.Conv_Ovf_U2_Un:
case OperationCode.Conv_Ovf_U4:
case OperationCode.Conv_Ovf_U4_Un:
case OperationCode.Conv_Ovf_U8:
case OperationCode.Conv_Ovf_U8_Un:
case OperationCode.Conv_R_Un:
case OperationCode.Conv_R4:
case OperationCode.Conv_R8:
case OperationCode.Conv_U:
case OperationCode.Conv_U1:
case OperationCode.Conv_U2:
case OperationCode.Conv_U4:
case OperationCode.Conv_U8:
case OperationCode.Isinst:
case OperationCode.Ldind_I:
case OperationCode.Ldind_I1:
case OperationCode.Ldind_I2:
case OperationCode.Ldind_I4:
case OperationCode.Ldind_I8:
case OperationCode.Ldind_R4:
case OperationCode.Ldind_R8:
case OperationCode.Ldind_Ref:
case OperationCode.Ldind_U1:
case OperationCode.Ldind_U2:
case OperationCode.Ldind_U4:
case OperationCode.Ldobj:
case OperationCode.Ldflda:
case OperationCode.Ldfld:
case OperationCode.Ldlen:
case OperationCode.Ldvirtftn:
case OperationCode.Localloc:
case OperationCode.Mkrefany:
case OperationCode.Neg:
case OperationCode.Not:
case OperationCode.Refanytype:
case OperationCode.Refanyval:
case OperationCode.Unbox:
case OperationCode.Unbox_Any:
instruction.Operand1 = this.stack.Pop();
this.stack.Push(instruction);
break;
case OperationCode.Brfalse:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue:
case OperationCode.Brtrue_S:
instruction.Operand1 = this.stack.Pop();
break;
case OperationCode.Call:
case OperationCode.Callvirt:
var signature = instruction.Operation.Value as ISignature;
Contract.Assume(signature != null); //This is an informally specified property of the Metadata model.
InitializeArgumentsAndPushReturnResult(instruction, this.stack, signature);
break;
case OperationCode.Calli:
var funcPointer = instruction.Operation.Value as IFunctionPointerTypeReference;
Contract.Assume(funcPointer != null); //This is an informally specified property of the Metadata model.
InitializeArgumentsAndPushReturnResult(instruction, this.stack, funcPointer);
break;
case OperationCode.Cpobj:
case OperationCode.Stfld:
case OperationCode.Stind_I:
case OperationCode.Stind_I1:
case OperationCode.Stind_I2:
case OperationCode.Stind_I4:
case OperationCode.Stind_I8:
case OperationCode.Stind_R4:
case OperationCode.Stind_R8:
case OperationCode.Stind_Ref:
case OperationCode.Stobj:
instruction.Operand2 = this.stack.Pop();
instruction.Operand1 = this.stack.Pop();
break;
case OperationCode.Cpblk:
case OperationCode.Initblk:
case OperationCode.Stelem:
case OperationCode.Stelem_I:
case OperationCode.Stelem_I1:
case OperationCode.Stelem_I2:
case OperationCode.Stelem_I4:
case OperationCode.Stelem_I8:
case OperationCode.Stelem_R4:
case OperationCode.Stelem_R8:
case OperationCode.Stelem_Ref:
var indexAndValue = new Instruction[2];
indexAndValue[1] = this.stack.Pop();
indexAndValue[0] = this.stack.Pop();
instruction.Operand2 = indexAndValue;
instruction.Operand1 = this.stack.Pop();
break;
case OperationCode.Dup:
var dupop = this.stack.Pop();
instruction.Operand1 = dupop;
this.stack.Push(instruction);
this.stack.Push(instruction);
break;
case OperationCode.Endfilter:
case OperationCode.Initobj:
case OperationCode.Pop:
case OperationCode.Starg:
case OperationCode.Starg_S:
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
case OperationCode.Stsfld:
case OperationCode.Throw:
case OperationCode.Switch:
instruction.Operand1 = this.stack.Pop();
break;
case OperationCode.Leave:
case OperationCode.Leave_S:
this.stack.Clear();
break;
case OperationCode.Newobj:
Contract.Assume(instruction.Operation.Value is ISignature); //This is an informally specified property of the Metadata model.
signature = (ISignature)instruction.Operation.Value;
var numArguments = (int)IteratorHelper.EnumerableCount(signature.Parameters);
if (numArguments > 0) {
if (numArguments > 1) {
numArguments--;
var arguments = new Instruction[numArguments];
instruction.Operand2 = arguments;
for (var i = numArguments-1; i >= 0; i--)
arguments[i] = stack.Pop();
}
instruction.Operand1 = stack.Pop();
}
this.stack.Push(instruction);
break;
case OperationCode.Ret:
if (this.codeIsUnreachable && this.stack.Top < 0) break;
if (this.cdfg.MethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void)
instruction.Operand1 = this.stack.Pop();
break;
}
}
private static void InitializeArgumentsAndPushReturnResult(Instruction instruction, Stack<Instruction> stack, ISignature signature) {
Contract.Requires(instruction != null);
Contract.Requires(stack != null);
Contract.Requires(signature != null);
var methodRef = signature as IMethodReference;
uint numArguments = IteratorHelper.EnumerableCount(signature.Parameters);
if (methodRef != null && methodRef.AcceptsExtraArguments) numArguments += IteratorHelper.EnumerableCount(methodRef.ExtraParameters);
if (!signature.IsStatic) numArguments++;
if (numArguments > 0) {
numArguments--;
if (numArguments > 0) {
var arguments = new Instruction[numArguments];
instruction.Operand2 = arguments;
for (var i = numArguments; i > 0; i--)
arguments[i-1] = stack.Pop();
}
instruction.Operand1 = stack.Pop();
}
if (signature.Type.TypeCode != PrimitiveTypeCode.Void)
stack.Push(instruction);
}
private static void InitializeArgumentsAndPushReturnResult(Instruction instruction, Stack<Instruction> stack, IFunctionPointerTypeReference funcPointer) {
Contract.Requires(instruction != null);
Contract.Requires(stack != null);
Contract.Requires(funcPointer != null);
instruction.Operand1 = stack.Pop(); //the function pointer
var numArguments = IteratorHelper.EnumerableCount(funcPointer.Parameters);
if (!funcPointer.IsStatic) numArguments++;
var arguments = new Instruction[numArguments];
instruction.Operand2 = arguments;
for (var i = numArguments; i > 0; i--)
arguments[i-1] = stack.Pop();
if (funcPointer.Type.TypeCode != PrimitiveTypeCode.Void)
stack.Push(instruction);
}
private static void InitializeArrayCreateInstruction(Instruction instruction, Stack<Instruction> stack, IOperation currentOperation) {
Contract.Requires(instruction != null);
Contract.Requires(stack != null);
Contract.Requires(currentOperation != null);
IArrayTypeReference arrayType = (IArrayTypeReference)currentOperation.Value;
Contract.Assume(arrayType != null); //This is an informally specified property of the Metadata model.
var rank = arrayType.Rank;
if (rank > 0) {
if (currentOperation.OperationCode == OperationCode.Array_Create_WithLowerBound) rank *= 2;
rank--;
if (rank > 0) {
var indices = new Instruction[rank];
instruction.Operand2 = indices;
for (var i = rank; i > 0; i--)
indices[i-1] = stack.Pop();
}
instruction.Operand1 = stack.Pop();
}
stack.Push(instruction);
}
private static void InitializeArrayIndexerInstruction(Instruction instruction, Stack<Instruction> stack, IArrayTypeReference arrayType) {
Contract.Requires(instruction != null);
Contract.Requires(stack != null);
Contract.Requires(arrayType != null);
var rank = arrayType.Rank;
var indices = new Instruction[rank];
instruction.Operand2 = indices;
for (var i = rank; i > 0; i--)
indices[i-1] = stack.Pop();
instruction.Operand1 = stack.Pop();
stack.Push(instruction);
}
private static void InitializeArraySetInstruction(Instruction instruction, Stack<Instruction> stack, IArrayTypeReference arrayType) {
Contract.Requires(instruction != null);
Contract.Requires(stack != null);
Contract.Requires(arrayType != null);
var rank = arrayType.Rank;
var indices = new Instruction[rank+1];
instruction.Operand2 = indices;
for (var i = rank+1; i > 0; i--)
indices[i-1] = stack.Pop();
instruction.Operand1 = stack.Pop();
}
}
}

Просмотреть файл

@ -0,0 +1,765 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Analysis {
/// <summary>
/// A set of basic blocks, each of which has a list of successor blocks and some other information.
/// Each block consists of a list of instructions, each of which can point to previous instructions that compute the operands it consumes.
/// </summary>
public class ControlAndDataFlowGraph<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.BasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
internal ControlAndDataFlowGraph(IMethodBody body, List<BasicBlock> successorEdges, List<BasicBlock> allBlocks, List<BasicBlock> rootBlocks, Hashtable<BasicBlock> blockFor) {
Contract.Requires(body != null);
Contract.Requires(successorEdges != null);
Contract.Requires(allBlocks != null);
Contract.Requires(rootBlocks != null);
Contract.Requires(blockFor != null);
this.methodBody = body;
this.successorEdges = successorEdges;
this.allBlocks = allBlocks;
this.rootBlocks = rootBlocks;
this.blockFor = blockFor;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.methodBody != null);
Contract.Invariant(this.successorEdges != null);
Contract.Invariant(this.allBlocks != null);
Contract.Invariant(this.rootBlocks != null);
Contract.Invariant(this.blockFor != null);
}
/// <summary>
/// The method body for which this instance is a Control and Data Flow Graph.
/// </summary>
public IMethodBody MethodBody {
get {
Contract.Ensures(Contract.Result<IMethodBody>() != null);
return this.methodBody;
}
set {
Contract.Requires(value != null);
this.methodBody = value;
}
}
private IMethodBody methodBody;
/// <summary>
/// The first block in the method as well as the first blocks of any exception handlers, fault handlers and finally clauses.
/// </summary>
public List<BasicBlock> RootBlocks {
get {
Contract.Ensures(Contract.Result<List<BasicBlock>>() != null);
return this.rootBlocks;
}
set {
Contract.Requires(value != null);
this.rootBlocks = value;
}
}
List<BasicBlock> rootBlocks;
/// <summary>
/// A list of all basic blocks in the graph, ordered so that any block that ends on a conditional branch immediately precedes the block
/// to which it falls through and so that all blocks that make up a try body or handler are contiguous.
/// </summary>
public List<BasicBlock> AllBlocks {
get {
Contract.Ensures(Contract.Result<List<BasicBlock>>() != null);
return this.allBlocks;
}
set {
Contract.Requires(value != null);
this.allBlocks = value;
}
}
List<BasicBlock> allBlocks;
/// <summary>
/// A map from IL offset to corresponding basic block.
/// </summary>
public Hashtable<BasicBlock> BlockFor {
get {
Contract.Ensures(Contract.Result<Hashtable<BasicBlock>>() != null);
return this.blockFor;
}
set {
Contract.Requires(value != null);
this.blockFor = value;
}
}
private Hashtable<BasicBlock> blockFor;
/// <summary>
/// The master list of all successor edges. The successor list for each basic block is a sublist of this list.
/// </summary>
public List<BasicBlock> SuccessorEdges {
get {
Contract.Ensures(Contract.Result<List<BasicBlock>>() != null);
return this.successorEdges;
}
set {
Contract.Requires(value != null);
this.successorEdges = value;
}
}
List<BasicBlock> successorEdges;
/// <summary>
/// All basic blocks that can be reached via control flow out of the given basic block.
/// </summary>
public Sublist<BasicBlock> SuccessorsFor(BasicBlock basicBlock) {
Contract.Requires(basicBlock != null);
if (basicBlock.firstSuccessorEdge+basicBlock.successorCount > this.SuccessorEdges.Count)
throw new InvalidOperationException(); //can only happen if the basic block does not belong to this graph.
Contract.Assume(basicBlock.firstSuccessorEdge >= 0);
Contract.Assume(basicBlock.successorCount >= 0);
return new Sublist<BasicBlock>(this.SuccessorEdges, basicBlock.firstSuccessorEdge, basicBlock.successorCount);
}
/// <summary>
/// Returns the pc for the first block
/// </summary>
public BlockPC StartPC { get { return new BlockPC(0u.Singleton()); } }
/// <summary>
/// Returns the successor BlockPCs from the given BlockPC, properly taking into account finally blocks
/// </summary>
public IEnumerable<BlockPC> Successors(BlockPC pc)
{
var current = this.BlockFor[pc.Current];
var succs = this.SuccessorsFor(current);
if (succs.Count > 0)
{
foreach (var succ in succs)
{
var finallyBlocks = this.FinallyBlocksOnEdge(current, succ);
if (finallyBlocks != null)
{
var to = pc.Stack.Tail; // pop current
to = to.Cons(succ.Offset); // push ultimate successor
while (finallyBlocks != null)
{
to = to.Cons(finallyBlocks.Head.Offset); // push each finally block to execute
finallyBlocks = finallyBlocks.Tail;
}
yield return new BlockPC(to);
}
else
{
yield return pc.Replace(succ.Offset);
}
}
}
else
{
// no direct successors
// find the next pending block
var to = pc.Stack.Tail;
if (to != null) yield return new BlockPC(to);
}
}
/// <summary>
/// Return the Block corresponding to the offset on top of the execution stack
/// </summary>
public BasicBlock CurrentBlock(BlockPC pc)
{
var current = this.BlockFor[pc.Current];
return current;
}
/// <summary>
/// Constructs a control and data flow graph for the given method body.
/// </summary>
public static ControlAndDataFlowGraph<BasicBlock, Instruction> GetControlAndDataFlowGraphFor(IMetadataHost host, IMethodBody methodBody, ILocalScopeProvider/*?*/ localScopeProvider = null) {
Contract.Requires(host != null);
Contract.Requires(methodBody != null);
Contract.Ensures(Contract.Result<ControlAndDataFlowGraph<BasicBlock, Instruction>>() != null);
var cdfg = ControlFlowInferencer<BasicBlock, Instruction>.SetupControlFlow(host, methodBody, localScopeProvider);
DataFlowInferencer<BasicBlock, Instruction>.SetupDataFlow(host, methodBody, cdfg);
TypeInferencer<BasicBlock, Instruction>.FillInTypes(host, cdfg);
HandlerInferencer<BasicBlock, Instruction>.FillInHandlers(host, cdfg);
return cdfg;
}
/// <summary>
/// Returns the finally blocks on this control flow edge in reverse execution order on a forward traversal.
/// </summary>
public FList<BasicBlock> FinallyBlocksOnEdge(BasicBlock from, BasicBlock to)
{
Contract.Requires(from != null);
Contract.Requires(to != null);
var fromHandlers = from.Handlers;
var toHandlers = to.Handlers;
var commonTail = fromHandlers.LongestCommonTail(toHandlers);
var result = FList<BasicBlock>.Empty;
while (fromHandlers != commonTail)
{
Contract.Assume(fromHandlers != null);
var handler = fromHandlers.Head;
if (handler.HandlerKind == HandlerKind.Finally)
{
result = result.Cons(this.BlockFor[fromHandlers.Head.HandlerStartOffset]);
}
fromHandlers = fromHandlers.Tail;
}
return result;
}
/// <summary>
/// Given an instruction representing an address (byref), find the local or parameter it corresponds to or null
/// </summary>
public object LocalOrParameter(Analysis.Instruction address)
{
if (address == null) return null;
while (true)
{
if (address.IsMergeNode) { address = address.Operand1; } // all merges should be same address
else
{
switch (address.Operation.OperationCode)
{
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
return address.Operation.Value; // the parameter definition
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
return address.Operation.Value; // the local definition
default:
return null;
}
}
}
}
}
/// <summary>
/// A block of instructions of which only the first instruction can be reached via explicit control flow.
/// </summary>
public class BasicBlock<Instruction> where Instruction : Microsoft.Cci.Analysis.Instruction {
/// <summary>
/// The first edge that leaves this block. The edges are a contiguous sublist of the the SuccessorEdges list of the ControlAndDataFlowGraph that contains this block.
/// </summary>
internal int firstSuccessorEdge;
/// <summary>
/// The number of edges that leave this block. The edges are a contiguous sublist of the the SuccessorEdges list of the ControlAndDataFlowGraph that contains this block.
/// </summary>
internal int successorCount;
/// <summary>
/// A list of pseudo instructions that initialize the operand stack when the block is entered. No actual code should be generated for these instructions
/// as the actual stack will be set up by the code transferring control to this block.
/// </summary>
public Sublist<Instruction> OperandStack;
/// <summary>
/// The instructions making up this block.
/// </summary>
public Sublist<Instruction> Instructions;
private uint offset;
/// <summary>
/// The IL offset of the first instruction in this basic block. If the block is empty, it is the same as the Offset of the following block. If there is no following block,
/// it is the offset where the next instruction would have appeared.
/// </summary>
public uint Offset
{
get
{
if (this.offset == 0)
{
if (this.Instructions.Count == 0) return 0; else return this.Instructions[0].Operation.Offset;
}
return this.offset;
}
set
{
this.offset = value;
}
}
/// <summary>
/// The enclosing handlers of this block in innermost to outermost order
/// </summary>
public FList<IOperationExceptionInformation> Handlers;
/// <summary>
/// If this block is physically inside a catch, fault, finally, or filter handler, then
/// ContainingHandler points to the closest enclosing such handler.
/// </summary>
public IOperationExceptionInformation/*?*/ ContainingHandler;
private FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction> localDefs;
/// <summary>
/// Maps local variables at the beginning of the block to the corresponding defining instruction
/// </summary>
public FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction> LocalDefs
{
get
{
Contract.Ensures(Contract.Result<FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction>>() != null);
if (this.localDefs == null)
{
this.localDefs = new FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction>(l => l.GetHashCode());
}
return this.localDefs;
}
set {
Contract.Requires(value != null);
this.localDefs = value;
}
}
private FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction> paramDefs;
/// <summary>
/// Maps parameters at the beginning of the block to the corresponding defining instruction
/// </summary>
public FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction> ParamDefs
{
get
{
Contract.Ensures(Contract.Result<FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction>>() != null);
if (this.paramDefs == null)
{
this.paramDefs = new FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction>(l => l.Index);
}
return this.paramDefs;
}
set
{
Contract.Requires(value != null);
this.paramDefs = value;
}
}
/// <summary>
/// If this instruction is a constrained call virt, return the corresponding preceeding type constraint.
/// </summary>
public ITypeReference CallConstraint(Instruction instruction)
{
Contract.Requires(instruction != null);
if (instruction.Operation.OperationCode != OperationCode.Callvirt) return null;
Instruction pred = null;
for (int i = 0; i < this.Instructions.Count; i++)
{
if (this.Instructions[i] == instruction) break;
pred = this.Instructions[i];
}
if (pred != null && pred.Operation.OperationCode == OperationCode.Constrained_)
{
return pred.Operation.Value as ITypeReference;
}
return null;
}
/// <summary>
/// Returns a string describing the basic block.
/// </summary>
/// <returns></returns>
public override string ToString() {
if (this.Instructions.Count == 0) return "Empty BasicBlock";
return "BasicBlock at "+this.Offset.ToString("x4");
}
}
/// <summary>
/// A model of an IL operation, but with the implicit operand stack made explicit via the properties Operand1 and Operand2
/// that point to the previous instructions that computed the operands, if any, that the instruction consumes.
/// </summary>
public class Instruction {
/// <summary>
/// A model of an IL operation, but with the implicit operand stack made explicit via the properties Operand1 and Operand2
/// that point to the previous instructions that computed the operands, if any, that the instruction consumes.
/// </summary>
public Instruction() {
this.operation = Dummy.Operation;
this.type = Dummy.Type;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.operation != null);
Contract.Invariant(this.type != null);
}
/// <summary>
/// The operation this instruction carries out.
/// </summary>
public IOperation Operation {
get {
Contract.Ensures(Contract.Result<IOperation>() != null);
return operation;
}
set {
Contract.Requires(value != null);
operation = value;
}
}
private IOperation operation;
/// <summary>
/// The instruction that results in the first operand of the operation, if an operand is required.
/// </summary>
public Instruction/*?*/ Operand1;
/// <summary>
/// The instruction that results in the second operand of the operation, if a second operand is required.
/// Could also be an array of instructions if the instruction is n-ary for n > 2.
/// </summary>
public object/*?*/ Operand2;
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString() {
var stringBuilder = new StringBuilder();
stringBuilder.Append(this.Operation.Offset.ToString("x4"));
stringBuilder.Append(", ");
stringBuilder.Append(this.Operation.OperationCode.ToString());
if (this.Operation.Value is uint)
stringBuilder.Append(" "+((uint)this.Operation.Value).ToString("x4"));
stringBuilder.Append(", ");
stringBuilder.Append(TypeHelper.GetTypeName(this.Type));
if (this.Operand1 != null) {
stringBuilder.Append(", ");
this.AppendFlowFrom(this.Operand1, stringBuilder);
}
var i2 = this.Operand2 as Instruction;
if (i2 != null) {
stringBuilder.Append(", ");
this.AppendFlowFrom(i2, stringBuilder);
} else {
var i2a = this.Operand2 as Instruction[];
if (i2a != null) {
foreach (var i2e in i2a) {
Contract.Assume(i2e != null); //Assumed because of the informal specification of the ControlFlowInferencer
stringBuilder.Append(", ");
this.AppendFlowFrom(i2e, stringBuilder);
}
}
}
return stringBuilder.ToString();
}
private void AppendFlowFrom(Instruction instruction, StringBuilder stringBuilder) {
Contract.Requires(instruction != null);
Contract.Requires(stringBuilder != null);
if (instruction.Operation is Dummy)
stringBuilder.Append("stack");
else
stringBuilder.Append(instruction.Operation.Offset.ToString("x4"));
}
/// <summary>
/// The type of the result this instruction pushes onto the stack. Void if none.
/// </summary>
public ITypeReference Type {
get {
Contract.Ensures(Contract.Result<ITypeReference>() != null);
return type;
}
set {
Contract.Requires(value != null);
Contract.Assume(!(value is Dummy)); //It is a bit too onerous on the client code to prove this statically, but it does seem a very desirable check.
type = value;
}
}
private ITypeReference type;
/// <summary>
/// Extra dataflow information for Ldloc, Ldarg, Ldind. It contains the actual result value that was loaded
/// </summary>
public Instruction Aux;
/// <summary>
/// The local definitions after the instruction
/// </summary>
public FMap<ILocalDefinition, Instruction> PostLocalDefs;
/// <summary>
/// The parameter definitions after the instruction
/// </summary>
public FMap<IParameterDefinition, Instruction> PostParamDefs;
/// <summary>
/// Return true if the instruction is a synthetic merge node (aka Phi node) at block entry
/// </summary>
public bool IsMergeNode { get { return this.operation is Dummy; } }
/// <summary>
/// Returns the defining instruction of the local or parameter definition after this instruction or null
/// </summary>
public Instruction this[object localOrParameter]
{
get
{
Instruction result;
var local = localOrParameter as ILocalDefinition;
if (this.PostLocalDefs != null && local != null)
{
this.PostLocalDefs.TryGetValue(local, out result);
return result;
}
var param = localOrParameter as IParameterDefinition;
if (this.PostParamDefs != null && param != null)
{
this.PostParamDefs.TryGetValue(param, out result);
return result;
}
return null;
}
}
/// <summary>
/// If the instruction is a merge node, then return all in-flowing defs
/// </summary>
/// <returns></returns>
public IEnumerable<Instruction> InFlows()
{
if (!this.IsMergeNode) yield break;
if (this.Operand1 != null)
{
yield return this.Operand1;
}
var second = this.Operand2 as Instruction;
if (second != null) yield return second;
var rest = this.Operand2 as List<Instruction>;
if (rest != null)
{
for (int i = 0; i < rest.Count; i++)
{
yield return rest[i];
}
}
}
}
internal class Stack<Instruction> where Instruction : class {
internal Stack(int maxStack) {
if (maxStack <= 0) maxStack = 8;
this.elements = new Instruction[maxStack];
this.top = -1;
}
Instruction[] elements;
private int top;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.elements != null);
Contract.Invariant(this.elements.Length > 0);
Contract.Invariant(this.top < this.elements.Length);
Contract.Invariant(Contract.ForAll(0, this.top+1, (i) => this.elements[i] != null));
Contract.Invariant(this.top >= -1);
}
internal void Clear() {
this.top = -1;
}
internal void Push(Instruction instruction) {
Contract.Requires(instruction != null);
if (this.top >= this.elements.Length-1) {
Array.Resize(ref this.elements, this.elements.Length*2);
Contract.Assume(Contract.ForAll(0, this.top+1, (i) => this.elements[i] != null)); //this the expected behavior of Array.Resize
}
this.elements[++this.top] = instruction;
}
internal Instruction Peek(int i) {
Contract.Requires(0 <= i);
Contract.Requires(i <= this.Top);
Contract.Ensures(Contract.Result<Instruction>() != null);
Contract.Ensures(this.Top == Contract.OldValue<int>(this.Top));
return this.elements[i];
}
internal Instruction Pop() {
Contract.Ensures(Contract.Result<Instruction>() != null);
Contract.Assume(this.top >= 0); //This is an optimistic assumption. Clients have to match their Pop and Push calls, but enforcing this convention via contracts is too verbose.
return this.elements[this.top--];
}
internal int Top {
get { return this.top; }
}
}
/// <summary>
/// A generalized program counter that contains the current block (and blocks to execute after that)
///
/// Equality and hashing is based on content (the blocks) rather than the list pointers, so they are value equal
/// </summary>
public struct BlockPC : IEquatable<BlockPC>
{
/// <summary>
/// List of blocks (identified by start instruction offset) that are form a stack of execution contexts
/// </summary>
public readonly FList<uint> Stack;
[ContractInvariantMethod]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
private void ObjectInvariant()
{
Contract.Invariant(this.Stack != null);
}
/// <summary>
/// Produce a block PC with the given control stack
/// </summary>
public BlockPC(FList<uint> stack)
{
Contract.Requires(stack != null);
this.Stack = stack;
}
/// <summary>
/// Return the block offset of the current block in the PC
/// </summary>
public uint Current { get { return this.Stack.Head; } }
/// <summary>
/// Produce a new BlockPC with the current block replaced by the given one. The rest of the stack is unchanged.
/// </summary>
public BlockPC Replace(uint newCurrent)
{
return new BlockPC(this.Stack.Tail.Cons(newCurrent));
}
/// <summary>
/// Produce a new BlockPC starting at the given Block.
/// </summary>
public static BlockPC For<Block, Instruction>(Block b)
where Block : Analysis.BasicBlock<Instruction>
where Instruction : Analysis.Instruction
{
return new BlockPC(b.Offset.Singleton());
}
/// <summary>
/// Push the given block on top of the BlockPC call stack
/// </summary>
public BlockPC Push<Block, Instruction>(Block b)
where Block : Analysis.BasicBlock<Instruction>
where Instruction : Analysis.Instruction
{
return new BlockPC(this.Stack.Cons(b.Offset));
}
#region IEquatable<BlockPC> Members
/// <summary>
/// Compare two BlockPCs for value equality
/// </summary>
public bool Equals(BlockPC other)
{
return EqualLists(this.Stack, other.Stack);
}
private static bool EqualLists(FList<uint> tl, FList<uint> ol)
{
while (tl != null && ol != null)
{
if (tl.Head != ol.Head) return false;
tl = tl.Tail;
ol = ol.Tail;
}
if (ol != tl) return false; // both must be null here
return true;
}
/// <summary>
/// Return the hash code for this BlockPC
/// </summary>
public override int GetHashCode()
{
return HashList(0, this.Stack);
}
private static int HashList(int hash, FList<uint> l)
{
while (l != null) { hash = 2 * hash + (int)l.Head; l = l.Tail; }
return hash;
}
/// <summary>
/// Return a string representation of this BlockPC
/// </summary>
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("Block ");
sb.AppendFormat("{0:x3}", this.Stack.Head);
sb.Append(" (");
var to = this.Stack.Tail;
while (to != null)
{
sb.AppendFormat("{0:x3}", to.Head);
sb.Append(", ");
to = to.Tail;
}
sb.Append(")");
return sb.ToString();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,474 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Immutable;
using Microsoft.Cci.UtilityDataStructures;
using System;
namespace Microsoft.Cci.Analysis
{
/// <summary>
/// Infer protecting local handlers for each block.
///
/// With that information we can then traverse finally and exception handler blocks in the proper order to infer data flow for locals and parameters
/// </summary>
internal class HandlerInferencer<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.BasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new()
{
internal static void FillInHandlers(IMetadataHost host, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg)
{
var method = cdfg.MethodBody;
var handlers = new List<IOperationExceptionInformation>(method.OperationExceptionInformation).ToArray();
#region Compute enclosing handlers for each block
FList<IOperationExceptionInformation> currentHandlers = null;
FList<IOperationExceptionInformation> containingHandlers = null;
foreach (var current in cdfg.AllBlocks)
{
//traceFile.WriteLine("Block at: {0:x3}", current.Offset);
currentHandlers = PopPushHandlers(current, currentHandlers, handlers, ref containingHandlers);
}
#endregion
// now compute extra block information:
// - local def maps
// - parameter def maps
ComputeDataFlowThroughLocals(cdfg);
}
private static FList<IOperationExceptionInformation> PopPushHandlers(BasicBlock block, FList<IOperationExceptionInformation> currentHandlers, IOperationExceptionInformation[] handlers, ref FList<IOperationExceptionInformation> containingHandlers)
{
Contract.Requires(block != null);
Contract.Requires(handlers != null);
Contract.Requires(Contract.ForAll(handlers, h => h != null));
// pop fault/finally subroutines off subroutine stack whose scope ends here
var blockOffset = block.Offset;
#region Pop protecting handlers off stack whose scope ends here
for (int i = 0; i < handlers.Length; i++)
{
if (handlers[i].TryEndOffset == blockOffset)
{
// must be head
if (currentHandlers != null && Object.Equals(handlers[i], currentHandlers.Head))
{
currentHandlers = currentHandlers.Tail;
}
else
{
throw new ApplicationException("bad order of handlers");
}
}
}
#endregion
#region Push protecting handlers on stack whose scope starts here
// reverse order
for (int i = handlers.Length - 1; i >= 0; i--)
{
if (handlers[i].TryStartOffset == blockOffset)
{
// push this handler on top of current block enclosing handlers
currentHandlers = FList<IOperationExceptionInformation>.Cons(handlers[i], currentHandlers); // Push handler
}
}
#endregion
#region Pop containing handlers off containing handler stack whose scope ends here
for (int i = 0; i < handlers.Length; i++)
{
if (handlers[i].HandlerEndOffset == blockOffset)
{
// must be head
if (containingHandlers != null && Object.Equals(handlers[i], containingHandlers.Head))
{
containingHandlers = containingHandlers.Tail;
}
else
{
throw new ApplicationException("bad order of handlers");
}
}
}
#endregion
#region Push containing handler on stack whose scope starts here
// reverse order
for (int i = handlers.Length - 1; i >= 0; i--)
{
if (handlers[i].HandlerStartOffset == blockOffset)
{
// push this handler on top of containing handlers
containingHandlers = FList<IOperationExceptionInformation>.Cons(handlers[i], containingHandlers); // Push handler
}
}
#endregion
// record handlers for this block
block.Handlers = currentHandlers;
block.ContainingHandler = (containingHandlers != null) ? containingHandlers.Head : null;
return currentHandlers;
}
private static void ComputeDataFlowThroughLocals(ControlAndDataFlowGraph<BasicBlock, Instruction> cdg)
{
FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction> currentLocals;
var todo = new Queue<BlockPC>();
var seen = new HashSet<BlockPC>();
var startBlock = cdg.RootBlocks[0];
FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction> currentParameters = new FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction>(k => k.Index);
var initialLocation = GetStartLocation(startBlock);
// push parameters onto start block
foreach (var arg in cdg.MethodBody.MethodDefinition.Parameters)
{
var initialOp = new InitialParameterAssignment(arg, initialLocation);
var initialDef = new Instruction() { Operation = initialOp };
currentParameters = currentParameters.Insert(arg, initialDef);
}
startBlock.ParamDefs = currentParameters;
todo.Enqueue(new BlockPC(startBlock.Offset.Singleton()));
while (todo.Count > 0)
{
var currentPC = todo.Dequeue();
if (seen.Contains(currentPC)) continue;
seen.Add(currentPC);
var block = cdg.CurrentBlock(currentPC);
Contract.Assume(block != null);
currentLocals = block.LocalDefs;
currentParameters = block.ParamDefs;
foreach (var instr in block.Instructions)
{
if (instr.IsMergeNode) continue;
switch (instr.Operation.OperationCode)
{
case OperationCode.Starg:
case OperationCode.Starg_S:
// without pdb we seem to have no parameter info.
var pdef = (IParameterDefinition)instr.Operation.Value;
if (pdef != null)
{
currentParameters = currentParameters.Insert(pdef, instr.Operand1);
}
break;
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
var ldef = (ILocalDefinition)instr.Operation.Value;
currentLocals = currentLocals.Insert(ldef, instr.Operand1);
break;
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
// save the source in Aux
{
currentLocals.TryGetValue((ILocalDefinition)instr.Operation.Value, out instr.Aux);
break;
}
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
// save the source in Aux
var pdef2 = (IParameterDefinition)instr.Operation.Value;
if (pdef2 == null)
{
// this parameter. Assume it's never overwritten
}
else
{
currentParameters.TryGetValue(pdef2, out instr.Aux);
}
break;
case OperationCode.Stind_I:
case OperationCode.Stind_I1:
case OperationCode.Stind_I2:
case OperationCode.Stind_I4:
case OperationCode.Stind_I8:
case OperationCode.Stind_R4:
case OperationCode.Stind_R8:
case OperationCode.Stind_Ref:
{
var location = cdg.LocalOrParameter(instr.Operand1);
UpdateLocation(ref currentLocals, ref currentParameters, location, (Analysis.Instruction)instr.Operand2);
break;
}
case OperationCode.Ldind_I:
case OperationCode.Ldind_I1:
case OperationCode.Ldind_I2:
case OperationCode.Ldind_I4:
case OperationCode.Ldind_I8:
case OperationCode.Ldind_R4:
case OperationCode.Ldind_R8:
case OperationCode.Ldind_Ref:
case OperationCode.Ldind_U1:
case OperationCode.Ldind_U2:
case OperationCode.Ldind_U4:
{
// save the read value in Aux
var location = cdg.LocalOrParameter(instr.Operand1);
instr.Aux = ReadLocation(currentLocals, currentParameters, location);
break;
}
case OperationCode.Call:
case OperationCode.Callvirt:
{
// update byref / out parameters
var methodRef = instr.Operation.Value as IMethodReference;
var args = instr.Operand2 as Instruction[];
if (args != null && methodRef != null)
{
foreach (var p in methodRef.Parameters)
{
if (p.IsByReference && p.Index < args.Length)
{
var arg = args[p.Index];
if (arg != null)
{
var loc = cdg.LocalOrParameter(arg);
var syntheticOp = new CallByRefAssignment(instr, p);
UpdateLocation(ref currentLocals, ref currentParameters, loc, new Instruction() { Operation = syntheticOp, Type = p.Type });
}
}
}
}
break;
}
}
instr.PostLocalDefs = currentLocals;
instr.PostParamDefs = currentParameters;
}
foreach (var succ in cdg.Successors(currentPC))
{
MergeLocalsAndParameters(cdg.CurrentBlock(succ), currentLocals, currentParameters);
todo.Enqueue(succ);
}
}
}
private static Analysis.Instruction ReadLocation(FMap<ILocalDefinition, Analysis.Instruction> currentLocals, FMap<IParameterDefinition, Analysis.Instruction> currentParameters, object localOrParameter)
{
Analysis.Instruction result;
var local = localOrParameter as ILocalDefinition;
if (local != null)
{
currentLocals.TryGetValue(local, out result);
return result;
}
var param = localOrParameter as IParameterDefinition;
if (param != null)
{
currentParameters.TryGetValue(param, out result);
return result;
}
return null;
}
private static ILocation GetStartLocation(BasicBlock startBlock)
{
foreach (var i in startBlock.Instructions)
{
if (i.Operation.Location != null && !(i.Operation.Location is Dummy)) return i.Operation.Location;
}
return null;
}
private static void UpdateLocation(ref FMap<ILocalDefinition, Analysis.Instruction> currentLocals, ref FMap<IParameterDefinition, Analysis.Instruction> currentParameters, object localOrParameter, Analysis.Instruction newValue)
{
Contract.Requires(currentParameters != null);
Contract.Requires(currentLocals != null);
Contract.Ensures(Contract.ValueAtReturn(out currentParameters) != null);
Contract.Ensures(Contract.ValueAtReturn(out currentLocals) != null);
var local = localOrParameter as ILocalDefinition;
if (local != null)
{
currentLocals = currentLocals.Insert(local, newValue);
return;
}
var param = localOrParameter as IParameterDefinition;
if (param != null)
{
currentParameters = currentParameters.Insert(param, newValue);
return;
}
}
private static void MergeLocalsAndParameters(BasicBlock succ, FMap<ILocalDefinition, Microsoft.Cci.Analysis.Instruction> currentLocals, FMap<IParameterDefinition, Microsoft.Cci.Analysis.Instruction> currentParameters)
{
foreach (var p in currentLocals)
{
Microsoft.Cci.Analysis.Instruction existing;
if (succ.LocalDefs.TryGetValue(p.Key, out existing))
{
PushMerge(existing, p.Value);
}
else
{
var mergeInstruction = new Instruction() { Operand1 = p.Value };
succ.LocalDefs = succ.LocalDefs.Insert(p.Key, mergeInstruction);
}
}
foreach (var p in currentParameters)
{
Microsoft.Cci.Analysis.Instruction existing;
if (succ.ParamDefs.TryGetValue(p.Key, out existing))
{
PushMerge(existing, p.Value);
}
else
{
var mergeInstruction = new Instruction() { Operand1 = p.Value };
succ.ParamDefs = succ.ParamDefs.Insert(p.Key, mergeInstruction);
}
}
}
private static void PushMerge(Microsoft.Cci.Analysis.Instruction target, Microsoft.Cci.Analysis.Instruction inflow)
{
if (target.Operand2 == null)
target.Operand2 = inflow;
else
{
var list = target.Operand2 as List<Microsoft.Cci.Analysis.Instruction>;
if (list == null)
{
//Contract.Assume(target.Operand2 is Instruction);
list = new List<Microsoft.Cci.Analysis.Instruction>(4);
list.Add((Microsoft.Cci.Analysis.Instruction)target.Operand2);
}
list.Add(inflow);
}
}
}
/// <summary>
/// Dummy instruction to give definition of initial parameter values
/// </summary>
public class InitialParameterAssignment : IOperation
{
private ILocation location;
private IParameterDefinition parameter;
internal InitialParameterAssignment(IParameterDefinition p, ILocation locs) {
this.location = locs;
this.parameter = p;
}
#region IOperation Members
OperationCode IOperation.OperationCode
{
get { return Cci.OperationCode.Starg; }
}
uint IOperation.Offset
{
get { return 0; }
}
ILocation IOperation.Location
{
get { return this.location; }
}
object IOperation.Value
{
get { return this.parameter; }
}
#endregion
}
/// <summary>
/// Dummy instruction to give definition of byref/out parameter values at a call
/// </summary>
public class CallByRefAssignment : IOperation
{
Instruction original;
/// <summary>
/// The parameter assigned by this operation
/// </summary>
public readonly IParameterTypeInformation Parameter;
internal CallByRefAssignment(Instruction original, IParameterTypeInformation p)
{
this.original = original;
this.Parameter = p;
}
/// <summary>
/// The original call instruction giving rise to this by-ref assignment
/// </summary>
public Instruction Call { get { return this.original; } }
#region IOperation Members
OperationCode IOperation.OperationCode
{
get { return Cci.OperationCode.Starg; }
}
uint IOperation.Offset
{
get { return original.Operation.Offset; }
}
ILocation IOperation.Location
{
get { return this.original.Operation.Location; }
}
object IOperation.Value
{
get { return this.original.Operation.Value; }
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsof.Cci.ControlAndDataFlowGraph")]
[assembly: AssemblyDescription("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("29c3269c-6c6e-49fc-b471-181bb71ec938")]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{08156C78-403A-4112-AD81-8646AC51CD2F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci</RootNamespace>
<AssemblyName>Microsoft.Cci.ILGenerator</AssemblyName>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<SignAssembly>true</SignAssembly>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<IsWebBootstrapper>false</IsWebBootstrapper>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Debug\Microsoft.Cci.ILGenerator.XML</DocumentationFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Release\Microsoft.Cci.ILGenerator.XML</DocumentationFile>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CompilerOnly|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\CompilerOnly\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Microsoft.Cci.ILGenerator.XML</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\version.cs">
<Link>Build\version.cs</Link>
</Compile>
<Compile Include="ILGenerator.cs" />
<Compile Include="ILRewriter.cs" />
<Compile Include="MethodBody.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataHelper\MetadataHelper.csproj">
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
<Name>MetadataHelper</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\SourceModel\SourceModel.csproj">
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
<Name>SourceModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,410 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Cci.ILGeneratorImplementation;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci {
/// <summary>
/// Rewrites the IL of method bodies.
/// </summary>
public class ILRewriter {
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="localScopeProvider"></param>
/// <param name="sourceLocationProvider"></param>
public ILRewriter(IMetadataHost host, ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider) {
Contract.Requires(host != null);
this.host = host;
this.generator = new ILGenerator(host, Dummy.MethodDefinition);
this.localScopeProvider = localScopeProvider;
this.sourceLocationProvider = sourceLocationProvider;
}
/// <summary>
///
/// </summary>
protected readonly IMetadataHost host;
/// <summary>
///
/// </summary>
protected readonly ILocalScopeProvider/*?*/ localScopeProvider;
/// <summary>
///
/// </summary>
protected readonly ISourceLocationProvider/*?*/ sourceLocationProvider;
ILGenerator generator;
Hashtable<ILGeneratorLabel> labelFor = new Hashtable<ILGeneratorLabel>();
readonly HashtableForUintValues<ILocalDefinition> localIndex = new HashtableForUintValues<ILocalDefinition>();
readonly List<ILocalDefinition> localVariables = new List<ILocalDefinition>();
readonly Microsoft.Cci.ILGeneratorImplementation.Stack<ILocalScope> scopeStack = new Microsoft.Cci.ILGeneratorImplementation.Stack<ILocalScope>();
IEnumerator<ILocalScope>/*?*/ scopeEnumerator;
bool scopeEnumeratorIsValid;
IEnumerator<ILocalScope>/*?*/ iteratorScopeEnumerator;
bool iteratorScopeEnumeratorIsValid;
ISynchronizationInformation/*?*/ synchronizationInfo;
IEnumerator<ISynchronizationPoint>/*?*/ syncPointEnumerator;
bool syncPointEnumeratorIsValid;
/// <summary>
///
/// </summary>
protected ushort maxStack;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.host != null);
Contract.Invariant(this.generator != null);
Contract.Invariant(this.labelFor != null);
Contract.Invariant(this.localIndex != null);
Contract.Invariant(this.localVariables != null);
Contract.Invariant(this.scopeStack != null);
}
/// <summary>
///
/// </summary>
protected ILGenerator Generator {
get {
Contract.Ensures(Contract.Result<ILGenerator>() != null);
return this.generator;
}
}
/// <summary>
///
/// </summary>
protected IMetadataHost Host {
get {
Contract.Ensures(Contract.Result<IMetadataHost>() != null);
return this.host;
}
}
/// <summary>
///
/// </summary>
/// <param name="methodBody"></param>
/// <returns></returns>
public virtual IMethodBody Rewrite(IMethodBody methodBody) {
Contract.Requires(methodBody != null);
IMethodDefinition asyncMethodDefinition = null;
if (this.localScopeProvider != null) {
this.synchronizationInfo = this.localScopeProvider.GetSynchronizationInformation(methodBody);
if (this.synchronizationInfo != null) asyncMethodDefinition = this.synchronizationInfo.AsyncMethod;
}
this.generator = new ILGenerator(this.host, methodBody.MethodDefinition, asyncMethodDefinition);
this.maxStack = methodBody.MaxStack;
this.labelFor.Clear();
this.localIndex.Clear();
this.localVariables.Clear();
this.scopeStack.Count = 0;
this.EmitMethodBody(methodBody);
return new ILGeneratorMethodBody(this.Generator, methodBody.LocalsAreZeroed, this.maxStack, methodBody.MethodDefinition,
this.localVariables.ToArray(), Enumerable<ITypeDefinition>.Empty);
}
/// <summary>
///
/// </summary>
/// <param name="methodBody"></param>
[ContractVerification(false)]
protected virtual void EmitMethodBody(IMethodBody methodBody) {
Contract.Requires(methodBody != null);
var savedLabelFor = this.labelFor;
this.labelFor = new Hashtable<ILGeneratorLabel>();
var initialScopeStackCount = this.scopeStack.Count;
foreach (var exceptionInfo in methodBody.OperationExceptionInformation) {
Contract.Assume(exceptionInfo != null);
this.Generator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType,
this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset),
this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset),
exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null);
}
if (this.localScopeProvider == null) {
foreach (var localDef in methodBody.LocalVariables) {
Contract.Assume(localDef != null);
this.Generator.AddVariableToCurrentScope(localDef);
}
} else {
foreach (var ns in this.localScopeProvider.GetNamespaceScopes(methodBody)) {
Contract.Assume(ns != null);
foreach (var uns in ns.UsedNamespaces) {
Contract.Assume(uns != null);
this.Generator.UseNamespace(uns.NamespaceName.Value);
}
}
this.scopeEnumerator = this.localScopeProvider.GetLocalScopes(methodBody).GetEnumerator();
this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext();
this.iteratorScopeEnumerator = this.localScopeProvider.GetIteratorScopes(methodBody).GetEnumerator();
this.iteratorScopeEnumeratorIsValid = this.iteratorScopeEnumerator.MoveNext();
if (this.synchronizationInfo != null) {
this.syncPointEnumerator = this.synchronizationInfo.SynchronizationPoints.GetEnumerator();
this.syncPointEnumeratorIsValid = this.syncPointEnumerator.MoveNext();
}
}
foreach (var operation in methodBody.Operations) {
switch (operation.OperationCode) {
case OperationCode.Beq:
case OperationCode.Bge:
case OperationCode.Bge_Un:
case OperationCode.Bgt:
case OperationCode.Bgt_Un:
case OperationCode.Ble:
case OperationCode.Ble_Un:
case OperationCode.Blt:
case OperationCode.Blt_Un:
case OperationCode.Bne_Un:
case OperationCode.Br:
case OperationCode.Br_S:
case OperationCode.Brfalse:
case OperationCode.Brtrue:
case OperationCode.Leave:
case OperationCode.Beq_S:
case OperationCode.Bge_S:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble_S:
case OperationCode.Ble_Un_S:
case OperationCode.Blt_S:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un_S:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue_S:
case OperationCode.Leave_S:
Contract.Assume(operation.Value is uint);
this.GetLabelFor((uint)operation.Value);
break;
case OperationCode.Switch:
uint[] offsets = operation.Value as uint[];
Contract.Assume(offsets != null);
foreach (var offset in offsets) {
this.GetLabelFor(offset);
}
break;
}
}
foreach (var operation in methodBody.Operations) {
Contract.Assume(operation != null);
Contract.Assume(this.labelFor != null);
var label = this.labelFor.Find(operation.Offset);
if (label != null) this.Generator.MarkLabel(label);
this.EmitDebugInformationFor(operation);
this.EmitOperation(operation);
this.TrackLocal(operation.Value);
}
while (this.scopeStack.Count > initialScopeStackCount) {
this.Generator.EndScope();
this.scopeStack.Pop();
}
this.labelFor = savedLabelFor;
Contract.Assume(this.generator != null);
}
/// <summary>
///
/// </summary>
/// <param name="operation"></param>
protected virtual void EmitDebugInformationFor(IOperation operation) {
Contract.Requires(operation != null);
this.Generator.MarkSequencePoint(operation.Location);
if (this.scopeEnumerator == null) return;
ILocalScope/*?*/ currentScope = null;
while (this.scopeStack.Count > 0) {
currentScope = this.scopeStack.Peek();
Contract.Assume(currentScope != null);
if (operation.Offset < currentScope.Offset+currentScope.Length) break;
this.scopeStack.Pop();
this.Generator.EndScope();
currentScope = null;
}
while (this.scopeEnumeratorIsValid) {
currentScope = this.scopeEnumerator.Current;
Contract.Assume(currentScope != null);
if (currentScope.Offset <= operation.Offset && operation.Offset < currentScope.Offset+currentScope.Length) {
this.scopeStack.Push(currentScope);
uint iteratorLocalsInScope = 0;
if (this.iteratorScopeEnumerator != null) {
while (this.iteratorScopeEnumeratorIsValid) {
var iteratorScope = this.iteratorScopeEnumerator.Current;
Contract.Assume(iteratorScope != null);
if (iteratorScope.Offset >= currentScope.Offset && iteratorScope.Offset+iteratorScope.Length <= currentScope.Offset+currentScope.Length) {
iteratorLocalsInScope++;
this.iteratorScopeEnumeratorIsValid = this.iteratorScopeEnumerator.MoveNext();
} else {
break;
}
}
}
this.Generator.BeginScope(iteratorLocalsInScope);
Contract.Assume(this.localScopeProvider != null);
foreach (var local in this.localScopeProvider.GetVariablesInScope(currentScope)) {
Contract.Assume(local != null);
Contract.Assume(local.MethodDefinition == this.generator.Method);
if (!this.localIndex.ContainsKey(local)) {
this.localIndex.Add(local, (uint)this.localVariables.Count);
this.localVariables.Add(local);
}
this.Generator.AddVariableToCurrentScope(local);
}
foreach (var constant in this.localScopeProvider.GetConstantsInScope(currentScope)) {
Contract.Assume(constant != null);
Contract.Assume(constant.MethodDefinition == this.generator.Method);
this.Generator.AddConstantToCurrentScope(constant);
}
this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext();
} else
break;
}
if (this.syncPointEnumeratorIsValid) {
Contract.Assume(this.syncPointEnumerator != null);
var syncPoint = this.syncPointEnumerator.Current;
Contract.Assume(syncPoint != null);
if (syncPoint.SynchronizeOffset == operation.Offset) {
if (syncPoint.ContinuationMethod == null)
this.generator.MarkSynchronizationPoint(this.generator.Method, this.GetLabelFor(syncPoint.ContinuationOffset));
else
this.generator.MarkSynchronizationPoint(syncPoint.ContinuationMethod, new ILGeneratorLabel() { Offset = syncPoint.ContinuationOffset });
Contract.Assume(this.syncPointEnumerator != null);
this.syncPointEnumeratorIsValid = this.syncPointEnumerator.MoveNext();
}
}
}
/// <summary>
/// Emits the given operation at the current position of the new IL stream. Also tracks any referenced local definitions,
/// so that this.localVariables will contain the exact list of locals used in the new method body.
/// </summary>
/// <param name="operation"></param>
protected virtual void EmitOperation(IOperation operation) {
Contract.Requires(operation != null);
var operationCode = operation.OperationCode;
var value = operation.Value;
switch (operationCode) {
case OperationCode.Beq:
case OperationCode.Bge:
case OperationCode.Bge_Un:
case OperationCode.Bgt:
case OperationCode.Bgt_Un:
case OperationCode.Ble:
case OperationCode.Ble_Un:
case OperationCode.Blt:
case OperationCode.Blt_Un:
case OperationCode.Bne_Un:
case OperationCode.Br:
case OperationCode.Br_S:
case OperationCode.Brfalse:
case OperationCode.Brtrue:
case OperationCode.Leave:
case OperationCode.Beq_S:
case OperationCode.Bge_S:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble_S:
case OperationCode.Ble_Un_S:
case OperationCode.Blt_S:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un_S:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue_S:
case OperationCode.Leave_S:
operationCode = ILGenerator.LongVersionOf(operationCode);
Contract.Assume(operation.Value is uint);
value = this.GetLabelFor(+(uint)operation.Value);
break;
case OperationCode.Switch:
uint[] offsets = operation.Value as uint[];
Contract.Assume(offsets != null);
var n = offsets.Length;
ILGeneratorLabel[] labels = new ILGeneratorLabel[n];
for (int i = 0; i < n; i++) {
var offset = offsets[i];
labels[i] = this.GetLabelFor(offset);
}
value = labels;
break;
//Avoid the short forms because the locals can get reordered.
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
operationCode = OperationCode.Ldloc;
break;
case OperationCode.Ldloca_S:
operationCode = OperationCode.Ldloca;
break;
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
operationCode = OperationCode.Stloc;
break;
}
this.generator.Emit(operationCode, value);
}
/// <summary>
///
/// </summary>
/// <param name="operationValue"></param>
protected void TrackLocal(object operationValue) {
var local = operationValue as ILocalDefinition;
if (local != null) {
if (!this.localIndex.ContainsKey(local)) {
this.localIndex.Add(local, (uint)this.localVariables.Count);
this.localVariables.Add(local);
}
}
}
/// <summary>
/// Returns a label that represents the given offset in the original IL. This label must be marked
/// at the corresponding location in the rewritten IL.
/// </summary>
protected virtual ILGeneratorLabel GetLabelFor(uint offset) {
Contract.Ensures(Contract.Result<ILGeneratorLabel>() != null);
var result = this.labelFor[offset];
if (result == null)
this.labelFor[offset] = result = new ILGeneratorLabel();
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,290 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace Microsoft.Cci {
using Microsoft.Cci.ILGeneratorImplementation;
/// <summary>
/// A metadata (IL) level represetation of the body of a method or of a property/event accessor.
/// </summary>
public class ILGeneratorMethodBody : IMethodBody {
/// <summary>
/// Allocates an object that is the metadata (IL) level represetation of the body of a method or of a property/event accessor.
/// </summary>
/// <param name="generator">An object that provides a way to construct the information needed by a method body. Construction should
/// be completed by the time the generator is passed to this constructor. The generator is not referenced by the resulting method body.</param>
/// <param name="localsAreZeroed">True if the locals are initialized by zeroeing the stack upon method entry.</param>
/// <param name="maxStack">The maximum number of elements on the evaluation stack during the execution of the method.</param>
/// <param name="methodDefinition">The definition of the method whose body this is.
/// If this is the body of an event or property accessor, this will hold the corresponding adder/remover/setter or getter method.</param>
/// <param name="localVariables"></param>
/// <param name="privateHelperTypes">Any types that are implicitly defined in order to implement the body semantics.
/// In case of AST to instructions conversion this lists the types produced.
/// In case of instructions to AST decompilation this should ideally be list of all types
/// which are local to method.</param>
public ILGeneratorMethodBody(ILGenerator generator, bool localsAreZeroed, ushort maxStack, IMethodDefinition methodDefinition,
IEnumerable<ILocalDefinition> localVariables, IEnumerable<ITypeDefinition> privateHelperTypes) {
Contract.Requires(generator != null);
Contract.Requires(methodDefinition != null);
Contract.Requires(localVariables != null);
Contract.Requires(privateHelperTypes != null);
this.localsAreZeroed = localsAreZeroed;
this.operationExceptionInformation = generator.GetOperationExceptionInformation();
this.operations = generator.GetOperations();
this.privateHelperTypes = privateHelperTypes;
this.generatorIteratorScopes = generator.GetIteratorScopes();
this.generatorLocalScopes = generator.GetLocalScopes();
this.localVariables = localVariables;
this.maxStack = maxStack;
this.methodDefinition = methodDefinition;
this.size = generator.CurrentOffset;
this.synchronizationInformation = generator.GetSynchronizationInformation();
}
/// <summary>
/// Calls visitor.Visit(IMethodBody).
/// </summary>
public void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
readonly IEnumerable<ILocalScope>/*?*/ generatorIteratorScopes;
readonly IEnumerable<ILGeneratorScope> generatorLocalScopes;
readonly ISynchronizationInformation/*?*/ synchronizationInformation;
/// <summary>
/// Returns a block scope associated with each local variable in the iterator for which this is the generator for its MoveNext method.
/// May return null.
/// </summary>
/// <remarks>The PDB file model seems to be that scopes are duplicated if necessary so that there is a separate scope for each
/// local variable in the original iterator and the mapping from local to scope is done by position.</remarks>
public IEnumerable<ILocalScope>/*?*/ GetIteratorScopes() {
return this.generatorIteratorScopes;
}
/// <summary>
/// Returns zero or more local (block) scopes into which the CLR IL operations of this method body is organized.
/// </summary>
public IEnumerable<ILocalScope> GetLocalScopes() {
foreach (var generatorScope in this.generatorLocalScopes) {
if (generatorScope.locals.Count > 0)
yield return generatorScope;
}
}
/// <summary>
/// Returns zero or more namespace scopes into which the namespace type containing the given method body has been nested.
/// These scopes determine how simple names are looked up inside the method body. There is a separate scope for each dotted
/// component in the namespace type name. For istance namespace type x.y.z will have two namespace scopes, the first is for the x and the second
/// is for the y.
/// </summary>
public IEnumerable<INamespaceScope> GetNamespaceScopes() {
foreach (var generatorScope in this.generatorLocalScopes) {
if (generatorScope.usedNamespaces.Count > 0)
yield return generatorScope;
}
}
/// <summary>
/// Returns an object that describes where synchronization points occur in the IL operations of the "MoveNext" method of
/// the state class of an async method. Returns null otherwise.
/// </summary>
public ISynchronizationInformation/*?*/ GetSynchronizationInformation() {
return this.synchronizationInformation;
}
/// <summary>
/// A list exception data within the method body IL.
/// </summary>
public IEnumerable<IOperationExceptionInformation> OperationExceptionInformation {
[ContractVerification(false)]
get { return this.operationExceptionInformation; }
}
readonly IEnumerable<IOperationExceptionInformation> operationExceptionInformation;
/// <summary>
/// True if the locals are initialized by zeroeing the stack upon method entry.
/// </summary>
public bool LocalsAreZeroed {
get { return this.localsAreZeroed; }
}
readonly bool localsAreZeroed;
/// <summary>
/// The local variables of the method.
/// </summary>
public IEnumerable<ILocalDefinition> LocalVariables {
[ContractVerification(false)]
get { return this.localVariables; }
}
readonly IEnumerable<ILocalDefinition> localVariables;
/// <summary>
/// The definition of the method whose body this is.
/// If this is the body of an event or property accessor, this will hold the corresponding adder/remover/setter or getter method.
/// </summary>
public IMethodDefinition MethodDefinition {
get { return this.methodDefinition; }
}
readonly IMethodDefinition methodDefinition;
/// <summary>
/// A list CLR IL operations that implement this method body.
/// </summary>
public IEnumerable<IOperation> Operations {
[ContractVerification(false)]
get { return this.operations; }
}
readonly IEnumerable<IOperation> operations;
/// <summary>
/// The maximum number of elements on the evaluation stack during the execution of the method.
/// </summary>
public ushort MaxStack {
get { return this.maxStack; }
}
readonly ushort maxStack;
/// <summary>
/// Any types that are implicitly defined in order to implement the body semantics.
/// In case of AST to instructions conversion this lists the types produced.
/// In case of instructions to AST decompilation this should ideally be list of all types
/// which are local to method.
/// </summary>
public IEnumerable<ITypeDefinition> PrivateHelperTypes {
[ContractVerification(false)]
get { return this.privateHelperTypes; }
}
readonly IEnumerable<ITypeDefinition> privateHelperTypes;
/// <summary>
/// The size in bytes of the method body when serialized.
/// </summary>
public uint Size {
get { return this.size; }
}
readonly uint size;
}
/// <summary>
/// An object that can provide information about the local scopes of a method and that can map ILocation objects
/// to IPrimarySourceLocation objects.
/// </summary>
public class ILGeneratorSourceInformationProvider : ILocalScopeProvider, ISourceLocationProvider {
/// <summary>
/// Returns zero or more local (block) scopes, each defining an IL range in which an iterator local is defined.
/// The scopes are returned by the MoveNext method of the object returned by the iterator method.
/// The index of the scope corresponds to the index of the local. Specifically local scope i corresponds
/// to the local stored in field &lt;localName&gt;x_i of the class used to store the local values in between
/// calls to MoveNext.
/// </summary>
public virtual IEnumerable<ILocalScope> GetIteratorScopes(IMethodBody methodBody) {
return Enumerable<ILocalScope>.Empty;
}
/// <summary>
/// Returns zero or more local (block) scopes into which the CLR IL operations in the given method body is organized.
/// </summary>
public virtual IEnumerable<ILocalScope> GetLocalScopes(IMethodBody methodBody) {
var ilGeneratorMethodBody = methodBody as ILGeneratorMethodBody;
if (ilGeneratorMethodBody == null) return Enumerable<ILocalScope>.Empty;
return ilGeneratorMethodBody.GetLocalScopes();
}
/// <summary>
/// Returns zero or more namespace scopes into which the namespace type containing the given method body has been nested.
/// These scopes determine how simple names are looked up inside the method body. There is a separate scope for each dotted
/// component in the namespace type name. For istance namespace type x.y.z will have two namespace scopes, the first is for the x and the second
/// is for the y.
/// </summary>
public virtual IEnumerable<INamespaceScope> GetNamespaceScopes(IMethodBody methodBody) {
var ilGeneratorMethodBody = methodBody as ILGeneratorMethodBody;
if (ilGeneratorMethodBody == null) return Enumerable<INamespaceScope>.Empty;
return ilGeneratorMethodBody.GetNamespaceScopes();
}
/// <summary>
/// Returns zero or more local constant definitions that are local to the given scope.
/// </summary>
public virtual IEnumerable<ILocalDefinition> GetConstantsInScope(ILocalScope scope) {
var ilGeneratorScope = scope as ILGeneratorScope;
if (ilGeneratorScope == null) return Enumerable<ILocalDefinition>.Empty;
return ilGeneratorScope.Constants;
}
/// <summary>
/// Returns zero or more local variable definitions that are local to the given scope.
/// </summary>
public virtual IEnumerable<ILocalDefinition> GetVariablesInScope(ILocalScope scope) {
var ilGeneratorScope = scope as ILGeneratorScope;
if (ilGeneratorScope == null) return Enumerable<ILocalDefinition>.Empty;
return ilGeneratorScope.Locals;
}
/// <summary>
/// Returns true if the method body is an iterator.
/// </summary>
public virtual bool IsIterator(IMethodBody methodBody) {
return false;
}
/// <summary>
/// If the given method body is the "MoveNext" method of the state class of an asynchronous method, the returned
/// object describes where synchronization points occur in the IL operations of the "MoveNext" method. Otherwise
/// the result is null.
/// </summary>
public ISynchronizationInformation/*?*/ GetSynchronizationInformation(IMethodBody methodBody) {
return null;
}
/// <summary>
/// Return zero or more locations in primary source documents that correspond to one or more of the given derived (non primary) document locations.
/// </summary>
public virtual IEnumerable<IPrimarySourceLocation> GetPrimarySourceLocationsFor(IEnumerable<ILocation> locations) {
foreach (var location in locations) {
IPrimarySourceLocation psloc = location as IPrimarySourceLocation;
if (psloc != null) yield return psloc;
}
}
/// <summary>
/// Return zero or more locations in primary source documents that correspond to the given derived (non primary) document location.
/// </summary>
public virtual IEnumerable<IPrimarySourceLocation> GetPrimarySourceLocationsFor(ILocation location) {
IPrimarySourceLocation psloc = location as IPrimarySourceLocation;
if (psloc != null) yield return psloc;
}
/// <summary>
/// Return zero or more locations in primary source documents that correspond to the definition of the given local.
/// </summary>
public virtual IEnumerable<IPrimarySourceLocation> GetPrimarySourceLocationsForDefinitionOf(ILocalDefinition localDefinition) {
return Enumerable<IPrimarySourceLocation>.Empty;
}
/// <summary>
/// Returns the source name of the given local definition, if this is available.
/// Otherwise returns the value of the Name property and sets isCompilerGenerated to true.
/// </summary>
public virtual string GetSourceNameFor(ILocalDefinition localDefinition, out bool isCompilerGenerated) {
isCompilerGenerated = false;
var generatorLocal = localDefinition as GeneratorLocal;
if (generatorLocal != null) isCompilerGenerated = generatorLocal.IsCompilerGenerated;
return localDefinition.Name.Value;
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsof.Cci.ILGenerator")]
[assembly: AssemblyDescription("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("64b687bd-39ec-4270-9ecf-6bfa09db035d")]

Просмотреть файл

@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.Contracts;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
/// <summary>
/// Class containing helper routines for Attributes
/// </summary>
public static class AttributeHelper {
/// <summary>
/// Returns true if the type definition is an attribute. Typedefinition is said to be attribute when it inherits from [mscorlib]System.Attribute
/// </summary>
public static bool IsAttributeType(ITypeDefinition typeDefinition) {
Contract.Requires(typeDefinition != null);
return TypeHelper.Type1DerivesFromType2(typeDefinition, typeDefinition.PlatformType.SystemAttribute);
}
/// <summary>
/// Returns true if the given collection of attributes contains an attribute of the given type.
/// </summary>
public static bool Contains(IEnumerable<ICustomAttribute> attributes, ITypeReference attributeType) {
Contract.Requires(attributes != null);
Contract.Requires(attributeType != null);
foreach (ICustomAttribute attribute in attributes) {
if (attribute == null) continue;
if (TypeHelper.TypesAreEquivalent(attribute.Type, attributeType)) return true;
}
return false;
}
/// <summary>
/// Specifies whether more than one instance of this type of attribute is allowed on same element.
/// This information is obtained from an attribute on the attribute type definition.
/// </summary>
public static bool AllowMultiple(ITypeDefinition attributeType, INameTable nameTable) {
Contract.Requires(attributeType != null);
Contract.Requires(nameTable != null);
foreach (ICustomAttribute ca in attributeType.Attributes) {
if (!TypeHelper.TypesAreEquivalent(ca.Type, attributeType.PlatformType.SystemAttributeUsageAttribute))
continue;
foreach (IMetadataNamedArgument namedArgument in ca.NamedArguments) {
if (namedArgument.ArgumentName.UniqueKey == nameTable.AllowMultiple.UniqueKey) {
IMetadataConstant/*?*/ compileTimeConst = namedArgument.ArgumentValue as IMetadataConstant;
if (compileTimeConst == null || compileTimeConst.Value == null || !(compileTimeConst.Value is bool))
continue;
//^ assume false; //Unboxing cast might fail
return (bool)compileTimeConst.Value;
}
}
}
return false;
}
/// <summary>
/// Specifies whether this attribute applies to derived types and/or overridden methods.
/// This information is obtained from an attribute on the attribute type definition.
/// </summary>
public static bool Inherited(ITypeDefinition attributeType, INameTable nameTable) {
Contract.Requires(attributeType != null);
Contract.Requires(nameTable != null);
foreach (ICustomAttribute ca in attributeType.Attributes) {
if (!TypeHelper.TypesAreEquivalent(ca.Type, attributeType.PlatformType.SystemAttributeUsageAttribute))
continue;
foreach (IMetadataNamedArgument namedArgument in ca.NamedArguments) {
if (namedArgument.ArgumentName.UniqueKey == nameTable.AllowMultiple.UniqueKey) {
IMetadataConstant/*?*/ compileTimeConst = namedArgument.ArgumentValue as IMetadataConstant;
if (compileTimeConst == null || compileTimeConst.Value == null || !(compileTimeConst.Value is bool))
continue;
//^ assume false; //Unboxing cast might fail
return (bool)compileTimeConst.Value;
}
}
}
return false;
}
/// <summary>
/// Specifies the symbol table elements on which it is valid to apply this attribute.
/// This information is obtained from an attribute on the attribute type definition.
/// </summary>
public static AttributeTargets ValidOn(ITypeDefinition attributeType) {
Contract.Requires(attributeType != null);
foreach (ICustomAttribute ca in attributeType.Attributes) {
if (!TypeHelper.TypesAreEquivalent(ca.Type, attributeType.PlatformType.SystemAttributeUsageAttribute))
continue;
foreach (IMetadataExpression expr in ca.Arguments) {
IMetadataConstant/*?*/ ctorParam = expr as IMetadataConstant;
if (ctorParam == null || ctorParam.Value == null || !(ctorParam.Value is int))
break;
//^ assume false; //Unboxing cast might fail
int val = (int)ctorParam.Value;
return (AttributeTargets)val;
}
}
return AttributeTargets.All;
}
}
}

Просмотреть файл

@ -0,0 +1,950 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using System.IO;
namespace Microsoft.Cci
{
/// <summary>
/// Subclass this class and define public fields for options
/// </summary>
[ContractVerification(false)]
public abstract class OptionParsing //TODO: move this to another assembly.
{
/// <summary>
/// Base constructor for building parseable options
/// </summary>
public OptionParsing()
{
this.requiredOptions = GatherRequiredOptions();
}
[ContractInvariantMethod]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
private void ObjectInvariant()
{
Contract.Invariant(this.generalArguments != null);
Contract.Invariant(this.errorMessages != null);
}
/// <summary>
/// The number of errors discovered during command-line option parsing.
/// </summary>
protected int errors = 0;
private bool helpRequested;
/// <summary>
/// True if and only if a question mark was given as a command-line option.
/// </summary>
public bool HelpRequested { get { return helpRequested; } }
/// <summary>
/// True if and only if some command-line option caused a parsing error, or specifies an option
/// that does not exist.
/// </summary>
public bool HasErrors { get { return errors > 0; } }
List<string> errorMessages = new List<string>();
/// <summary>
/// Allows a client to signal that there is an error in the command-line options.
/// </summary>
public void AddError() { this.errors++; }
/// <summary>
/// Allows a client to signal that there is an error in the command-line options.
/// </summary>
public void AddError(string format, params object[] args)
{
this.AddMessage(format, args);
this.errors++;
}
/// <summary>
/// Allows a client add a message to the output.
/// </summary>
public void AddMessage(string format, params object[] args)
{
this.errorMessages.Add(String.Format(format, args));
}
/// <summary>
/// The list of errors or other messages produced during parsing
/// </summary>
protected IEnumerable<string> Messages
{
get
{
Contract.Ensures(Contract.Result<IEnumerable<string>>() != null);
return this.errorMessages;
}
}
/// <summary>
/// Put this on fields if you want a more verbose help description
/// </summary>
protected class OptionDescription : Attribute
{
/// <summary>
/// The text that is shown when the usage is displayed.
/// </summary>
readonly public string Description;
/// <summary>
/// Constructor for creating the information about an option.
/// </summary>
public OptionDescription(string s) { this.Description = s; }
/// <summary>
/// Indicates whether the associated option is required or not.
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Indicates a short form for the option. Very useful for options
/// whose names are reserved keywords.
/// </summary>
public string ShortForm { get; set; }
}
/// <summary>
/// Put this on fields if you want the field to be relevant when hashing an Option object
/// </summary>
protected class OptionWitness : Attribute { }
/// <summary>
/// If a field has this attribute, then its value is inherited by all the family of analyses
/// </summary>
public class OptionValueOverridesFamily : Attribute { }
/// <summary>
/// A way to have a single option be a macro for several options.
/// </summary>
protected class OptionFor : Attribute
{
/// <summary>
/// The field that this option is a macro for.
/// </summary>
readonly public string options;
/// <summary>
/// Constructor for specifying which field this is a macro option for.
/// </summary>
public OptionFor(string options)
{
this.options = options;
}
}
/// <summary>
/// Override and return false if options do not start with '-' or '/'
/// </summary>
protected virtual bool UseDashOptionPrefix { get { return true; } }
/// <summary>
/// This field will hold non-option arguments
/// </summary>
readonly List<string> generalArguments = new List<string>();
private IList<string> requiredOptions;
/// <summary>
/// The non-option arguments provided on the command line.
/// </summary>
public List<string> GeneralArguments
{
get
{
Contract.Ensures(Contract.Result<List<string>>() != null);
return this.generalArguments;
}
}
#region Parsing and Reflection
/// <summary>
/// Called when reflection based resolution does not find option
/// </summary>
/// <param name="option">option name (no - or /)</param>
/// <param name="args">all args being parsed</param>
/// <param name="index">current index of arg</param>
/// <param name="optionEqualsArgument">null, or the optionArgument when option was option=optionArgument</param>
/// <returns>true if option is recognized, false otherwise</returns>
protected virtual bool ParseUnknown(string option, string[] args, ref int index, string optionEqualsArgument)
{
return false;
}
/// <summary>
/// Main method called by a client to process the command-line options.
/// </summary>
public void Parse(string[] args)
{
int index = 0;
while (index < args.Length)
{
string arg = args[index];
if (arg == "") { index++; continue; }
if (arg[0] == '@')
{
var responseFile = arg.Substring(1);
ParseResponseFile(responseFile);
}
else if (!UseDashOptionPrefix || arg[0] == '/' || arg[0] == '-')
{
if (UseDashOptionPrefix)
{
arg = arg.Remove(0, 1);
}
if (arg == "?")
{
this.helpRequested = true;
index++;
continue;
}
string equalArgument = null;
int equalIndex = arg.IndexOf(':');
if (equalIndex <= 0)
{
equalIndex = arg.IndexOf('=');
if (equalIndex < 0) // Also add '!' as synonim for '=', as cmd.exe performs fuzzy things with '='
equalIndex = arg.IndexOf('!');
}
if (equalIndex > 0)
{
equalArgument = arg.Substring(equalIndex + 1);
arg = arg.Substring(0, equalIndex);
}
bool optionOK = this.FindOptionByReflection(arg, args, ref index, equalArgument);
if (!optionOK)
{
optionOK = this.ParseUnknown(arg, args, ref index, equalArgument);
if (!optionOK)
{
AddError("Unknown option '{0}'", arg);
}
}
}
else
{
this.generalArguments.Add(arg);
}
index++;
}
if (!helpRequested) CheckRequiredOptions();
}
private void ParseResponseFile(string responseFile)
{
if (!File.Exists(responseFile))
{
AddError("Response file '{0}' does not exist.", responseFile);
return;
}
try
{
var lines = File.ReadAllLines(responseFile);
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i];
if (line.Length == 0) continue;
if (line[0] == '#') {
// comment skip
continue;
}
if (ContainsQuote(line))
{
Parse(SplitLineWithQuotes(responseFile, i, line));
}
else
{
// simple splitting
Parse(line.Split(' '));
}
}
}
catch
{
AddError("Failure reading from response file '{0}'.", responseFile);
}
}
private string[] SplitLineWithQuotes(string responseFileName, int lineNo, string line)
{
var start = 0;
var args = new List<string>();
bool inDoubleQuotes = false;
int escaping = 0; // number of escape characters in sequence
var currentArg = new StringBuilder();
for (var index = 0; index < line.Length; index++)
{
var current = line[index];
if (current == '\\')
{
// escape character
escaping++;
// swallow the escape character for now
// grab everything prior to prior escape character
if (index > start)
{
currentArg.Append(line.Substring(start, index - start));
}
start = index + 1;
continue;
}
if (escaping > 0)
{
if (current == '"')
{
var backslashes = escaping / 2;
for (int i = 0; i < backslashes; i++) { currentArg.Append('\\'); }
if (escaping % 2 == 1)
{
// escapes the "
currentArg.Append('"');
escaping = 0;
start = index + 1;
continue;
}
}
else
{
var backslashes = escaping;
for (int i = 0; i < backslashes; i++) { currentArg.Append('\\'); }
}
escaping = 0;
}
if (inDoubleQuotes)
{
if (current == '"')
{
// ending argument
FinishArgument(line, start, args, currentArg, index, true);
start = index + 1;
inDoubleQuotes = false;
continue;
}
}
else // not in quotes
{
if (Char.IsWhiteSpace(current))
{
// end previous, start new
FinishArgument(line, start, args, currentArg, index, false);
start = index + 1;
continue;
}
if (current == '"')
{
// starting double quote
if (index != start)
{
AddError("Response file '{0}' line {1}, char {2} contains '\"' not starting or ending an argument", responseFileName, lineNo, index);
}
start = index + 1;
inDoubleQuotes = true;
continue;
}
}
}
// add outstanding escape characters
while (escaping > 0) { currentArg.Append('\\'); escaping--; }
FinishArgument(line, start, args, currentArg, line.Length, inDoubleQuotes);
return args.ToArray();
}
private static void FinishArgument(string line, int start, List<string> args, StringBuilder currentArg, int index, bool includeEmpty)
{
currentArg.Append(line.Substring(start, index - start));
if (includeEmpty || currentArg.Length > 0)
{
args.Add(currentArg.ToString());
currentArg.Length = 0;
}
}
private bool ContainsQuote(string line)
{
var index = line.IndexOf('"');
if (index >= 0) return true;
index = line.IndexOf('\'');
if (index >= 0) return true;
return false;
}
private void CheckRequiredOptions()
{
foreach (var missed in this.requiredOptions)
{
AddError("Required option '-{0}' was not given.", missed);
}
}
private IList<string> GatherRequiredOptions()
{
List<string> result = new List<string>();
foreach (var field in this.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public))
{
var options = field.GetCustomAttributes(typeof(OptionDescription), false);
foreach (OptionDescription attr in options)
{
if (attr.Required)
{
result.Add(field.Name.ToLowerInvariant());
}
}
}
return result;
}
private bool ParseValue<T>(Converter<string, T> parser, string equalArgument, string[] args, ref int index, ref object result)
{
if (equalArgument == null)
{
if (index + 1 < args.Length)
{
equalArgument = args[++index];
}
}
bool success = false;
if (equalArgument != null)
{
try
{
result = parser(equalArgument);
success = true;
}
catch
{
}
}
return success;
}
private bool ParseValue<T>(Converter<string, T> parser, string argument, ref object result)
{
bool success = false;
if (argument != null)
{
try
{
result = parser(argument);
success = true;
}
catch
{
}
}
return success;
}
/// <summary>
/// A delegate that represents the various TryParse methods from int, bool, etc.
/// </summary>
public delegate bool TryParseConverter<in TInput, TOutput>(TInput input, out TOutput output);
private bool TryParseValue<T>(TryParseConverter<string, T> tryParser, string argument, ref T result) {
return (argument != null) ? tryParser(argument, out result) : false;
}
private object ParseValue(Type type, string argument, string option)
{
object result = null;
if (type == typeof(bool))
{
bool boolResult = false;
if (argument != null)
{
if (!TryParseValue<bool>(Boolean.TryParse, argument, ref boolResult))
{
// Allow "+/-" to turn on/off boolean options
if (argument.Equals("-"))
{
result = false;
}
else if (argument.Equals("+"))
{
result = true;
}
else
{
AddError("option -{0} requires a bool argument", option);
}
}
else
{
result = boolResult;
}
}
else
{
result = true;
}
}
else if (type == typeof(string))
{
if (!ParseValue<string>(s => s, argument, ref result))
{
AddError("option -{0} requires a string argument", option);
}
}
else if (type == typeof(int))
{
int intResult = 0;
if (!TryParseValue<int>(Int32.TryParse, argument, ref intResult))
{
AddError("option -{0} requires an int argument", option);
}
else
{
result = intResult;
}
}
else if (type.IsEnum)
{
if (!ParseValue<object>(ParseEnum(type), argument, ref result))
{
AddError("option -{0} expects one of", option);
foreach (System.Reflection.FieldInfo enumConstant in type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))
{
if (enumConstant.IsLiteral)
{
AddMessage(" {0}", enumConstant.Name);
}
}
}
}
return result;
}
string AdvanceArgumentIfNoExplicitArg(Type type, string explicitArg, string[] args, ref int index)
{
if (explicitArg != null) return explicitArg;
if (type == typeof(bool))
{
// bool args don't grab the next arg
return null;
}
if (index + 1 < args.Length)
{
return args[++index];
}
return null;
}
private bool FindOptionByReflection(string arg, string[] args, ref int index, string explicitArgument)
{
System.Reflection.FieldInfo fi = this.GetType().GetField(arg, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (fi != null)
{
this.requiredOptions.Remove(arg.ToLowerInvariant());
return ProcessOptionWithMatchingField(arg, args, ref index, explicitArgument, ref fi);
}
else
{
// derived options
fi = this.GetType().GetField(arg, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
if (fi != null)
{
object derived = fi.GetValue(this);
if (derived is string)
{
this.Parse(((string)derived).Split(' '));
this.requiredOptions.Remove(arg.ToLowerInvariant());
return true;
}
}
// Try to see if the arg matches any ShortForm of an option
var allFields = this.GetType().GetFields();
System.Reflection.FieldInfo matchingField = null;
foreach (var f in allFields)
{
matchingField = f;
var options = matchingField.GetCustomAttributes(typeof(OptionDescription), false);
foreach (OptionDescription attr in options)
{
if (attr.ShortForm != null)
{
var lower1 = attr.ShortForm.ToLowerInvariant();
var lower2 = arg.ToLowerInvariant();
if (lower1.Equals(lower2))
{
this.requiredOptions.Remove(matchingField.Name.ToLowerInvariant());
return ProcessOptionWithMatchingField(arg, args, ref index, explicitArgument, ref matchingField);
}
}
}
}
}
return false;
}
private bool ProcessOptionWithMatchingField(string arg, string[] args, ref int index, string explicitArgument, ref System.Reflection.FieldInfo fi)
{
Type type = fi.FieldType;
bool isList = false;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
isList = true;
type = type.GetGenericArguments()[0];
}
if (isList && explicitArgument == "!!")
{
// way to set list to empty
System.Collections.IList listhandle = (System.Collections.IList)fi.GetValue(this);
listhandle.Clear();
return true;
}
string argument = AdvanceArgumentIfNoExplicitArg(type, explicitArgument, args, ref index);
if (isList)
{
if (argument == null) {
AddError("option -{0} requires an argument", arg);
return true;
}
string[] listargs = argument.Split(';');
for (int i = 0; i < listargs.Length; i++)
{
if (listargs[i].Length == 0) continue; // skip empty values
bool remove = listargs[i][0] == '!';
string listarg = remove ? listargs[i].Substring(1) : listargs[i];
object value = ParseValue(type, listarg, arg);
if (value != null)
{
if (remove)
{
this.GetListField(fi).Remove(value);
}
else
{
this.GetListField(fi).Add(value);
}
}
}
}
else
{
object value = ParseValue(type, argument, arg);
if (value != null)
{
fi.SetValue(this, value);
string argname;
if (value is Int32 && HasOptionForAttribute(fi, out argname))
{
this.Parse(DerivedOptionFor(argname, (Int32)value).Split(' '));
}
}
}
return true;
}
private bool HasOptionForAttribute(System.Reflection.FieldInfo fi, out string argname)
{
var options = fi.GetCustomAttributes(typeof(OptionFor), true);
if (options != null && options.Length == 1)
{
argname = ((OptionFor)options[0]).options;
return true;
}
argname = null;
return false;
}
/// <summary>
/// For the given field, returns the derived option that is indexed by
/// option in the list of derived options.
/// </summary>
protected string DerivedOptionFor(string fieldWithOptions, int option)
{
string[] options;
if (TryGetOptions(fieldWithOptions, out options))
{
if (option < 0 || option >= options.Length)
{
return "";
}
return options[option];
}
return "";
}
/// <summary>
/// Returns the options associated with the field, specified as a string.
/// If there are none, options is set to null and false is returned.
/// </summary>
protected bool TryGetOptions(string fieldWithOptions, out string[] options)
{
var fi = this.GetType().GetField(fieldWithOptions,
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Public);
if (fi != null)
{
var obj = fi.GetValue(this);
if (obj is string[])
{
options = (string[])obj;
return true;
}
}
options = null;
return false;
}
/// <summary>
/// Use this
/// </summary>
public long GetCheckCode()
{
var res = 0L;
foreach (var f in this.GetType().GetFields())
{
foreach (var a in f.GetCustomAttributes(true))
{
if (a is OptionWitness)
{
res += (f.GetValue(this).GetHashCode()) * f.GetHashCode();
break;
}
}
}
return res;
}
Converter<string, object> ParseEnum(Type enumType)
{
return delegate(string s) { return Enum.Parse(enumType, s, true); };
}
System.Collections.IList GetListField(System.Reflection.FieldInfo fi)
{
object obj = fi.GetValue(this);
if (obj != null) { return (System.Collections.IList)obj; }
System.Collections.IList result = (System.Collections.IList)fi.FieldType.GetConstructor(new Type[] { }).Invoke(new object[] { });
fi.SetValue(this, result);
return result;
}
/// <summary>
/// Writes all of the options out to the console.
/// </summary>
public void PrintOptions(string indent)
{
foreach (System.Reflection.FieldInfo f in this.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
System.Type opttype = f.FieldType;
bool isList;
if (opttype.IsGenericType && opttype.GetGenericTypeDefinition() == typeof(List<>))
{
opttype = opttype.GetGenericArguments()[0];
isList = true;
}
else
{
isList = false;
}
string description = GetOptionAttribute(f);
string option = null;
if (opttype == typeof(bool))
{
if (!isList && f.GetValue(this).Equals(true))
{
option = String.Format("{0} (default=true)", f.Name);
}
else
{
option = f.Name;
}
}
else if (opttype == typeof(string))
{
if (!f.IsLiteral)
{
object defaultValue = f.GetValue(this);
if (!isList && defaultValue != null)
{
option = String.Format("{0} <string-arg> (default={1})", f.Name, defaultValue);
}
else
{
option = String.Format("{0} <string-arg>", f.Name);
}
}
}
else if (opttype == typeof(int))
{
if (!isList)
{
option = String.Format("{0} <int-arg> (default={1})", f.Name, f.GetValue(this));
}
else
{
option = String.Format("{0} <int-arg>", f.Name);
}
}
else if (opttype.IsEnum)
{
StringBuilder sb = new StringBuilder();
sb.Append(f.Name).Append(" (");
bool first = true;
foreach (System.Reflection.FieldInfo enumConstant in opttype.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
{
if (enumConstant.IsLiteral)
{
if (!first)
{
if (isList)
{
sb.Append(" + ");
}
else
{
sb.Append(" | ");
}
}
else
{
first = false;
}
sb.Append(enumConstant.Name);
}
}
sb.Append(") ");
if (!isList)
{
sb.AppendFormat("(default={0})", f.GetValue(this));
}
else
{
sb.Append("(default=");
bool first2 = true;
foreach (object eval in (System.Collections.IEnumerable)f.GetValue(this))
{
if (!first2)
{
sb.Append(',');
}
else
{
first2 = false;
}
sb.Append(eval.ToString());
}
sb.Append(')');
}
option = sb.ToString();
}
if (option != null)
{
Console.Write("{1} -{0,-30}", option, indent);
if (description != null)
{
Console.WriteLine(" : {0}", description);
}
else
{
Console.WriteLine();
}
}
}
Console.WriteLine(Environment.NewLine + "To clear a list, use -<option>=!!");
Console.WriteLine(Environment.NewLine + "To remove an item from a list, use -<option> !<item>");
}
/// <summary>
/// Prints all of the derived options to the console.
/// </summary>
public void PrintDerivedOptions(string indent)
{
foreach (System.Reflection.FieldInfo f in this.GetType().GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))
{
if (f.IsLiteral)
{
Console.WriteLine("{2} -{0} is '{1}'", f.Name, f.GetValue(this), indent);
}
}
}
private string GetOptionAttribute(System.Reflection.FieldInfo f)
{
object[] attrs = f.GetCustomAttributes(typeof(OptionDescription), true);
if (attrs != null && attrs.Length == 1)
{
StringBuilder result = new StringBuilder();
OptionDescription descr = (OptionDescription)attrs[0];
if (descr.Required)
{
result.Append("(required) ");
}
result.Append(descr.Description);
if (descr.ShortForm != null)
{
result.Append("[short form: " + descr.ShortForm + "]");
}
object[] optionsFor = f.GetCustomAttributes(typeof(OptionFor), true);
string[] options;
if (optionsFor != null && optionsFor.Length == 1 && TryGetOptions(((OptionFor)optionsFor[0]).options, out options))
{
result.AppendLine(Environment.NewLine + "Detailed explanation:");
for (int i = 0; i < options.Length; i++)
{
result.Append(string.Format("{0} : {1}" + Environment.NewLine, i, options[i]));
}
}
return result.ToString();
}
return null;
}
#endregion
/// <summary>
/// Call this when HasErrors is true
/// It will print the errors on the given output and then exit the process with Environment.Exit(-1)
/// </summary>
/// <param name="output">Output stream for messages</param>
public void PrintErrorsAndExit(TextWriter output)
{
foreach (string message in this.errorMessages)
{
output.WriteLine(message);
}
output.WriteLine();
output.WriteLine(" use /? to see a list of options");
Environment.Exit(-1);
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,414 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AliasedTypeDoesNotBelongToAModule" xml:space="preserve">
<value>The type referenced by this alias does not come from a module of this assembly.</value>
</data>
<data name="ContainingAliasNotListedInExportedTypes" xml:space="preserve">
<value>This type alias is referenced as the parent of an exported type alias, but does not itself appear in the ExportedTypes property of the assembly.</value>
</data>
<data name="EmptyName" xml:space="preserve">
<value>This node may not have an empty name.</value>
</data>
<data name="ExportedTypeBelongsToManifestModule" xml:space="preserve">
<value>This type alias references a type that is defined in the module that contains the assembly manifest. The public types of such modules are already exported and should not be explicitly exported via the ExportedTypes collection of the assembly.</value>
</data>
<data name="IncompleteNode" xml:space="preserve">
<value>The node has not been fully initialized. Property {0} has a dummy value.</value>
</data>
<data name="InvalidCulture" xml:space="preserve">
<value>The assembly culture string "{0}" does not match one of the strings allowed by the specification.</value>
</data>
<data name="NonPublicTypeAlias" xml:space="preserve">
<value>A nested type can only be aliased (exported) if it is public.</value>
</data>
<data name="NotPosixName" xml:space="preserve">
<value>The name "{0}" is not POSIX compliant because it contains a colon, forward-slash, backslash, or period.</value>
</data>
<data name="ReferenceToTypeAlias" xml:space="preserve">
<value>Imported type aliases may not appear directly in the metadata model. Instead refer to the aliased type via the value of the IAliasForType.AliasedType property.</value>
</data>
<data name="UnexpectedAliasMember" xml:space="preserve">
<value>This type alias member is not itself a nested type alias.</value>
</data>
<data name="UnknownAssemblyFlags" xml:space="preserve">
<value>The assembly's Flags property has bits set that are not valid according to the specification.</value>
</data>
<data name="AbstractMethodMayNotBeSealedPlatformInvokeOrForwardReference" xml:space="preserve">
<value>An abstract method may not be marked as being sealed or as a platform invoke method or as being a forward reference.</value>
</data>
<data name="AbstractMethodsMustBeVirtual" xml:space="preserve">
<value>An abstract method must be marked as being virtual.</value>
</data>
<data name="AutoLayoutTypesCannotSpecifySize" xml:space="preserve">
<value>The size of a type can only be specified if the type does not have its LayoutKind set to Auto.</value>
</data>
<data name="ConstantFieldMustBeStatic" xml:space="preserve">
<value>This field is a compile time constant but it is not marked as static.</value>
</data>
<data name="ConstraintMayNotBeVoid" xml:space="preserve">
<value>A constraint on a generic parameter may not reference System.Void.</value>
</data>
<data name="ConstructorInInterface" xml:space="preserve">
<value>Constructor methods may not be members of interface types.</value>
</data>
<data name="ConstructorsMustNotReturnValues" xml:space="preserve">
<value>Constructor methods may not return values. I.e. their return type must be System.Void.</value>
</data>
<data name="ContainingTypeDefinitionNotVisited" xml:space="preserve">
<value>This type member is being visited before its parent is being visited, which can only happen if its ContainingTypeDefinition value is not valid.</value>
</data>
<data name="CustomAttributeConstructorIsBadReference" xml:space="preserve">
<value>The custom attribute's Constructor property references a method that resolves to something other than a constructor.</value>
</data>
<data name="CustomAttributeTypeIsNotConstructorContainer" xml:space="preserve">
<value>The Type of the custom attribute is not the same as the containing type of the custom attribute's Constructor.</value>
</data>
<data name="DeclarativeSecurityOnInterfacesIsIgnored" xml:space="preserve">
<value>Declarative security annotations on interface types are ignored by the CLR.</value>
</data>
<data name="DerivedTypeHasDifferentLayoutFromBaseType" xml:space="preserve">
<value>A derived type with LayoutKind other than Auto must have the same LayoutKind as its base type, unless its base type is System.Object.</value>
</data>
<data name="DuplicateAssemblyReference" xml:space="preserve">
<value>The module's assembly references list contains a duplicate entry.</value>
</data>
<data name="DuplicateConstraint" xml:space="preserve">
<value>This constraint has already been encountered during the traversal of its defining generic parameters' Constraints collection.</value>
</data>
<data name="DuplicateDefinition" xml:space="preserve">
<value>This definition has already been encountered during the traversal of the module being validated.</value>
</data>
<data name="DuplicateEntryInAllTypes" xml:space="preserve">
<value>The list of types returned by calling GetAllTypes on the module being validated contains a duplicate entry.</value>
</data>
<data name="DuplicateEvent" xml:space="preserve">
<value>This event is listed more than once, or has the same name as another event of its containing type definition.</value>
</data>
<data name="DuplicateField" xml:space="preserve">
<value>This field is listed more than once, or has the same name and signature as another field of its containing type definition.</value>
</data>
<data name="DuplicateFileReference" xml:space="preserve">
<value>This file reference instance occurs more than once, or has the same file name as another file reference in the Files collection of its contaiing assembly.</value>
</data>
<data name="DuplicateGenericTypeParameter" xml:space="preserve">
<value>This generic type parameter occurs more than once, or has the same InternedKey as another type parameter, in the GenericParameters collection of its defining type.</value>
</data>
<data name="DuplicateInterface" xml:space="preserve">
<value>This interface occurs more than once, or there is another interface with same InternedKey, in the Interfaces collection of the type definition.</value>
</data>
<data name="DuplicateMethodGenericTypeParameter" xml:space="preserve">
<value>This generic method type parameter occurs more than once, or has the same InternedKey as another type parameter, in the GenericParameters collection of its defining method.</value>
</data>
<data name="DuplicateResource" xml:space="preserve">
<value>This resource reference occurs more than once, or there is another reference with the same name, in the Resources collection of the assembly.</value>
</data>
<data name="EnumerationCountIsInconsistentWithCountProperty" xml:space="preserve">
<value>The actual number of elements is not the same as the number of elements specified by the {0} property.</value>
</data>
<data name="ExplicitOverrideDoesNotMatchSignatureOfOverriddenMethod" xml:space="preserve">
<value>This method implementation (or explicit override) has an implemeting method that does not match the signature of the implemented method.</value>
</data>
<data name="FieldMayNotBeConstantAndReadonly" xml:space="preserve">
<value>A field may not be both a compile time constant and readonly.</value>
</data>
<data name="FieldOffsetNotNaturallyAlignedForObjectRef" xml:space="preserve">
<value>The offset of this field must be naturally aligned because its value is an object reference.</value>
</data>
<data name="FieldReferenceResolvesToDifferentField" xml:space="preserve">
<value>This field reference resolves to a field definition with a different InternedKey value.</value>
</data>
<data name="GenericConstructor" xml:space="preserve">
<value>This method is a constructor but is also generic. That is not allowed.</value>
</data>
<data name="GenericParameterCountDoesNotMatchGenericParameters" xml:space="preserve">
<value>The value of GenericParameterCount does not match the number of parameters in the GenericParameters collection.</value>
</data>
<data name="GetAllTypesIsIncomplete" xml:space="preserve">
<value>A type definition is being visited that is not an element of the list returned by calling GetAllTypes on the module being validated.</value>
</data>
<data name="InstanceConstructorMayNotBeStatic" xml:space="preserve">
<value>An instance constructor (a method with the name .ctor) may not be marked as static. After all, it is supposed initialize its this object...</value>
</data>
<data name="InvalidAlignment" xml:space="preserve">
<value>The given type alignment, {0}, is invalid. A valid alignment is one of 0, 1, 2, 4, 8, 16, 32, 64, 128.</value>
</data>
<data name="InvalidCustomModifier" xml:space="preserve">
<value>Only references to named types may appear in custom modifiers.</value>
</data>
<data name="InvalidGlobalFieldVisibility" xml:space="preserve">
<value>This global field has a visibility that only makes sense for type members.</value>
</data>
<data name="InvalidMetadataConstant" xml:space="preserve">
<value>The value of a IMetadataConstant instance must be a bool, char, number, string, or a null object.</value>
</data>
<data name="MappedFieldDoesNotHaveAValidType" xml:space="preserve">
<value>This field is mapped to a static data area in its PE file, but its type is not a value type or it has fields that are not public or that contain pointers into the managed heap.</value>
</data>
<data name="MemberDisagreesAboutContainer" xml:space="preserve">
<value>This member definition thinks its containing definition is a different object than the one listing it as a member.</value>
</data>
<data name="MethodCannotBeAnOverride" xml:space="preserve">
<value>This method is not virtual, or it has no body, so it cannot serve as the explicit override or implementation of a base class or interface method.</value>
</data>
<data name="MethodGenericTypeParameterCountMismatch" xml:space="preserve">
<value>The value of GenericParameterCount does not match the number of parameters in the GenericParameters collection of the method.</value>
</data>
<data name="MethodMarkedAsHavingDeclarativeSecurityHasNoSecurityAttributes" xml:space="preserve">
<value>This method definition is marked has having declarative security, but it has no security attributes and no SuppressUnmanagedCodeSecurityAttribute.</value>
</data>
<data name="MethodParameterCountDoesNotAgreeWithTheActualNumberOfParameters" xml:space="preserve">
<value>The value of ParameterCount does not match the number of parameters in the Parameters collection.</value>
</data>
<data name="MethodsCalledWithExplicitThisParametersMustNotBeStatic" xml:space="preserve">
<value>A method that are called with an explicit this parameter (via a function pointer) must actually have a this parameter.</value>
</data>
<data name="MethodsNamedLikeConstructorsMustBeMarkedAsRuntimeSpecial" xml:space="preserve">
<value>A method named .ctor or .cctor must also be marked as special name and runtime special.</value>
</data>
<data name="MethodWithSecurityAttributesMustBeMarkedAsHavingDeclarativeSecurity" xml:space="preserve">
<value>The method definition is not marked as having declarative security, but it has security attributes or a SuppressUnmanagedCodeSecurityAttribute.</value>
</data>
<data name="NamedArgumentNameDoesNotMatchNameOfResolvedFieldOrProperty" xml:space="preserve">
<value>The named argument's name does not match the name of the field or property that the argument resolves to.</value>
</data>
<data name="NamedArgumentTypeDoesNotMatchTypeOfResolvedFieldOrProperty" xml:space="preserve">
<value>The named argument's Type does not match the Type of the field or property that the argument resolves to.</value>
</data>
<data name="NonStaticPlatformInvokeMethod" xml:space="preserve">
<value>This method has platform invoke information but it is not marked as static.</value>
</data>
<data name="NotPosixAssemblyName" xml:space="preserve">
<value>The assembly name "{0}" is not POSIX compliant because it contains a colon, forward-slash, backslash, or period.</value>
</data>
<data name="OnlySequentialLayoutTypesCanSpecificyAlignment" xml:space="preserve">
<value>Only types that have LayoutKind set to SequentialLayout are permitted to specify a non zero value for Alignment.</value>
</data>
<data name="ReferenceToTypeMemberWithOtherVisibility" xml:space="preserve">
<value>The given type member reference resolves to a type member (i.e. method or field) that has Other visibility (visible only to the compiler).</value>
</data>
<data name="RuntimeSpecialMustAlsoBeSpecialName" xml:space="preserve">
<value>A RuntimeSpecial member must also have its SpecialName flag set.</value>
</data>
<data name="SealedNewSlotOrOverrideMethodsMustAlsoBeVirtual" xml:space="preserve">
<value>It only makes sense to mark a method as sealed, new slot or access checked on override, if the method is virtual.</value>
</data>
<data name="SelfReference" xml:space="preserve">
<value>An assembly may not reference the file that contains the assembly's manifest module (the one being analyzed).</value>
</data>
<data name="SingleFileAssemblyHasExportedTypes" xml:space="preserve">
<value>A single file assembly may not explicitly export types. The public types of the manifest module of any assembly are exported by default.</value>
</data>
<data name="SpecialMethodsMayNotHaveCompilerControlledVisibility" xml:space="preserve">
<value>A method marked as SpecialName or as RuntimeSpecial may not be visible only to the compiler.</value>
</data>
<data name="StaticConstructorMayNotHaveParameters" xml:space="preserve">
<value>A static constructor may not have any parameters since it is invoked implicitly.</value>
</data>
<data name="StaticConstructorMustBeStatic" xml:space="preserve">
<value>Uhm, a static constructor (a method with the name .cctor) must be marked as being static, because well, its a static constructor.</value>
</data>
<data name="StaticMethodMayNotBeSealedVirtualOrNewSlot" xml:space="preserve">
<value>A static method may not be marked as sealed, virtual, new slot.</value>
</data>
<data name="StructsSizeMustBeLessThanOneMegaByte" xml:space="preserve">
<value>The given size, {0}, is too large for a value type (struct). The size must be less than 1 MByte (0x100000).</value>
</data>
<data name="SynchronizedValueTypeMethod" xml:space="preserve">
<value>A method defined by a value type operates on an object without identity, therefore it makes no sense to mark it as synchronized.</value>
</data>
<data name="TypeReferenceResolvesToDifferentType" xml:space="preserve">
<value>Resolving the type reference results in a type with a different InternedKey from the type reference and no aliasing is involved.</value>
</data>
<data name="MayNotOverrideInaccessibleMethod" xml:space="preserve">
<value>The method being implemented by an explicit override is not visible to the class doing the overriding, which is not allowed.</value>
</data>
<data name="EnumDoesNotHaveAnInstanceField" xml:space="preserve">
<value>An enum type must have a single instance field of an integral type.</value>
</data>
<data name="EnumInstanceFieldNotUnique" xml:space="preserve">
<value>An enum type may only have a single instance field.</value>
</data>
<data name="EnumInstanceFieldTypeNotIntegral" xml:space="preserve">
<value>The instance field of an enum must be of an integral type.</value>
</data>
<data name="EventTypeMustBeClass" xml:space="preserve">
<value>The type of an event may not be an interface or a value type.</value>
</data>
<data name="InvalidSecurityAction" xml:space="preserve">
<value>The security action value is not valid.</value>
</data>
<data name="InvalidTypeMemberVisibility" xml:space="preserve">
<value>The value of the ITypeMember.Visibility is not valid.</value>
</data>
<data name="MetadataConstantTypeMismatch" xml:space="preserve">
<value>This metadata constant value has a type that is incompatible with the type of the field, parameter or property.</value>
</data>
<data name="SecurityActionMismatch" xml:space="preserve">
<value>The security action of the security attribute is not compatible with the definition to which the attribute is applied.</value>
</data>
<data name="SecurityAttributeOnInterface" xml:space="preserve">
<value>Security attributes on interfaces are ignored by the security system.</value>
</data>
<data name="StaticFieldsMayNotHaveLayout" xml:space="preserve">
<value>A static field should not have layout information since it does not contribute to the layout of its containing type.</value>
</data>
<data name="TypeReferenceResolvesToDifferentTypeFromAlias" xml:space="preserve">
<value>Resolving the type reference results in a type with a different InternedKey from the resolved value of the TypeAlias property.</value>
</data>
<data name="ArraysMarshalledToFieldsCannotSpecifyElementCountParameter" xml:space="preserve">
<value>It makes no sense for the marshalling information for a field to specify which parameter to use for the element count of an array value.</value>
</data>
<data name="MarshalledArraysMustHaveSizeKnownAtCompileTime" xml:space="preserve">
<value>Fields whose values are marshalled to unmanaged arrays, must specify the size of the array at compile time since there is no place in the unmanaged array for the marshaller to store the number of elements.</value>
</data>
<data name="MarshallingInformationIsInvalid" xml:space="preserve">
<value>IMarshallingInformation.{0} has an invalid value.</value>
</data>
<data name="ParameterCannotBeMarshalledAsByValArray" xml:space="preserve">
<value>Only field values can be marshalled as ByVal (fixed length) arrays.</value>
</data>
<data name="ParameterIndexIsInvalid" xml:space="preserve">
<value>The index of the parameter to contain the size of the variable portion of an array that is marshalled as an unmanaged array is out of range.</value>
</data>
<data name="ParameterMarshalledArraysMustHaveSizeKnownAtCompileTime" xml:space="preserve">
<value>Parameters whose values are marshalled to unmanaged arrays and for which the marshalling information does not specify a parameter to convey the number of array elements, must specify the size of the array at compile time since there is no place in the unmanaged array for the marshaller to store the number of elements.</value>
</data>
<data name="NumberOfElementsSpecifiedExplicitlyAsWellAsByAParameter" xml:space="preserve">
<value>The size of the array passed in this parameter is specified explicitly as well as via another (size) parameter. This is probably a mistake.</value>
</data>
<data name="InvalidMetadataFormatVersionForGenerics" xml:space="preserve">
<value>Bad module metadata format version. Found '{0}', should be at least 2.</value>
</data>
<data name="StructSizeMustBeNonZero" xml:space="preserve">
<value>A struct must have a non-zero size.</value>
</data>
<data name="ContainingNamespaceDefinitionNotVisited" xml:space="preserve">
<value>This namespace member is being visited before its parent is being visited, which can only happen if its ContainingNamespace value is not valid.</value>
</data>
<data name="AccessorListInconsistent" xml:space="preserve">
<value>No method found in the accessor list that is a {0}.</value>
</data>
<data name="InitLocalsMustBeTrueIfLocalVariables" xml:space="preserve">
<value>The method has local variables, but LocalsAreZeroed is not true.</value>
</data>
<data name="EventPropertyNamingPatternWarning" xml:space="preserve">
<value>An accessor method does not follow the naming conventions.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,121 @@
using Microsoft.Cci;
using System;
using System.Diagnostics.Contracts;
/// <summary>
/// Class containing helper routines for IMetadataExpression expressions.
/// </summary>
public static class MetadataExpressionHelper {
/// <summary>
/// Returns true if the given constant expression contains a finite numeric value. In other words, infinities and NaN are excluded.
/// </summary>
/// <param name="constExpression"></param>
/// <returns></returns>
public static bool IsFiniteNumeric(IMetadataConstant constExpression) {
IConvertible/*?*/ ic = constExpression.Value as IConvertible;
if (ic == null) return false;
switch (ic.GetTypeCode()) {
case System.TypeCode.SByte:
case System.TypeCode.Int16:
case System.TypeCode.Int32:
case System.TypeCode.Int64:
case System.TypeCode.Byte:
case System.TypeCode.UInt16:
case System.TypeCode.UInt32:
case System.TypeCode.UInt64:
return true;
case System.TypeCode.Double:
var d = ic.ToDouble(null);
return !(Double.IsNaN(d) || Double.IsInfinity(d));
case System.TypeCode.Single:
var s = ic.ToSingle(null);
return !(Single.IsNaN(s) || Single.IsInfinity(s));
}
return false;
}
/// <summary>
/// True if the value is a boxed -1 of type byte, int, long, sbyte, short, uint, ulong or ushort.
/// </summary>
[Pure]
public static bool IsIntegralMinusOne(IMetadataConstant constExpression) {
IConvertible/*?*/ ic = constExpression.Value as IConvertible;
if (ic == null) return false;
switch (ic.GetTypeCode()) {
case System.TypeCode.SByte: return ic.ToSByte(null) == -1;
case System.TypeCode.Int16: return ic.ToInt16(null) == -1;
case System.TypeCode.Int32: return ic.ToInt32(null) == -1;
case System.TypeCode.Int64: return ic.ToInt64(null) == -1;
case System.TypeCode.Byte: return ic.ToByte(null) == byte.MaxValue;
case System.TypeCode.UInt16: return ic.ToUInt16(null) == ushort.MaxValue;
case System.TypeCode.UInt32: return ic.ToUInt32(null) == uint.MaxValue;
case System.TypeCode.UInt64: return ic.ToUInt64(null) == ulong.MaxValue;
}
return false;
}
/// <summary>
/// True if the value is a boxed zero of type byte, int, long, sbyte, short, uint, ulong, ushort or bool that is not equal to 0.
/// </summary>
[Pure]
public static bool IsIntegralNonzero(IMetadataConstant constExpression) {
IConvertible/*?*/ ic = constExpression.Value as IConvertible;
if (ic == null) return false;
switch (ic.GetTypeCode()) {
case System.TypeCode.SByte: return ic.ToSByte(null) != 0;
case System.TypeCode.Int16: return ic.ToInt16(null) != 0;
case System.TypeCode.Int32: return ic.ToInt32(null) != 0;
case System.TypeCode.Int64: return ic.ToInt64(null) != 0;
case System.TypeCode.Byte: return ic.ToByte(null) != 0;
case System.TypeCode.UInt16: return ic.ToUInt16(null) != 0;
case System.TypeCode.UInt32: return ic.ToUInt32(null) != 0;
case System.TypeCode.UInt64: return ic.ToUInt64(null) != 0;
case System.TypeCode.Boolean: return ic.ToBoolean(null);
}
return false;
}
/// <summary>
/// True if the value is a boxed 1 of type byte, int, long, sbyte, short, uint, ulong, ushort or bool.
/// </summary>
[Pure]
public static bool IsIntegralOne(IMetadataConstant constExpression) {
IConvertible/*?*/ ic = constExpression.Value as IConvertible;
if (ic == null) return false;
switch (ic.GetTypeCode()) {
case System.TypeCode.SByte: return ic.ToSByte(null) == 1;
case System.TypeCode.Int16: return ic.ToInt16(null) == 1;
case System.TypeCode.Int32: return ic.ToInt32(null) == 1;
case System.TypeCode.Int64: return ic.ToInt64(null) == 1;
case System.TypeCode.Byte: return ic.ToByte(null) == 1;
case System.TypeCode.UInt16: return ic.ToUInt16(null) == 1;
case System.TypeCode.UInt32: return ic.ToUInt32(null) == 1;
case System.TypeCode.UInt64: return ic.ToUInt64(null) == 1;
case System.TypeCode.Boolean: return ic.ToBoolean(null);
}
return false;
}
/// <summary>
/// True if the value is a boxed zero of type byte, int, long, sbyte, short, uint, ulong, ushort or bool.
/// </summary>
[Pure]
public static bool IsIntegralZero(IMetadataConstant constExpression) {
IConvertible/*?*/ ic = constExpression.Value as IConvertible;
if (ic == null) return false;
switch (ic.GetTypeCode()) {
case System.TypeCode.SByte: return ic.ToSByte(null) == 0;
case System.TypeCode.Int16: return ic.ToInt16(null) == 0;
case System.TypeCode.Int32: return ic.ToInt32(null) == 0;
case System.TypeCode.Int64: return ic.ToInt64(null) == 0;
case System.TypeCode.Byte: return ic.ToByte(null) == 0;
case System.TypeCode.UInt16: return ic.ToUInt16(null) == 0;
case System.TypeCode.UInt32: return ic.ToUInt32(null) == 0;
case System.TypeCode.UInt64: return ic.ToUInt64(null) == 0;
case System.TypeCode.Boolean: return !ic.ToBoolean(null);
}
return false;
}
}

Просмотреть файл

@ -0,0 +1,441 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
/// <summary>
/// Contains helper routines to query the GAC for the presence and locations of assemblies.
/// </summary>
[ContractVerification(false)]
public static class GlobalAssemblyCache {
#if !COMPACTFX && !__MonoCS__
private static bool FusionLoaded;
#endif
//TODO: when loading Fusion, just enumerate the GAC and keep a static copy of the GAC. Release the assembly enumerator as soon as possible.
/// <summary>
/// Determines whether the GAC contains the specified code base URI.
/// </summary>
/// <param name="codeBaseUri">The code base URI.</param>
public static bool Contains(Uri codeBaseUri) {
Contract.Requires(codeBaseUri != null);
lock (GlobalLock.LockingObject) {
#if COMPACTFX
var gacKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"\Software\Microsoft\.NETCompactFramework\Installer\Assemblies\Global");
if (gacKey == null) return false;
var codeBase = codeBaseUri.AbsoluteUri;
foreach (var gacName in gacKey.GetValueNames()) {
var values = gacKey.GetValue(gacName) as string[];
if (values == null || values.Length == 0) continue;
if (string.Equals(values[0], codeBase, StringComparison.OrdinalIgnoreCase)) return true;
if (values.Length > 1 && string.Equals(values[1], codeBase, StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
#else
#if __MonoCS__
IAssemblyEnum assemblyEnum = new MonoAssemblyEnum();
#else
if (!GlobalAssemblyCache.FusionLoaded) {
GlobalAssemblyCache.FusionLoaded = true;
var systemAssembly = typeof(object).Assembly;
var systemAssemblyLocation = systemAssembly.Location;
string dir = Path.GetDirectoryName(systemAssemblyLocation)??"";
GlobalAssemblyCache.LoadLibrary(Path.Combine(dir, "fusion.dll"));
}
IAssemblyEnum assemblyEnum;
int rc = GlobalAssemblyCache.CreateAssemblyEnum(out assemblyEnum, null, null, ASM_CACHE.GAC, 0);
if (rc < 0 || assemblyEnum == null) return false;
#endif
IApplicationContext applicationContext;
IAssemblyName currentName;
while (assemblyEnum.GetNextAssembly(out applicationContext, out currentName, 0) == 0) {
//^ assume currentName != null;
AssemblyName assemblyName = new AssemblyName(currentName);
string/*?*/ scheme = codeBaseUri.Scheme;
if (scheme != null && assemblyName.CodeBase.StartsWith(scheme, StringComparison.OrdinalIgnoreCase)) {
try {
Uri foundUri = new Uri(assemblyName.CodeBase);
if (codeBaseUri.Equals(foundUri)) return true;
} catch (System.ArgumentNullException) {
} catch (System.UriFormatException) {
}
}
}
return false;
#endif
}
}
/// <summary>
/// Returns the original location of the corresponding assembly if available, otherwise returns the location of the shadow copy.
/// If the corresponding assembly is not in the GAC, null is returned.
/// </summary>
public static string/*?*/ GetLocation(AssemblyIdentity assemblyIdentity, IMetadataHost metadataHost) {
lock (GlobalLock.LockingObject) {
#if COMPACTFX
var gacKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"\Software\Microsoft\.NETCompactFramework\Installer\Assemblies\Global");
foreach (var gacName in gacKey.GetValueNames()) {
if (IdentityMatchesString(assemblyIdentity, gacName)) {
var values = gacKey.GetValue(gacName) as string[];
if (values == null || values.Length == 0) continue;
return values[0];
}
}
return null;
#else
#if __MonoCS__
IAssemblyEnum assemblyEnum = new MonoAssemblyEnum();
#else
if (!GlobalAssemblyCache.FusionLoaded) {
GlobalAssemblyCache.FusionLoaded = true;
var systemAssembly = typeof(object).Assembly;
var systemAssemblyLocation = systemAssembly.Location;
var dir = Path.GetDirectoryName(systemAssemblyLocation)??"";
GlobalAssemblyCache.LoadLibrary(Path.Combine(dir, "fusion.dll"));
}
IAssemblyEnum assemblyEnum;
int rc = CreateAssemblyEnum(out assemblyEnum, null, null, ASM_CACHE.GAC, 0);
if (rc < 0 || assemblyEnum == null) return null;
#endif
IApplicationContext applicationContext;
IAssemblyName currentName;
while (assemblyEnum.GetNextAssembly(out applicationContext, out currentName, 0) == 0) {
//^ assume currentName != null;
AssemblyName cn = new AssemblyName(currentName);
if (assemblyIdentity.Equals(new AssemblyIdentity(metadataHost.NameTable.GetNameFor(cn.Name), cn.Culture, cn.Version, cn.PublicKeyToken, ""))) {
string codeBase = cn.CodeBase;
if (codeBase != null && codeBase.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) {
Uri u = new Uri(codeBase, UriKind.Absolute);
return u.LocalPath;
}
return cn.GetLocation();
}
}
return null;
#endif
}
}
#if COMPACTX
private static bool IdentityMatchesString(AssemblyIdentity assemblyIdentity, string gacName) {
int n = gacName.Length;
var i = 0;
if (!MatchIgnoringCase(assemblyIdentity.Name.Value, ',', gacName, ref i, n)) return false;
while (i < n) {
char ch = gacName[i];
switch (ch) {
case 'v':
case 'V':
if (!MatchIgnoringCase("Version", '=', gacName, ref i, n)) return false;
if (!MatchDecimal(assemblyIdentity.Version.Major, '.', gacName, ref i, n)) return false;
if (!MatchDecimal(assemblyIdentity.Version.MajorRevision, '.', gacName, ref i, n)) return false;
if (!MatchDecimal(assemblyIdentity.Version.Minor, '.', gacName, ref i, n)) return false;
if (!MatchDecimal(assemblyIdentity.Version.MinorRevision, ',', gacName, ref i, n)) return false;
break;
case 'C':
case 'c':
if (!MatchIgnoringCase("Culture", '=', gacName, ref i, n)) return false;
var culture = assemblyIdentity.Culture;
if (culture.Length == 0) culture = "neutral";
if (!MatchIgnoringCase(culture, ',', gacName, ref i, n)) return false;
break;
case 'P':
case 'p':
if (!MatchIgnoringCase("PublicKeyToken", '=', gacName, ref i, n)) return false;
if (!MatchHex(assemblyIdentity.PublicKeyToken, ',', gacName, ref i, n)) return false;
break;
default:
return false;
}
}
return true;
}
private static bool MatchHex(IEnumerable<byte> bytes, char delimiter, string gacName, ref int i, int n) {
foreach (byte b in bytes) {
if (i >= n-1) return false;
var b1 = b >> 8;
var b2 = b & 0xF;
char c1 = b1 < 10 ? (char)(b1+'0') : (char)((b1-10)+'A');
char c2 = b2 < 10 ? (char)(b2+'0') : (char)((b2-10)+'A');
if (gacName[i++] != c1) return false;
if (gacName[i++] != c2) return false;
}
SkipBlanks(gacName, ref i, n);
if (i >= n) return true;
if (gacName[i++] != delimiter) return false;
SkipBlanks(gacName, ref i, n);
return true;
}
private static void SkipBlanks(string gacName, ref int i, int n) {
while (i < n && gacName[i] == ' ') i++;
}
private static bool MatchDecimal(int val, char delimiter, string gacName, ref int i, int n) {
int num = 0;
for (char ch = gacName[i++]; i < n; ) {
int d = ch - '0';
if (d < 0 || d > 9) return false;
num = num*10 + d;
}
if (num != val) return false;
SkipBlanks(gacName, ref i, n);
if (i >= n) return true;
if (gacName[i++] != delimiter) return false;
SkipBlanks(gacName, ref i, n);
return true;
}
private static bool MatchIgnoringCase(string str, char delimiter, string gacName, ref int i, int n) {
var m = str.Length;
int j = 0;
while (j < m && i < n) {
if (Char.ToLowerInvariant(str[j++]) != Char.ToLowerInvariant(gacName[i++])) return false;
}
if (j != m) return false;
SkipBlanks(gacName, ref i, n);
if (i >= n) return delimiter == ',';
if (gacName[i++] != delimiter) return false;
SkipBlanks(gacName, ref i, n);
return true;
}
#endif
#if !COMPACTFX && !__MonoCS__
[DllImport("kernel32.dll", CharSet=CharSet.Ansi)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("fusion.dll", CharSet=CharSet.Auto)]
private static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum, IApplicationContext/*?*/ pAppCtx, IAssemblyName/*?*/ pName, uint dwFlags, int pvReserved);
private class ASM_CACHE {
private ASM_CACHE() { }
public const uint ZAP = 1;
public const uint GAC = 2;
public const uint DOWNLOAD = 4;
}
#endif
}
#if !COMPACTFX
#pragma warning disable 1591
public class AssemblyName {
IAssemblyName assemblyName;
internal AssemblyName(IAssemblyName assemblyName) {
this.assemblyName = assemblyName;
//^ base();
}
internal string Name {
//set {this.WriteString(ASM_NAME.NAME, value);}
get { return this.ReadString(ASM_NAME.NAME); }
}
internal Version Version {
get {
int major = this.ReadUInt16(ASM_NAME.MAJOR_VERSION);
int minor = this.ReadUInt16(ASM_NAME.MINOR_VERSION);
int build = this.ReadUInt16(ASM_NAME.BUILD_NUMBER);
int revision = this.ReadUInt16(ASM_NAME.REVISION_NUMBER);
return new Version(major, minor, build, revision);
}
}
internal string Culture {
get { return this.ReadString(ASM_NAME.CULTURE); }
}
internal byte[] PublicKeyToken {
get { return this.ReadBytes(ASM_NAME.PUBLIC_KEY_TOKEN); }
}
internal string StrongName {
get {
uint usize = 0;
this.assemblyName.GetDisplayName(null, ref usize, (uint)AssemblyNameDisplayFlags.ALL);
int size = (int)usize;
if (size <= 0) return "";
StringBuilder strongName = new StringBuilder(size);
this.assemblyName.GetDisplayName(strongName, ref usize, (uint)AssemblyNameDisplayFlags.ALL);
return strongName.ToString();
}
}
internal string CodeBase {
get { return this.ReadString(ASM_NAME.CODEBASE_URL); }
}
//^ [Confined]
public override string ToString() {
return this.StrongName;
}
internal string/*?*/ GetLocation() {
#if __MonoCS__
IAssemblyCache assemblyCache = new MonoAssemblyCache();
#else
IAssemblyCache assemblyCache;
CreateAssemblyCache(out assemblyCache, 0);
if (assemblyCache == null) return null;
#endif
ASSEMBLY_INFO assemblyInfo = new ASSEMBLY_INFO();
assemblyInfo.cbAssemblyInfo = (uint)Marshal.SizeOf(typeof(ASSEMBLY_INFO));
assemblyCache.QueryAssemblyInfo(ASSEMBLYINFO_FLAG.VALIDATE | ASSEMBLYINFO_FLAG.GETSIZE, this.StrongName, ref assemblyInfo);
if (assemblyInfo.cbAssemblyInfo == 0) return null;
assemblyInfo.pszCurrentAssemblyPathBuf = new string(new char[assemblyInfo.cchBuf]);
assemblyCache.QueryAssemblyInfo(ASSEMBLYINFO_FLAG.VALIDATE | ASSEMBLYINFO_FLAG.GETSIZE, this.StrongName, ref assemblyInfo);
String value = assemblyInfo.pszCurrentAssemblyPathBuf;
return value;
}
private string ReadString(uint assemblyNameProperty) {
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
if (size == 0 || size > Int16.MaxValue) return String.Empty;
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
string/*?*/ str = Marshal.PtrToStringUni(ptr);
//^ assume str != null;
Marshal.FreeHGlobal(ptr);
return str;
}
private ushort ReadUInt16(uint assemblyNameProperty) {
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
ushort value = (ushort)Marshal.ReadInt16(ptr);
Marshal.FreeHGlobal(ptr);
return value;
}
private byte[] ReadBytes(uint assemblyNameProperty) {
uint size = 0;
this.assemblyName.GetProperty(assemblyNameProperty, IntPtr.Zero, ref size);
IntPtr ptr = Marshal.AllocHGlobal((int)size);
this.assemblyName.GetProperty(assemblyNameProperty, ptr, ref size);
byte[] value = new byte[(int)size];
Marshal.Copy(ptr, value, 0, (int)size);
Marshal.FreeHGlobal(ptr);
return value;
}
[DllImport("fusion.dll", CharSet=CharSet.Auto)]
private static extern int CreateAssemblyCache(out IAssemblyCache ppAsmCache, uint dwReserved);
private class CREATE_ASM_NAME_OBJ_FLAGS {
private CREATE_ASM_NAME_OBJ_FLAGS() { }
public const uint CANOF_PARSE_DISPLAY_NAME = 0x1;
public const uint CANOF_SET_DEFAULT_VALUES = 0x2;
}
private class ASM_NAME {
private ASM_NAME() { }
public const uint PUBLIC_KEY = 0;
public const uint PUBLIC_KEY_TOKEN = 1;
public const uint HASH_VALUE = 2;
public const uint NAME = 3;
public const uint MAJOR_VERSION = 4;
public const uint MINOR_VERSION = 5;
public const uint BUILD_NUMBER = 6;
public const uint REVISION_NUMBER = 7;
public const uint CULTURE = 8;
public const uint PROCESSOR_ID_ARRAY = 9;
public const uint OSINFO_ARRAY = 10;
public const uint HASH_ALGID = 11;
public const uint ALIAS = 12;
public const uint CODEBASE_URL = 13;
public const uint CODEBASE_LASTMOD = 14;
public const uint NULL_PUBLIC_KEY = 15;
public const uint NULL_PUBLIC_KEY_TOKEN = 16;
public const uint CUSTOM = 17;
public const uint NULL_CUSTOM = 18;
public const uint MVID = 19;
public const uint _32_BIT_ONLY = 20;
}
[Flags]
internal enum AssemblyNameDisplayFlags {
VERSION=0x01,
CULTURE=0x02,
PUBLIC_KEY_TOKEN=0x04,
PROCESSORARCHITECTURE=0x20,
RETARGETABLE=0x80,
ALL=VERSION | CULTURE | PUBLIC_KEY_TOKEN | PROCESSORARCHITECTURE | RETARGETABLE
}
private class ASSEMBLYINFO_FLAG {
private ASSEMBLYINFO_FLAG() { }
public const uint VALIDATE = 1;
public const uint GETSIZE = 2;
}
[StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct ASSEMBLY_INFO {
public uint cbAssemblyInfo;
public uint dwAssemblyFlags;
public ulong uliAssemblySizeInKB;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszCurrentAssemblyPathBuf;
public uint cchBuf;
}
[ComImport(), Guid("E707DCDE-D1CD-11D2-BAB9-00C04F8ECEAE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAssemblyCache {
[PreserveSig()]
int UninstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, IntPtr pvReserved, int pulDisposition);
[PreserveSig()]
int QueryAssemblyInfo(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, ref ASSEMBLY_INFO pAsmInfo);
[PreserveSig()]
int CreateAssemblyCacheItem(uint dwFlags, IntPtr pvReserved, out object ppAsmItem, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName);
[PreserveSig()]
int CreateAssemblyScavenger(out object ppAsmScavenger);
[PreserveSig()]
int InstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszManifestFilePath, IntPtr pvReserved);
}
}
#pragma warning restore 1591
[ComImport(), Guid("CD193BC0-B4BC-11D2-9833-00C04FC31D2E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAssemblyName {
[PreserveSig()]
int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty);
[PreserveSig()]
int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty);
[PreserveSig()]
int Finalize();
[PreserveSig()]
int GetDisplayName(StringBuilder/*?*/ szDisplayName, ref uint pccDisplayName, uint dwDisplayFlags);
[PreserveSig()]
int BindToObject(object refIID, object pAsmBindSink, IApplicationContext pApplicationContext, [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase, long llFlags, int pvReserved, uint cbReserved, out int ppv);
[PreserveSig()]
int GetName(out uint lpcwBuffer, out int pwzName);
[PreserveSig()]
int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow);
[PreserveSig()]
int IsEqual(IAssemblyName pName, uint dwCmpFlags);
[PreserveSig()]
int Clone(out IAssemblyName pName);
}
[ComImport(), Guid("7C23FF90-33AF-11D3-95DA-00A024A85B51"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IApplicationContext {
void SetContextNameObject(IAssemblyName pName);
void GetContextNameObject(out IAssemblyName ppName);
void Set([MarshalAs(UnmanagedType.LPWStr)] string szName, int pvValue, uint cbValue, uint dwFlags);
void Get([MarshalAs(UnmanagedType.LPWStr)] string szName, out int pvValue, ref uint pcbValue, uint dwFlags);
void GetDynamicDirectory(out int wzDynamicDir, ref uint pdwSize);
}
[ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAssemblyEnum {
[PreserveSig()]
int GetNextAssembly(out IApplicationContext ppAppCtx, out IAssemblyName ppName, uint dwFlags);
[PreserveSig()]
int Reset();
[PreserveSig()]
int Clone(out IAssemblyEnum ppEnum);
}
#endif
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.MetadataHelper</RootNamespace>
<AssemblyName>Microsoft.Cci.MetadataHelper</AssemblyName>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>true</SignAssembly>
<CodeAnalysisRules>-Microsoft.Design#CA1011;-Microsoft.Design#CA1051;-Microsoft.Design#CA1004;-Microsoft.Design#CA1014;-Microsoft.Design#CA1060;-Microsoft.Design#CA1034;-Microsoft.Design#CA1062;-Microsoft.Globalization#CA1305;-Microsoft.Maintainability#CA1502;-Microsoft.Maintainability#CA1500;-Microsoft.Naming#CA1706;-Microsoft.Performance#CA1815;-Microsoft.Performance#CA1814;-Microsoft.Security#CA2105;-Microsoft.Security#CA2104;-Microsoft.Usage#CA2233</CodeAnalysisRules>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Debug\Microsoft.Cci.MetadataHelper.XML</DocumentationFile>
<WarningsAsErrors>1591</WarningsAsErrors>
<NoWarn>
</NoWarn>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Release\Microsoft.Cci.MetadataHelper.xml</DocumentationFile>
<WarningsAsErrors>1591</WarningsAsErrors>
<NoWarn>
</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyDebug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\NightlyDebug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<DocumentationFile>bin\NightlyDebug\Microsoft.Cci.MetadataHelper.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyRelease|AnyCPU' ">
<OutputPath>bin\NightlyRelease\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<DocumentationFile>bin\NightlyRelease\Microsoft.Cci.MetadataHelper.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CompilerOnly|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\CompilerOnly\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\Microsoft.Cci.MetadataHelper.XML</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<WarningsAsErrors>1591</WarningsAsErrors>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\version.cs">
<Link>Build\version.cs</Link>
</Compile>
<Compile Include="AttributeHelper.cs" />
<Compile Include="CommandLineOptions.cs" />
<Compile Include="Core.cs" />
<Compile Include="ExpressionHelper.cs" />
<Compile Include="GlobalAssemblyCache.cs" />
<Compile Include="MemberHelper.cs" />
<Compile Include="Members.cs" />
<Compile Include="MonoAssemblyCache.cs" />
<Compile Include="PlatformTypes.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Types.cs" />
<Compile Include="Visitors.cs" />
<Compile Include="TypeHelper.cs" />
<Compile Include="UnitHelper.cs" />
<Compile Include="UnmanagedFileIO.cs" />
<Compile Include="UtilityDataStructures.cs" />
<Compile Include="Validator.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<EmbeddedResource Include="ErrorMessages.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,354 @@
//Contributed by YodaSkywalker under the MSPL license.
#if __MonoCS__
using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Microsoft.Cci;
class MonoGACHelpers
{
public static string GetGACDir()
{
System.Reflection.PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic );
if ( gac == null )
{
Console.WriteLine( "Can't find the GAC!" );
Environment.Exit( 1 );
}
System.Reflection.MethodInfo get_gac = gac.GetGetMethod (true);
string sGACDir = (string) get_gac.Invoke (null, null);
return sGACDir;
}
}
// Since Mono doesn't have a fusion.dll to access the GAC, this is a MINIMAL implementation
// of IAssemblyCache. It only has enough to satisfy GlobalAssemblyCache's usage above!
class MonoAssemblyCache : AssemblyName.IAssemblyCache
{
public MonoAssemblyCache()
{
}
public int UninstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, IntPtr pvReserved, int pulDisposition)
{
Debug.Assert( false );
return 0;
}
public int QueryAssemblyInfo(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName, ref AssemblyName.ASSEMBLY_INFO pAsmInfo)
{
pAsmInfo = new AssemblyName.ASSEMBLY_INFO();
pAsmInfo.cbAssemblyInfo = 1; // just needs to be nonzero for our purposes
// All they need here is pszCurrentAssemblyPathBuf to be filled out.
// pszAssemblyName is the strong name (as returned from MonoAssemblyName.GetDisplayName),
// like "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
//
// Mono stores them in monoDir\lib\mono\gac\ASSEMBLY_NAME\VERSION__PUBLICKEYTOKEN\ASSEMBLY_NAME.dll
//
// .. so this strong name : "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
// .. would be located here: monoDir\lib\mono\gac\System.Core\4.0.0.0__b77a5c561934e089\System.Core.dll
string [] parts = pszAssemblyName.Split( new string[] {", "}, StringSplitOptions.RemoveEmptyEntries );
string sAssemblyName = parts[0];
string sVersion = parts[1].Split( new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries )[1];
string sPublicKeyToken = parts[3].Split( new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries )[1];
string sGACDir = MonoGACHelpers.GetGACDir();
sGACDir = Path.Combine( sGACDir, sAssemblyName );
sGACDir = Path.Combine( sGACDir, sVersion + "__" + sPublicKeyToken );
pAsmInfo.pszCurrentAssemblyPathBuf = Path.Combine( sGACDir, sAssemblyName + ".dll" );
Debug.Assert( false );
return 0;
}
public int CreateAssemblyCacheItem(uint dwFlags, IntPtr pvReserved, out object ppAsmItem, [MarshalAs(UnmanagedType.LPWStr)] string pszAssemblyName)
{
ppAsmItem = null;
Debug.Assert( false );
return 0;
}
public int CreateAssemblyScavenger(out object ppAsmScavenger)
{
ppAsmScavenger = null;
Debug.Assert( false );
return 0;
}
public int InstallAssembly(uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pszManifestFilePath, IntPtr pvReserved)
{
Debug.Assert( false );
return 0;
}
}
// Since Mono doesn't have a fusion.dll to access the GAC, this is a MINIMAL implementation
// of IAssemblyName. It only has enough to satisfy GlobalAssemblyCache's usage above!
class MonoAssemblyName : IAssemblyName
{
public MonoAssemblyName( string sAssemblyName, string sVersion, string sCulture, string sPublicKeyToken, string sDisplayName )
{
m_sAssemblyName = sAssemblyName;
m_sVersion = sVersion;
m_sCulture = sCulture;
m_sPublicKeyToken = sPublicKeyToken;
m_sDisplayName = sDisplayName;
}
public int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty)
{
Debug.Assert( false );
return 0;
}
public int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty)
{
string sSource = null;
if ( PropertyId == MY_ASM_NAME.NAME )
sSource = m_sAssemblyName;
else if ( PropertyId == MY_ASM_NAME.CULTURE )
sSource = ""; // The Visual Studio version gets an empty string for culture.. otherwise it'd be m_sCulture.
else if ( PropertyId == MY_ASM_NAME.CODEBASE_URL )
sSource = "";
if ( sSource != null )
{
// They're asking for a string.
int nBytes = sSource.Length * 2 + 2;
pcbProperty = (uint)nBytes;
if ( pvProperty == IntPtr.Zero )
return 0;
// Get the unicode string into bytes.
IntPtr pString = Marshal.StringToHGlobalUni( sSource );
byte [] bytes = new byte[nBytes];
Marshal.Copy( pString, bytes, 0, nBytes );
Marshal.FreeHGlobal( pString );
// Get the bytes into their dest array.
Marshal.Copy( bytes, 0, pvProperty, nBytes );
return 0;
}
// Do they want an int16?
if ( PropertyId == MY_ASM_NAME.MAJOR_VERSION || PropertyId == MY_ASM_NAME.MINOR_VERSION || PropertyId == MY_ASM_NAME.BUILD_NUMBER || PropertyId == MY_ASM_NAME.REVISION_NUMBER )
{
pcbProperty = 2;
// Do they only want the size?
if ( pvProperty == IntPtr.Zero )
{
return 0;
}
string [] versionParts = m_sVersion.Split( new char[] {'.'} );
string sValuePart = ( PropertyId == MY_ASM_NAME.MAJOR_VERSION ) ? versionParts[0] :
(
( PropertyId == MY_ASM_NAME.MINOR_VERSION ) ? versionParts[1] :
(
( PropertyId == MY_ASM_NAME.BUILD_NUMBER ) ? versionParts[2] : versionParts[3]
)
);
UInt16 value = Convert.ToUInt16( sValuePart );
Marshal.WriteInt16( pvProperty, (Int16)value );
return 0;
}
// Do they want raw bytes?
if ( PropertyId == MY_ASM_NAME.PUBLIC_KEY_TOKEN )
{
pcbProperty = 8;
if ( pvProperty == IntPtr.Zero )
return 0;
byte [] bytes = new byte[8];
for ( int i=0; i < 8; i++ )
{
string s = m_sPublicKeyToken.Substring( i*2, 2 );
bytes[i] = Convert.ToByte( s, 16 );
}
Marshal.Copy( bytes, 0, pvProperty, 8 );
return 0;
}
Debug.Assert( false );
return 0;
}
public int Finalize()
{
Debug.Assert( false );
return 0;
}
public int GetDisplayName(StringBuilder/*?*/ szDisplayName, ref uint pccDisplayName, uint dwDisplayFlags)
{
pccDisplayName = 1; // They only care if this is nonzero.
if ( szDisplayName != null )
{
szDisplayName.Append( m_sDisplayName );
}
return 1;
}
public int BindToObject(object refIID, object pAsmBindSink, IApplicationContext pApplicationContext, [MarshalAs(UnmanagedType.LPWStr)] string szCodeBase, long llFlags, int pvReserved, uint cbReserved, out int ppv)
{
ppv = 0;
Debug.Assert( false );
return 0;
}
public int GetName(out uint lpcwBuffer, out int pwzName)
{
lpcwBuffer = 0;
pwzName = 0;
Debug.Assert( false );
return 0;
}
public int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow)
{
pdwVersionHi = pdwVersionLow = 0;
Debug.Assert( false );
return 0;
}
public int IsEqual(IAssemblyName pName, uint dwCmpFlags)
{
Debug.Assert( false );
return 0;
}
public int Clone(out IAssemblyName pName)
{
pName = null;
Debug.Assert( false );
return 0;
}
private class MY_ASM_NAME {
public const uint PUBLIC_KEY = 0;
public const uint PUBLIC_KEY_TOKEN = 1;
public const uint HASH_VALUE = 2;
public const uint NAME = 3;
public const uint MAJOR_VERSION = 4;
public const uint MINOR_VERSION = 5;
public const uint BUILD_NUMBER = 6;
public const uint REVISION_NUMBER = 7;
public const uint CULTURE = 8;
public const uint PROCESSOR_ID_ARRAY = 9;
public const uint OSINFO_ARRAY = 10;
public const uint HASH_ALGID = 11;
public const uint ALIAS = 12;
public const uint CODEBASE_URL = 13;
public const uint CODEBASE_LASTMOD = 14;
public const uint NULL_PUBLIC_KEY = 15;
public const uint NULL_PUBLIC_KEY_TOKEN = 16;
public const uint CUSTOM = 17;
public const uint NULL_CUSTOM = 18;
public const uint MVID = 19;
public const uint _32_BIT_ONLY = 20;
}
string m_sAssemblyName;
string m_sVersion;
string m_sCulture;
string m_sPublicKeyToken;
string m_sDisplayName;
}
// Since Mono doesn't have a fusion.dll to access the GAC, this is a MINIMAL implementation
// of IAssemblyEnum. It only has enough to satisfy GlobalAssemblyCache's usage above!
class MonoAssemblyEnum : IAssemblyEnum
{
public MonoAssemblyEnum()
{
string binDir = MonoGACHelpers.GetGACDir();
binDir = Path.GetDirectoryName( binDir );
binDir = Path.GetDirectoryName( binDir );
binDir = Path.GetDirectoryName( binDir );
// Run gacutil to get the list.
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
if ( (int)Environment.OSVersion.Platform == 4 || (int)Environment.OSVersion.Platform == 128 )
{
// Running under Unix.
info.FileName = "gacutil";
info.Arguments = "-l";
}
else
{
// Running under Windows.
info.FileName = "cmd.exe";
info.Arguments = "/C \"" + Path.Combine( Path.Combine(binDir, "bin"), "gacutil.bat" ) + "\" -l";
}
Process p = Process.Start( info );
string sOutput = p.StandardOutput.ReadToEnd();
p.Close();
string [] lines = sOutput.Split( new char[] { '\n' } );
m_Names = new MonoAssemblyName[lines.Length - 3];
for ( int i=1; i < lines.Length-2; i++ )
{
string sLine = lines[i].Replace( "\r", "" );
string [] parts = sLine.Split( new string[] {", "}, StringSplitOptions.RemoveEmptyEntries );
string sAssemblyName = parts[0];
string sVersion = parts[1].Split( new char[] {'='} )[1];
string sCulture = parts[2].Split( new char[] {'='} )[1];
string sPublicKeyToken = parts[3].Split( new char[] {'='} )[1];
m_Names[i-1] = new MonoAssemblyName( sAssemblyName, sVersion, sCulture, sPublicKeyToken, sLine );
}
m_nCurrentName = 0;
}
public int GetNextAssembly(out IApplicationContext ppAppCtx, out IAssemblyName ppName, uint dwFlags)
{
ppAppCtx = null;
ppName = null;
if ( m_nCurrentName >= m_Names.Length )
return 1;
ppName = m_Names[m_nCurrentName++];
return 0;
}
public int Reset()
{
Debug.Assert( false );
return 0;
}
public int Clone(out IAssemblyEnum ppEnum)
{
ppEnum = null;
Debug.Assert( false );
return 0;
}
MonoAssemblyName [] m_Names;
int m_nCurrentName;
}
#endif // __MonoCS__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsof.Cci.MetadataHelper")]
[assembly: AssemblyDescription("A collection of convenience methods that are implemented solely in terms of the metadata object model.")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e18a577e-4477-4fbd-ae4f-5f1116791fcf")]
[assembly: ContractVerification(false)]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,903 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Text;
using System.Globalization;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
/// <summary>
/// Class containing helper routines for Units
/// </summary>
public static class UnitHelper {
/// <summary>
/// True if assembly1 has an attribute that allows assembly2 to access internal members of assembly1.
/// </summary>
/// <param name="assembly1">The assembly whose attribute is to be inspected.</param>
/// <param name="assembly2">The assembly that must be mentioned in the attribute of assembly1.</param>
/// <returns></returns>
public static bool AssemblyOneAllowsAssemblyTwoToAccessItsInternals(IAssembly assembly1, IAssembly assembly2) {
var name2 = assembly2.Name.Value;
var name2Length = assembly2.Name.Value.Length;
foreach (var attribute in assembly1.AssemblyAttributes) {
if (!TypeHelper.TypesAreEquivalent(attribute.Type, assembly1.PlatformType.SystemRuntimeCompilerServicesInternalsVisibleToAttribute)) continue;
foreach (var argument in attribute.Arguments) {
var metadataConst = argument as IMetadataConstant;
if (metadataConst == null) break;
var assemblyName = metadataConst.Value as string;
if (assemblyName == null) break;
var assemblyNameLength = assemblyName.Length;
if (assemblyNameLength < name2Length) break;
if (assemblyNameLength > name2Length) {
var len = assemblyName.IndexOf(' ');
if (len < 0) len = assemblyName.IndexOf(',');
if (len != name2Length) break;
}
if (string.Compare(assemblyName, 0, assembly2.Name.Value, 0, name2Length, StringComparison.OrdinalIgnoreCase) == 0) return true;
}
}
return false;
}
/// <summary>
/// Returns the Assembly identity for the assembly name.
/// </summary>
/// <param name="assemblyName"></param>
/// <param name="metadataHost"></param>
/// <returns></returns>
public static AssemblyIdentity GetAssemblyIdentity(System.Reflection.AssemblyName assemblyName, IMetadataHost metadataHost) {
Contract.Requires(assemblyName != null);
Contract.Requires(metadataHost != null);
Contract.Ensures(Contract.Result<AssemblyIdentity>() != null);
string culture = assemblyName.CultureInfo == null || assemblyName.CultureInfo == System.Globalization.CultureInfo.InvariantCulture ? "neutral" : assemblyName.CultureInfo.ToString();
string name = assemblyName.Name;
if (name == null) name = string.Empty;
Version version = assemblyName.Version;
if (version == null) version = Dummy.Version;
byte[] token = assemblyName.GetPublicKeyToken();
if (token == null) token = new byte[0];
var codeBase = assemblyName.CodeBase;
if (codeBase == null) codeBase = string.Empty;
return new AssemblyIdentity(metadataHost.NameTable.GetNameFor(name), culture, version, token, codeBase);
}
/// <summary>
/// Allocates an object that identifies a .NET assembly, using the IAssembly object
/// </summary>
/// <param name="assembly"></param>
public static AssemblyIdentity GetAssemblyIdentity(IAssembly assembly) {
Contract.Requires(assembly != null);
Contract.Ensures(Contract.Result<AssemblyIdentity>() != null);
byte[] pKey = new List<byte>(assembly.PublicKey).ToArray();
if (pKey.Length != 0) {
return new AssemblyIdentity(assembly.Name, assembly.Culture, assembly.Version, UnitHelper.ComputePublicKeyToken(pKey), assembly.Location);
} else {
return new AssemblyIdentity(assembly.Name, assembly.Culture, assembly.Version, new byte[0], assembly.Location);
}
}
/// <summary>
/// Constructs module identity for the given module
/// </summary>
/// <param name="module">Module for which the identity is desired.</param>
/// <returns>The module identity corresponding to the passed module.</returns>
public static ModuleIdentity GetModuleIdentity(IModule module) {
Contract.Requires(module != null);
Contract.Ensures(Contract.Result<ModuleIdentity>() != null);
if (module.ContainingAssembly != null) {
return new ModuleIdentity(module.Name, module.Location, UnitHelper.GetAssemblyIdentity(module.ContainingAssembly));
} else {
return new ModuleIdentity(module.Name, module.Location);
}
}
/// <summary>
/// Computes the public key token for the given public key
/// </summary>
/// <param name="publicKey"></param>
/// <returns></returns>
public static byte[] ComputePublicKeyToken(IEnumerable<byte> publicKey) {
Contract.Requires(publicKey != null);
Contract.Ensures(Contract.Result<byte[]>() != null);
byte[] pKey = new List<byte>(publicKey).ToArray();
if (pKey.Length == 0)
return pKey;
System.Security.Cryptography.SHA1Managed sha1Algo = new System.Security.Cryptography.SHA1Managed();
byte[] hash = sha1Algo.ComputeHash(pKey);
byte[] publicKeyToken = new byte[8];
int startIndex = hash.Length - 8;
Contract.Assume(0 <= startIndex && startIndex < hash.Length);
Contract.Assert(startIndex + 8 <= hash.GetLowerBound(0) + hash.Length);
Array.Copy(hash, startIndex, publicKeyToken, 0, 8);
Array.Reverse(publicKeyToken, 0, 8);
return publicKeyToken;
}
/// <summary>
/// Returns a unit namespace definition, nested in the given unitNamespace if possible,
/// otherwise nested in the given unit if possible, otherwise nested in the given host if possible, otherwise it returns Dummy.UnitNamespace.
/// If unitNamespaceReference is a root namespace, the result is equal to the given unitNamespace if not null,
/// otherwise the result is the root namespace of the given unit if not null,
/// otherwise the result is root namespace of unitNamespaceReference.Unit, if that can be resolved via the given host,
/// otherwise the result is Dummy.UnitNamespace.
/// </summary>
public static IUnitNamespace Resolve(IUnitNamespaceReference unitNamespaceReference, IMetadataHost host, IUnit unit = null, IUnitNamespace unitNamespace = null) {
Contract.Requires(unitNamespaceReference != null);
Contract.Requires(host != null);
Contract.Requires(unit != null || unitNamespace == null);
Contract.Ensures(Contract.Result<IUnitNamespace>() != null);
var rootNsRef = unitNamespaceReference as IRootUnitNamespaceReference;
if (rootNsRef != null) {
if (unitNamespace != null) return unitNamespace;
if (unit != null) return unit.UnitNamespaceRoot;
unit = UnitHelper.Resolve(unitNamespaceReference.Unit, host);
if (unit is Dummy) return Dummy.UnitNamespace;
return unit.UnitNamespaceRoot;
}
var nestedNsRef = unitNamespaceReference as INestedUnitNamespaceReference;
if (nestedNsRef == null) return Dummy.UnitNamespace;
var containingNsDef = UnitHelper.Resolve(nestedNsRef.ContainingUnitNamespace, host, unit, unitNamespace);
if (containingNsDef is Dummy) return Dummy.UnitNamespace;
foreach (var nsMem in containingNsDef.GetMembersNamed(nestedNsRef.Name, ignoreCase: false)) {
var neNsDef = nsMem as INestedUnitNamespace;
if (neNsDef != null) return neNsDef;
}
return Dummy.UnitNamespace;
}
/// <summary>
/// Returns a unit, loaded into the given host, that matches unitReference. The host will load the unit, if necessary and possible.
/// If the reference cannot be resolved a dummy unit is returned.
/// </summary>
public static IUnit Resolve(IUnitReference unitReference, IMetadataHost host) {
Contract.Requires(unitReference != null);
Contract.Requires(host != null);
Contract.Ensures(Contract.Result<IUnit>() != null);
return host.LoadUnit(unitReference.UnitIdentity);
}
/// <summary>
/// Computes the string representing the strong name of the given assembly reference.
/// </summary>
public static string StrongName(IAssemblyReference assemblyReference) {
Contract.Requires(assemblyReference != null);
Contract.Ensures(Contract.Result<string>() != null);
StringBuilder sb = new StringBuilder();
sb.Append(assemblyReference.Name.Value);
sb.AppendFormat(CultureInfo.InvariantCulture, ", Version={0}.{1}.{2}.{3}", assemblyReference.Version.Major, assemblyReference.Version.Minor, assemblyReference.Version.Build, assemblyReference.Version.Revision);
if (assemblyReference.Culture.Length > 0)
sb.AppendFormat(CultureInfo.InvariantCulture, ", Culture={0}", assemblyReference.Culture);
else
sb.Append(", Culture=neutral");
sb.AppendFormat(CultureInfo.InvariantCulture, ", PublicKeyToken=");
if (IteratorHelper.EnumerableIsNotEmpty(assemblyReference.PublicKeyToken)) {
foreach (byte b in assemblyReference.PublicKeyToken) sb.Append(b.ToString("x2", CultureInfo.InvariantCulture));
} else {
sb.Append("null");
}
if (assemblyReference.IsRetargetable)
sb.Append(", Retargetable=Yes");
if (assemblyReference.ContainsForeignTypes)
sb.Append(", ContentType=WindowsRuntime");
return sb.ToString();
}
/// <summary>
/// Computes the string representing the strong name of the given assembly reference.
/// </summary>
public static string StrongName(AssemblyIdentity assemblyIdentity) {
Contract.Requires(assemblyIdentity != null);
Contract.Ensures(Contract.Result<string>() != null);
StringBuilder sb = new StringBuilder();
sb.Append(assemblyIdentity.Name.Value);
sb.AppendFormat(CultureInfo.InvariantCulture, ", Version={0}.{1}.{2}.{3}", assemblyIdentity.Version.Major, assemblyIdentity.Version.Minor, assemblyIdentity.Version.Build, assemblyIdentity.Version.Revision);
if (assemblyIdentity.Culture.Length > 0)
sb.AppendFormat(CultureInfo.InvariantCulture, ", Culture={0}", assemblyIdentity.Culture);
else
sb.Append(", Culture=neutral");
sb.AppendFormat(CultureInfo.InvariantCulture, ", PublicKeyToken=");
if (IteratorHelper.EnumerableIsNotEmpty(assemblyIdentity.PublicKeyToken)) {
foreach (byte b in assemblyIdentity.PublicKeyToken) sb.Append(b.ToString("x2", CultureInfo.InvariantCulture));
} else {
sb.Append("null");
}
return sb.ToString();
}
/// <summary>
/// Finds a type in the given module using the given type name, expressed in C# notation with dots separating both namespaces and types.
/// If no such type can be found Dummy.NamespaceTypeDefinition is returned.
/// </summary>
/// <param name="nameTable">A collection of IName instances that represent names that are commonly used during compilation.
/// This is a provided as a parameter to the host environment in order to allow more than one host
/// environment to co-exist while agreeing on how to map strings to IName instances.</param>
/// <param name="unit">The unit of metadata to search for the type.</param>
/// <param name="typeName">A string containing the fully qualified type name, using C# formatting conventions.</param>
public static INamedTypeDefinition FindType(INameTable nameTable, IUnit unit, string typeName) {
Contract.Requires(nameTable != null);
Contract.Requires(unit != null);
Contract.Requires(typeName != null);
Contract.Ensures(Contract.Result<INamedTypeDefinition>() != null);
int offset = 0;
INamedTypeDefinition/*?*/ result = GetType(nameTable, unit.UnitNamespaceRoot, typeName, 0, ref offset);
if (result != null) return result;
return Dummy.NamespaceTypeDefinition;
}
/// <summary>
/// Finds a type in the given module using the given type name, expressed in C# notation with dots separating both namespaces and types.
/// If no such type can be found Dummy.NamespaceTypeDefinition is returned.
/// </summary>
/// <param name="nameTable">A collection of IName instances that represent names that are commonly used during compilation.
/// This is a provided as a parameter to the host environment in order to allow more than one host
/// environment to co-exist while agreeing on how to map strings to IName instances.</param>
/// <param name="unit">The unit of metadata to search for the type.</param>
/// <param name="typeName">A string containing the fully qualified type name, using C# formatting conventions.</param>
/// <param name="genericParameterCount">The total number of generic parameters (including inherited parameters) that the returned type should have.</param>
public static INamedTypeDefinition FindType(INameTable nameTable, IUnit unit, string typeName, int genericParameterCount) {
Contract.Requires(nameTable != null);
Contract.Requires(unit != null);
Contract.Requires(typeName != null);
Contract.Requires(genericParameterCount >= 0);
Contract.Ensures(Contract.Result<INamedTypeDefinition>() != null);
int offset = 0;
INamedTypeDefinition/*?*/ result = GetType(nameTable, unit.UnitNamespaceRoot, typeName, genericParameterCount, ref offset);
if (result != null) return result;
return Dummy.NamespaceTypeDefinition;
}
private static INamedTypeDefinition/*?*/ GetType(INameTable nameTable, INamespaceDefinition namespaceDefinition, string typeName, int genericParameterCount, ref int offset) {
Contract.Requires(nameTable != null);
Contract.Requires(namespaceDefinition != null);
Contract.Requires(typeName != null);
Contract.Requires(genericParameterCount >= 0);
Contract.Requires(offset >= 0);
Contract.Ensures(offset >= 0);
int len = typeName.Length;
if (offset >= len) return null;
int savedOffset = offset;
var nestedNamespaceDefinition = GetNamespace(nameTable, namespaceDefinition, typeName, ref offset);
if (nestedNamespaceDefinition != null) {
var naType = GetType(nameTable, nestedNamespaceDefinition, typeName, genericParameterCount, ref offset);
if (naType != null) return naType;
}
offset = savedOffset;
int dotPos = typeName.IndexOf('.', offset);
Contract.Assume(dotPos < 0 || (dotPos >= offset && dotPos < len));
if (dotPos < 0) dotPos = len;
IName tName = nameTable.GetNameFor(typeName.Substring(offset, dotPos-offset));
foreach (var member in namespaceDefinition.GetMembersNamed(tName, false)) {
var namespaceType = member as INamespaceTypeDefinition;
if (namespaceType == null) continue;
if (dotPos == len) {
if (namespaceType.GenericParameterCount != genericParameterCount) continue;
return namespaceType;
} else {
if (namespaceType.GenericParameterCount > genericParameterCount) continue;
offset = dotPos+1;
var nt = GetNestedType(nameTable, namespaceType, typeName, genericParameterCount-namespaceType.GenericParameterCount, ref offset);
if (nt != null) return nt;
}
}
return null;
}
private static INestedUnitNamespace/*?*/ GetNamespace(INameTable nameTable, INamespaceDefinition namespaceDefinition, string typeName, ref int offset) {
Contract.Requires(nameTable != null);
Contract.Requires(namespaceDefinition != null);
Contract.Requires(typeName != null);
Contract.Requires(offset >= 0);
Contract.Ensures(offset >= 0);
int len = typeName.Length;
if (offset >= len) return null;
int dotPos = typeName.IndexOf('.', offset);
if (dotPos < 0) return null;
Contract.Assume(dotPos >= offset); //if a dot has been found, it must be at offset or later
IName neName = nameTable.GetNameFor(typeName.Substring(offset, dotPos-offset));
foreach (var member in namespaceDefinition.GetMembersNamed(neName, false)) {
var nestedNamespace = member as INestedUnitNamespace;
if (nestedNamespace == null) continue;
offset = dotPos+1;
return nestedNamespace;
}
return null;
}
private static INestedTypeDefinition/*?*/ GetNestedType(INameTable nameTable, ITypeDefinition typeDefinition, string typeName, int genericParameterCount, ref int offset) {
Contract.Requires(nameTable != null);
Contract.Requires(typeDefinition != null);
Contract.Requires(typeName != null);
Contract.Requires(genericParameterCount >= 0);
Contract.Requires(offset >= 0);
Contract.Ensures(offset >= 0);
int len = typeName.Length;
if (offset >= len) return null;
int dotPos = typeName.IndexOf('.', offset);
Contract.Assume(dotPos < 0 || (dotPos >= offset && dotPos < len));
if (dotPos < 0) dotPos = len;
IName tName = nameTable.GetNameFor(typeName.Substring(offset, dotPos-offset));
foreach (var member in typeDefinition.GetMembersNamed(tName, false)) {
var nestedType = member as INestedTypeDefinition;
if (nestedType == null) continue;
if (dotPos == len) {
if (nestedType.GenericParameterCount != genericParameterCount) continue;
return nestedType;
}
if (nestedType.GenericParameterCount > genericParameterCount) continue;
offset = dotPos+1;
var nt = GetNestedType(nameTable, nestedType, typeName, genericParameterCount-nestedType.GenericParameterCount, ref offset);
if (nt != null) return nt;
}
return null;
}
/// <summary>
/// Searches for the resource with given name in the given assembly.
/// </summary>
public static IResourceReference/*?*/ FindResourceNamed(IAssembly assembly, IName resourceName) {
Contract.Requires(assembly != null);
Contract.Requires(resourceName != null);
foreach (IResourceReference resourceRef in assembly.Resources) {
if (resourceRef.Name.UniqueKey == resourceName.UniqueKey)
return resourceRef;
}
return null;
}
/// <summary>
/// Returns true if the given two assembly references are to be considered equivalent.
/// </summary>
public static bool AssembliesAreEquivalent(IAssemblyReference/*?*/ assembly1, IAssemblyReference/*?*/ assembly2) {
if (assembly1 == null || assembly2 == null)
return false;
if (assembly1 == assembly2)
return true;
if (assembly1.Name.UniqueKeyIgnoringCase != assembly2.Name.UniqueKeyIgnoringCase)
return false;
if (!assembly1.Version.Equals(assembly2.Version))
return false;
if (!assembly1.Culture.Equals(assembly2.Culture))
return false;
return IteratorHelper.EnumerablesAreEqual<byte>(assembly1.PublicKeyToken, assembly2.PublicKeyToken);
}
/// <summary>
/// Returns true if the given two module references are to be considered equivalent.
/// </summary>
public static bool ModulesAreEquivalent(IModuleReference/*?*/ module1, IModuleReference/*?*/ module2) {
if (module1 == null || module2 == null)
return false;
if (module1 == module2)
return true;
if (module1.ContainingAssembly != null) {
if (module2.ContainingAssembly == null)
return false;
if (!UnitHelper.AssembliesAreEquivalent(module1.ContainingAssembly, module2.ContainingAssembly))
return false;
}
return module1.Name.UniqueKeyIgnoringCase == module2.Name.UniqueKeyIgnoringCase;
}
/// <summary>
/// Returns true if the given two unit references are to be considered equivalent.
/// </summary>
public static bool UnitsAreEquivalent(IUnitReference/*?*/ unit1, IUnitReference/*?*/ unit2) {
if (unit1 == null || unit2 == null)
return false;
if (unit1 == unit2)
return true;
if (UnitHelper.AssembliesAreEquivalent(unit1 as IAssemblyReference, unit2 as IAssemblyReference))
return true;
if (UnitHelper.ModulesAreEquivalent(unit1 as IModuleReference, unit2 as IModuleReference))
return true;
return false;
}
/// <summary>
/// Returns true if the given two unit references are to be considered equivalent as containers.
/// </summary>
public static bool UnitsAreContainmentEquivalent(IUnitReference/*?*/ unit1, IUnitReference/*?*/ unit2) {
if (unit1 == null || unit2 == null)
return false;
if (unit1 == unit2)
return true;
IModuleReference/*?*/ moduleRef1 = unit1 as IModuleReference;
IModuleReference/*?*/ moduleRef2 = unit2 as IModuleReference;
if (moduleRef1 != null && moduleRef2 != null) {
if (UnitHelper.AssembliesAreEquivalent(moduleRef1.ContainingAssembly, moduleRef2.ContainingAssembly))
return true;
}
return false;
}
/// <summary>
/// Returns true if the given two unit namespaces are to be considered equivalent as containers.
/// </summary>
public static bool UnitNamespacesAreEquivalent(IUnitNamespaceReference/*?*/ unitNamespace1, IUnitNamespaceReference/*?*/ unitNamespace2) {
if (unitNamespace1 == null || unitNamespace2 == null)
return false;
if (unitNamespace1 == unitNamespace2)
return true;
INestedUnitNamespaceReference/*?*/ nstUnitNamespace1 = unitNamespace1 as INestedUnitNamespaceReference;
INestedUnitNamespaceReference/*?*/ nstUnitNamespace2 = unitNamespace2 as INestedUnitNamespaceReference;
if (nstUnitNamespace1 != null && nstUnitNamespace2 != null) {
return nstUnitNamespace1.Name.UniqueKey == nstUnitNamespace2.Name.UniqueKey
&& UnitHelper.UnitNamespacesAreEquivalent(nstUnitNamespace1.ContainingUnitNamespace, nstUnitNamespace2.ContainingUnitNamespace);
}
if (nstUnitNamespace1 != null || nstUnitNamespace2 != null)
return false;
return UnitHelper.UnitsAreContainmentEquivalent(unitNamespace1.Unit, unitNamespace2.Unit);
}
}
}
namespace Microsoft.Cci.Immutable {
/// <summary>
/// A set of units that all contribute to a unified root namespace. For example the set of assemblies referenced by a C# project.
/// </summary>
public sealed class UnitSet : IUnitSet {
/// <summary>
/// Constructs a unit set made up of the given (non empty) list of units.
/// </summary>
public UnitSet(IEnumerable<IUnit> units)
// ^ requires EnumerationHelper.EnumerableIsNotEmpty(units); //TODO: it seems impossible to establish this precondition, even with an assumption just before a call.
{
this.units = units;
}
/// <summary>
/// Determines if the given unit belongs to this set of units.
/// </summary>
public bool Contains(IUnit unit) {
bool result = IteratorHelper.EnumerableContains(this.units, unit);
//^ assume result == exists{IUnit u in this.Units; u == unit}; //TODO: Boogie: need a working postcodition on EnumerableContains
return result;
}
/// <summary>
/// Enumerates the units making up this set of units.
/// </summary>
public IEnumerable<IUnit> Units {
get {
return this.units;
}
}
readonly IEnumerable<IUnit> units;
/// <summary>
/// A unified root namespace for this set of units. It contains nested namespaces as well as top level types and anything else that implements INamespaceMember.
/// </summary>
public IUnitSetNamespace UnitSetNamespaceRoot {
get
//^ ensures result == null || result.RootOwner == this;
//^ ensures result == null || result.UnitSet == this;
{
if (this.unitSetNamespaceRoot == null) {
lock (GlobalLock.LockingObject) {
if (this.unitSetNamespaceRoot == null) {
IName rootName = Dummy.Name;
foreach (IUnit unit in this.Units) { rootName = unit.NamespaceRoot.Name; break; }
this.unitSetNamespaceRoot = new RootUnitSetNamespace(rootName, this);
this.unitSetNamespaceRoot.Locations.GetEnumerator().MoveNext();
}
}
}
//^ assume false;
return this.unitSetNamespaceRoot;
}
}
IRootUnitSetNamespace/*?*/ unitSetNamespaceRoot;
//^ invariant unitSetNamespaceRoot == null || unitSetNamespaceRoot.RootOwner == this;
//^ invariant unitSetNamespaceRoot == null || unitSetNamespaceRoot.UnitSet == this;
#region INamespaceRootOwner Members
INamespaceDefinition INamespaceRootOwner.NamespaceRoot {
get { return this.UnitSetNamespaceRoot; }
}
#endregion
}
/// <summary>
/// A namespace definition whose members are aggregations of the members of a collection of containers of the given container type.
/// </summary>
/// <typeparam name="ContainerType">The type of container that provides the members (or parts of members) for this namespace. For example NamespaceDeclaration.</typeparam>
/// <typeparam name="ContainerMemberType">The base type for members supplied by the container. For example IAggregatableNamespaceDeclarationMember.</typeparam>
public abstract class AggregatedNamespace<ContainerType, ContainerMemberType> : AggregatedScope<INamespaceMember, ContainerType, ContainerMemberType>, INamespaceDefinition
where ContainerType : class, IContainer<ContainerMemberType>
where ContainerMemberType : class, IContainerMember<ContainerType> {
/// <summary>
/// Allocates a namespace definition whose members are aggregations of the members of a collection of containers of the given container type.
/// </summary>
/// <param name="name">The name of this namespace definition.</param>
protected AggregatedNamespace(IName name) {
this.name = name;
}
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference. The dispatch method does nothing else.
/// </summary>
public abstract void Dispatch(IMetadataVisitor visitor);
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference, which is not derived from IDefinition. For example an object implemeting IArrayType will
/// call visitor.Visit(IArrayTypeReference) and not visitor.Visit(IArrayType).
/// The dispatch method does nothing else.
/// </summary>
public abstract void DispatchAsReference(IMetadataVisitor visitor);
#region IContainer<ITypeDefinitionMember>
IEnumerable<INamespaceMember> IContainer<INamespaceMember>.Members {
get {
return this.Members;
}
}
#endregion
#region INamespaceDefinition Members
IEnumerable<INamespaceMember> INamespaceDefinition.Members {
get {
return this.Members;
}
}
/// <summary>
/// The name of this namespace definition.
/// </summary>
public IName Name {
get {
return this.name;
}
}
private IName name;
/// <summary>
/// The object associated with the namespace. For example an IUnit or IUnitSet instance. This namespace is either the root namespace of that object
/// or it is a nested namespace that is directly of indirectly nested in the root namespace.
/// </summary>
public abstract INamespaceRootOwner RootOwner {
get;
}
#endregion
#region IDefinition Members
/// <summary>
/// A potentially empty collection of locations that correspond to this instance.
/// </summary>
public abstract IEnumerable<ILocation> Locations {
get;
}
#endregion
#region IDefinition Members
/// <summary>
/// A collection of metadata custom attributes that are associated with this definition.
/// </summary>
public virtual IEnumerable<ICustomAttribute> Attributes {
get { return Enumerable<ICustomAttribute>.Empty; }
}
#endregion
}
/// <summary>
/// A scope whose members are aggregations of the members of a collection of "containers". For example, a symbol table type definition whose members
/// are the aggregations of the members of a collection of source type declarations.
/// </summary>
/// <typeparam name="ScopeMemberType">The base type for members of the aggregated scope. For example ITypeDefinitionMember.</typeparam>
/// <typeparam name="ContainerType">The type of container that provides the members (or parts of members) for this scope. For example ITypeDeclaration.</typeparam>
/// <typeparam name="ContainerMemberType">The base type for members supplied by the container. For example ITypeDeclarationMember.</typeparam>
public abstract class AggregatedScope<ScopeMemberType, ContainerType, ContainerMemberType> : Scope<ScopeMemberType>
where ScopeMemberType : class, IScopeMember<IScope<ScopeMemberType>>
where ContainerType : class, IContainer<ContainerMemberType>
where ContainerMemberType : class, IContainerMember<ContainerType> {
/// <summary>
/// Takes a container member, gets a corresponding aggregated member for it and adds the latter to the member collection of this scope (if necessary).
/// Usually, the container member is added to the declarations collection of the aggregated member. This behavior is overridable. See GetAggregatedMember.
/// </summary>
/// <param name="member">The container member to aggregate. The aggregation gets cached and shows up in the Members collection of this scope.</param>
private void AddContainerMemberToCache(ContainerMemberType/*!*/ member) {
this.AddMemberToCache(this.GetAggregatedMember(member));
}
/// <summary>
/// Adds all of the members of the given container to this scope, after aggregating the members with members from other containers.
/// </summary>
/// <param name="container">A collection of members to aggregate with members from other containers and add to the members collection of this scope.</param>
protected virtual void AddContainer(ContainerType/*!*/ container) {
foreach (ContainerMemberType containerMember in container.Members) {
if (containerMember == null) continue; //TODO: see if the type system can preclude this
this.AddContainerMemberToCache(containerMember);
}
}
/// <summary>
/// Finds or creates an aggregated member instance corresponding to the given member. Usually this should result in the given member being added to the declarations
/// collection of the aggregated member.
/// </summary>
/// <param name="member">The member to aggregate.</param>
protected abstract ScopeMemberType/*!*/ GetAggregatedMember(ContainerMemberType/*!*/ member);
}
/// <summary>
///
/// </summary>
public sealed class RootUnitSetNamespace : UnitSetNamespace, IRootUnitSetNamespace {
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="unitSet"></param>
public RootUnitSetNamespace(IName name, UnitSet unitSet)
: base(name, unitSet) {
}
/// <summary>
/// Calls the visitor.Visit(IRootUnitSetNamespace) method.
/// </summary>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Throws an invalid operation exception since it makes no sense to have a reference to unit set namespace.
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
throw new InvalidOperationException();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
//^ [Confined]
public override string ToString() {
return TypeHelper.GetNamespaceName(this, NameFormattingOptions.None);
}
}
/// <summary>
///
/// </summary>
public abstract class UnitSetNamespace : AggregatedNamespace<INamespaceDefinition, INamespaceMember>, IUnitSetNamespace {
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="unitSet"></param>
protected UnitSetNamespace(IName name, UnitSet unitSet)
: base(name) {
this.unitSet = unitSet;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="unitSet"></param>
/// <param name="nestedUnitNamespaces"></param>
protected UnitSetNamespace(IName name, IUnitSet unitSet, List<IUnitNamespace> nestedUnitNamespaces)
: base(name) {
this.unitSet = unitSet;
this.unitNamespaces = nestedUnitNamespaces;
}
/// <summary>
///
/// </summary>
public override IEnumerable<ILocation> Locations {
get {
foreach (IUnitNamespace unitNamespace in this.UnitNamespaces)
foreach (ILocation location in unitNamespace.Locations)
yield return location;
}
}
/// <summary>
///
/// </summary>
/// <param name="member"></param>
/// <returns></returns>
protected override INamespaceMember GetAggregatedMember(INamespaceMember member) {
INestedUnitNamespace/*?*/ nestedUnitNamespace = member as INestedUnitNamespace;
if (nestedUnitNamespace == null) return member;
NestedUnitSetNamespace/*?*/ result;
if (!this.nestedUnitNamespaceToNestedUnitSetNamespaceMap.TryGetValue(nestedUnitNamespace.Name.UniqueKey, out result)) {
result = new NestedUnitSetNamespace(this, member.Name, this.unitSet, new List<IUnitNamespace>());
this.nestedUnitNamespaceToNestedUnitSetNamespaceMap.Add(nestedUnitNamespace.Name.UniqueKey, result);
}
//^ assume result != null && result.unitNamespaces != null;
result.unitNamespaces.Add(nestedUnitNamespace);
//TODO: thread safety
return result;
}
readonly Dictionary<int, NestedUnitSetNamespace> nestedUnitNamespaceToNestedUnitSetNamespaceMap = new Dictionary<int, NestedUnitSetNamespace>();
/// <summary>
///
/// </summary>
public override INamespaceRootOwner RootOwner {
get { return this.unitSet; }
}
/// <summary>
///
/// </summary>
protected List<IUnitNamespace> UnitNamespaces {
get {
if (this.unitNamespaces == null) {
lock (GlobalLock.LockingObject) {
if (this.unitNamespaces == null) {
List<IUnitNamespace> unitNamespaces = this.unitNamespaces = new List<IUnitNamespace>();
foreach (IUnit unit in unitSet.Units) {
unitNamespaces.Add(unit.UnitNamespaceRoot);
this.AddContainer(unit.UnitNamespaceRoot);
}
}
}
}
return this.unitNamespaces;
}
}
List<IUnitNamespace>/*?*/ unitNamespaces;
/// <summary>
///
/// </summary>
public IUnitSet UnitSet {
get { return this.unitSet; }
}
readonly IUnitSet unitSet;
}
/// <summary>
///
/// </summary>
public sealed class NestedUnitSetNamespace : UnitSetNamespace, INamespaceMember, INestedUnitSetNamespace {
internal NestedUnitSetNamespace(UnitSetNamespace containingNamespace, IName name, IUnitSet unitSet, List<IUnitNamespace> nestedUnitNamepaces)
: base(name, unitSet, nestedUnitNamepaces) {
this.containingNamespace = containingNamespace;
}
/// <summary>
/// Calls the visitor.Visit(INestedUnitSetNamespace) method.
/// </summary>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Throws an invalid operation exception since it makes no sense to have a reference to unit set namespace.
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
throw new InvalidOperationException();
}
/// <summary>
///
/// </summary>
protected override void InitializeIfNecessary() {
if (this.isInitialized) return;
lock (GlobalLock.LockingObject) {
if (this.isInitialized) return;
foreach (IUnitNamespace unitNamespace in this.UnitNamespaces)
foreach (INamespaceMember member in unitNamespace.Members)
this.AddMemberToCache(this.GetAggregatedMember(member));
this.isInitialized = true;
}
}
private bool isInitialized;
/// <summary>
///
/// </summary>
public UnitSetNamespace ContainingNamespace {
get { return this.containingNamespace; }
}
readonly UnitSetNamespace containingNamespace;
/// <summary>
///
/// </summary>
/// <returns></returns>
//^ [Confined]
public override string ToString() {
return TypeHelper.GetNamespaceName(this, NameFormattingOptions.None);
}
#region INamespaceMember Members
INamespaceDefinition INamespaceMember.ContainingNamespace {
get { return this.ContainingNamespace; }
}
#endregion
#region IScopeMember<IScope<INamespaceMember>> Members
/// <summary>
///
/// </summary>
public IScope<INamespaceMember> ContainingScope {
get { return this.ContainingNamespace; }
}
#endregion
#region IContainerMember<INamespaceDefinition> Members
/// <summary>
///
/// </summary>
public INamespaceDefinition Container {
get { return this.ContainingNamespace; }
}
IName IContainerMember<INamespaceDefinition>.Name {
get { return this.Name; }
}
#endregion
#region INestedUnitSetNamespace Members
/// <summary>
///
/// </summary>
public IUnitSetNamespace ContainingUnitSetNamespace {
get { return this.containingNamespace; }
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,521 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Globalization;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
#if !COMPACTFX && !__MonoCS__
/// <summary>
/// A managed wrapper for an unmanaged memory mapped file.
/// Important: each instance of this class holds a read-lock on a file. Instances should be explicitly disposed as soon as they become inactive.
/// </summary>
public unsafe sealed class MemoryMappedFile : IBinaryDocumentMemoryBlock, IDisposable {
private MemoryMappedFile(
IBinaryDocument binaryDocument,
byte* buffer,
uint length
) {
this.binaryDocument = binaryDocument;
this.buffer = buffer;
this.length = length;
}
/// <summary>
/// Finalizer for the Memory mapped file. Calls the CloseMap.
/// </summary>
~MemoryMappedFile() {
this.Close();
}
/// <summary>
/// Frees the memory mapped file.
/// </summary>
public void Dispose() {
this.Close();
GC.SuppressFinalize(this);
}
private void Close() {
if (buffer != null) {
MemoryMappedFile.UnmapViewOfFile(buffer);
buffer = null;
}
}
#region IBinaryDocumentMemoryBlock Members
byte* IBinaryDocumentMemoryBlock.Pointer {
get { return this.buffer; }
}
private byte* buffer;
uint IBinaryDocumentMemoryBlock.Length {
get { return this.length; }
}
private uint length;
IBinaryDocument IBinaryDocumentMemoryBlock.BinaryDocument {
get { return this.binaryDocument; }
}
private IBinaryDocument binaryDocument;
#endregion
/// <summary>
/// Factory method for opening the memory mapped file. The content of the map is assumed to come from localFileName.
/// This can throw FileLoadException in case of error.
/// </summary>
/// <param name="localFileName">Name of the file from where the binary document needs to be opened.
/// This is useful in case we want to copy the file to temporary location and then open or when we want to open document on the network.</param>
/// <param name="binaryDocument">The binary document for which the memory mapping is requested.</param>
public static MemoryMappedFile CreateMemoryMappedFile(
string localFileName,
IBinaryDocument binaryDocument
) {
uint length;
Byte* buffer;
MemoryMappedFile.OpenFileMemoryMap(localFileName, out buffer, out length);
if (length != binaryDocument.Length)
throw new IOException("File size difference: " + localFileName);
return new MemoryMappedFile(
binaryDocument,
buffer,
length
);
}
private static void OpenFileMemoryMap(string filename, out Byte* buffer, out uint length) {
IntPtr hmap;
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
if (stream.Length > Int32.MaxValue)
throw new IOException("File too Big: " + filename);
length = unchecked((uint)stream.Length);
Microsoft.Win32.SafeHandles.SafeFileHandle/*?*/ safeHandle = stream.SafeFileHandle;
if (safeHandle == null) {
throw new IOException("Unable to create Memory map: " + filename);
}
hmap = MemoryMappedFile.CreateFileMapping(safeHandle.DangerousGetHandle(), IntPtr.Zero, PageAccess.PAGE_READONLY, 0, length, null);
if (hmap == IntPtr.Zero) {
int rc = Marshal.GetLastWin32Error();
throw new IOException("Unable to create Memory map: " + filename + " - " + rc.ToString("X", CultureInfo.InvariantCulture));
}
}
buffer = (byte*)MemoryMappedFile.MapViewOfFile(hmap, FileMapAccess.FILE_MAP_READ, 0, 0, (IntPtr)length);
MemoryMappedFile.CloseHandle(hmap);
if (buffer == null) {
int rc = Marshal.GetLastWin32Error();
throw new IOException("Unable to create Memory map: " + filename + " - " +rc.ToString("X", CultureInfo.InvariantCulture));
}
}
#region Interop stuff
private enum PageAccess : int { PAGE_READONLY = 0x02 };
private enum FileMapAccess : int { FILE_MAP_READ = 0x0004 };
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateFileMapping(
IntPtr hFile, // handle to file
IntPtr lpAttributes, // security
PageAccess flProtect, // protection
uint dwMaximumSizeHigh, // high-order DWORD of size
uint dwMaximumSizeLow, // low-order DWORD of size
string/*?*/ lpName // object name
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern void* MapViewOfFile(
IntPtr hFileMappingObject, // handle to file-mapping object
FileMapAccess dwDesiredAccess, // access mode
int dwFileOffsetHigh, // high-order DWORD of offset
int dwFileOffsetLow, // low-order DWORD of offset
IntPtr dwNumberOfBytesToMap // number of bytes to map
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnmapViewOfFile(
void* lpBaseAddress // starting address
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(
IntPtr hObject // handle to object
);
#endregion Interop stuff
}
#endif
/// <summary>
/// A managed wrapper for a block of memory allocated from the unmanaged heap.
/// Important: each instance of this class holds a read-lock on a file. Instances should be explicitly disposed as soon as they become inactive.
/// </summary>
public unsafe sealed class UnmanagedBinaryMemoryBlock : IBinaryDocumentMemoryBlock, IDisposable {
IBinaryDocument binaryDocument;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
IntPtr Pointer;
private UnmanagedBinaryMemoryBlock(IBinaryDocument binaryDocument) {
this.binaryDocument = binaryDocument;
this.Pointer = Marshal.AllocHGlobal((int)binaryDocument.Length);
if (this.Pointer == IntPtr.Zero) {
throw new OutOfMemoryException();
}
}
/// <summary>
/// Frees the umanaged memory block.
/// </summary>
~UnmanagedBinaryMemoryBlock() {
this.Close();
}
/// <summary>
/// Frees the umanaged memory block.
/// </summary>
public void Dispose() {
this.Close();
GC.SuppressFinalize(this);
}
private void Close() {
if (this.Pointer != IntPtr.Zero)
Marshal.FreeHGlobal(this.Pointer);
this.Pointer = IntPtr.Zero;
}
#region IBinaryDocumentMemoryBlock Members
IBinaryDocument IBinaryDocumentMemoryBlock.BinaryDocument {
get { return this.binaryDocument; }
}
byte* IBinaryDocumentMemoryBlock.Pointer {
get { return (byte*)this.Pointer; }
}
uint IBinaryDocumentMemoryBlock.Length {
get { return this.binaryDocument.Length; }
}
#endregion
/// <summary>
/// Creates an unmanaged binary memory block and copies the contents of the file at the given location into the block.
/// </summary>
/// <param name="localFileName">The path to the file to read.</param>
/// <param name="binaryDocument">The binary document whose contents are stored in the given file.</param>
/// <exception cref="System.ArgumentException">localFileName is an empty string (""), contains only white space, or contains one
/// or more invalid characters. -or- localFileName refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in an NTFS environment.</exception>
/// <exception cref="System.NotSupportedException">localFileName refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in a non-NTFS environment.</exception>
/// <exception cref="System.IO.FileNotFoundException">The file specified by localFileName does not exist.</exception>
/// <exception cref="System.Security.SecurityException">The caller does not have the required permission.</exception>
/// <exception cref="System.IO.DirectoryNotFoundException">The specified path is invalid, such as being on an unmapped drive.</exception>
/// <exception cref="System.UnauthorizedAccessException">The file cannot be be read, for example because it is already being accessed exclusively by another process.</exception>
/// <exception cref="System.IO.PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms,
/// paths must be less than 248 characters, and file names must be less than 260 characters.</exception>
public static UnmanagedBinaryMemoryBlock CreateUnmanagedBinaryMemoryBlock(string localFileName, IBinaryDocument binaryDocument) {
using (FileStream stream = new FileStream(localFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
return CreateUnmanagedBinaryMemoryBlock(stream, binaryDocument);
}
}
/// <summary>
/// Creates an unmanaged binary memory block and copies the contents of the given stream into the block.
/// </summary>
/// <param name="stream">A stream of bytes that are to be copied into the resulting memory block.</param>
/// <param name="binaryDocument">The binary document whose contents are stored in the given file.</param>
/// <exception cref="System.IO.IOException">The length of the stream is not the same as the length of the binary document, or the stream length is greater than Int32.MaxValue.</exception>
public static UnmanagedBinaryMemoryBlock CreateUnmanagedBinaryMemoryBlock(Stream stream, IBinaryDocument binaryDocument) {
if (stream.Length != binaryDocument.Length)
throw new IOException("stream.Length != binaryDocument.Length: " + binaryDocument.Location);
if (stream.Length > Int32.MaxValue)
throw new IOException("stream.Length > Int32.MaxValue: " + binaryDocument.Location);
UnmanagedBinaryMemoryBlock unmanagedBinaryMemoryBlock = new UnmanagedBinaryMemoryBlock(binaryDocument);
byte* pMainBuffer = (byte*)unmanagedBinaryMemoryBlock.Pointer;
//Read a fixed length block at a time, so that the GC does not come under pressure from lots of large byte arrays.
int remainingLength = (int)binaryDocument.Length;
int copyBufferLength = 8096;
byte[] tempBuffer = new byte[copyBufferLength];
fixed (byte* tempBufferPtr = tempBuffer) {
while (remainingLength > 0) {
if (remainingLength < copyBufferLength) {
copyBufferLength = remainingLength;
}
stream.Read(tempBuffer, 0, copyBufferLength);
byte* iterBuffer = tempBufferPtr;
byte* endBuffer = tempBufferPtr + copyBufferLength;
while (iterBuffer < endBuffer) {
*pMainBuffer++ = *iterBuffer++;
}
remainingLength -= copyBufferLength;
}
}
return unmanagedBinaryMemoryBlock;
}
/// <summary>
/// Creates an unmanaged binary memory block and copies the contents of the given byte enumeration into the block.
/// </summary>
/// <param name="stream">A stream of bytes that are to be copied into the resulting memory block.</param>
/// <param name="binaryDocument">The binary document whose contents are stored in the given file.</param>
/// <exception cref="System.IO.IOException">The length of the stream is not the same as the length of the binary document, or the stream length is greater than Int32.MaxValue.</exception>
public static UnmanagedBinaryMemoryBlock CreateUnmanagedBinaryMemoryBlock(IEnumerable<byte> stream, IBinaryDocument binaryDocument) {
UnmanagedBinaryMemoryBlock unmanagedBinaryMemoryBlock = new UnmanagedBinaryMemoryBlock(binaryDocument);
byte* pMainBuffer = (byte*)unmanagedBinaryMemoryBlock.Pointer;
byte* endOfBuffer = pMainBuffer + binaryDocument.Length;
foreach (var b in stream) {
if (pMainBuffer == endOfBuffer) throw new IOException("stream length != binaryDocument.Length: " + binaryDocument.Location);
*pMainBuffer++ = b;
}
if (pMainBuffer != endOfBuffer) throw new IOException("stream length != binaryDocument.Length: " + binaryDocument.Location);
return unmanagedBinaryMemoryBlock;
}
}
/// <summary>
/// Class representing a binary document
/// </summary>
public sealed class BinaryDocument : IBinaryDocument {
/// <summary>
/// Constructor for the Binay Document.
/// </summary>
/// <param name="location"></param>
/// <param name="name"></param>
/// <param name="length"></param>
public BinaryDocument(string location, IName name, uint length) {
this.location = location;
this.name = name;
this.length = length;
}
#region IBinaryDocument Members
uint IBinaryDocument.Length {
get { return this.length; }
}
uint length;
#endregion
#region IDocument Members
string IDocument.Location {
get { return this.location; }
}
string location;
IName IDocument.Name {
get { return this.name; }
}
IName name;
#endregion
/// <summary>
/// Static factory method for getting the Binary document given full file path. Note this reads the file on the disk hence can throw some of the IO exceptions.
/// </summary>
/// <param name="fullFilePath"></param>
/// <param name="compilationHost"></param>
public static BinaryDocument GetBinaryDocumentForFile(string fullFilePath, IMetadataHost compilationHost) {
Contract.Requires(fullFilePath != null);
Contract.Requires(compilationHost != null);
Contract.Ensures(Contract.Result<BinaryDocument>() != null);
IName name = compilationHost.NameTable.GetNameFor(Path.GetFileName(fullFilePath));
FileInfo fileInfo = new FileInfo(fullFilePath);
uint length = 0;
if (fileInfo.Exists) {
//TODO: error if file too large
length = (uint)fileInfo.Length;
}
return new BinaryDocument(fullFilePath, name, length);
}
}
/// <summary>
/// Class representing the Binary location.
/// </summary>
public sealed class BinaryLocation : IBinaryLocation {
//^ [SpecPublic]
IBinaryDocument binaryDocument;
uint offset;
//^ invariant offset >= 0 && offset <= binaryDocument.Length;
/// <summary>
/// Constructor for the Binary location
/// </summary>
/// <param name="binaryDocument"></param>
/// <param name="offset"></param>
public BinaryLocation(
IBinaryDocument binaryDocument,
uint offset
) {
this.binaryDocument = binaryDocument;
this.offset = offset;
}
#region IBinaryLocation Members
IBinaryDocument IBinaryLocation.BinaryDocument {
get
//^ ensures result == this.binaryDocument;
{
return this.binaryDocument;
}
}
uint IBinaryLocation.Offset {
get {
//^ assume ((IBinaryLocation)this).BinaryDocument == this.binaryDocument; //see above
return this.offset;
}
}
#endregion
#region ILocation Members
IDocument ILocation.Document {
get { return this.binaryDocument; }
}
#endregion
/// <summary>
/// Compares the equality of two locations.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
//^ [Confined, MustOverride]
public override bool Equals(object/*?*/ obj) {
BinaryLocation/*?*/ binaryLocation = obj as BinaryLocation;
if (binaryLocation == null)
return false;
if (this.offset != binaryLocation.offset)
return false;
return this.binaryDocument.Location.Equals(binaryLocation.binaryDocument.Location);
}
/// <summary>
/// Gives the hash code of the location
/// </summary>
/// <returns></returns>
//^ [Confined, MustOverride]
public override int GetHashCode() {
return this.offset.GetHashCode();
}
/// <summary>
/// Gives the string representing the location
/// </summary>
/// <returns></returns>
//^ [Confined, MustOverride]
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb.AppendFormat(CultureInfo.InvariantCulture, "BinaryLocation({0},{1})", this.binaryDocument.Location, this.offset);
return sb.ToString();
}
}
/// <summary>
/// Class representing the location in IL stream.
/// </summary>
public sealed class ILLocation : IILLocation {
readonly IBinaryDocument binaryDocument;
readonly IMethodDefinition methodDefinition;
readonly uint offset;
/// <summary>
/// Constructor for IL location
/// </summary>
/// <param name="binaryDocument"></param>
/// <param name="methodDefinition"></param>
/// <param name="offset"></param>
public ILLocation(
IBinaryDocument binaryDocument,
IMethodDefinition methodDefinition,
uint offset
) {
this.binaryDocument = binaryDocument;
this.methodDefinition = methodDefinition;
this.offset = offset;
}
#region IILLocation Members
IMethodDefinition IILLocation.MethodDefinition {
get { return this.methodDefinition; }
}
uint IILLocation.Offset {
get { return this.offset; }
}
#endregion
#region ILocation Members
IDocument ILocation.Document {
get { return this.binaryDocument; }
}
#endregion
/// <summary>
/// Compares the equality of two locations.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
//^ [Confined, MustOverride]
public override bool Equals(object/*?*/ obj) {
ILLocation/*?*/ ilLocation = obj as ILLocation;
if (ilLocation == null)
return false;
if (this.offset != ilLocation.offset)
return false;
if (this.methodDefinition.Equals(ilLocation.methodDefinition))
return false;
return this.binaryDocument.Location.Equals(ilLocation.binaryDocument.Location);
}
/// <summary>
/// Gives the hash code of the location
/// </summary>
/// <returns></returns>
//^ [Confined, MustOverride]
public override int GetHashCode() {
return this.offset.GetHashCode() ^ this.methodDefinition.GetHashCode();
}
/// <summary>
/// Gives the string representing the location
/// </summary>
/// <returns></returns>
//^ [Confined, MustOverride]
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb.AppendFormat(CultureInfo.InvariantCulture, "ILLocation({0},0x{1})", this.methodDefinition.ToString(), this.offset.ToString("X8", CultureInfo.InvariantCulture));
return sb.ToString();
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,265 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
/// <summary>
/// An expression that does not change its value at runtime and can be evaluated at compile time.
/// </summary>
public interface IMetadataConstant : IMetadataExpression {
/// <summary>
/// The compile time value of the expression. Can be null.
/// </summary>
object/*?*/ Value { get; }
}
/// <summary>
/// Implemented by IFieldDefinition, IParameterDefinition and IPropertyDefinition.
/// </summary>
public interface IMetadataConstantContainer {
/// <summary>
/// The constant value associated with this metadata object. For example, the default value of a parameter.
/// </summary>
IMetadataConstant Constant { get; }
}
/// <summary>
/// An expression that creates an array instance in metadata. Only for use in custom attributes.
/// </summary>
[ContractClass(typeof(IMetadataCreateArrayContract))]
public interface IMetadataCreateArray : IMetadataExpression {
/// <summary>
/// The element type of the array.
/// </summary>
ITypeReference ElementType { get; }
/// <summary>
/// The initial values of the array elements. May be empty.
/// </summary>
IEnumerable<IMetadataExpression> Initializers {
get;
}
/// <summary>
/// The index value of the first element in each dimension.
/// </summary>
IEnumerable<int> LowerBounds {
get;
// ^ ensures count{int lb in result} == Rank;
}
/// <summary>
/// The number of dimensions of the array.
/// </summary>
uint Rank {
get;
//^ ensures result > 0;
}
/// <summary>
/// The number of elements allowed in each dimension.
/// </summary>
IEnumerable<ulong> Sizes {
get;
// ^ ensures count{int size in result} == Rank;
}
}
#region IMetadataCreateArray contract binding
[ContractClassFor(typeof(IMetadataCreateArray))]
abstract class IMetadataCreateArrayContract : IMetadataCreateArray {
public ITypeReference ElementType {
get {
Contract.Ensures(Contract.Result<ITypeReference>() != null);
throw new NotImplementedException();
}
}
public IEnumerable<IMetadataExpression> Initializers {
get {
Contract.Ensures(Contract.Result<IEnumerable<IMetadataExpression>>() != null);
throw new NotImplementedException();
}
}
public IEnumerable<int> LowerBounds {
get {
Contract.Ensures(Contract.Result<IEnumerable<int>>() != null);
throw new NotImplementedException();
}
}
public uint Rank {
get {
Contract.Ensures(Contract.Result<uint>() > 0);
throw new NotImplementedException();
}
}
public IEnumerable<ulong> Sizes {
get {
Contract.Ensures(Contract.Result<IEnumerable<ulong>>() != null);
throw new NotImplementedException();
}
}
public ITypeReference Type {
get {
throw new NotImplementedException();
}
}
public IEnumerable<ILocation> Locations {
get {
throw new NotImplementedException();
}
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
#endregion
/// <summary>
/// An expression that can be represented directly in metadata.
/// </summary>
[ContractClass(typeof(IMetadataExpressionContract))]
public interface IMetadataExpression : IObjectWithLocations {
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IStatement. The dispatch method does not invoke Dispatch on any child objects. If child traversal
/// is desired, the implementations of the Visit methods should do the subsequent dispatching.
/// </summary>
void Dispatch(IMetadataVisitor visitor);
/// <summary>
/// The type of value the expression represents.
/// </summary>
ITypeReference Type { get; }
}
#region IMetadataExpression contract binding
[ContractClassFor(typeof(IMetadataExpression))]
abstract class IMetadataExpressionContract : IMetadataExpression {
public void Dispatch(IMetadataVisitor visitor) {
Contract.Requires(visitor != null);
throw new NotImplementedException();
}
public ITypeReference Type {
get {
Contract.Ensures(Contract.Result<ITypeReference>() != null);
throw new NotImplementedException();
}
}
public IEnumerable<ILocation> Locations {
get {
throw new NotImplementedException();
}
}
}
#endregion
/// <summary>
/// An expression that represents a (name, value) pair and that is typically used in method calls, custom attributes and object initializers.
/// </summary>
[ContractClass(typeof(IMetadataNamedArgumentContract))]
public interface IMetadataNamedArgument : IMetadataExpression {
/// <summary>
/// The name of the parameter or property or field that corresponds to the argument.
/// </summary>
IName ArgumentName { get; }
/// <summary>
/// The value of the argument.
/// </summary>
IMetadataExpression ArgumentValue { get; }
/// <summary>
/// True if the named argument provides the value of a field.
/// </summary>
bool IsField { get; }
/// <summary>
/// Returns either null or the parameter or property or field that corresponds to this argument.
/// Obsolete, please do not use.
/// </summary>
object/*?*/ ResolvedDefinition { //TODO: remove this
get;
//^ ensures result == null || (IsField <==> result is IFieldDefinition) || result is IPropertyDefinition;
}
}
[ContractClassFor(typeof(IMetadataNamedArgument))]
abstract class IMetadataNamedArgumentContract : IMetadataNamedArgument {
public IName ArgumentName {
get {
Contract.Ensures(Contract.Result<IName>() != null);
throw new NotImplementedException();
}
}
public IMetadataExpression ArgumentValue {
get {
Contract.Ensures(Contract.Result<IMetadataExpression>() != null);
throw new NotImplementedException();
}
}
public bool IsField {
get {
throw new NotImplementedException();
}
}
public object ResolvedDefinition {
get {
Contract.Ensures(Contract.Result<object>() == null || (this.IsField && Contract.Result<object>() is IFieldDefinition) ||
(!this.IsField && Contract.Result<object>() is IPropertyDefinition));
throw new NotImplementedException();
}
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public ITypeReference Type {
get { throw new NotImplementedException(); }
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
}
/// <summary>
/// An expression that results in a System.Type instance.
/// </summary>
public interface IMetadataTypeOf : IMetadataExpression {
/// <summary>
/// The type that will be represented by the System.Type instance.
/// </summary>
ITypeReference TypeToGet { get; }
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci</RootNamespace>
<AssemblyName>Microsoft.Cci.MetadataModel</AssemblyName>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>true</SignAssembly>
<CodeAnalysisRules>-Microsoft.Design#CA1040;-Microsoft.Design#CA1021;-Microsoft.Design#CA1051;-Microsoft.Design#CA1008;-Microsoft.Design#CA1004;-Microsoft.Design#CA1024;-Microsoft.Design#CA1062;-Microsoft.Maintainability#CA1500;-Microsoft.Naming#CA1718;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1706;-Microsoft.Security#CA2104</CodeAnalysisRules>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Microsoft.Cci.MetadataModel.xml</DocumentationFile>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors>1591</WarningsAsErrors>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;AllowCsharpConstructorSyntax</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Release\Microsoft.Cci.MetadataModel.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyDebug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\NightlyDebug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<DocumentationFile>bin\NightlyDebug\Microsoft.Cci.MetadataModel.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyRelease|AnyCPU' ">
<OutputPath>bin\NightlyRelease\</OutputPath>
<DefineConstants>TRACE;AllowCsharpConstructorSyntax</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<DocumentationFile>bin\NightlyRelease\Microsoft.Cci.MetadataModel.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CompilerOnly|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\CompilerOnly\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\Microsoft.Cci.MetadataModel.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<WarningsAsErrors>1591</WarningsAsErrors>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\version.cs">
<Link>Build\version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Core.cs" />
<Compile Include="DummyObjects.cs" />
<Compile Include="Expressions.cs" />
<Compile Include="Members.cs" />
<Compile Include="Miscellaneous.cs" />
<Compile Include="Namespaces.cs" />
<Compile Include="Types.cs" />
<Compile Include="Units.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Core.cd">
<SubType>
</SubType>
</Content>
<Content Include="Members.cd" />
<Content Include="Namespaces.cd" />
<Content Include="Types.cd" />
<Content Include="Units.cd" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,644 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci {
/// <summary>
/// A definition that is a member of a namespace. Typically a nested namespace or a namespace type definition.
/// </summary>
[ContractClass(typeof(INamespaceMemberContract))]
public interface INamespaceMember : IContainerMember<INamespaceDefinition>, IDefinition, IScopeMember<IScope<INamespaceMember>> {
/// <summary>
/// The namespace that contains this member.
/// </summary>
INamespaceDefinition ContainingNamespace { get; }
}
[ContractClassFor(typeof(INamespaceMember))]
abstract class INamespaceMemberContract : INamespaceMember {
public INamespaceDefinition ContainingNamespace {
get {
Contract.Ensures(Contract.Result<INamespaceDefinition>() != null);
throw new NotImplementedException();
}
}
public INamespaceDefinition Container {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IScope<INamespaceMember> ContainingScope {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// Implemented by objects that are associated with a root INamespace object.
/// </summary>
[ContractClass(typeof(INamespaceRootOwnerContract))]
public interface INamespaceRootOwner {
/// <summary>
/// The associated root namespace.
/// </summary>
INamespaceDefinition NamespaceRoot {
get;
//^ ensures result.RootOwner == this;
}
}
[ContractClassFor(typeof(INamespaceRootOwner))]
abstract class INamespaceRootOwnerContract : INamespaceRootOwner {
public INamespaceDefinition NamespaceRoot {
get {
Contract.Ensures(Contract.Result<INamespaceDefinition>() != null);
throw new NotImplementedException();
}
}
}
/// <summary>
/// A unit namespace that is nested inside another unit namespace.
/// </summary>
[ContractClass(typeof(INestedUnitNamespaceContract))]
public interface INestedUnitNamespace : IUnitNamespace, INamespaceMember, INestedUnitNamespaceReference {
/// <summary>
/// The unit namespace that contains this member.
/// </summary>
new IUnitNamespace ContainingUnitNamespace { get; }
}
[ContractClassFor(typeof(INestedUnitNamespace))]
abstract class INestedUnitNamespaceContract : INestedUnitNamespace {
public IUnitNamespace ContainingUnitNamespace {
get {
Contract.Ensures(Contract.Result<IUnitNamespace>() != null);
throw new NotImplementedException();
}
}
public IUnit Unit {
get { throw new NotImplementedException(); }
}
public INamespaceRootOwner RootOwner {
get { throw new NotImplementedException(); }
}
public IEnumerable<INamespaceMember> Members {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public bool Contains(INamespaceMember member) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
throw new NotImplementedException();
}
IUnitReference IUnitNamespaceReference.Unit {
get { throw new NotImplementedException(); }
}
public IUnitNamespace ResolvedUnitNamespace {
get { throw new NotImplementedException(); }
}
public INamespaceDefinition ContainingNamespace {
get { throw new NotImplementedException(); }
}
public INamespaceDefinition Container {
get { throw new NotImplementedException(); }
}
public IScope<INamespaceMember> ContainingScope {
get { throw new NotImplementedException(); }
}
IUnitNamespaceReference INestedUnitNamespaceReference.ContainingUnitNamespace {
get { throw new NotImplementedException(); }
}
public INestedUnitNamespace ResolvedNestedUnitNamespace {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// A reference to a nested unit namespace.
/// </summary>
[ContractClass(typeof(INestedUnitNamespaceReferenceContract))]
public interface INestedUnitNamespaceReference : IUnitNamespaceReference, INamedEntity {
/// <summary>
/// A reference to the unit namespace that contains the referenced nested unit namespace.
/// </summary>
IUnitNamespaceReference ContainingUnitNamespace { get; }
/// <summary>
/// The namespace definition being referred to.
/// </summary>
INestedUnitNamespace ResolvedNestedUnitNamespace { get; }
}
[ContractClassFor(typeof(INestedUnitNamespaceReference))]
abstract class INestedUnitNamespaceReferenceContract : INestedUnitNamespaceReference {
public IUnitNamespaceReference ContainingUnitNamespace {
get {
Contract.Ensures(Contract.Result<IUnitNamespaceReference>() != null);
Contract.Ensures(Contract.Result<IUnitNamespaceReference>() != this);
throw new NotImplementedException();
}
}
public INestedUnitNamespace ResolvedNestedUnitNamespace {
get {
Contract.Ensures(Contract.Result<INestedUnitNamespace>() != null);
throw new NotImplementedException();
}
}
public IUnitReference Unit {
get { throw new NotImplementedException(); }
}
public IUnitNamespace ResolvedUnitNamespace {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// A unit set namespace that is nested inside another unit set namespace.
/// </summary>
[ContractClass(typeof(INestedUnitSetNamespaceContract))]
public interface INestedUnitSetNamespace : IUnitSetNamespace, INamespaceMember {
/// <summary>
/// The unit set namespace that contains this member.
/// </summary>
IUnitSetNamespace ContainingUnitSetNamespace { get; }
}
[ContractClassFor(typeof(INestedUnitSetNamespace))]
abstract class INestedUnitSetNamespaceContract : INestedUnitSetNamespace {
public IUnitSetNamespace ContainingUnitSetNamespace {
get {
Contract.Ensures(Contract.Result<IUnitSetNamespace>() != null);
throw new NotImplementedException();
}
}
public IUnitSet UnitSet {
get { throw new NotImplementedException(); }
}
public INamespaceRootOwner RootOwner {
get { throw new NotImplementedException(); }
}
public IEnumerable<INamespaceMember> Members {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public bool Contains(INamespaceMember member) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
throw new NotImplementedException();
}
public INamespaceDefinition ContainingNamespace {
get { throw new NotImplementedException(); }
}
public INamespaceDefinition Container {
get { throw new NotImplementedException(); }
}
public IScope<INamespaceMember> ContainingScope {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// A named collection of namespace members, with routines to search and maintain the collection.
/// </summary>
[ContractClass(typeof(INamespaceDefinitionContract))]
public interface INamespaceDefinition : IContainer<INamespaceMember>, IDefinition, INamedEntity, IScope<INamespaceMember> {
/// <summary>
/// The object associated with the namespace. For example an IUnit or IUnitSet instance. This namespace is either the root namespace of that object
/// or it is a nested namespace that is directly of indirectly nested in the root namespace.
/// </summary>
INamespaceRootOwner RootOwner {
get;
}
/// <summary>
/// The collection of member objects comprising the namespaces.
/// </summary>
new IEnumerable<INamespaceMember> Members {
get;
}
}
[ContractClassFor(typeof(INamespaceDefinition))]
abstract class INamespaceDefinitionContract : INamespaceDefinition {
public INamespaceRootOwner RootOwner {
get {
Contract.Ensures(Contract.Result<INamespaceRootOwner>() != null);
throw new NotImplementedException();
}
}
IEnumerable<INamespaceMember> INamespaceDefinition.Members {
get {
Contract.Ensures(Contract.Result<IEnumerable<INamespaceMember>>() != null);
Contract.Ensures(Contract.ForAll(Contract.Result<IEnumerable<INamespaceMember>>(), x => x != null));
throw new NotImplementedException();
}
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public bool Contains(INamespaceMember member) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
throw new NotImplementedException();
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> Members {
get { throw new NotImplementedException(); }
}
}
/// <summary>
/// A unit namespace that is not nested inside another namespace.
/// </summary>
public interface IRootUnitNamespace : IUnitNamespace, IRootUnitNamespaceReference {
}
/// <summary>
/// A reference to a root unit namespace.
/// </summary>
public interface IRootUnitNamespaceReference : IUnitNamespaceReference {
}
/// <summary>
/// A named collection of namespace members, with routines to search and maintain the collection. All the members belong to an associated
/// IUnit instance.
/// </summary>
[ContractClass(typeof(IUnitNamespaceContract))]
public interface IUnitNamespace : INamespaceDefinition, IUnitNamespaceReference {
/// <summary>
/// The IUnit instance associated with this namespace.
/// </summary>
new IUnit Unit {
get;
}
}
[ContractClassFor(typeof(IUnitNamespace))]
abstract class IUnitNamespaceContract : IUnitNamespace {
public IUnit Unit {
get {
Contract.Ensures(Contract.Result<IUnit>() != null);
throw new NotImplementedException();
}
}
public INamespaceRootOwner RootOwner {
get { throw new NotImplementedException(); }
}
public IEnumerable<INamespaceMember> Members {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public bool Contains(INamespaceMember member) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
throw new NotImplementedException();
}
IUnitReference IUnitNamespaceReference.Unit {
get { throw new NotImplementedException(); }
}
public IUnitNamespace ResolvedUnitNamespace {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// A reference to an unit namespace.
/// </summary>
public partial interface IUnitNamespaceReference : IReference {
/// <summary>
/// A reference to the unit that defines the referenced namespace.
/// </summary>
IUnitReference Unit {
get;
}
/// <summary>
/// The namespace definition being referred to.
/// </summary>
IUnitNamespace ResolvedUnitNamespace { get; }
}
#region IUnitNamespaceReference contract binding
[ContractClass(typeof(IUnitNamespaceReferenceContract))]
public partial interface IUnitNamespaceReference {
}
[ContractClassFor(typeof(IUnitNamespaceReference))]
abstract class IUnitNamespaceReferenceContract : IUnitNamespaceReference {
public IUnitReference Unit {
get {
Contract.Ensures(Contract.Result<IUnitReference>() != null);
throw new NotImplementedException();
}
}
public IUnitNamespace ResolvedUnitNamespace {
get {
Contract.Ensures(Contract.Result<IUnitNamespace>() != null);
throw new NotImplementedException();
}
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
#endregion
/// <summary>
/// A named collection of namespace members, with routines to search and maintain the collection. The collection of members
/// is the union of the individual members collections of one of more IUnit instances making up the IUnitSet instance associated
/// with this namespace.
/// </summary>
// Issue: If we just want to model Metadata/Language independent model faithfully, why do we need unit sets etc? This seems to be more of an
// Symbol table lookup helper interface.
[ContractClass(typeof(IUnitSetNamespaceContract))]
public interface IUnitSetNamespace : INamespaceDefinition {
/// <summary>
/// The IUnitSet instance associated with the namespace.
/// </summary>
IUnitSet UnitSet {
get;
}
}
[ContractClassFor(typeof(IUnitSetNamespace))]
abstract class IUnitSetNamespaceContract : IUnitSetNamespace {
public IUnitSet UnitSet {
get {
Contract.Ensures(Contract.Result<IUnitSet>() != null);
throw new NotImplementedException();
}
}
public INamespaceRootOwner RootOwner {
get { throw new NotImplementedException(); }
}
public IEnumerable<INamespaceMember> Members {
get { throw new NotImplementedException(); }
}
public IEnumerable<ICustomAttribute> Attributes {
get { throw new NotImplementedException(); }
}
public void Dispatch(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
public IEnumerable<ILocation> Locations {
get { throw new NotImplementedException(); }
}
public IName Name {
get { throw new NotImplementedException(); }
}
public bool Contains(INamespaceMember member) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
throw new NotImplementedException();
}
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
throw new NotImplementedException();
}
public void DispatchAsReference(IMetadataVisitor visitor) {
throw new NotImplementedException();
}
}
/// <summary>
/// A unit set namespace that is not nested inside another namespace.
/// </summary>
public interface IRootUnitSetNamespace : IUnitSetNamespace {
}
}

Просмотреть файл

@ -0,0 +1,28 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All Rights Reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsoft.Cci.MetadataModel")]
[assembly: AssemblyDescription("An object model for CLR metadata and IL")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("62878a7b-9cd8-48f0-af78-02b7583ab03d")]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,365 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
//^ using Microsoft.Contracts;
namespace Microsoft.Cci.MutableCodeModel {
/// <summary>
/// An expression that does not change its value at runtime and can be evaluated at compile time.
/// </summary>
public sealed class MetadataConstant : MetadataExpression, IMetadataConstant, ICopyFrom<IMetadataConstant> {
/// <summary>
/// An expression that does not change its value at runtime and can be evaluated at compile time.
/// </summary>
public MetadataConstant() {
this.value = null;
}
/// <summary>
/// An expression that does not change its value at runtime and can be evaluated at compile time.
/// </summary>
/// <param name="metadataConstant">A template from which to construct a shallow copy.</param>
/// <param name="internFactory">The intern factory to use for computing the interned identity (if applicable) of this mutable object.</param>
public void Copy(IMetadataConstant metadataConstant, IInternFactory internFactory) {
((ICopyFrom<IMetadataExpression>)this).Copy(metadataConstant, internFactory);
this.value = metadataConstant.Value;
}
/// <summary>
/// Calls visitor(IMetadataConstant).
/// </summary>
/// <param name="visitor"></param>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// The compile time value of the expression. Can be null.
/// </summary>
/// <value></value>
public object Value {
get { return this.value; }
set { this.value = value; }
}
object value;
}
/// <summary>
/// An expression that creates an array instance in metadata. Only for use in custom attributes.
/// </summary>
public sealed class MetadataCreateArray : MetadataExpression, IMetadataCreateArray, ICopyFrom<IMetadataCreateArray> {
/// <summary>
/// An expression that creates an array instance in metadata. Only for use in custom attributes.
/// </summary>
public MetadataCreateArray() {
this.elementType = Dummy.TypeReference;
this.initializers = null;
this.lowerBounds = null;
this.rank = 0;
this.sizes = null;
}
/// <summary>
/// Makes a shallow copy of an expression that creates an array instance in metadata. Only for use in custom attributes.
/// </summary>
/// <param name="createArray"></param>
/// <param name="internFactory"></param>
public void Copy(IMetadataCreateArray createArray, IInternFactory internFactory) {
((ICopyFrom<IMetadataExpression>)this).Copy(createArray, internFactory);
this.elementType = createArray.ElementType;
if (!IteratorHelper.EnumerableIsEmpty(createArray.Initializers))
this.initializers = new List<IMetadataExpression>(createArray.Initializers);
if (!IteratorHelper.EnumerableIsEmpty(createArray.LowerBounds))
this.lowerBounds = new List<int>(createArray.LowerBounds);
this.rank = createArray.Rank;
if (!IteratorHelper.EnumerableIsEmpty(createArray.Sizes))
this.sizes = new List<ulong>(createArray.Sizes);
}
/// <summary>
/// Calls visitor.Visit(IMetadataCreateArray).
/// </summary>
/// <param name="visitor"></param>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// The element type of the array.
/// </summary>
/// <value></value>
public ITypeReference ElementType {
get { return this.elementType; }
set { this.elementType = value; }
}
ITypeReference elementType;
/// <summary>
/// The initial values of the array elements. May be empty or null.
/// </summary>
/// <value></value>
public List<IMetadataExpression>/*?*/ Initializers {
get { return this.initializers; }
set { this.initializers = value; }
}
List<IMetadataExpression>/*?*/ initializers;
/// <summary>
/// The index value of the first element in each dimension. May be null.
/// </summary>
/// <value></value>
public List<int>/*?*/ LowerBounds {
get { return this.lowerBounds; }
set { this.lowerBounds = value; }
}
List<int>/*?*/ lowerBounds;
/// <summary>
/// The number of dimensions of the array.
/// </summary>
/// <value></value>
public uint Rank {
get { return this.rank; }
set { this.rank = value; }
}
uint rank;
/// <summary>
/// The number of elements allowed in each dimension. May be null.
/// </summary>
/// <value></value>
public List<ulong>/*?*/ Sizes {
get { return this.sizes; }
set { this.sizes = value; }
}
List<ulong>/*?*/ sizes;
#region IMetadataCreateArray Members
IEnumerable<IMetadataExpression> IMetadataCreateArray.Initializers {
get {
if (this.initializers == null) return Enumerable<IMetadataExpression>.Empty;
return this.initializers.AsReadOnly();
}
}
IEnumerable<int> IMetadataCreateArray.LowerBounds {
get {
if (this.lowerBounds == null) return Enumerable<int>.Empty;
return this.lowerBounds.AsReadOnly();
}
}
IEnumerable<ulong> IMetadataCreateArray.Sizes {
get {
if (this.sizes == null) return Enumerable<ulong>.Empty;
return this.sizes.AsReadOnly();
}
}
#endregion
}
/// <summary>
/// An expression that can be represented directly in metadata.
/// </summary>
public abstract class MetadataExpression : IMetadataExpression, ICopyFrom<IMetadataExpression> {
/// <summary>
/// An expression that can be represented directly in metadata.
/// </summary>
internal MetadataExpression() {
this.locations = null;
this.type = Dummy.TypeReference;
}
/// <summary>
/// Makes a shallow copy of an expression that can be represented directly in metadata.
/// </summary>
/// <param name="metadataExpression"></param>
/// <param name="internFactory"></param>
public void Copy(IMetadataExpression metadataExpression, IInternFactory internFactory) {
if (IteratorHelper.EnumerableIsNotEmpty(metadataExpression.Locations))
this.locations = new List<ILocation>(metadataExpression.Locations);
this.type = metadataExpression.Type;
}
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IStatement. The dispatch method does not invoke Dispatch on any child objects. If child traversal
/// is desired, the implementations of the Visit methods should do the subsequent dispatching.
/// </summary>
/// <param name="visitor"></param>
public abstract void Dispatch(IMetadataVisitor visitor);
/// <summary>
/// A potentially empty collection of locations that correspond to this instance. May be null.
/// </summary>
/// <value></value>
public List<ILocation>/*?*/ Locations {
get { return this.locations; }
set { this.locations = value; }
}
List<ILocation>/*?*/ locations;
/// <summary>
/// The type of value the expression represents.
/// </summary>
/// <value></value>
public ITypeReference Type {
get { return this.type; }
set { this.type = value; }
}
ITypeReference type;
#region IMetadataExpression Members
IEnumerable<ILocation> IObjectWithLocations.Locations {
get {
if (this.locations == null) return Enumerable<ILocation>.Empty;
return this.locations.AsReadOnly();
}
}
#endregion
}
/// <summary>
/// An expression that represents a (name, value) pair and that is typically used in method calls, custom attributes and object initializers.
/// </summary>
public sealed class MetadataNamedArgument : MetadataExpression, IMetadataNamedArgument, ICopyFrom<IMetadataNamedArgument> {
/// <summary>
/// An expression that represents a (name, value) pair and that is typically used in method calls, custom attributes and object initializers.
/// </summary>
public MetadataNamedArgument() {
this.argumentName = Dummy.Name;
this.argumentValue = Dummy.Expression;
this.isField = false;
this.resolvedDefinition = null;
}
/// <summary>
/// Makes a shallow copy of an expression that represents a (name, value) pair and that is typically used in method calls, custom attributes and object initializers.
/// </summary>
/// <param name="namedArgument"></param>
/// <param name="internFactory"></param>
public void Copy(IMetadataNamedArgument namedArgument, IInternFactory internFactory) {
((ICopyFrom<IMetadataExpression>)this).Copy(namedArgument, internFactory);
this.argumentName = namedArgument.ArgumentName;
this.argumentValue = namedArgument.ArgumentValue;
this.isField = namedArgument.IsField;
this.resolvedDefinition = namedArgument.ResolvedDefinition;
}
/// <summary>
/// The name of the parameter or property or field that corresponds to the argument.
/// </summary>
/// <value></value>
public IName ArgumentName {
get { return this.argumentName; }
set { this.argumentName = value; }
}
IName argumentName;
/// <summary>
/// The value of the argument.
/// </summary>
/// <value></value>
public IMetadataExpression ArgumentValue {
get { return this.argumentValue; }
set { this.argumentValue = value; }
}
IMetadataExpression argumentValue;
/// <summary>
/// Calls visitor.Visit(IMetadataNamedArgument).
/// </summary>
/// <param name="visitor"></param>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// True if the named argument provides the value of a field.
/// </summary>
/// <value></value>
public bool IsField {
get { return this.isField; }
set { this.isField = value; }
}
bool isField;
/// <summary>
/// Returns either null or the parameter or property or field that corresponds to this argument.
/// </summary>
/// <value></value>
public object/*?*/ ResolvedDefinition {
get { return this.resolvedDefinition; }
set { this.resolvedDefinition = value; }
}
object/*?*/ resolvedDefinition;
}
/// <summary>
/// An expression that results in a System.Type instance.
/// </summary>
public sealed class MetadataTypeOf : MetadataExpression, IMetadataTypeOf, ICopyFrom<IMetadataTypeOf> {
/// <summary>
/// An expression that results in a System.Type instance.
/// </summary>
public MetadataTypeOf() {
this.typeToGet = Dummy.TypeReference;
}
/// <summary>
/// Makes a shallow copy of an expression that results in a System.Type instance.
/// </summary>
/// <param name="typeOf"></param>
/// <param name="internFactory"></param>
public void Copy(IMetadataTypeOf typeOf, IInternFactory internFactory) {
((ICopyFrom<IMetadataExpression>)this).Copy(typeOf, internFactory);
this.typeToGet = typeOf.TypeToGet;
}
/// <summary>
/// Calls visitor.Visit(IMetadataTypeOf).
/// </summary>
/// <param name="visitor"></param>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// The type that will be represented by the System.Type instance.
/// </summary>
/// <value></value>
public ITypeReference TypeToGet {
get { return this.typeToGet; }
set { this.typeToGet = value; }
}
ITypeReference typeToGet;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{319E151C-8F33-49E7-81C9-30F02F9BA90A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.MutableMetadataModel</RootNamespace>
<AssemblyName>Microsoft.Cci.MutableMetadataModel</AssemblyName>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<StartupObject>
</StartupObject>
<SignAssembly>true</SignAssembly>
<CodeAnalysisRules>-Microsoft.Design#CA1051;-Microsoft.Design#CA1033;-Microsoft.Design#CA1014;-Microsoft.Design#CA1060;-Microsoft.Design#CA1024;-Microsoft.Design#CA1062;-Microsoft.Maintainability#CA1500;-Microsoft.Naming#CA1718;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1719;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1814;-Microsoft.Security#CA2105;-Microsoft.Security#CA2104</CodeAnalysisRules>
<DocumentationFile>bin\$(Configuration)\Microsoft.Cci.MutableMetadataModel.XML</DocumentationFile>
<NoWarn>1591</NoWarn>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile />
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<NoWarn>
</NoWarn>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Release\Microsoft.Cci.MutableMetadataModel.XML</DocumentationFile>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyDebug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\NightlyDebug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NightlyRelease|AnyCPU' ">
<OutputPath>bin\NightlyRelease\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<AssemblyOriginatorKeyFile>..\Common\ToolsPublicKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>true</DelaySign>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'CompilerOnly|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\CompilerOnly\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Microsoft.Cci.MutableMetadataModel.XML</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules />
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\version.cs">
<Link>Build\version.cs</Link>
</Compile>
<Compile Include="Copier.cs" />
<Compile Include="Expressions.cs" />
<Compile Include="Members.cs" />
<Compile Include="Miscellaneous.cs" />
<Compile Include="Mutator.cs" />
<Compile Include="Namespaces.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Types.cs" />
<Compile Include="Units.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataHelper\MetadataHelper.csproj">
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
<Name>MetadataHelper</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,697 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Text;
namespace Microsoft.Cci.MutableCodeModel {
/// <summary>
///
/// </summary>
public sealed class NestedUnitNamespace : UnitNamespace, INestedUnitNamespace, ICopyFrom<INestedUnitNamespace> {
/// <summary>
///
/// </summary>
public NestedUnitNamespace() {
this.containingUnitNamespace = Dummy.RootUnitNamespace;
}
/// <summary>
///
/// </summary>
/// <param name="nestedUnitNamespace"></param>
/// <param name="internFactory"></param>
public void Copy(INestedUnitNamespace nestedUnitNamespace, IInternFactory internFactory) {
((ICopyFrom<IUnitNamespace>)this).Copy(nestedUnitNamespace, internFactory);
this.containingUnitNamespace = nestedUnitNamespace.ContainingUnitNamespace;
}
/// <summary>
/// The unit namespace that contains this member.
/// </summary>
/// <value></value>
public IUnitNamespace ContainingUnitNamespace {
get { return this.containingUnitNamespace; }
set { this.containingUnitNamespace = value; }
}
IUnitNamespace containingUnitNamespace;
/// <summary>
/// Calls visitor.Visit(INestedUnitNamespace).
/// </summary>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Calls visitor.Visit(INestedUnitNamespaceReference).
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
visitor.Visit((INestedUnitNamespaceReference)this);
}
internal override IUnit GetUnit() {
return this.ContainingUnitNamespace.Unit;
}
#region INamespaceMember Members
INamespaceDefinition INamespaceMember.ContainingNamespace {
get { return this.ContainingUnitNamespace; }
}
#endregion
#region IScopeMember<IScope<INamespaceMember>> Members
/// <summary>
/// The scope instance with a Members collection that includes this instance.
/// </summary>
/// <value></value>
public IScope<INamespaceMember> ContainingScope {
get { return this.ContainingUnitNamespace; }
}
#endregion
#region IContainerMember<INamespaceDefinition> Members
/// <summary>
/// The container instance with a Members collection that includes this instance.
/// </summary>
/// <value></value>
public INamespaceDefinition Container {
get { return this.ContainingUnitNamespace; }
}
IName IContainerMember<INamespaceDefinition>.Name {
get { return this.Name; }
}
#endregion
#region INestedUnitNamespaceReference Members
IUnitNamespaceReference INestedUnitNamespaceReference.ContainingUnitNamespace {
get { return this.ContainingUnitNamespace; }
}
INestedUnitNamespace INestedUnitNamespaceReference.ResolvedNestedUnitNamespace {
get { return this; }
}
#endregion
}
/// <summary>
///
/// </summary>
public sealed class NestedUnitNamespaceReference : UnitNamespaceReference, INestedUnitNamespaceReference, ICopyFrom<INestedUnitNamespaceReference> {
/// <summary>
///
/// </summary>
public NestedUnitNamespaceReference() {
Contract.Ensures(!this.IsFrozen);
this.containingUnitNamespace = Dummy.RootUnitNamespace;
this.name = Dummy.Name;
}
/// <summary>
///
/// </summary>
/// <param name="nestedUnitNamespaceReference"></param>
/// <param name="internFactory"></param>
public void Copy(INestedUnitNamespaceReference nestedUnitNamespaceReference, IInternFactory internFactory) {
((ICopyFrom<IUnitNamespaceReference>)this).Copy(nestedUnitNamespaceReference, internFactory);
this.containingUnitNamespace = nestedUnitNamespaceReference.ContainingUnitNamespace;
this.name = nestedUnitNamespaceReference.Name;
}
/// <summary>
/// A reference to the unit namespace that contains the referenced nested unit namespace.
/// </summary>
/// <value></value>
public IUnitNamespaceReference ContainingUnitNamespace {
get { return this.containingUnitNamespace; }
set { this.containingUnitNamespace = value; this.resolvedNestedUnitNamespace = null; }
}
IUnitNamespaceReference containingUnitNamespace;
/// <summary>
/// Calls visitor.Visit(INestedUnitNamespaceReference).
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Gets the unit.
/// </summary>
/// <returns></returns>
internal override IUnitReference GetUnit() {
return this.Unit;
}
/// <summary>
/// The name of the entity.
/// </summary>
/// <value></value>
public IName Name {
get { return this.name; }
set {
Contract.Requires(!this.IsFrozen);
this.name = value;
}
}
IName name;
private INestedUnitNamespace Resolve() {
this.isFrozen = true;
foreach (INamespaceMember member in this.containingUnitNamespace.ResolvedUnitNamespace.GetMembersNamed(this.Name, false)) {
INestedUnitNamespace/*?*/ ns = member as INestedUnitNamespace;
if (ns != null) return ns;
}
return Dummy.NestedUnitNamespace;
}
/// <summary>
/// The namespace definition being referred to.
/// </summary>
/// <value></value>
public INestedUnitNamespace ResolvedNestedUnitNamespace {
get {
if (this.resolvedNestedUnitNamespace == null)
this.resolvedNestedUnitNamespace = this.Resolve();
return this.resolvedNestedUnitNamespace;
}
}
INestedUnitNamespace/*?*/ resolvedNestedUnitNamespace;
/// <summary>
/// The namespace definition being referred to.
/// </summary>
/// <value></value>
public override IUnitNamespace ResolvedUnitNamespace {
get { return this.ResolvedNestedUnitNamespace; }
}
/// <summary>
/// A reference to the unit that defines the referenced namespace.
/// </summary>
/// <value></value>
public IUnitReference Unit {
get { return this.containingUnitNamespace.Unit; }
}
}
/// <summary>
///
/// </summary>
public sealed class RootUnitNamespace : UnitNamespace, IRootUnitNamespace, ICopyFrom<IRootUnitNamespace> {
/// <summary>
///
/// </summary>
public RootUnitNamespace() {
this.unit = Dummy.Unit;
}
/// <summary>
///
/// </summary>
/// <param name="rootUnitNamespace"></param>
/// <param name="internFactory"></param>
public void Copy(IRootUnitNamespace rootUnitNamespace, IInternFactory internFactory) {
((ICopyFrom<IUnitNamespace>)this).Copy(rootUnitNamespace, internFactory);
this.unit = rootUnitNamespace.Unit;
}
/// <summary>
/// Calls visitor.Visit(IRootUnitNamespace).
/// </summary>
public override void Dispatch(IMetadataVisitor visitor) {
visitor.Visit(this);
}
/// <summary>
/// Calls visitor.Visit(IRootUnitNamespaceReference).
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
visitor.Visit((IRootUnitNamespaceReference)this);
}
internal override IUnit GetUnit() {
return this.unit;
}
/// <summary>
/// The IUnit instance associated with this namespace.
/// </summary>
/// <value></value>
public new IUnit Unit {
get { return this.unit; }
set { this.unit = value; }
}
IUnit unit;
}
/// <summary>
///
/// </summary>
public sealed class RootUnitNamespaceReference : UnitNamespaceReference, IRootUnitNamespaceReference, ICopyFrom<IRootUnitNamespaceReference> {
/// <summary>
///
/// </summary>
public RootUnitNamespaceReference() {
Contract.Ensures(!this.IsFrozen);
this.unit = Dummy.Unit;
}
/// <summary>
///
/// </summary>
/// <param name="rootUnitNamespaceReference"></param>
/// <param name="internFactory"></param>
public void Copy(IRootUnitNamespaceReference rootUnitNamespaceReference, IInternFactory internFactory) {
((ICopyFrom<IUnitNamespaceReference>)this).Copy(rootUnitNamespaceReference, internFactory);
this.unit = rootUnitNamespaceReference.Unit;
}
/// <summary>
/// Calls visitor.Visit(IRootUnitNamespaceReference).
/// </summary>
public override void DispatchAsReference(IMetadataVisitor visitor) {
visitor.Visit(this);
}
internal override IUnitReference GetUnit() {
return this.Unit;
}
/// <summary>
/// The namespace definition being referred to.
/// </summary>
/// <value></value>
public override IUnitNamespace ResolvedUnitNamespace {
get {
if (this.resolvedUnitNamespace == null) {
this.isFrozen = true;
this.resolvedUnitNamespace = this.Unit.ResolvedUnit.UnitNamespaceRoot;
}
return this.resolvedUnitNamespace;
}
}
IUnitNamespace resolvedUnitNamespace;
/// <summary>
/// A reference to the unit that defines the referenced namespace.
/// </summary>
/// <value></value>
public IUnitReference Unit {
get { return this.unit; }
set {
Contract.Requires(!this.IsFrozen);
Contract.Requires(value != null);
this.unit = value;
}
}
IUnitReference unit;
}
/// <summary>
///
/// </summary>
public abstract class UnitNamespace : IUnitNamespace, ICopyFrom<IUnitNamespace> {
/// <summary>
///
/// </summary>
internal UnitNamespace() {
this.attributes = null;
this.locations = null;
this.members = null;
this.name = Dummy.Name;
}
/// <summary>
///
/// </summary>
/// <param name="unitNamespace"></param>
/// <param name="internFactory"></param>
public virtual void Copy(IUnitNamespace unitNamespace, IInternFactory internFactory) {
if (IteratorHelper.EnumerableIsNotEmpty(unitNamespace.Attributes))
this.attributes = new List<ICustomAttribute>(unitNamespace.Attributes);
else
this.attributes = null;
if (IteratorHelper.EnumerableIsNotEmpty(unitNamespace.Locations))
this.locations = new List<ILocation>(unitNamespace.Locations);
else
this.locations = null;
this.members = new List<INamespaceMember>(unitNamespace.Members);
this.name = unitNamespace.Name;
}
/// <summary>
/// A collection of metadata custom attributes that are associated with this definition. May be null.
/// </summary>
/// <value></value>
public List<ICustomAttribute>/*?*/ Attributes {
get { return this.attributes; }
set { this.attributes = value; }
}
List<ICustomAttribute>/*?*/ attributes;
//^ [Pure]
/// <summary>
/// Return true if the given member instance is a member of this scope.
/// </summary>
/// <param name="member"></param>
/// <returns></returns>
public bool Contains(INamespaceMember member) {
foreach (INamespaceMember nsmem in this.Members)
if (member == nsmem) return true;
return false;
}
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference. The dispatch method does nothing else.
/// </summary>
public abstract void Dispatch(IMetadataVisitor visitor);
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference, which is not derived from IDefinition. For example an object implemeting IArrayType will
/// call visitor.Visit(IArrayTypeReference) and not visitor.Visit(IArrayType).
/// The dispatch method does nothing else.
/// </summary>
public abstract void DispatchAsReference(IMetadataVisitor visitor);
//^ [Pure]
/// <summary>
/// Returns the list of members with the given name that also satisfy the given predicate.
/// </summary>
/// <param name="name"></param>
/// <param name="ignoreCase"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public IEnumerable<INamespaceMember> GetMatchingMembersNamed(IName name, bool ignoreCase, Function<INamespaceMember, bool> predicate) {
foreach (INamespaceMember nsmem in this.Members) {
if (nsmem.Name.UniqueKey == name.UniqueKey || ignoreCase && (name.UniqueKeyIgnoringCase == nsmem.Name.UniqueKeyIgnoringCase)) {
if (predicate(nsmem)) yield return nsmem;
}
}
}
//^ [Pure]
/// <summary>
/// Returns the list of members that satisfy the given predicate.
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
public IEnumerable<INamespaceMember> GetMatchingMembers(Function<INamespaceMember, bool> predicate) {
foreach (INamespaceMember nsmem in this.Members) {
if (predicate(nsmem)) yield return nsmem;
}
}
//^ [Pure]
/// <summary>
/// Returns the list of members with the given name.
/// </summary>
/// <param name="name"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public IEnumerable<INamespaceMember> GetMembersNamed(IName name, bool ignoreCase) {
foreach (INamespaceMember nsmem in this.Members) {
if (nsmem.Name.UniqueKey == name.UniqueKey || ignoreCase && (name.UniqueKeyIgnoringCase == nsmem.Name.UniqueKeyIgnoringCase)) {
yield return nsmem;
}
}
}
/// <summary>
/// A potentially empty collection of locations that correspond to this instance. May be null.
/// </summary>
/// <value></value>
public List<ILocation>/*?*/ Locations {
get { return this.locations; }
set { this.locations = value; }
}
List<ILocation>/*?*/ locations;
/// <summary>
/// The collection of member objects comprising the namespaces.
/// </summary>
/// <value></value>
public List<INamespaceMember> Members {
get {
Contract.Ensures(Contract.Result<List<INamespaceMember>>() != null);
if (this.members == null) this.members = new List<INamespaceMember>();
return this.members;
}
set { this.members = value; }
}
List<INamespaceMember>/*?*/ members;
/// <summary>
/// The name of the entity.
/// </summary>
/// <value></value>
public IName Name {
get { return this.name; }
set { this.name = value; }
}
IName name;
internal abstract IUnit GetUnit();
/// <summary>
/// The IUnit instance associated with this namespace.
/// </summary>
/// <value></value>
public IUnit Unit {
get { return this.GetUnit(); }
}
#region INamespaceDefinition Members
INamespaceRootOwner INamespaceDefinition.RootOwner {
get { return this.Unit; }
}
#endregion
#region INamespaceDefinition Members
IEnumerable<INamespaceMember> INamespaceDefinition.Members {
get { return this.Members.AsReadOnly(); }
}
#endregion
#region IContainer<INamespaceMember> Members
IEnumerable<INamespaceMember> IContainer<INamespaceMember>.Members {
get { return this.Members.AsReadOnly(); }
}
#endregion
#region IReference Members
IEnumerable<ICustomAttribute> IReference.Attributes {
get {
if (this.Attributes == null) return Enumerable<ICustomAttribute>.Empty;
return this.Attributes.AsReadOnly();
}
}
IEnumerable<ILocation> IObjectWithLocations.Locations {
get {
if (this.Locations == null) return Enumerable<ILocation>.Empty;
return this.Locations.AsReadOnly();
}
}
#endregion
#region IScope<INamespaceMember> Members
IEnumerable<INamespaceMember> IScope<INamespaceMember>.Members {
get { return this.Members.AsReadOnly(); }
}
#endregion
#region IUnitNamespaceReference Members
IUnitReference IUnitNamespaceReference.Unit {
get { return this.Unit; }
}
IUnitNamespace IUnitNamespaceReference.ResolvedUnitNamespace {
get { return this; }
}
#endregion
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </returns>
public override string ToString() {
return TypeHelper.GetNamespaceName(this, NameFormattingOptions.SmartNamespaceName);
}
}
/// <summary>
///
/// </summary>
public abstract class UnitNamespaceReference : IUnitNamespaceReference, ICopyFrom<IUnitNamespaceReference> {
/// <summary>
///
/// </summary>
internal UnitNamespaceReference() {
this.attributes = null;
this.locations = null;
}
/// <summary>
///
/// </summary>
/// <param name="unitNamespaceReference"></param>
/// <param name="internFactory"></param>
public virtual void Copy(IUnitNamespaceReference unitNamespaceReference, IInternFactory internFactory) {
if (IteratorHelper.EnumerableIsNotEmpty(unitNamespaceReference.Attributes))
this.attributes = new List<ICustomAttribute>(unitNamespaceReference.Attributes);
else
this.attributes = null;
if (IteratorHelper.EnumerableIsNotEmpty(unitNamespaceReference.Locations))
this.locations = new List<ILocation>(unitNamespaceReference.Locations);
else
this.locations = null;
}
/// <summary>
/// A collection of metadata custom attributes that are associated with this definition. May be null.
/// </summary>
/// <value></value>
public List<ICustomAttribute>/*?*/ Attributes {
get { return this.attributes; }
set { this.attributes = value; }
}
List<ICustomAttribute>/*?*/ attributes;
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference. The dispatch method does nothing else.
/// </summary>
/// <param name="visitor"></param>
public void Dispatch(IMetadataVisitor visitor) {
this.DispatchAsReference(visitor);
}
/// <summary>
/// Calls the visitor.Visit(T) method where T is the most derived object model node interface type implemented by the concrete type
/// of the object implementing IReference, which is not derived from IDefinition. For example an object implemeting IArrayType will
/// call visitor.Visit(IArrayTypeReference) and not visitor.Visit(IArrayType).
/// The dispatch method does nothing else.
/// </summary>
public abstract void DispatchAsReference(IMetadataVisitor visitor);
/// <summary>
/// True if the reference has been frozen and can no longer be modified. A reference becomes frozen
/// as soon as it is resolved or interned. An unfrozen reference can also explicitly be set to be frozen.
/// It is recommended that any code constructing a type reference freezes it immediately after construction is complete.
/// </summary>
public bool IsFrozen {
get { return this.isFrozen; }
set {
Contract.Requires(!this.IsFrozen && value);
this.isFrozen = value;
}
}
/// <summary>
/// True if the reference has been frozen and can no longer be modified. A reference becomes frozen
/// as soon as it is resolved or interned. An unfrozen reference can also explicitly be set to be frozen.
/// It is recommended that any code constructing a type reference freezes it immediately after construction is complete.
/// </summary>
protected bool isFrozen;
/// <summary>
/// A potentially empty collection of locations that correspond to this instance. May be null.
/// </summary>
/// <value></value>
public List<ILocation>/*?*/ Locations {
get { return this.locations; }
set { this.locations = value; }
}
List<ILocation>/*?*/ locations;
/// <summary>
/// The namespace definition being referred to.
/// </summary>
/// <value></value>
public abstract IUnitNamespace ResolvedUnitNamespace {
get;
}
internal abstract IUnitReference GetUnit();
IUnitReference IUnitNamespaceReference.Unit {
get { return this.GetUnit(); }
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString() {
return TypeHelper.GetNamespaceName(this, NameFormattingOptions.None);
}
#region IReference Members
IEnumerable<ICustomAttribute> IReference.Attributes {
get {
if (this.Attributes == null) return Enumerable<ICustomAttribute>.Empty;
return this.Attributes.AsReadOnly();
}
}
IEnumerable<ILocation> IObjectWithLocations.Locations {
get {
if (this.Locations == null) return Enumerable<ILocation>.Empty;
return this.Locations.AsReadOnly();
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All Rights Reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Microsoft.Cci.MutableMetadataModel")]
[assembly: AssemblyDescription("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b7dccfcd-96b3-499e-ba5f-1f1ba7b09978")]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,709 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Analysis;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Optimization {
/// <summary>
/// A base class for converters that populate ILGenerator instances with the IL operations found in ControlAndDataFlowGraph instances.
/// </summary>
public class ControlFlowToMethodBodyConverter<BasicBlock, Instruction>
where BasicBlock : Microsoft.Cci.Analysis.BasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
///
/// </summary>
/// <param name="cdfg"></param>
/// <param name="ilGenerator"></param>
/// <param name="localScopeProvider"></param>
/// <param name="sourceLocationProvider"></param>
public ControlFlowToMethodBodyConverter(ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg, ILGenerator ilGenerator,
ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider) {
Contract.Requires(cdfg != null);
Contract.Requires(ilGenerator != null);
this.cdfg = cdfg;
this.ilGenerator = ilGenerator;
this.localScopeProvider = localScopeProvider;
this.sourceLocationProvider = sourceLocationProvider;
}
ILGenerator ilGenerator;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
ILocalScopeProvider/*?*/ localScopeProvider;
ISourceLocationProvider/*?*/ sourceLocationProvider;
Hashtable<ILGeneratorLabel> labelFor = new Hashtable<ILGeneratorLabel>();
Dictionary<ILocalDefinition, ushort> localIndex = new Dictionary<ILocalDefinition, ushort>();
List<ILocalDefinition> localVariables = new List<ILocalDefinition>();
Stack<ILocalScope> scopeStack = new Stack<ILocalScope>();
IEnumerator<ILocalScope>/*?*/ scopeEnumerator;
bool scopeEnumeratorIsValid;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.ilGenerator != null);
Contract.Invariant(this.labelFor != null);
Contract.Invariant(this.localIndex != null);
Contract.Invariant(this.localVariables != null);
Contract.Invariant(this.scopeStack != null);
}
/// <summary>
///
/// </summary>
protected ControlAndDataFlowGraph<BasicBlock, Instruction> Cdfg {
get {
Contract.Ensures(Contract.Result<ControlAndDataFlowGraph<BasicBlock, Instruction>>() != null);
return this.cdfg;
}
}
/// <summary>
///
/// </summary>
protected ILGenerator ILGenerator {
get {
Contract.Ensures(Contract.Result<ILGenerator>() != null);
return this.ilGenerator;
}
}
/// <summary>
///
/// </summary>
public List<ILocalDefinition> Locals {
get { return this.localVariables; }
}
/// <summary>
///
/// </summary>
public ushort MaxStack {
get { return (ushort)this.maxStack; }
}
private uint maxStack;
/// <summary>
///
/// </summary>
protected uint StackHeight {
get { return this.stackHeight; }
set {
//Contract.Assume(value != uint.MaxValue);
this.stackHeight = value;
if (value >= this.maxStack) this.maxStack = value;
}
}
private uint stackHeight;
/// <summary>
///
/// </summary>
public void PopulateILGenerator() {
this.InitializeLocals();
var numberOfBlocks = (uint)this.cdfg.SuccessorEdges.Count;
this.labelFor = new Hashtable<ILGeneratorLabel>(numberOfBlocks);
var methodBody = this.cdfg.MethodBody;
foreach (var exceptionInfo in methodBody.OperationExceptionInformation) {
Contract.Assume(exceptionInfo != null);
this.ILGenerator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType,
this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset),
this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset),
exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null);
}
if (this.localScopeProvider == null) {
foreach (var localDef in this.Locals) {
Contract.Assume(localDef != null);
this.ILGenerator.AddVariableToCurrentScope(localDef);
}
foreach (var scope in this.ILGenerator.GetLocalScopes())
this.scopeStack.Push(scope);
} else {
foreach (var ns in this.localScopeProvider.GetNamespaceScopes(methodBody)) {
Contract.Assume(ns != null);
foreach (var uns in ns.UsedNamespaces) {
Contract.Assume(uns != null);
this.ILGenerator.UseNamespace(uns.NamespaceName.Value);
}
}
this.scopeEnumerator = this.localScopeProvider.GetLocalScopes(methodBody).GetEnumerator();
this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext();
}
Contract.Assume(this.cdfg != null);
//TODO: rather follow the control flow graph so that dead code is not visited.
foreach (var block in this.cdfg.AllBlocks) {
Contract.Assume(block != null);
this.GenerateILFor(block);
}
Contract.Assume(this.scopeStack != null);
while (this.scopeStack.Count > 0) {
this.ILGenerator.EndScope();
this.scopeStack.Pop();
}
this.ILGenerator.AdjustBranchSizesToBestFit(eliminateBranchesToNext: true);
this.localVariables.TrimExcess();
}
private void InitializeLocals() {
this.PopulateLocals();
for (int i = 0, n = this.localVariables.Count; i < n; i++) {
var local = this.localVariables[i];
this.localIndex.Add(local, (ushort)i);
}
}
/// <summary>
///
/// </summary>
protected virtual void PopulateLocals() {
if (this.localScopeProvider != null) {
var localAlreadySeen = new SetOfObjects();
foreach (var scope in this.localScopeProvider.GetLocalScopes(this.cdfg.MethodBody)) {
Contract.Assume(scope != null);
foreach (var local in this.localScopeProvider.GetVariablesInScope(scope)) {
if (localAlreadySeen.Add(local)) {
if (this.sourceLocationProvider != null) {
bool isCompilerGenerated;
this.sourceLocationProvider.GetSourceNameFor(local, out isCompilerGenerated);
if (isCompilerGenerated) continue;
}
this.localVariables.Add(local);
}
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="instruction"></param>
protected virtual void EmitScopeInformationFor(Instruction instruction) {
Contract.Requires(instruction != null);
IOperation operation = instruction.Operation;
if (this.scopeEnumerator == null) return;
ILocalScope/*?*/ currentScope = null;
while (this.scopeStack.Count > 0) {
currentScope = this.scopeStack.Peek();
Contract.Assume(currentScope != null);
if (operation.Offset < currentScope.Offset+currentScope.Length) break;
this.scopeStack.Pop();
this.ilGenerator.EndScope();
currentScope = null;
}
while (this.scopeEnumeratorIsValid) {
currentScope = this.scopeEnumerator.Current;
Contract.Assume(currentScope != null);
if (currentScope.Offset <= operation.Offset && operation.Offset < currentScope.Offset+currentScope.Length) {
this.scopeStack.Push(currentScope);
this.ilGenerator.BeginScope();
Contract.Assume(this.localScopeProvider != null);
foreach (var local in this.localScopeProvider.GetVariablesInScope(currentScope)) {
Contract.Assume(local != null);
if (this.localIndex.ContainsKey(local))
this.ilGenerator.AddVariableToCurrentScope(local);
}
foreach (var constant in this.localScopeProvider.GetConstantsInScope(currentScope)) {
Contract.Assume(constant != null);
this.ilGenerator.AddConstantToCurrentScope(constant);
}
this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext();
} else
break;
}
}
/// <summary>
///
/// </summary>
/// <param name="instruction"></param>
protected virtual void EmitSourceLocationFor(Instruction instruction) {
Contract.Requires(instruction != null);
IOperation operation = instruction.Operation;
this.ilGenerator.MarkSequencePoint(operation.Location);
}
/// <summary>
///
/// </summary>
/// <param name="block"></param>
protected virtual void GenerateILFor(BasicBlock block) {
Contract.Requires(block != null);
this.StackHeight = (uint)block.OperandStack.Count;
this.ilGenerator.MarkLabel(this.GetLabelFor(block.Offset));
for (int i = 0, n = block.Instructions.Count; i < n; i++) {
var instruction = block.Instructions[i];
var operation = instruction.Operation;
this.EmitOperandsFor(instruction);
this.EmitScopeInformationFor(instruction);
this.EmitSourceLocationFor(instruction);
this.EmitOperationFor(instruction);
}
}
/// <summary>
///
/// </summary>
/// <param name="instruction"></param>
protected virtual void EmitOperandsFor(Instruction instruction) {
Contract.Requires(instruction != null);
}
/// <summary>
///
/// </summary>
/// <param name="instruction"></param>
protected virtual void EmitOperationFor(Instruction instruction) {
Contract.Requires(instruction != null);
var operation = instruction.Operation;
switch (operation.OperationCode) {
case OperationCode.Arglist:
case OperationCode.Dup:
case OperationCode.Ldc_I4:
case OperationCode.Ldc_I4_0:
case OperationCode.Ldc_I4_1:
case OperationCode.Ldc_I4_2:
case OperationCode.Ldc_I4_3:
case OperationCode.Ldc_I4_4:
case OperationCode.Ldc_I4_5:
case OperationCode.Ldc_I4_6:
case OperationCode.Ldc_I4_7:
case OperationCode.Ldc_I4_8:
case OperationCode.Ldc_I4_M1:
case OperationCode.Ldc_I4_S:
case OperationCode.Ldc_I8:
case OperationCode.Ldc_R4:
case OperationCode.Ldc_R8:
case OperationCode.Ldftn:
case OperationCode.Ldnull:
case OperationCode.Ldsfld:
case OperationCode.Ldsflda:
case OperationCode.Ldstr:
case OperationCode.Ldtoken:
this.StackHeight += 1;
break;
case OperationCode.Add:
case OperationCode.Add_Ovf:
case OperationCode.Add_Ovf_Un:
case OperationCode.And:
case OperationCode.Ceq:
case OperationCode.Cgt:
case OperationCode.Cgt_Un:
case OperationCode.Clt:
case OperationCode.Clt_Un:
case OperationCode.Div:
case OperationCode.Div_Un:
case OperationCode.Initobj:
case OperationCode.Ldelem:
case OperationCode.Ldelem_I:
case OperationCode.Ldelem_I1:
case OperationCode.Ldelem_I2:
case OperationCode.Ldelem_I4:
case OperationCode.Ldelem_I8:
case OperationCode.Ldelem_R4:
case OperationCode.Ldelem_R8:
case OperationCode.Ldelem_Ref:
case OperationCode.Ldelem_U1:
case OperationCode.Ldelem_U2:
case OperationCode.Ldelem_U4:
case OperationCode.Ldelema:
case OperationCode.Mkrefany:
case OperationCode.Mul:
case OperationCode.Mul_Ovf:
case OperationCode.Mul_Ovf_Un:
case OperationCode.Or:
case OperationCode.Pop:
case OperationCode.Rem:
case OperationCode.Rem_Un:
case OperationCode.Shl:
case OperationCode.Shr:
case OperationCode.Shr_Un:
case OperationCode.Stsfld:
case OperationCode.Sub:
case OperationCode.Sub_Ovf:
case OperationCode.Sub_Ovf_Un:
case OperationCode.Switch:
case OperationCode.Throw:
case OperationCode.Xor:
this.StackHeight -= 1;
break;
case OperationCode.Array_Addr:
case OperationCode.Array_Get:
Contract.Assume(operation.Value is IArrayTypeReference);
var arrayType = (IArrayTypeReference)operation.Value;
this.StackHeight -= arrayType.Rank;
break;
case OperationCode.Array_Set:
Contract.Assume(operation.Value is IArrayTypeReference);
arrayType = (IArrayTypeReference)operation.Value;
this.StackHeight -= arrayType.Rank+1;
break;
case OperationCode.Array_Create:
Contract.Assume(operation.Value is IArrayTypeReference);
arrayType = (IArrayTypeReference)operation.Value;
this.StackHeight -= arrayType.Rank-1;
break;
case OperationCode.Array_Create_WithLowerBound:
Contract.Assume(operation.Value is IArrayTypeReference);
arrayType = (IArrayTypeReference)operation.Value;
this.StackHeight -= arrayType.Rank*2-1;
break;
case OperationCode.Br:
case OperationCode.Br_S:
case OperationCode.Leave:
case OperationCode.Leave_S:
Contract.Assume(operation.Value is uint);
this.ilGenerator.Emit(operation.OperationCode, this.GetLabelFor((uint)operation.Value));
return;
case OperationCode.Beq:
case OperationCode.Beq_S:
case OperationCode.Bge:
case OperationCode.Bge_S:
case OperationCode.Bge_Un:
case OperationCode.Bge_Un_S:
case OperationCode.Bgt:
case OperationCode.Bgt_S:
case OperationCode.Bgt_Un:
case OperationCode.Bgt_Un_S:
case OperationCode.Ble:
case OperationCode.Ble_S:
case OperationCode.Ble_Un:
case OperationCode.Ble_Un_S:
case OperationCode.Blt:
case OperationCode.Blt_S:
case OperationCode.Blt_Un:
case OperationCode.Blt_Un_S:
case OperationCode.Bne_Un:
case OperationCode.Bne_Un_S:
this.StackHeight -= 2;
Contract.Assume(operation.Value is uint);
this.ilGenerator.Emit(operation.OperationCode, this.GetLabelFor((uint)operation.Value));
return;
case OperationCode.Brfalse:
case OperationCode.Brfalse_S:
case OperationCode.Brtrue:
case OperationCode.Brtrue_S:
this.StackHeight -= 1;
Contract.Assume(operation.Value is uint);
this.ilGenerator.Emit(operation.OperationCode, this.GetLabelFor((uint)operation.Value));
return;
case OperationCode.Call:
case OperationCode.Calli:
case OperationCode.Callvirt:
case OperationCode.Newobj:
Contract.Assume(operation.Value is ISignature);
var signature = (ISignature)operation.Value;
var adjustment = IteratorHelper.EnumerableCount(signature.Parameters);
if (operation.OperationCode == OperationCode.Newobj)
adjustment--;
else {
if (operation.OperationCode == OperationCode.Calli) adjustment++;
if (!signature.IsStatic) adjustment++;
if (signature.Type.TypeCode != PrimitiveTypeCode.Void) adjustment--;
}
this.StackHeight -= adjustment;
break;
case OperationCode.Cpobj:
case OperationCode.Stfld:
case OperationCode.Stind_I:
case OperationCode.Stind_I1:
case OperationCode.Stind_I2:
case OperationCode.Stind_I4:
case OperationCode.Stind_I8:
case OperationCode.Stind_R4:
case OperationCode.Stind_R8:
case OperationCode.Stind_Ref:
case OperationCode.Stobj:
this.StackHeight -= 2;
break;
case OperationCode.Cpblk:
case OperationCode.Initblk:
case OperationCode.Stelem:
case OperationCode.Stelem_I:
case OperationCode.Stelem_I1:
case OperationCode.Stelem_I2:
case OperationCode.Stelem_I4:
case OperationCode.Stelem_I8:
case OperationCode.Stelem_R4:
case OperationCode.Stelem_R8:
case OperationCode.Stelem_Ref:
this.StackHeight -= 3;
break;
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
this.StackHeight += 1;
this.LoadParameter(operation.Value as IParameterDefinition);
return;
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
this.StackHeight += 1;
this.LoadParameterAddress(operation.Value as IParameterDefinition);
return;
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
this.StackHeight += 1;
Contract.Assume(operation.Value is ILocalDefinition);
this.LoadLocal((ILocalDefinition)operation.Value);
return;
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
this.StackHeight += 1;
Contract.Assume(operation.Value is ILocalDefinition);
LoadLocalAddress((ILocalDefinition)operation.Value);
return;
case OperationCode.Starg:
case OperationCode.Starg_S:
this.StackHeight -= 1;
this.StoreParameter(operation.Value as IParameterDefinition);
return;
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
this.StackHeight -= 1;
Contract.Assume(operation.Value is ILocalDefinition);
this.StoreLocal((ILocalDefinition)operation.Value);
return;
case OperationCode.Box:
case OperationCode.Break:
case OperationCode.Castclass:
case OperationCode.Ckfinite:
case OperationCode.Constrained_:
case OperationCode.Conv_I:
case OperationCode.Conv_I1:
case OperationCode.Conv_I2:
case OperationCode.Conv_I4:
case OperationCode.Conv_I8:
case OperationCode.Conv_Ovf_I:
case OperationCode.Conv_Ovf_I_Un:
case OperationCode.Conv_Ovf_I1:
case OperationCode.Conv_Ovf_I1_Un:
case OperationCode.Conv_Ovf_I2:
case OperationCode.Conv_Ovf_I2_Un:
case OperationCode.Conv_Ovf_I4:
case OperationCode.Conv_Ovf_I4_Un:
case OperationCode.Conv_Ovf_I8:
case OperationCode.Conv_Ovf_I8_Un:
case OperationCode.Conv_Ovf_U:
case OperationCode.Conv_Ovf_U_Un:
case OperationCode.Conv_Ovf_U1:
case OperationCode.Conv_Ovf_U1_Un:
case OperationCode.Conv_Ovf_U2:
case OperationCode.Conv_Ovf_U2_Un:
case OperationCode.Conv_Ovf_U4:
case OperationCode.Conv_Ovf_U4_Un:
case OperationCode.Conv_Ovf_U8:
case OperationCode.Conv_Ovf_U8_Un:
case OperationCode.Conv_R_Un:
case OperationCode.Conv_R4:
case OperationCode.Conv_R8:
case OperationCode.Conv_U:
case OperationCode.Conv_U1:
case OperationCode.Conv_U2:
case OperationCode.Conv_U4:
case OperationCode.Conv_U8:
case OperationCode.Endfilter:
case OperationCode.Endfinally:
case OperationCode.Isinst:
case OperationCode.Jmp:
case OperationCode.Ldfld:
case OperationCode.Ldflda:
case OperationCode.Ldind_I:
case OperationCode.Ldind_I1:
case OperationCode.Ldind_I2:
case OperationCode.Ldind_I4:
case OperationCode.Ldind_I8:
case OperationCode.Ldind_R4:
case OperationCode.Ldind_R8:
case OperationCode.Ldind_Ref:
case OperationCode.Ldind_U1:
case OperationCode.Ldind_U2:
case OperationCode.Ldind_U4:
case OperationCode.Ldlen:
case OperationCode.Ldobj:
case OperationCode.Ldvirtftn:
case OperationCode.Localloc:
case OperationCode.Neg:
case OperationCode.Newarr:
case OperationCode.No_:
case OperationCode.Nop:
case OperationCode.Not:
case OperationCode.Readonly_:
case OperationCode.Refanytype:
case OperationCode.Refanyval:
case OperationCode.Rethrow:
case OperationCode.Sizeof:
case OperationCode.Tail_:
case OperationCode.Unaligned_:
case OperationCode.Unbox:
case OperationCode.Unbox_Any:
case OperationCode.Volatile_:
break;
case OperationCode.Ret:
if (this.Cdfg.MethodBody.MethodDefinition.Type.TypeCode != PrimitiveTypeCode.Void)
this.StackHeight -= 1;
break;
default:
Contract.Assume(false);
break;
}
this.ilGenerator.Emit(operation.OperationCode, operation.Value);
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
protected ILGeneratorLabel GetLabelFor(uint offset) {
var result = this.labelFor[offset];
if (result == null)
this.labelFor[offset] = result = new ILGeneratorLabel();
return result;
}
/// <summary>
///
/// </summary>
/// <param name="local"></param>
/// <returns></returns>
protected ushort GetLocalIndex(ILocalDefinition local) {
Contract.Requires(local != null);
ushort localIndex;
if (this.localIndex.TryGetValue(local, out localIndex)) return localIndex;
localIndex = (ushort)this.localIndex.Count;
this.localIndex.Add(local, localIndex);
this.localVariables.Add(local);
return localIndex;
}
/// <summary>
/// Translates the parameter list position of the given parameter to an IL parameter index. In other words,
/// it adds 1 to the parameterDefinition.Index value if the containing method has an implicit this parameter.
/// </summary>
private static ushort GetParameterIndex(IParameterDefinition/*?*/ parameterDefinition) {
if (parameterDefinition == null) return 0;
ushort parameterIndex = parameterDefinition.Index;
if (!parameterDefinition.ContainingSignature.IsStatic) parameterIndex++;
return parameterIndex;
}
/// <summary>
///
/// </summary>
/// <param name="local"></param>
protected void LoadLocal(ILocalDefinition local) {
Contract.Requires(local != null);
ushort localIndex = this.GetLocalIndex(local);
if (localIndex == 0) this.ilGenerator.Emit(OperationCode.Ldloc_0, local);
else if (localIndex == 1) this.ilGenerator.Emit(OperationCode.Ldloc_1, local);
else if (localIndex == 2) this.ilGenerator.Emit(OperationCode.Ldloc_2, local);
else if (localIndex == 3) this.ilGenerator.Emit(OperationCode.Ldloc_3, local);
else if (localIndex <= byte.MaxValue) this.ilGenerator.Emit(OperationCode.Ldloc_S, local);
else this.ilGenerator.Emit(OperationCode.Ldloc, local);
}
/// <summary>
///
/// </summary>
/// <param name="local"></param>
protected void LoadLocalAddress(ILocalDefinition local) {
Contract.Requires(local != null);
ushort locIndex = GetLocalIndex(local);
if (locIndex <= byte.MaxValue)
this.ilGenerator.Emit(OperationCode.Ldloca_S, local);
else
this.ilGenerator.Emit(OperationCode.Ldloca, local);
}
/// <summary>
///
/// </summary>
/// <param name="parameter"></param>
protected void LoadParameter(IParameterDefinition/*?*/ parameter) {
ushort parIndex = GetParameterIndex(parameter);
if (parIndex == 0) this.ilGenerator.Emit(OperationCode.Ldarg_0, parameter);
else if (parIndex == 1) this.ilGenerator.Emit(OperationCode.Ldarg_1, parameter);
else if (parIndex == 2) this.ilGenerator.Emit(OperationCode.Ldarg_2, parameter);
else if (parIndex == 3) this.ilGenerator.Emit(OperationCode.Ldarg_3, parameter);
else if (parIndex <= byte.MaxValue) this.ilGenerator.Emit(OperationCode.Ldarg_S, parameter);
else this.ilGenerator.Emit(OperationCode.Ldarg, parameter);
}
/// <summary>
///
/// </summary>
/// <param name="parameter"></param>
protected void LoadParameterAddress(IParameterDefinition/*?*/ parameter) {
ushort parIndex = GetParameterIndex(parameter);
if (parIndex <= byte.MaxValue)
this.ilGenerator.Emit(OperationCode.Ldarga_S, parameter);
else
this.ilGenerator.Emit(OperationCode.Ldarga, parameter);
}
/// <summary>
///
/// </summary>
/// <param name="local"></param>
protected void StoreLocal(ILocalDefinition local) {
Contract.Requires(local != null);
ushort localIndex = this.GetLocalIndex(local);
if (localIndex == 0) this.ilGenerator.Emit(OperationCode.Stloc_0, local);
else if (localIndex == 1) this.ilGenerator.Emit(OperationCode.Stloc_1, local);
else if (localIndex == 2) this.ilGenerator.Emit(OperationCode.Stloc_2, local);
else if (localIndex == 3) this.ilGenerator.Emit(OperationCode.Stloc_3, local);
else if (localIndex <= byte.MaxValue) this.ilGenerator.Emit(OperationCode.Stloc_S, local);
else this.ilGenerator.Emit(OperationCode.Stloc, local);
}
/// <summary>
///
/// </summary>
/// <param name="parameter"></param>
protected void StoreParameter(IParameterDefinition/*?*/ parameter) {
ushort parIndex = GetParameterIndex(parameter);
if (parIndex <= byte.MaxValue) this.ilGenerator.Emit(OperationCode.Starg_S, parameter);
else this.ilGenerator.Emit(OperationCode.Starg, parameter);
}
}
}

Просмотреть файл

@ -0,0 +1,198 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Immutable;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Optimization {
/// <summary>
/// A rewriter for method bodies that inlines calls to methods identified by the rewriter client via a call back.
/// </summary>
public class Inliner : ILRewriter {
/// <summary>
/// A rewriter for method bodies that inlines calls to methods identified by the rewriter client via a call back.
/// </summary>
/// <param name="host">An object representing the application that is hosting this mutator. It is used to obtain access to some global
/// objects and services such as the shared name table and the table for interning references.</param>
/// <param name="inlineSelector">
/// Returns zero or more method definitions that should be inlined at a given call site. Zero methods means no inlining. For non virtual calls, one method means that the call
/// should be inlined. For virtual calls, one or methods means that the call site should do call site type tests to avoid virtual calls for the returned methods.
/// A subsequent call to ShouldInline, using one of the method definitions as the methodBeingCalled parameter can be used to determine if the call following the type test
/// should be inline or not.
/// </param>
/// <param name="sourceLocationProvider">An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.</param>
/// <param name="localScopeProvider">An object that can provide information about the local scopes of a method. May be null.</param>
public Inliner(IMetadataHost host, ShouldInline inlineSelector, ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider)
: base(host, localScopeProvider, sourceLocationProvider) {
Contract.Requires(host != null);
Contract.Requires(inlineSelector != null);
this.inlineSelector = inlineSelector;
this.method = Dummy.MethodDefinition;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(inlineSelector != null);
Contract.Invariant(this.method != null);
Contract.Invariant(this.localFor != null);
}
ShouldInline inlineSelector;
IMethodDefinition method;
Hashtable<IParameterDefinition, GeneratorLocal> localFor = new Hashtable<IParameterDefinition, GeneratorLocal>();
GeneratorLocal/*?*/ localForThis;
ILGeneratorLabel/*?*/ returnLabel;
ushort combinedMaxStack;
/// <summary>
/// </summary>
/// <param name="methodBody"></param>
/// <returns></returns>
public override IMethodBody Rewrite(IMethodBody methodBody) {
this.combinedMaxStack = methodBody.MaxStack;
this.method = methodBody.MethodDefinition;
return base.Rewrite(methodBody);
}
/// <summary>
/// Emits the given operation at the current position of the new IL stream. Also tracks any referenced local definitions,
/// so that this.localVariables will contain the exact list of locals used in the new method body.
/// </summary>
protected override void EmitOperation(IOperation operation) {
switch (operation.OperationCode) {
case OperationCode.Call:
Contract.Assume(operation.Value is IMethodReference);
var methodsToInline = this.inlineSelector(this.method, operation.Offset, (IMethodReference)operation.Value);
Contract.Assume(methodsToInline != null);
if (methodsToInline.Count == 1) {
var methodToInline = methodsToInline[0];
Contract.Assume(methodToInline != null && !methodToInline.IsAbstract && !methodToInline.IsExternal);
this.Inline(methodToInline.Body);
return;
}
break;
//TODO: virtual calls
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
if (this.returnLabel == null) break;
this.EmitMappedLocalInsteadOfArgument(OperationCode.Ldloc, operation.Value);
return;
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
if (this.returnLabel == null) break;
this.EmitMappedLocalInsteadOfArgument(OperationCode.Ldloca, operation.Value);
return;
case OperationCode.Starg:
case OperationCode.Starg_S:
if (this.returnLabel == null) break;
this.EmitMappedLocalInsteadOfArgument(OperationCode.Stloc, operation.Value);
return;
case OperationCode.Ret:
if (this.returnLabel != null) {
this.Generator.Emit(OperationCode.Br, this.returnLabel);
return;
}
break;
}
base.EmitOperation(operation);
}
private void EmitMappedLocalInsteadOfArgument(OperationCode opCodeToUse, object parameter) {
var parDef = parameter as IParameterDefinition;
var local = parDef == null ? this.localForThis : this.localFor[parDef];
Contract.Assume(local != null);
this.Generator.Emit(opCodeToUse, local);
}
[ContractVerification(false)] //Times out
private void Inline(IMethodBody methodBody) {
Contract.Requires(methodBody != null);
var savedCombinedMaxStack = this.combinedMaxStack;
this.combinedMaxStack += methodBody.MaxStack;
if (this.combinedMaxStack > this.maxStack) this.maxStack = this.combinedMaxStack;
var savedLocalForThis = this.localForThis;
var nametable = this.Host.NameTable;
var method = methodBody.MethodDefinition;
var n = method.ParameterCount;
if (!method.IsStatic) n++;
var temps = new GeneratorLocal[n];
for (ushort i = 0; i < n; i++) temps[i] = new GeneratorLocal() { MethodDefinition = method };
var j = 0;
if (!method.IsStatic) {
var temp0 = temps[0];
Contract.Assume(temp0 != null);
temp0.Name = nametable.GetNameFor("this");
temp0.Type = method.ContainingTypeDefinition;
if (method.ContainingTypeDefinition.IsValueType)
temp0.Type = ManagedPointerType.GetManagedPointerType(temp0.Type, this.Host.InternFactory);
j = 1;
this.localForThis = temp0;
}
foreach (var par in methodBody.MethodDefinition.Parameters) {
Contract.Assume(par != null);
Contract.Assume(j < n);
var tempj = temps[j++];
Contract.Assume(tempj != null);
this.localFor[par] = tempj;
tempj.Name = par.Name;
tempj.Type = par.Type;
if (par.IsByReference)
tempj.Type = ManagedPointerType.GetManagedPointerType(tempj.Type, this.Host.InternFactory);
}
this.Generator.BeginScope();
for (int i = n-1; i >= 0; i--) {
var temp = temps[i];
Contract.Assume(temp != null);
this.Generator.Emit(OperationCode.Stloc, temp);
this.TrackLocal(temp);
this.Generator.AddVariableToCurrentScope(temp);
}
var savedReturnLabel = this.returnLabel;
var returnLabel = this.returnLabel = new ILGeneratorLabel();
this.EmitMethodBody(methodBody);
this.Generator.MarkLabel(returnLabel);
this.returnLabel = savedReturnLabel;
this.localForThis = savedLocalForThis;
this.Generator.EndScope();
this.combinedMaxStack = savedCombinedMaxStack;
}
}
/// <summary>
/// Returns zero or more method definitions that should be inlined at the given call site. Zero methods means no inlining. For non virtual calls, one method means that the call
/// should be inlined. For virtual calls, one or methods means that the call site should do call site type tests to avoid virtual calls for the returned methods.
/// A subsequent call to ShouldInline, using one of the method definitions as the methodBeingCalled parameter can be used to determine if the call following the type test
/// should be inline or not.
/// </summary>
/// <param name="callingMethod">The method into which the called method should be inlined, if so desired.</param>
/// <param name="offsetOfCall">The offset in the calling method where the inlining should take place.</param>
/// <param name="methodBeingCalled">The method being called.</param>
public delegate IList<IMethodDefinition> ShouldInline(IMethodDefinition callingMethod, uint offsetOfCall, IMethodReference methodBeingCalled);
}

Просмотреть файл

@ -0,0 +1,291 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Analysis;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Optimization {
/// <summary>
/// Removes SSA locals that are used in redundant store, load sequences.
/// </summary>
[ContractVerification(false)]
public class LocalMinimizer<BasicBlock, Instruction>
where BasicBlock : SSABasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="cdfg"></param>
/// <param name="cfgQueries"></param>
/// <param name="localScopeProvider"></param>
/// <param name="sourceLocationProvider"></param>
public LocalMinimizer(IMetadataHost host,
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg, ControlGraphQueries<BasicBlock, Instruction> cfgQueries,
ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider) {
Contract.Requires(host != null);
Contract.Requires(cdfg != null);
Contract.Requires(cfgQueries != null);
this.host = host;
this.localScopeProvider = localScopeProvider;
this.sourceLocationProvider = sourceLocationProvider;
this.cdfg = cdfg;
this.cfgQueries = cfgQueries;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.host != null);
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.cfgQueries != null);
}
IMetadataHost host;
ILocalScopeProvider/*?*/ localScopeProvider;
ISourceLocationProvider/*?*/ sourceLocationProvider;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
ControlGraphQueries<BasicBlock, Instruction> cfgQueries;
/// <summary>
///
/// </summary>
/// <returns></returns>
public IMethodBody MinimizeLocals() {
//First eliminate redundant store load pairs
//now run a post order traversal of blocks, and a reverse traversal of instructions in each block. Once a write to an SSA local is processed, return its
//minimized local to a pool of available locals.
var methodBody = this.cdfg.MethodBody;
var ilGenerator = new ILGenerator(host, methodBody.MethodDefinition);
var converter = new ILConverter(this.cdfg, ilGenerator, this.localScopeProvider, this.sourceLocationProvider);
converter.PopulateILGenerator();
return new ILGeneratorMethodBody(ilGenerator, methodBody.LocalsAreZeroed, converter.MaxStack, methodBody.MethodDefinition,
converter.Locals.AsReadOnly(), Enumerable<ITypeDefinition>.Empty);
}
class ILConverter : ControlFlowToMethodBodyConverter<BasicBlock, Instruction> {
internal ILConverter(ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg, ILGenerator ilGenerator,
ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider)
: base(cdfg, ilGenerator, localScopeProvider, sourceLocationProvider) {
Contract.Requires(cdfg != null);
Contract.Requires(ilGenerator != null);
this.localFor = new Hashtable<object, GeneratorLocal>();
this.redundantLocals = new SetOfObjects();
this.storesThatShouldBecomePops = new SetOfObjects();
this.useCount = new Dictionary<ILocalDefinition, int>();
}
Hashtable<object, GeneratorLocal> localFor;
SetOfObjects redundantLocals;
SetOfObjects storesThatShouldBecomePops;
Dictionary<ILocalDefinition, int> useCount;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.localFor != null);
Contract.Invariant(this.redundantLocals != null);
Contract.Invariant(this.storesThatShouldBecomePops != null);
Contract.Invariant(this.useCount != null);
}
protected override void PopulateLocals() {
foreach (var block in this.Cdfg.AllBlocks) {
Contract.Assume(block != null);
foreach (var instruction in block.Instructions) {
Contract.Assume(instruction != null);
//if (instruction.OmitInstruction) continue;
this.CountLocalUses(instruction);
}
}
foreach (var block in this.Cdfg.AllBlocks) {
Contract.Assume(block != null);
Instruction previous = null;
foreach (var instruction in block.Instructions) {
Contract.Assume(instruction != null);
//if (instruction.OmitInstruction) continue;
this.CheckForRedundantLocals(instruction, previous);
previous = instruction;
}
}
var counts = new List<KeyValuePair<ILocalDefinition, int>>(this.useCount);
counts.Sort((KeyValuePair<ILocalDefinition, int> pair1, KeyValuePair<ILocalDefinition, int> pair2) => pair2.Value - pair1.Value);
var locals = this.Locals;
locals.Clear();
foreach (var pair in counts) locals.Add(pair.Key);
}
private void CheckForRedundantLocals(Instruction instruction, Instruction/*?*/ previous) {
Contract.Requires(instruction != null);
var local = instruction.Operation.Value as ILocalDefinition;
if (local != null) {
switch (instruction.Operation.OperationCode) {
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
if (this.useCount[local] == 1) {
this.storesThatShouldBecomePops.Add(instruction);
this.useCount.Remove(local);
}
break;
}
local = null;
}
if (previous == null) return;
while (local == null && instruction.Operand1 is Instruction) {
instruction = (Instruction)instruction.Operand1;
local = instruction.Operation.Value as ILocalDefinition;
}
if (local == null || local != previous.Operation.Value) return;
switch (previous.Operation.OperationCode) {
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
break;
default:
return;
}
switch (instruction.Operation.OperationCode) {
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
break;
default:
return;
}
if (this.useCount[local] == 2) {
this.redundantLocals.Add(previous.Operation.Value);
this.useCount.Remove(local);
}
}
private void CountLocalUses(Instruction instruction) {
Contract.Requires(instruction != null);
var local = instruction.Operation.Value as ILocalDefinition;
if (local != null) {
int count = 0;
useCount.TryGetValue(local, out count);
useCount[local] = ++count;
}
var operand1 = instruction.Operand1 as Instruction;
if (operand1 != null) {
this.CountLocalUses(operand1);
var operand2 = instruction.Operand2 as Instruction;
if (operand2 != null) {
this.CountLocalUses(operand2);
} else {
var operands2toN = instruction.Operand2 as Instruction[];
if (operands2toN != null) {
for (int i = 0, n = operands2toN.Length; i < n; i++) {
Contract.Assume(operands2toN[i] != null);
this.CountLocalUses(operands2toN[i]);
}
}
}
}
}
[ContractVerification(false)]
protected override void EmitOperationFor(Instruction instruction) {
var operation = instruction.Operation;
switch (operation.OperationCode) {
case OperationCode.Ldarg:
case OperationCode.Ldarg_0:
case OperationCode.Ldarg_1:
case OperationCode.Ldarg_2:
case OperationCode.Ldarg_3:
case OperationCode.Ldarg_S:
var local = this.localFor[operation.Value];
if (local == null) break;
this.LoadLocal(local);
return;
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
var ssaParameter = operation.Value as SSAParameterDefinition;
if (ssaParameter == null) break;
local = this.localFor[ssaParameter.OriginalParameter];
if (local == null)
this.LoadParameter(ssaParameter.OriginalParameter);
else
this.LoadLocal(local);
this.localFor[ssaParameter] = local = new GeneratorLocal() { Name = ssaParameter.Name, Type = ssaParameter.Type };
this.StoreLocal(local);
this.LoadLocalAddress(local);
return;
case OperationCode.Starg:
case OperationCode.Starg_S:
ssaParameter = operation.Value as SSAParameterDefinition;
if (ssaParameter == null) break;
this.localFor[ssaParameter] = local = new GeneratorLocal() { Name = ssaParameter.Name, Type = ssaParameter.Type };
this.StoreLocal(local);
return;
case OperationCode.Ldloc:
case OperationCode.Ldloc_0:
case OperationCode.Ldloc_1:
case OperationCode.Ldloc_2:
case OperationCode.Ldloc_3:
case OperationCode.Ldloc_S:
if (this.redundantLocals.Contains(operation.Value)) return;
local = this.localFor[operation.Value];
if (local == null) break;
this.LoadLocal(local);
return;
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
if (this.storesThatShouldBecomePops.Contains(instruction)) {
this.ILGenerator.Emit(OperationCode.Pop);
return;
}
if (this.redundantLocals.Contains(operation.Value)) return;
var ssaLocal = operation.Value as SSALocalDefinition;
if (ssaLocal == null) break;
this.localFor[ssaLocal] = local = new GeneratorLocal() { Name = ssaLocal.Name, Type = ssaLocal.Type };
this.StoreLocal(local);
return;
}
base.EmitOperationFor(instruction);
}
}
}
}

Просмотреть файл

@ -0,0 +1,608 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.UtilityDataStructures;
using Microsoft.Cci.MutableCodeModel;
namespace Microsoft.Cci.Optimization {
/// <summary>
///
/// </summary>
public class AssemblyMerger : ModuleMerger {
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="result"></param>
/// <param name="modulesToMerge"></param>
public AssemblyMerger(IMetadataHost host, Assembly result, params Module[] modulesToMerge)
: base(host, result, modulesToMerge) {
Contract.Requires(host != null);
Contract.Requires(result != null);
Contract.Requires(modulesToMerge != null);
this.result = result;
}
Assembly result;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.result != null);
}
/// <summary>
///
/// </summary>
public override void Merge() {
base.Merge();
this.result.AssemblyAttributes = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).AssemblyAttributes);
this.result.ExportedTypes = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).ExportedTypes);
this.result.Files = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).Files);
this.result.MemberModules = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).MemberModules);
this.result.Resources = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).Resources);
this.result.SecurityAttributes = this.Concatenate((a) => ((a as Assembly)??Dummy.Assembly).SecurityAttributes);
this.MergeAttributes(this.result.Attributes);
this.ReparentFilesAndDealWithDuplicates();
this.ReparentMemberModulesAndDealWithDuplicates();
this.ReparentResourcesAndDealWithDuplicates();
this.MergeSecurityAttributes();
}
private void ReparentFilesAndDealWithDuplicates() {
var files = this.result.Files;
if (files == null) return;
var fileRefFor = new Hashtable<FileReference>();
for (int i = 0; i < files.Count; i++) {
var fileRef = files[i] as FileReference;
if (fileRef == null) { files.RemoveAt(i); continue; } //TODO: error
var key = (uint)fileRef.FileName.UniqueKey;
if (fileRefFor[key] != null) { files.RemoveAt(i); continue; }; //TODO: check that hash values match
fileRef.ContainingAssembly = this.result;
fileRefFor[key] = fileRef;
}
files.TrimExcess();
}
private void ReparentMemberModulesAndDealWithDuplicates() {
var memberModules = this.result.MemberModules;
if (memberModules == null) return;
var memberModuleFor = new Dictionary<ModuleIdentity, Module>();
for (int i = 0; i < memberModules.Count; i++) {
var memberModule = memberModules[i] as Module;
if (memberModule == null) { memberModules.RemoveAt(i); continue; } //TODO: error
if (memberModuleFor.ContainsKey(memberModule.ModuleIdentity)) { memberModules.RemoveAt(i); continue; }
memberModule.ContainingAssembly = this.result;
memberModuleFor[memberModule.ModuleIdentity] = memberModule;
}
memberModules.TrimExcess();
}
private void ReparentResourcesAndDealWithDuplicates() {
var resources = this.result.Resources;
if (resources == null) return;
var resourceFor = new Hashtable<Resource>();
for (int i = 0; i < resources.Count; i++) {
var resource = resources[i] as Resource;
if (resource == null) { resources.RemoveAt(i); continue; } //TODO: error
var key = (uint)resource.Name.UniqueKey;
if (resourceFor[key] != null) { resources.RemoveAt(i); continue; }
resource.DefiningAssembly = this.result;
resourceFor[key] = resource;
}
resources.TrimExcess();
}
private void MergeSecurityAttributes() {
var secAttrs = this.result.SecurityAttributes;
if (secAttrs == null) return;
for (int i = 0; i < secAttrs.Count; i++) {
var attr = secAttrs[i];
Contract.Assume(attr != null);
var mutableSecAttr = attr as SecurityAttribute;
for (int j = i+1; j < secAttrs.Count; j++) {
var laterAttr = secAttrs[j];
Contract.Assume(laterAttr != null);
if (attr.Action == laterAttr.Action) {
if (mutableSecAttr == null) {
mutableSecAttr = new SecurityAttribute() { Action = attr.Action, Attributes = new List<ICustomAttribute>(attr.Attributes) };
secAttrs[i] = mutableSecAttr;
}
Contract.Assume(mutableSecAttr.Attributes != null);
if (laterAttr.Attributes != null)
mutableSecAttr.Attributes.AddRange(laterAttr.Attributes);
secAttrs.RemoveAt(j);
}
}
if (mutableSecAttr != null)
this.MergeAttributes(mutableSecAttr.Attributes);
}
}
}
/// <summary>
///
/// </summary>
public class ModuleMerger {
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="result"></param>
/// <param name="modulesToMerge"></param>
public ModuleMerger(IMetadataHost host, Module result, params Module[] modulesToMerge) {
Contract.Requires(host != null);
Contract.Requires(result != null);
Contract.Requires(modulesToMerge != null);
this.result = result;
this.resultModuleType = new NamespaceTypeDefinition();
this.rootNamespace = new RootUnitNamespace() { Unit = result };
this.modulesToMerge = modulesToMerge;
this.assemblyReferenceFor = new Dictionary<AssemblyIdentity, IAssemblyReference>();
this.host = host;
}
Module result;
NamespaceTypeDefinition resultModuleType; //result.AllTypes[0]
RootUnitNamespace rootNamespace;
Module[] modulesToMerge;
Dictionary<AssemblyIdentity, IAssemblyReference> assemblyReferenceFor;
IMetadataHost host;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.result != null);
Contract.Invariant(this.resultModuleType != null);
Contract.Invariant(this.rootNamespace != null);
Contract.Invariant(this.modulesToMerge != null);
Contract.Invariant(this.host != null);
Contract.Invariant(this.assemblyReferenceFor != null);
}
/// <summary>
///
/// </summary>
public virtual void Merge() {
this.MergeModuleTypes();
this.ConcatenateOtherTypes();
this.result.ModuleAttributes = this.Concatenate((a) => a.ModuleAttributes);
this.result.ModuleReferences = this.Concatenate((a) => a.ModuleReferences);
this.result.UninterpretedSections = this.Concatenate((a) => a.UninterpretedSections);
this.MergeUnitNamespaceRoots();
this.MergeAssemblyReferences();
this.ReparentMembersAndDealWithDuplicates(this.rootNamespace);
this.MergeAttributes(this.result.ModuleAttributes);
this.ReparentModuleReferencesAndDealWithDuplicates();
this.DealWithDuplicateUninterpretedSections();
}
private void MergeModuleTypes() {
this.resultModuleType.Name = host.NameTable.GetNameFor("<Module>");
this.resultModuleType.ContainingUnitNamespace = this.result.UnitNamespaceRoot;
this.resultModuleType.InternFactory = this.host.InternFactory;
this.result.AllTypes.Add(this.resultModuleType);
this.resultModuleType.Fields = new List<IFieldDefinition>();
this.resultModuleType.Methods = new List<IMethodDefinition>();
for (int i = 0, n = this.modulesToMerge.Length; i < n; i++) {
var assemToMerge = this.modulesToMerge[i];
Contract.Assume(assemToMerge != null);
if (assemToMerge.AllTypes.Count == 0) continue;
var moduleTypeToMerge = assemToMerge.AllTypes[0];
Contract.Assume(moduleTypeToMerge != null);
Contract.Assume(this.resultModuleType.Fields != null);
if (moduleTypeToMerge.Fields != null)
this.resultModuleType.Fields.AddRange(moduleTypeToMerge.Fields);
Contract.Assume(this.resultModuleType.Methods != null);
if (moduleTypeToMerge.Methods != null)
this.resultModuleType.Methods.AddRange(moduleTypeToMerge.Methods);
}
Contract.Assume(this.resultModuleType.Fields != null);
if (this.resultModuleType.Fields.Count == 0)
this.resultModuleType.Fields = null;
else
this.resultModuleType.Fields.TrimExcess();
Contract.Assume(this.resultModuleType.Methods != null);
if (this.resultModuleType.Methods.Count == 0)
this.resultModuleType.Methods = null;
else
this.resultModuleType.Methods.TrimExcess();
}
private void ConcatenateOtherTypes() {
var resultTypes = this.result.AllTypes;
for (int i = 0, n = this.modulesToMerge.Length; i < n; i++) {
var assemToMerge = this.modulesToMerge[i];
Contract.Assume(assemToMerge != null);
if (assemToMerge.AllTypes.Count < 1) continue;
for (int j = 0, m = assemToMerge.AllTypes.Count; j < m; j++) {
var typeToMerge = assemToMerge.AllTypes[j];
Contract.Assume(typeToMerge != null);
resultTypes.Add(typeToMerge);
}
}
resultTypes.TrimExcess();
}
internal delegate IEnumerable<ElementType> GetCollection<ElementType>(IModule module);
internal List<ElementType>/*?*/ Concatenate<ElementType>(GetCollection<ElementType> getCollectionFrom) {
Contract.Requires(getCollectionFrom != null);
var result = new List<ElementType>();
for (int i = 0, n = this.modulesToMerge.Length; i < n; i++) {
var moduleToMerge = this.modulesToMerge[i];
Contract.Assume(moduleToMerge != null);
var collection = getCollectionFrom(moduleToMerge);
Contract.Assume(collection != null);
result.AddRange(collection);
}
if (result.Count == 0) return null;
result.TrimExcess();
return result;
}
private void MergeUnitNamespaceRoots() {
this.result.UnitNamespaceRoot = this.rootNamespace;
for (int i = 0; i < this.modulesToMerge.Length; i++) {
var assemblyToMerge = this.modulesToMerge[i];
Contract.Assume(assemblyToMerge != null);
this.MergeNamespaces(this.rootNamespace, assemblyToMerge.UnitNamespaceRoot);
}
}
private void MergeNamespaces(UnitNamespace result, IUnitNamespace namespaceToMerge) {
Contract.Requires(result != null);
Contract.Requires(namespaceToMerge != null);
foreach (var member in namespaceToMerge.Members) {
var nestedNs = member as NestedUnitNamespace;
if (nestedNs != null) {
UnitNamespace nestedResult = null;
foreach (var rmember in result.Members) {
Contract.Assume(rmember != null);
if (rmember.Name != nestedNs.Name) continue;
nestedResult = rmember as UnitNamespace;
if (nestedResult != null) break;
}
if (nestedResult == null)
nestedResult = new NestedUnitNamespace() { ContainingUnitNamespace = result, Name = nestedNs.Name };
this.MergeNamespaces(nestedResult, nestedNs);
continue;
}
result.Members.Add(member);
}
}
/// <summary>
/// Fixes up all references in this.result that would resolve to definitions in one of the assemblies to merge
/// so that instead they will resolve to the (reparented) definition in the merged assembly. Consolidates
/// the other assembly references so that there is a single instance for each referenced assembly.
/// Also replaces all references to definitions in the merged assembly, with the actual definitions.
/// </summary>
private void MergeAssemblyReferences() {
for (int i = 0, n = this.modulesToMerge.Length; i < n; i++) {
var moduleToMerge = this.modulesToMerge[i];
Contract.Assume(moduleToMerge != null);
}
var referenceMerger = new AssemblyReferenceMerger(this.host, this.result, this.assemblyReferenceFor);
referenceMerger.Rewrite(this.result);
var nonSelfReferences = new List<IAssemblyReference>(this.assemblyReferenceFor.Count-1);
this.result.AssemblyReferences = nonSelfReferences;
foreach (var assemRef in this.assemblyReferenceFor.Values) {
if (assemRef == this.result) continue;
nonSelfReferences.Add(assemRef);
}
}
private void ReparentMembersAndDealWithDuplicates(UnitNamespace unitNamespace) {
Contract.Requires(unitNamespace != null);
var members = unitNamespace.Members;
for (int i = 0, n = members.Count; i < n; i++) {
var member = members[i];
var nsType = member as NamespaceTypeDefinition;
if (nsType != null) {
nsType.ContainingUnitNamespace = unitNamespace;
for (int j = i+1; j < n; j++) {
var laterNsType = members[j] as NamespaceTypeDefinition;
if (laterNsType == null || laterNsType.Name != nsType.Name) continue;
if (nsType.MangleName != laterNsType.MangleName) continue;
if (nsType.MangleName && nsType.GenericParameterCount != laterNsType.GenericParameterCount) continue;
this.ReportNameCollisionAndRename(nsType, laterNsType, j);
}
continue;
}
var globalField = member as GlobalFieldDefinition;
if (globalField != null) {
globalField.ContainingTypeDefinition = this.resultModuleType;
for (int j = i+1; j < n; j++) {
var laterField = members[j] as GlobalFieldDefinition;
if (laterField == null || laterField.Name != globalField.Name) continue;
if (!TypeHelper.TypesAreEquivalent(globalField.Type, laterField.Type)) continue;
//TODO: check custom modifiers
this.ReportNameCollisionAndRename(globalField, laterField, j);
}
continue;
}
var globalMethod = member as GlobalMethodDefinition;
if (globalMethod != null) {
globalMethod.ContainingTypeDefinition = this.resultModuleType;
for (int j = i+1; j < n; j++) {
var laterMethod = members[j] as GlobalMethodDefinition;
if (laterMethod == null || laterMethod.Name != globalMethod.Name) continue;
if (!MemberHelper.SignaturesAreEqual(globalMethod, laterMethod, resolveTypes: false)) continue;
this.ReportNameCollisionAndRename(globalMethod, laterMethod, j);
}
continue;
}
var alias = member as NamespaceAliasForType;
if (alias != null) {
alias.ContainingNamespace = unitNamespace;
for (int j = i+1; j < n; j++) {
var laterAlias = members[j] as NamespaceAliasForType;
if (laterAlias == null || laterAlias.Name != alias.Name || laterAlias.GenericParameterCount != alias.GenericParameterCount) continue; //Note: these names are not unmangled
this.ReportNameCollision(alias, laterAlias, j);
}
continue;
}
}
}
private void ReportNameCollision(NamespaceAliasForType alias, NamespaceAliasForType laterAlias, int position) {
Contract.Requires(alias != null);
Contract.Requires(laterAlias != null);
this.host.ReportError(new ErrorMessage() {
Code = 1, ErrorReporter = this, Error = MergeError.DuplicateAlias,
MessageParameter = TypeHelper.GetTypeName(alias.AliasedType)
});
}
private void ReportNameCollisionAndRename(GlobalFieldDefinition globalField, GlobalFieldDefinition laterField, int position) {
Contract.Requires(globalField != null);
Contract.Requires(laterField != null);
laterField.Name = this.host.NameTable.GetNameFor(laterField.Name.Value+"``"+position);
this.host.ReportError(new ErrorMessage() {
Code = 2, ErrorReporter = this, Error = MergeError.DuplicateGlobalField,
MessageParameter = MemberHelper.GetMemberSignature(globalField, NameFormattingOptions.Signature),
});
}
private void ReportNameCollisionAndRename(GlobalMethodDefinition globalMethod, GlobalMethodDefinition laterMethod, int position) {
Contract.Requires(globalMethod != null);
Contract.Requires(laterMethod != null);
laterMethod.Name = this.host.NameTable.GetNameFor(laterMethod.Name.Value+"``"+position);
this.host.ReportError(new ErrorMessage() {
Code = 3, ErrorReporter = this, Error = MergeError.DuplicateGlobalMethod,
MessageParameter = MemberHelper.GetMethodSignature(globalMethod, NameFormattingOptions.ReturnType|NameFormattingOptions.Signature),
});
}
private void ReportNameCollisionAndRename(NamespaceTypeDefinition nsType, NamespaceTypeDefinition laterNsType, int position) {
Contract.Requires(nsType != null);
Contract.Requires(laterNsType != null);
laterNsType.Name = this.host.NameTable.GetNameFor(laterNsType.Name.Value+"``"+position);
this.host.ReportError(new ErrorMessage() {
Code = 4, ErrorReporter = this, Error = MergeError.DuplicateGlobalField,
MessageParameter = TypeHelper.GetTypeName(nsType),
});
}
internal void MergeAttributes(List<ICustomAttribute> attrs) {
if (attrs == null) return;
for (int i = 0; i < attrs.Count; i++) {
var attr = attrs[i];
Contract.Assume(attr != null);
for (int j = i+1; j < attrs.Count; j++) {
var laterAttr = attrs[j];
Contract.Assume(laterAttr != null);
if (TypeHelper.TypesAreEquivalent(attr.Type, laterAttr.Type))
attrs.RemoveAt(j);
}
}
}
[ContractVerification(false)] //moduleRef.ModuleIdentity = .... reports requires unproven: !this.IsFrozen
private void ReparentModuleReferencesAndDealWithDuplicates() {
var moduleReferences = this.result.ModuleReferences;
if (moduleReferences == null) return;
var moduleRefFor = new Hashtable<ModuleReference>();
for (int i = 0; i < moduleReferences.Count; i++) {
var moduleRef = moduleReferences[i] as ModuleReference;
if (moduleRef == null || moduleRef.IsFrozen) { moduleReferences.RemoveAt(i); continue; }; //TODO: error
var modId = moduleRef.ModuleIdentity;
var key = (uint)modId.Name.UniqueKey;
if (moduleRefFor[key] != null) { moduleReferences.RemoveAt(i); continue; };
moduleRef.ContainingAssembly = this.result as IAssembly;
moduleRef.ModuleIdentity = new ModuleIdentity(modId.Name, modId.Location, this.result.ModuleIdentity as AssemblyIdentity);
moduleRefFor[key] = moduleRef;
}
moduleReferences.TrimExcess();
}
private void DealWithDuplicateUninterpretedSections() {
var uninterpretedSections = this.result.UninterpretedSections;
if (uninterpretedSections == null) return;
var uninterpretedSectionFor = new Hashtable<PESection>();
for (int i = 0; i < uninterpretedSections.Count; i++) {
var uninterpretedSection = uninterpretedSections[i] as PESection;
if (uninterpretedSection == null) { uninterpretedSections.RemoveAt(i); continue; } //TODO: error
var key = (uint)uninterpretedSection.SectionName.UniqueKey;
if (uninterpretedSectionFor[key] != null) { uninterpretedSections.RemoveAt(i); continue; } //TODO: error
uninterpretedSectionFor[key] = uninterpretedSection;
}
}
}
internal class AssemblyReferenceMerger : MetadataRewriter {
internal AssemblyReferenceMerger(IMetadataHost host, Module mergedModule, Dictionary<AssemblyIdentity, IAssemblyReference> assemblyReferenceFor)
: base(host) {
Contract.Requires(host != null);
Contract.Requires(mergedModule != null);
Contract.Requires(assemblyReferenceFor != null);
this.mergedModule = mergedModule;
this.assemblyReferenceFor = assemblyReferenceFor;
}
Module mergedModule;
Dictionary<AssemblyIdentity, IAssemblyReference> assemblyReferenceFor;
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.mergedModule != null);
Contract.Invariant(this.assemblyReferenceFor != null);
}
public override IAssemblyReference Rewrite(IAssemblyReference assemblyReference) {
IAssemblyReference result;
if (!this.assemblyReferenceFor.TryGetValue(assemblyReference.AssemblyIdentity, out result))
this.assemblyReferenceFor[assemblyReference.AssemblyIdentity] = result = assemblyReference;
Contract.Assume(result != null);
return result;
}
public override INamespaceTypeReference Rewrite(INamespaceTypeReference namespaceTypeReference) {
namespaceTypeReference = base.Rewrite(namespaceTypeReference);
var unit = TypeHelper.GetDefiningUnitReference(namespaceTypeReference);
if (unit == this.mergedModule) {
var resolvedType = namespaceTypeReference.ResolvedType;
Contract.Assume(!(resolvedType is Dummy));
return resolvedType;
}
return namespaceTypeReference;
}
public override INestedTypeReference Rewrite(INestedTypeReference nestedTypeReference) {
nestedTypeReference = base.Rewrite(nestedTypeReference);
var unit = TypeHelper.GetDefiningUnitReference(nestedTypeReference);
if (unit == this.mergedModule) {
var resolvedType = nestedTypeReference.ResolvedType;
Contract.Assume(!(resolvedType is Dummy));
return resolvedType;
}
return nestedTypeReference;
}
}
/// <summary>
/// Information about an error that occurred during an assembly merge operation.
/// </summary>
public sealed class ErrorMessage : IErrorMessage {
/// <summary>
/// The object reporting the error. This can be used to filter out errors coming from non interesting sources.
/// </summary>
public object ErrorReporter { get; internal set; }
/// <summary>
/// A short identifier for the reporter of the error, suitable for use in human interfaces. For example "CS" in the case of a C# language error.
/// </summary>
public string ErrorReporterIdentifier {
get { return "Merger"; }
}
/// <summary>
/// The error this message pertains to.
/// </summary>
public MergeError Error { get; internal set; }
/// <summary>
/// A code that corresponds to this error. This code is the same for all cultures.
/// </summary>
public long Code { get; internal set; }
/// <summary>
/// True if the error message should be treated as an informational warning rather than as an indication that the associated
/// merge has failed and no useful executable output has been generated.
/// </summary>
public bool IsWarning {
get { return true; }
}
/// <summary>
/// A description of the error suitable for user interaction. Localized to the current culture.
/// </summary>
public string Message {
get {
System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager("Microsoft.Cci.Optimization.AssemblyMerger.ErrorMessages", typeof(ErrorMessage).Assembly);
string messageKey = this.Error.ToString();
string/*?*/ localizedString = null;
try {
localizedString = resourceManager.GetString(messageKey);
} catch (System.Resources.MissingManifestResourceException) {
}
try {
if (localizedString == null) {
localizedString = resourceManager.GetString(messageKey, System.Globalization.CultureInfo.InvariantCulture);
}
} catch (System.Resources.MissingManifestResourceException) {
}
if (localizedString == null)
localizedString = messageKey;
else if (this.MessageParameter != null)
localizedString = string.Format(localizedString, this.MessageParameter);
return localizedString;
}
}
/// <summary>
/// If not null, this strings parameterizes the error message.
/// </summary>
public string/*?*/ MessageParameter { get; internal set; }
/// <summary>
/// The location of the error.
/// </summary>
public ILocation Location { get { return Dummy.Location; } }
/// <summary>
/// Zero ore more locations that are related to this error.
/// </summary>
public IEnumerable<ILocation> RelatedLocations { get { return Enumerable<ILocation>.Empty; } }
}
/// <summary>
/// An enumeration of errors that can occur during assembly merging.
/// </summary>
public enum MergeError {
/// <summary>
/// Type {0} is exported from more than one of the merged assemblies. A rename was done to prevent the merged assembly from being invalid.
/// </summary>
DuplicateAlias,
/// <summary>
/// Global method {0} is exported from more than one of the merged assemblies. A rename was done to prevent the merged assembly from being invalid.
/// </summary>
DuplicateGlobalMethod,
/// <summary>
/// Global field {0} is exported from more than one of the merged assemblies. A rename was done to prevent the merged assembly from being invalid.
/// </summary>
DuplicateGlobalField,
/// <summary>
/// Namespace type {0} is exported from more than one of the merged assemblies. A rename was done to prevent the merged assembly from being invalid.
/// </summary>
DuplicateType,
}
}

Просмотреть файл

@ -0,0 +1,286 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Analysis;
using Microsoft.Cci.MutableCodeModel;
using Microsoft.Cci.UtilityDataStructures;
namespace Microsoft.Cci.Optimization {
/// <summary>
/// Changes a control flow graph from SSA form to a version where the SSA variables are unified into the smallest number of locals.
/// This is somewhat like register allocation where the number of registers can grow as large as needed, but registers are typed.
/// </summary>
public class MultipleAssigner<BasicBlock, Instruction>
where BasicBlock : PeBasicBlock<Instruction>, new()
where Instruction : Microsoft.Cci.Analysis.Instruction, new() {
/// <summary>
/// Changes a control flow graph from SSA form to a version where the SSA variables are unified into the smallest number of locals.
/// This is somewhat like register allocation where the number of registers can grow as large as needed, but registers are typed.
/// </summary>
/// <param name="host"></param>
/// <param name="cdfg"></param>
/// <param name="cfgQueries"></param>
public MultipleAssigner(IMetadataHost host, ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg, ControlGraphQueries<BasicBlock, Instruction> cfgQueries) {
Contract.Requires(host != null);
Contract.Requires(cdfg != null);
Contract.Requires(cfgQueries != null);
this.host = host;
this.cdfg = cdfg;
this.cfgQueries = cfgQueries;
this.unifiedLocalFor = new Hashtable<object, GeneratorLocal>();
this.availableLocalsFor = new MultiHashtable<GeneratorLocal>();
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.host != null);
Contract.Invariant(this.cdfg != null);
Contract.Invariant(this.cfgQueries != null);
Contract.Invariant(this.unifiedLocalFor != null);
Contract.Invariant(this.availableLocalsFor != null);
}
IMetadataHost host;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
ControlGraphQueries<BasicBlock, Instruction> cfgQueries;
Hashtable<object, GeneratorLocal> unifiedLocalFor;
MultiHashtable<GeneratorLocal> availableLocalsFor;
/// <summary>
/// Changes a control flow graph from SSA form to a version where the SSA variables are unified into the smallest number of locals.
/// This is somewhat like register allocation where the number of registers can grow as large as needed, but registers are typed.
/// </summary>
public void ReuseDeadLocals() {
this.AddTransferInstructions();
this.ReplaceSSALocalsInBlocks();
this.ReplaceSSALocalsInTransferInstructions();
}
private void AddTransferInstructions() {
var definedSSAVariables = new SetOfObjects();
var blocksAlreadyVisited = new SetOfObjects();
foreach (var block in this.cdfg.RootBlocks) {
Contract.Assume(block != null);
definedSSAVariables.Clear();
blocksAlreadyVisited.Clear();
this.AddTransferInstructions(block, definedSSAVariables, blocksAlreadyVisited);
}
}
private void AddTransferInstructions(BasicBlock block, SetOfObjects definedSSAVariables, SetOfObjects blocksAlreadyVisited) {
Contract.Requires(block != null);
Contract.Requires(definedSSAVariables != null);
Contract.Requires(blocksAlreadyVisited != null);
if (block.Joins != null) {
foreach (var join in block.Joins) {
Contract.Assume(join.NewLocal != null);
definedSSAVariables.Add(join.NewLocal);
}
}
foreach (var instruction in block.Instructions) {
var ssaLocal = instruction.Operation.Value as SSALocalDefinition;
if (ssaLocal != null)
definedSSAVariables.Add(ssaLocal);
else {
var ssaParam = instruction.Operation.Value as SSAParameterDefinition;
if (ssaParam != null)
definedSSAVariables.Add(ssaParam);
}
}
var successors = this.cdfg.SuccessorsFor(block);
var n = successors.Count;
if (n == 0) return;
for (var i = 0; i < n-1; i++) {
var succ = successors[i];
this.AddTransferInstructions(block, succ, i, definedSSAVariables);
if (!blocksAlreadyVisited.Add(succ)) continue;
var copyOfssaVariableFor = new SetOfObjects(definedSSAVariables);
this.AddTransferInstructions(succ, copyOfssaVariableFor, blocksAlreadyVisited);
}
var lastSucc = successors[n-1];
if (blocksAlreadyVisited.Add(lastSucc)) {
this.AddTransferInstructions(block, lastSucc, n-1, definedSSAVariables);
this.AddTransferInstructions(lastSucc, definedSSAVariables, blocksAlreadyVisited);
}
}
private void AddTransferInstructions(BasicBlock block, BasicBlock succ, int successorIndex, SetOfObjects definedSSAVariables) {
Contract.Requires(block != null);
Contract.Requires(succ != null);
Contract.Requires(definedSSAVariables != null);
if (succ.Joins == null) return;
foreach (var join in succ.Joins) {
Contract.Assume(join.Join1 != null);
if (definedSSAVariables.Contains(join.Join1)) {
this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, join.Join1, join.Type);
continue;
}
if (join.Join2 == null) continue;
if (definedSSAVariables.Contains(join.Join2)) {
this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, join.Join2, join.Type);
continue;
}
if (join.OtherJoins == null) continue;
foreach (var joini in join.OtherJoins) {
if (!definedSSAVariables.Contains(joini)) continue;
this.AddTransferInstruction(block, succ, successorIndex, join.NewLocal, joini, join.Type);
}
}
}
private void AddTransferInstruction(BasicBlock block, BasicBlock succ, int successorIndex, object targetLocal, object sourceLocal, ITypeReference type) {
Contract.Requires(block != null);
Contract.Requires(succ != null);
Contract.Requires(type != null);
if (block.transferBlocks == null)
block.transferBlocks = new PeBasicBlock<Instruction>[this.cdfg.SuccessorsFor(block).Count];
Contract.Assume(0 <= successorIndex && successorIndex < block.transferBlocks.Length);
var transferBlock = block.transferBlocks[successorIndex];
if (transferBlock == null)
transferBlock = block.transferBlocks[successorIndex] = new PeBasicBlock<Instruction>();
var transferInstructions = transferBlock.transferInstructions;
if (transferInstructions == null)
transferInstructions = transferBlock.transferInstructions = new List<Instruction>();
var ldlocOp = new Operation() { OperationCode = Cci.OperationCode.Ldloc, Value = sourceLocal };
var ldlocInstr = new Instruction() { Operation = ldlocOp, Type = type };
transferInstructions.Add(ldlocInstr);
var stlocOp = new Operation() { OperationCode = Cci.OperationCode.Stloc, Value = targetLocal };
var stlocInstr = new Instruction() { Operation = stlocOp, Type = type.PlatformType.SystemVoid };
transferInstructions.Add(stlocInstr);
}
private void ReplaceSSALocalsInBlocks() {
foreach (var block in this.cfgQueries.BlocksInPostorder) {
Contract.Assume(block != null);
var n = block.Instructions.Count;
for (int i = n-1; i >= 0; i--) {
var instruction = block.Instructions[i];
var ssaLocal = instruction.Operation.Value as SSALocalDefinition;
if (ssaLocal != null)
this.ReplaceSSALocal(instruction, ssaLocal);
else {
var ssaParam = instruction.Operation.Value as SSAParameterDefinition;
if (ssaParam != null)
this.ReplaceSSAParameter(instruction, ssaParam);
}
}
if (block.Joins == null) continue;
foreach (var join in block.Joins) {
Contract.Assume(join.NewLocal != null);
var unifiedLocal = this.unifiedLocalFor[join.NewLocal];
if (unifiedLocal == null) continue;
this.availableLocalsFor.Add(join.Type.InternedKey, unifiedLocal);
}
}
}
private void ReplaceSSALocal(Instruction instruction, SSALocalDefinition ssaLocal) {
Contract.Requires(instruction != null);
Contract.Requires(ssaLocal != null);
var unifiedLocal = this.unifiedLocalFor[ssaLocal];
if (unifiedLocal == null) {
foreach (var local in this.availableLocalsFor.GetValuesFor(ssaLocal.Type.InternedKey)) {
unifiedLocal = local;
break;
}
if (unifiedLocal == null) {
unifiedLocal = new GeneratorLocal() { Name = ssaLocal.Name, Type = ssaLocal.Type };
}
this.unifiedLocalFor[ssaLocal] = unifiedLocal;
}
var oldOperation = instruction.Operation;
OperationCode newOp = OperationCode.Ldloc;
switch (oldOperation.OperationCode) {
case OperationCode.Ldloca:
case OperationCode.Ldloca_S:
newOp = OperationCode.Ldloca;
goto freeUnifiedLocal;
case OperationCode.Stloc:
case OperationCode.Stloc_0:
case OperationCode.Stloc_1:
case OperationCode.Stloc_2:
case OperationCode.Stloc_3:
case OperationCode.Stloc_S:
newOp = OperationCode.Stloc;
freeUnifiedLocal:
this.availableLocalsFor.Add(ssaLocal.Type.InternedKey, unifiedLocal);
break;
}
instruction.Operation = new Operation() { Location = oldOperation.Location, Offset = oldOperation.Offset, OperationCode = newOp, Value = unifiedLocal };
}
private void ReplaceSSAParameter(Instruction instruction, SSAParameterDefinition ssaParameter) {
Contract.Requires(instruction != null);
Contract.Requires(ssaParameter != null);
var unifiedLocal = this.unifiedLocalFor[ssaParameter];
if (unifiedLocal == null) {
foreach (var local in this.availableLocalsFor.GetValuesFor(ssaParameter.Type.InternedKey)) {
unifiedLocal = local;
break;
}
if (unifiedLocal == null) {
unifiedLocal = new GeneratorLocal() { Name = ssaParameter.Name, Type = ssaParameter.Type };
}
this.unifiedLocalFor[ssaParameter] = unifiedLocal;
}
var oldOperation = instruction.Operation;
OperationCode newOp = OperationCode.Ldloc;
switch (oldOperation.OperationCode) {
case OperationCode.Ldarga:
case OperationCode.Ldarga_S:
newOp = OperationCode.Ldloca;
goto freeUnifiedLocal;
case OperationCode.Starg:
case OperationCode.Starg_S:
newOp = OperationCode.Stloc;
freeUnifiedLocal:
this.availableLocalsFor.Add(ssaParameter.Type.InternedKey, unifiedLocal);
break;
}
instruction.Operation = new Operation() { Location = oldOperation.Location, Offset = oldOperation.Offset, OperationCode = newOp, Value = unifiedLocal };
}
private void ReplaceSSALocalsInTransferInstructions() {
foreach (var block in this.cdfg.AllBlocks) {
Contract.Assume(block != null);
if (block.transferBlocks == null) continue;
foreach (var transferBlock in block.transferBlocks) {
if (transferBlock == null) continue;
if (transferBlock.transferInstructions == null) continue;
foreach (var instruction in transferBlock.transferInstructions) {
Contract.Assume(instruction != null);
if (instruction.Operation.Value == null) continue;
var unifiedLocal = this.unifiedLocalFor[instruction.Operation.Value];
if (unifiedLocal == null) continue;
var operation = instruction.Operation;
var mutableOperation = operation as Operation;
if (mutableOperation == null) mutableOperation = new Operation() { OperationCode = operation.OperationCode, Offset = operation.Offset, Location = operation.Location };
mutableOperation.Value = unifiedLocal;
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CBBD690B-398D-4A4F-ADA6-D418B226243F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.Optimization</RootNamespace>
<AssemblyName>Microsoft.Cci.Optimization.OptimizationUtilities</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
<CodeContractsInferRequires>True</CodeContractsInferRequires>
<CodeContractsInferEnsures>True</CodeContractsInferEnsures>
<CodeContractsInferObjectInvariants>True</CodeContractsInferObjectInvariants>
<CodeContractsSuggestAssumptions>True</CodeContractsSuggestAssumptions>
<CodeContractsSuggestRequires>False</CodeContractsSuggestRequires>
<CodeContractsSuggestEnsures>False</CodeContractsSuggestEnsures>
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
<CodeContractsDisjunctiveRequires>True</CodeContractsDisjunctiveRequires>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions>-show unreached</CodeContractsExtraAnalysisOptions>
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>2</CodeContractsAnalysisWarningLevel>
<DocumentationFile>bin\Debug\Microsoft.Cci.Optimization.OptimizationUtilities.XML</DocumentationFile>
<CodeContractsSQLServerOption />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\Version.cs">
<Link>Build\Version.cs</Link>
</Compile>
<Compile Include="Merger.cs" />
<Compile Include="ILGeneration.cs" />
<Compile Include="Inlining.cs" />
<Compile Include="LocalMinimizer.cs" />
<Compile Include="MultipleAssignment.cs" />
<Compile Include="PartialEvaluation.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StackEliminator.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ILGenerator\ILGenerator.csproj">
<Project>{08156C78-403A-4112-AD81-8646AC51CD2F}</Project>
<Name>ILGenerator</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataHelper\MetadataHelper.csproj">
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
<Name>MetadataHelper</Name>
</ProjectReference>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\MutableMetadataModel\MutableMetadataModel.csproj">
<Project>{319E151C-8F33-49E7-81C9-30F02F9BA90A}</Project>
<Name>MutableMetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\SourceModel\SourceModel.csproj">
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
<Name>SourceModel</Name>
</ProjectReference>
<ProjectReference Include="..\ControlAndDataFlowGraph\ControlAndDataFlowGraph.csproj">
<Project>{2596EFB0-87AE-42CE-89EB-84F35D6350D2}</Project>
<Name>ControlAndDataFlowGraph</Name>
</ProjectReference>
<ProjectReference Include="..\AnalyisUtilities\AnalysisUtilities.csproj">
<Project>{E8B89C56-383A-4A1D-9EEE-E5FE9FC9DE03}</Project>
<Name>AnalysisUtilities</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Optimization")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9a1c684f-4070-4fa3-af2d-c33b1c7f6fd7")]

Просмотреть файл

@ -0,0 +1,160 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Microsoft.Cci.Analysis;
using Microsoft.Cci.UtilityDataStructures;
using System;
using Microsoft.Cci.MutableCodeModel;
using System.Diagnostics;
namespace Microsoft.Cci.Optimization {
/// <summary>
/// Introduces temporary variables and transfer instructions in order to ensure that the operand stack is empty at the start of every basic block.
/// </summary>
[ContractVerification(false)]
public class StackEliminator<BasicBlock, Instruction>
where BasicBlock :PeBasicBlock<Instruction>, new()
where Instruction : PeInstruction, new() {
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="cdfg"></param>
/// <param name="localScopeProvider"></param>
/// <param name="sourceLocationProvider"></param>
public StackEliminator(IMetadataHost host,
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg, ILocalScopeProvider/*?*/ localScopeProvider, ISourceLocationProvider/*?*/ sourceLocationProvider) {
Contract.Requires(host != null);
Contract.Requires(cdfg != null);
this.host = host;
this.localScopeProvider = localScopeProvider;
this.sourceLocationProvider = sourceLocationProvider;
this.cdfg = cdfg;
}
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(this.host != null);
Contract.Invariant(this.cdfg != null);
}
IMetadataHost host;
ILocalScopeProvider/*?*/ localScopeProvider;
ISourceLocationProvider/*?*/ sourceLocationProvider;
ControlAndDataFlowGraph<BasicBlock, Instruction> cdfg;
/// <summary>
///
/// </summary>
/// <returns></returns>
public IMethodBody GetNewBody() {
this.Eliminate();
var methodBody = this.cdfg.MethodBody;
var ilGenerator = new ILGenerator(host, methodBody.MethodDefinition);
var converter = new PeILConverter<BasicBlock, Instruction>(this.cdfg, ilGenerator, this.localScopeProvider, this.sourceLocationProvider);
converter.PopulateILGenerator();
return new ILGeneratorMethodBody(ilGenerator, methodBody.LocalsAreZeroed, converter.MaxStack, methodBody.MethodDefinition,
converter.Locals.AsReadOnly(), Enumerable<ITypeDefinition>.Empty);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private void Eliminate() {
var blocksAlreadyVisited = new SetOfObjects();
foreach (var block in this.cdfg.RootBlocks) {
Contract.Assume(block != null);
blocksAlreadyVisited.Clear();
this.Eliminate(block, blocksAlreadyVisited);
}
}
private void Eliminate(BasicBlock block, SetOfObjects blocksAlreadyVisited) {
Contract.Requires(block != null);
Contract.Requires(blocksAlreadyVisited != null);
var successors = this.cdfg.SuccessorsFor(block);
var n = successors.Count;
if (n == 0) return;
for (var i = 0; i < n; i++) {
var succ = successors[i];
this.AddTransferInstructions(block, succ, i);
if (!blocksAlreadyVisited.Add(succ)) continue;
this.Eliminate(succ, blocksAlreadyVisited);
}
}
private void AddTransferInstructions(BasicBlock block, BasicBlock succ, int successorIndex) {
Contract.Requires(block != null);
Contract.Requires(succ != null);
foreach (var stackLoad in succ.OperandStack) {
if (stackLoad.temporaryForResult != null)
stackLoad.temporaryForResult = new GeneratorLocal() { Type = stackLoad.Type };
var joins = stackLoad.Operand2 as Instruction[];
Contract.Assume(joins != null);
for (int i = 0, n = joins.Length; i < n; i++) {
var join = joins[i];
Contract.Assume(join != null);
Contract.Assume(BelongsTo(block, join));
if (join.temporaryForResult == null) {
join.temporaryForResult = new GeneratorLocal() { Type = stackLoad.Type };
join.MustBeCachedInTemporary = true;
join.LeaveResultOnStack = false;
} else {
Contract.Assume(join.MustBeCachedInTemporary);
Contract.Assume(!join.LeaveResultOnStack);
}
this.AddTransferInstruction(block, succ, successorIndex, stackLoad.temporaryForResult, join.temporaryForResult, stackLoad.Type);
}
}
}
private void AddTransferInstruction(BasicBlock block, BasicBlock succ, int successorIndex, object targetLocal, object sourceLocal, ITypeReference type) {
Contract.Requires(block != null);
Contract.Requires(succ != null);
Contract.Requires(type != null);
if (block.transferBlocks == null)
block.transferBlocks = new PeBasicBlock<Instruction>[this.cdfg.SuccessorsFor(block).Count];
Contract.Assume(0 <= successorIndex && successorIndex < block.transferBlocks.Length);
var transferBlock = block.transferBlocks[successorIndex];
if (transferBlock == null)
transferBlock = block.transferBlocks[successorIndex] = new PeBasicBlock<Instruction>();
var transferInstructions = transferBlock.transferInstructions;
if (transferInstructions == null)
transferInstructions = transferBlock.transferInstructions = new List<Instruction>();
var ldlocOp = new Operation() { OperationCode = Cci.OperationCode.Ldloc, Value = sourceLocal };
var ldlocInstr = new Instruction() { Operation = ldlocOp, Type = type };
transferInstructions.Add(ldlocInstr);
var stlocOp = new Operation() { OperationCode = Cci.OperationCode.Stloc, Value = targetLocal };
var stlocInstr = new Instruction() { Operation = stlocOp, Type = type.PlatformType.SystemVoid };
transferInstructions.Add(stlocInstr);
}
[Pure]
private static bool BelongsTo(BasicBlock block, Instruction instruction) {
if (block == null) return false;
foreach (var instr in block.Instructions) {
if (instr == instruction) return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,255 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
using System.Text;
namespace Microsoft.Cci.Pdb {
internal class BitAccess {
internal BitAccess(int capacity) {
this.buffer = new byte[capacity];
}
internal byte[] Buffer {
get { return buffer; }
}
private byte[] buffer;
internal void FillBuffer(Stream stream, int capacity) {
MinCapacity(capacity);
stream.Read(buffer, 0, capacity);
offset = 0;
}
internal void Append(Stream stream, int count) {
int newCapacity = offset + count;
if (buffer.Length < newCapacity) {
byte[] newBuffer = new byte[newCapacity];
Array.Copy(buffer, newBuffer, buffer.Length);
buffer = newBuffer;
}
stream.Read(buffer, offset, count);
offset += count;
}
internal int Position {
get { return offset; }
set { offset = value; }
}
private int offset;
//internal void WriteBuffer(Stream stream, int count) {
// stream.Write(buffer, 0, count);
//}
internal void MinCapacity(int capacity) {
if (buffer.Length < capacity) {
buffer = new byte[capacity];
}
offset = 0;
}
internal void Align(int alignment) {
while ((offset % alignment) != 0) {
offset++;
}
}
//internal void WriteInt32(int value) {
// buffer[offset + 0] = (byte)value;
// buffer[offset + 1] = (byte)(value >> 8);
// buffer[offset + 2] = (byte)(value >> 16);
// buffer[offset + 3] = (byte)(value >> 24);
// offset += 4;
//}
//internal void WriteInt32(int[] values) {
// for (int i = 0; i < values.Length; i++) {
// WriteInt32(values[i]);
// }
//}
//internal void WriteBytes(byte[] bytes) {
// for (int i = 0; i < bytes.Length; i++) {
// buffer[offset++] = bytes[i];
// }
//}
internal void ReadInt16(out short value) {
value = (short)((buffer[offset + 0] & 0xFF) |
(buffer[offset + 1] << 8));
offset += 2;
}
internal void ReadInt8(out sbyte value) {
value = (sbyte)buffer[offset];
offset += 1;
}
internal void ReadInt32(out int value) {
value = (int)((buffer[offset + 0] & 0xFF) |
(buffer[offset + 1] << 8) |
(buffer[offset + 2] << 16) |
(buffer[offset + 3] << 24));
offset += 4;
}
internal void ReadInt64(out long value) {
value = (long)(((ulong)buffer[offset + 0] & 0xFF) |
((ulong)buffer[offset + 1] << 8) |
((ulong)buffer[offset + 2] << 16) |
((ulong)buffer[offset + 3] << 24) |
((ulong)buffer[offset + 4] << 32) |
((ulong)buffer[offset + 5] << 40) |
((ulong)buffer[offset + 6] << 48) |
((ulong)buffer[offset + 7] << 56));
offset += 8;
}
internal void ReadUInt16(out ushort value) {
value = (ushort)((buffer[offset + 0] & 0xFF) |
(buffer[offset + 1] << 8));
offset += 2;
}
internal void ReadUInt8(out byte value) {
value = (byte)((buffer[offset + 0] & 0xFF));
offset += 1;
}
internal void ReadUInt32(out uint value) {
value = (uint)((buffer[offset + 0] & 0xFF) |
(buffer[offset + 1] << 8) |
(buffer[offset + 2] << 16) |
(buffer[offset + 3] << 24));
offset += 4;
}
internal void ReadUInt64(out ulong value) {
value = (ulong)(((ulong)buffer[offset + 0] & 0xFF) |
((ulong)buffer[offset + 1] << 8) |
((ulong)buffer[offset + 2] << 16) |
((ulong)buffer[offset + 3] << 24) |
((ulong)buffer[offset + 4] << 32) |
((ulong)buffer[offset + 5] << 40) |
((ulong)buffer[offset + 6] << 48) |
((ulong)buffer[offset + 7] << 56));
offset += 8;
}
internal void ReadInt32(int[] values) {
for (int i = 0; i < values.Length; i++) {
ReadInt32(out values[i]);
}
}
internal void ReadUInt32(uint[] values) {
for (int i = 0; i < values.Length; i++) {
ReadUInt32(out values[i]);
}
}
internal void ReadBytes(byte[] bytes) {
for (int i = 0; i < bytes.Length; i++) {
bytes[i] = buffer[offset++];
}
}
internal float ReadFloat() {
float result = BitConverter.ToSingle(buffer, offset);
offset += 4;
return result;
}
internal double ReadDouble() {
double result = BitConverter.ToDouble(buffer, offset);
offset += 8;
return result;
}
internal decimal ReadDecimal() {
int[] bits = new int[4];
this.ReadInt32(bits);
return new decimal(bits[2], bits[3], bits[1], bits[0] < 0, (byte)((bits[0] & 0x00FF0000) >> 16));
}
internal void ReadBString(out string value) {
ushort len;
this.ReadUInt16(out len);
value = Encoding.UTF8.GetString(buffer, offset, len);
offset += len;
}
internal string ReadBString(int len) {
var result = Encoding.UTF8.GetString(buffer, offset, len);
offset += len;
return result;
}
internal void ReadCString(out string value) {
int len = 0;
while (offset + len < buffer.Length && buffer[offset + len] != 0) {
len++;
}
value = Encoding.UTF8.GetString(buffer, offset, len);
offset += len + 1;
}
internal void SkipCString(out string value) {
int len = 0;
while (offset + len < buffer.Length && buffer[offset + len] != 0) {
len++;
}
offset += len + 1;
value= null;
}
internal void ReadGuid(out Guid guid) {
uint a;
ushort b;
ushort c;
byte d;
byte e;
byte f;
byte g;
byte h;
byte i;
byte j;
byte k;
ReadUInt32(out a);
ReadUInt16(out b);
ReadUInt16(out c);
ReadUInt8(out d);
ReadUInt8(out e);
ReadUInt8(out f);
ReadUInt8(out g);
ReadUInt8(out h);
ReadUInt8(out i);
ReadUInt8(out j);
ReadUInt8(out k);
guid = new Guid(a, b, c, d, e, f, g, h, i, j, k);
}
internal string ReadString() {
int len = 0;
while (offset + len < buffer.Length && buffer[offset + len] != 0) {
len+=2;
}
string result = Encoding.Unicode.GetString(buffer, offset, len);
offset += len + 2;
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal struct BitSet {
internal BitSet(BitAccess bits) {
bits.ReadInt32(out size); // 0..3 : Number of words
words = new uint[size];
bits.ReadUInt32(words);
}
//internal BitSet(int size) {
// this.size = size;
// words = new uint[size];
//}
internal bool IsSet(int index) {
int word = index / 32;
if (word >= this.size) return false;
return ((words[word] & GetBit(index)) != 0);
}
//internal void Set(int index) {
// int word = index / 32;
// if (word >= this.size) return;
// words[word] |= GetBit(index);
//}
//internal void Clear(int index) {
// int word = index / 32;
// if (word >= this.size) return;
// words[word] &= ~GetBit(index);
//}
private static uint GetBit(int index) {
return ((uint)1 << (index % 32));
}
//private static uint ReverseBits(uint value) {
// uint o = 0;
// for (int i = 0; i < 32; i++) {
// o = (o << 1) | (value & 1);
// value >>= 1;
// }
// return o;
//}
internal bool IsEmpty {
get { return size == 0; }
}
//internal bool GetWord(int index, out uint word) {
// if (index < size) {
// word = ReverseBits(words[index]);
// return true;
// }
// word = 0;
// return false;
//}
private int size;
private uint[] words;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,111 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
namespace Microsoft.Cci.Pdb {
internal class DataStream {
internal DataStream() {
}
internal DataStream(int contentSize, BitAccess bits, int count) {
this.contentSize = contentSize;
if (count > 0) {
this.pages = new int[count];
bits.ReadInt32(this.pages);
}
}
internal void Read(PdbReader reader, BitAccess bits) {
bits.MinCapacity(contentSize);
Read(reader, 0, bits.Buffer, 0, contentSize);
}
internal void Read(PdbReader reader, int position,
byte[] bytes, int offset, int data) {
if (position + data > contentSize) {
throw new PdbException("DataStream can't read off end of stream. " +
"(pos={0},siz={1})",
position, data);
}
if (position == contentSize) {
return;
}
int left = data;
int page = position / reader.pageSize;
int rema = position % reader.pageSize;
// First get remained of first page.
if (rema != 0) {
int todo = reader.pageSize - rema;
if (todo > left) {
todo = left;
}
reader.Seek(pages[page], rema);
reader.Read(bytes, offset, todo);
offset += todo;
left -= todo;
page++;
}
// Now get the remaining pages.
while (left > 0) {
int todo = reader.pageSize;
if (todo > left) {
todo = left;
}
reader.Seek(pages[page], 0);
reader.Read(bytes, offset, todo);
offset += todo;
left -= todo;
page++;
}
}
//private void AddPages(int page0, int count) {
// if (pages == null) {
// pages = new int[count];
// for (int i = 0; i < count; i++) {
// pages[i] = page0 + i;
// }
// } else {
// int[] old = pages;
// int used = old.Length;
// pages = new int[used + count];
// Array.Copy(old, pages, used);
// for (int i = 0; i < count; i++) {
// pages[used + i] = page0 + i;
// }
// }
//}
//internal int Pages {
// get { return pages == null ? 0 : pages.Length; }
//}
internal int Length {
get { return contentSize; }
}
//internal int GetPage(int index) {
// return pages[index];
//}
internal int contentSize;
internal int[] pages;
}
}

Просмотреть файл

@ -0,0 +1,41 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal struct DbiDbgHdr {
internal DbiDbgHdr(BitAccess bits) {
bits.ReadUInt16(out snFPO);
bits.ReadUInt16(out snException);
bits.ReadUInt16(out snFixup);
bits.ReadUInt16(out snOmapToSrc);
bits.ReadUInt16(out snOmapFromSrc);
bits.ReadUInt16(out snSectionHdr);
bits.ReadUInt16(out snTokenRidMap);
bits.ReadUInt16(out snXdata);
bits.ReadUInt16(out snPdata);
bits.ReadUInt16(out snNewFPO);
bits.ReadUInt16(out snSectionHdrOrig);
}
internal ushort snFPO; // 0..1
internal ushort snException; // 2..3 (deprecated)
internal ushort snFixup; // 4..5
internal ushort snOmapToSrc; // 6..7
internal ushort snOmapFromSrc; // 8..9
internal ushort snSectionHdr; // 10..11
internal ushort snTokenRidMap; // 12..13
internal ushort snXdata; // 14..15
internal ushort snPdata; // 16..17
internal ushort snNewFPO; // 18..19
internal ushort snSectionHdrOrig; // 20..21
}
}

Просмотреть файл

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal struct DbiHeader {
internal DbiHeader(BitAccess bits) {
bits.ReadInt32(out sig);
bits.ReadInt32(out ver);
bits.ReadInt32(out age);
bits.ReadInt16(out gssymStream);
bits.ReadUInt16(out vers);
bits.ReadInt16(out pssymStream);
bits.ReadUInt16(out pdbver);
bits.ReadInt16(out symrecStream);
bits.ReadUInt16(out pdbver2);
bits.ReadInt32(out gpmodiSize);
bits.ReadInt32(out secconSize);
bits.ReadInt32(out secmapSize);
bits.ReadInt32(out filinfSize);
bits.ReadInt32(out tsmapSize);
bits.ReadInt32(out mfcIndex);
bits.ReadInt32(out dbghdrSize);
bits.ReadInt32(out ecinfoSize);
bits.ReadUInt16(out flags);
bits.ReadUInt16(out machine);
bits.ReadInt32(out reserved);
}
internal int sig; // 0..3
internal int ver; // 4..7
internal int age; // 8..11
internal short gssymStream; // 12..13
internal ushort vers; // 14..15
internal short pssymStream; // 16..17
internal ushort pdbver; // 18..19
internal short symrecStream; // 20..21
internal ushort pdbver2; // 22..23
internal int gpmodiSize; // 24..27
internal int secconSize; // 28..31
internal int secmapSize; // 32..35
internal int filinfSize; // 36..39
internal int tsmapSize; // 40..43
internal int mfcIndex; // 44..47
internal int dbghdrSize; // 48..51
internal int ecinfoSize; // 52..55
internal ushort flags; // 56..57
internal ushort machine; // 58..59
internal int reserved; // 60..63
}
}

Просмотреть файл

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class DbiModuleInfo {
internal DbiModuleInfo(BitAccess bits, bool readStrings) {
bits.ReadInt32(out opened);
new DbiSecCon(bits);
bits.ReadUInt16(out flags);
bits.ReadInt16(out stream);
bits.ReadInt32(out cbSyms);
bits.ReadInt32(out cbOldLines);
bits.ReadInt32(out cbLines);
bits.ReadInt16(out files);
bits.ReadInt16(out pad1);
bits.ReadUInt32(out offsets);
bits.ReadInt32(out niSource);
bits.ReadInt32(out niCompiler);
if (readStrings) {
bits.ReadCString(out moduleName);
bits.ReadCString(out objectName);
} else {
bits.SkipCString(out moduleName);
bits.SkipCString(out objectName);
}
bits.Align(4);
//if (opened != 0 || pad1 != 0) {
// throw new PdbException("Invalid DBI module. "+
// "(opened={0}, pad={1})", opened, pad1);
//}
}
internal int opened; // 0..3
//internal DbiSecCon section; // 4..31
internal ushort flags; // 32..33
internal short stream; // 34..35
internal int cbSyms; // 36..39
internal int cbOldLines; // 40..43
internal int cbLines; // 44..57
internal short files; // 48..49
internal short pad1; // 50..51
internal uint offsets;
internal int niSource;
internal int niCompiler;
internal string moduleName;
internal string objectName;
}
}

Просмотреть файл

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal struct DbiSecCon {
internal DbiSecCon(BitAccess bits) {
bits.ReadInt16(out section);
bits.ReadInt16(out pad1);
bits.ReadInt32(out offset);
bits.ReadInt32(out size);
bits.ReadUInt32(out flags);
bits.ReadInt16(out module);
bits.ReadInt16(out pad2);
bits.ReadUInt32(out dataCrc);
bits.ReadUInt32(out relocCrc);
//if (pad1 != 0 || pad2 != 0) {
// throw new PdbException("Invalid DBI section. "+
// "(pad1={0}, pad2={1})",
// pad1, pad2);
//}
}
internal short section; // 0..1
internal short pad1; // 2..3
internal int offset; // 4..7
internal int size; // 8..11
internal uint flags; // 12..15
internal short module; // 16..17
internal short pad2; // 18..19
internal uint dataCrc; // 20..23
internal uint relocCrc; // 24..27
}
}

Просмотреть файл

@ -0,0 +1,583 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections;
namespace Microsoft.Cci.Pdb {
// The IntHashTable class represents a dictionary of associated keys and
// values with constant lookup time.
//
// Objects used as keys in a hashtable must implement the GetHashCode
// and Equals methods (or they can rely on the default implementations
// inherited from Object if key equality is simply reference
// equality). Furthermore, the GetHashCode and Equals methods of
// a key object must produce the same results given the same parameters
// for the entire time the key is present in the hashtable. In practical
// terms, this means that key objects should be immutable, at least for
// the time they are used as keys in a hashtable.
//
// When entries are added to a hashtable, they are placed into
// buckets based on the hashcode of their keys. Subsequent lookups of
// keys will use the hashcode of the keys to only search a particular
// bucket, thus substantially reducing the number of key comparisons
// required to find an entry. A hashtable's maximum load factor, which
// can be specified when the hashtable is instantiated, determines the
// maximum ratio of hashtable entries to hashtable buckets. Smaller load
// factors cause faster average lookup times at the cost of increased
// memory consumption. The default maximum load factor of 1.0 generally
// provides the best balance between speed and size. As entries are added
// to a hashtable, the hashtable's actual load factor increases, and when
// the actual load factor reaches the maximum load factor value, the
// number of buckets in the hashtable is automatically increased by
// approximately a factor of two (to be precise, the number of hashtable
// buckets is increased to the smallest prime number that is larger than
// twice the current number of hashtable buckets).
//
// Each object provides their own hash function, accessed by calling
// GetHashCode(). However, one can write their own object
// implementing IHashCodeProvider and pass it to a constructor on
// the IntHashTable. That hash function would be used for all objects in
// the table.
//
// This IntHashTable is implemented to support multiple concurrent readers
// and one concurrent writer without using any synchronization primitives.
// All read methods essentially must protect themselves from a resize
// occuring while they are running. This was done by enforcing an
// ordering on inserts & removes, as well as removing some member variables
// and special casing the expand code to work in a temporary array instead
// of the live bucket array. All inserts must set a bucket's value and
// key before setting the hash code & collision field.
//
// By Brian Grunkemeyer, algorithm by Patrick Dussud.
// Version 1.30 2/20/2000
//| <include path='docs/doc[@for="IntHashTable"]/*' />
internal class IntHashTable {//: IEnumerable {
/*
Implementation Notes:
This IntHashTable uses double hashing. There are hashsize buckets in
the table, and each bucket can contain 0 or 1 element. We a bit to
mark whether there's been a collision when we inserted multiple
elements (ie, an inserted item was hashed at least a second time and
we probed this bucket, but it was already in use). Using the
collision bit, we can terminate lookups & removes for elements that
aren't in the hash table more quickly. We steal the most
significant bit from the hash code to store the collision bit.
Our hash function is of the following form:
h(key, n) = h1(key) + n*h2(key)
where n is the number of times we've hit a collided bucket and
rehashed (on this particular lookup). Here are our hash functions:
h1(key) = GetHash(key); // default implementation calls key.GetHashCode();
h2(key) = 1 + (((h1(key) >> 5) + 1) % (hashsize - 1));
The h1 can return any number. h2 must return a number between 1 and
hashsize - 1 that is relatively prime to hashsize (not a problem if
hashsize is prime). (Knuth's Art of Computer Programming, Vol. 3,
p. 528-9)
If this is true, then we are guaranteed to visit every bucket in
exactly hashsize probes, since the least common multiple of hashsize
and h2(key) will be hashsize * h2(key). (This is the first number
where adding h2 to h1 mod hashsize will be 0 and we will search the
same bucket twice).
We previously used a different h2(key, n) that was not constant.
That is a horrifically bad idea, unless you can prove that series
will never produce any identical numbers that overlap when you mod
them by hashsize, for all subranges from i to i+hashsize, for all i.
It's not worth investigating, since there was no clear benefit from
using that hash function, and it was broken.
For efficiency reasons, we've implemented this by storing h1 and h2
in a temporary, and setting a variable called seed equal to h1. We
do a probe, and if we collided, we simply add h2 to seed each time
through the loop.
A good test for h2() is to subclass IntHashTable, provide your own
implementation of GetHash() that returns a constant, then add many
items to the hash table. Make sure Count equals the number of items
you inserted.
-- Brian Grunkemeyer, 10/28/1999
*/
// A typical resize algorithm would pick the smallest prime number in this array
// that is larger than twice the previous capacity.
// Suppose our Hashtable currently has capacity x and enough elements are added
// such that a resize needs to occur. Resizing first computes 2x then finds the
// first prime in the table greater than 2x, i.e. if primes are ordered
// p_1, p_2, …, p_i,…, it finds p_n such that p_n-1 < 2x < p_n.
// Doubling is important for preserving the asymptotic complexity of the
// hashtable operations such as add. Having a prime guarantees that double
// hashing does not lead to infinite loops. IE, your hash function will be
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
private static readonly int[] primes = {
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
private static int GetPrime(int minSize) {
if (minSize < 0) {
throw new ArgumentException("Arg_HTCapacityOverflow");
}
for (int i = 0; i < primes.Length; i++) {
int size = primes[i];
if (size >= minSize) {
return size;
}
}
throw new ArgumentException("Arg_HTCapacityOverflow");
}
// Deleted entries have their key set to buckets
// The hash table data.
// This cannot be serialised
private struct bucket {
internal int key;
internal int hash_coll; // Store hash code; sign bit means there was a collision.
internal Object val;
}
private bucket[] buckets;
// The total number of entries in the hash table.
private int count;
// The total number of collision bits set in the hashtable
private int occupancy;
private int loadsize;
private int loadFactorPerc; // 100 = 1.0
private int version;
// Constructs a new hashtable. The hashtable is created with an initial
// capacity of zero and a load factor of 1.0.
//| <include path='docs/doc[@for="IntHashTable.IntHashTable"]/*' />
internal IntHashTable()
: this(0, 100) {
}
//// Constructs a new hashtable with the given initial capacity and a load
//// factor of 1.0. The capacity argument serves as an indication of
//// the number of entries the hashtable will contain. When this number (or
//// an approximation) is known, specifying it in the constructor can
//// eliminate a number of resizing operations that would otherwise be
//// performed when elements are added to the hashtable.
////
////| <include path='docs/doc[@for="IntHashTable.IntHashTable1"]/*' />
//internal IntHashTable(int capacity)
// : this(capacity, 100) {
//}
// Constructs a new hashtable with the given initial capacity and load
// factor. The capacity argument serves as an indication of the
// number of entries the hashtable will contain. When this number (or an
// approximation) is known, specifying it in the constructor can eliminate
// a number of resizing operations that would otherwise be performed when
// elements are added to the hashtable. The loadFactorPerc argument
// indicates the maximum ratio of hashtable entries to hashtable buckets.
// Smaller load factors cause faster average lookup times at the cost of
// increased memory consumption. A load factor of 1.0 generally provides
// the best balance between speed and size.
//
//| <include path='docs/doc[@for="IntHashTable.IntHashTable3"]/*' />
internal IntHashTable(int capacity, int loadFactorPerc) {
if (capacity < 0)
throw new ArgumentOutOfRangeException("capacity", "ArgumentOutOfRange_NeedNonNegNum");
if (!(loadFactorPerc >= 10 && loadFactorPerc <= 100))
throw new ArgumentOutOfRangeException("loadFactorPerc", String.Format("ArgumentOutOfRange_IntHashTableLoadFactor", 10, 100));
// Based on perf work, .72 is the optimal load factor for this table.
this.loadFactorPerc = (loadFactorPerc * 72) / 100;
int hashsize = GetPrime((int)(capacity / this.loadFactorPerc));
buckets = new bucket[hashsize];
loadsize = (int)(this.loadFactorPerc * hashsize) / 100;
if (loadsize >= hashsize)
loadsize = hashsize-1;
}
// Computes the hash function: H(key, i) = h1(key) + i*h2(key, hashSize).
// The out parameter seed is h1(key), while the out parameter
// incr is h2(key, hashSize). Callers of this function should
// add incr each time through a loop.
private static uint InitHash(int key, int hashsize, out uint seed, out uint incr) {
// Hashcode must be positive. Also, we must not use the sign bit, since
// that is used for the collision bit.
uint hashcode = (uint)key & 0x7FFFFFFF;
seed = (uint)hashcode;
// Restriction: incr MUST be between 1 and hashsize - 1, inclusive for
// the modular arithmetic to work correctly. This guarantees you'll
// visit every bucket in the table exactly once within hashsize
// iterations. Violate this and it'll cause obscure bugs forever.
// If you change this calculation for h2(key), update putEntry too!
incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)hashsize - 1)));
return hashcode;
}
// Adds an entry with the given key and value to this hashtable. An
// ArgumentException is thrown if the key is null or if the key is already
// present in the hashtable.
//
//| <include path='docs/doc[@for="IntHashTable.Add"]/*' />
internal void Add(int key, Object value) {
Insert(key, value, true);
}
//// Removes all entries from this hashtable.
////| <include path='docs/doc[@for="IntHashTable.Clear"]/*' />
//internal void Clear() {
// if (count == 0)
// return;
// for (int i = 0; i < buckets.Length; i++) {
// buckets[i].hash_coll = 0;
// buckets[i].key = -1;
// buckets[i].val = null;
// }
// count = 0;
// occupancy = 0;
//}
// Checks if this hashtable contains an entry with the given key. This is
// an O(1) operation.
//
//| <include path='docs/doc[@for="IntHashTable.Contains"]/*' />
//internal bool Contains(int key) {
// if (key < 0) {
// throw new ArgumentException("Argument_KeyLessThanZero");
// }
// uint seed;
// uint incr;
// // Take a snapshot of buckets, in case another thread resizes table
// bucket[] lbuckets = buckets;
// uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr);
// int ntry = 0;
// bucket b;
// do {
// int bucketNumber = (int)(seed % (uint)lbuckets.Length);
// b = lbuckets[bucketNumber];
// if (b.val == null) {
// return false;
// }
// if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && b.key == key) {
// return true;
// }
// seed += incr;
// } while (b.hash_coll < 0 && ++ntry < lbuckets.Length);
// return false;
//}
// Returns the value associated with the given key. If an entry with the
// given key is not found, the returned value is null.
//
//| <include path='docs/doc[@for="IntHashTable.this"]/*' />
internal Object this[int key] {
get {
if (key < 0) {
throw new ArgumentException("Argument_KeyLessThanZero");
}
uint seed;
uint incr;
// Take a snapshot of buckets, in case another thread does a resize
bucket[] lbuckets = buckets;
uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr);
int ntry = 0;
bucket b;
do {
int bucketNumber = (int)(seed % (uint)lbuckets.Length);
b = lbuckets[bucketNumber];
if (b.val == null) {
return null;
}
if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && key == b.key) {
return b.val;
}
seed += incr;
} while (b.hash_coll < 0 && ++ntry < lbuckets.Length);
return null;
}
//set {
// Insert(key, value, false);
//}
}
// Increases the bucket count of this hashtable. This method is called from
// the Insert method when the actual load factor of the hashtable reaches
// the upper limit specified when the hashtable was constructed. The number
// of buckets in the hashtable is increased to the smallest prime number
// that is larger than twice the current number of buckets, and the entries
// in the hashtable are redistributed into the new buckets using the cached
// hashcodes.
private void expand() {
rehash(GetPrime(1+buckets.Length*2));
}
// We occationally need to rehash the table to clean up the collision bits.
private void rehash() {
rehash(buckets.Length);
}
private void rehash(int newsize) {
// reset occupancy
occupancy=0;
// Don't replace any internal state until we've finished adding to the
// new bucket[]. This serves two purposes:
// 1) Allow concurrent readers to see valid hashtable contents
// at all times
// 2) Protect against an OutOfMemoryException while allocating this
// new bucket[].
bucket[] newBuckets = new bucket[newsize];
// rehash table into new buckets
int nb;
for (nb = 0; nb < buckets.Length; nb++) {
bucket oldb = buckets[nb];
if (oldb.val != null) {
putEntry(newBuckets, oldb.key, oldb.val, oldb.hash_coll & 0x7FFFFFFF);
}
}
// New bucket[] is good to go - replace buckets and other internal state.
version++;
buckets = newBuckets;
loadsize = (int)(loadFactorPerc * newsize) / 100;
if (loadsize >= newsize) {
loadsize = newsize-1;
}
return;
}
// Returns an enumerator for this hashtable.
// If modifications made to the hashtable while an enumeration is
// in progress, the MoveNext and Current methods of the
// enumerator will throw an exception.
//
//| <include path='docs/doc[@for="IntHashTable.IEnumerable.GetEnumerator"]/*' />
//IEnumerator IEnumerable.GetEnumerator() {
// return new IntHashTableEnumerator(this);
//}
// Internal method to compare two keys.
//
// Inserts an entry into this hashtable. This method is called from the Set
// and Add methods. If the add parameter is true and the given key already
// exists in the hashtable, an exception is thrown.
private void Insert(int key, Object nvalue, bool add) {
if (key < 0) {
throw new ArgumentException("Argument_KeyLessThanZero");
}
if (nvalue == null) {
throw new ArgumentNullException("nvalue", "ArgumentNull_Value");
}
if (count >= loadsize) {
expand();
} else if (occupancy > loadsize && count > 100) {
rehash();
}
uint seed;
uint incr;
// Assume we only have one thread writing concurrently. Modify
// buckets to contain new data, as long as we insert in the right order.
uint hashcode = InitHash(key, buckets.Length, out seed, out incr);
int ntry = 0;
int emptySlotNumber = -1; // We use the empty slot number to cache the first empty slot. We chose to reuse slots
// create by remove that have the collision bit set over using up new slots.
do {
int bucketNumber = (int)(seed % (uint)buckets.Length);
// Set emptySlot number to current bucket if it is the first available bucket that we have seen
// that once contained an entry and also has had a collision.
// We need to search this entire collision chain because we have to ensure that there are no
// duplicate entries in the table.
// Insert the key/value pair into this bucket if this bucket is empty and has never contained an entry
// OR
// This bucket once contained an entry but there has never been a collision
if (buckets[bucketNumber].val == null) {
// If we have found an available bucket that has never had a collision, but we've seen an available
// bucket in the past that has the collision bit set, use the previous bucket instead
if (emptySlotNumber != -1) { // Reuse slot
bucketNumber = emptySlotNumber;
}
// We pretty much have to insert in this order. Don't set hash
// code until the value & key are set appropriately.
buckets[bucketNumber].val = nvalue;
buckets[bucketNumber].key = key;
buckets[bucketNumber].hash_coll |= (int)hashcode;
count++;
version++;
return;
}
// The current bucket is in use
// OR
// it is available, but has had the collision bit set and we have already found an available bucket
if (((buckets[bucketNumber].hash_coll & 0x7FFFFFFF) == hashcode) &&
key == buckets[bucketNumber].key) {
if (add) {
throw new ArgumentException("Argument_AddingDuplicate__" + buckets[bucketNumber].key);
}
buckets[bucketNumber].val = nvalue;
version++;
return;
}
// The current bucket is full, and we have therefore collided. We need to set the collision bit
// UNLESS
// we have remembered an available slot previously.
if (emptySlotNumber == -1) {// We don't need to set the collision bit here since we already have an empty slot
if (buckets[bucketNumber].hash_coll >= 0) {
buckets[bucketNumber].hash_coll |= unchecked((int)0x80000000);
occupancy++;
}
}
seed += incr;
} while (++ntry < buckets.Length);
// This code is here if and only if there were no buckets without a collision bit set in the entire table
if (emptySlotNumber != -1) {
// We pretty much have to insert in this order. Don't set hash
// code until the value & key are set appropriately.
buckets[emptySlotNumber].val = nvalue;
buckets[emptySlotNumber].key = key;
buckets[emptySlotNumber].hash_coll |= (int)hashcode;
count++;
version++;
return;
}
// If you see this assert, make sure load factor & count are reasonable.
// Then verify that our double hash function (h2, described at top of file)
// meets the requirements described above. You should never see this assert.
throw new InvalidOperationException("InvalidOperation_HashInsertFailed");
}
private void putEntry(bucket[] newBuckets, int key, Object nvalue, int hashcode) {
uint seed = (uint)hashcode;
uint incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)newBuckets.Length - 1)));
do {
int bucketNumber = (int)(seed % (uint)newBuckets.Length);
if ((newBuckets[bucketNumber].val == null)) {
newBuckets[bucketNumber].val = nvalue;
newBuckets[bucketNumber].key = key;
newBuckets[bucketNumber].hash_coll |= hashcode;
return;
}
if (newBuckets[bucketNumber].hash_coll >= 0) {
newBuckets[bucketNumber].hash_coll |= unchecked((int)0x80000000);
occupancy++;
}
seed += incr;
} while (true);
}
// Returns the number of associations in this hashtable.
//
//| <include path='docs/doc[@for="IntHashTable.Count"]/*' />
//internal int Count {
// get { return count; }
//}
// Implements an enumerator for a hashtable. The enumerator uses the
// internal version number of the hashtabke to ensure that no modifications
// are made to the hashtable while an enumeration is in progress.
//private class IntHashTableEnumerator : IEnumerator {
// private IntHashTable hashtable;
// private int bucket;
// private int version;
// private bool current;
// //private int currentKey;
// private Object currentValue;
// internal IntHashTableEnumerator(IntHashTable hashtable) {
// this.hashtable = hashtable;
// bucket = hashtable.buckets.Length;
// version = hashtable.version;
// }
// public bool MoveNext() {
// if (version != hashtable.version)
// throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
// while (bucket > 0) {
// bucket--;
// Object val = hashtable.buckets[bucket].val;
// if (val != null) {
// //currentKey = hashtable.buckets[bucket].key;
// currentValue = val;
// current = true;
// return true;
// }
// }
// current = false;
// return false;
// }
// //internal int Key {
// // get {
// // if (current == false)
// // throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen");
// // return currentKey;
// // }
// //}
// public Object Current {
// get {
// if (current == false)
// throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen");
// return currentValue;
// }
// }
// //public Object Value {
// // get {
// // if (version != hashtable.version)
// // throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
// // if (current == false)
// // throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen");
// // return currentValue;
// // }
// //}
// public void Reset() {
// if (version != hashtable.version) throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
// current = false;
// bucket = hashtable.buckets.Length;
// //currentKey = -1;
// currentValue = null;
// }
//}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class MsfDirectory {
internal MsfDirectory(PdbReader reader, PdbFileHeader head, BitAccess bits) {
int pages = reader.PagesFromSize(head.directorySize);
// 0..n in page of directory pages.
bits.MinCapacity(head.directorySize);
int directoryRootPages = head.directoryRoot.Length;
int pagesPerPage = head.pageSize / 4;
int pagesToGo = pages;
for (int i = 0; i < directoryRootPages; i++) {
int pagesInThisPage = pagesToGo <= pagesPerPage ? pagesToGo : pagesPerPage;
reader.Seek(head.directoryRoot[i], 0);
bits.Append(reader.reader, pagesInThisPage * 4);
pagesToGo -= pagesInThisPage;
}
bits.Position = 0;
DataStream stream = new DataStream(head.directorySize, bits, pages);
bits.MinCapacity(head.directorySize);
stream.Read(reader, bits);
// 0..3 in directory pages
int count;
bits.ReadInt32(out count);
// 4..n
int[] sizes = new int[count];
bits.ReadInt32(sizes);
// n..m
streams = new DataStream[count];
for (int i = 0; i < count; i++) {
if (sizes[i] <= 0) {
streams[i] = new DataStream();
} else {
streams[i] = new DataStream(sizes[i], bits,
reader.PagesFromSize(sizes[i]));
}
}
}
internal DataStream[] streams;
}
}

Просмотреть файл

@ -0,0 +1,89 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Cci.Pdb {
internal class PdbConstant {
internal string name;
internal uint token;
internal object value;
internal PdbConstant(BitAccess bits) {
bits.ReadUInt32(out this.token);
byte tag1;
bits.ReadUInt8(out tag1);
byte tag2;
bits.ReadUInt8(out tag2);
if (tag2 == 0) {
this.value = tag1;
} else if (tag2 == 0x80) {
switch (tag1) {
case 0x00: //sbyte
sbyte sb;
bits.ReadInt8(out sb);
this.value = sb;
break;
case 0x01: //short
short s;
bits.ReadInt16(out s);
this.value = s;
break;
case 0x02: //ushort
ushort us;
bits.ReadUInt16(out us);
this.value = us;
break;
case 0x03: //int
int i;
bits.ReadInt32(out i);
this.value = i;
break;
case 0x04: //uint
uint ui;
bits.ReadUInt32(out ui);
this.value = ui;
break;
case 0x05: //float
this.value = bits.ReadFloat();
break;
case 0x06: //double
this.value = bits.ReadDouble();
break;
case 0x09: //long
long sl;
bits.ReadInt64(out sl);
this.value = sl;
break;
case 0x0a: //ulong
ulong ul;
bits.ReadUInt64(out ul);
this.value = ul;
break;
case 0x10: //string
string str;
bits.ReadBString(out str);
this.value = str;
break;
case 0x19: //decimal
this.value = bits.ReadDecimal();
break;
default:
//TODO: error
break;
}
} else {
//TODO: error
}
bits.ReadCString(out name);
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
namespace Microsoft.Cci.Pdb {
internal class PdbDebugException : IOException {
internal PdbDebugException(String format, params object[] args)
: base(String.Format(format, args)) {
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
namespace Microsoft.Cci.Pdb {
internal class PdbException : IOException {
internal PdbException(String format, params object[] args)
: base(String.Format(format, args)) {
}
}
}

Просмотреть файл

@ -0,0 +1,553 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics.SymbolStore;
namespace Microsoft.Cci.Pdb {
internal class PdbFile {
private PdbFile() // This class can't be instantiated.
{
}
static void LoadGuidStream(BitAccess bits, out Guid doctype, out Guid language, out Guid vendor) {
bits.ReadGuid(out language);
bits.ReadGuid(out vendor);
bits.ReadGuid(out doctype);
}
static Dictionary<string, int> LoadNameIndex(BitAccess bits) {
Dictionary<string, int> result = new Dictionary<string, int>();
int ver;
int sig;
int age;
Guid guid;
bits.ReadInt32(out ver); // 0..3 Version
bits.ReadInt32(out sig); // 4..7 Signature
bits.ReadInt32(out age); // 8..11 Age
bits.ReadGuid(out guid); // 12..27 GUID
//if (ver != 20000404) {
// throw new PdbDebugException("Unsupported PDB Stream version {0}", ver);
//}
// Read string buffer.
int buf;
bits.ReadInt32(out buf); // 28..31 Bytes of Strings
int beg = bits.Position;
int nxt = bits.Position + buf;
bits.Position = nxt;
// Read map index.
int cnt; // n+0..3 hash size.
int max; // n+4..7 maximum ni.
bits.ReadInt32(out cnt);
bits.ReadInt32(out max);
BitSet present = new BitSet(bits);
BitSet deleted = new BitSet(bits);
if (!deleted.IsEmpty) {
throw new PdbDebugException("Unsupported PDB deleted bitset is not empty.");
}
int j = 0;
for (int i = 0; i < max; i++) {
if (present.IsSet(i)) {
int ns;
int ni;
bits.ReadInt32(out ns);
bits.ReadInt32(out ni);
string name;
int saved = bits.Position;
bits.Position = beg + ns;
bits.ReadCString(out name);
bits.Position = saved;
result.Add(name.ToUpperInvariant(), ni);
j++;
}
}
if (j != cnt) {
throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt);
}
return result;
}
static IntHashTable LoadNameStream(BitAccess bits) {
IntHashTable ht = new IntHashTable();
uint sig;
int ver;
bits.ReadUInt32(out sig); // 0..3 Signature
bits.ReadInt32(out ver); // 4..7 Version
// Read (or skip) string buffer.
int buf;
bits.ReadInt32(out buf); // 8..11 Bytes of Strings
if (sig != 0xeffeeffe || ver != 1) {
throw new PdbDebugException("Unsupported Name Stream version. "+
"(sig={0:x8}, ver={1})",
sig, ver);
}
int beg = bits.Position;
int nxt = bits.Position + buf;
bits.Position = nxt;
// Read hash table.
int siz;
bits.ReadInt32(out siz); // n+0..3 Number of hash buckets.
nxt = bits.Position;
for (int i = 0; i < siz; i++) {
int ni;
string name;
bits.ReadInt32(out ni);
if (ni != 0) {
int saved = bits.Position;
bits.Position = beg + ni;
bits.ReadCString(out name);
bits.Position = saved;
ht.Add(ni, name);
}
}
bits.Position = nxt;
return ht;
}
private static PdbFunction match = new PdbFunction();
private static int FindFunction(PdbFunction[] funcs, ushort sec, uint off) {
match.segment = sec;
match.address = off;
return Array.BinarySearch(funcs, match, PdbFunction.byAddress);
}
static void LoadManagedLines(PdbFunction[] funcs,
IntHashTable names,
BitAccess bits,
MsfDirectory dir,
Dictionary<string, int> nameIndex,
PdbReader reader,
uint limit,
Dictionary<string, PdbSource> sourceCache)
{
Array.Sort(funcs, PdbFunction.byAddressAndToken);
int begin = bits.Position;
IntHashTable checks = ReadSourceFileInfo(bits, limit, names, dir, nameIndex, reader, sourceCache);
// Read the lines next.
bits.Position = begin;
while (bits.Position < limit) {
int sig;
int siz;
bits.ReadInt32(out sig);
bits.ReadInt32(out siz);
int endSym = bits.Position + siz;
switch ((DEBUG_S_SUBSECTION)sig) {
case DEBUG_S_SUBSECTION.LINES: {
CV_LineSection sec;
bits.ReadUInt32(out sec.off);
bits.ReadUInt16(out sec.sec);
bits.ReadUInt16(out sec.flags);
bits.ReadUInt32(out sec.cod);
int funcIndex = FindFunction(funcs, sec.sec, sec.off);
if (funcIndex < 0) break;
var func = funcs[funcIndex];
if (func.lines == null) {
while (funcIndex > 0) {
var f = funcs[funcIndex-1];
if (f.lines != null || f.segment != sec.sec || f.address != sec.off) break;
func = f;
funcIndex--;
}
} else {
while (funcIndex < funcs.Length-1 && func.lines != null) {
var f = funcs[funcIndex+1];
if (f.segment != sec.sec || f.address != sec.off) break;
func = f;
funcIndex++;
}
}
if (func.lines != null) break;
// Count the line blocks.
int begSym = bits.Position;
int blocks = 0;
while (bits.Position < endSym) {
CV_SourceFile file;
bits.ReadUInt32(out file.index);
bits.ReadUInt32(out file.count);
bits.ReadUInt32(out file.linsiz); // Size of payload.
int linsiz = (int)file.count * (8 + ((sec.flags & 1) != 0 ? 4 : 0));
bits.Position += linsiz;
blocks++;
}
func.lines = new PdbLines[blocks];
int block = 0;
bits.Position = begSym;
while (bits.Position < endSym) {
CV_SourceFile file;
bits.ReadUInt32(out file.index);
bits.ReadUInt32(out file.count);
bits.ReadUInt32(out file.linsiz); // Size of payload.
PdbSource src = (PdbSource)checks[(int)file.index];
PdbLines tmp = new PdbLines(src, file.count);
func.lines[block++] = tmp;
PdbLine[] lines = tmp.lines;
int plin = bits.Position;
int pcol = bits.Position + 8 * (int)file.count;
for (int i = 0; i < file.count; i++) {
CV_Line line;
CV_Column column = new CV_Column();
bits.Position = plin + 8 * i;
bits.ReadUInt32(out line.offset);
bits.ReadUInt32(out line.flags);
uint lineBegin = line.flags & (uint)CV_Line_Flags.linenumStart;
uint delta = (line.flags & (uint)CV_Line_Flags.deltaLineEnd) >> 24;
//bool statement = ((line.flags & (uint)CV_Line_Flags.fStatement) == 0);
if ((sec.flags & 1) != 0) {
bits.Position = pcol + 4 * i;
bits.ReadUInt16(out column.offColumnStart);
bits.ReadUInt16(out column.offColumnEnd);
}
lines[i] = new PdbLine(line.offset,
lineBegin,
column.offColumnStart,
lineBegin+delta,
column.offColumnEnd);
}
}
break;
}
}
bits.Position = endSym;
}
}
static void LoadFuncsFromDbiModule(BitAccess bits,
DbiModuleInfo info,
IntHashTable names,
ArrayList funcList,
bool readStrings,
MsfDirectory dir,
Dictionary<string, int> nameIndex,
PdbReader reader,
Dictionary<string, PdbSource> sourceCache)
{
PdbFunction[] funcs = null;
bits.Position = 0;
int sig;
bits.ReadInt32(out sig);
if (sig != 4) {
throw new PdbDebugException("Invalid signature. (sig={0})", sig);
}
bits.Position = 4;
// Console.WriteLine("{0}:", info.moduleName);
funcs = PdbFunction.LoadManagedFunctions(/*info.moduleName,*/
bits, (uint)info.cbSyms,
readStrings);
if (funcs != null) {
bits.Position = info.cbSyms + info.cbOldLines;
LoadManagedLines(funcs, names, bits, dir, nameIndex, reader,
(uint)(info.cbSyms + info.cbOldLines + info.cbLines),
sourceCache);
for (int i = 0; i < funcs.Length; i++) {
funcList.Add(funcs[i]);
}
}
}
static void LoadDbiStream(BitAccess bits,
out DbiModuleInfo[] modules,
out DbiDbgHdr header,
bool readStrings) {
DbiHeader dh = new DbiHeader(bits);
header = new DbiDbgHdr();
//if (dh.sig != -1 || dh.ver != 19990903) {
// throw new PdbException("Unsupported DBI Stream version, sig={0}, ver={1}",
// dh.sig, dh.ver);
//}
// Read gpmod section.
ArrayList modList = new ArrayList();
int end = bits.Position + dh.gpmodiSize;
while (bits.Position < end) {
DbiModuleInfo mod = new DbiModuleInfo(bits, readStrings);
modList.Add(mod);
}
if (bits.Position != end) {
throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}",
bits.Position, end);
}
if (modList.Count > 0) {
modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo));
} else {
modules = null;
}
// Skip the Section Contribution substream.
bits.Position += dh.secconSize;
// Skip the Section Map substream.
bits.Position += dh.secmapSize;
// Skip the File Info substream.
bits.Position += dh.filinfSize;
// Skip the TSM substream.
bits.Position += dh.tsmapSize;
// Skip the EC substream.
bits.Position += dh.ecinfoSize;
// Read the optional header.
end = bits.Position + dh.dbghdrSize;
if (dh.dbghdrSize > 0) {
header = new DbiDbgHdr(bits);
}
bits.Position = end;
}
internal static PdbFunction[] LoadFunctions(Stream read, out Dictionary<uint, PdbTokenLine> tokenToSourceMapping, out string sourceServerData) {
tokenToSourceMapping = new Dictionary<uint, PdbTokenLine>();
BitAccess bits = new BitAccess(512 * 1024);
PdbFileHeader head = new PdbFileHeader(read, bits);
PdbReader reader = new PdbReader(read, head.pageSize);
MsfDirectory dir = new MsfDirectory(reader, head, bits);
DbiModuleInfo[] modules = null;
DbiDbgHdr header;
Dictionary<string, PdbSource> sourceCache = new Dictionary<string, PdbSource>();
dir.streams[1].Read(reader, bits);
Dictionary<string, int> nameIndex = LoadNameIndex(bits);
int nameStream;
if (!nameIndex.TryGetValue("/NAMES", out nameStream)) {
throw new PdbException("No `name' stream");
}
dir.streams[nameStream].Read(reader, bits);
IntHashTable names = LoadNameStream(bits);
int srcsrvStream;
if (!nameIndex.TryGetValue("SRCSRV", out srcsrvStream))
sourceServerData = string.Empty;
else {
DataStream dataStream = dir.streams[srcsrvStream];
byte[] bytes = new byte[dataStream.contentSize];
dataStream.Read(reader, bits);
sourceServerData = bits.ReadBString(bytes.Length);
}
dir.streams[3].Read(reader, bits);
LoadDbiStream(bits, out modules, out header, true);
ArrayList funcList = new ArrayList();
if (modules != null) {
for (int m = 0; m < modules.Length; m++) {
var module = modules[m];
if (module.stream > 0) {
dir.streams[module.stream].Read(reader, bits);
if (module.moduleName == "TokenSourceLineInfo") {
LoadTokenToSourceInfo(bits, module, names, dir, nameIndex, reader, tokenToSourceMapping, sourceCache);
continue;
}
LoadFuncsFromDbiModule(bits, module, names, funcList, true, dir, nameIndex, reader, sourceCache);
}
}
}
PdbFunction[] funcs = (PdbFunction[])funcList.ToArray(typeof(PdbFunction));
// After reading the functions, apply the token remapping table if it exists.
if (header.snTokenRidMap != 0 && header.snTokenRidMap != 0xffff) {
dir.streams[header.snTokenRidMap].Read(reader, bits);
uint[] ridMap = new uint[dir.streams[header.snTokenRidMap].Length / 4];
bits.ReadUInt32(ridMap);
foreach (PdbFunction func in funcs) {
func.token = 0x06000000 | ridMap[func.token & 0xffffff];
}
}
//
Array.Sort(funcs, PdbFunction.byAddressAndToken);
//Array.Sort(funcs, PdbFunction.byToken);
return funcs;
}
private static void LoadTokenToSourceInfo(BitAccess bits, DbiModuleInfo module, IntHashTable names, MsfDirectory dir,
Dictionary<string, int> nameIndex, PdbReader reader, Dictionary<uint, PdbTokenLine> tokenToSourceMapping, Dictionary<string,PdbSource> sourceCache) {
bits.Position = 0;
int sig;
bits.ReadInt32(out sig);
if (sig != 4) {
throw new PdbDebugException("Invalid signature. (sig={0})", sig);
}
bits.Position = 4;
while (bits.Position < module.cbSyms) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.Position = star;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_OEM:
OemSymbol oem;
bits.ReadGuid(out oem.idOem);
bits.ReadUInt32(out oem.typind);
// internal byte[] rgl; // user data, force 4-byte alignment
if (oem.idOem == PdbFunction.msilMetaData) {
string name = bits.ReadString();
if (name == "TSLI") {
uint token;
uint file_id;
uint line;
uint column;
uint endLine;
uint endColumn;
bits.ReadUInt32(out token);
bits.ReadUInt32(out file_id);
bits.ReadUInt32(out line);
bits.ReadUInt32(out column);
bits.ReadUInt32(out endLine);
bits.ReadUInt32(out endColumn);
PdbTokenLine tokenLine;
if (!tokenToSourceMapping.TryGetValue(token, out tokenLine))
tokenToSourceMapping.Add(token, new PdbTokenLine(token, file_id, line, column, endLine, endColumn));
else {
while (tokenLine.nextLine != null) tokenLine = tokenLine.nextLine;
tokenLine.nextLine = new PdbTokenLine(token, file_id, line, column, endLine, endColumn);
}
}
bits.Position = stop;
break;
} else {
throw new PdbDebugException("OEM section: guid={0} ti={1}",
oem.idOem, oem.typind);
// bits.Position = stop;
}
case SYM.S_END:
bits.Position = stop;
break;
default:
//Console.WriteLine("{0,6}: {1:x2} {2}",
// bits.Position, rec, (SYM)rec);
bits.Position = stop;
break;
}
}
bits.Position = module.cbSyms + module.cbOldLines;
int limit = module.cbSyms + module.cbOldLines + module.cbLines;
IntHashTable sourceFiles = ReadSourceFileInfo(bits, (uint)limit, names, dir, nameIndex, reader, sourceCache);
foreach (var tokenLine in tokenToSourceMapping.Values) {
tokenLine.sourceFile = (PdbSource)sourceFiles[(int)tokenLine.file_id];
}
}
private static IntHashTable ReadSourceFileInfo(BitAccess bits, uint limit, IntHashTable names, MsfDirectory dir,
Dictionary<string, int> nameIndex, PdbReader reader, Dictionary<string, PdbSource> sourceCache)
{
IntHashTable checks = new IntHashTable();
int begin = bits.Position;
while (bits.Position < limit) {
int sig;
int siz;
bits.ReadInt32(out sig);
bits.ReadInt32(out siz);
int place = bits.Position;
int endSym = bits.Position + siz;
switch ((DEBUG_S_SUBSECTION)sig) {
case DEBUG_S_SUBSECTION.FILECHKSMS:
while (bits.Position < endSym) {
CV_FileCheckSum chk;
int ni = bits.Position - place;
bits.ReadUInt32(out chk.name);
bits.ReadUInt8(out chk.len);
bits.ReadUInt8(out chk.type);
string name = (string)names[(int)chk.name];
PdbSource src;
if (!sourceCache.TryGetValue(name, out src))
{
int guidStream;
Guid doctypeGuid = SymDocumentType.Text;
Guid languageGuid = Guid.Empty;
Guid vendorGuid = Guid.Empty;
if (nameIndex.TryGetValue("/SRC/FILES/" + name.ToUpperInvariant(), out guidStream))
{
var guidBits = new BitAccess(0x100);
dir.streams[guidStream].Read(reader, guidBits);
LoadGuidStream(guidBits, out doctypeGuid, out languageGuid, out vendorGuid);
}
src = new PdbSource(/*(uint)ni,*/ name, doctypeGuid, languageGuid, vendorGuid);
sourceCache.Add(name, src);
}
checks.Add(ni, src);
bits.Position += chk.len;
bits.Align(4);
}
bits.Position = endSym;
break;
default:
bits.Position = endSym;
break;
}
}
return checks;
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
using System.Text;
namespace Microsoft.Cci.Pdb {
internal class PdbFileHeader {
//internal PdbFileHeader(int pageSize) {
// this.magic = new byte[32] {
// 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, // "Microsof"
// 0x74, 0x20, 0x43, 0x2F, 0x43, 0x2B, 0x2B, 0x20, // "t C/C++ "
// 0x4D, 0x53, 0x46, 0x20, 0x37, 0x2E, 0x30, 0x30, // "MSF 7.00"
// 0x0D, 0x0A, 0x1A, 0x44, 0x53, 0x00, 0x00, 0x00 // "^^^DS^^^"
// };
// this.pageSize = pageSize;
//}
internal PdbFileHeader(Stream reader, BitAccess bits) {
bits.MinCapacity(56);
reader.Seek(0, SeekOrigin.Begin);
bits.FillBuffer(reader, 52);
this.magic = new byte[32];
bits.ReadBytes(this.magic); // 0..31
bits.ReadInt32(out this.pageSize); // 32..35
bits.ReadInt32(out this.freePageMap); // 36..39
bits.ReadInt32(out this.pagesUsed); // 40..43
bits.ReadInt32(out this.directorySize); // 44..47
bits.ReadInt32(out this.zero); // 48..51
int directoryPages = ((((directorySize + pageSize - 1) / pageSize) * 4) + pageSize - 1) / pageSize;
this.directoryRoot = new int[directoryPages];
bits.FillBuffer(reader, directoryPages * 4);
bits.ReadInt32(this.directoryRoot);
}
//internal string Magic {
// get { return StringFromBytesUTF8(magic); }
//}
//internal void Write(Stream writer, BitAccess bits) {
// bits.MinCapacity(pageSize);
// bits.WriteBytes(magic); // 0..31
// bits.WriteInt32(pageSize); // 32..35
// bits.WriteInt32(freePageMap); // 36..39
// bits.WriteInt32(pagesUsed); // 40..43
// bits.WriteInt32(directorySize); // 44..47
// bits.WriteInt32(zero); // 48..51
// bits.WriteInt32(directoryRoot); // 52..55
// writer.Seek(0, SeekOrigin.Begin);
// bits.WriteBuffer(writer, pageSize);
//}
//////////////////////////////////////////////////// Helper Functions.
//
//internal static string StringFromBytesUTF8(byte[] bytes) {
// return StringFromBytesUTF8(bytes, 0, bytes.Length);
//}
//internal static string StringFromBytesUTF8(byte[] bytes, int offset, int length) {
// for (int i = 0; i < length; i++) {
// if (bytes[offset + i] < ' ') {
// length = i;
// }
// }
// return Encoding.UTF8.GetString(bytes, offset, length);
//}
////////////////////////////////////////////////////////////// Fields.
//
internal readonly byte[] magic;
internal readonly int pageSize;
internal int freePageMap;
internal int pagesUsed;
internal int directorySize;
internal readonly int zero;
internal int[] directoryRoot;
}
}

Просмотреть файл

@ -0,0 +1,520 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.Cci.Pdb {
internal class PdbFunction {
static internal readonly Guid msilMetaData = new Guid(0xc6ea3fc9, 0x59b3, 0x49d6, 0xbc, 0x25,
0x09, 0x02, 0xbb, 0xab, 0xb4, 0x60);
static internal readonly IComparer byAddress = new PdbFunctionsByAddress();
static internal readonly IComparer byAddressAndToken = new PdbFunctionsByAddressAndToken();
//static internal readonly IComparer byToken = new PdbFunctionsByToken();
internal uint token;
internal uint slotToken;
internal uint tokenOfMethodWhoseUsingInfoAppliesToThisMethod;
//internal string name;
//internal string module;
//internal ushort flags;
internal uint segment;
internal uint address;
//internal uint length;
//internal byte[] metadata;
internal PdbScope[] scopes;
internal PdbSlot[] slots;
internal PdbConstant[] constants;
internal string[] usedNamespaces;
internal PdbLines[] lines;
internal ushort[]/*?*/ usingCounts;
internal IEnumerable<INamespaceScope>/*?*/ namespaceScopes;
internal string/*?*/ iteratorClass;
internal List<ILocalScope>/*?*/ iteratorScopes;
internal PdbSynchronizationInformation/*?*/ synchronizationInformation;
private static string StripNamespace(string module) {
int li = module.LastIndexOf('.');
if (li > 0) {
return module.Substring(li + 1);
}
return module;
}
internal static PdbFunction[] LoadManagedFunctions(/*string module,*/
BitAccess bits, uint limit,
bool readStrings) {
//string mod = StripNamespace(module);
int begin = bits.Position;
int count = 0;
while (bits.Position < limit) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.Position = star;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_GMANPROC:
case SYM.S_LMANPROC:
ManProcSym proc;
bits.ReadUInt32(out proc.parent);
bits.ReadUInt32(out proc.end);
bits.Position = (int)proc.end;
count++;
break;
case SYM.S_END:
bits.Position = stop;
break;
default:
//Console.WriteLine("{0,6}: {1:x2} {2}",
// bits.Position, rec, (SYM)rec);
bits.Position = stop;
break;
}
}
if (count == 0) {
return null;
}
bits.Position = begin;
PdbFunction[] funcs = new PdbFunction[count];
int func = 0;
while (bits.Position < limit) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_GMANPROC:
case SYM.S_LMANPROC:
ManProcSym proc;
//int offset = bits.Position;
bits.ReadUInt32(out proc.parent);
bits.ReadUInt32(out proc.end);
bits.ReadUInt32(out proc.next);
bits.ReadUInt32(out proc.len);
bits.ReadUInt32(out proc.dbgStart);
bits.ReadUInt32(out proc.dbgEnd);
bits.ReadUInt32(out proc.token);
bits.ReadUInt32(out proc.off);
bits.ReadUInt16(out proc.seg);
bits.ReadUInt8(out proc.flags);
bits.ReadUInt16(out proc.retReg);
if (readStrings) {
bits.ReadCString(out proc.name);
} else {
bits.SkipCString(out proc.name);
}
//Console.WriteLine("token={0:X8} [{1}::{2}]", proc.token, module, proc.name);
bits.Position = stop;
funcs[func++] = new PdbFunction(/*module,*/ proc, bits);
break;
default: {
//throw new PdbDebugException("Unknown SYMREC {0}", (SYM)rec);
bits.Position = stop;
break;
}
}
}
return funcs;
}
internal static void CountScopesAndSlots(BitAccess bits, uint limit,
out int constants, out int scopes, out int slots, out int usedNamespaces) {
int pos = bits.Position;
BlockSym32 block;
constants = 0;
slots = 0;
scopes = 0;
usedNamespaces = 0;
while (bits.Position < limit) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.Position = star;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_BLOCK32: {
bits.ReadUInt32(out block.parent);
bits.ReadUInt32(out block.end);
scopes++;
bits.Position = (int)block.end;
break;
}
case SYM.S_MANSLOT:
slots++;
bits.Position = stop;
break;
case SYM.S_UNAMESPACE:
usedNamespaces++;
bits.Position = stop;
break;
case SYM.S_MANCONSTANT:
constants++;
bits.Position = stop;
break;
default:
bits.Position = stop;
break;
}
}
bits.Position = pos;
}
internal PdbFunction() {
}
internal PdbFunction(/*string module, */ManProcSym proc, BitAccess bits) {
this.token = proc.token;
//this.module = module;
//this.name = proc.name;
//this.flags = proc.flags;
this.segment = proc.seg;
this.address = proc.off;
//this.length = proc.len;
if (proc.seg != 1) {
throw new PdbDebugException("Segment is {0}, not 1.", proc.seg);
}
if (proc.parent != 0 || proc.next != 0) {
throw new PdbDebugException("Warning parent={0}, next={1}",
proc.parent, proc.next);
}
//if (proc.dbgStart != 0 || proc.dbgEnd != 0) {
// throw new PdbDebugException("Warning DBG start={0}, end={1}",
// proc.dbgStart, proc.dbgEnd);
//}
int constantCount;
int scopeCount;
int slotCount;
int usedNamespacesCount;
CountScopesAndSlots(bits, proc.end, out constantCount, out scopeCount, out slotCount, out usedNamespacesCount);
int scope = constantCount > 0 || slotCount > 0 || usedNamespacesCount > 0 ? 1 : 0;
int slot = 0;
int constant = 0;
int usedNs = 0;
scopes = new PdbScope[scopeCount+scope];
slots = new PdbSlot[slotCount];
constants = new PdbConstant[constantCount];
usedNamespaces = new string[usedNamespacesCount];
if (scope > 0)
scopes[0] = new PdbScope(this.address, proc.len, slots, constants, usedNamespaces);
while (bits.Position < proc.end) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.Position = star;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_OEM: { // 0x0404
OemSymbol oem;
bits.ReadGuid(out oem.idOem);
bits.ReadUInt32(out oem.typind);
// internal byte[] rgl; // user data, force 4-byte alignment
if (oem.idOem == msilMetaData) {
string name = bits.ReadString();
if (name == "MD2") {
byte version;
bits.ReadUInt8(out version);
if (version == 4) {
byte count;
bits.ReadUInt8(out count);
bits.Align(4);
while (count-- > 0)
this.ReadCustomMetadata(bits);
}
} else if (name == "asyncMethodInfo") {
this.synchronizationInformation = new PdbSynchronizationInformation(bits);
}
bits.Position = stop;
break;
} else {
throw new PdbDebugException("OEM section: guid={0} ti={1}",
oem.idOem, oem.typind);
// bits.Position = stop;
}
}
case SYM.S_BLOCK32: {
BlockSym32 block = new BlockSym32();
bits.ReadUInt32(out block.parent);
bits.ReadUInt32(out block.end);
bits.ReadUInt32(out block.len);
bits.ReadUInt32(out block.off);
bits.ReadUInt16(out block.seg);
bits.SkipCString(out block.name);
bits.Position = stop;
scopes[scope++] = new PdbScope(this.address, block, bits, out slotToken);
bits.Position = (int)block.end;
break;
}
case SYM.S_MANSLOT:
slots[slot++] = new PdbSlot(bits);
bits.Position = stop;
break;
case SYM.S_MANCONSTANT:
constants[constant++] = new PdbConstant(bits);
bits.Position = stop;
break;
case SYM.S_UNAMESPACE:
bits.ReadCString(out usedNamespaces[usedNs++]);
bits.Position = stop;
break;
case SYM.S_END:
bits.Position = stop;
break;
default: {
//throw new PdbDebugException("Unknown SYM: {0}", (SYM)rec);
bits.Position = stop;
break;
}
}
}
if (bits.Position != proc.end) {
throw new PdbDebugException("Not at S_END");
}
ushort esiz;
ushort erec;
bits.ReadUInt16(out esiz);
bits.ReadUInt16(out erec);
if (erec != (ushort)SYM.S_END) {
throw new PdbDebugException("Missing S_END");
}
}
private void ReadCustomMetadata(BitAccess bits)
{
int savedPosition = bits.Position;
byte version;
bits.ReadUInt8(out version);
byte kind;
bits.ReadUInt8(out kind);
bits.Align(4);
uint numberOfBytesInItem;
bits.ReadUInt32(out numberOfBytesInItem);
if (version == 4)
{
switch (kind)
{
case 0: this.ReadUsingInfo(bits); break;
case 1: this.ReadForwardInfo(bits); break;
case 2: break; // this.ReadForwardedToModuleInfo(bits); break;
case 3: this.ReadIteratorLocals(bits); break;
case 4: this.ReadForwardIterator(bits); break;
}
}
bits.Position = savedPosition + (int)numberOfBytesInItem;
}
private void ReadForwardIterator(BitAccess bits) {
this.iteratorClass = bits.ReadString();
}
private void ReadIteratorLocals(BitAccess bits) {
uint numberOfLocals;
bits.ReadUInt32(out numberOfLocals);
this.iteratorScopes = new List<ILocalScope>((int)numberOfLocals);
while (numberOfLocals-- > 0) {
uint ilStartOffset;
uint ilEndOffset;
bits.ReadUInt32(out ilStartOffset);
bits.ReadUInt32(out ilEndOffset);
this.iteratorScopes.Add(new PdbIteratorScope(ilStartOffset, ilEndOffset-ilStartOffset));
}
}
//private void ReadForwardedToModuleInfo(BitAccess bits) {
//}
private void ReadForwardInfo(BitAccess bits) {
bits.ReadUInt32(out this.tokenOfMethodWhoseUsingInfoAppliesToThisMethod);
}
private void ReadUsingInfo(BitAccess bits) {
ushort numberOfNamespaces;
bits.ReadUInt16(out numberOfNamespaces);
this.usingCounts = new ushort[numberOfNamespaces];
for (ushort i = 0; i < numberOfNamespaces; i++) {
bits.ReadUInt16(out this.usingCounts[i]);
}
}
internal class PdbFunctionsByAddress : IComparer {
public int Compare(Object x, Object y) {
PdbFunction fx = (PdbFunction)x;
PdbFunction fy = (PdbFunction)y;
if (fx.segment < fy.segment) {
return -1;
} else if (fx.segment > fy.segment) {
return 1;
} else if (fx.address < fy.address) {
return -1;
} else if (fx.address > fy.address) {
return 1;
} else {
return 0;
}
}
}
internal class PdbFunctionsByAddressAndToken : IComparer {
public int Compare(Object x, Object y) {
PdbFunction fx = (PdbFunction)x;
PdbFunction fy = (PdbFunction)y;
if (fx.segment < fy.segment) {
return -1;
} else if (fx.segment > fy.segment) {
return 1;
} else if (fx.address < fy.address) {
return -1;
} else if (fx.address > fy.address) {
return 1;
} else {
if (fx.token < fy.token)
return -1;
else if (fx.token > fy.token)
return 1;
else
return 0;
}
}
}
//internal class PdbFunctionsByToken : IComparer {
// public int Compare(Object x, Object y) {
// PdbFunction fx = (PdbFunction)x;
// PdbFunction fy = (PdbFunction)y;
// if (fx.token < fy.token) {
// return -1;
// } else if (fx.token > fy.token) {
// return 1;
// } else {
// return 0;
// }
// }
//}
}
internal class PdbSynchronizationInformation : ISynchronizationInformation {
internal uint kickoffMethodToken;
internal IMethodDefinition asyncMethod;
internal IMethodDefinition moveNextMethod;
internal uint generatedCatchHandlerIlOffset;
internal PdbSynchronizationPoint[] synchronizationPoints;
internal PdbSynchronizationInformation(BitAccess bits) {
uint asyncStepInfoCount;
bits.ReadUInt32(out this.kickoffMethodToken);
bits.ReadUInt32(out this.generatedCatchHandlerIlOffset);
bits.ReadUInt32(out asyncStepInfoCount);
this.synchronizationPoints = new PdbSynchronizationPoint[asyncStepInfoCount];
for (uint i = 0; i < asyncStepInfoCount; i += 1) {
this.synchronizationPoints[i] = new PdbSynchronizationPoint(bits);
}
this.asyncMethod = Dummy.MethodDefinition;
this.moveNextMethod = Dummy.MethodDefinition;
}
public IMethodDefinition AsyncMethod {
get { return this.asyncMethod; }
}
public IMethodDefinition MoveNextMethod {
get { return this.moveNextMethod; }
}
public uint GeneratedCatchHandlerOffset {
get { return this.generatedCatchHandlerIlOffset; }
}
public IEnumerable<ISynchronizationPoint> SynchronizationPoints {
get { return IteratorHelper.GetConversionEnumerable<PdbSynchronizationPoint, ISynchronizationPoint>(this.synchronizationPoints); }
}
}
internal class PdbSynchronizationPoint : ISynchronizationPoint {
internal uint synchronizeOffset;
internal uint continuationMethodToken;
internal IMethodDefinition/*?*/ continuationMethod;
internal uint continuationOffset;
internal PdbSynchronizationPoint(BitAccess bits) {
bits.ReadUInt32(out this.synchronizeOffset);
bits.ReadUInt32(out this.continuationMethodToken);
bits.ReadUInt32(out this.continuationOffset);
}
public uint SynchronizeOffset {
get { return this.synchronizeOffset; }
}
public IMethodDefinition/*?*/ ContinuationMethod {
get { return this.continuationMethod; }
}
public uint ContinuationOffset {
get { return this.continuationOffset; }
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal struct PdbLine {
internal uint offset;
internal uint lineBegin;
internal uint lineEnd;
internal ushort colBegin;
internal ushort colEnd;
internal PdbLine(uint offset, uint lineBegin, ushort colBegin, uint lineEnd, ushort colEnd) {
this.offset = offset;
this.lineBegin = lineBegin;
this.colBegin = colBegin;
this.lineEnd = lineEnd;
this.colEnd = colEnd;
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class PdbLines {
internal PdbSource file;
internal PdbLine[] lines;
internal PdbLines(PdbSource file, uint count) {
this.file = file;
this.lines = new PdbLine[count];
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
namespace Microsoft.Cci.Pdb {
internal class PdbReader {
internal PdbReader(Stream reader, int pageSize) {
this.pageSize = pageSize;
this.reader = reader;
}
internal void Seek(int page, int offset) {
reader.Seek(page * pageSize + offset, SeekOrigin.Begin);
}
internal void Read(byte[] bytes, int offset, int count) {
reader.Read(bytes, offset, count);
}
internal int PagesFromSize(int size) {
return (size + pageSize - 1) / (pageSize);
}
//internal int PageSize {
// get { return pageSize; }
//}
internal readonly int pageSize;
internal readonly Stream reader;
}
}

Просмотреть файл

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A6A31B03-7C3D-4DE6-AA73-BE88116BC40A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Cci.Pdb</RootNamespace>
<AssemblyName>Microsoft.Cci.PdbReader</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<SignAssembly>true</SignAssembly>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>649</NoWarn>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<DocumentationFile>bin\Debug\Microsoft.Cci.PdbReader.XML</DocumentationFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyOriginatorKeyFile>..\Common\InterimKey.snk</AssemblyOriginatorKeyFile>
<NoWarn>649</NoWarn>
<DocumentationFile>bin\Release\Microsoft.Cci.PdbReader.XML</DocumentationFile>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\common\include\version.cs">
<Link>Build\version.cs</Link>
</Compile>
<Compile Include="BitAccess.cs" />
<Compile Include="BitSet.cs" />
<Compile Include="CvInfo.cs" />
<Compile Include="DataStream.cs" />
<Compile Include="DbiDbgHdr.cs" />
<Compile Include="DbiHeader.cs" />
<Compile Include="DbiModuleInfo.cs" />
<Compile Include="DbiSecCon.cs" />
<Compile Include="IntHashTable.cs" />
<Compile Include="MsfDirectory.cs" />
<Compile Include="PdbConstant.cs" />
<Compile Include="PdbDebugException.cs" />
<Compile Include="PdbException.cs" />
<Compile Include="PdbFile.cs" />
<Compile Include="PdbFileHeader.cs" />
<Compile Include="PdbFunction.cs" />
<Compile Include="PdbLine.cs" />
<Compile Include="PdbLines.cs" />
<Compile Include="PdbReader.cs" />
<Compile Include="PdbScope.cs" />
<Compile Include="PdbSlot.cs" />
<Compile Include="PdbSource.cs" />
<Compile Include="PdbTokenLine.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SourceLocationProvider.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MetadataModel\MetadataModel.csproj">
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
<Name>MetadataModel</Name>
</ProjectReference>
<ProjectReference Include="..\PeReader\PeReader.csproj">
<Project>{34B9A0CE-DF18-4CBC-8F7A-90C2B74338D5}</Project>
<Name>PeReader</Name>
</ProjectReference>
<ProjectReference Include="..\SourceModel\SourceModel.csproj">
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
<Name>SourceModel</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,122 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class PdbScope {
internal PdbConstant[] constants;
internal PdbSlot[] slots;
internal PdbScope[] scopes;
internal string[] usedNamespaces;
//internal uint segment;
internal uint address;
internal uint offset;
internal uint length;
internal PdbScope(uint address, uint length, PdbSlot[] slots, PdbConstant[] constants, string[] usedNamespaces) {
this.constants = constants;
this.slots = slots;
this.scopes = new PdbScope[0];
this.usedNamespaces = usedNamespaces;
this.address = address;
this.offset = 0;
this.length = length;
}
internal PdbScope(uint funcOffset, BlockSym32 block, BitAccess bits, out uint typind) {
//this.segment = block.seg;
this.address = block.off;
this.offset = block.off - funcOffset;
this.length = block.len;
typind = 0;
int constantCount;
int scopeCount;
int slotCount;
int namespaceCount;
PdbFunction.CountScopesAndSlots(bits, block.end, out constantCount, out scopeCount, out slotCount, out namespaceCount);
constants = new PdbConstant[constantCount];
scopes = new PdbScope[scopeCount];
slots = new PdbSlot[slotCount];
usedNamespaces = new string[namespaceCount];
int constant = 0;
int scope = 0;
int slot = 0;
int usedNs = 0;
while (bits.Position < block.end) {
ushort siz;
ushort rec;
bits.ReadUInt16(out siz);
int star = bits.Position;
int stop = bits.Position + siz;
bits.Position = star;
bits.ReadUInt16(out rec);
switch ((SYM)rec) {
case SYM.S_BLOCK32: {
BlockSym32 sub = new BlockSym32();
bits.ReadUInt32(out sub.parent);
bits.ReadUInt32(out sub.end);
bits.ReadUInt32(out sub.len);
bits.ReadUInt32(out sub.off);
bits.ReadUInt16(out sub.seg);
bits.SkipCString(out sub.name);
bits.Position = stop;
scopes[scope++] = new PdbScope(funcOffset, sub, bits, out typind);
break;
}
case SYM.S_MANSLOT:
slots[slot++] = new PdbSlot(bits);
bits.Position = stop;
break;
case SYM.S_UNAMESPACE:
bits.ReadCString(out usedNamespaces[usedNs++]);
bits.Position = stop;
break;
case SYM.S_END:
bits.Position = stop;
break;
case SYM.S_MANCONSTANT:
constants[constant++] = new PdbConstant(bits);
bits.Position = stop;
break;
default:
//throw new PdbException("Unknown SYM in scope {0}", (SYM)rec);
bits.Position = stop;
break;
}
}
if (bits.Position != block.end) {
throw new Exception("Not at S_END");
}
ushort esiz;
ushort erec;
bits.ReadUInt16(out esiz);
bits.ReadUInt16(out erec);
if (erec != (ushort)SYM.S_END) {
throw new Exception("Missing S_END");
}
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class PdbSlot {
internal uint slot;
internal uint typeToken;
internal string name;
internal ushort flags;
//internal uint segment;
//internal uint address;
internal PdbSlot(BitAccess bits) {
AttrSlotSym slot;
bits.ReadUInt32(out slot.index);
bits.ReadUInt32(out slot.typind);
bits.ReadUInt32(out slot.offCod);
bits.ReadUInt16(out slot.segCod);
bits.ReadUInt16(out slot.flags);
bits.ReadCString(out slot.name);
this.slot = slot.index;
this.typeToken = slot.typind;
this.name = slot.name;
this.flags = slot.flags;
//this.segment = slot.segCod;
//this.address = slot.offCod;
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Microsoft Public License.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//-----------------------------------------------------------------------------
using System;
namespace Microsoft.Cci.Pdb {
internal class PdbSource {
//internal uint index;
internal string name;
internal Guid doctype;
internal Guid language;
internal Guid vendor;
internal PdbSource(/*uint index, */string name, Guid doctype, Guid language, Guid vendor) {
//this.index = index;
this.name = name;
this.doctype = doctype;
this.language = language;
this.vendor = vendor;
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше