Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,12 @@
//------------------------------------------------------------------------------
// <copyright file="Assembly.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">sdub</owner>
//------------------------------------------------------------------------------
using System.Runtime.CompilerServices;
// Hard bind to System.Xml
[assembly: Dependency("System.Xml,", LoadHint.Always)]
[assembly: InternalsVisibleTo("System.Xml, PublicKey=00000000000000000400000000000000")]

View File

@@ -0,0 +1,15 @@
//------------------------------------------------------------------------------
// <copyright file="ISourceLineInfo.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">sdub</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl {
internal interface ISourceLineInfo {
string Uri { get; }
bool IsNoSource { get; }
Location Start { get; }
Location End { get; }
}
}

View File

@@ -0,0 +1,262 @@
//------------------------------------------------------------------------------
// <copyright file="OptimizerPatterns.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.IlGen {
internal enum OptimizerPatternName {
None,
DodReverse, // (Dod $reverse-axis:*)
EqualityIndex, // ILGen will build an equality index when this pattern is recognized
FilterAttributeKind, // (Filter $iter:(Content *) (IsType $iter Attribute))
FilterContentKind, // (Filter $iter:* (IsType $iter $kind:*))
FilterElements, // (Filter $iter:* (And (IsType $iter Element) (NameOf $iter (LiteralQName * * *))))
IsDocOrderDistinct, // True if the annotated expression always returns nodes in document order, with no duplicates
IsPositional, // True if the annotated iterator should track current position during iteration
JoinAndDod, // (Dod (Loop $path1:* $path2:*)), where $path2.ContextNode = $path1
MaxPosition, // True if the position range of the annoted iterator or length expression has a maximum
SameDepth, // True if the annotated expression always returns nodes at the same depth in the tree
Step, // True if the annotated expression returns nodes from one of the simple axis operators, or from a union of Content operators
SingleTextRtf, // (RtfCtor (TextCtor *) *)
Axis, // (AnyAxis *)
MaybeSideEffects, // True if annotated expression might have side effects
TailCall, // (Invoke * *) True if invocation can be compiled as using .tailcall
DodMerge, // (Dod (Loop * (Invoke * *))), where invoked function returns nodes in document order
IsReferenced, // True if the annotated global iterator is referenced at least once
}
internal enum OptimizerPatternArgument {
StepNode = 0, // Step, QilNode: The QilNode of the inner step expression (Content, DescendantOrSelf, XPathFollowing, Union, etc.)
StepInput = 1, // Step, QilNode: The expression from which navigation begins
ElementQName = 2, // FilterElements, QilLiteral: All but elements of this QName are filtered by FilterElements expression
KindTestType = 2, // FilterContentKind, XmlType: All but nodes of this XmlType are filtered by FilterContentKind expression
IndexedNodes = 0, // EqualityIndex, QilNode: Expression that returns the nodes to be indexed
KeyExpression = 1, // EqualityIndex, QilNode: Expression that returns the keys for the index
DodStep = 2, // JoinAndDod | DodReverse, QilNode: Last step in a JoinAndDod expression, or only step in DodReverse expression
MaxPosition = 2, // MaxPosition, int: Maximum position of the annotated iterator or length expression
RtfText = 2, // SingleTextRtf, QilNode: Expression that constructs the text of the simple text Rtf
}
/// <summary>
/// As the Qil graph is traversed, patterns are identified. Subtrees that match these patterns are
/// annotated with this class, which identifies the matching patterns and their arguments.
/// </summary>
internal class OptimizerPatterns : IQilAnnotation {
private static readonly int PatternCount = Enum.GetValues(typeof(OptimizerPatternName)).Length;
private int patterns; // Set of patterns that the annotated Qil node and its subtree matches
private bool isReadOnly; // True if setters are disabled in the case of singleton OptimizerPatterns
private object arg0, arg1, arg2; // Arguments to the matching patterns
private static volatile OptimizerPatterns ZeroOrOneDefault;
private static volatile OptimizerPatterns MaybeManyDefault;
private static volatile OptimizerPatterns DodDefault;
/// <summary>
/// Get OptimizerPatterns annotation for the specified node. Lazily create if necessary.
/// </summary>
public static OptimizerPatterns Read(QilNode nd) {
XmlILAnnotation ann = nd.Annotation as XmlILAnnotation;
OptimizerPatterns optPatt = (ann != null) ? ann.Patterns : null;
if (optPatt == null) {
if (!nd.XmlType.MaybeMany) {
// Expressions with ZeroOrOne cardinality should always report IsDocOrderDistinct and NoContainedNodes
if (ZeroOrOneDefault == null) {
optPatt = new OptimizerPatterns();
optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
optPatt.AddPattern(OptimizerPatternName.SameDepth);
optPatt.isReadOnly = true;
ZeroOrOneDefault = optPatt;
}
else {
optPatt = ZeroOrOneDefault;
}
}
else if (nd.XmlType.IsDod) {
if (DodDefault == null) {
optPatt = new OptimizerPatterns();
optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
optPatt.isReadOnly = true;
DodDefault = optPatt;
}
else {
optPatt = DodDefault;
}
}
else {
if (MaybeManyDefault == null) {
optPatt = new OptimizerPatterns();
optPatt.isReadOnly = true;
MaybeManyDefault = optPatt;
}
else {
optPatt = MaybeManyDefault;
}
}
}
return optPatt;
}
/// <summary>
/// Create and initialize OptimizerPatterns annotation for the specified node.
/// </summary>
public static OptimizerPatterns Write(QilNode nd) {
XmlILAnnotation ann = XmlILAnnotation.Write(nd);
OptimizerPatterns optPatt = ann.Patterns;
if (optPatt == null || optPatt.isReadOnly) {
optPatt = new OptimizerPatterns();
ann.Patterns = optPatt;
if (!nd.XmlType.MaybeMany) {
optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
optPatt.AddPattern(OptimizerPatternName.SameDepth);
}
else if (nd.XmlType.IsDod) {
optPatt.AddPattern(OptimizerPatternName.IsDocOrderDistinct);
}
}
return optPatt;
}
/// <summary>
/// Create and initialize OptimizerPatterns annotation for the specified node.
/// </summary>
public static void Inherit(QilNode ndSrc, QilNode ndDst, OptimizerPatternName pattern) {
OptimizerPatterns annSrc = OptimizerPatterns.Read(ndSrc);
if (annSrc.MatchesPattern(pattern)) {
OptimizerPatterns annDst = OptimizerPatterns.Write(ndDst);
annDst.AddPattern(pattern);
// Inherit pattern arguments
switch (pattern) {
case OptimizerPatternName.Step:
annDst.AddArgument(OptimizerPatternArgument.StepNode, annSrc.GetArgument(OptimizerPatternArgument.StepNode));
annDst.AddArgument(OptimizerPatternArgument.StepInput, annSrc.GetArgument(OptimizerPatternArgument.StepInput));
break;
case OptimizerPatternName.FilterElements:
annDst.AddArgument(OptimizerPatternArgument.ElementQName, annSrc.GetArgument(OptimizerPatternArgument.ElementQName));
break;
case OptimizerPatternName.FilterContentKind:
annDst.AddArgument(OptimizerPatternArgument.KindTestType, annSrc.GetArgument(OptimizerPatternArgument.KindTestType));
break;
case OptimizerPatternName.EqualityIndex:
annDst.AddArgument(OptimizerPatternArgument.IndexedNodes, annSrc.GetArgument(OptimizerPatternArgument.IndexedNodes));
annDst.AddArgument(OptimizerPatternArgument.KeyExpression, annSrc.GetArgument(OptimizerPatternArgument.KeyExpression));
break;
case OptimizerPatternName.DodReverse:
case OptimizerPatternName.JoinAndDod:
annDst.AddArgument(OptimizerPatternArgument.DodStep, annSrc.GetArgument(OptimizerPatternArgument.DodStep));
break;
case OptimizerPatternName.MaxPosition:
annDst.AddArgument(OptimizerPatternArgument.MaxPosition, annSrc.GetArgument(OptimizerPatternArgument.MaxPosition));
break;
case OptimizerPatternName.SingleTextRtf:
annDst.AddArgument(OptimizerPatternArgument.RtfText, annSrc.GetArgument(OptimizerPatternArgument.RtfText));
break;
}
}
}
/// <summary>
/// Add an argument to one of the matching patterns.
/// </summary>
public void AddArgument(OptimizerPatternArgument argId, object arg) {
Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");
switch ((int) argId) {
case 0: this.arg0 = arg; break;
case 1: this.arg1 = arg; break;
case 2: this.arg2 = arg; break;
default:
Debug.Assert(false, "Cannot handle more than 2 arguments.");
break;
}
}
/// <summary>
/// Get an argument of one of the matching patterns.
/// </summary>
public object GetArgument(OptimizerPatternArgument argNum) {
object arg = null;
switch ((int) argNum) {
case 0: arg = this.arg0; break;
case 1: arg = this.arg1; break;
case 2: arg = this.arg2; break;
}
Debug.Assert(arg != null, "There is no '" + argNum + "' argument.");
return arg;
}
/// <summary>
/// Add a pattern to the list of patterns that the annotated node matches.
/// </summary>
public void AddPattern(OptimizerPatternName pattern) {
Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
Debug.Assert((int) pattern < 32);
Debug.Assert(!this.isReadOnly, "This OptimizerPatterns instance is read-only.");
this.patterns |= (1 << (int) pattern);
}
/// <summary>
/// Return true if the annotated node matches the specified pattern.
/// </summary>
public bool MatchesPattern(OptimizerPatternName pattern) {
Debug.Assert(Enum.IsDefined(typeof(OptimizerPatternName), pattern));
return (this.patterns & (1 << (int) pattern)) != 0;
}
/// <summary>
/// Return name of this annotation.
/// </summary>
public virtual string Name {
get { return "Patterns"; }
}
/// <summary>
/// Return string representation of this annotation.
/// </summary>
public override string ToString() {
string s = "";
for (int pattNum = 0; pattNum < PatternCount; pattNum++) {
if (MatchesPattern((OptimizerPatternName) pattNum)) {
if (s.Length != 0)
s += ", ";
s += ((OptimizerPatternName) pattNum).ToString();
}
}
return s;
}
}
}

