Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / IlGen / IteratorDescriptor.cs / 1305376 / IteratorDescriptor.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Xml; using System.Xml.XPath; using System.Xml.Schema; using System.Globalization; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Xml.Xsl.Runtime; namespace System.Xml.Xsl.IlGen { ////// Type of location in which iterator items are stored. /// internal enum ItemLocation { None = 0, Stack, // Each value is stored as the top value on the IL stack Parameter, // Each value is stored as a parameter to the current method Local, // Each value is stored as a local variable in the current method Current, // Each value is stored as an iterator's Current property Global, // Each value is stored as a global variable }; ////// None--Not in a branching context /// True--Branch if boolean expression evaluates to true /// False--Branch if boolean expression evaluates to false /// internal enum BranchingContext {None, OnTrue, OnFalse}; ////// Describes the Clr type and location of items returned by an iterator. /// This struct is meant to be immutable. /// internal struct StorageDescriptor { private ItemLocation location; private object locationObject; private Type itemStorageType; private bool isCached; //----------------------------------------------- // Create Methods //----------------------------------------------- ////// Create default, empty StorageDescriptor. /// public static StorageDescriptor None() { return new StorageDescriptor(); } ////// Create a StorageDescriptor for an item located on the stack. /// public static StorageDescriptor Stack(Type itemStorageType, bool isCached) { StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Stack; storage.itemStorageType = itemStorageType; storage.isCached = isCached; return storage; } ////// Create a StorageDescriptor for an item which is a parameter to the current method. /// public static StorageDescriptor Parameter(int paramIndex, Type itemStorageType, bool isCached) { StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Parameter; storage.locationObject = paramIndex; storage.itemStorageType = itemStorageType; storage.isCached = isCached; return storage; } ////// Create a StorageDescriptor for an item located in a local variable. /// public static StorageDescriptor Local(LocalBuilder loc, Type itemStorageType, bool isCached) { Debug.Assert(loc.LocalType == itemStorageType || typeof(IList<>).MakeGenericType(itemStorageType).IsAssignableFrom(loc.LocalType), "Type " + itemStorageType + " does not match the local variable's type"); StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Local; storage.locationObject = loc; storage.itemStorageType = itemStorageType; storage.isCached = isCached; return storage; } ////// Create a StorageDescriptor for an item which is the Current item in an iterator. /// public static StorageDescriptor Current(LocalBuilder locIter, Type itemStorageType) { Debug.Assert(locIter.LocalType.GetMethod("get_Current").ReturnType == itemStorageType, "Type " + itemStorageType + " does not match type of Current property."); StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Current; storage.locationObject = locIter; storage.itemStorageType = itemStorageType; return storage; } ////// Create a StorageDescriptor for an item located in a global variable. /// public static StorageDescriptor Global(MethodInfo methGlobal, Type itemStorageType, bool isCached) { Debug.Assert(methGlobal.ReturnType == itemStorageType || typeof(IList<>).MakeGenericType(itemStorageType).IsAssignableFrom(methGlobal.ReturnType), "Type " + itemStorageType + " does not match the global method's return type"); StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Global; storage.locationObject = methGlobal; storage.itemStorageType = itemStorageType; storage.isCached = isCached; return storage; } //----------------------------------------------- // Accessor Methods //----------------------------------------------- ////// Return copy of current descriptor, but change item's location to the stack. /// public StorageDescriptor ToStack() { return Stack(this.itemStorageType, this.isCached); } ////// Create a StorageDescriptor for an item located in a local variable. /// public StorageDescriptor ToLocal(LocalBuilder loc) { return Local(loc, this.itemStorageType, this.isCached); } ////// Create a StorageDescriptor which is the same as this one, except for the item storage type. /// public StorageDescriptor ToStorageType(Type itemStorageType) { StorageDescriptor storage = this; storage.itemStorageType = itemStorageType; return storage; } ////// Return an enumeration specifying where the value is located. /// public ItemLocation Location { get { return this.location; } } ////// Return the index of the parameter that stores this iterator's values. /// public int ParameterLocation { get { return (int) this.locationObject; } } ////// Return the LocalBuilder that stores this iterator's values. /// public LocalBuilder LocalLocation { get { return this.locationObject as LocalBuilder; } } ////// Return the LocalBuilder that will store this iterator's helper class. The Current property /// on this iterator can be accessed to get the current iteration value. /// public LocalBuilder CurrentLocation { get { return this.locationObject as LocalBuilder; } } ////// Return the MethodInfo for the method that computes this global value. /// public MethodInfo GlobalLocation { get { return this.locationObject as MethodInfo; } } ////// Return true if this iterator's values are cached. /// public bool IsCached { get { return this.isCached; } } ////// Return the Clr type of an individual item in the storage location (never an IList<> type). /// public Type ItemStorageType { get { return this.itemStorageType; } } } ////// Iterators are joined together, are nested within each other, and reference each other. This internal class /// contains detailed information about iteration next labels, caching, iterator item location, etc. /// internal class IteratorDescriptor { private GenerateHelper helper; // Related iterators private IteratorDescriptor iterParent; // Iteration private Label lblNext; private bool hasNext; private LocalBuilder locPos; // Branching private BranchingContext brctxt; private Label lblBranch; // Storage private StorageDescriptor storage; //----------------------------------------------- // Initialize //----------------------------------------------- ////// Create a "root" IteratorDescriptor which has no parent iterator. /// public IteratorDescriptor(GenerateHelper helper) { Init(null, helper); } ////// Create an IteratorDescriptor that is nested in a parent iterator. /// public IteratorDescriptor(IteratorDescriptor iterParent) { Init(iterParent, iterParent.helper); } ////// Internal helper initializor. /// private void Init(IteratorDescriptor iterParent, GenerateHelper helper) { this.helper = helper; this.iterParent = iterParent; } //----------------------------------------------- // Related Iterators //----------------------------------------------- ////// Return the iterator in which this iterator is nested. /// public IteratorDescriptor ParentIterator { get { return this.iterParent; } } //----------------------------------------------- // Iteration //----------------------------------------------- ////// Returns true if LabelNext is currently defined. If not, then this iterator will return /// exactly one result (iterator is cardinality one). /// public bool HasLabelNext { get { return this.hasNext; } } ////// Return the label that is anchored to this code iterator's MoveNext code. /// public Label GetLabelNext() { Debug.Assert(this.hasNext); return this.lblNext; } ////// Set this iterator's next label and storage. This iterator will range over a set of values located in /// "storage". To get the next value, jump to "lblNext". /// public void SetIterator(Label lblNext, StorageDescriptor storage) { this.lblNext = lblNext; this.hasNext = true; this.storage = storage; } ////// Set this iterator to be the same as the specified iterator. /// public void SetIterator(IteratorDescriptor iterInfo) { if (iterInfo.HasLabelNext) { this.lblNext = iterInfo.GetLabelNext(); this.hasNext = true; } this.storage = iterInfo.Storage; } ////// Continue iteration until it is complete. Branch to "lblOnEnd" when iteration is complete. /// ////// goto LabelNextCtxt; /// LabelOnEnd: /// public void LoopToEnd(Label lblOnEnd) { if (this.hasNext) { this.helper.BranchAndMark(this.lblNext, lblOnEnd); this.hasNext = false; } // After looping is finished, storage is N/A this.storage = StorageDescriptor.None(); } ////// Storage location containing the position of the current item as an integer. /// This location is only defined on iterators, and then only if they might be /// referenced by a PositionOf operator. /// public LocalBuilder LocalPosition { get { return this.locPos; } set { this.locPos = value; } } //----------------------------------------------- // Caching //----------------------------------------------- ////// Push the count of items in the cache onto the stack. /// public void CacheCount() { Debug.Assert(this.storage.IsCached); PushValue(); this.helper.CallCacheCount(this.storage.ItemStorageType); } ////// If the iterator has been fully cached, then iterate the values one-by-one. /// public void EnsureNoCache() { if (this.storage.IsCached) { if (!HasLabelNext) { // If no Next label, this must be a singleton cache EnsureStack(); this.helper.LoadInteger(0); this.helper.CallCacheItem(this.storage.ItemStorageType); this.storage = StorageDescriptor.Stack(this.storage.ItemStorageType, false); } else { // int idx; LocalBuilder locIdx = this.helper.DeclareLocal("$$$idx", typeof(int)); Label lblNext; // Make sure cache is not on the stack EnsureNoStack("$$$cache"); // idx = -1; this.helper.LoadInteger(-1); this.helper.Emit(OpCodes.Stloc, locIdx); // LabelNext: lblNext = this.helper.DefineLabel(); this.helper.MarkLabel(lblNext); // idx++; this.helper.Emit(OpCodes.Ldloc, locIdx); this.helper.LoadInteger(1); this.helper.Emit(OpCodes.Add); this.helper.Emit(OpCodes.Stloc, locIdx); // if (idx >= cache.Count) goto LabelNextCtxt; this.helper.Emit(OpCodes.Ldloc, locIdx); CacheCount(); this.helper.Emit(OpCodes.Bge, GetLabelNext()); // item = cache[idx]; PushValue(); this.helper.Emit(OpCodes.Ldloc, locIdx); this.helper.CallCacheItem(this.storage.ItemStorageType); SetIterator(lblNext, StorageDescriptor.Stack(this.storage.ItemStorageType, false)); } } } //----------------------------------------------- // If-then-else branching //----------------------------------------------- ////// Setup a branching context. All nested iterators compiled in this context must evaluate /// to a single boolean value. However, these expressions must not push the result as a boolean /// onto the stack. Instead, if brctxt is BranchType.True, then the expression should /// jump to lblBranch if it evaluates to true. If brctxt is BranchType.False, then the /// branch should happen if the evaluation result is false. /// public void SetBranching(BranchingContext brctxt, Label lblBranch) { Debug.Assert(brctxt != BranchingContext.None); this.brctxt = brctxt; this.lblBranch = lblBranch; } ////// True if within a branching context. /// public bool IsBranching { get { return this.brctxt != BranchingContext.None; } } ////// Returns the label to which conditionals should branch. /// public Label LabelBranch { get { return this.lblBranch; } } ////// If BranchingContext.OnTrue, branch on true. Otherwise, branch on false. /// public BranchingContext CurrentBranchingContext { get { return this.brctxt; } } //----------------------------------------------- // Storage //----------------------------------------------- ////// Returns information about how and where iterator values are stored. /// public StorageDescriptor Storage { get { return this.storage; } set { this.storage = value; } } ////// Push current item onto the stack without affecting Location. /// public void PushValue() { switch (this.storage.Location) { case ItemLocation.Stack: this.helper.Emit(OpCodes.Dup); break; case ItemLocation.Parameter: this.helper.LoadParameter(this.storage.ParameterLocation); break; case ItemLocation.Local: this.helper.Emit(OpCodes.Ldloc, this.storage.LocalLocation); break; case ItemLocation.Current: this.helper.Emit(OpCodes.Ldloca, this.storage.CurrentLocation); this.helper.Call(this.storage.CurrentLocation.LocalType.GetMethod("get_Current")); break; default: Debug.Assert(false, "Invalid location: " + this.storage.Location); break; } } ////// Ensure that the current item is pushed onto the stack. /// public void EnsureStack() { switch (this.storage.Location) { case ItemLocation.Stack: // Already on the stack return; case ItemLocation.Parameter: case ItemLocation.Local: case ItemLocation.Current: PushValue(); break; case ItemLocation.Global: // Call method that computes the value of this global value this.helper.LoadQueryRuntime(); this.helper.Call(this.storage.GlobalLocation); break; default: Debug.Assert(false, "Invalid location: " + this.storage.Location); break; } this.storage = this.storage.ToStack(); } ////// If the current item is on the stack, move it to a local variable. /// public void EnsureNoStack(string locName) { if (this.storage.Location == ItemLocation.Stack) EnsureLocal(locName); } ////// If current item is not already in a local variable, then move it to a local variable of the specified name. /// public void EnsureLocal(string locName) { if (this.storage.Location != ItemLocation.Local) { if (this.storage.IsCached) EnsureLocal(this.helper.DeclareLocal(locName, typeof(IList<>).MakeGenericType(this.storage.ItemStorageType))); else EnsureLocal(this.helper.DeclareLocal(locName, this.storage.ItemStorageType)); } } ////// Ensure that current item is saved to the specified local variable. /// public void EnsureLocal(LocalBuilder bldr) { if (this.storage.LocalLocation != bldr) { // Push value onto stack and then save to bldr EnsureStack(); this.helper.Emit(OpCodes.Stloc, bldr); this.storage = this.storage.ToLocal(bldr); } } ////// Discard the current item if it is pushed onto the stack. /// public void DiscardStack() { if (this.storage.Location == ItemLocation.Stack) { this.helper.Emit(OpCodes.Pop); this.storage = StorageDescriptor.None(); } } ////// Ensure that the iterator's items are not cached, and that the current item is pushed onto the stack. /// public void EnsureStackNoCache() { EnsureNoCache(); EnsureStack(); } ////// Ensure that the iterator's items are not cached, and that if the current item is pushed onto the stack, /// that it is moved to a local variable. /// public void EnsureNoStackNoCache(string locName) { EnsureNoCache(); EnsureNoStack(locName); } ////// Ensure that the iterator's items are not cached, and that if the current item is not already in a local, /// variable, that it is moved to a local variable of the specified name. /// public void EnsureLocalNoCache(string locName) { EnsureNoCache(); EnsureLocal(locName); } ////// Ensure that the iterator's items are not cached and that the current item is saved to the specified local variable. /// public void EnsureLocalNoCache(LocalBuilder bldr) { EnsureNoCache(); EnsureLocal(bldr); } ////// Each XmlQueryType has multiple legal CLR representations. Ensure that all items returned by this iterator are in /// the Clr representation specified by "storageTypeDest". /// public void EnsureItemStorageType(XmlQueryType xmlType, Type storageTypeDest) { // If source type = destination type, then done if (this.storage.ItemStorageType == storageTypeDest) goto SetStorageType; Debug.Assert(this.storage.ItemStorageType == typeof(XPathItem) || storageTypeDest == typeof(XPathItem), "EnsureItemStorageType must convert to or from Item"); // If items are cached, if (this.storage.IsCached) { // Check for special case of IList-> IList if (this.storage.ItemStorageType == typeof(XPathNavigator)) { EnsureStack(); this.helper.Call(XmlILMethods.NavsToItems); goto SetStorageType; } // Check for special case of IList -> IList if (storageTypeDest == typeof(XPathNavigator)) { EnsureStack(); this.helper.Call(XmlILMethods.ItemsToNavs); goto SetStorageType; } } // Iterate over each item, and convert each to the destination type EnsureStackNoCache(); // If source type is Item, if (this.storage.ItemStorageType == typeof(XPathItem)) { // Then downcast to Navigator if (storageTypeDest == typeof(XPathNavigator)) { this.helper.Emit(OpCodes.Castclass, typeof(XPathNavigator)); } else { // Call ValueAs methods for atomic types this.helper.CallValueAs(storageTypeDest); } goto SetStorageType; } else if (this.storage.ItemStorageType == typeof(XPathNavigator)) { // No-op if converting from XPathNavigator to XPathItem Debug.Assert(storageTypeDest == typeof(XPathItem), "Must be converting from XPathNavigator to XPathItem"); goto SetStorageType; } // Destination type must be item, so generate code to create an XmlAtomicValue this.helper.LoadInteger(this.helper.StaticData.DeclareXmlType(xmlType)); this.helper.LoadQueryRuntime(); this.helper.Call(XmlILMethods.StorageMethods[this.storage.ItemStorageType].ToAtomicValue); SetStorageType: this.storage = this.storage.ToStorageType(storageTypeDest); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SocketPermission.cs
- DesignBindingPropertyDescriptor.cs
- BinHexEncoder.cs
- ScaleTransform3D.cs
- ApplicationServiceHelper.cs
- FrameworkPropertyMetadata.cs
- StringWriter.cs
- XmlSchemaException.cs
- GC.cs
- CloseSequence.cs
- dbenumerator.cs
- TransactionChannelListener.cs
- PersonalizationAdministration.cs
- invalidudtexception.cs
- WebPartsPersonalizationAuthorization.cs
- BuilderElements.cs
- ThemeDictionaryExtension.cs
- TextDecorations.cs
- Number.cs
- BindingsCollection.cs
- ConfigurationSectionGroupCollection.cs
- Delay.cs
- Timeline.cs
- PageWrapper.cs
- TdsParserStaticMethods.cs
- MatrixAnimationBase.cs
- Stack.cs
- EntityDataSourceContainerNameConverter.cs
- ActiveXSite.cs
- BamlBinaryReader.cs
- Cursors.cs
- StorageMappingItemLoader.cs
- HotSpotCollection.cs
- SerializationStore.cs
- Inflater.cs
- RenderDataDrawingContext.cs
- TextBounds.cs
- CacheDependency.cs
- ReferencedCollectionType.cs
- RevocationPoint.cs
- EncoderBestFitFallback.cs
- SuppressIldasmAttribute.cs
- DocumentViewerBase.cs
- XmlException.cs
- BaseTreeIterator.cs
- GridItemCollection.cs
- TextChangedEventArgs.cs
- IncrementalCompileAnalyzer.cs
- PingReply.cs
- IISUnsafeMethods.cs
- TabPageDesigner.cs
- ArrayConverter.cs
- ObjectListComponentEditor.cs
- NameTable.cs
- XmlQueryOutput.cs
- ClientSideProviderDescription.cs
- TimeSpan.cs
- FixedDocumentSequencePaginator.cs
- IsolatedStorageFilePermission.cs
- ThreadExceptionDialog.cs
- Label.cs
- DbInsertCommandTree.cs
- ConfigurationValidatorBase.cs
- EdgeProfileValidation.cs
- CorePropertiesFilter.cs
- EventMappingSettings.cs
- COSERVERINFO.cs
- DbProviderFactories.cs
- HttpValueCollection.cs
- GridViewUpdatedEventArgs.cs
- ProfilePropertyMetadata.cs
- DesignerActionHeaderItem.cs
- ColumnBinding.cs
- ListMarkerLine.cs
- XPathNodeIterator.cs
- ZipIOCentralDirectoryFileHeader.cs
- ArrangedElement.cs
- DocumentPageViewAutomationPeer.cs
- WindowsListViewItem.cs
- ClientBuildManager.cs
- FontStretch.cs
- X500Name.cs
- AssociationSetEnd.cs
- BitmapEffect.cs
- WindowsGraphicsCacheManager.cs
- ReadOnlyDictionary.cs
- DesignTimeVisibleAttribute.cs
- DiscoveryRequestHandler.cs
- VirtualPath.cs
- WorkflowControlEndpoint.cs
- ReferenceService.cs
- CommandPlan.cs
- SiteMapDataSource.cs
- PackageRelationship.cs
- CallbackValidatorAttribute.cs
- LineBreak.cs
- ApplyImportsAction.cs
- ObjectListGeneralPage.cs
- DataViewSetting.cs
- ChangesetResponse.cs