/// <summary> /// Ensure that the current item is pushed onto the stack. /// </summary> public void EnsureStack() { switch (_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 _helper.LoadQueryRuntime(); _helper.Call(_storage.GlobalLocation); break; default: Debug.Assert(false, "Invalid location: " + _storage.Location); break; } _storage = _storage.ToStack(); }
/// <summary> /// Create a StorageDescriptor which is the same as this one, except for the item storage type. /// </summary> public StorageDescriptor ToStorageType(Type itemStorageType) { StorageDescriptor storage = this; storage._itemStorageType = itemStorageType; return(storage); }
/// <summary> /// Create a StorageDescriptor for an item located on the stack. /// </summary> public static StorageDescriptor Stack(Type itemStorageType, bool isCached) { StorageDescriptor storage = new StorageDescriptor(); storage.location = ItemLocation.Stack; storage.itemStorageType = itemStorageType; storage.isCached = isCached; return storage; }
/// <summary> /// Discard the current item if it is pushed onto the stack. /// </summary> public void DiscardStack() { if (_storage.Location == ItemLocation.Stack) { _helper.Emit(OpCodes.Pop); _storage = StorageDescriptor.None(); } }
/// <summary> /// Create a StorageDescriptor for an item which is a parameter to the current method. /// </summary> 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; }
/// <summary> /// Create a StorageDescriptor for an item located on the stack. /// </summary> public static StorageDescriptor Stack(Type itemStorageType, bool isCached) { StorageDescriptor storage = new StorageDescriptor(); storage._location = ItemLocation.Stack; storage._itemStorageType = itemStorageType; storage._isCached = isCached; return(storage); }
/// <summary> /// Create a StorageDescriptor for an item which is a parameter to the current method. /// </summary> 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); }
/// <summary> /// Set this iterator to be the same as the specified iterator. /// </summary> public void SetIterator(IteratorDescriptor iterInfo) { if (iterInfo.HasLabelNext) { _lblNext = iterInfo.GetLabelNext(); _hasNext = true; } _storage = iterInfo.Storage; }
/// <summary> /// Ensure that current item is saved to the specified local variable. /// </summary> public void EnsureLocal(LocalBuilder bldr) { if (_storage.LocalLocation != bldr) { // Push value onto stack and then save to bldr EnsureStack(); _helper.Emit(OpCodes.Stloc, bldr); _storage = _storage.ToLocal(bldr); } }
/// <summary> /// Set this iterator to be the same as the specified iterator. /// </summary> public void SetIterator(IteratorDescriptor iterInfo) { if (iterInfo.HasLabelNext) { this.lblNext = iterInfo.GetLabelNext(); this.hasNext = true; } this.storage = iterInfo.Storage; }
/// <summary> /// Continue iteration until it is complete. Branch to "lblOnEnd" when iteration is complete. /// </summary> /// <remarks> /// goto LabelNextCtxt; /// LabelOnEnd: /// </remarks> public void LoopToEnd(Label lblOnEnd) { if (_hasNext) { _helper.BranchAndMark(_lblNext, lblOnEnd); _hasNext = false; } // After looping is finished, storage is N/A _storage = StorageDescriptor.None(); }
/// <summary> /// Create a StorageDescriptor for an item which is the Current item in an iterator. /// </summary> 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); }
/// <summary> /// If the iterator has been fully cached, then iterate the values one-by-one. /// </summary> public void EnsureNoCache() { if (_storage.IsCached) { if (!HasLabelNext) { // If no Next label, this must be a singleton cache EnsureStack(); _helper.LoadInteger(0); _helper.CallCacheItem(_storage.ItemStorageType); _storage = StorageDescriptor.Stack(_storage.ItemStorageType, false); } else { // int idx; LocalBuilder locIdx = _helper.DeclareLocal("$$$idx", typeof(int)); Label lblNext; // Make sure cache is not on the stack EnsureNoStack("$$$cache"); // idx = -1; _helper.LoadInteger(-1); _helper.Emit(OpCodes.Stloc, locIdx); // LabelNext: lblNext = _helper.DefineLabel(); _helper.MarkLabel(lblNext); // idx++; _helper.Emit(OpCodes.Ldloc, locIdx); _helper.LoadInteger(1); _helper.Emit(OpCodes.Add); _helper.Emit(OpCodes.Stloc, locIdx); // if (idx >= cache.Count) goto LabelNextCtxt; _helper.Emit(OpCodes.Ldloc, locIdx); CacheCount(); _helper.Emit(OpCodes.Bge, GetLabelNext()); // item = cache[idx]; PushValue(); _helper.Emit(OpCodes.Ldloc, locIdx); _helper.CallCacheItem(_storage.ItemStorageType); SetIterator(lblNext, StorageDescriptor.Stack(_storage.ItemStorageType, false)); } } }
/// <summary> /// Create a StorageDescriptor for an item located in a local variable. /// </summary> 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); }
/// <summary> /// Create a StorageDescriptor for an item located in a global variable. /// </summary> 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); }
/// <summary> /// Each XmlQueryType has multiple legal CLR representations. Ensure that all items returned by this iterator are in /// the Clr representation specified by "storageTypeDest". /// </summary> public void EnsureItemStorageType(XmlQueryType xmlType, Type storageTypeDest) { // If source type = destination type, then done if (_storage.ItemStorageType == storageTypeDest) { goto SetStorageType; } Debug.Assert(_storage.ItemStorageType == typeof(XPathItem) || storageTypeDest == typeof(XPathItem), "EnsureItemStorageType must convert to or from Item"); // If items are cached, if (_storage.IsCached) { // Check for special case of IList<XPathNavigator> -> IList<XPathItem> if (_storage.ItemStorageType == typeof(XPathNavigator)) { EnsureStack(); _helper.Call(XmlILMethods.NavsToItems); goto SetStorageType; } // Check for special case of IList<XPathItem> -> IList<XPathNavigator> if (storageTypeDest == typeof(XPathNavigator)) { EnsureStack(); _helper.Call(XmlILMethods.ItemsToNavs); goto SetStorageType; } } // Iterate over each item, and convert each to the destination type EnsureStackNoCache(); // If source type is Item, if (_storage.ItemStorageType == typeof(XPathItem)) { // Then downcast to Navigator if (storageTypeDest == typeof(XPathNavigator)) { _helper.Emit(OpCodes.Castclass, typeof(XPathNavigator)); } else { // Call ValueAs methods for atomic types _helper.CallValueAs(storageTypeDest); } goto SetStorageType; } else if (_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 _helper.LoadInteger(_helper.StaticData.DeclareXmlType(xmlType)); _helper.LoadQueryRuntime(); _helper.Call(XmlILMethods.StorageMethods[_storage.ItemStorageType].ToAtomicValue); SetStorageType: _storage = _storage.ToStorageType(storageTypeDest); }
/// <summary> /// Discard the current item if it is pushed onto the stack. /// </summary> public void DiscardStack() { if (this.storage.Location == ItemLocation.Stack) { this.helper.Emit(OpCodes.Pop); this.storage = StorageDescriptor.None(); } }
/// <summary> /// Each XmlQueryType has multiple legal CLR representations. Ensure that all items returned by this iterator are in /// the Clr representation specified by "storageTypeDest". /// </summary> 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<XPathNavigator> -> IList<XPathItem> if (this.storage.ItemStorageType == typeof(XPathNavigator)) { EnsureStack(); this.helper.Call(XmlILMethods.NavsToItems); goto SetStorageType; } // Check for special case of IList<XPathItem> -> IList<XPathNavigator> 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); }
/// <summary> /// Ensure that the current item is pushed onto the stack. /// </summary> 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(); }
/// <summary> /// Ensure that current item is saved to the specified local variable. /// </summary> 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); } }
/// <summary> /// Continue iteration until it is complete. Branch to "lblOnEnd" when iteration is complete. /// </summary> /// <remarks> /// goto LabelNextCtxt; /// LabelOnEnd: /// </remarks> 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(); }
/// <summary> /// If the iterator has been fully cached, then iterate the values one-by-one. /// </summary> 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)); } } }
/// <summary> /// 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". /// </summary> public void SetIterator(Label lblNext, StorageDescriptor storage) { this.lblNext = lblNext; this.hasNext = true; this.storage = storage; }
/// <summary> /// Create a StorageDescriptor for an item located in a global variable. /// </summary> 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; }
/// <summary> /// Create a StorageDescriptor for an item which is the Current item in an iterator. /// </summary> 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; }
/// <summary> /// 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". /// </summary> public void SetIterator(Label lblNext, StorageDescriptor storage) { _lblNext = lblNext; _hasNext = true; _storage = storage; }
/// <summary> /// Create a StorageDescriptor for an item located in a local variable. /// </summary> 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; }