View File

@@ -0,0 +1,221 @@
//------------------------------------------------------------------------------
// <copyright file="StaticDataManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
// <owner current="false">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Xml.Xsl.Qil;
using System.Xml.Xsl.Runtime;
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// This internal class maintains a list of unique values. Each unique value is assigned a unique ID, which can
/// be used to quickly access the value, since it corresponds to the value's position in the list.
/// </summary>
internal class UniqueList<T> {
private Dictionary<T, int> lookup = new Dictionary<T, int>();
private List<T> list = new List<T>();
/// <summary>
/// If "value" is already in the list, do not add it. Return the unique ID of the value in the list.
/// </summary>
public int Add(T value) {
int id;
if (!this.lookup.ContainsKey(value)) {
// The value does not yet exist, so add it to the list
id = list.Count;
this.lookup.Add(value, id);
this.list.Add(value);
}
else {
id = this.lookup[value];
}
return id;
}
/// <summary>
/// Return an array of the unique values.
/// </summary>
public T[] ToArray() {
return list.ToArray();
}
}
/// <summary>
/// Manages all static data that is used by the runtime. This includes:
/// 1. All NCName and QName atoms that will be used at run-time
/// 2. All QName filters that will be used at run-time
/// 3. All Xml types that will be used at run-time
/// 4. All global variables and parameters
/// </summary>
internal class StaticDataManager {
private UniqueList<string> uniqueNames;
private UniqueList<Int32Pair> uniqueFilters;
private List<StringPair[]> prefixMappingsList;
private List<string> globalNames;
private UniqueList<EarlyBoundInfo> earlyInfo;
private UniqueList<XmlQueryType> uniqueXmlTypes;
private UniqueList<XmlCollation> uniqueCollations;
/// <summary>
/// Add "name" to the list of unique names that are used by this query. Return the index of
/// the unique name in the list.
/// </summary>
public int DeclareName(string name) {
if (this.uniqueNames == null)
this.uniqueNames = new UniqueList<string>();
return this.uniqueNames.Add(name);
}
/// <summary>
/// Return an array of all names that are used by the query (null if no names).
/// </summary>
public string[] Names {
get { return (this.uniqueNames != null) ? this.uniqueNames.ToArray() : null; }
}
/// <summary>
/// Add a name filter to the list of unique filters that are used by this query. Return the index of
/// the unique filter in the list.
/// </summary>
public int DeclareNameFilter(string locName, string nsUri) {
if (this.uniqueFilters == null)
this.uniqueFilters = new UniqueList<Int32Pair>();
return this.uniqueFilters.Add(new Int32Pair(DeclareName(locName), DeclareName(nsUri)));
}
/// <summary>
/// Return an array of all name filters, where each name filter is represented as a pair of integer offsets (localName, namespaceUri)
/// into the Names array (null if no name filters).
/// </summary>
public Int32Pair[] NameFilters {
get { return (this.uniqueFilters != null) ? this.uniqueFilters.ToArray() : null; }
}
/// <summary>
/// Add a list of QilExpression NamespaceDeclarations to an array of strings (prefix followed by namespace URI).
/// Return index of the prefix mappings within this array.
/// </summary>
public int DeclarePrefixMappings(IList<QilNode> list) {
StringPair[] prefixMappings;
// Fill mappings array
prefixMappings = new StringPair[list.Count];
for (int i = 0; i < list.Count; i++) {
// Each entry in mappings array must be a constant NamespaceDeclaration
QilBinary ndNmspDecl = (QilBinary) list[i];
Debug.Assert(ndNmspDecl != null);
Debug.Assert(ndNmspDecl.Left is QilLiteral && ndNmspDecl.Right is QilLiteral);
prefixMappings[i] = new StringPair((string) (QilLiteral) ndNmspDecl.Left, (string) (QilLiteral) ndNmspDecl.Right);
}
// Add mappings to list and return index
if (this.prefixMappingsList == null)
this.prefixMappingsList = new List<StringPair[]>();
this.prefixMappingsList.Add(prefixMappings);
return this.prefixMappingsList.Count - 1;
}
/// <summary>
/// Return an array of all prefix mappings that are used by the query to compute names (null if no mappings).
/// </summary>
public StringPair[][] PrefixMappingsList {
get { return (this.prefixMappingsList != null) ? this.prefixMappingsList.ToArray() : null; }
}
/// <summary>
/// Declare a new global variable or parameter.
/// </summary>
public int DeclareGlobalValue(string name) {
int idx;
if (this.globalNames == null)
this.globalNames = new List<string>();
idx = this.globalNames.Count;
this.globalNames.Add(name);
return idx;
}
/// <summary>
/// Return an array containing the names of all global variables and parameters.
/// </summary>
public string[] GlobalNames {
get { return (this.globalNames != null) ? this.globalNames.ToArray() : null; }
}
/// <summary>
/// Add early bound information to a list that is used by this query. Return the index of
/// the early bound information in the list.
/// </summary>
public int DeclareEarlyBound(string namespaceUri, Type ebType) {
if (this.earlyInfo == null)
this.earlyInfo = new UniqueList<EarlyBoundInfo>();
return this.earlyInfo.Add(new EarlyBoundInfo(namespaceUri, ebType));
}
/// <summary>
/// Return an array of all early bound information that is used by the query (null if none is used).
/// </summary>
public EarlyBoundInfo[] EarlyBound {
get {
if (this.earlyInfo != null)
return this.earlyInfo.ToArray();
return null;
}
}
/// <summary>
/// Add "type" to the list of unique types that are used by this query. Return the index of
/// the unique type in the list.
/// </summary>
public int DeclareXmlType(XmlQueryType type) {
if (this.uniqueXmlTypes == null)
this.uniqueXmlTypes = new UniqueList<XmlQueryType>();
XmlQueryTypeFactory.CheckSerializability(type);
return this.uniqueXmlTypes.Add(type);
}
/// <summary>
/// Return an array of all types that are used by the query (null if no names).
/// </summary>
public XmlQueryType[] XmlTypes {
get { return (this.uniqueXmlTypes != null) ? this.uniqueXmlTypes.ToArray() : null; }
}
/// <summary>
/// Add "collation" to the list of unique collations that are used by this query. Return the index of
/// the unique collation in the list.
/// </summary>
public int DeclareCollation(string collation) {
if (this.uniqueCollations == null)
this.uniqueCollations = new UniqueList<XmlCollation>();
return this.uniqueCollations.Add(XmlCollation.Create(collation));
}
/// <summary>
/// Return an array of all collations that are used by the query (null if no names).
/// </summary>
public XmlCollation[] Collations {
get { return (this.uniqueCollations != null) ? this.uniqueCollations.ToArray() : null; }
}
}
}

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
// <copyright file="TailCallAnalyzer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// This analyzer walks each function in the graph and annotates Invoke nodes which can
/// be compiled using the IL .tailcall instruction. This instruction will discard the
/// current stack frame before calling the new function.
/// </summary>
internal static class TailCallAnalyzer {
/// <summary>
/// Perform tail-call analysis on the functions in the specified QilExpression.
/// </summary>
public static void Analyze(QilExpression qil) {
foreach (QilFunction ndFunc in qil.FunctionList) {
// Only analyze functions which are pushed to the writer, since otherwise code
// is generated after the call instruction in order to process cached results
if (XmlILConstructInfo.Read(ndFunc).ConstructMethod == XmlILConstructMethod.Writer)
AnalyzeDefinition(ndFunc.Definition);
}
}
/// <summary>
/// Recursively analyze the definition of a function.
/// </summary>
private static void AnalyzeDefinition(QilNode nd) {
Debug.Assert(XmlILConstructInfo.Read(nd).PushToWriterLast,
"Only need to analyze expressions which will be compiled in push mode.");
switch (nd.NodeType) {
case QilNodeType.Invoke:
// Invoke node can either be compiled as IteratorThenWriter, or Writer.
// Since IteratorThenWriter involves caching the results of the function call
// and iterating over them, .tailcall cannot be used
if (XmlILConstructInfo.Read(nd).ConstructMethod == XmlILConstructMethod.Writer)
OptimizerPatterns.Write(nd).AddPattern(OptimizerPatternName.TailCall);
break;
case QilNodeType.Loop: {
// Recursively analyze Loop return value
QilLoop ndLoop = (QilLoop) nd;
if (ndLoop.Variable.NodeType == QilNodeType.Let || !ndLoop.Variable.Binding.XmlType.MaybeMany)
AnalyzeDefinition(ndLoop.Body);
break;
}
case QilNodeType.Sequence: {
// Recursively analyze last expression in Sequence
QilList ndSeq = (QilList) nd;
if (ndSeq.Count > 0)
AnalyzeDefinition(ndSeq[ndSeq.Count - 1]);
break;
}
case QilNodeType.Choice: {
// Recursively analyze Choice branches
QilChoice ndChoice = (QilChoice) nd;
for (int i = 0; i < ndChoice.Branches.Count; i++)
AnalyzeDefinition(ndChoice.Branches[i]);
break;
}
case QilNodeType.Conditional: {
// Recursively analyze Conditional branches
QilTernary ndCond = (QilTernary) nd;
AnalyzeDefinition(ndCond.Center);
AnalyzeDefinition(ndCond.Right);
break;
}
case QilNodeType.Nop:
AnalyzeDefinition(((QilUnary) nd).Child);
break;
}
}
}
}

