You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -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")]
|
@@ -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; }
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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_,
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
e1c869221fa43552e2ba4aeda158583a553d307c
|
@@ -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
|
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
786be8983fcf729e04fe03010b521bd7b8ee8d84
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
Reference in New Issue
Block a user