View File

@@ -0,0 +1,134 @@
//------------------------------------------------------------------------------
// <copyright file="XmlILAnnotation.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
using System.Xml.Xsl.Qil;
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// Several annotations are created and attached to Qil nodes during the optimization and code generation phase.
/// </summary>
internal class XmlILAnnotation : ListBase<object> {
private object annPrev;
private MethodInfo funcMethod;
private int argPos;
private IteratorDescriptor iterInfo;
private XmlILConstructInfo constrInfo;
private OptimizerPatterns optPatt;
//-----------------------------------------------
// Constructor
//-----------------------------------------------
/// <summary>
/// Create and initialize XmlILAnnotation for the specified node.
/// </summary>
public static XmlILAnnotation Write(QilNode nd) {
XmlILAnnotation ann = nd.Annotation as XmlILAnnotation;
if (ann == null) {
ann = new XmlILAnnotation(nd.Annotation);
nd.Annotation = ann;
}
return ann;
}
private XmlILAnnotation(object annPrev) {
this.annPrev = annPrev;
}
//-----------------------------------------------
// Annotations
//-----------------------------------------------
/// <summary>
/// User-defined functions and global variables and parameters are bound to Clr MethodInfo objects.
/// Attached to Function, global Let, and global Parameter nodes.
/// </summary>
public MethodInfo FunctionBinding {
get { return this.funcMethod; }
set { this.funcMethod = value; }
}
/// <summary>
/// Function arguments are tracked by position.
/// Attached to function Parameter nodes.
/// </summary>
public int ArgumentPosition {
get { return this.argPos; }
set { this.argPos = value; }
}
/// <summary>
/// The IteratorDescriptor that is derived for Qil For and Let nodes is cached so that it can be used when the
/// For/Let node is referenced.
/// Attached to For and Let nodes.
/// </summary>
public IteratorDescriptor CachedIteratorDescriptor {
get { return this.iterInfo; }
set { this.iterInfo = value; }
}
/// <summary>
/// Contains information about how this expression will be constructed by ILGen.
/// Attached to any kind of Qil node.
/// </summary>
public XmlILConstructInfo ConstructInfo {
get { return this.constrInfo; }
set { this.constrInfo = value; }
}
/// <summary>
/// Contains patterns that the subtree rooted at this node matches.
/// Attached to any kind of Qil node.
/// </summary>
public OptimizerPatterns Patterns {
get { return this.optPatt; }
set { this.optPatt = value; }
}
//-----------------------------------------------
// ListBase implementation
//-----------------------------------------------
/// <summary>
/// Return the count of sub-annotations maintained by this annotation.
/// </summary>
public override int Count {
get { return (this.annPrev != null) ? 3 : 2; }
}
/// <summary>
/// Return the annotation at the specified index.
/// </summary>
public override object this[int index] {
get {
if (this.annPrev != null) {
if (index == 0)
return this.annPrev;
index--;
}
switch (index) {
case 0: return this.constrInfo;
case 1: return this.optPatt;
}
throw new IndexOutOfRangeException();
}
set {
throw new NotSupportedException();
}
}
}
}

View File

@@ -0,0 +1,347 @@
//------------------------------------------------------------------------------
// <copyright file="XmlILModule.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
// <owner current="false">[....]</owner>
//------------------------------------------------------------------------------
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.Reflection;
using System.Reflection.Emit;
using System.Security;
using System.Security.Permissions;
using System.Xml.Xsl.Runtime;
using System.Runtime.Versioning;
namespace System.Xml.Xsl.IlGen {
using DebuggingModes = DebuggableAttribute.DebuggingModes;
internal enum XmlILMethodAttributes {
None = 0,
NonUser = 1, // Non-user method which should debugger should step through
Raw = 2, // Raw method which should not add an implicit first argument of type XmlQueryRuntime
}
internal class XmlILModule {
public static readonly PermissionSet CreateModulePermissionSet; // Permission set that contains permissions required for generating module
private static long AssemblyId; // Unique identifier used to ensure that assembly names are unique within AppDomain
private static ModuleBuilder LREModule; // Module used to emit dynamic lightweight-reflection-emit (LRE) methods
private TypeBuilder typeBldr;
private Hashtable methods, urlToSymWriter;
private string modFile;
private bool persistAsm, useLRE, emitSymbols;
private static readonly Guid LanguageGuid = new Guid(0x462d4a3e, 0xb257, 0x4aee, 0x97, 0xcd, 0x59, 0x18, 0xc7, 0x53, 0x17, 0x58);
private static readonly Guid VendorGuid = new Guid(0x994b45c4, 0xe6e9, 0x11d2, 0x90, 0x3f, 0x00, 0xc0, 0x4f, 0xa3, 0x02, 0xa1);
private const string RuntimeName = "{" + XmlReservedNs.NsXslDebug + "}" + "runtime";
static XmlILModule() {
AssemblyName asmName;
AssemblyBuilder asmBldr;
CreateModulePermissionSet = new PermissionSet(PermissionState.None);
// CreateDelegate demands MemberAccess permission
CreateModulePermissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
// DynamicMethod constructor demands ControlEvidence permissions.
// Emitting symbols in DefineDynamicModule (to allow to debug the stylesheet) requires UnmanagedCode permission.
CreateModulePermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.UnmanagedCode));
AssemblyId = 0;
// 1. LRE assembly only needs to execute
// 2. No temp files need be created
// 3. Never allow assembly to Assert permissions
asmName = CreateAssemblyName();
asmBldr = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
try {
CreateModulePermissionSet.Assert();
// Add custom attribute to assembly marking it as security transparent so that Assert will not be allowed
// and link demands will be converted to full demands.
asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Transparent, new object[] {}));
// Store LREModule once. If multiple threads are doing this, then some threads might get different
// modules. This is OK, since it's not mandatory to share, just preferable.
LREModule = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", false);
}
finally {
CodeAccessPermission.RevertAssert();
}
}
public XmlILModule(TypeBuilder typeBldr) {
this.typeBldr = typeBldr;
this.emitSymbols = ((ModuleBuilder) this.typeBldr.Module).GetSymWriter() != null;
this.useLRE = false;
this.persistAsm = false;
// Index all methods added to this module by unique name
this.methods = new Hashtable();
if (this.emitSymbols) {
// Create mapping from source document to symbol writer
this.urlToSymWriter = new Hashtable();
}
}
public bool EmitSymbols {
get {
return this.emitSymbols;
}
}
// SxS note: AssemblyBuilder.DefineDynamicModule() below may be using name which is not SxS safe.
// This file is written only for internal tracing/debugging purposes. In retail builds persistAsm
// will be always false and the file should never be written. As a result it's fine just to supress
// the the SxS warning.
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
public XmlILModule(bool useLRE, bool emitSymbols) {
AssemblyName asmName;
AssemblyBuilder asmBldr;
ModuleBuilder modBldr;
Debug.Assert(!(useLRE && emitSymbols));
this.useLRE = useLRE;
this.emitSymbols = emitSymbols;
this.persistAsm = false;
// Index all methods added to this module by unique name
this.methods = new Hashtable();
if (!useLRE) {
// 1. If assembly needs to support debugging, then it must be saved and re-loaded (rule of CLR)
// 2. Get path of temp directory, where assembly will be saved
// 3. Never allow assembly to Assert permissions
asmName = CreateAssemblyName();
#if DEBUG
if (XmlILTrace.IsEnabled) {
this.modFile = "System.Xml.Xsl.CompiledQuery";
this.persistAsm = true;
}
#endif
asmBldr = AppDomain.CurrentDomain.DefineDynamicAssembly(
asmName,
this.persistAsm ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
// Add custom attribute to assembly marking it as security transparent so that Assert will not be allowed
// and link demands will be converted to full demands.
asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Transparent, new object[] { }));
if (emitSymbols) {
// Create mapping from source document to symbol writer
this.urlToSymWriter = new Hashtable();
// Add DebuggableAttribute to assembly so that debugging is a better experience
DebuggingModes debuggingModes = DebuggingModes.Default | DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggingModes.DisableOptimizations;
asmBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.Debuggable, new object[] {debuggingModes}));
}
// Create ModuleBuilder
if (this.persistAsm)
modBldr = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", this.modFile + ".dll", emitSymbols);
else
modBldr = asmBldr.DefineDynamicModule("System.Xml.Xsl.CompiledQuery", emitSymbols);
this.typeBldr = modBldr.DefineType("System.Xml.Xsl.CompiledQuery.Query", TypeAttributes.Public);
}
}
/// <summary>
/// Define a method in this module with the specified name and parameters.
/// </summary>
public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string[] paramNames, XmlILMethodAttributes xmlAttrs) {
MethodInfo methResult;
int uniqueId = 1;
string nameOrig = name;
Type[] paramTypesNew;
bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0;
// Ensure that name is unique
while (this.methods[name] != null) {
// Add unique id to end of name in order to make it unique within this module
uniqueId++;
name = nameOrig + " (" + uniqueId + ")";
}
if (!isRaw) {
// XmlQueryRuntime is always 0th parameter
paramTypesNew = new Type[paramTypes.Length + 1];
paramTypesNew[0] = typeof(XmlQueryRuntime);
Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length);
paramTypes = paramTypesNew;
}
if (!this.useLRE) {
MethodBuilder methBldr;
methBldr = this.typeBldr.DefineMethod(
name,
MethodAttributes.Private | MethodAttributes.Static,
returnType,
paramTypes);
if (emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) {
// Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience
methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, new object[] {}));
methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, new object[] {}));
}
if (!isRaw)
methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName);
for (int i = 0; i < paramNames.Length; i++) {
if (paramNames[i] != null && paramNames[i].Length != 0)
methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]);
}
methResult = methBldr;
}
else {
DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, LREModule);
methDyn.InitLocals = true;
if (!isRaw)
methDyn.DefineParameter(1, ParameterAttributes.None, RuntimeName);
for (int i = 0; i < paramNames.Length; i++) {
if (paramNames[i] != null && paramNames[i].Length != 0)
methDyn.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]);
}
methResult = methDyn;
}
// Index method by name
this.methods[name] = methResult;
return methResult;
}
/// <summary>
/// Get an XmlILGenerator that can be used to generate the body of the specified method.
/// </summary>
public static ILGenerator DefineMethodBody(MethodBase methInfo) {
DynamicMethod methDyn = methInfo as DynamicMethod;
if (methDyn != null)
return methDyn.GetILGenerator();
MethodBuilder methBldr = methInfo as MethodBuilder;
if (methBldr != null)
return methBldr.GetILGenerator();
return ((ConstructorBuilder) methInfo).GetILGenerator();
}
/// <summary>
/// Find a MethodInfo of the specified name and return it. Return null if no such method exists.
/// </summary>
public MethodInfo FindMethod(string name) {
return (MethodInfo) this.methods[name];
}
/// <summary>
/// Define ginitialized data field with the specified name and value.
/// </summary>
public FieldInfo DefineInitializedData(string name, byte[] data) {
Debug.Assert(!this.useLRE, "Cannot create initialized data for an LRE module");
return this.typeBldr.DefineInitializedData(name, data, FieldAttributes.Private | FieldAttributes.Static);
}
/// <summary>
/// Define private static field with the specified name and value.
/// </summary>
public FieldInfo DefineField(string fieldName, Type type) {
Debug.Assert(!this.useLRE, "Cannot create field for an LRE module");
return this.typeBldr.DefineField(fieldName, type, FieldAttributes.Private | FieldAttributes.Static);
}
/// <summary>
/// Define static constructor for this type.
/// </summary>
public ConstructorInfo DefineTypeInitializer() {
Debug.Assert(!this.useLRE, "Cannot create type initializer for an LRE module");
return this.typeBldr.DefineTypeInitializer();
}
/// <summary>
/// Add the file name of a document containing source code for this module and return a symbol writer.
/// </summary>
public ISymbolDocumentWriter AddSourceDocument(string fileName) {
ISymbolDocumentWriter symDoc;
Debug.Assert(this.emitSymbols, "Cannot add source information to a module that doesn't allow symbols.");
symDoc = this.urlToSymWriter[fileName] as ISymbolDocumentWriter;
if (symDoc == null) {
symDoc = ((ModuleBuilder) this.typeBldr.Module).DefineDocument(fileName, LanguageGuid, VendorGuid, Guid.Empty);
this.urlToSymWriter.Add(fileName, symDoc);
}
return symDoc;
}
/// <summary>
/// Once all methods have been defined, CreateModule must be called in order to "bake" the methods within
/// this module.
/// </summary>
// SxS note: AssemblyBuilder.Save() below is using name which is not SxS safe. This file is written only for
// internal tracing/debugging purposes. In retail builds persistAsm will be always false and the file should
// never be written. As a result it's fine just to supress the the SxS warning.
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
public void BakeMethods() {
Type typBaked;
Hashtable methodsBaked;
if (!this.useLRE) {
typBaked = this.typeBldr.CreateType();
if (this.persistAsm) {
// Persist the assembly to disk
((AssemblyBuilder) this.typeBldr.Module.Assembly).Save(this.modFile + ".dll");
}
// Replace all MethodInfos in this.methods
methodsBaked = new Hashtable(this.methods.Count);
foreach (string methName in this.methods.Keys) {
methodsBaked[methName] = typBaked.GetMethod(methName, BindingFlags.NonPublic | BindingFlags.Static);
}
this.methods = methodsBaked;
// Release TypeBuilder and symbol writer resources
this.typeBldr = null;
this.urlToSymWriter = null;
}
}
/// <summary>
/// Wrap a delegate around a MethodInfo of the specified name and type and return it.
/// </summary>
public Delegate CreateDelegate(string name, Type typDelegate) {
if (!this.useLRE)
return Delegate.CreateDelegate(typDelegate, (MethodInfo) this.methods[name]);
return ((DynamicMethod) this.methods[name]).CreateDelegate(typDelegate);
}
/// <summary>
/// Define unique assembly name (within AppDomain).
/// </summary>
private static AssemblyName CreateAssemblyName() {
AssemblyName name;
System.Threading.Interlocked.Increment(ref AssemblyId);
name = new AssemblyName();
name.Name = "System.Xml.Xsl.CompiledQuery." + AssemblyId;
return name;
}
}
}

View File

@@ -0,0 +1,164 @@
//------------------------------------------------------------------------------
// <copyright file="XmlILOptimization.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">akimball</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// Xml IL patterns.
/// </summary>
internal enum XmlILOptimization {
None,
EliminateLiteralVariables,
TailCall,
// Do not edit this region
// It is auto-generated
#region AUTOGENERATED
AnnotateAncestor,
AnnotateAncestorSelf,
AnnotateAttribute,
AnnotateAttrNmspLoop,
AnnotateBarrier,
AnnotateConstruction,
AnnotateContent,
AnnotateContentLoop,
AnnotateDescendant,
AnnotateDescendantLoop,
AnnotateDescendantSelf,
AnnotateDifference,
AnnotateDod,
AnnotateDodMerge,
AnnotateDodReverse,
AnnotateFilter,
AnnotateFilterAttributeKind,
AnnotateFilterContentKind,
AnnotateFilterElements,
AnnotateFollowingSibling,
AnnotateIndex1,
AnnotateIndex2,
AnnotateIntersect,
AnnotateInvoke,
AnnotateJoinAndDod,
AnnotateLet,
AnnotateMaxLengthEq,
AnnotateMaxLengthGe,
AnnotateMaxLengthGt,
AnnotateMaxLengthLe,
AnnotateMaxLengthLt,
AnnotateMaxLengthNe,
AnnotateMaxPositionEq,
AnnotateMaxPositionLe,
AnnotateMaxPositionLt,
AnnotateNamespace,
AnnotateNodeRange,
AnnotateParent,
AnnotatePositionalIterator,
AnnotatePreceding,
AnnotatePrecedingSibling,
AnnotateRoot,
AnnotateRootLoop,
AnnotateSingleTextRtf,
AnnotateSingletonLoop,
AnnotateTrackCallers,
AnnotateUnion,
AnnotateUnionContent,
AnnotateXPathFollowing,
AnnotateXPathPreceding,
CommuteDodFilter,
CommuteFilterLoop,
EliminateAdd,
EliminateAfter,
EliminateAnd,
EliminateAverage,
EliminateBefore,
EliminateConditional,
EliminateDifference,
EliminateDivide,
EliminateDod,
EliminateEq,
EliminateFilter,
EliminateGe,
EliminateGt,
EliminateIntersection,
EliminateIs,
EliminateIsEmpty,
EliminateIsType,
EliminateIterator,
EliminateIteratorUsedAtMostOnce,
EliminateLe,
EliminateLength,
EliminateLoop,
EliminateLt,
EliminateMaximum,
EliminateMinimum,
EliminateModulo,
EliminateMultiply,
EliminateNamespaceDecl,
EliminateNe,
EliminateNegate,
EliminateNop,
EliminateNot,
EliminateOr,
EliminatePositionOf,
EliminateReturnDod,
EliminateSequence,
EliminateSort,
EliminateStrConcat,
EliminateStrConcatSingle,
EliminateStrLength,
EliminateSubtract,
EliminateSum,
EliminateTypeAssert,
EliminateTypeAssertOptional,
EliminateUnion,
EliminateUnusedGlobals,
EliminateXsltConvert,
FoldConditionalNot,
FoldNamedDescendants,
FoldNone,
FoldXsltConvertLiteral,
IntroduceDod,
IntroducePrecedingDod,
NormalizeAddEq,
NormalizeAddLiteral,
NormalizeAttribute,
NormalizeConditionalText,
NormalizeDifference,
NormalizeEqLiteral,
NormalizeGeLiteral,
NormalizeGtLiteral,
NormalizeIdEq,
NormalizeIdNe,
NormalizeIntersect,
NormalizeInvokeEmpty,
NormalizeLeLiteral,
NormalizeLengthGt,
NormalizeLengthNe,
NormalizeLoopConditional,
NormalizeLoopInvariant,
NormalizeLoopLoop,
NormalizeLoopText,
NormalizeLtLiteral,
NormalizeMuenchian,
NormalizeMultiplyLiteral,
NormalizeNeLiteral,
NormalizeNestedSequences,
NormalizeSingletonLet,
NormalizeSortXsltConvert,
NormalizeUnion,
NormalizeXsltConvertEq,
NormalizeXsltConvertGe,
NormalizeXsltConvertGt,
NormalizeXsltConvertLe,
NormalizeXsltConvertLt,
NormalizeXsltConvertNe,
#endregion // AUTOGENERATED
// Must appear last in the enum
Last_,
}
}

View File

@@ -0,0 +1 @@
e1c869221fa43552e2ba4aeda158583a553d307c

View File

@@ -0,0 +1,195 @@
//------------------------------------------------------------------------------
// <copyright file="XmlILTrace.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">akimball</owner>
//------------------------------------------------------------------------------
using System;
using System.IO;
using System.Security;
using System.Xml;
using System.Globalization;
using System.Xml.Xsl.Qil;
using System.Runtime.Versioning;
// This class is only for debug purposes so there is no need to have it in Retail builds
#if DEBUG
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// Helper class that facilitates tracing of ILGen.
/// </summary>
internal static class XmlILTrace {
private const int MAX_REWRITES = 200;
/// <summary>
/// Check environment variable in order to determine whether to write out trace files. This really should be a
/// check of the configuration file, but System.Xml does not yet have a good tracing story.
/// </summary>
private static volatile string dirName = null;
private static volatile bool alreadyCheckedEnabled = false;
/// <summary>
/// True if tracing has been enabled (environment variable set).
/// </summary>
public static bool IsEnabled {
// SxS: This property poses potential SxS issue. However the class is used only in debug builds (it won't
// get compiled into ret build) so it's OK to suppress the SxS warning.
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
get {
// If environment variable has not yet been checked, do so now
if (!alreadyCheckedEnabled) {
try {
dirName = Environment.GetEnvironmentVariable("XmlILTrace");
}
catch (SecurityException) {
// If user does not have access to environment variables, tracing will remain disabled
}
alreadyCheckedEnabled = true;
}
return (dirName != null);
}
}
/// <summary>
/// If tracing is enabled, this method will delete the contents of "filename" in preparation for append
/// operations.
/// </summary>
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
public static void PrepareTraceWriter(string fileName) {
if (!IsEnabled)
return;
File.Delete(dirName + "\\" + fileName);
}
/// <summary>
/// If tracing is enabled, this method will open a TextWriter over "fileName" and return it. Otherwise,
/// null will be returned.
/// </summary>
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
public static TextWriter GetTraceWriter(string fileName) {
if (!IsEnabled)
return null;
return new StreamWriter(dirName + "\\" + fileName, true);
}
/// <summary>
/// Serialize Qil tree to "fileName", in the directory identified by "dirName".
/// </summary>
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
public static void WriteQil(QilExpression qil, string fileName) {
if (!IsEnabled)
return;
XmlWriter w = XmlWriter.Create(dirName + "\\" + fileName);
try {
WriteQil(qil, w);
}
finally {
w.Close();
}
}
/// <summary>
/// Trace ILGen optimizations and log them to "fileName".
/// </summary>
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
public static void TraceOptimizations(QilExpression qil, string fileName) {
if (!IsEnabled)
return;
XmlWriter w = XmlWriter.Create(dirName + "\\" + fileName);
w.WriteStartDocument();
w.WriteProcessingInstruction("xml-stylesheet", "href='qilo.xslt' type='text/xsl'");
w.WriteStartElement("QilOptimizer");
w.WriteAttributeString("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture));
WriteQilRewrite(qil, w, null);
try {
// Then, rewrite the graph until "done" or some max value is reached.
for (int i = 1; i < MAX_REWRITES; i++) {
QilExpression qilTemp = (QilExpression) (new QilCloneVisitor(qil.Factory).Clone(qil));
XmlILOptimizerVisitor visitor = new XmlILOptimizerVisitor(qilTemp, !qilTemp.IsDebug);
visitor.Threshold = i;
qilTemp = visitor.Optimize();
// In debug code, ensure that QIL after N steps is correct
QilValidationVisitor.Validate(qilTemp);
// Trace the rewrite
WriteQilRewrite(qilTemp, w, OptimizationToString(visitor.LastReplacement));
if (visitor.ReplacementCount < i)
break;
}
}
catch (Exception e) {
if (!XmlException.IsCatchableException(e)) {
throw;
}
w.WriteElementString("Exception", null, e.ToString());
throw;
}
finally {
w.WriteEndElement();
w.WriteEndDocument();
w.Flush();
w.Close();
}
}
/// <summary>
/// Serialize Qil tree to writer "w".
/// </summary>
private static void WriteQil(QilExpression qil, XmlWriter w) {
QilXmlWriter qw = new QilXmlWriter(w);
qw.ToXml(qil);
}
/// <summary>
/// Serialize rewritten Qil tree to writer "w".
/// </summary>
private static void WriteQilRewrite(QilExpression qil, XmlWriter w, string rewriteName) {
w.WriteStartElement("Diff");
if (rewriteName != null)
w.WriteAttributeString("rewrite", rewriteName);
WriteQil(qil, w);
w.WriteEndElement();
}
/// <summary>
/// Get friendly string description of an ILGen optimization.
/// </summary>
private static string OptimizationToString(int opt) {
string s = Enum.GetName(typeof(XmlILOptimization), opt);
if (s.StartsWith("Introduce", StringComparison.Ordinal)) {
return s.Substring(9) + " introduction";
}
else if (s.StartsWith("Eliminate", StringComparison.Ordinal)) {
return s.Substring(9) + " elimination";
}
else if (s.StartsWith("Commute", StringComparison.Ordinal)) {
return s.Substring(7) + " commutation";
}
else if (s.StartsWith("Fold", StringComparison.Ordinal)) {
return s.Substring(4) + " folding";
}
else if (s.StartsWith("Misc", StringComparison.Ordinal)) {
return s.Substring(4);
}
return s;
}
}
}
#endif

View File

@@ -0,0 +1,168 @@
//------------------------------------------------------------------------------
// <copyright file="XmlIlTypeHelper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
using System.Xml.Xsl.Runtime;
namespace System.Xml.Xsl.IlGen {
/// <summary>
/// Static QilExpression type helper methods.
/// </summary>
internal class XmlILTypeHelper {
// Not creatable
private XmlILTypeHelper() {
}
/// <summary>
/// Return the default Clr data type that will be used to store instances of the QilNode's type.
/// </summary>
public static Type GetStorageType(XmlQueryType qyTyp) {
Type storageType;
if (qyTyp.IsSingleton) {
storageType = TypeCodeToStorage[(int) qyTyp.TypeCode];
// Non-strict items must store the type along with the value, so use XPathItem
if (!qyTyp.IsStrict && storageType != typeof(XPathNavigator))
return typeof(XPathItem);
}
else {
storageType = TypeCodeToCachedStorage[(int) qyTyp.TypeCode];
// Non-strict items must store the type along with the value, so use XPathItem
if (!qyTyp.IsStrict && storageType != typeof(IList<XPathNavigator>))
return typeof(IList<XPathItem>);
}
return storageType;
}
private static readonly Type[] TypeCodeToStorage = {
typeof(XPathItem), // XmlTypeCode.None
typeof(XPathItem), // XmlTypeCode.Item
typeof(XPathNavigator), // XmlTypeCode.Node
typeof(XPathNavigator), // XmlTypeCode.Document
typeof(XPathNavigator), // XmlTypeCode.Element
typeof(XPathNavigator), // XmlTypeCode.Attribute
typeof(XPathNavigator), // XmlTypeCode.Namespace
typeof(XPathNavigator), // XmlTypeCode.ProcessingInstruction
typeof(XPathNavigator), // XmlTypeCode.Comment
typeof(XPathNavigator), // XmlTypeCode.Text
typeof(XPathItem), // XmlTypeCode.AnyAtomicType
typeof(string), // XmlTypeCode.UntypedAtomic
typeof(string), // XmlTypeCode.String
typeof(bool), // XmlTypeCode.Boolean
typeof(decimal), // XmlTypeCode.Decimal
typeof(float), // XmlTypeCode.Float
typeof(double), // XmlTypeCode.Double
typeof(string), // XmlTypeCode.Duration
typeof(DateTime), // XmlTypeCode.DateTime
typeof(DateTime), // XmlTypeCode.Time
typeof(DateTime), // XmlTypeCode.Date
typeof(DateTime), // XmlTypeCode.GYearMonth
typeof(DateTime), // XmlTypeCode.GYear
typeof(DateTime), // XmlTypeCode.GMonthDay
typeof(DateTime), // XmlTypeCode.GDay
typeof(DateTime), // XmlTypeCode.GMonth
typeof(byte[]), // XmlTypeCode.HexBinary
typeof(byte[]), // XmlTypeCode.Base64Binary
typeof(string), // XmlTypeCode.AnyUri
typeof(XmlQualifiedName), // XmlTypeCode.QName
typeof(XmlQualifiedName), // XmlTypeCode.Notation
typeof(string), // XmlTypeCode.NormalizedString
typeof(string), // XmlTypeCode.Token
typeof(string), // XmlTypeCode.Language
typeof(string), // XmlTypeCode.NmToken
typeof(string), // XmlTypeCode.Name
typeof(string), // XmlTypeCode.NCName
typeof(string), // XmlTypeCode.Id
typeof(string), // XmlTypeCode.Idref
typeof(string), // XmlTypeCode.Entity
typeof(long), // XmlTypeCode.Integer
typeof(decimal), // XmlTypeCode.NonPositiveInteger
typeof(decimal), // XmlTypeCode.NegativeInteger
typeof(long), // XmlTypeCode.Long
typeof(int), // XmlTypeCode.Int
typeof(int), // XmlTypeCode.Short
typeof(int), // XmlTypeCode.Byte
typeof(decimal), // XmlTypeCode.NonNegativeInteger
typeof(decimal), // XmlTypeCode.UnsignedLong
typeof(long), // XmlTypeCode.UnsignedInt
typeof(int), // XmlTypeCode.UnsignedShort
typeof(int), // XmlTypeCode.UnsignedByte
typeof(decimal), // XmlTypeCode.PositiveInteger
typeof(TimeSpan), // XmlTypeCode.YearMonthDuration
typeof(TimeSpan), // XmlTypeCode.DayTimeDuration
};
private static readonly Type[] TypeCodeToCachedStorage = {
typeof(IList<XPathItem>), // XmlTypeCode.None
typeof(IList<XPathItem>), // XmlTypeCode.Item
typeof(IList<XPathNavigator>), // XmlTypeCode.Node
typeof(IList<XPathNavigator>), // XmlTypeCode.Document
typeof(IList<XPathNavigator>), // XmlTypeCode.Element
typeof(IList<XPathNavigator>), // XmlTypeCode.Attribute
typeof(IList<XPathNavigator>), // XmlTypeCode.Namespace
typeof(IList<XPathNavigator>), // XmlTypeCode.ProcessingInstruction
typeof(IList<XPathNavigator>), // XmlTypeCode.Comment
typeof(IList<XPathNavigator>), // XmlTypeCode.Text
typeof(IList<XPathItem>), // XmlTypeCode.AnyAtomicType
typeof(IList<string>), // XmlTypeCode.UntypedAtomic
typeof(IList<string>), // XmlTypeCode.String
typeof(IList<bool>), // XmlTypeCode.Boolean
typeof(IList<decimal>), // XmlTypeCode.Decimal
typeof(IList<float>), // XmlTypeCode.Float
typeof(IList<double>), // XmlTypeCode.Double
typeof(IList<string>), // XmlTypeCode.Duration
typeof(IList<DateTime>), // XmlTypeCode.DateTime
typeof(IList<DateTime>), // XmlTypeCode.Time
typeof(IList<DateTime>), // XmlTypeCode.Date
typeof(IList<DateTime>), // XmlTypeCode.GYearMonth
typeof(IList<DateTime>), // XmlTypeCode.GYear
typeof(IList<DateTime>), // XmlTypeCode.GMonthDay
typeof(IList<DateTime>), // XmlTypeCode.GDay
typeof(IList<DateTime>), // XmlTypeCode.GMonth
typeof(IList<byte[]>), // XmlTypeCode.HexBinary
typeof(IList<byte[]>), // XmlTypeCode.Base64Binary
typeof(IList<string>), // XmlTypeCode.AnyUri
typeof(IList<XmlQualifiedName>), // XmlTypeCode.QName
typeof(IList<XmlQualifiedName>), // XmlTypeCode.Notation
typeof(IList<string>), // XmlTypeCode.NormalizedString
typeof(IList<string>), // XmlTypeCode.Token
typeof(IList<string>), // XmlTypeCode.Language
typeof(IList<string>), // XmlTypeCode.NmToken
typeof(IList<string>), // XmlTypeCode.Name
typeof(IList<string>), // XmlTypeCode.NCName
typeof(IList<string>), // XmlTypeCode.Id
typeof(IList<string>), // XmlTypeCode.Idref
typeof(IList<string>), // XmlTypeCode.Entity
typeof(IList<long>), // XmlTypeCode.Integer
typeof(IList<decimal>), // XmlTypeCode.NonPositiveInteger
typeof(IList<decimal>), // XmlTypeCode.NegativeInteger
typeof(IList<long>), // XmlTypeCode.Long
typeof(IList<int>), // XmlTypeCode.Int
typeof(IList<int>), // XmlTypeCode.Short
typeof(IList<int>), // XmlTypeCode.Byte
typeof(IList<decimal>), // XmlTypeCode.NonNegativeInteger
typeof(IList<decimal>), // XmlTypeCode.UnsignedLong
typeof(IList<long>), // XmlTypeCode.UnsignedInt
typeof(IList<int>), // XmlTypeCode.UnsignedShort
typeof(IList<int>), // XmlTypeCode.UnsignedByte
typeof(IList<decimal>), // XmlTypeCode.PositiveInteger
typeof(IList<TimeSpan>), // XmlTypeCode.YearMonthDuration
typeof(IList<TimeSpan>), // XmlTypeCode.DayTimeDuration
};
}
}

View File

@@ -0,0 +1 @@
786be8983fcf729e04fe03010b521bd7b8ee8d84

View File

@@ -0,0 +1,243 @@
//------------------------------------------------------------------------------
// <copyright file="ListBase.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Xml;
using System.Xml.Schema;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace System.Xml.Xsl {
/// <summary>
/// Implementation of read-only IList and IList<T> interfaces. Derived classes can inherit from
/// this class and implement only two methods, Count and Item, rather than the entire IList interface.
/// </summary>
internal abstract class ListBase<T> : IList<T>, System.Collections.IList {
//-----------------------------------------------
// Abstract IList methods that must be
// implemented by derived classes
//-----------------------------------------------
public abstract int Count { get; }
public abstract T this[int index] { get; set; }
//-----------------------------------------------
// Implemented by base class -- accessible on
// ListBase
//-----------------------------------------------
public virtual bool Contains(T value) {
return IndexOf(value) != -1;
}
public virtual int IndexOf(T value) {
for (int i = 0; i < Count; i++)
if (value.Equals(this[i]))
return i;
return -1;
}
public virtual void CopyTo(T[] array, int index) {
for (int i = 0; i < Count; i++)
array[index + i] = this[i];
}
public virtual IListEnumerator<T> GetEnumerator() {
return new IListEnumerator<T>(this);
}
public virtual bool IsFixedSize {
get { return true; }
}
public virtual bool IsReadOnly {
get { return true; }
}
public virtual void Add(T value) {
Insert(Count, value);
}
public virtual void Insert(int index, T value) {
throw new NotSupportedException();
}
public virtual bool Remove(T value) {
int index = IndexOf(value);
if (index >= 0) {
RemoveAt(index);
return true;
}
return false;
}
public virtual void RemoveAt(int index) {
throw new NotSupportedException();
}
public virtual void Clear() {
for (int index = Count - 1; index >= 0; index--)
RemoveAt(index);
}
//-----------------------------------------------
// Implemented by base class -- only accessible
// after casting to IList
//-----------------------------------------------
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new IListEnumerator<T>(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return new IListEnumerator<T>(this);
}
bool System.Collections.ICollection.IsSynchronized {
get { return IsReadOnly; }
}
object System.Collections.ICollection.SyncRoot {
get { return this; }
}
void System.Collections.ICollection.CopyTo(Array array, int index) {
for (int i = 0; i < Count; i++)
array.SetValue(this[i], index);
}
object System.Collections.IList.this[int index] {
get { return this[index]; }
set {
if (!IsCompatibleType(value.GetType()))
throw new ArgumentException(Res.GetString(Res.Arg_IncompatibleParamType), "value");
this[index] = (T) value;
}
}
int System.Collections.IList.Add(object value) {
if (!IsCompatibleType(value.GetType()))
throw new ArgumentException(Res.GetString(Res.Arg_IncompatibleParamType), "value");
Add((T) value);
return Count - 1;
}
void System.Collections.IList.Clear() {
Clear();
}
bool System.Collections.IList.Contains(object value) {
if (!IsCompatibleType(value.GetType()))
return false;
return Contains((T) value);
}
int System.Collections.IList.IndexOf(object value) {
if (!IsCompatibleType(value.GetType()))
return -1;
return IndexOf((T) value);
}
void System.Collections.IList.Insert(int index, object value) {
if (!IsCompatibleType(value.GetType()))
throw new ArgumentException(Res.GetString(Res.Arg_IncompatibleParamType), "value");
Insert(index, (T) value);
}
void System.Collections.IList.Remove(object value) {
if (IsCompatibleType(value.GetType())) {
Remove((T)value);
}
}
//-----------------------------------------------
// Helper methods and classes
//-----------------------------------------------
private static bool IsCompatibleType(object value) {
if((value == null && !typeof(T).IsValueType) || (value is T))
return true;
return false;
}
}
/// <summary>
/// Implementation of IEnumerator<T> and IEnumerator over an IList<T>.
/// </summary>
internal struct IListEnumerator<T> : IEnumerator<T>, System.Collections.IEnumerator {
private IList<T> sequence;
private int index;
private T current;
/// <summary>
/// Constructor.
/// </summary>
public IListEnumerator(IList<T> sequence) {
this.sequence = sequence;
this.index = 0;
this.current = default(T);
}
/// <summary>
/// No-op.
/// </summary>
public void Dispose() {
}
/// <summary>
/// Return current item. Return default value if before first item or after last item in the list.
/// </summary>
public T Current {
get { return this.current; }
}
/// <summary>
/// Return current item. Throw exception if before first item or after last item in the list.
/// </summary>
object System.Collections.IEnumerator.Current {
get {
if (this.index == 0)
throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
if (this.index > this.sequence.Count)
throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
return this.current;
}
}
/// <summary>
/// Advance enumerator to next item in list. Return false if there are no more items.
/// </summary>
public bool MoveNext() {
if (this.index < this.sequence.Count) {
this.current = this.sequence[this.index];
this.index++;
return true;
}
this.current = default(T);
return false;
}
/// <summary>
/// Set the enumerator to its initial position, which is before the first item in the list.
/// </summary>
void System.Collections.IEnumerator.Reset() {
this.index = 0;
this.current = default(T);
}
}
}

View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
// <copyright file="Pair.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
namespace System.Xml.Xsl {
internal struct Int32Pair {
private int left;
private int right;
public Int32Pair(int left, int right) {
this.left = left;
this.right = right;
}
public int Left { get { return this.left ; } }
public int Right { get { return this.right; } }
public override bool Equals(object other) {
if (other is Int32Pair) {
Int32Pair o = (Int32Pair) other;
return this.left == o.left && this.right == o.right;
}
return false;
}
public override int GetHashCode() {
return this.left.GetHashCode() ^ this.right.GetHashCode();
}
}
internal struct StringPair {
private string left;
private string right;
public StringPair(string left, string right) {
this.left = left;
this.right = right;
}
public string Left { get { return this.left ; } }
public string Right { get { return this.right; } }
}
}

View File

@@ -0,0 +1,76 @@
//------------------------------------------------------------------------------
// <copyright file="QilBinary.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Xml.Xsl.Qil {
/// <summary>
/// View over a Qil operator having two children.
/// </summary>
/// <remarks>
/// Don't construct QIL nodes directly; instead, use the <see cref="QilFactory">QilFactory</see>.
/// </remarks>
internal class QilBinary : QilNode {
private QilNode left, right;
//-----------------------------------------------
// Constructor
//-----------------------------------------------
/// <summary>
/// Construct a new node
/// </summary>
public QilBinary(QilNodeType nodeType, QilNode left, QilNode right) : base(nodeType) {
this.left = left;
this.right = right;
}
//-----------------------------------------------
// IList<QilNode> methods -- override
//-----------------------------------------------
public override int Count {
get { return 2; }
}
public override QilNode this[int index] {
get {
switch (index) {
case 0: return this.left;
case 1: return this.right;
default: throw new IndexOutOfRangeException();
}
}
set {
switch (index) {
case 0: this.left = value; break;
case 1: this.right = value; break;
default: throw new IndexOutOfRangeException();
}
}
}
//-----------------------------------------------
// QilBinary methods
//-----------------------------------------------
public QilNode Left {
get { return this.left; }
set { this.left = value; }
}
public QilNode Right {
get { return this.right; }
set { this.right = value; }
}
}
}

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// <copyright file="QilLoop.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Diagnostics;
using System.Xml.Schema;
using System.Xml.Xsl;
namespace System.Xml.Xsl.Qil {
/// <summary>
/// View over a Qil choice operator.
/// </summary>
/// <remarks>
/// Don't construct QIL nodes directly; instead, use the <see cref="QilFactory">QilFactory</see>.
/// </remarks>
internal class QilChoice : QilBinary {
//-----------------------------------------------
// Constructor
//-----------------------------------------------
/// <summary>
/// Construct a new node
/// </summary>
public QilChoice(QilNodeType nodeType, QilNode expression, QilNode branches) : base(nodeType, expression, branches) {
}
//-----------------------------------------------
// QilChoice methods
//-----------------------------------------------
public QilNode Expression {
get { return Left; }
set { Left = value; }
}
public QilList Branches {
get { return (QilList) Right; }
set { Right = value; }
}
}
}

View File

@@ -0,0 +1,136 @@
//------------------------------------------------------------------------------
// <copyright file="QilCloneVisitor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Xml.Xsl;
namespace System.Xml.Xsl.Qil {
// Create an exact replica of a QIL graph
internal class QilCloneVisitor : QilScopedVisitor {
private QilFactory fac;
private SubstitutionList subs;
//-----------------------------------------------
// Constructors
//-----------------------------------------------
public QilCloneVisitor(QilFactory fac) : this(fac, new SubstitutionList()) {
}
public QilCloneVisitor(QilFactory fac, SubstitutionList subs) {
this.fac = fac;
this.subs = subs;
}
//-----------------------------------------------
// Entry
//-----------------------------------------------
public QilNode Clone(QilNode node) {
QilDepthChecker.Check(node);
// Assume that iterator nodes at the top-level are references rather than definitions
return VisitAssumeReference(node);
}
//-----------------------------------------------
// QilVisitor overrides
//-----------------------------------------------
/// <summary>
/// Visit all children of "parent", replacing each child with a copy of each child.
/// </summary>
protected override QilNode Visit(QilNode oldNode) {
QilNode newNode = null;
if (oldNode == null)
return null;
// ShallowClone any nodes which have not yet been cloned
if (oldNode is QilReference) {
// Reference nodes may have been cloned previously and put into scope
newNode = FindClonedReference(oldNode);
}
if (newNode == null)
newNode = oldNode.ShallowClone(this.fac);
return base.Visit(newNode);
}
/// <summary>
/// Visit all children of "parent", replacing each child with a copy of each child.
/// </summary>
protected override QilNode VisitChildren(QilNode parent) {
// Visit children
for (int i = 0; i < parent.Count; i++) {
QilNode child = parent[i];
// If child is a reference,
if (IsReference(parent, i)) {
// Visit the reference and substitute its copy
parent[i] = VisitReference(child);
// If no substutition found, then use original child
if (parent[i] == null)
parent[i] = child;
}
else {
// Otherwise, visit the node and substitute its copy
parent[i] = Visit(child);
}
}
return parent;
}
/// <summary>
/// If a cloned reference is in scope, replace "oldNode". Otherwise, return "oldNode".
/// </summary>
protected override QilNode VisitReference(QilNode oldNode) {
QilNode newNode = FindClonedReference(oldNode);
return base.VisitReference(newNode == null ? oldNode : newNode);
}
//-----------------------------------------------
// QilScopedVisitor methods
//-----------------------------------------------
/// <summary>
/// Push node and its shallow clone onto the substitution list.
/// </summary>
protected override void BeginScope(QilNode node) {
this.subs.AddSubstitutionPair(node, node.ShallowClone(this.fac));
}
/// <summary>
/// Pop entry from substitution list.
/// </summary>
protected override void EndScope(QilNode node) {
this.subs.RemoveLastSubstitutionPair();
}
//-----------------------------------------------
// QilCloneVisitor methods
//-----------------------------------------------
/// <summary>
/// Find the clone of an in-scope reference.
/// </summary>
protected QilNode FindClonedReference(QilNode node) {
return this.subs.FindReplacement(node);
}
}
}

Some files were not shown because too many files have changed in this diff Show More